summaryrefslogtreecommitdiff
path: root/cpp/src/IceSSL/SslTransceiver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/IceSSL/SslTransceiver.cpp')
-rw-r--r--cpp/src/IceSSL/SslTransceiver.cpp879
1 files changed, 865 insertions, 14 deletions
diff --git a/cpp/src/IceSSL/SslTransceiver.cpp b/cpp/src/IceSSL/SslTransceiver.cpp
index 00966041063..1b9d582f622 100644
--- a/cpp/src/IceSSL/SslTransceiver.cpp
+++ b/cpp/src/IceSSL/SslTransceiver.cpp
@@ -12,15 +12,37 @@
#include <Ice/Buffer.h>
#include <Ice/Network.h>
#include <IceSSL/OpenSSL.h>
-#include <IceSSL/SslConnection.h>
#include <IceSSL/SslTransceiver.h>
#include <IceSSL/PluginBaseI.h>
#include <IceSSL/TraceLevels.h>
+// Added
+#include <Ice/Logger.h>
+#include <Ice/LocalException.h>
+
+#include <IceSSL/Exception.h>
+#include <IceSSL/OpenSSLPluginI.h>
+#include <IceSSL/CertificateVerifierOpenSSL.h>
+#include <IceSSL/OpenSSLUtils.h>
+
+#include <openssl/err.h>
+
+#include <sstream>
+// Added
+
using namespace std;
using namespace Ice;
using namespace IceInternal;
-using IceSSL::ConnectionPtr;
+using namespace IceSSL::OpenSSL;
+
+//
+// Static Member Initialization
+//
+IceSSL::SslTransceiverMap IceSSL::SslTransceiver::_transceiverMap;
+IceUtil::Mutex IceSSL::SslTransceiver::_transceiverRepositoryMutex;
+
+void ::IceInternal::incRef(::IceSSL::SslTransceiver* p) { p->__incRef(); }
+void ::IceInternal::decRef(::IceSSL::SslTransceiver* p) { p->__decRef(); }
SOCKET
IceSSL::SslTransceiver::fd()
@@ -45,7 +67,7 @@ IceSSL::SslTransceiver::close()
int retries = -numRetries;
do
{
- shutdown = _sslConnection->shutdown();
+ shutdown = internalShutdown();
retries++;
}
while((shutdown == 0) && (retries < 0));
@@ -77,7 +99,7 @@ IceSSL::SslTransceiver::shutdown()
int retries = -numRetries;
do
{
- shutdown = _sslConnection->shutdown();
+ shutdown = internalShutdown();
retries++;
}
while((shutdown == 0) && (retries < 0));
@@ -87,17 +109,154 @@ IceSSL::SslTransceiver::shutdown()
}
void
-IceSSL::SslTransceiver::write(Buffer& buf, int timeout)
-{
- assert(_fd != INVALID_SOCKET);
- _sslConnection->write(buf, timeout);
-}
-
-void
IceSSL::SslTransceiver::read(Buffer& buf, int timeout)
{
assert(_fd != INVALID_SOCKET);
- if(!_sslConnection->read(buf, 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;
+ }
+ }
+ }
+
+ if(totalBytesRead == 0)
{
if(_traceLevels->security >= IceSSL::SECURITY_WARNINGS)
{
@@ -113,21 +272,713 @@ IceSSL::SslTransceiver::toString() const
return fdToString(_fd);
}
+void
+IceSSL::SslTransceiver::setHandshakeReadTimeout(int timeout)
+{
+ _handshakeReadTimeout = timeout;
+}
+
+IceSSL::SslTransceiverPtr
+IceSSL::SslTransceiver::getTransceiver(SSL* sslPtr)
+{
+ IceUtil::Mutex::Lock sync(_transceiverRepositoryMutex);
+
+ assert(sslPtr);
+
+ SslTransceiver* transceiver = _transceiverMap[sslPtr];
+
+ assert(transceiver);
+
+ return SslTransceiverPtr(transceiver);
+}
+
+//
+// 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::SslTransceiver::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
+//
+
+// Note: I would use a using directive of the form:
+// using IceSSL::CertificateVerifierPtr;
+// but unfortunately, it appears that this is not properly picked up.
+//
+
+int
+IceSSL::SslTransceiver::internalShutdown(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;
+}
+
+int
+IceSSL::SslTransceiver::connect()
+{
+ assert(_sslConnection != 0);
+
+ ERR_clear_error();
+ int result = SSL_connect(_sslConnection);
+
+ setLastError(result);
+
+ return result;
+}
+
+int
+IceSSL::SslTransceiver::accept()
+{
+ assert(_sslConnection != 0);
+
+ ERR_clear_error();
+ int result = SSL_accept(_sslConnection);
+
+ setLastError(result);
+
+ return result;
+}
+
+// NOTE: Currently not used, maybe later.
+int
+IceSSL::SslTransceiver::renegotiate()
+{
+ assert(_sslConnection != 0);
+ return SSL_renegotiate(_sslConnection);
+}
+
+int
+IceSSL::SslTransceiver::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 = internalShutdown(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::SslTransceiver::pending()
+{
+ assert(_sslConnection != 0);
+ return SSL_pending(_sslConnection);
+}
+
+int
+IceSSL::SslTransceiver::getLastError() const
+{
+ assert(_sslConnection != 0);
+ return SSL_get_error(_sslConnection, _lastError);
+}
+
+int
+IceSSL::SslTransceiver::sslRead(char* buffer, int bufferSize)
+{
+ assert(_sslConnection != 0);
+
+ ERR_clear_error();
+ int bytesRead = SSL_read(_sslConnection, buffer, bufferSize);
+
+ setLastError(bytesRead);
+
+ return bytesRead;
+}
+
+int
+IceSSL::SslTransceiver::sslWrite(char* buffer, int bufferSize)
+{
+ assert(_sslConnection != 0);
+
+ ERR_clear_error();
+ int bytesWritten = SSL_write(_sslConnection, buffer, bufferSize);
+
+ setLastError(bytesWritten);
+
+ return bytesWritten;
+}
+
+int
+IceSSL::SslTransceiver::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::SslTransceiver::readSelect(int timeout)
+{
+ return select(timeout, false);
+}
+
+int
+IceSSL::SslTransceiver::writeSelect(int timeout)
+{
+ return select(timeout, true);
+}
+
+//
+// Static Protected
+//
+
+void
+IceSSL::SslTransceiver::addTransceiver(SSL* sslPtr, SslTransceiver* transceiver)
+{
+ assert(sslPtr);
+ assert(transceiver);
+ IceUtil::Mutex::Lock sync(_transceiverRepositoryMutex);
+ _transceiverMap[sslPtr] = transceiver;
+}
+
+void
+IceSSL::SslTransceiver::removeTransceiver(SSL* sslPtr)
+{
+ assert(sslPtr);
+ IceUtil::Mutex::Lock sync(_transceiverRepositoryMutex);
+ _transceiverMap.erase(sslPtr);
+}
+
+void
+IceSSL::SslTransceiver::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::SslTransceiver::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::SslTransceiver::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::SslTransceiver::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::SslTransceiver::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::SslTransceiver::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::SslTransceiver::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);
+ }
+}
+
+
+//
+// Private Methods
+//
+
IceSSL::SslTransceiver::SslTransceiver(const PluginBaseIPtr& plugin,
SOCKET fd,
- const ConnectionPtr& sslConnection) :
+ const IceSSL::OpenSSL::CertificateVerifierPtr& certificateVerifier,
+ SSL* sslConnection) :
+ _sslConnection(sslConnection),
_traceLevels(plugin->getTraceLevels()),
_logger(plugin->getLogger()),
_fd(fd),
- _sslConnection(sslConnection)
+ _certificateVerifier(certificateVerifier)
{
assert(sslConnection != 0);
FD_ZERO(&_rFdSet);
FD_ZERO(&_wFdSet);
+
+ 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.
+ addTransceiver(_sslConnection, this);
}
IceSSL::SslTransceiver::~SslTransceiver()
{
assert(_fd == INVALID_SOCKET);
+
+ if(_sslConnection != 0)
+ {
+ removeTransceiver(_sslConnection);
+ SSL_set_ex_data(_sslConnection, 0, 0);
+ SSL_free(_sslConnection);
+ _sslConnection = 0;
+ }
}
+