You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@activemq.apache.org by ta...@apache.org on 2010/05/25 22:17:27 UTC

svn commit: r948196 - in /activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf: internal/net/ssl/openssl/OpenSSLSocket.cpp internal/net/ssl/openssl/OpenSSLSocket.h net/ssl/SSLSocket.h

Author: tabish
Date: Tue May 25 20:17:26 2010
New Revision: 948196

URL: http://svn.apache.org/viewvc?rev=948196&view=rev
Log:
https://issues.apache.org/activemq/browse/AMQCPP-140

Add code to allow the OpenSSLSocket to be used as either a client or a server based socket.  

Modified:
    activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/internal/net/ssl/openssl/OpenSSLSocket.cpp
    activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/internal/net/ssl/openssl/OpenSSLSocket.h
    activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/net/ssl/SSLSocket.h

Modified: activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/internal/net/ssl/openssl/OpenSSLSocket.cpp
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/internal/net/ssl/openssl/OpenSSLSocket.cpp?rev=948196&r1=948195&r2=948196&view=diff
==============================================================================
--- activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/internal/net/ssl/openssl/OpenSSLSocket.cpp (original)
+++ activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/internal/net/ssl/openssl/OpenSSLSocket.cpp Tue May 25 20:17:26 2010
@@ -35,6 +35,7 @@
 #include <decaf/internal/net/ssl/openssl/OpenSSLSocketException.h>
 #include <decaf/internal/net/ssl/openssl/OpenSSLSocketInputStream.h>
 #include <decaf/internal/net/ssl/openssl/OpenSSLSocketOutputStream.h>
+#include <decaf/util/concurrent/Mutex.h>
 
 using namespace decaf;
 using namespace decaf::lang;
@@ -42,6 +43,7 @@ using namespace decaf::lang::exceptions;
 using namespace decaf::io;
 using namespace decaf::net;
 using namespace decaf::net::ssl;
+using namespace decaf::util::concurrent;
 using namespace decaf::internal;
 using namespace decaf::internal::net;
 using namespace decaf::internal::net::ssl;
@@ -64,10 +66,17 @@ namespace openssl {
 #endif
         bool needsClientAuth;
         bool wantsClientAuth;
+        bool useClientMode;
+        bool handshakeStarted;
+        bool handshakeCompleted;
+        std::string commonName;
+
+        Mutex handshakeLock;
 
     public:
 
-        SocketData() : ssl( NULL ), needsClientAuth( false ), wantsClientAuth( false ) {
+        SocketData() : ssl( NULL ), needsClientAuth( false ), wantsClientAuth( false ),
+                       useClientMode( true ), handshakeStarted( false ), handshakeCompleted( false ) {
         }
 
         ~SocketData() {
@@ -139,7 +148,12 @@ void OpenSSLSocket::connect( const std::
     try{
 
 #ifdef HAVE_OPENSSL
+
+        // Perform the actual Socket connection work
         SSLSocket::connect( host, port, timeout );
+
+        // If we actually connected then we can connect the Socket to an OpenSSL
+        // BIO filter so that we can use it in OpenSSL APIs.
         if( isConnected() ) {
 
             BIO* bio = BIO_new( BIO_s_socket() );
@@ -159,26 +173,9 @@ void OpenSSLSocket::connect( const std::
             BIO_set_fd( bio, (int)fd->getValue(), BIO_NOCLOSE );
             SSL_set_bio( this->data->ssl, bio, bio );
 
-            // Since we are a client we want to enforce peer verification, we set a
-            // callback so we can collect data on why a verify failed for debugging.
-            SSL_set_verify( this->data->ssl, SSL_VERIFY_PEER, SocketData::verifyCallback );
-
-            int result = SSL_connect( this->data->ssl );
-
-            // Checks the error status, when things go right we still perform a deeper
-            // check on the provided certificate to ensure that it matches the host name
-            // that we connected to, this prevents someone from using any certificate
-            // signed by a signing authority that we trust.
-            switch( SSL_get_error( this->data->ssl, result ) ) {
-                case SSL_ERROR_NONE:
-                    verifyServerCert( host );
-                    return;
-                case SSL_ERROR_SSL:
-                case SSL_ERROR_ZERO_RETURN:
-                case SSL_ERROR_SYSCALL:
-                    SSLSocket::close();
-                    throw OpenSSLSocketException( __FILE__, __LINE__ );
-            }
+            // Later when startHandshake is called we will check for this common name
+            // in the provided certificate
+            this->data->commonName = host;
         }
 #else
         throw SocketException( __FILE__, __LINE__, "Not Supported" );
@@ -310,6 +307,123 @@ void OpenSSLSocket::setEnabledProtocols(
 }
 
 ////////////////////////////////////////////////////////////////////////////////
+void OpenSSLSocket::startHandshake() {
+
+    if( !this->isConnected() ) {
+        throw IOException( __FILE__, __LINE__, "Socket is not connected." );
+    }
+
+    if( this->isClosed() ) {
+        throw IOException( __FILE__, __LINE__, "Socket already closed." );
+    }
+
+    try {
+
+        synchronized( &(this->data->handshakeLock ) ) {
+
+            if( this->data->handshakeStarted ) {
+                return;
+            }
+
+            this->data->handshakeStarted = true;
+
+            if( this->data->useClientMode ) {
+
+                // Since we are a client we want to enforce peer verification, we set a
+                // callback so we can collect data on why a verify failed for debugging.
+                SSL_set_verify( this->data->ssl, SSL_VERIFY_PEER, SocketData::verifyCallback );
+
+                int result = SSL_connect( this->data->ssl );
+
+                // Checks the error status, when things go right we still perform a deeper
+                // check on the provided certificate to ensure that it matches the host name
+                // that we connected to, this prevents someone from using any certificate
+                // signed by a signing authority that we trust.
+                switch( SSL_get_error( this->data->ssl, result ) ) {
+                    case SSL_ERROR_NONE:
+                        verifyServerCert( this->data->commonName );
+                        std::cout << "OpenSSLSocket::startHandshake() - Verified name: "
+                                  << this->data->commonName << std::endl;
+                        break;
+                    case SSL_ERROR_SSL:
+                    case SSL_ERROR_ZERO_RETURN:
+                    case SSL_ERROR_SYSCALL:
+                        SSLSocket::close();
+                        throw OpenSSLSocketException( __FILE__, __LINE__ );
+                }
+
+            } else {  // We are in Server Mode.
+
+                int mode = SSL_VERIFY_NONE;
+
+                if( this->data->wantsClientAuth ) {
+                    mode = SSL_VERIFY_PEER;
+                }
+
+                if( this->data->needsClientAuth ) {
+                    mode = SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+                }
+
+                // Since we are a client we want to enforce peer verification, we set a
+                // callback so we can collect data on why a verify failed for debugging.
+                SSL_set_verify( this->data->ssl, mode, SocketData::verifyCallback );
+
+                int result = SSL_accept( this->data->ssl );
+
+                if( result != SSL_ERROR_NONE ) {
+                    SSLSocket::close();
+                    throw OpenSSLSocketException( __FILE__, __LINE__ );
+                }
+            }
+
+            this->data->handshakeCompleted = true;
+        }
+    }
+    DECAF_CATCH_RETHROW( IOException )
+    DECAF_CATCHALL_THROW( IOException )
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void OpenSSLSocket::setUseClientMode( bool value ) {
+
+    synchronized( &( this->data->handshakeLock ) ) {
+        if( this->data->handshakeStarted ) {
+            throw IllegalArgumentException(
+                __FILE__, __LINE__, "Handshake has already been started cannot change mode." );
+        }
+
+        this->data->useClientMode = value;
+    }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool OpenSSLSocket::getUseClientMode() const {
+    return this->data->useClientMode;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void OpenSSLSocket::setNeedClientAuth( bool value ) {
+    this->data->needsClientAuth = value;
+    this->data->wantsClientAuth = false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool OpenSSLSocket::getNeedClientAuth() const {
+    return this->data->needsClientAuth;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+void OpenSSLSocket::setWantClientAuth( bool value ) {
+    this->data->wantsClientAuth = value;
+    this->data->needsClientAuth = false;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+bool OpenSSLSocket::getWantClientAuth() const {
+    return this->data->wantsClientAuth;
+}
+
+////////////////////////////////////////////////////////////////////////////////
 int OpenSSLSocket::read( unsigned char* buffer, int size, int offset, int length ) {
 
     try{
@@ -347,6 +461,11 @@ int OpenSSLSocket::read( unsigned char* 
         }
 
 #ifdef HAVE_OPENSSL
+
+        if( !this->data->handshakeCompleted ) {
+            this->startHandshake();
+        }
+
         // Read data from the socket.
         int result = SSL_read( this->data->ssl, buffer + offset, length );
 
@@ -408,6 +527,11 @@ void OpenSSLSocket::write( const unsigne
         }
 
 #ifdef HAVE_OPENSSL
+
+        if( !this->data->handshakeCompleted ) {
+            this->startHandshake();
+        }
+
         int remaining = length;
 
         while( remaining > 0 && !isClosed() ) {

Modified: activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/internal/net/ssl/openssl/OpenSSLSocket.h
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/internal/net/ssl/openssl/OpenSSLSocket.h?rev=948196&r1=948195&r2=948196&view=diff
==============================================================================
--- activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/internal/net/ssl/openssl/OpenSSLSocket.h (original)
+++ activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/internal/net/ssl/openssl/OpenSSLSocket.h Tue May 25 20:17:26 2010
@@ -133,6 +133,41 @@ namespace openssl {
          */
         virtual void setEnabledProtocols( const std::vector<std::string>& protocols );
 
+        /**
+         * {@inheritDoc}
+         */
+        virtual void startHandshake();
+
+        /**
+         * {@inheritDoc}
+         */
+        virtual void setUseClientMode( bool value );
+
+        /**
+         * {@inheritDoc}
+         */
+        virtual bool getUseClientMode() const;
+
+        /**
+         * {@inheritDoc}
+         */
+        virtual void setNeedClientAuth( bool value );
+
+        /**
+         * {@inheritDoc}
+         */
+        virtual bool getNeedClientAuth() const;
+
+        /**
+         * {@inheritDoc}
+         */
+        virtual void setWantClientAuth( bool value );
+
+        /**
+         * {@inheritDoc}
+         */
+        virtual bool getWantClientAuth() const;
+
     public:
 
         /**

Modified: activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/net/ssl/SSLSocket.h
URL: http://svn.apache.org/viewvc/activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/net/ssl/SSLSocket.h?rev=948196&r1=948195&r2=948196&view=diff
==============================================================================
--- activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/net/ssl/SSLSocket.h (original)
+++ activemq/activemq-cpp/trunk/activemq-cpp/src/main/decaf/net/ssl/SSLSocket.h Tue May 25 20:17:26 2010
@@ -124,6 +124,86 @@ namespace ssl {
          */
         virtual void setSSLParameters( const SSLParameters& value );
 
+        /**
+         * Initiates a handshake for this SSL Connection, this can be necessary for several reasons such
+         * as using new encryption keys, or starting a new session.
+         *
+         * When called for the first time after the socket connects this method blocks until the handshake
+         * is completed.  The provider is not require to support multiple handshakes and can throw an
+         * IOException to indicate an error.
+         *
+         * @throw IOException if an I/O error occurs while performing the Handshake
+         */
+        virtual void startHandshake() = 0;
+
+        /**
+         * Determines the mode that the socket uses when a handshake is initiated, client or server.
+         *
+         * This method must be called prior to any handshake attempts on this Socket, once a handshake
+         * has be initiated this socket remains the the set mode; client or server, for the life of
+         * this object.
+         *
+         * @param value
+         *      The mode setting, true for client or false for server.
+         *
+         * @throw IllegalArguementException if the handshake process has begun and mode is lcoked.
+         */
+        virtual void setUseClientMode( bool value ) = 0;
+
+        /**
+         * Gets whether this Socket is in Client or Server mode, true indicates that the mode is
+         * set to Client.
+         *
+         * @return true if the Socket is in Client mode, false otherwise.
+         */
+        virtual bool getUseClientMode() const = 0;
+
+        /**
+         * Sets the Socket to require that a client authenticate itself by sending a valid Certificate that
+         * is trusted by this Server mode socket.  This option only applies to sockets in the Server mode.
+         *
+         * If the option is enabled an the client does not provide a certificate then the handshake is
+         * considered failed and the connection is refused.  Calling this method resets any previous
+         * value for this option as well as clears any value set in the setWantClientAuth method.
+         *
+         * @param value
+         *      The value indicating if a client is required to authenticate itself or not.
+         */
+        virtual void setNeedClientAuth( bool value ) = 0;
+
+        /**
+         * Returns if this socket is configured to require client authentication, true means that is has
+         * and that clients that failed to authenticate will be rejected.  This option is only useful when
+         * the socket is operating in server mode.
+         *
+         * @return true if client authentication is required.
+         */
+        virtual bool getNeedClientAuth() const = 0;
+
+        /**
+         * Sets the Socket to request that a client authenticate itself by sending a valid Certificate that
+         * is trusted by this Server mode socket.  This option only applies to sockets in the Server mode.
+         *
+         * If the option is enabled an the client does not provide a certificate then the handshake is
+         * considered to have succeeded, if it does send a certificate and that certificate is invalid the
+         * the handshake will fail.  Calling this method resets any previous value for this option as well
+         * as clears any value set in the setNeedClientAuth method.
+         *
+         * @param value
+         *      The value indicating if a client is requested to authenticate itself or not.
+         */
+        virtual void setWantClientAuth( bool value ) = 0;
+
+        /**
+         * Returns if this socket is configured to request client authentication, true means that is has
+         * and that clients that failed to authenticate will be rejected but that cleints that do not send
+         * a certificate are not considered to have failed authentication.  This option is only useful when
+         * the socket is operating in server mode.
+         *
+         * @return true if client authentication is required.
+         */
+        virtual bool getWantClientAuth() const = 0;
+
     };
 
 }}}