![]() ![]() |
![]() |
File: [Pegasus] / pegasus / src / Pegasus / Common / SSLContext.cpp
(download)
Revision: 1.25.6.6, Mon Apr 26 13:50:45 2004 UTC (20 years, 2 months ago) by h.sterling Branch: RELEASE_2_3_2-branch CVS Tags: RELEASE_2_3_2-testfreeze, RELEASE_2_3_2-releasesnapshot, RELEASE_2_3_2-branch-freeze Changes since 1.25.6.5: +1 -1 lines PEP#: 165 BRANCH: RELEASE_2_3_2-branch TITLE: SSL client verification DESCRIPTION added comments |
//%2003//////////////////////////////////////////////////////////////////////// // // Copyright (c) 2000, 2001, 2002 BMC Software, Hewlett-Packard Development // Company, L. P., IBM Corp., The Open Group, Tivoli Systems. // Copyright (c) 2003 BMC Software; Hewlett-Packard Development Company, L. P.; // IBM Corp.; EMC Corporation, The Open Group. // // Permission is hereby granted, free of charge, to any person obtaining a copy // of this software and associated documentation files (the "Software"), to // deal in the Software without restriction, including without limitation the // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or // sell copies of the Software, and to permit persons to whom the Software is // furnished to do so, subject to the following conditions: // // THE ABOVE COPYRIGHT NOTICE AND THIS PERMISSION NOTICE SHALL BE INCLUDED IN // ALL COPIES OR SUBSTANTIAL PORTIONS OF THE SOFTWARE. THE SOFTWARE IS PROVIDED // "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT // LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR // PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT // HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN // ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // //============================================================================== // // Author: Markus Mueller (sedgewick_de@yahoo.de) // // Modified By: Nag Boranna, Hewlett-Packard Company (nagaraja_boranna@hp.com) // Roger Kumpf, Hewlett-Packard Company (roger_kumpf@hp.com) // Sushma Fernandes, Hewlett-Packard Company (sushma_fernandes@hp.com) // Heather Sterling, IBM (hsterl@us.ibm.com) // //%///////////////////////////////////////////////////////////////////////////// #ifdef PEGASUS_HAS_SSL #define OPENSSL_NO_KRB5 1 #include <openssl/err.h> #include <openssl/ssl.h> #include <openssl/rand.h> #else #define SSL_CTX void #endif // end of PEGASUS_HAS_SSL #include <Pegasus/Common/Destroyer.h> #include <Pegasus/Common/Socket.h> #include <Pegasus/Common/Tracer.h> #include <Pegasus/Common/FileSystem.h> #include <time.h> #include <Pegasus/Common/MessageLoader.h> //l10n #include "SSLContext.h" #include "SSLContextRep.h" typedef struct Timestamp { char year[4]; char month[2]; char day[2]; char hour[2]; char minutes[2]; char seconds[2]; char dot; char microSeconds[6]; char plusOrMinus; char utcOffset[3]; char padding[3]; } Timestamp_t; PEGASUS_USING_STD; PEGASUS_NAMESPACE_BEGIN // // use the following definitions only if SSL is available // #ifdef PEGASUS_HAS_SSL // // certificate handling routine // // ATTN-RK-20020905: This global variable is unsafe with multiple SSL contexts SSLCertificateVerifyFunction* verify_certificate; // Mutex for SSL locks. Mutex* SSLContextRep::_sslLocks = 0; // Mutex for _countRep. Mutex SSLContextRep::_countRepMutex; // Initialise _count for SSLContextRep objects. int SSLContextRep::_countRep = 0; // // Convert ASN1_UTCTIME to CIMDateTime // CIMDateTime getDateTime(const ASN1_UTCTIME *utcTime) { struct tm time; int offset; Timestamp_t timeStamp; char tempString[80]; char plusOrMinus = '+'; memset(&time, '\0', sizeof(time)); #define g2(p) ( ( (p)[0] - '0' ) * 10 + (p)[1] - '0' ) time.tm_year = g2(utcTime->data); if(time.tm_year < 50) { time.tm_year += 100; } time.tm_mon = g2(utcTime->data + 2) - 1; time.tm_mday = g2(utcTime->data + 4); time.tm_hour = g2(utcTime->data + 6); time.tm_min = g2(utcTime->data + 8); time.tm_sec = g2(utcTime->data + 10); if(utcTime->data[12] == 'Z') { offset = 0; } else { offset = g2(utcTime->data + 13) * 60 + g2(utcTime->data + 15); if(utcTime->data[12] == '-') { plusOrMinus = '-'; } } #undef g2 int year = 1900; memset((void *)&timeStamp, 0, sizeof(Timestamp_t)); // Format the date. sprintf((char *) &timeStamp,"%04d%02d%02d%02d%02d%02d.%06d%04d", year + time.tm_year, time.tm_mon + 1, time.tm_mday, time.tm_hour, time.tm_min, time.tm_sec, 0, offset); timeStamp.plusOrMinus = plusOrMinus; CIMDateTime dateTime; dateTime.clear(); strcpy(tempString, (char *)&timeStamp); dateTime.set(tempString); return (dateTime); } // // Callback function that is called by the OpenSSL library. This function // extracts X509 certficate information and pass that on to client application // callback function. // int prepareForCallback(int preVerifyOk, X509_STORE_CTX *ctx) { PEG_METHOD_ENTER(TRC_SSL, "prepareForCallback()"); char buf[256]; X509 *currentCert; int verifyError = X509_V_OK; #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION // if the SSLContext does not have an additional callback // simply return the preverification error // we do not need to go through the additional steps if (verify_certificate == NULL) { return (preVerifyOk); } #endif // // get the current certificate // currentCert = X509_STORE_CTX_get_current_cert(ctx); // // get the default verification error code // int errorCode = X509_STORE_CTX_get_error(ctx); // // get the depth of certificate chain // int depth = X509_STORE_CTX_get_error_depth(ctx); //FUTURE: Not sure what to do with these...? //ssl = X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()); //mydata = SSL_get_ex_data(ssl, mydata_index); // // get the version on the certificate // long version = X509_get_version(currentCert); // // get the serial number of the certificate // long serialNumber = ASN1_INTEGER_get(X509_get_serialNumber(currentCert)); // // get the validity of the certificate // CIMDateTime notBefore = getDateTime(X509_get_notBefore(currentCert)); CIMDateTime notAfter = getDateTime(X509_get_notAfter(currentCert)); // // get the subject name on the certificate // X509_NAME_oneline(X509_get_subject_name(currentCert), buf, 256); String subjectName = String(buf); // // get the default verification error string // String errorStr = String(X509_verify_cert_error_string(errorCode)); // // log the error string if the default verification was failed // if (!preVerifyOk) { PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, "---> SSL: certificate default verification error: " + errorStr); } // // get the issuer name on the certificate // if (!preVerifyOk && (errorCode == X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT)) { X509_NAME_oneline(X509_get_issuer_name(ctx->current_cert), buf, 256); } else { X509_NAME_oneline(X509_get_issuer_name(currentCert), buf, 256); } String issuerName = String(buf); // // Call the verify_certificate() application callback // SSLCertificateInfo certInfo(subjectName, issuerName, version, serialNumber, notBefore, notAfter, depth, errorCode, errorStr, preVerifyOk); if (verify_certificate(certInfo)) { #ifndef PEGASUS_USE_232_CLIENT_VERIFICATION verifyError = X509_V_OK; #endif preVerifyOk = 1; Tracer::trace(TRC_SSL, Tracer::LEVEL4, "--> SSL: verify_certificate() returned X509_V_OK"); } else { #ifndef PEGASUS_USE_232_CLIENT_VERIFICATION verifyError = certInfo.getErrorCode(); #endif preVerifyOk = 0; Tracer::trace(TRC_SSL, Tracer::LEVEL4, "--> SSL: verify_certificate() returned error %d", verifyError); } // We need a way for the server to retain the verification result, // so that in 'optional' settings, we can still continue the connection. // We can then give the verification result to a consumer and let them // decide whether to accept or reject the request. // // The problem is that if we don't reset the error, the server verification // gets messed up on the client side. // // If SSL client verification is disabled, do things the old way, // since the server will never even use the callback. // // If SSL client verification is enabled, do not set the error code explicitly. // Instead, require the client to set the error code within its callback. // i.e. // Boolean verifyCertificate(SSLCertificateInfo cert) // { // cert.setErrorCode(SSLCertificateInfo::V_OK); // return true; // } // // If clients do not do this w/ PEGASUS_USE_232_CLIENT_VERIFICATION enabled, // the server verification will fail because the error code will be the original result. // This is sort of a kluge, but I cannot figure out a better way to do this w/o // some storage tactic. // // This will definitely be fixed in 2.4. For 2.3.2, it shouldn't matter since we // are not using server verification. #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION X509_STORE_CTX_set_error(ctx, certInfo.getErrorCode()); #else X509_STORE_CTX_set_error(ctx, verifyError); #endif PEG_METHOD_EXIT(); return(preVerifyOk); } // // Implement OpenSSL locking callback. // void pegasus_locking_callback( int mode, int type, const char* file, int line) { // Check whether the mode is lock or unlock. if ( mode & CRYPTO_LOCK ) { /*Tracer::trace(TRC_SSL, Tracer::LEVEL4, "Now locking for %d", pegasus_thread_self());*/ SSLContextRep::_sslLocks[type].lock( pegasus_thread_self() ); } else { /*Tracer::trace(TRC_SSL, Tracer::LEVEL4, "Now unlocking for %d", pegasus_thread_self());*/ SSLContextRep::_sslLocks[type].unlock( ); } } // // Initialize OpenSSL Locking and id callbacks. // void SSLContextRep::init_ssl() { // Allocate Memory for _sslLocks. SSL locks needs to be able to handle // up to CRYPTO_num_locks() different mutex locks. PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, "Initialized SSL callback."); _sslLocks= new Mutex[CRYPTO_num_locks()]; // Set the ID callback. The ID callback returns a thread ID. CRYPTO_set_id_callback((unsigned long (*)())pegasus_thread_self); // Set the locking callback to pegasus_locking_callback. CRYPTO_set_locking_callback((void (*)(int,int,const char *,int))pegasus_locking_callback); } // Free OpenSSL Locking and id callbacks. void SSLContextRep::free_ssl() { // Cleanup _sslLocks and set locking & id callback to NULL. CRYPTO_set_locking_callback(NULL); CRYPTO_set_id_callback (NULL); PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, "Freed SSL callback."); delete []_sslLocks; } // // SSL context area // // For the OSs that don't have /dev/random device file, // must enable PEGASUS_SSL_RANDOMFILE flag. // SSLContextRep::SSLContextRep(const String& trustStore, const String& certPath, const String& keyPath, SSLCertificateVerifyFunction* verifyCert, const String& randomFile) { PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::SSLContextRep()"); _trustStore = trustStore.getCString(); _certPath = certPath.getCString(); _keyPath = keyPath.getCString(); verify_certificate = verifyCert; // Initialiaze SSL callbacks and increment the SSLContextRep object _counter. _countRepMutex.lock(pegasus_thread_self()); try { Tracer::trace(TRC_SSL, Tracer::LEVEL4, "Value of Countrep in constructor %d", _countRep); if ( _countRep == 0 ) { init_ssl(); // // load SSL library // Tracer::trace(TRC_SSL, Tracer::LEVEL4, "Before calling SSL_load_error_strings %d", pegasus_thread_self()); SSL_load_error_strings(); Tracer::trace(TRC_SSL, Tracer::LEVEL4, "After calling SSL_load_error_strings %d", pegasus_thread_self()); Tracer::trace(TRC_SSL, Tracer::LEVEL4, "Before calling SSL_library_init %d", pegasus_thread_self()); SSL_library_init(); Tracer::trace(TRC_SSL, Tracer::LEVEL4, "After calling SSL_library_init %d", pegasus_thread_self()); } } catch(...) { _countRepMutex.unlock(); throw; } _countRep++; _countRepMutex.unlock(); _randomInit(randomFile); _sslContext = _makeSSLContext(); PEG_METHOD_EXIT(); } #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION SSLContextRep::SSLContextRep( const String& trustStore, const String& certPath, const String& keyPath, SSLCertificateVerifyFunction* verifyCert, Boolean trustStoreAutoUpdate, Boolean failIfNoPeerCert, const String& randomFile) { PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::SSLContextRep()"); _trustStore = trustStore.getCString(); _certPath = certPath.getCString(); _keyPath = keyPath.getCString(); verify_certificate = verifyCert; _trustStoreAutoUpdate = trustStoreAutoUpdate; _failIfNoPeerCert = failIfNoPeerCert; // if no truststore is specified and no callback is specified, // do not enable peer verification if (trustStore != String::EMPTY || verifyCert != NULL) { _verifyPeer = true; } else { _verifyPeer = false; } // Initialiaze SSL callbacks and increment the SSLContextRep object _counter. _countRepMutex.lock(pegasus_thread_self()); try { Tracer::trace(TRC_SSL, Tracer::LEVEL4, "Value of Countrep in constructor %d", _countRep); if ( _countRep == 0 ) { init_ssl(); // // load SSL library // Tracer::trace(TRC_SSL, Tracer::LEVEL4, "Before calling SSL_load_error_strings %d", pegasus_thread_self()); SSL_load_error_strings(); Tracer::trace(TRC_SSL, Tracer::LEVEL4, "After calling SSL_load_error_strings %d", pegasus_thread_self()); Tracer::trace(TRC_SSL, Tracer::LEVEL4, "Before calling SSL_library_init %d", pegasus_thread_self()); SSL_library_init(); Tracer::trace(TRC_SSL, Tracer::LEVEL4, "After calling SSL_library_init %d", pegasus_thread_self()); } } catch(...) { _countRepMutex.unlock(); throw; } _countRep++; _countRepMutex.unlock(); _randomInit(randomFile); _sslContext = _makeSSLContext(); PEG_METHOD_EXIT(); } #endif SSLContextRep::SSLContextRep(const SSLContextRep& sslContextRep) { PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::SSLContextRep()"); _trustStore = sslContextRep._trustStore; _certPath = sslContextRep._certPath; _keyPath = sslContextRep._keyPath; #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION _verifyPeer = sslContextRep._verifyPeer; _trustStoreAutoUpdate = sslContextRep._trustStoreAutoUpdate; _failIfNoPeerCert = sslContextRep._failIfNoPeerCert; #endif // ATTN: verify_certificate is set implicitly in global variable _randomFile = sslContextRep._randomFile; // Initialiaze SSL callbacks and increment the SSLContextRep object _counter. _countRepMutex.lock(pegasus_thread_self()); try { Tracer::trace(TRC_SSL, Tracer::LEVEL4, "Value of Countrep in copy constructor %d", _countRep); if ( _countRep == 0 ) { init_ssl(); } } catch(...) { _countRepMutex.unlock(); throw; } _countRep++; _countRepMutex.unlock(); _sslContext = _makeSSLContext(); PEG_METHOD_EXIT(); } // // Destructor // SSLContextRep::~SSLContextRep() { PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::~SSLContextRep()"); SSL_CTX_free(_sslContext); // Decrement the SSLContextRep object _counter. _countRepMutex.lock(pegasus_thread_self()); _countRep--; // Free SSL locks if no instances of SSLContextRep exist. try { Tracer::trace(TRC_SSL, Tracer::LEVEL4, "Value of Countrep in destructor %d", _countRep); if ( _countRep == 0 ) { free_ssl(); } } catch(...) { _countRepMutex.unlock(); throw; } _countRepMutex.unlock(); PEG_METHOD_EXIT(); } // // initialize OpenSSL's PRNG // void SSLContextRep::_randomInit(const String& randomFile) { PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::_randomInit()"); Boolean ret; int retVal = 0; const int DEV_RANDOM_BYTES = 64; /* how many bytes to read */ const String devRandom = "/dev/random"; /* random device name */ const String devUrandom = "/dev/urandom"; /* pseudo-random device name */ #ifdef PEGASUS_SSL_DEVRANDOM if ( FileSystem::exists(devRandom) ) { while ( RAND_status() == 0 ) { // // Always attempt to seed from good entropy sources, first // try /dev/random // retVal = RAND_load_file(devRandom.getCString(), DEV_RANDOM_BYTES); if (retVal <= 0) { break; } } } if ( FileSystem::exists(devUrandom) ) { while ( RAND_status() == 0 ) { // // If there isn't /dev/random try /dev/urandom // retVal = RAND_load_file(devUrandom.getCString(), DEV_RANDOM_BYTES); if (retVal <= 0) { break; } } } #endif /* PEGASUS_SSL_DEVRANDOM */ #ifdef PEGASUS_SSL_RANDOMFILE if ( RAND_status() == 0 ) { // // Initialise OpenSSL random number generator. // if ( randomFile == String::EMPTY ) { PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, "Random seed file is required."); PEG_METHOD_EXIT(); //l10n //throw( SSLException("Random seed file required")); MessageLoaderParms parms("Common.SSLContext.RANDOM_SEED_FILE_REQUIRED", "Random seed file required"); throw SSLException(parms); } // // Try the given random seed file // ret = FileSystem::exists(randomFile); if( ret ) { retVal = RAND_load_file(randomFile.getCString(), -1); if ( retVal < 0 ) { PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, "Not enough seed data in seed file: " + randomFile); PEG_METHOD_EXIT(); //l10n // do not put in $0 in default message, but pass in filename for bundle message //throw( SSLException("Not enough seed data in random seed file.")); MessageLoaderParms parms("Common.SSLContext.NOT_ENOUGH_SEED_DATA_IN_FILE", "Not enough seed data in random seed file.", randomFile); throw SSLException(parms); } } else { PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, "seed file - " + randomFile + " does not exist."); PEG_METHOD_EXIT(); //l10n //throw( SSLException("Seed file '" + randomFile + "' does not exist.")); MessageLoaderParms parms("Common.SSLContext.SEED_FILE_DOES_NOT_EXIST", "Seed file '$0' does not exist.", randomFile); throw SSLException(parms); } if ( RAND_status() == 0 ) { // // Try to do more seeding // long seedNumber; #if defined(PEGASUS_PLATFORM_WIN32_IX86_MSVC) srand((unsigned int)time(NULL)); // Initialize seedNumber = rand(); #else srandom((unsigned int)time(NULL)); // Initialize seedNumber = random(); #endif RAND_seed((unsigned char *) &seedNumber, sizeof(seedNumber)); int seedRet = RAND_status(); if ( seedRet == 0 ) { PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, "Not enough seed data in random seed file, RAND_status = " + seedRet); PEG_METHOD_EXIT(); //l10n 485 // do not put in $0 in default message, but pass in filename for bundle message //throw( SSLException("Not enough seed data in random seed file.")); MessageLoaderParms parms("Common.SSLContext.NOT_ENOUGH_SEED_DATA_IN_FILE", "Not enough seed data in random seed file.", randomFile); throw SSLException(parms); } } } #endif /* PEGASUS_SSL_RANDOMFILE */ int seedRet = RAND_status(); if ( seedRet == 0 ) { PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, "Not enough seed data , RAND_status = " + seedRet ); PEG_METHOD_EXIT(); //l10n //throw( SSLException("Not enough seed data.")); MessageLoaderParms parms("Common.SSLContext.NOT_ENOUGH_SEED_DATA", "Not enough seed data."); throw SSLException(parms); } PEG_METHOD_EXIT(); } SSL_CTX * SSLContextRep::_makeSSLContext() { PEG_METHOD_ENTER(TRC_SSL, "SSLContextRep::_makeSSLContext()"); SSL_CTX * sslContext = 0; // // create SSL Context Area // if (!( sslContext = SSL_CTX_new(SSLv23_method()) )) { PEG_METHOD_EXIT(); //l10n //throw( SSLException("Could not get SSL CTX")); MessageLoaderParms parms("Common.SSLContext.COULD_NOT_GET", "Could not get SSL CTX"); throw SSLException(parms); } #ifdef PEGASUS_SSL_WEAKENCRYPTION if (!(SSL_CTX_set_cipher_list(sslContext, SSL_TXT_EXP40))){ //l10n //throw( SSLException("Could not set the cipher list")); MessageLoaderParms parms("Common.SSLContext.COULD_NOT_SET_CIPHER_LIST", "Could not set the cipher list"); throw SSLException(parms); } #endif // // set overall SSL Context flags // SSL_CTX_set_quiet_shutdown(sslContext, 1); SSL_CTX_set_mode(sslContext, SSL_MODE_AUTO_RETRY); SSL_CTX_set_options(sslContext,SSL_OP_ALL); SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF); #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION if (_verifyPeer) { // If SSL_VERIFY_FAIL_IF_NO_PEER_CERT is ON, SSL will immediately be terminated if the client sends no certificate // or sends an untrusted certificate. The callback function is not called in this case; the handshake is simply terminated. // This value has NO effect in from a client perspective if (_failIfNoPeerCert) { SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, prepareForCallback); } else { SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, prepareForCallback); } } else { SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL); } #else if (verify_certificate != NULL || (strncmp(_trustStore, "", 1) != 0)) { SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_CLIENT_ONCE, prepareForCallback); } else { SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL); } #endif // // Check if there is CA certificate file specified. If specified, // load the certificates from the file in to the CA trust store. // if (strncmp(_trustStore, "", 1) != 0) { #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION // // The truststore may be a single file of CA certificates OR // a directory containing multiple CA certificates. // Check which one it is, and call the load_verify_locations function // with the appropriate parameter. Note: It is possible to have both // options, in which the CA file takes precedence over the CA path. // However, since there is currently only one trust parameter to the // SSL functions, only allow one choice here. // modified by hns for client ssl auth const char* CA_Directory = NULL; const char* CA_File = NULL; if (FileSystem::isDirectory((const char*)_trustStore)) { CA_Directory = _trustStore; PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4,"Truststore is a directory"); } else if (FileSystem::exists((const char*)_trustStore)) //ATTN: need to do nocase? { CA_File = _trustStore; PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4,"Truststore is a file"); } #endif // // load certificates in to trust store // #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION if ((!SSL_CTX_load_verify_locations(sslContext, CA_File, CA_Directory)) || #else if ((!SSL_CTX_load_verify_locations(sslContext, _trustStore, NULL)) || #endif (!SSL_CTX_set_default_verify_paths(sslContext))) { PEG_METHOD_EXIT(); //l10n //throw( SSLException("Could not load certificates in to trust store.")); MessageLoaderParms parms("Common.SSLContext.COULD_NOT_LOAD_CERTIFICATES", "Could not load certificates in to trust store."); throw SSLException(parms); } } Boolean keyLoaded = false; // // Check if there is a certificate file (file containing server // certificate) specified. If specified, validate and load the // certificate. // if (strncmp(_certPath, "", 1) != 0) { // // load the specified server certificates // if (SSL_CTX_use_certificate_file(sslContext, _certPath, SSL_FILETYPE_PEM) <=0) { PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, "---> SSL: no certificate found in " + String(_certPath)); PEG_METHOD_EXIT(); //l10n //throw( SSLException("Could not get server certificate.")); MessageLoaderParms parms("Common.SSLContext.COULD_NOT_GET_SERVER_CERTIFICATE", "Could not get server certificate."); throw SSLException(parms); } // // If there is no key file (file containing server // private key) specified or the specified file does not exist, // then try loading the key from the certificate file. // if ( strncmp(_keyPath, "", 1) == 0 || !FileSystem::exists(String(_keyPath)) ) { PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL3, "---> SSL: loading key from" + String(_certPath)); // // load the private key and check for validity // if (!_verifyPrivateKey(sslContext, _certPath)) { PEG_METHOD_EXIT(); //l10n //throw( SSLException("Could not get private key.")); MessageLoaderParms parms("Common.SSLContext.COULD_NOT_GET_PRIVATE_KEY", "Could not get private key."); throw SSLException(parms); } keyLoaded = true; } } // // Check if there is a key file (file containing server // private key) specified and the key was not already loaded. // If specified, validate and load the key. // if (strncmp(_keyPath, "", 1) != 0 && !keyLoaded) { PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL3, "---> SSL: loading key from" + String(_keyPath)); // // load given private key and check for validity // if (!_verifyPrivateKey(sslContext, _keyPath)) { PEG_METHOD_EXIT(); //l10n //throw( SSLException("Could not get private key.")); MessageLoaderParms parms("Common.SSLContext.COULD_NOT_GET_PRIVATE_KEY", "Could not get private key."); throw SSLException(parms); } keyLoaded = true; } PEG_METHOD_EXIT(); return sslContext; } Boolean SSLContextRep::_verifyPrivateKey(SSL_CTX *ctx, const char *keyPath) { PEG_METHOD_ENTER(TRC_SSL, "_verifyPrivateKey()"); if (SSL_CTX_use_PrivateKey_file(ctx, keyPath, SSL_FILETYPE_PEM) <= 0) { PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, "---> SSL: no private key found in " + String(keyPath)); PEG_METHOD_EXIT(); return false; } if (!SSL_CTX_check_private_key(ctx)) { PEG_TRACE_STRING(TRC_SSL, Tracer::LEVEL4, "---> SSL: Private and public key do not match"); PEG_METHOD_EXIT(); return false; } PEG_METHOD_EXIT(); return true; } SSL_CTX * SSLContextRep::getContext() const { return _sslContext; } #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION CString SSLContextRep::getTrustStore() const { return _trustStore; } CString SSLContextRep::getCertPath() const { return _certPath; } CString SSLContextRep::getKeyPath() const { return _keyPath; } Boolean SSLContextRep::isPeerVerificationEnabled() const { return _verifyPeer; } Boolean SSLContextRep::isTrustStoreAutoUpdateEnabled() const { return _trustStoreAutoUpdate; } #endif #else // // these definitions are used if ssl is not available // SSLContextRep::SSLContextRep(const String& trustStore, const String& certPath, const String& keyPath, SSLCertificateVerifyFunction* verifyCert, const String& randomFile) {} #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION SSLContextRep::SSLContextRep(const String& trustStore, const String& certPath, const String& keyPath, SSLCertificateVerifyFunction* verifyCert, Boolean trustStoreAutoUpdate, Boolean failIfNoPeerCert, const String& randomFile) {} #endif SSLContextRep::SSLContextRep(const SSLContextRep& sslContextRep) {} SSLContextRep::~SSLContextRep() {} SSL_CTX * SSLContextRep::_makeSSLContext() { return 0; } Boolean SSLContextRep::_verifyPrivateKey(SSL_CTX *ctx, const char *keyPath) { return false; } SSL_CTX * SSLContextRep::getContext() const { return 0; } #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION CString SSLContextRep::getTrustStore() const { return String::EMPTY.getCString(); } CString SSLContextRep::getCertPath() const { return String::EMPTY.getCString(); } CString SSLContextRep::getKeyPath() const { return String::EMPTY.getCString(); } Boolean SSLContextRep::isPeerVerificationEnabled() const { return false; } Boolean SSLContextRep::isTrustStoreAutoUpdateEnabled() const { return false; } #endif void SSLContextRep::init_ssl() {} void SSLContextRep::free_ssl() {} #endif // end of PEGASUS_HAS_SSL /////////////////////////////////////////////////////////////////////////////// // // SSLContext // /////////////////////////////////////////////////////////////////////////////// SSLContext::SSLContext( const String& trustStore, SSLCertificateVerifyFunction* verifyCert, const String& randomFile) { #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION _rep = new SSLContextRep(trustStore, String::EMPTY, String::EMPTY, verifyCert, false, false, randomFile); #else _rep = new SSLContextRep(trustStore, String::EMPTY, String::EMPTY, verifyCert, randomFile); #endif } #ifdef PEGASUS_USE_DEPRECATED_INTERFACES SSLContext::SSLContext( const String& certPath, SSLCertificateVerifyFunction* verifyCert, const String& randomFile, Boolean isCIMClient) { #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION _rep = new SSLContextRep(certPath, String::EMPTY, String::EMPTY, verifyCert, false, false, randomFile); #else _rep = new SSLContextRep(certPath, String::EMPTY, String::EMPTY, verifyCert, randomFile); #endif } SSLContext::SSLContext( const String& certPath, const String& certKeyPath, SSLCertificateVerifyFunction* verifyCert, const String& randomFile) { #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION _rep = new SSLContextRep(certPath, certKeyPath, String::EMPTY, verifyCert, false, false, randomFile); #else _rep = new SSLContextRep(certPath, certKeyPath, String::EMPTY, verifyCert, randomFile); #endif } #endif SSLContext::SSLContext( const String& trustStore, const String& certPath, const String& keyPath, SSLCertificateVerifyFunction* verifyCert, const String& randomFile) { #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION _rep = new SSLContextRep(trustStore, certPath, keyPath, verifyCert, false, false, randomFile); #else _rep = new SSLContextRep(trustStore, certPath, keyPath, verifyCert, randomFile); #endif } #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION SSLContext::SSLContext( const String& trustStore, const String& certPath, const String& keyPath, SSLCertificateVerifyFunction* verifyCert, Boolean trustStoreAutoUpdate, Boolean failIfNoPeerCert, const String& randomFile) { _rep = new SSLContextRep(trustStore, certPath, keyPath, verifyCert, trustStoreAutoUpdate, failIfNoPeerCert, randomFile); } #endif SSLContext::SSLContext(const SSLContext& sslContext) { _rep = new SSLContextRep(*sslContext._rep); } // Dummy constructor made private to disallow default construction SSLContext::SSLContext() { } SSLContext::~SSLContext() { delete _rep; } #ifdef PEGASUS_USE_232_CLIENT_VERIFICATION String SSLContext::getTrustStore() const { CString trustStore = _rep->getTrustStore(); if (strncmp(trustStore, "", 1) == 0) { return (String::EMPTY); } return (String((const char*) trustStore)); } String SSLContext::getCertPath() const { CString certPath = _rep->getCertPath(); if (strncmp(certPath, "", 1) == 0) { return (String::EMPTY); } return (String((const char*) certPath)); } String SSLContext::getKeyPath() const { CString keyPath = _rep->getKeyPath(); if (strncmp(keyPath, "", 1) == 0) { return (String::EMPTY); } return (String((const char*) keyPath)); } Boolean SSLContext::isPeerVerificationEnabled() const { return (_rep->isPeerVerificationEnabled()); } Boolean SSLContext::isTrustStoreAutoUpdateEnabled() const { return (_rep->isTrustStoreAutoUpdateEnabled()); } #endif /////////////////////////////////////////////////////////////////////////////// // // SSLCertificateInfo // /////////////////////////////////////////////////////////////////////////////// // // Certificate validation result codes. // const int SSLCertificateInfo::V_OK = 0; const int SSLCertificateInfo::V_ERR_UNABLE_TO_GET_ISSUER_CERT = 2; const int SSLCertificateInfo::V_ERR_UNABLE_TO_GET_CRL = 3; const int SSLCertificateInfo::V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE = 4; const int SSLCertificateInfo::V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE = 5; const int SSLCertificateInfo::V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY = 6; const int SSLCertificateInfo::V_ERR_CERT_SIGNATURE_FAILURE = 7; const int SSLCertificateInfo::V_ERR_CRL_SIGNATURE_FAILURE = 8; const int SSLCertificateInfo::V_ERR_CERT_NOT_YET_VALID = 9; const int SSLCertificateInfo::V_ERR_CERT_HAS_EXPIRED = 10; const int SSLCertificateInfo::V_ERR_CRL_NOT_YET_VALID = 11; const int SSLCertificateInfo::V_ERR_CRL_HAS_EXPIRED = 12; const int SSLCertificateInfo::V_ERR_ERROR_IN_CERT_NOT_BEFORE_FIELD = 13; const int SSLCertificateInfo::V_ERR_ERROR_IN_CERT_NOT_AFTER_FIELD = 14; const int SSLCertificateInfo::V_ERR_ERROR_IN_CRL_LAST_UPDATE_FIELD = 15; const int SSLCertificateInfo::V_ERR_ERROR_IN_CRL_NEXT_UPDATE_FIELD = 16; const int SSLCertificateInfo::V_ERR_OUT_OF_MEM = 17; const int SSLCertificateInfo::V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT = 18; const int SSLCertificateInfo::V_ERR_SELF_SIGNED_CERT_IN_CHAIN = 19; const int SSLCertificateInfo::V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY = 20; const int SSLCertificateInfo::V_ERR_UNABLE_TO_VERIFY_LEAF_SIGNATURE = 21; const int SSLCertificateInfo::V_ERR_CERT_CHAIN_TOO_LONG = 22; const int SSLCertificateInfo::V_ERR_CERT_REVOKED = 23; const int SSLCertificateInfo::V_ERR_INVALID_CA = 24; const int SSLCertificateInfo::V_ERR_PATH_LENGTH_EXCEEDED = 25; const int SSLCertificateInfo::V_ERR_INVALID_PURPOSE = 26; const int SSLCertificateInfo::V_ERR_CERT_UNTRUSTED = 27; const int SSLCertificateInfo::V_ERR_CERT_REJECTED = 28; const int SSLCertificateInfo::V_ERR_SUBJECT_ISSUER_MISMATCH = 29; const int SSLCertificateInfo::V_ERR_AKID_SKID_MISMATCH = 30; const int SSLCertificateInfo::V_ERR_AKID_ISSUER_SERIAL_MISMATCH = 31; const int SSLCertificateInfo::V_ERR_KEYUSAGE_NO_CERTSIGN = 32; const int SSLCertificateInfo::V_ERR_APPLICATION_VERIFICATION = 50; class SSLCertificateInfoRep { public: String subjectName; String issuerName; Uint32 depth; Uint32 errorCode; Uint32 respCode; String errorString; Uint32 versionNumber; long serialNumber; CIMDateTime notBefore; CIMDateTime notAfter; }; SSLCertificateInfo::SSLCertificateInfo( const String subjectName, const String issuerName, const int errorDepth, const int errorCode, const int respCode) { _rep = new SSLCertificateInfoRep(); _rep->subjectName = subjectName; _rep->issuerName = issuerName; _rep->versionNumber = 0; _rep->serialNumber = 0; _rep->notBefore = CIMDateTime(); _rep->notAfter = CIMDateTime(); _rep->depth = errorDepth; _rep->errorCode = errorCode; _rep->errorString = String::EMPTY; _rep->respCode = respCode; } SSLCertificateInfo::SSLCertificateInfo( const String subjectName, const String issuerName, const Uint32 versionNumber, const long serialNumber, const CIMDateTime notBefore, const CIMDateTime notAfter, const Uint32 depth, const Uint32 errorCode, const String errorString, const Uint32 respCode) { _rep = new SSLCertificateInfoRep(); _rep->subjectName = subjectName; _rep->issuerName = issuerName; _rep->versionNumber = versionNumber; _rep->serialNumber = serialNumber; _rep->notBefore = notBefore; _rep->notAfter = notAfter; _rep->depth = depth; _rep->errorCode = errorCode; _rep->errorString = errorString; _rep->respCode = respCode; } SSLCertificateInfo::SSLCertificateInfo( const SSLCertificateInfo& certificateInfo) { _rep = new SSLCertificateInfoRep(); _rep->subjectName = certificateInfo._rep->subjectName; _rep->issuerName = certificateInfo._rep->issuerName; _rep->versionNumber = certificateInfo._rep->versionNumber; _rep->serialNumber = certificateInfo._rep->serialNumber; _rep->notBefore = certificateInfo._rep->notBefore; _rep->notAfter = certificateInfo._rep->notAfter; _rep->depth = certificateInfo._rep->depth; _rep->errorCode = certificateInfo._rep->errorCode; _rep->errorString = certificateInfo._rep->errorString; _rep->respCode = certificateInfo._rep->respCode; } // Dummy constructor made private to disallow default construction SSLCertificateInfo::SSLCertificateInfo() { } SSLCertificateInfo::~SSLCertificateInfo() { delete _rep; } String SSLCertificateInfo::getSubjectName() const { return (_rep->subjectName); } String SSLCertificateInfo::getIssuerName() const { return (_rep->issuerName); } Uint32 SSLCertificateInfo::getVersionNumber() const { return (_rep->versionNumber); } long SSLCertificateInfo::getSerialNumber() const { return (_rep->serialNumber); } CIMDateTime SSLCertificateInfo::getNotBefore() const { return (_rep->notBefore); } CIMDateTime SSLCertificateInfo::getNotAfter() const { return (_rep->notAfter); } Uint32 SSLCertificateInfo::getErrorDepth() const { return (_rep->depth); } Uint32 SSLCertificateInfo::getErrorCode() const { return (_rep->errorCode); } void SSLCertificateInfo::setErrorCode(const int errorCode) { _rep->errorCode = errorCode; } String SSLCertificateInfo::getErrorString() const { return (_rep->errorString); } Uint32 SSLCertificateInfo::getResponseCode() const { return (_rep->respCode); } void SSLCertificateInfo::setResponseCode(const int respCode) { _rep->respCode = respCode; } PEGASUS_NAMESPACE_END
No CVS admin address has been configured |
Powered by ViewCVS 0.9.2 |