--- ./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