diff options
Diffstat (limited to 'cpp/src/Ice/SslSystemOpenSSL.cpp')
-rw-r--r-- | cpp/src/Ice/SslSystemOpenSSL.cpp | 415 |
1 files changed, 57 insertions, 358 deletions
diff --git a/cpp/src/Ice/SslSystemOpenSSL.cpp b/cpp/src/Ice/SslSystemOpenSSL.cpp index d2828615af3..734bb5ecfbd 100644 --- a/cpp/src/Ice/SslSystemOpenSSL.cpp +++ b/cpp/src/Ice/SslSystemOpenSSL.cpp @@ -33,7 +33,10 @@ #include <Ice/SecurityException.h> #include <Ice/SslConnectionOpenSSLClient.h> #include <Ice/SslConnectionOpenSSLServer.h> -#include <Ice/SslConfig.h> +#include <Ice/SslConfig.h>
+#include <Ice/SslRSAKeyPair.h>
+#include <Ice/SslJanitors.h>
+#include <Ice/SslCertificateVerifierOpenSSL.h> #include <Ice/TraceLevels.h> #include <Ice/Logger.h> @@ -92,158 +95,6 @@ Ice::LoggerPtr System::_globalLogger = 0; using IceSecurity::Ssl::OpenSSL::ContextException; using IceSecurity::Ssl::SystemPtr; -// -// NOTE: The following (mon, getGeneralizedTime, getUTCTime and getASN1time are routines that -// have been abducted from the OpenSSL X509 library, and modified to work with the STL -// basic_string template. - -static const char *mon[12]= -{ - "Jan","Feb","Mar","Apr","May","Jun", - "Jul","Aug","Sep","Oct","Nov","Dec" -}; - -string -getGeneralizedTime(ASN1_GENERALIZEDTIME *tm) -{ - char buf[30]; - char *v; - int gmt=0; - int i; - int y = 0, M = 0, d = 0, h = 0, m = 0, s = 0; - - i = tm->length; - v = (char *) tm->data; - - if (i < 12) - { - goto err; - } - - if (v[i-1] == 'Z') - { - gmt=1; - } - - for (i=0; i<12; i++) - { - if ((v[i] > '9') || (v[i] < '0')) - { - goto err; - } - } - - y = (v[0] - '0') * 1000 + (v[1] - '0') * 100 + (v[2] - '0') * 10 + (v[3] - '0'); - M = (v[4] - '0') * 10 + (v[5] - '0'); - - if ((M > 12) || (M < 1)) - { - goto err; - } - - d = (v[6] - '0') * 10 + (v[7] - '0'); - h = (v[8] - '0') * 10 + (v[9] - '0'); - m = (v[10] - '0') * 10 + (v[11] - '0'); - - if ((v[12] >= '0') && (v[12] <= '9') && - (v[13] >= '0') && (v[13] <= '9')) - { - s = (v[12] - '0') * 10 + (v[13] - '0'); - } - - sprintf(buf, "%s %2d %02d:%02d:%02d %d%s", mon[M-1], d, h, m, s, y, (gmt)?" GMT":""); - return string(buf); - -err: - return string("Bad time value"); -} - -string -getUTCTime(ASN1_UTCTIME *tm) -{ - char buf[30]; - char *v; - int gmt=0; - int i; - int y = 0, M = 0, d = 0, h = 0, m = 0, s = 0; - - i = tm->length; - v = (char *) tm->data; - - if (i < 10) - { - goto err; - } - - if (v[i-1] == 'Z') - { - gmt=1; - } - - for (i = 0; i < 10; i++) - { - if ((v[i] > '9') || (v[i] < '0')) - { - goto err; - } - } - - y = (v[0] - '0') * 10 + (v[1] - '0'); - - if (y < 50) - { - y+=100; - } - - M = (v[2] - '0') * 10 + (v[3] - '0'); - - if ((M > 12) || (M < 1)) - { - goto err; - } - - d = (v[4] - '0') * 10 + (v[5] - '0'); - h = (v[6] - '0') * 10 + (v[7] - '0'); - m = (v[8] - '0') * 10 + (v[9] - '0'); - - if ((v[10] >= '0') && (v[10] <= '9') && (v[11] >= '0') && (v[11] <= '9')) - { - s = (v[10] - '0') * 10 + (v[11] - '0'); - } - - sprintf(buf, "%s %2d %02d:%02d:%02d %d%s", mon[M-1], d, h, m, s, y+1900, (gmt)?" GMT":""); - return string(buf); - -err: - return string("Bad time value"); -} - -string -getASN1time(ASN1_TIME *tm) -{ - string theTime; - - switch (tm->type) - { - case V_ASN1_UTCTIME : - { - theTime = getUTCTime(tm); - } - - case V_ASN1_GENERALIZEDTIME : - { - theTime = getGeneralizedTime(tm); - } - - default : - { - theTime = "Bad time value"; - } - } - - return theTime; -} - extern "C" { @@ -252,7 +103,8 @@ tmpRSACallback(SSL *s, int isExport, int keyLength) { IceSecurity::Ssl::SystemPtr sslSystem = IceSecurity::Ssl::Factory::getSystemFromHandle(s); - IceSecurity::Ssl::OpenSSL::System* openSslSystem = dynamic_cast<IceSecurity::Ssl::OpenSSL::System*>(sslSystem.get()); + IceSecurity::Ssl::OpenSSL::System* openSslSystem = 0;
+ openSslSystem = dynamic_cast<IceSecurity::Ssl::OpenSSL::System*>(sslSystem.get()); RSA* rsaKey = openSslSystem->getRSAKey(s, isExport, keyLength); @@ -264,7 +116,8 @@ tmpDHCallback(SSL *s, int isExport, int keyLength) { IceSecurity::Ssl::SystemPtr sslSystem = IceSecurity::Ssl::Factory::getSystemFromHandle(s); - IceSecurity::Ssl::OpenSSL::System* openSslSystem = dynamic_cast<IceSecurity::Ssl::OpenSSL::System*>(sslSystem.get()); + IceSecurity::Ssl::OpenSSL::System* openSslSystem = 0;
+ openSslSystem = dynamic_cast<IceSecurity::Ssl::OpenSSL::System*>(sslSystem.get()); DH* dh = openSslSystem->getDHParams(s, isExport, keyLength); @@ -275,71 +128,16 @@ tmpDHCallback(SSL *s, int isExport, int keyLength) int verifyCallback(int ok, X509_STORE_CTX *ctx) { - X509* err_cert = X509_STORE_CTX_get_current_cert(ctx); - int verifyError = X509_STORE_CTX_get_error(ctx); - int depth = X509_STORE_CTX_get_error_depth(ctx); - - // If we have no errors so far, and the certificate chain is too long - if ((verifyError != X509_V_OK) && (10 < depth)) - { - verifyError = X509_V_ERR_CERT_CHAIN_TOO_LONG; - } - - if (verifyError != X509_V_OK) - { - // If we have ANY errors, we bail out. - ok = 0; - } - - // Only if ICE_PROTOCOL level logging is on do we worry about this. - if (ICE_SECURITY_LEVEL_PROTOCOL_GLOBAL) - { - char buf[256]; - - X509_NAME_oneline(X509_get_subject_name(err_cert), buf, sizeof(buf)); - - ostringstream outStringStream; - - outStringStream << "depth = " << depth << ":" << buf << endl; - - if (!ok) - { - outStringStream << "verify error: num = " << verifyError << " : " - << X509_verify_cert_error_string(verifyError) << endl; - - } - - switch (verifyError) - { - case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT: - { - X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, sizeof(buf)); - outStringStream << "issuer = " << buf << endl; - break; - } - - case X509_V_ERR_CERT_NOT_YET_VALID: - case X509_V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD: - { - outStringStream << "notBefore =" << getASN1time(X509_get_notBefore(ctx->current_cert)) << endl; - break; - } - - case X509_V_ERR_CERT_HAS_EXPIRED: - case X509_V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD: - { - outStringStream << "notAfter =" << getASN1time(X509_get_notAfter(ctx->current_cert)) << endl; - break; - } - } - - outStringStream << "verify return = " << ok << endl; - - IceSecurity::Ssl::OpenSSL::System::_globalLogger->trace( - IceSecurity::Ssl::OpenSSL::System::_globalTraceLevels->securityCat, outStringStream.str()); - } - - return ok; + // Tricky method to get access to our connection. I would use SSL_get_ex_data() to get
+ // the Connection object, if only I had some way to retrieve the index of the object
+ // in this function. Hence, we have to invent our own reference system here.
+ SSL* ssl = static_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
+ IceSecurity::Ssl::OpenSSL::ConnectionPtr connection = 0;
+ connection = IceSecurity::Ssl::OpenSSL::Connection::getConnection(ssl);
+ assert(connection);
+
+ // Call the connection, get it to perform the verification.
+ return connection->verifyCertificate(ok, ctx); } // This code duplicates functionality that existed in the BIO library of @@ -531,7 +329,7 @@ IceSecurity::Ssl::OpenSSL::System::createServerConnection(int socket) // Set the Accept Connection state for this connection. SSL_set_accept_state(sslConnection); - Connection* connection = new ServerConnection(sslConnection, SystemPtr(this)); + Connection* connection = new ServerConnection(_serverVerifier, sslConnection, SystemPtr(this)); commonConnectionSetup(connection); @@ -562,7 +360,7 @@ IceSecurity::Ssl::OpenSSL::System::createClientConnection(int socket) // Set the Connect Connection state for this connection. SSL_set_connect_state(sslConnection); - Connection* connection = new ClientConnection(sslConnection, SystemPtr(this)); + Connection* connection = new ClientConnection(_clientVerifier, sslConnection, SystemPtr(this)); commonConnectionSetup(connection); @@ -842,6 +640,11 @@ IceSecurity::Ssl::OpenSSL::System::System() _randSeeded = 0; _sslServerContext = 0; _sslClientContext = 0; +
+ // Here we create a default verifier, which does very little other
+ // than check the verification depth. This can be overridden.
+ _clientVerifier = new DefaultCertificateVerifier();
+ _serverVerifier = _clientVerifier;
SSL_load_error_strings(); @@ -912,8 +715,8 @@ IceSecurity::Ssl::OpenSSL::System::initClient(GeneralConfig& general, setKeyCert(_sslClientContext, baseCerts.getRSACert(), privateRSAKey, publicRSAKey); // Process the DSA Certificate - string privateDSAKey = _properties->getProperty("Ice.Security.Ssl.Overrides.Client.DSA.PrivateKey"); - string publicDSAKey = _properties->getProperty("Ice.Security.Ssl.Overrides.Client.DSA.Certificate"); + string privateDSAKey; // = _properties->getProperty("Ice.Security.Ssl.Overrides.Client.DSA.PrivateKey"); + string publicDSAKey; // = _properties->getProperty("Ice.Security.Ssl.Overrides.Client.DSA.Certificate"); setKeyCert(_sslClientContext, baseCerts.getDSACert(), privateDSAKey, publicDSAKey); // Set the DH key agreement parameters. @@ -965,8 +768,8 @@ IceSecurity::Ssl::OpenSSL::System::initServer(GeneralConfig& general, setKeyCert(_sslServerContext, baseCerts.getRSACert(), privateRSAKey, publicRSAKey); // Process the DSA Certificate - string privateDSAKey = _properties->getProperty("Ice.Security.Ssl.Overrides.Server.DSA.PrivateKey"); - string publicDSAKey = _properties->getProperty("Ice.Security.Ssl.Overrides.Server.DSA.Certificate"); + string privateDSAKey; // = _properties->getProperty("Ice.Security.Ssl.Overrides.Server.DSA.PrivateKey"); + string publicDSAKey; // = _properties->getProperty("Ice.Security.Ssl.Overrides.Server.DSA.Certificate"); setKeyCert(_sslServerContext, baseCerts.getDSACert(), privateDSAKey, publicDSAKey); // Set the DH key agreement parameters. @@ -988,8 +791,8 @@ IceSecurity::Ssl::OpenSSL::System::initServer(GeneralConfig& general, SSL_CTX_set_verify(_sslServerContext, general.getVerifyMode(), verifyCallback); // Set the certificate verify depth - SSL_CTX_set_verify_depth(_sslServerContext, general.getVerifyDepth()); - + SSL_CTX_set_verify_depth(_sslServerContext, general.getVerifyDepth());
+
// Set the default context for the SSL system (can be overridden if needed) [SERVER ONLY]. SSL_CTX_set_session_id_context(_sslServerContext, reinterpret_cast<const unsigned char *>(_sessionContext.c_str()), @@ -1145,22 +948,35 @@ IceSecurity::Ssl::OpenSSL::System::addKeyCert(SSL_CTX* sslContext, ICE_METHOD_RET("OpenSSL::System::addKeyCert()"); } -X509* -IceSecurity::Ssl::OpenSSL::System::byteSeqToX509(ByteSeq& byteSeq) +void +IceSecurity::Ssl::OpenSSL::System::addKeyCert(SSL_CTX* sslContext, + const string& privateKey, + const string& publicKey) { - // Create a BIO that reads directly from our ByteSeq! - // NOTE: The reinterpret_cast is required, nasty OpenSSL hack! - BIO* memoryBio = BIO_new_mem_buf(reinterpret_cast<void *>(byteSeq.begin()), byteSeq.size()); + ICE_METHOD_INV("OpenSSL::System::addKeyCert()"); - X509* x509 = PEM_read_bio_X509(memoryBio, 0, 0, 0); + string privKey = privateKey; - if (!x509) + if (privKey.empty()) { - SSLerr(SSL_F_SSL_CTX_USE_CERTIFICATE_FILE, ERR_R_PEM_LIB); + ICE_WARNING("No private key specified - using the certificate."); + privKey = publicKey; + } +
+ // Make a key pair based on the Base64 encoded strings
+ RSAKeyPair keyPair(privateKey, publicKey);
+
+ // Janitors to ensure that everything gets cleaned up properly
+ RSAJanitor rsaJanitor(keyPair.getRSAPrivateKey());
+ X509Janitor x509Janitor(keyPair.getX509PublicKey());
+
+ // Set which Public Key file to use. + if (SSL_CTX_use_certificate(sslContext, x509Janitor.get()) <= 0) + { ContextException contextEx(__FILE__, __LINE__); - contextEx._message = "Unable to load Public Key from memory buffer."; + contextEx._message = "Unable to set certificate from memory."; string sslError = sslGetErrors(); if (!sslError.empty()) @@ -1169,33 +985,17 @@ IceSecurity::Ssl::OpenSSL::System::byteSeqToX509(ByteSeq& byteSeq) contextEx._message += sslError; } - ICE_EXCEPTION(contextEx._message); throw contextEx; } - BIO_free(memoryBio); - - return x509; -} - -RSA* -IceSecurity::Ssl::OpenSSL::System::byteSeqToKey(ByteSeq& byteSeq) -{ - // Create a BIO that reads directly from our ByteSeq! - // NOTE: The reinterpret_cast is required, nasty OpenSSL hack! - BIO* memoryBio = BIO_new_mem_buf(reinterpret_cast<void *>(byteSeq.begin()), byteSeq.size()); - - RSA* rsa = PEM_read_bio_RSAPrivateKey(memoryBio, 0, 0, 0); - - if (!rsa) + // Set which Private Key file to use. + if (SSL_CTX_use_RSAPrivateKey(sslContext, rsaJanitor.get()) <= 0) { - SSLerr(SSL_F_SSL_CTX_USE_PRIVATEKEY_FILE, ERR_R_PEM_LIB); - ContextException contextEx(__FILE__, __LINE__); - contextEx._message = "Unable to load Private Key from memory buffer."; + contextEx._message = "Unable to set private key from memory."; string sslError = sslGetErrors(); if (!sslError.empty()) @@ -1204,112 +1004,11 @@ IceSecurity::Ssl::OpenSSL::System::byteSeqToKey(ByteSeq& byteSeq) contextEx._message += sslError; } - ICE_EXCEPTION(contextEx._message); throw contextEx; } - - BIO_free(memoryBio); - - return rsa; -} - -void -IceSecurity::Ssl::OpenSSL::System::addKeyCert(SSL_CTX* sslContext, - const string& privateKey, - const string& publicKey) -{ - ICE_METHOD_INV("OpenSSL::System::addKeyCert()"); - - string privKey = privateKey; - - if (privKey.empty()) - { - ICE_WARNING("No private key specified - using the certificate."); - - privKey = publicKey; - } - - // - // Convert the strings containing the Key (Private Key) and Certificate (Public Key) - // into byte sequences. - // - ByteSeq publicKeyByteSeq; - ByteSeq privateKeyByteSeq; - - publicKeyByteSeq.reserve(privateKey.size()); - privateKeyByteSeq.reserve(publicKey.size()); - - std::copy(privateKey.begin(), privateKey.end(), back_inserter(privateKeyByteSeq)); - std::copy(publicKey.begin(), publicKey.end(), back_inserter(publicKeyByteSeq)); - - X509* x509 = 0; - RSA* rsa = 0; - - try - { - // These methods should throw exceptions if they can't perform the conversion. - x509 = byteSeqToX509(publicKeyByteSeq); - rsa = byteSeqToKey(privateKeyByteSeq); - - // Set which Public Key file to use. - if (SSL_CTX_use_certificate(sslContext, x509) <= 0) - { - ContextException contextEx(__FILE__, __LINE__); - - contextEx._message = "Unable to set certificate from memory."; - string sslError = sslGetErrors(); - - if (!sslError.empty()) - { - contextEx._message += "\n"; - contextEx._message += sslError; - } - - - ICE_EXCEPTION(contextEx._message); - - throw contextEx; - } - - // Set which Private Key file to use. - if (SSL_CTX_use_RSAPrivateKey(sslContext, rsa) <= 0) - { - ContextException contextEx(__FILE__, __LINE__); - - contextEx._message = "Unable to set private key from memory."; - string sslError = sslGetErrors(); - - if (!sslError.empty()) - { - contextEx._message += "\n"; - contextEx._message += sslError; - } - - ICE_EXCEPTION(contextEx._message); - - throw contextEx; - } - } - catch (...) - { - if (x509) - { - X509_free(x509); - } - - if (rsa) - { - RSA_free(rsa); - } - - throw; - } - - X509_free(x509); - RSA_free(rsa); - +
// Check to see if the Private and Public keys that have been // set against the SSL context match up. if (!SSL_CTX_check_private_key(sslContext)) |