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;
+
};
}}}