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 ([EMAIL PROTECTED])
- * @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 ([EMAIL PROTECTED])
+ * @author Jan Andersson ([EMAIL PROTECTED])
+ *
+ * @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 ([EMAIL PROTECTED])
+ * @author Jan Andersson ([EMAIL PROTECTED])
+ *
+ * @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 ([EMAIL PROTECTED])
+ * @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 [EMAIL PROTECTED] 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 ([EMAIL PROTECTED])
+ * @author Trustin Lee ([EMAIL PROTECTED])
+ * @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 [EMAIL PROTECTED]
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 [EMAIL
PROTECTED] SSLFilter}.
+ *
+ * @author Trustin Lee ([EMAIL PROTECTED])
+ * @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 ([EMAIL PROTECTED])
+ * @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>