directory-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From trus...@apache.org
Subject svn commit: r156507 - in incubator/directory/network/mina/trunk: src/examples/org/apache/mina/examples/echoserver/ src/examples/org/apache/mina/examples/echoserver/ssl/ src/java/org/apache/mina/io/filter/ src/test/org/apache/mina/examples/echoserver/ xdocs/
Date Tue, 08 Mar 2005 07:34:47 GMT
Author: trustin
Date: Mon Mar  7 23:34:43 2005
New Revision: 156507

URL: http://svn.apache.org/viewcvs?view=rev&rev=156507
Log:
Added SSLFilter, its example, and its test. (DIRMINA-11)

Added:
    incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/
    incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/BogusSSLContextFactory.java   (with props)
    incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/BogusTrustManagerFactory.java   (with props)
    incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/SSLServerSocketFactory.java   (with props)
    incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/SSLSocketFactory.java   (with props)
    incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/bogus.cert   (with props)
    incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLByteBufferPool.java   (with props)
    incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLFilter.java   (with props)
    incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLHandler.java   (with props)
Modified:
    incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/Main.java
    incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/package.html
    incubator/directory/network/mina/trunk/src/test/org/apache/mina/examples/echoserver/Test.java
    incubator/directory/network/mina/trunk/xdocs/index.xml

Modified: incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/Main.java
URL: http://svn.apache.org/viewcvs/incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/Main.java?view=diff&r1=156506&r2=156507
==============================================================================
--- incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/Main.java (original)
+++ incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/Main.java Mon Mar  7 23:34:43 2005
@@ -20,20 +20,26 @@
 
 import java.net.InetSocketAddress;
 
+import org.apache.mina.examples.echoserver.ssl.BogusSSLContextFactory;
 import org.apache.mina.io.IoAcceptor;
 import org.apache.mina.io.datagram.DatagramAcceptor;
 import org.apache.mina.io.filter.IoThreadPoolFilter;
+import org.apache.mina.io.filter.SSLFilter;
 import org.apache.mina.io.socket.SocketAcceptor;
 
 /**
  * (<b>Entry point</b>) Echo server
  * 
  * @author Trustin Lee (trustin@apache.org)
- * @version $Rev$, $Date$,
+ * @version $Rev$, $Date$
  */
 public class Main
 {
+    /** Choose your favorite port number. */
     private static final int PORT = 8080;
+    
+    /** Set this to true if you want to make the server SSL */
+    private static final boolean USE_SSL = false;
 
     public static void main( String[] args ) throws Exception
     {
@@ -47,6 +53,15 @@
         // Add thread pool filter
         // MINA runs in a single thread if you don't add this filter.
         acceptor.addFilter( Integer.MAX_VALUE, threadPoolFilter );
+
+        // Add SSL filter if SSL is enabled.
+        if( USE_SSL )
+        {
+            System.out.println( "SSL is enabled." );
+            SSLFilter sslFilter = new SSLFilter( BogusSSLContextFactory
+                    .getInstance( true ) );
+            acceptor.addFilter( Integer.MAX_VALUE - 1, sslFilter );
+        }
 
         // Bind
         acceptor.bind( new InetSocketAddress( PORT ),

Modified: incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/package.html
URL: http://svn.apache.org/viewcvs/incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/package.html?view=diff&r1=156506&r2=156507
==============================================================================
--- incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/package.html (original)
+++ incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/package.html Mon Mar  7 23:34:43 2005
@@ -3,6 +3,6 @@
 <head>
 </head>
 <body>
-Echo server which demonstates low-level I/O layer.
+Echo server which demonstates low-level I/O layer and SSL support.
 </body>
 </html>

Added: incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/BogusSSLContextFactory.java
URL: http://svn.apache.org/viewcvs/incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/BogusSSLContextFactory.java?view=auto&rev=156507
==============================================================================
--- incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/BogusSSLContextFactory.java (added)
+++ incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/BogusSSLContextFactory.java Mon Mar  7 23:34:43 2005
@@ -0,0 +1,162 @@
+/*
+ *   @(#) $Id$
+ *
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed 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.mina.examples.echoserver.ssl;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.security.GeneralSecurityException;
+import java.security.KeyStore;
+
+import javax.net.ssl.KeyManagerFactory;
+import javax.net.ssl.SSLContext;
+
+/**
+ * Factory to create a bougus SSLContext.
+ *
+ * @author Per Widerlund (per@minq.se)
+ * @author Jan Andersson (janne@minq.se)
+ * 
+ * @version $Rev$, $Date$
+ */
+public class BogusSSLContextFactory
+{
+
+    /**
+     * Protocol to use.
+     */
+    private static final String PROTOCOL = "TLS";
+
+    /**
+     * Bougus Server certificate keystore file name.
+     */
+    private static final String BOGUS_KEYSTORE = "bogus.cert";
+
+    // NOTE: The keystore was generated using keytool:
+    //   keytool -genkey -alias bogus -keysize 512 -validity 3650
+    //           -keyalg RSA -dname "CN=bogus.com, OU=XXX CA,
+    //               O=Bogus Inc, L=Stockholm, S=Stockholm, C=SE"
+    //           -keypass boguspw -storepass boguspw -keystore bogus.cert
+
+    /**
+     * Bougus keystore password.
+     */
+    private static final char[] BOGUS_PW = { 'b', 'o', 'g', 'u', 's', 'p',
+                                            'w' };
+
+    private static SSLContext serverInstance = null;
+
+    private static SSLContext clientInstance = null;
+
+    /**
+     * Get SSLContext singleton.
+     *
+     * @return SSLContext
+     * @throws java.security.GeneralSecurityException
+     *
+     */
+    public static SSLContext getInstance( boolean server )
+            throws GeneralSecurityException
+    {
+        SSLContext retInstance = null;
+        if( server )
+        {
+            if( serverInstance == null )
+            {
+                synchronized( BogusSSLContextFactory.class )
+                {
+                    if( serverInstance == null )
+                    {
+                        try
+                        {
+                            serverInstance = createBougusServerSSLContext();
+                        }
+                        catch( Exception ioe )
+                        {
+                            throw new GeneralSecurityException(
+                                    "Can't create Server SSLContext:" + ioe );
+                        }
+                    }
+                }
+            }
+            retInstance = serverInstance;
+        }
+        else
+        {
+            if( clientInstance == null )
+            {
+                synchronized( BogusSSLContextFactory.class )
+                {
+                    if( clientInstance == null )
+                    {
+                        clientInstance = createBougusClientSSLContext();
+                    }
+                }
+            }
+            retInstance = clientInstance;
+        }
+        return retInstance;
+    }
+
+    private static SSLContext createBougusServerSSLContext()
+            throws GeneralSecurityException, IOException
+    {
+        // Create keystore
+        KeyStore ks = KeyStore.getInstance( "JKS" );
+        InputStream in = null;
+        try
+        {
+            in = BogusSSLContextFactory.class
+                    .getResourceAsStream( BOGUS_KEYSTORE );
+            ks.load( in, BOGUS_PW );
+        }
+        finally
+        {
+            if( in != null )
+            {
+                try
+                {
+                    in.close();
+                }
+                catch( IOException ignored )
+                {
+                }
+            }
+        }
+
+        // Set up key manager factory to use our key store
+        KeyManagerFactory kmf = KeyManagerFactory.getInstance( "SunX509" );
+        kmf.init( ks, BOGUS_PW );
+
+        // Initialize the SSLContext to work with our key managers.
+        SSLContext sslContext = SSLContext.getInstance( PROTOCOL );
+        sslContext.init( kmf.getKeyManagers(),
+                BogusTrustManagerFactory.X509_MANAGERS, null );
+
+        return sslContext;
+    }
+
+    private static SSLContext createBougusClientSSLContext()
+            throws GeneralSecurityException
+    {
+        SSLContext context = SSLContext.getInstance( PROTOCOL );
+        context.init( null, BogusTrustManagerFactory.X509_MANAGERS, null );
+        return context;
+    }
+
+}

Propchange: incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/BogusSSLContextFactory.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision

Added: incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/BogusTrustManagerFactory.java
URL: http://svn.apache.org/viewcvs/incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/BogusTrustManagerFactory.java?view=auto&rev=156507
==============================================================================
--- incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/BogusTrustManagerFactory.java (added)
+++ incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/BogusTrustManagerFactory.java Mon Mar  7 23:34:43 2005
@@ -0,0 +1,83 @@
+/*
+ *   @(#) $Id$
+ *
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed 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.mina.examples.echoserver.ssl;
+
+import java.security.InvalidAlgorithmParameterException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.cert.CertificateException;
+import java.security.cert.X509Certificate;
+
+import javax.net.ssl.ManagerFactoryParameters;
+import javax.net.ssl.TrustManager;
+import javax.net.ssl.TrustManagerFactorySpi;
+import javax.net.ssl.X509TrustManager;
+
+/**
+ * Bogus trust manager factory. Creates BogusX509TrustManager
+ *
+ * @author Per Widerlund (per@minq.se)
+ * @author Jan Andersson (janne@minq.se)
+ * 
+ * @version $Rev$, $Date$
+ */
+class BogusTrustManagerFactory extends TrustManagerFactorySpi
+{
+
+    static final X509TrustManager X509 = new X509TrustManager()
+    {
+        public void checkClientTrusted( X509Certificate[] x509Certificates,
+                                       String s ) throws CertificateException
+        {
+        }
+
+        public void checkServerTrusted( X509Certificate[] x509Certificates,
+                                       String s ) throws CertificateException
+        {
+        }
+
+        public X509Certificate[] getAcceptedIssuers()
+        {
+            return new X509Certificate[ 0 ];
+        }
+    };
+
+    static final TrustManager[] X509_MANAGERS = new TrustManager[] { X509 };
+
+    public BogusTrustManagerFactory()
+    {
+    }
+
+    protected TrustManager[] engineGetTrustManagers()
+    {
+        return X509_MANAGERS;
+    }
+
+    protected void engineInit( KeyStore keystore ) throws KeyStoreException
+    {
+        // noop
+    }
+
+    protected void engineInit(
+                              ManagerFactoryParameters managerFactoryParameters )
+            throws InvalidAlgorithmParameterException
+    {
+        // noop
+    }
+}

Propchange: incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/BogusTrustManagerFactory.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision

Added: incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/SSLServerSocketFactory.java
URL: http://svn.apache.org/viewcvs/incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/SSLServerSocketFactory.java?view=auto&rev=156507
==============================================================================
--- incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/SSLServerSocketFactory.java (added)
+++ incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/SSLServerSocketFactory.java Mon Mar  7 23:34:43 2005
@@ -0,0 +1,107 @@
+/*
+ *   @(#) $Id$
+ *
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed 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.mina.examples.echoserver.ssl;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.ServerSocket;
+import java.security.GeneralSecurityException;
+
+import javax.net.ServerSocketFactory;
+
+/**
+ * Simple Server Socket factory to create sockets with or without SSL enabled.
+ * If SSL enabled a "bougus" SSL Context is used (suitable for test purposes)
+ * 
+ * @version $Rev$, $Date$
+ */
+public class SSLServerSocketFactory extends javax.net.ServerSocketFactory
+{
+    private static boolean sslEnabled = false;
+
+    private static javax.net.ServerSocketFactory sslFactory = null;
+
+    private static ServerSocketFactory factory = null;
+
+    public SSLServerSocketFactory()
+    {
+        super();
+    }
+
+    public ServerSocket createServerSocket( int port ) throws IOException
+    {
+        return new ServerSocket( port );
+    }
+
+    public ServerSocket createServerSocket( int port, int backlog )
+            throws IOException
+    {
+        return new ServerSocket( port, backlog );
+    }
+
+    public ServerSocket createServerSocket( int port, int backlog,
+                                           InetAddress ifAddress )
+            throws IOException
+    {
+        return new ServerSocket( port, backlog, ifAddress );
+    }
+
+    public static javax.net.ServerSocketFactory getServerSocketFactory()
+            throws IOException
+    {
+        if( isSslEnabled() )
+        {
+            if( sslFactory == null )
+            {
+                try
+                {
+                    sslFactory = BogusSSLContextFactory.getInstance( true )
+                            .getServerSocketFactory();
+                }
+                catch( GeneralSecurityException e )
+                {
+                    IOException ioe = new IOException(
+                            "could not create SSL socket" );
+                    ioe.initCause( e );
+                    throw ioe;
+                }
+            }
+            return sslFactory;
+        }
+        else
+        {
+            if( factory == null )
+            {
+                factory = new SSLServerSocketFactory();
+            }
+            return factory;
+        }
+
+    }
+
+    public static boolean isSslEnabled()
+    {
+        return sslEnabled;
+    }
+
+    public static void setSslEnabled( boolean newSslEnabled )
+    {
+        sslEnabled = newSslEnabled;
+    }
+}

Propchange: incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/SSLServerSocketFactory.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision

Added: incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/SSLSocketFactory.java
URL: http://svn.apache.org/viewcvs/incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/SSLSocketFactory.java?view=auto&rev=156507
==============================================================================
--- incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/SSLSocketFactory.java (added)
+++ incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/SSLSocketFactory.java Mon Mar  7 23:34:43 2005
@@ -0,0 +1,137 @@
+/*
+ *   @(#) $Id$
+ *
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed 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.mina.examples.echoserver.ssl;
+
+import java.io.IOException;
+import java.net.InetAddress;
+import java.net.Socket;
+import java.net.UnknownHostException;
+import java.security.GeneralSecurityException;
+
+import javax.net.SocketFactory;
+
+/**
+ * Simple Socket factory to create sockets with or without SSL enabled.
+ * If SSL enabled a "bougus" SSL Context is used (suitable for test purposes)
+ * 
+ * @version $Rev$, $Date$
+ */
+public class SSLSocketFactory extends SocketFactory
+{
+    private static boolean sslEnabled = false;
+
+    private static javax.net.ssl.SSLSocketFactory sslFactory = null;
+
+    private static javax.net.SocketFactory factory = null;
+
+    public SSLSocketFactory()
+    {
+        super();
+    }
+
+    public Socket createSocket( String arg1, int arg2 ) throws IOException,
+            UnknownHostException
+    {
+        if( isSslEnabled() )
+        {
+            return getSSLFactory().createSocket( arg1, arg2 );
+        }
+        else
+        {
+            return new Socket( arg1, arg2 );
+        }
+    }
+
+    public Socket createSocket( String arg1, int arg2, InetAddress arg3,
+                               int arg4 ) throws IOException,
+            UnknownHostException
+    {
+        if( isSslEnabled() )
+        {
+            return getSSLFactory().createSocket( arg1, arg2, arg3, arg4 );
+        }
+        else
+        {
+            return new Socket( arg1, arg2, arg3, arg4 );
+        }
+    }
+
+    public Socket createSocket( InetAddress arg1, int arg2 )
+            throws IOException
+    {
+        if( isSslEnabled() )
+        {
+            return getSSLFactory().createSocket( arg1, arg2 );
+        }
+        else
+        {
+            return new Socket( arg1, arg2 );
+        }
+    }
+
+    public Socket createSocket( InetAddress arg1, int arg2, InetAddress arg3,
+                               int arg4 ) throws IOException
+    {
+        if( isSslEnabled() )
+        {
+            return getSSLFactory().createSocket( arg1, arg2, arg3, arg4 );
+        }
+        else
+        {
+            return new Socket( arg1, arg2, arg3, arg4 );
+        }
+    }
+
+    public static javax.net.SocketFactory getSocketFactory()
+    {
+        if( factory == null )
+        {
+            factory = new SSLSocketFactory();
+        }
+        return factory;
+    }
+
+    private javax.net.ssl.SSLSocketFactory getSSLFactory()
+    {
+        if( sslFactory == null )
+        {
+            try
+            {
+                sslFactory = BogusSSLContextFactory.getInstance( false )
+                        .getSocketFactory();
+            }
+            catch( GeneralSecurityException e )
+            {
+                throw new RuntimeException( "could not create SSL socket", e );
+            }
+        }
+        return sslFactory;
+    }
+
+    public static boolean isSslEnabled()
+    {
+        return sslEnabled;
+    }
+
+    public static void setSslEnabled( boolean newSslEnabled )
+    {
+        sslEnabled = newSslEnabled;
+    }
+
+}

Propchange: incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/SSLSocketFactory.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision

Added: incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/bogus.cert
URL: http://svn.apache.org/viewcvs/incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/bogus.cert?view=auto&rev=156507
==============================================================================
Binary file - no diff available.

Propchange: incubator/directory/network/mina/trunk/src/examples/org/apache/mina/examples/echoserver/ssl/bogus.cert
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLByteBufferPool.java
URL: http://svn.apache.org/viewcvs/incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLByteBufferPool.java?view=auto&rev=156507
==============================================================================
--- incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLByteBufferPool.java (added)
+++ incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLByteBufferPool.java Mon Mar  7 23:34:43 2005
@@ -0,0 +1,173 @@
+/*
+ *   @(#) $Id$
+ *
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed 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.mina.io.filter;
+
+import java.nio.ByteBuffer;
+
+import javax.net.ssl.SSLEngine;
+
+import org.apache.mina.util.Stack;
+
+/**
+ * Simple ByteBuffer pool used by SSLHandler.
+ * ByteBuffers are by default allocated as direct byte buffers. To use non-direct
+ * ByteBuffers, set system property mina.sslfilter.directbuffer to false.
+ *
+ * @author Jan Andersson (janne@minq.se)
+ * @version $Rev$, $Date$
+ */
+class SSLByteBufferPool
+{
+    private static final int PACKET_BUFFER_INDEX = 0;
+
+    private static final int APPLICATION_BUFFER_INDEX = 1;
+
+    private static boolean initiated = false;
+
+    private static final String DIRECT_MEMORY_PROP = "mina.sslfilter.directbuffer";
+
+    private static boolean useDirectAllocatedBuffers = true;
+
+    private static int packetBufferSize;
+
+    private static int appBufferSize;
+
+    private static int[] bufferStackSizes;
+
+    private static final Stack[] bufferStacks = new Stack[] { new Stack(),
+                                                             new Stack(), };
+
+    /**
+     * Initiate buffer pool and buffer sizes from SSLEngine session.
+     *
+     * @param sslEngine SSLEngine
+     */
+    static void initiate( SSLEngine sslEngine )
+    {
+        if( !initiated )
+        {
+            // Use direct allocated memory or not?
+            String prop = System.getProperty( DIRECT_MEMORY_PROP );
+            if( prop != null )
+            {
+                useDirectAllocatedBuffers = Boolean
+                        .getBoolean( DIRECT_MEMORY_PROP );
+            }
+            // init buffer sizes from SSLEngine
+            packetBufferSize = sslEngine.getSession().getPacketBufferSize();
+            appBufferSize = sslEngine.getSession().getApplicationBufferSize();
+            initiateBufferStacks();
+            initiated = true;
+        }
+    }
+
+    /**
+     * Get bytebuffer with size the size of the largest SSL/TLS packet that may occur
+     * (as defined by SSLSession).
+     */
+    static ByteBuffer getPacketBuffer()
+    {
+        if( !initiated )
+        {
+            throw new IllegalStateException( "Not initialized" );
+        }
+        return get( PACKET_BUFFER_INDEX );
+    }
+
+    /**
+     * Get ByteBuffer with the size of the largest application buffer that may occur
+     * (as defined by SSLSession).
+     */
+    static ByteBuffer getApplicationBuffer()
+    {
+        if( !initiated )
+        {
+            throw new IllegalStateException( "Not initialized" );
+        }
+        return get( APPLICATION_BUFFER_INDEX );
+    }
+
+    /**
+     * Get the buffer which is capable of the specified size.
+     */
+    private static ByteBuffer get( int idx )
+    {
+        Stack stack = bufferStacks[ idx ];
+
+        ByteBuffer buf;
+        synchronized( stack )
+        {
+            buf = ( ByteBuffer ) stack.pop();
+            if( buf == null )
+            {
+                buf = createBuffer( bufferStackSizes[ idx ] );
+            }
+        }
+
+        buf.clear();
+        return buf;
+    }
+
+    /**
+     * Returns the specified buffer to buffer pool.
+     */
+    public static void put( ByteBuffer buf )
+    {
+        Stack stack = bufferStacks[ getBufferStackIndex( buf.capacity() ) ];
+        synchronized( stack )
+        {
+            stack.push( buf );
+        }
+    }
+
+    private static void initiateBufferStacks()
+    {
+        bufferStackSizes = new int[ 2 ];
+        bufferStackSizes[ PACKET_BUFFER_INDEX ] = packetBufferSize;
+        bufferStackSizes[ APPLICATION_BUFFER_INDEX ] = appBufferSize;
+    }
+
+    private static int getBufferStackIndex( int size )
+    {
+        if( size == packetBufferSize )
+            return PACKET_BUFFER_INDEX;
+        if( size == appBufferSize )
+            return APPLICATION_BUFFER_INDEX;
+        throw new IllegalArgumentException( "Unknown buffer size: " + size );
+    }
+
+    private static ByteBuffer createBuffer( int capacity )
+    {
+        if( useDirectAllocatedBuffers )
+        {
+            try
+            {
+                return ByteBuffer.allocateDirect( capacity );
+            }
+            catch( OutOfMemoryError e )
+            {
+                useDirectAllocatedBuffers = false;
+                System.err
+                        .println( "OutOfMemoryError: No more direct buffers available; trying heap buffer instead" );
+            }
+        }
+        return ByteBuffer.allocate( capacity );
+    }
+
+}

Propchange: incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLByteBufferPool.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision

Added: incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLFilter.java
URL: http://svn.apache.org/viewcvs/incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLFilter.java?view=auto&rev=156507
==============================================================================
--- incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLFilter.java (added)
+++ incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLFilter.java Mon Mar  7 23:34:43 2005
@@ -0,0 +1,489 @@
+/*
+ *   @(#) $Id$
+ *
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed 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.mina.io.filter;
+
+import java.lang.reflect.Method;
+import java.text.DateFormat;
+import java.util.Date;
+import java.util.IdentityHashMap;
+import java.util.Map;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLException;
+import javax.net.ssl.SSLHandshakeException;
+
+import org.apache.mina.common.ByteBuffer;
+import org.apache.mina.io.DefaultExceptionMonitor;
+import org.apache.mina.io.IoHandler;
+import org.apache.mina.io.IoHandlerFilterAdapter;
+import org.apache.mina.io.IoSession;
+
+/**
+ * An SSL filter that encrypts and decrypts the data exchanged in the session.
+ * This filter uses an {@link SSLEngine} which was introduced in Java 5, so 
+ * Java version 5 or above is mandatory to use this filter. And please note that
+ * this filter only works for TCP/IP connections.
+ * <p>
+ * Jan Andersson kindly contributed this filter for the Apache Directory team.
+ * We thank him a lot for his significant contribution.
+ * 
+ * @author Jan Andersson (janne@minq.se)
+ * @author Trustin Lee (trustin@apache.org)
+ * @version $Rev$, $Date$
+ */
+public class SSLFilter extends IoHandlerFilterAdapter
+{
+    // SSL Context
+    private SSLContext sslContext;
+
+    // Map used to map SSLHandler objects per session (key is IoSession)
+    private Map sslSessionHandlerMap = new IdentityHashMap();
+
+    /** debug interface */
+    Debug debug = null;
+
+    /**
+     * Creates a new SSL filter using the specified {@link SSLContext}.
+     */
+    public SSLFilter( SSLContext sslContext )
+    {
+        if( sslContext == null )
+        {
+            throw new NullPointerException( "sslContext" );
+        }
+
+        this.sslContext = sslContext;
+    }
+
+    /**
+     * Sets the debug message auditter.
+     */
+    public void setDebug( Debug debug )
+    {
+        if( debug == null )
+        {
+            throw new NullPointerException( "debug" );
+        }
+
+        if( debug == Debug.OFF )
+        {
+            this.debug = null;
+        }
+        else
+        {
+            this.debug = debug;
+        }
+    }
+
+    /**
+     * Gets the debug message auditter.
+     */
+    public Debug getDebug()
+    {
+        if( debug == null )
+        {
+            return Debug.OFF;
+        }
+        else
+        {
+            return debug;
+        }
+    }
+
+    // IoHandlerFilter impl.
+
+    public void sessionOpened( IoHandler nextHandler, IoSession session )
+    {
+        nextHandler.sessionOpened( session );
+        // Create an SSL handler
+        createSSLSessionHandler( session );
+    }
+
+    public void sessionClosed( IoHandler nextHandler, IoSession session )
+    {
+        SSLHandler sslHandler = getSSLSessionHandler( session );
+        if( debug != null )
+        {
+            debug.print( "Closed: " + sslHandler );
+        }
+        if( sslHandler != null )
+        {
+            // Start SSL shutdown process
+            try
+            {
+                // shut down
+                sslHandler.shutdown();
+
+                // there might be data to write out here?
+                writeNetBuffer( session, sslHandler );
+            }
+            catch( SSLException ssle )
+            {
+                nextHandler.exceptionCaught( session, ssle );
+            }
+            finally
+            {
+                // notify closed session
+                nextHandler.sessionClosed( session );
+
+                // release buffers
+                sslHandler.release();
+                removeSSLSessionHandler( session );
+            }
+        }
+    }
+
+    public void dataRead( IoHandler nextHandler, IoSession session,
+                         ByteBuffer buf )
+    {
+        SSLHandler sslHandler = getSSLSessionHandler( session );
+        if( sslHandler != null )
+        {
+            synchronized( sslHandler )
+            {
+                try
+                {
+                    // forward read encrypted data to SSL handler
+                    sslHandler.dataRead( buf.buf() );
+
+                    // Handle data to be forwarded to application or written to net
+                    handleSSLData( nextHandler, session, sslHandler );
+                }
+                catch( SSLException ssle )
+                {
+                    if( !sslHandler.isInitialHandshakeComplete() )
+                    {
+                        SSLException newSSLE = new SSLHandshakeException(
+                                "Initial SSL handshake failed." );
+                        newSSLE.initCause( ssle );
+                        ssle = newSSLE;
+                    }
+
+                    nextHandler.exceptionCaught( session, ssle );
+                }
+            }
+        }
+        else
+        {
+            nextHandler.dataRead( session, buf );
+        }
+    }
+
+    public void dataWritten( IoHandler nextHandler, IoSession session,
+                            Object marker )
+    {
+        nextHandler.dataWritten( session, marker );
+    }
+
+    public ByteBuffer filterWrite( IoSession session, ByteBuffer buf )
+    {
+
+        SSLHandler sslHandler = getSSLSessionHandler( session );
+        if( sslHandler != null )
+        {
+            synchronized( sslHandler )
+            {
+                if( sslHandler.isWritingEncryptedData() )
+                {
+                    // data already encrypted; simply return buffer
+                    if( debug != null )
+                    {
+                        debug.print( "  already encrypted: " + buf );
+                    }
+                    return buf;
+                }
+                if( sslHandler.isInitialHandshakeComplete() )
+                {
+                    // SSL encrypt
+                    try
+                    {
+                        if( debug != null )
+                        {
+                            debug.print( "encrypt: " + buf );
+                        }
+                        sslHandler.encrypt( buf.buf() );
+                        ByteBuffer encryptedBuffer = copy( sslHandler
+                                .getOutNetBuffer() );
+                        //debug("encrypted data: {0}", encryptedBuffer.getHexDump());
+                        return encryptedBuffer;
+                    }
+                    catch( SSLException ssle )
+                    {
+                        throw new RuntimeException(
+                                "Unexpected SSLException.", ssle );
+                    }
+                }
+            }
+        }
+        return buf;
+    }
+
+    // Utiliities
+    private void handleSSLData( IoHandler nextHandler, IoSession session,
+                               SSLHandler sslHandler ) throws SSLException
+    {
+        // First write encrypted data to be written (if any)
+        writeNetBuffer( session, sslHandler );
+        // handle app. data read (if any)
+        handleAppDataRead( nextHandler, session, sslHandler );
+    }
+
+    private void handleAppDataRead( IoHandler nextHandler, IoSession session,
+                                   SSLHandler sslHandler )
+    {
+        if( debug != null )
+        {
+            debug.print( "appBuffer: " + sslHandler.getAppBuffer() );
+        }
+        if( sslHandler.getAppBuffer().hasRemaining() )
+        {
+            // forward read app data
+            ByteBuffer readBuffer = copy( sslHandler.getAppBuffer() );
+            if( debug != null )
+            {
+                debug.print( "app data read: " + readBuffer );
+            }
+            //debug("app data: {0}", readBuffer.getHexDump());
+            nextHandler.dataRead( session, readBuffer );
+        }
+    }
+
+    private void writeNetBuffer( IoSession session, SSLHandler sslHandler )
+            throws SSLException
+    {
+        // first check if any net data needed to be writen
+        if( !sslHandler.getOutNetBuffer().hasRemaining() )
+        {
+            // no; bail out
+            return;
+        }
+
+        // write net data
+
+        // set flag that we are writing encrypted data
+        // (used in filterWrite() above)
+        synchronized( sslHandler )
+        {
+            sslHandler.setWritingEncryptedData( true );
+        }
+
+        try
+        {
+            if( debug != null )
+            {
+                debug.print( "write outNetBuffer: "
+                        + sslHandler.getOutNetBuffer() );
+            }
+            ByteBuffer writeBuffer = copy( sslHandler.getOutNetBuffer() );
+            if( debug != null )
+            {
+                debug.print( "session write: " + writeBuffer );
+            }
+            //debug("outNetBuffer (after copy): {0}", sslHandler.getOutNetBuffer());
+            session.write( writeBuffer, null );
+
+            // loop while more writes required to complete handshake
+            while( sslHandler.needToCompleteInitialHandshake() )
+            {
+                try
+                {
+                    sslHandler.continueHandshake();
+                }
+                catch( SSLException ssle )
+                {
+                    SSLException newSSLE = new SSLHandshakeException(
+                            "Initial SSL handshake failed." );
+                    newSSLE.initCause( ssle );
+                    throw newSSLE;
+                }
+                if( sslHandler.getOutNetBuffer().hasRemaining() )
+                {
+                    if( debug != null )
+                    {
+                        debug.print( "write outNetBuffer2: "
+                                + sslHandler.getOutNetBuffer() );
+                    }
+                    ByteBuffer writeBuffer2 = copy( sslHandler
+                            .getOutNetBuffer() );
+                    session.write( writeBuffer2, null );
+                }
+            }
+        }
+        finally
+        {
+            synchronized( sslHandler )
+            {
+                sslHandler.setWritingEncryptedData( false );
+            }
+        }
+    }
+
+    /**
+     * Creates a new Mina byte buffer that is a deep copy of the remaining bytes
+     * in the given buffer (between index buf.position() and buf.limit())
+     *
+     * @param src the buffer to copy
+     * @return the new buffer, ready to read from
+     */
+    private ByteBuffer copy( java.nio.ByteBuffer src )
+    {
+        ByteBuffer copy = ByteBuffer.allocate( src.remaining() );
+        copy.put( src );
+        copy.flip();
+        return copy;
+    }
+
+    // Utilities to mainpulate SSLHandler based on IoSession
+
+    private SSLHandler createSSLSessionHandler( IoSession session )
+    {
+        SSLHandler sslHandler = new SSLHandler( this, sslContext );
+        synchronized( sslSessionHandlerMap )
+        {
+            sslSessionHandlerMap.put( session, sslHandler );
+        }
+        return sslHandler;
+    }
+
+    private SSLHandler getSSLSessionHandler( IoSession session )
+    {
+        return ( SSLHandler ) sslSessionHandlerMap.get( session );
+    }
+
+    private void removeSSLSessionHandler( IoSession session )
+    {
+        synchronized( sslSessionHandlerMap )
+        {
+            sslSessionHandlerMap.remove( session );
+        }
+    }
+
+    /**
+     * An interface that users can log debug messages from an {@link SSLFilter}.
+     * 
+     * @author Trustin Lee (trustin@apache.org)
+     * @version $Rev$, $Date$
+     */
+    public static interface Debug
+    {
+        /**
+         * This will print out the messages to Commons-Logging or stdout.
+         */
+        static final Debug ON = new DebugOn();
+        
+        /**
+         * This will suppress debug messages.
+         */
+        static final Debug OFF = new DebugOff();
+
+        /**
+         * Prints out the specified debug messages.
+         */
+        void print( String message );
+    }
+
+    private static class DebugOn implements Debug
+    {
+        private static final Object log;
+
+        private static final Method debugMethod;
+
+        static
+        {
+            Object tempLog = null;
+            Method tempDebugMethod = null;
+
+            try
+            {
+                Class logCls = Class
+                        .forName( "org.apache.commons.logging.Log" );
+                Class logFactoryCls = Class
+                        .forName( "org.apache.commons.logging.LogFactory" );
+                Method getLogMethod = logFactoryCls.getMethod( "getLog",
+                        new Class[] { String.class } );
+                tempLog = getLogMethod.invoke( null,
+                        new Object[] { DefaultExceptionMonitor.class
+                                .getPackage().getName() } );
+                tempDebugMethod = logCls.getMethod( "debug",
+                        new Class[] { Object.class } );
+            }
+            catch( Exception e )
+            {
+                tempLog = null;
+                tempDebugMethod = null;
+            }
+
+            log = tempLog;
+            debugMethod = tempDebugMethod;
+        }
+
+        private final DateFormat df = DateFormat.getDateTimeInstance(
+                DateFormat.MEDIUM, DateFormat.MEDIUM );
+
+        private final Date date = new Date();
+
+        public void print( String message )
+        {
+            if( log == null )
+            {
+                logToStdOut( message );
+            }
+            else
+            {
+                logToCommonsLogging( message );
+            }
+        }
+
+        private void logToCommonsLogging( String message )
+        {
+            try
+            {
+                debugMethod.invoke( log, new Object[] { message } );
+            }
+            catch( Exception e )
+            {
+                logToStdOut( message );
+            }
+        }
+
+        private void logToStdOut( String message )
+        {
+            synchronized( System.out )
+            {
+                date.setTime( System.currentTimeMillis() );
+
+                System.out.print( '[' );
+                System.out.print( df.format( date ) );
+                System.out.print( "] [" );
+                System.out.print( Thread.currentThread().getName() );
+                System.out.print( "] " );
+                System.out.println( message );
+            }
+        }
+    }
+
+    private static class DebugOff implements Debug
+    {
+        public void print( String message )
+        {
+            // do nothing
+        }
+    }
+}

Propchange: incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLFilter.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision

Added: incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLHandler.java
URL: http://svn.apache.org/viewcvs/incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLHandler.java?view=auto&rev=156507
==============================================================================
--- incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLHandler.java (added)
+++ incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLHandler.java Mon Mar  7 23:34:43 2005
@@ -0,0 +1,491 @@
+/*
+ *   @(#) $Id$
+ *
+ *   Copyright 2004 The Apache Software Foundation
+ *
+ *   Licensed 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.mina.io.filter;
+
+import java.nio.ByteBuffer;
+
+import javax.net.ssl.SSLContext;
+import javax.net.ssl.SSLEngine;
+import javax.net.ssl.SSLEngineResult;
+import javax.net.ssl.SSLException;
+
+/**
+ * A helper class using the SSLEngine API to decrypt/encrypt data.
+ * <p>
+ * Each connection has a SSLEngine that is used through the lifetime of the connection.
+ * We allocate byte buffers for use as the outbound and inbound network buffers.
+ * These buffers handle all of the intermediary data for the SSL connection. To make things easy,
+ * we'll require outNetBuffer be completely flushed before trying to wrap any more data.
+ *
+ * @author Jan Andersson (janne@minq.se)
+ * @version $Rev$, $Date$
+ */
+class SSLHandler
+{
+    private final SSLFilter parent;
+
+    private SSLEngine sslEngine;
+
+    /**
+     * Encrypted data from the net
+     */
+    private ByteBuffer inNetBuffer;
+
+    /**
+     * Encrypted data to be written to the net
+     */
+    private ByteBuffer outNetBuffer;
+
+    /**
+     * Applicaton cleartext data to be read by application
+     */
+    private ByteBuffer appBuffer;
+
+    /**
+     * Empty buffer used during initial handshake and close operations
+     */
+    private static ByteBuffer hsBB = ByteBuffer.allocate( 0 );
+
+    /**
+     * Handshake status
+     */
+    private SSLEngineResult.HandshakeStatus initialHandshakeStatus;
+
+    /**
+     * Initial handshake complete?
+     */
+    private boolean initialHandshakeComplete;
+
+    /**
+     * We have received the shutdown request by our caller, and have
+     * closed our outbound side.
+     */
+    private boolean shutdown = false;
+
+    private boolean closed = false;
+
+    private boolean isWritingEncryptedData = false;
+
+    /**
+     * Constuctor.
+     *
+     * @param sslc
+     */
+    protected SSLHandler( SSLFilter parent, SSLContext sslc )
+    {
+        this.parent = parent;
+        sslEngine = sslc.createSSLEngine();
+        sslEngine.setUseClientMode( false );
+        initialHandshakeStatus = SSLEngineResult.HandshakeStatus.NEED_UNWRAP;
+        initialHandshakeComplete = false;
+
+        SSLByteBufferPool.initiate( sslEngine );
+
+        appBuffer = SSLByteBufferPool.getApplicationBuffer();
+
+        inNetBuffer = SSLByteBufferPool.getPacketBuffer();
+        outNetBuffer = SSLByteBufferPool.getPacketBuffer();
+        outNetBuffer.position( 0 );
+        outNetBuffer.limit( 0 );
+    }
+
+    /**
+     * Indicate that we are writing encrypted data.
+     * Only used as a flag by IoSSLFiler
+     */
+    public void setWritingEncryptedData( boolean flag )
+    {
+        isWritingEncryptedData = flag;
+    }
+
+    /**
+     * Check we are writing encrypted data.
+     */
+    public boolean isWritingEncryptedData()
+    {
+        return isWritingEncryptedData;
+    }
+
+    /**
+     * Check if initial handshake is completed.
+     */
+    public boolean isInitialHandshakeComplete()
+    {
+        return initialHandshakeComplete;
+    }
+
+    /**
+     * Check if there is any need to complete initial handshake.
+     */
+    public boolean needToCompleteInitialHandshake()
+    {
+        return ( initialHandshakeStatus == SSLEngineResult.HandshakeStatus.NEED_WRAP && !closed );
+    }
+
+    /**
+     * Call when data read from net. Will perform inial hanshake or decrypt provided
+     * Buffer.
+     * Decrytpted data reurned by getAppBuffer(), if any.
+     *
+     * @param buf buffer to decrypt
+     * @throws SSLException on errors
+     */
+    public void dataRead( ByteBuffer buf ) throws SSLException
+    {
+        // append buf to inNetBuffer
+        inNetBuffer.put( buf );
+        if( !initialHandshakeComplete )
+        {
+            doHandshake();
+        }
+        else
+        {
+            doDecrypt();
+        }
+    }
+
+    /**
+     * Continue initial SSL handshake.
+     *
+     * @throws SSLException on errors
+     */
+    public void continueHandshake() throws SSLException
+    {
+        if( parent.debug != null )
+        {
+            parent.debug.print( "continueHandshake()" );
+        }
+        doHandshake();
+    }
+
+    /**
+     * Get decrypted application data.
+     *
+     * @return buffer with data
+     */
+    public ByteBuffer getAppBuffer()
+    {
+        return appBuffer;
+    }
+
+    /**
+     * Get encrypted data to be sent.
+     *
+     * @return buffer with data
+     */
+    public ByteBuffer getOutNetBuffer()
+    {
+        return outNetBuffer;
+    }
+
+    /**
+     * Encrypt provided buffer. Encytpted data reurned by getOutNetBuffer().
+     *
+     * @param buf data to encrypt
+     * @throws SSLException on errors
+     */
+    public void encrypt( ByteBuffer buf ) throws SSLException
+    {
+        doEncrypt( buf );
+    }
+
+    /**
+     * Start SSL shutdown process
+     *
+     * @throws SSLException on errors
+     */
+    public void shutdown() throws SSLException
+    {
+        doShutdown();
+    }
+
+    /**
+     * Release allocated ByteBuffers.
+     */
+    public void release()
+    {
+        SSLByteBufferPool.put( appBuffer );
+        SSLByteBufferPool.put( inNetBuffer );
+        SSLByteBufferPool.put( outNetBuffer );
+    }
+
+    /**
+     * Decrypt in net buffer. Result is stored in app buffer.
+     *
+     * @throws SSLException
+     */
+    private void doDecrypt() throws SSLException
+    {
+
+        if( !initialHandshakeComplete )
+        {
+            throw new IllegalStateException();
+        }
+
+        if( appBuffer.hasRemaining() )
+        {
+            //still app data in buffer!?
+            throw new IllegalStateException();
+        }
+
+        SSLEngineResult.Status status = unwrap();
+        if( status != SSLEngineResult.Status.OK
+                && status != SSLEngineResult.Status.CLOSED )
+        {
+            throw new SSLException( "Unexpected SSLEngineResult: " + status );
+        }
+    }
+
+    private void doEncrypt( ByteBuffer src ) throws SSLException
+    {
+        if( !initialHandshakeComplete )
+        {
+            throw new IllegalStateException();
+        }
+
+        // The data buffer is (must be) empty, we can reuse the entire buffer.
+        outNetBuffer.clear();
+
+        SSLEngineResult result = sslEngine.wrap( src, outNetBuffer );
+
+        outNetBuffer.flip();
+
+        switch( result.getStatus() )
+        {
+
+        case OK:
+            if( result.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK )
+            {
+                doTasks();
+            }
+            break;
+
+        default:
+            throw new SSLException( "SSLEngine error during data write: "
+                    + result.getStatus() );
+        }
+    }
+
+    /**
+     * Perform any handshaking processing.
+     */
+    void doHandshake() throws SSLException
+    {
+
+        if( parent.debug != null )
+        {
+            parent.debug.print( "doHandshake()" );
+        }
+        while( true )
+        {
+            switch( initialHandshakeStatus )
+            {
+            case FINISHED:
+                if( parent.debug != null )
+                {
+                    parent.debug.print( " initialHandshakeStatus=FINISHED" );
+                }
+                initialHandshakeComplete = true;
+                return;
+            case NEED_TASK:
+                if( parent.debug != null )
+                {
+                    parent.debug.print( " initialHandshakeStatus=NEED_TASK" );
+                }
+                initialHandshakeStatus = doTasks();
+                break;
+            case NEED_UNWRAP:
+                // we need more data read
+                if( parent.debug != null )
+                {
+                    parent.debug
+                            .print( " initialHandshakeStatus=NEED_UNWRAP" );
+                }
+                SSLEngineResult.Status status = unwrap();
+                if( status == SSLEngineResult.Status.BUFFER_UNDERFLOW )
+                {
+                    // We need more data
+                    return;
+                }
+                break;
+            case NEED_WRAP:
+                if( parent.debug != null )
+                {
+                    parent.debug.print( " initialHandshakeStatus=NEED_WRAP" );
+                }
+                // First make sure that the out buffer is completely empty. Since we
+                // cannot call wrap with data left on the buffer
+                if( outNetBuffer.hasRemaining() )
+                {
+                    if( parent.debug != null )
+                    {
+                        parent.debug.print( " Still data in out buffer!" );
+                    }
+                    return;
+                }
+                outNetBuffer.clear();
+                SSLEngineResult result = sslEngine.wrap( hsBB, outNetBuffer );
+                outNetBuffer.flip();
+                initialHandshakeStatus = result.getHandshakeStatus();
+                // return to allow data on out buffer being sent
+                // TODO: We might want to send more data immidiatley?
+                break;
+            //return;
+            default: // NOT_HANDSHAKING
+                throw new IllegalStateException( "Invalid Handshaking State"
+                        + initialHandshakeStatus );
+            }
+        }
+    }
+
+    SSLEngineResult.Status unwrap() throws SSLException
+    {
+        if( parent.debug != null )
+        {
+            parent.debug.print( "unwrap()" );
+        }
+        // Prepare the application buffer to receive decrypted data
+        appBuffer.clear();
+
+        SSLEngineResult res;
+        do
+        {
+            // Prepare the net data for reading.
+            inNetBuffer.flip();
+
+            if( parent.debug != null )
+            {
+                parent.debug.print( "  inNetBuffer: " + inNetBuffer );
+                parent.debug.print( "  appBuffer: " + appBuffer );
+            }
+            res = sslEngine.unwrap( inNetBuffer, appBuffer );
+            if( parent.debug != null )
+            {
+                parent.debug.print( "Unwrap res:" + res );
+            }
+            // prepare to be written again
+            inNetBuffer.compact();
+
+            /*
+             * Could check here for a renegotation, but we're only
+             * doing a simple read/write, and won't have enough state
+             * transitions to do a complete handshake, so ignore that
+             * possibility.
+             */
+            switch( res.getStatus() )
+            {
+
+            case BUFFER_UNDERFLOW:
+            case OK:
+                if( res.getHandshakeStatus() == SSLEngineResult.HandshakeStatus.NEED_TASK )
+                {
+                    doTasks();
+                }
+                break;
+            case CLOSED:
+                if( parent.debug != null )
+                {
+                    parent.debug.print( "Closed while unwrapping" );
+                }
+                break;
+            default:
+                throw new SSLException( "SSLEngine error during data read: "
+                        + res.getStatus() );
+            }
+
+        }
+        while( ( inNetBuffer.position() != 0 )
+                && res.getStatus() != SSLEngineResult.Status.BUFFER_UNDERFLOW );
+
+        // If we are CLOSED, set flag
+        if( res.getStatus() == SSLEngineResult.Status.CLOSED )
+        {
+            closed = true;
+        }
+
+        // prepare app datat to be read
+        appBuffer.flip();
+
+        /*
+         * The status may be:
+         * OK - Normal operation
+         * OVERFLOW - Should never happen since the application buffer is
+         *      sized to hold the maximum packet size.
+         * UNDERFLOW - Need to read more data from the socket. It's normal.
+         * CLOSED - The other peer closed the socket. Also normal.
+         */
+        initialHandshakeStatus = res.getHandshakeStatus();
+        return res.getStatus();
+    }
+
+    /**
+     * Do all the outstanding handshake tasks in the current Thread.
+     */
+    private SSLEngineResult.HandshakeStatus doTasks()
+    {
+        if( parent.debug != null )
+        {
+            parent.debug.print( "  doTasks()" );
+        }
+
+        /*
+         * We could run this in a separate thread, but I don't see the need
+         * for this when used from IoSSLFilter.Use thread filters in Mina instead?
+         */
+        Runnable runnable;
+        while( ( runnable = sslEngine.getDelegatedTask() ) != null )
+        {
+            if( parent.debug != null )
+            {
+                parent.debug.print( "   doTask: " + runnable );
+            }
+            runnable.run();
+        }
+        if( parent.debug != null )
+        {
+            parent.debug.print( "  doTasks(): "
+                    + sslEngine.getHandshakeStatus() );
+        }
+        return sslEngine.getHandshakeStatus();
+    }
+
+    /**
+     * Begin the shutdown process.
+     */
+    void doShutdown() throws SSLException
+    {
+
+        if( !shutdown )
+        {
+            sslEngine.closeOutbound();
+            shutdown = true;
+        }
+
+        // By RFC 2616, we can "fire and forget" our close_notify
+        // message, so that's what we'll do here.
+
+        outNetBuffer.clear();
+        SSLEngineResult result = sslEngine.wrap( hsBB, outNetBuffer );
+        if( result.getStatus() != SSLEngineResult.Status.CLOSED )
+        {
+            throw new SSLException( "Improper close state: " + result );
+        }
+        outNetBuffer.flip();
+    }
+}

Propchange: incubator/directory/network/mina/trunk/src/java/org/apache/mina/io/filter/SSLHandler.java
------------------------------------------------------------------------------
    svn:keywords = HeadURL Id LastChangedBy LastChangedDate LastChangedRevision

Modified: incubator/directory/network/mina/trunk/src/test/org/apache/mina/examples/echoserver/Test.java
URL: http://svn.apache.org/viewcvs/incubator/directory/network/mina/trunk/src/test/org/apache/mina/examples/echoserver/Test.java?view=diff&r1=156506&r2=156507
==============================================================================
--- incubator/directory/network/mina/trunk/src/test/org/apache/mina/examples/echoserver/Test.java (original)
+++ incubator/directory/network/mina/trunk/src/test/org/apache/mina/examples/echoserver/Test.java Mon Mar  7 23:34:43 2005
@@ -6,15 +6,25 @@
 import java.io.IOException;
 import java.net.InetAddress;
 import java.net.InetSocketAddress;
+import java.net.ServerSocket;
+import java.net.Socket;
 import java.net.SocketTimeoutException;
+import java.net.UnknownHostException;
+
+import javax.net.ServerSocketFactory;
+import javax.net.SocketFactory;
 
 import junit.framework.TestCase;
 
 import org.apache.commons.net.EchoTCPClient;
 import org.apache.commons.net.EchoUDPClient;
+import org.apache.mina.examples.echoserver.ssl.BogusSSLContextFactory;
+import org.apache.mina.examples.echoserver.ssl.SSLServerSocketFactory;
+import org.apache.mina.examples.echoserver.ssl.SSLSocketFactory;
 import org.apache.mina.io.IoAcceptor;
 import org.apache.mina.io.datagram.DatagramAcceptor;
 import org.apache.mina.io.filter.IoThreadPoolFilter;
+import org.apache.mina.io.filter.SSLFilter;
 import org.apache.mina.io.socket.SocketAcceptor;
 
 /**
@@ -27,7 +37,7 @@
 {
     private int port;
 
-    private IoAcceptor acceptor;
+    protected IoAcceptor acceptor;
 
     private IoAcceptor datagramAcceptor;
 
@@ -57,7 +67,7 @@
         // Find an availble test port and bind to it.
         boolean socketBound = false;
         boolean datagramBound = false;
-        
+
         // Let's start from port #1 to detect possible resource leak
         // because test will fail in port 1-1023 if user run this test
         // as a normal user.
@@ -122,6 +132,69 @@
     public void testTCP() throws Exception
     {
         EchoTCPClient client = new EchoTCPClient();
+        testTCP0( client );
+    }
+
+    public void testTCPWithSSL() throws Exception
+    {
+        // Add an SSL filter
+        SSLFilter sslFilter = new SSLFilter( BogusSSLContextFactory.getInstance( true ) );
+        sslFilter.setDebug( SSLFilter.Debug.ON );
+        acceptor.addFilter( Integer.MAX_VALUE - 1, sslFilter );
+        
+        // Create a commons-net socket factory
+        SSLSocketFactory.setSslEnabled(true);
+        SSLServerSocketFactory.setSslEnabled(true);
+        org.apache.commons.net.SocketFactory factory = new org.apache.commons.net.SocketFactory() {
+
+            private SocketFactory f = SSLSocketFactory.getSocketFactory();
+            private ServerSocketFactory ssf = SSLServerSocketFactory.getServerSocketFactory();
+
+            public Socket createSocket( String arg0, int arg1 ) throws UnknownHostException, IOException
+            {
+                return f.createSocket(arg0, arg1);
+            }
+
+            public Socket createSocket( InetAddress arg0, int arg1 ) throws IOException
+            {
+                return f.createSocket(arg0, arg1);
+            }
+
+            public Socket createSocket( String arg0, int arg1, InetAddress arg2, int arg3 ) throws UnknownHostException, IOException
+            {
+                return f.createSocket(arg0, arg1, arg2, arg3);
+            }
+
+            public Socket createSocket( InetAddress arg0, int arg1, InetAddress arg2, int arg3 ) throws IOException
+            {
+                return f.createSocket(arg0, arg1, arg2, arg3);
+            }
+
+            public ServerSocket createServerSocket( int arg0 ) throws IOException
+            {
+                return ssf.createServerSocket(arg0);
+            }
+
+            public ServerSocket createServerSocket( int arg0, int arg1 ) throws IOException
+            {
+                return ssf.createServerSocket(arg0, arg1);
+            }
+
+            public ServerSocket createServerSocket( int arg0, int arg1, InetAddress arg2 ) throws IOException
+            {
+                return ssf.createServerSocket(arg0, arg1, arg2);
+            }
+            
+        };
+        
+        // Create a echo client with SSL factory and test it.
+        EchoTCPClient client = new EchoTCPClient();
+        client.setSocketFactory( factory );
+        testTCP0( client );
+    }
+    
+    private void testTCP0( EchoTCPClient client ) throws Exception
+    {
         client.connect( InetAddress.getLocalHost(), port );
         client.setSoTimeout( 3000 );
 

Modified: incubator/directory/network/mina/trunk/xdocs/index.xml
URL: http://svn.apache.org/viewcvs/incubator/directory/network/mina/trunk/xdocs/index.xml?view=diff&r1=156506&r2=156507
==============================================================================
--- incubator/directory/network/mina/trunk/xdocs/index.xml (original)
+++ incubator/directory/network/mina/trunk/xdocs/index.xml Mon Mar  7 23:34:43 2005
@@ -47,7 +47,7 @@
                     </tr>
                     <tr>
                         <td><a target="classFrame" href="xref-examples/org/apache/mina/examples/echoserver/package-summary.html">Echo server</a></td>
-                        <td>Low-level I/O layer</td>
+                        <td>Low-level I/O layer and SSL support</td>
                         <td>Server</td>
                     </tr>
                     <tr>



Mime
View raw message