You are viewing a plain text version of this content. The canonical link for it is here.
Posted to server-dev@james.apache.org by Pietro Romanazzi <p....@tno.it> on 2008/02/13 13:14:50 UTC

New proposed implementation of STARTTLS

Dear All,

just added an attachment to JAMES-290 containing a new version of the
previous experiment. I left the old file in place.
The STARTTLS support is now configurable.
I submit this code for discussion.
Is the James developer community interested in this new feature?
Regards,

Pietro

---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


RE: New proposed implementation of STARTTLS

Posted by "Noel J. Bergman" <no...@devtech.com>.
Please attach the patch to the JIRA issue.  In-line patches on the mailing
list get corrupted by mail clients.

	--- Noel



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


RE: New proposed implementation of STARTTLS

Posted by Pietro Romanazzi <p....@tno.it>.
> Robert Burrell Donkin wrote:
> 
> > we'll need to wait until one of the SMTP experts finds some time
> > to comment before we can start reviewing the contribution in detail.
> 
> I have asked that he submit the change as a diff (patch) against v2.3.1, and
> will review.  I need to create a branch soon, anyway, to maintain a version
> of JAMES suitable for use in production, and will apply this code there for
> testing.
> 
> 	--- Noel
> 
> 
> 
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
> For additional commands, e-mail: server-dev-help@james.apache.org
> 
Hi,

Please find the diff for the smtpserver classes involved and the source for the new classes.

Kindest regards

Pietro

--- ./smtpserver/EhloCmdHandler.java	2007-01-12 13:56:26.000000000 +0100
+++ EhloCmdHandler.java	2008-02-12 18:50:04.000000000 +0100
@@ -126,7 +126,11 @@
             if (maxMessageSize > 0) {
                 esmtpextensions.add("SIZE " + maxMessageSize);
             }
-
+            //NEW FOR SMTP STARTTLS
+            if (!session.isTLSStarted() && session.isStartTlsSupported()) {
+                esmtpextensions.add("STARTTLS");
+            }
+            //END NEW
             if (session.isAuthRequired()) {
                 esmtpextensions.add("AUTH LOGIN PLAIN");
                 esmtpextensions.add("AUTH=LOGIN PLAIN");


--- ./smtpserver/SMTPHandlerChain.java	2007-01-12 13:56:26.000000000 +0100
+++ SMTPHandlerChain.java	2008-01-28 16:55:51.000000000 +0100
@@ -78,6 +78,9 @@
             cmds.setProperty("RCPT" ,RcptCmdHandler.class.getName());
             cmds.setProperty("RSET",RsetCmdHandler.class.getName());
             cmds.setProperty("VRFY",VrfyCmdHandler.class.getName());
+            //NEW FOR SMTP STARTTLS
+            cmds.setProperty("STARTTLS",StartTlsCmdHandler.class.getName());
+            // 
             cmds.setProperty("Default SendMailHandler",SendMailHandler.class.getName());
             Enumeration e = cmds.keys();
             while (e.hasMoreElements()) {


--- ./smtpserver/SMTPHandlerConfigurationData.java	2007-01-12 13:56:26.000000000 +0100
+++ SMTPHandlerConfigurationData.java	2008-02-12 18:54:07.000000000 +0100
@@ -19,6 +19,8 @@
 
 package org.apache.james.smtpserver;
 
+import javax.net.ssl.SSLSocketFactory;
+
 import org.apache.james.services.MailServer;
 import org.apache.james.services.UsersRepository;
 
@@ -104,4 +106,14 @@
      */
     UsersRepository getUsersRepository();
 
+//NEW FOR STARTTLS
+    boolean isStartTlsSupported();
+
+    /**
+     * Returns the SSLSocketFactory for STARTTLS support.
+     * 
+     * @return the ssl socket factory
+     */
+    SSLSocketFactory getSSLSocketFactory();
+//END NEW
 }


--- ./smtpserver/SMTPHandler.java	2007-01-12 13:56:26.000000000 +0100
+++ SMTPHandler.java	2008-02-12 18:54:07.000000000 +0100
@@ -34,6 +34,7 @@
 
 import java.io.BufferedInputStream;
 import java.io.BufferedWriter;
+import java.io.FileInputStream;
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.InterruptedIOException;
@@ -41,6 +42,12 @@
 import java.io.PrintWriter;
 import java.net.Socket;
 import java.net.SocketException;
+
+import java.security.KeyStore;
+
+import java.security.Provider;
+import java.security.Security;
+
 import java.util.ArrayList;
 import java.util.Date;
 import java.util.HashMap;
@@ -48,6 +55,12 @@
 import java.util.Locale;
 import java.util.Random;
 
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocket;
+import javax.net.ssl.SSLSocketFactory;
+
+
 /**
  * Provides SMTP functionality by carrying out the server side of the SMTP
  * interaction.
@@ -133,6 +146,8 @@
      * The writer to which outgoing messages are written.
      */
     private PrintWriter out;
+    
+
 
     /**
      * A Reader wrapper for the incoming stream of bytes coming from the socket.
@@ -208,6 +223,9 @@
      */
     private StringBuffer responseBuffer = new StringBuffer(256);
 
+// NEW FOR SMTP STARTTLS
+    private boolean TLSStarted=false;
+    private boolean startTlsSupported=false;
     /**
      * Set the configuration data for the handler
      *
@@ -281,6 +299,9 @@
             relayingAllowed = theConfigData.isRelayingAllowed(remoteIP);
             authRequired = theConfigData.isAuthRequired(remoteIP);
             heloEhloEnforcement = theConfigData.useHeloEhloEnforcement();
+            //NEW FOR STARTTLS
+            startTlsSupported= theConfigData.isStartTlsSupported();
+            //END NEW
             sessionEnded = false;
             resetState();
         } catch (Exception e) {
@@ -788,4 +809,39 @@
         mode = MESSAGE_ABORT_MODE;
     }
 
+// NEW METHODS FOR SMTP STARTTLS 
+    public boolean isTLSStarted() {
+        return TLSStarted;
+    }
+   
+   public boolean isStartTlsSupported() {
+        return startTlsSupported;
+    }
+   
+    public void secure() throws Exception {
+
+
+        SSLSocket sslsock;
+
+        try { 
+        sslsock=(SSLSocket)theConfigData.getSSLSocketFactory().createSocket(
+        socket,
+        socket.getInetAddress().getHostName(),
+        socket.getPort(),
+        true);
+        sslsock.setUseClientMode(false);
+        // just to see SSL negotiated algo
+        getLogger().debug("Finished negotiating SSL - algorithm is " +
+        sslsock.getSession().getCipherSuite());
+        TLSStarted=true;
+        // new socket, in, out, inReader. what about old objects?
+        socket=sslsock;
+        in = new BufferedInputStream(socket.getInputStream(), 1024);
+        inReader = new CRLFTerminatedReader(in, "ASCII");
+        out = new InternetPrintWriter(new BufferedWriter(new OutputStreamWriter(socket.getOutputStream()), 1024), false);
+        } catch (Exception e) {
+        getLogger().error("Error layering SSL over the socket");
+        throw e;
+        }
+        } 
 }


--- ./smtpserver/SMTPServer.java	2007-01-12 13:56:26.000000000 +0100
+++ SMTPServer.java	2008-02-12 18:54:07.000000000 +0100
@@ -19,6 +19,16 @@
 
 package org.apache.james.smtpserver;
 
+import java.io.FileInputStream;
+
+import java.security.KeyStore;
+import java.security.Provider;
+import java.security.Security;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLSocketFactory;
+
 import org.apache.avalon.cornerstone.services.connection.ConnectionHandler;
 import org.apache.avalon.excalibur.pool.DefaultPool;
 import org.apache.avalon.excalibur.pool.HardResourceLimitingPool;
@@ -141,6 +151,11 @@
 
     private ServiceManager serviceManager;
 
+//NEW FOR STARTTLS
+    private boolean isStartTlsSupported;
+    
+    private SSLSocketFactory sslSocketFactory;
+
     /**
      * @see org.apache.avalon.framework.service.Serviceable#service(ServiceManager)
      */
@@ -160,6 +175,45 @@
         if (isEnabled()) {
             mailetcontext.setAttribute(Constants.HELLO_NAME, helloName);
             Configuration handlerConfiguration = configuration.getChild("handler");
+            // NEW FOR STARTTLS
+            String startTLS=handlerConfiguration.getChild("starttls").getValue("false").trim().toLowerCase();
+            isStartTlsSupported=false;
+            if (startTLS.equals("true"))  {
+            isStartTlsSupported=true;
+            System.out.println("starttls="+startTLS);
+            Configuration sslMaterial = handlerConfiguration.getChild("sslMaterial");
+            SSLMaterial sslm = new SSLMaterial(sslMaterial);
+            KeyStore ks = null;
+            KeyManagerFactory kmf = null;
+            SSLContext sslcontext = null;
+            //just to see SunJCE is loaded
+            Provider[] provs=Security.getProviders();
+            for(int i=0;i<provs.length;i++) 
+                    getLogger().debug("Provider["+i+"]="+provs[i].getName());
+                // This loads the key material, and initialises the
+                // SSLSocketFactory
+                // Note: in order to load SunJCE provider the jre/lib/ext should be added
+                // to the java.ext.dirs see the note in run.sh script
+
+            try {
+                ks = KeyStore.getInstance(sslm.getKeystoreType(),sslm.getKeystoreProvider());
+                ks.load(new FileInputStream(sslm.getKeystoreLocation()), sslm.getKeystorePassword().toCharArray());
+                kmf = KeyManagerFactory.getInstance(sslm.getAlgorithm(), sslm.getAlgoProvider());
+                kmf.init(ks, sslm.getKeystorePassword().toCharArray());
+                sslcontext = SSLContext.getInstance(sslm.getSslProtocol(),sslm.getSslProvider());
+                sslcontext.init(kmf.getKeyManagers(), null, null);
+                sslSocketFactory = sslcontext.getSocketFactory();
+                // just to see the list of supported ciphers
+                String[] ss=sslSocketFactory.getSupportedCipherSuites();
+                getLogger().debug("list of supported ciphers");
+                for(int i=0;i<ss.length;i++) 
+                        getLogger().debug(ss[i]);
+            } catch (Exception e) {
+                getLogger().error("Exception accessing keystore: " + e);
+                // TODO throw e;
+                }
+            }
+            // END NEW
             String authRequiredString = handlerConfiguration.getChild("authRequired").getValue("false").trim().toLowerCase();
             if (authRequiredString.equals("true")) authRequired = AUTH_REQUIRED;
             else if (authRequiredString.equals("announce")) authRequired = AUTH_ANNOUNCE;
@@ -441,5 +495,19 @@
             return SMTPServer.this.heloEhloEnforcement;
         }
 
+//NEW FOR STARTTLS        
+        public boolean isStartTlsSupported() {
+            return SMTPServer.this.isStartTlsSupported;
+        }
+
+        /**
+         * Returns the SSLSocketFactory for STARTTLS support.
+         * 
+         * @return the ssl socket factory
+         */
+        public SSLSocketFactory getSSLSocketFactory() {
+            return SMTPServer.this.sslSocketFactory;
+        }
+//END NEW
     }
 }

--- ./smtpserver/SMTPSession.java	2007-01-12 13:56:26.000000000 +0100
+++ SMTPSession.java	2008-02-12 18:50:04.000000000 +0100
@@ -204,7 +204,7 @@
     /**
      * Sets the user name associated with this SMTP interaction.
      *
-     * @param userID the user name
+     * @param user the user name
      */
     void setUser(String user);
 
@@ -221,6 +221,12 @@
      * @return SMTP session id
      */
     String getSessionID();
+    
+// NEW METHODS FOR SMTP STARTTLS
+    boolean isStartTlsSupported();
+    
+    boolean isTLSStarted();
 
+    void secure() throws Exception;
 }
 
/****************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one   *
 * or more contributor license agreements.  See the NOTICE file *
 * distributed with this work for additional information        *
 * regarding copyright ownership.  The ASF licenses this file   *
 * to you under the Apache License, Version 2.0 (the            *
 * "License"); you may not use this file except in compliance   *
 * with the License.  You may obtain a copy of the License at   *
 *                                                              *
 *   http://www.apache.org/licenses/LICENSE-2.0                 *
 *                                                              *
 * Unless required by applicable law or agreed to in writing,   *
 * software distributed under the License is distributed on an  *
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
 * KIND, either express or implied.  See the License for the    *
 * specific language governing permissions and limitations      *
 * under the License.                                           *
 ****************************************************************/

package org.apache.james.smtpserver;

import org.apache.james.util.mail.dsn.DSNStatus;

/**
  * Handles STARTTLS command
  */
public class StartTlsCmdHandler implements CommandHandler {
    /**
     * The name of the command handled by the command handler
     */
    private final static String COMMAND_NAME = "STARTTLS";

    /*
     * handles STARTTLS command
     *
     * @see org.apache.james.smtpserver.CommandHandler#onCommand(SMTPSession)
    **/
    public void onCommand(SMTPSession session) {
        doSTARTTLS(session, session.getCommandArgument());
    }


    /**
     * Handler method called upon receipt of a STARTTLS command.
     * Resets message-specific, but not authenticated user, state.
     *
     * @param session SMTP session object
     * @param argument the argument passed in with the command by the SMTP client
     */
    private void doSTARTTLS(SMTPSession session, String argument) {
        String responseString = "";
        if (!session.isStartTlsSupported()) {
            responseString = "500 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.SECURITY_UNSUPPORTED)+" 
STARTTLS not supported";
        }
        else if (session.isTLSStarted()) {
                responseString = "500 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_CMD)+" TLS 
already active RFC2487 5.2";
             } else if ((argument == null) || (argument.length() == 0)) {
                        responseString = "220 "+DSNStatus.getStatus(DSNStatus.SUCCESS,DSNStatus.UNDEFINED_STATUS)+" Ready to 
start TLS";
                    } else {
                        responseString = "501 "+DSNStatus.getStatus(DSNStatus.PERMANENT,DSNStatus.DELIVERY_INVALID_ARG)+" 
Syntax error (no parameters allowed) with STARTTLS command";
                      }
                
        session.writeResponse(responseString);
        try {
            if(!session.isTLSStarted() && session.isStartTlsSupported()) {
            session.secure();
            //force reset
            session.resetState();
            }
        } catch (Exception e) {
            // TODO
        }
    }

}


/****************************************************************
 * Licensed to the Apache Software Foundation (ASF) under one   *
 * or more contributor license agreements.  See the NOTICE file *
 * distributed with this work for additional information        *
 * regarding copyright ownership.  The ASF licenses this file   *
 * to you under the Apache License, Version 2.0 (the            *
 * "License"); you may not use this file except in compliance   *
 * with the License.  You may obtain a copy of the License at   *
 *                                                              *
 *   http://www.apache.org/licenses/LICENSE-2.0                 *
 *                                                              *
 * Unless required by applicable law or agreed to in writing,   *
 * software distributed under the License is distributed on an  *
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY       *
 * KIND, either express or implied.  See the License for the    *
 * specific language governing permissions and limitations      *
 * under the License.                                           *
 ****************************************************************/

package org.apache.james.smtpserver;

import org.apache.avalon.framework.configuration.Configuration;
import org.apache.avalon.framework.configuration.ConfigurationException;

public class SSLMaterial {
    private String keystoreType;
    private String keystoreProvider;
    private String keystoreLocation;
    private String keystorePassword;
    private String alias;
    private String aliasPassword;
    private String algorithm;
    private String algoProvider;
    private String sslProtocol;
    private String sslProvider;
    public SSLMaterial(Configuration con) throws ConfigurationException {
    keystoreType=con.getChild("keystoreType").getValue("JKS").trim();
    keystoreProvider=con.getChild("keystoreProvider").getValue("SUN").trim();
    keystoreLocation=con.getChild("keystoreLocation").getValue().trim();
    keystorePassword=con.getChild("keystorePassword").getValue().trim();
    alias=con.getChild("alias").getValue("").trim();
    aliasPassword=con.getChild("aliasPassword").getValue("").trim();
    algorithm=con.getChild("algorithm").getValue("SunX509").trim();
    algoProvider=con.getChild("algoProvider").getValue("SunJSSE").trim();
    sslProtocol=con.getChild("sslProtocol").getValue("SSL").trim();
    sslProvider=con.getChild("sslProvider").getValue("SunJSSE").trim();
    }

    public String getKeystoreType() {
        return keystoreType;
    }

    public String getKeystoreProvider() {
        return keystoreProvider;
    }

    public String getKeystoreLocation() {
        return keystoreLocation;
    }

    public String getKeystorePassword() {
        return keystorePassword;
    }

    public String getAlias() {
        return alias;
    }

    public String getAliasPassword() {
        return aliasPassword;
    }

    public String getAlgorithm() {
        return algorithm;
    }

    public String getAlgoProvider() {
        return algoProvider;
    }

    public String getSslProtocol() {
        return sslProtocol;
    }

    public String getSslProvider() {
        return sslProvider;
    }
}
Pietro Romanazzi
Responsabile Servizio PEC
Tecnopolis CSATA s.c.r.l.
Centro Tecnico RUPAR Puglia
70010 Valenzano (BA)
e-mail: p.romanazzi@ct.rupar.puglia.it
ITALY
Tel: +39 080 4670512
Mob: +39 320 7673652



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


Re: New proposed implementation of STARTTLS

Posted by Norman Maurer <no...@apache.org>.
Am Donnerstag, den 14.02.2008, 09:40 +0100 schrieb Norman Maurer:
> Am Mittwoch, den 13.02.2008, 23:04 +0000 schrieb Robert Burrell Donkin:
> > On Feb 13, 2008 12:14 PM, Pietro Romanazzi <p....@tno.it> wrote:
> > > Dear All,
> > 
> > hi
> > 
> > > just added an attachment to JAMES-290 containing a new version of the
> > > previous experiment. I left the old file in place.
> > > The STARTTLS support is now configurable.
> > > I submit this code for discussion.
> > > Is the James developer community interested in this new feature?
> > 
> > we're always interested in new code :-)
> > 
> > but we'll need to wait until one of the SMTP experts finds some time
> > to comment before we can start reviewing the contribution in detail...
> > 
> > - robert
> 
> I don't know if im an expert of SMTP ;-P but I will have a look at this
> later today.
> 
> bye
> Norman

>>From a quick review it seems to be ok. But the main problem seems to
that it is based on 2.3.x code base. We don't include new features in
2.3.x releases. So the question is what todo ..

1. Refactor it to fit the smtp architecture in trunk ( will this be
really the code to go in next release or should we better use the 2.3.x
code ? ) ....

2. Put it in queue for a 2.4.x release ( Noel ? ) ..

Any ideas ?

Cheers,
Norman



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


Re: New proposed implementation of STARTTLS

Posted by Norman Maurer <no...@apache.org>.
Am Mittwoch, den 13.02.2008, 23:04 +0000 schrieb Robert Burrell Donkin:
> On Feb 13, 2008 12:14 PM, Pietro Romanazzi <p....@tno.it> wrote:
> > Dear All,
> 
> hi
> 
> > just added an attachment to JAMES-290 containing a new version of the
> > previous experiment. I left the old file in place.
> > The STARTTLS support is now configurable.
> > I submit this code for discussion.
> > Is the James developer community interested in this new feature?
> 
> we're always interested in new code :-)
> 
> but we'll need to wait until one of the SMTP experts finds some time
> to comment before we can start reviewing the contribution in detail...
> 
> - robert

I don't know if im an expert of SMTP ;-P but I will have a look at this
later today.

bye
Norman



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


RE: New proposed implementation of STARTTLS

Posted by "Noel J. Bergman" <no...@devtech.com>.
Robert Burrell Donkin wrote:

> we'll need to wait until one of the SMTP experts finds some time
> to comment before we can start reviewing the contribution in detail.

I have asked that he submit the change as a diff (patch) against v2.3.1, and
will review.  I need to create a branch soon, anyway, to maintain a version
of JAMES suitable for use in production, and will apply this code there for
testing.

	--- Noel



---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org


Re: New proposed implementation of STARTTLS

Posted by Robert Burrell Donkin <ro...@gmail.com>.
On Feb 13, 2008 12:14 PM, Pietro Romanazzi <p....@tno.it> wrote:
> Dear All,

hi

> just added an attachment to JAMES-290 containing a new version of the
> previous experiment. I left the old file in place.
> The STARTTLS support is now configurable.
> I submit this code for discussion.
> Is the James developer community interested in this new feature?

we're always interested in new code :-)

but we'll need to wait until one of the SMTP experts finds some time
to comment before we can start reviewing the contribution in detail...

- robert

---------------------------------------------------------------------
To unsubscribe, e-mail: server-dev-unsubscribe@james.apache.org
For additional commands, e-mail: server-dev-help@james.apache.org