summaryrefslogtreecommitdiff
path: root/cpp/src/IceSSL/SslConnectionOpenSSL.cpp
diff options
context:
space:
mode:
authorAnthony Neal <aneal@zeroc.com>2002-09-11 12:33:02 +0000
committerAnthony Neal <aneal@zeroc.com>2002-09-11 12:33:02 +0000
commit22056550f5f34cc2ee1cd28a23fd40545c566c4b (patch)
treedcd27d328d2e11f09924a407cc5fb08dfac32d8d /cpp/src/IceSSL/SslConnectionOpenSSL.cpp
parentfixed retry bug (diff)
downloadice-22056550f5f34cc2ee1cd28a23fd40545c566c4b.tar.bz2
ice-22056550f5f34cc2ee1cd28a23fd40545c566c4b.tar.xz
ice-22056550f5f34cc2ee1cd28a23fd40545c566c4b.zip
Removed the Connection classes, added the new SslTransceiver hierarchy,
cleaned up a lot of code.
Diffstat (limited to 'cpp/src/IceSSL/SslConnectionOpenSSL.cpp')
-rw-r--r--cpp/src/IceSSL/SslConnectionOpenSSL.cpp889
1 files changed, 0 insertions, 889 deletions
diff --git a/cpp/src/IceSSL/SslConnectionOpenSSL.cpp b/cpp/src/IceSSL/SslConnectionOpenSSL.cpp
deleted file mode 100644
index 32de83aa15a..00000000000
--- a/cpp/src/IceSSL/SslConnectionOpenSSL.cpp
+++ /dev/null
@@ -1,889 +0,0 @@
-// **********************************************************************
-//
-// Copyright (c) 2001
-// Mutable Realms, Inc.
-// Huntsville, AL, USA
-//
-// All Rights Reserved
-//
-// **********************************************************************
-
-#include <Ice/Network.h>
-#include <Ice/Logger.h>
-#include <Ice/LocalException.h>
-
-#include <IceSSL/OpenSSL.h>
-#include <IceSSL/Exception.h>
-#include <IceSSL/SslConnection.h>
-#include <IceSSL/SslConnectionOpenSSL.h>
-#include <IceSSL/OpenSSLPluginI.h>
-#include <IceSSL/CertificateVerifierOpenSSL.h>
-#include <IceSSL/OpenSSLUtils.h>
-#include <IceSSL/TraceLevels.h>
-
-#include <openssl/err.h>
-
-#include <sstream>
-
-using namespace std;
-using namespace Ice;
-using namespace IceInternal;
-
-////////////////////////////////
-////////// Connection //////////
-////////////////////////////////
-
-//
-// Static Member Initialization
-//
-IceSSL::OpenSSL::SslConnectionMap IceSSL::OpenSSL::Connection::_connectionMap;
-IceUtil::Mutex IceSSL::OpenSSL::Connection::_connectionRepositoryMutex;
-
-//
-// Public Methods
-//
-
-void IceInternal::incRef(IceSSL::OpenSSL::Connection* p) { p->__incRef(); }
-void IceInternal::decRef(IceSSL::OpenSSL::Connection* p) { p->__decRef(); }
-
-// Note: I would use a using directive of the form:
-// using IceSSL::CertificateVerifierPtr;
-// but unfortunately, it appears that this is not properly picked up.
-//
-
-IceSSL::OpenSSL::Connection::Connection(const IceSSL::CertificateVerifierPtr& certificateVerifier,
- SSL* sslConnection,
- const PluginBaseIPtr& plugin) :
- IceSSL::Connection(plugin->getTraceLevels(), plugin->getLogger(), certificateVerifier),
- _sslConnection(sslConnection)
-{
- assert(_sslConnection != 0);
- assert(system != 0);
-
- SSL_set_ex_data(sslConnection, 0, static_cast<void*>(plugin.get()));
-
- // We always start off in a Handshake
- _phase = Handshake;
-
- _lastError = SSL_ERROR_NONE;
-
- _initWantRead = 0;
- _initWantWrite = 0;
-
- // None configured, default to indicated timeout
- _handshakeReadTimeout = 0;
-
- // Set up the SSL to be able to refer back to our connection object.
- addConnection(_sslConnection, this);
-}
-
-IceSSL::OpenSSL::Connection::~Connection()
-{
- if(_sslConnection != 0)
- {
- removeConnection(_sslConnection);
- SSL_set_ex_data(_sslConnection, 0, 0);
- SSL_free(_sslConnection);
- _sslConnection = 0;
- }
-}
-
-int
-IceSSL::OpenSSL::Connection::shutdown(int timeout)
-{
- if(_sslConnection == 0)
- {
- return 1;
- }
-
- int retCode = 0;
-
- if(_initWantWrite)
- {
- int i = writeSelect(timeout);
-
- if(i == 0)
- {
- return 0;
- }
-
- _initWantWrite = 0;
- }
- else if(_initWantRead)
- {
- int i = readSelect(timeout);
-
- if(i == 0)
- {
- return 0;
- }
-
- _initWantRead = 0;
- }
-
- ERR_clear_error();
-
- retCode = SSL_shutdown(_sslConnection);
-
- if(retCode == 1)
- {
- // Shutdown successful - shut down the socket for writing.
- ::shutdown(SSL_get_fd(_sslConnection), SHUT_WR);
- }
- else if(retCode == -1)
- {
- setLastError(retCode);
-
- // Shutdown failed due to an error.
-
- switch(getLastError())
- {
- case SSL_ERROR_WANT_WRITE:
- {
- _initWantWrite = 1;
- retCode = 0;
- break;
- }
-
- case SSL_ERROR_WANT_READ:
- {
- _initWantRead = 1;
- retCode = 0;
- break;
- }
-
- case SSL_ERROR_NONE:
- case SSL_ERROR_WANT_X509_LOOKUP:
- {
- // Ignore
- retCode = 0;
- break;
- }
-
- case SSL_ERROR_SYSCALL:
- {
- //
- // Some error with the underlying transport.
- //
-
- if(interrupted())
- {
- retCode = 0;
- break;
- }
-
- if(wouldBlock())
- {
- readSelect(timeout);
- retCode = 0;
- break;
- }
-
- if(connectionLost())
- {
- ConnectionLostException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
-
- //
- // Non-specific socket problem.
- //
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
-
- case SSL_ERROR_SSL:
- {
- //
- // Error in the SSL library, usually a Protocol error.
- //
-
- ProtocolException protocolEx(__FILE__, __LINE__);
-
- protocolEx.message = "encountered a violation of the ssl protocol during shutdown\n";
- protocolEx.message += sslGetErrors();
-
- throw protocolEx;
- }
-
- case SSL_ERROR_ZERO_RETURN:
- {
- //
- // Indicates that the SSL connection has been closed. For SSLv3.0
- // and TLSv1.0, it indicates that a closure alert was received,
- // and thus the connection has been closed cleanly.
- //
-
- CloseConnectionException ex(__FILE__, __LINE__);
- throw ex;
- }
- }
- }
-
- return retCode;
-}
-
-void
-IceSSL::OpenSSL::Connection::setHandshakeReadTimeout(int timeout)
-{
- _handshakeReadTimeout = timeout;
-}
-
-IceSSL::OpenSSL::ConnectionPtr
-IceSSL::OpenSSL::Connection::getConnection(SSL* sslPtr)
-{
- IceUtil::Mutex::Lock sync(_connectionRepositoryMutex);
-
- assert(sslPtr);
-
- Connection* connection = _connectionMap[sslPtr];
-
- assert(connection);
-
- return ConnectionPtr(connection);
-}
-
-//
-// Note: Do not throw exceptions from verifyCertificate - it would rip through the OpenSSL system,
-// interfering with the usual handling and alert system of the handshake. Exceptions should
-// be caught here (if they can be generated), logged and then a fail return code (0) should
-// returned.
-//
-int
-IceSSL::OpenSSL::Connection::verifyCertificate(int preVerifyOkay, X509_STORE_CTX* x509StoreContext)
-{
- // Should NEVER be able to happen.
- assert(_certificateVerifier.get() != 0);
-
- // Get the verifier, make sure it is for OpenSSL connections
- IceSSL::OpenSSL::CertificateVerifierPtr verifier;
- verifier = dynamic_cast<IceSSL::OpenSSL::CertificateVerifier*>(_certificateVerifier.get());
-
- // Check to make sure we have a proper verifier for the operation.
- if(verifier)
- {
- // Use the verifier to verify the certificate
- try
- {
- preVerifyOkay = verifier->verify(preVerifyOkay, x509StoreContext, _sslConnection);
- }
- catch(const Ice::LocalException& localEx)
- {
- if(_traceLevels->security >= IceSSL::SECURITY_WARNINGS)
- {
- ostringstream s;
-
- s << "WRN exception during certificate verification: " << std::endl;
- s << localEx << flush;
-
- _logger->trace(_traceLevels->securityCat, s.str());
- }
-
- preVerifyOkay = 0;
- }
- }
- else
- {
- // Note: This code should NEVER be able to be reached, as we check each
- // CertificateVerifier as it is added to the System.
-
- if(_traceLevels->security >= IceSSL::SECURITY_WARNINGS)
- {
- string errorString;
-
- if(_certificateVerifier.get())
- {
- errorString = "WRN improper CertificateVerifier type";
- }
- else
- {
- // NOTE: This should NEVER be able to happen, but just in case.
- errorString = "WRN CertificateVerifier not set";
- }
-
- _logger->trace(_traceLevels->securityCat, errorString);
- }
- }
-
- return preVerifyOkay;
-}
-
-//
-// Protected Methods
-//
-
-int
-IceSSL::OpenSSL::Connection::connect()
-{
- assert(_sslConnection != 0);
-
- ERR_clear_error();
- int result = SSL_connect(_sslConnection);
-
- setLastError(result);
-
- return result;
-}
-
-int
-IceSSL::OpenSSL::Connection::accept()
-{
- assert(_sslConnection != 0);
-
- ERR_clear_error();
- int result = SSL_accept(_sslConnection);
-
- setLastError(result);
-
- return result;
-}
-
-// NOTE: Currently not used, maybe later.
-int
-IceSSL::OpenSSL::Connection::renegotiate()
-{
- assert(_sslConnection != 0);
- return SSL_renegotiate(_sslConnection);
-}
-
-int
-IceSSL::OpenSSL::Connection::initialize(int timeout)
-{
- int retCode = 0;
-
- while(true)
- {
- // One lucky thread will get the honor of carrying out the hanshake,
- // if there is one to perform. The HandshakeSentinel effectively
- // establishes a first-come, first-serve policy. One thread will own
- // the handshake, and the others will either return rejected to the
- // caller (who will figure out what to do with them) OR wait until
- // our lead thread is done. Then, the shuffle begins again.
- // Eventually, all threads will filter through.
-
- HandshakeSentinel handshakeSentinel(_handshakeFlag);
-
- if(!handshakeSentinel.ownHandshake())
- {
- if(timeout >= 0)
- {
- // We should return immediately here - do not block,
- // leave it to the caller to figure this out.
- retCode = -1;
- break;
- }
- else
- {
- // We will wait here - blocking IO is being used.
- IceUtil::Mutex::Lock sync(_handshakeWaitMutex);
- }
- }
- else
- {
- // Perform our init(), then leave.
- IceUtil::Mutex::Lock sync(_handshakeWaitMutex);
-
- // Here we 'take the ball and run with it' for as long as we can
- // get away with it. As long as we don't encounter some error
- // status (or completion), this thread continues to service the
- // initialize() call.
- while(retCode == 0)
- {
- switch(_phase)
- {
- case Handshake :
- {
- retCode = handshake(timeout);
- break;
- }
-
- case Shutdown :
- {
- retCode = shutdown(timeout);
- break;
- }
-
- case Connected :
- {
- retCode = SSL_is_init_finished(_sslConnection);
-
- if(!retCode)
- {
- // In this case, we are essentially renegotiating
- // the connection at the behest of the peer.
- _phase = Handshake;
- continue;
- }
-
- // Done here.
- return retCode;
- }
- }
- }
-
- break;
- }
- }
-
- return retCode;
-}
-
-int
-IceSSL::OpenSSL::Connection::pending()
-{
- assert(_sslConnection != 0);
- return SSL_pending(_sslConnection);
-}
-
-int
-IceSSL::OpenSSL::Connection::getLastError() const
-{
- assert(_sslConnection != 0);
- return SSL_get_error(_sslConnection, _lastError);
-}
-
-int
-IceSSL::OpenSSL::Connection::sslRead(char* buffer, int bufferSize)
-{
- assert(_sslConnection != 0);
-
- ERR_clear_error();
- int bytesRead = SSL_read(_sslConnection, buffer, bufferSize);
-
- setLastError(bytesRead);
-
- return bytesRead;
-}
-
-int
-IceSSL::OpenSSL::Connection::sslWrite(char* buffer, int bufferSize)
-{
- assert(_sslConnection != 0);
-
- ERR_clear_error();
- int bytesWritten = SSL_write(_sslConnection, buffer, bufferSize);
-
- setLastError(bytesWritten);
-
- return bytesWritten;
-}
-
-int
-IceSSL::OpenSSL::Connection::select(int timeout, bool write)
-{
- int ret;
-
- assert(_sslConnection != 0);
- SOCKET fd = SSL_get_fd(_sslConnection);
-
- fd_set rwFdSet;
- struct timeval tv;
-
- if(timeout >= 0)
- {
- tv.tv_sec = timeout / 1000;
- tv.tv_usec = (timeout - tv.tv_sec * 1000) * 1000;
- }
-
- do
- {
- FD_ZERO(&rwFdSet);
- FD_SET(fd, &rwFdSet);
-
- if(timeout >= 0)
- {
- if(write)
- {
- ret = ::select(fd + 1, 0, &rwFdSet, 0, &tv);
- }
- else
- {
- ret = ::select(fd + 1, &rwFdSet, 0, 0, &tv);
- }
- }
- else
- {
- if(write)
- {
- ret = ::select(fd + 1, 0, &rwFdSet, 0, 0);
- }
- else
- {
- ret = ::select(fd + 1, &rwFdSet, 0, 0, 0);
- }
- }
- }
- while(ret == SOCKET_ERROR && interrupted());
-
- if(ret == SOCKET_ERROR)
- {
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
-
- if(ret == 0)
- {
- throw TimeoutException(__FILE__, __LINE__);
- }
-
- return FD_ISSET(fd, &rwFdSet);
-}
-
-int
-IceSSL::OpenSSL::Connection::readSelect(int timeout)
-{
- return select(timeout, false);
-}
-
-int
-IceSSL::OpenSSL::Connection::writeSelect(int timeout)
-{
- return select(timeout, true);
-}
-
-int
-IceSSL::OpenSSL::Connection::read(Buffer& buf, int timeout)
-{
- int packetSize = buf.b.end() - buf.i;
- int totalBytesRead = 0;
- int bytesRead;
-
- int initReturn = 0;
-
- // We keep reading until we're done.
- while(buf.i != buf.b.end())
- {
- // Ensure we're initialized.
- initReturn = initialize(timeout);
-
- if(initReturn == -1)
- {
- // Handshake underway, timeout immediately, easy way to deal with this.
- throw TimeoutException(__FILE__, __LINE__);
- }
-
- if(initReturn == 0)
- {
- // Retry the initialize call
- continue;
- }
-
- // initReturn must be > 0, so we're okay to try a read
-
- if(!pending() && !readSelect(_readTimeout))
- {
- // Nothing is left to read (according to SSL).
- if(_traceLevels->security >= IceSSL::SECURITY_PROTOCOL)
- {
- _logger->trace(_traceLevels->securityCat, "no pending application-level bytes");
- }
-
- // We're done here.
- break;
- }
-
- _readTimeout = timeout;
-
- bytesRead = sslRead(static_cast<char*>(&*buf.i), packetSize);
-
- switch(getLastError())
- {
- case SSL_ERROR_NONE:
- {
- if(bytesRead > 0)
- {
- if(_traceLevels->network >= 3)
- {
- ostringstream s;
- s << "received " << bytesRead << " of " << packetSize;
- s << " bytes via ssl\n" << fdToString(SSL_get_fd(_sslConnection));
- _logger->trace(_traceLevels->networkCat, s.str());
- }
-
- totalBytesRead += bytesRead;
-
- buf.i += bytesRead;
-
- if(packetSize > buf.b.end() - buf.i)
- {
- packetSize = buf.b.end() - buf.i;
- }
- }
- continue;
- }
-
- case SSL_ERROR_WANT_READ:
- {
- if(!readSelect(timeout))
- {
- // Timeout and wait for them to arrive.
- throw TimeoutException(__FILE__, __LINE__);
- }
- continue;
- }
-
- case SSL_ERROR_WANT_WRITE:
- case SSL_ERROR_WANT_X509_LOOKUP:
- {
- // Perform another read. The read should take care of this.
- continue;
- }
-
- case SSL_ERROR_SYSCALL:
- {
- if(bytesRead == -1)
- {
- // IO Error in underlying BIO
-
- if(interrupted())
- {
- break;
- }
-
- if(wouldBlock())
- {
- break;
- }
-
- if(connectionLost())
- {
- ConnectionLostException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
-
- SocketException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
- else // (bytesRead == 0)
- {
- ConnectionLostException ex(__FILE__, __LINE__);
- ex.error = 0;
- throw ex;
- }
- }
-
- case SSL_ERROR_SSL:
- {
- ProtocolException protocolEx(__FILE__, __LINE__);
-
- protocolEx.message = "encountered a violation of the ssl protocol\n";
- protocolEx.message += sslGetErrors();
-
- throw protocolEx;
- }
-
- case SSL_ERROR_ZERO_RETURN:
- {
- // Indicates that that the SSL Connection has been closed.
- // But does not necessarily indicate that the underlying transport
- // has been closed (in the case of Ice, it definitely hasn't yet).
-
- ConnectionLostException ex(__FILE__, __LINE__);
- ex.error = getSocketErrno();
- throw ex;
- }
- }
- }
-
- return totalBytesRead;
-}
-
-void
-IceSSL::OpenSSL::Connection::addConnection(SSL* sslPtr, Connection* connection)
-{
- assert(sslPtr);
- assert(connection);
- IceUtil::Mutex::Lock sync(_connectionRepositoryMutex);
- _connectionMap[sslPtr] = connection;
-}
-
-void
-IceSSL::OpenSSL::Connection::removeConnection(SSL* sslPtr)
-{
- assert(sslPtr);
- IceUtil::Mutex::Lock sync(_connectionRepositoryMutex);
- _connectionMap.erase(sslPtr);
-}
-
-void
-IceSSL::OpenSSL::Connection::showCertificateChain(BIO* bio)
-{
- assert(_sslConnection != 0);
- assert(bio != 0);
-
- STACK_OF(X509)* sk;
-
- // Big nasty buffer
- char buffer[4096];
-
- if((sk = SSL_get_peer_cert_chain(_sslConnection)) != 0)
- {
- BIO_printf(bio,"---\nCertificate chain\n");
-
- for(int i = 0; i < sk_X509_num(sk); i++)
- {
- X509_NAME_oneline(X509_get_subject_name(sk_X509_value(sk,i)), buffer, sizeof(buffer));
- BIO_printf(bio, "%2d s:%s\n", i, buffer);
-
- X509_NAME_oneline(X509_get_issuer_name(sk_X509_value(sk,i)), buffer, sizeof(buffer));
- BIO_printf(bio, " i:%s\n", buffer);
-
- PEM_write_bio_X509(bio, sk_X509_value(sk, i));
- }
- }
- else
- {
- BIO_printf(bio, "---\nNo peer certificate chain available.\n");
- }
-}
-
-void
-IceSSL::OpenSSL::Connection::showPeerCertificate(BIO* bio, const char* connType)
-{
- assert(_sslConnection != 0);
- assert(bio != 0);
-
- X509* peerCert = 0;
- char buffer[4096];
-
- if((peerCert = SSL_get_peer_certificate(_sslConnection)) != 0)
- {
- BIO_printf(bio, "%s Certificate\n", connType);
- PEM_write_bio_X509(bio, peerCert);
-
- X509_NAME_oneline(X509_get_subject_name(peerCert), buffer, sizeof(buffer));
- BIO_printf(bio, "subject=%s\n", buffer);
-
- X509_NAME_oneline(X509_get_issuer_name(peerCert), buffer, sizeof(buffer));
- BIO_printf(bio, "issuer=%s\n", buffer);
-
- EVP_PKEY *pktmp;
- pktmp = X509_get_pubkey(peerCert);
- BIO_printf(bio,"%s public key is %d bit\n", connType, EVP_PKEY_bits(pktmp));
- EVP_PKEY_free(pktmp);
-
- X509_free(peerCert);
- }
- else
- {
- BIO_printf(bio, "No %s certificate available.\n", connType);
- }
-}
-
-void
-IceSSL::OpenSSL::Connection::showSharedCiphers(BIO* bio)
-{
- assert(_sslConnection != 0);
- assert(bio != 0);
-
- char buffer[4096];
- char* strPointer = 0;
-
- if((strPointer = SSL_get_shared_ciphers(_sslConnection, buffer, sizeof(buffer))) != 0)
- {
- // This works only for SSL 2. In later protocol versions, the client does not know
- // what other ciphers (in addition to the one to be used in the current connection)
- // the server supports.
-
- BIO_printf(bio, "---\nShared Ciphers:\n");
-
- int j = 0;
- int i = 0;
-
- while(*strPointer)
- {
- if(*strPointer == ':')
- {
- BIO_write(bio, " ", (15-j%25));
- i++;
- j=0;
- BIO_write(bio, ((i%3)?" ":"\n"), 1);
- }
- else
- {
- BIO_write(bio, strPointer, 1);
- j++;
- }
-
- strPointer++;
- }
-
- BIO_write(bio,"\n",1);
- }
-}
-
-void
-IceSSL::OpenSSL::Connection::showSessionInfo(BIO* bio)
-{
- assert(_sslConnection != 0);
- assert(bio != 0);
-
- if(_sslConnection->hit)
- {
- BIO_printf(bio, "Reused session-id\n");
- }
-
- PEM_write_bio_SSL_SESSION(bio, SSL_get_session(_sslConnection));
-}
-
-void
-IceSSL::OpenSSL::Connection::showSelectedCipherInfo(BIO* bio)
-{
- assert(_sslConnection != 0);
- assert(bio != 0);
-
- const char* str;
- SSL_CIPHER* cipher;
-
- // Show the cipher that was finally selected.
- cipher = SSL_get_current_cipher(_sslConnection);
-
- str = SSL_CIPHER_get_name(cipher);
- BIO_printf(bio, "Cipher Version: %s\n", ((str != 0) ? str : "(NONE)"));
-
- str = SSL_CIPHER_get_version(cipher);
- BIO_printf(bio, "Cipher Name: %s\n", ((str != 0) ? str : "(NONE)"));
-}
-
-void
-IceSSL::OpenSSL::Connection::showHandshakeStats(BIO* bio)
-{
- assert(_sslConnection != 0);
- assert(bio != 0);
-
- BIO_printf(bio, "---\nSSL handshake has read %ld bytes and written %ld bytes\n",
- BIO_number_read(SSL_get_rbio(_sslConnection)),
- BIO_number_written(SSL_get_wbio(_sslConnection)));
-}
-
-void
-IceSSL::OpenSSL::Connection::showClientCAList(BIO* bio, const char* connType)
-{
- assert(_sslConnection != 0);
- assert(bio != 0);
- assert(connType != 0);
-
- char buffer[4096];
- STACK_OF(X509_NAME)* sk = SSL_get_client_CA_list(_sslConnection);
-
- if((sk != 0) && (sk_X509_NAME_num(sk) > 0))
- {
- BIO_printf(bio,"---\nAcceptable %s certificate CA names\n", connType);
-
- for(int i = 0; i < sk_X509_NAME_num(sk); i++)
- {
- X509_NAME_oneline(sk_X509_NAME_value(sk, i), buffer, sizeof(buffer));
- BIO_write(bio, buffer, strlen(buffer));
- BIO_write(bio,"\n", 1);
- }
- }
- else
- {
- BIO_printf(bio,"---\nNo %s certificate CA names sent\n", connType);
- }
-}