diff options
author | Mark Spruiell <mes@zeroc.com> | 2002-04-24 21:13:00 +0000 |
---|---|---|
committer | Mark Spruiell <mes@zeroc.com> | 2002-04-24 21:13:00 +0000 |
commit | 5409c1ecef0f226dedc77721c0d2fc8dfe9e85de (patch) | |
tree | 97ba75bc47a143726d6d8382be3a462e51716700 /cpp/src/Ice/SslConnectionOpenSSL.cpp | |
parent | cleaning up sample impls (diff) | |
download | ice-5409c1ecef0f226dedc77721c0d2fc8dfe9e85de.tar.bz2 ice-5409c1ecef0f226dedc77721c0d2fc8dfe9e85de.tar.xz ice-5409c1ecef0f226dedc77721c0d2fc8dfe9e85de.zip |
merging from plugins branch
Diffstat (limited to 'cpp/src/Ice/SslConnectionOpenSSL.cpp')
-rw-r--r-- | cpp/src/Ice/SslConnectionOpenSSL.cpp | 769 |
1 files changed, 0 insertions, 769 deletions
diff --git a/cpp/src/Ice/SslConnectionOpenSSL.cpp b/cpp/src/Ice/SslConnectionOpenSSL.cpp deleted file mode 100644 index 132429375a9..00000000000 --- a/cpp/src/Ice/SslConnectionOpenSSL.cpp +++ /dev/null @@ -1,769 +0,0 @@ -// ********************************************************************** -// -// Copyright (c) 2001 -// MutableRealms, Inc. -// Huntsville, AL, USA -// -// All Rights Reserved -// -// ********************************************************************** - -// Note: This pragma is used to disable spurious warning messages having -// to do with the length of debug symbols exceeding 255 characters. -// This is due to STL template identifiers expansion. -// The MSDN Library recommends that you put this pragma directive -// in place to avoid the warnings. -#ifdef _WIN32 -#pragma warning(disable:4786) -#endif - -#include <openssl/err.h> -#include <string> -#include <sstream> -#include <Ice/Network.h> -#include <Ice/OpenSSL.h> -#include <Ice/LocalException.h> -#include <Ice/SslException.h> -#include <Ice/SslFactory.h> -#include <Ice/SslConnection.h> -#include <Ice/SslConnectionOpenSSL.h> -#include <Ice/SystemOpenSSL.h> -#include <Ice/CertificateVerifierOpenSSL.h> -#include <Ice/OpenSSLUtils.h> - -#include <Ice/TraceLevels.h> -#include <Ice/Logger.h> - -using namespace std; -using namespace IceInternal; - -using Ice::SocketException; -using Ice::TimeoutException; -using Ice::ConnectionLostException; -using Ice::LoggerPtr; -using Ice::Int; - -using std::endl; - -using IceSSL::Factory; -using IceSSL::SystemInternalPtr; - -//////////////////////////////// -////////// 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 IceInternal::TraceLevelsPtr& traceLevels, - const Ice::LoggerPtr& logger, - const IceSSL::CertificateVerifierPtr& certificateVerifier, - SSL* sslConnection, - const IceSSL::SystemInternalPtr& system) : - IceSSL::Connection(traceLevels, logger, certificateVerifier), - _sslConnection(sslConnection) -{ - assert(_sslConnection != 0); - assert(system != 0); - - Factory::addSystemHandle(_sslConnection, system); - - _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); - Factory::removeSystemHandle(_sslConnection); - SSL_free(_sslConnection); - _sslConnection = 0; - } -} - -void -IceSSL::OpenSSL::Connection::shutdown() -{ - if (_sslConnection == 0) - { - return; - } - - if (_traceLevels->security >= IceSSL::SECURITY_WARNINGS) - { - _logger->trace(_traceLevels->securityCat, "WRN " + - string("shutting down ssl connection\n") + - fdToString(SSL_get_fd(_sslConnection))); - } - - int shutdown = 0; - int numRetries = 100; - int retries = -numRetries; - - do - { - shutdown = SSL_shutdown(_sslConnection); - retries++; - } - while ((shutdown == 0) && (retries < 0)); - - if ((_traceLevels->security >= IceSSL::SECURITY_PROTOCOL) && (shutdown <= 0)) - { - ostringstream s; - s << "ssl shutdown failure encountered: code[" << shutdown << "] retries["; - s << (retries + numRetries) << "]\n" << fdToString(SSL_get_fd(_sslConnection)); - _logger->trace(_traceLevels->securityCat, s.str()); - } -} - -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); - - int result = SSL_connect(_sslConnection); - - setLastError(result); - - return result; -} - -int -IceSSL::OpenSSL::Connection::accept() -{ - assert(_sslConnection != 0); - - 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); - retCode = init(timeout); - 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); - - int bytesRead = SSL_read(_sslConnection, buffer, bufferSize); - - setLastError(bytesRead); - - return bytesRead; -} - -int -IceSSL::OpenSSL::Connection::sslWrite(char* buffer, int bufferSize) -{ - assert(_sslConnection != 0); - - 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((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; - } - else - { - SocketException ex(__FILE__, __LINE__); - ex.error = getSocketErrno(); - throw ex; - } - } - else // (bytesRead == 0) - { - ProtocolException protocolEx(__FILE__, __LINE__); - - // Protocol Error: Unexpected EOF - protocolEx._message = "encountered an EOF that violates the ssl protocol\n"; - protocolEx._message += sslGetErrors(); - - throw protocolEx; - } - } - - 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); - } -} |