diff options
author | Anthony Neal <aneal@zeroc.com> | 2002-03-18 17:51:29 +0000 |
---|---|---|
committer | Anthony Neal <aneal@zeroc.com> | 2002-03-18 17:51:29 +0000 |
commit | 0e943ab6c7159ac053a9d4da4ff6ac37c801ff38 (patch) | |
tree | 07b6189539cfd40c9c6bbf579d0e4b0bb205dbe3 /cpp/src/Ice/SystemOpenSSL.cpp | |
parent | bug fix: create copy of Identity (diff) | |
download | ice-0e943ab6c7159ac053a9d4da4ff6ac37c801ff38.tar.bz2 ice-0e943ab6c7159ac053a9d4da4ff6ac37c801ff38.tar.xz ice-0e943ab6c7159ac053a9d4da4ff6ac37c801ff38.zip |
Renamed all the Ssl* files. Modified the config/TestUtil.py file to include
a clientServerHybridTest - handles the test case that client and server
are BOTH client and server roles.
Diffstat (limited to 'cpp/src/Ice/SystemOpenSSL.cpp')
-rw-r--r-- | cpp/src/Ice/SystemOpenSSL.cpp | 593 |
1 files changed, 593 insertions, 0 deletions
diff --git a/cpp/src/Ice/SystemOpenSSL.cpp b/cpp/src/Ice/SystemOpenSSL.cpp new file mode 100644 index 00000000000..098f09daaba --- /dev/null +++ b/cpp/src/Ice/SystemOpenSSL.cpp @@ -0,0 +1,593 @@ +// ********************************************************************** +// +// 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 + +// +// This needs to be first since <openssl/e_os.h> #include <windows.h> +// without our configuration settings. +// +#include <IceUtil/Config.h> +#include <IceUtil/Mutex.h> +#include <Ice/SslConnectionOpenSSL.h> +#include <Ice/SystemOpenSSL.h> +#include <Ice/SslException.h> +#include <Ice/ConfigParser.h> +#include <Ice/OpenSSLJanitors.h> +#include <Ice/TraceLevels.h> +#include <Ice/Logger.h> + +#include <openssl/e_os.h> +#include <openssl/rand.h> + +#include <sstream> + +using namespace std; +using IceInternal::TraceLevelsPtr; +using Ice::LoggerPtr; + +using IceSSL::OpenSSL::ContextException; +using IceSSL::OpenSSL::UnsupportedContextException; +using IceSSL::SystemInternalPtr; + +IceSSL::ConnectionPtr +IceSSL::OpenSSL::System::createConnection(ContextType connectionType, int socket) +{ + if (connectionType == ClientServer) + { + UnsupportedContextException unsupportedException(__FILE__, __LINE__); + + unsupportedException._message = "Unable to create ClientServer connections."; + + throw unsupportedException; + } + + // Configure the context if need be. + if (!isConfigured(connectionType)) + { + configure(connectionType); + } + + IceSSL::ConnectionPtr connection; + + if (connectionType == Client) + { + connection = _clientContext.createConnection(socket, this); + } + else if (connectionType == Server) + { + connection = _serverContext.createConnection(socket, this); + } + + return connection; +} + +void +IceSSL::OpenSSL::System::shutdown() +{ + // Free our temporary RSA keys. + RSAMap::iterator iRSA = _tempRSAKeys.begin(); + RSAMap::iterator eRSA = _tempRSAKeys.end(); + + while (iRSA != eRSA) + { + RSA_free((*iRSA).second); + iRSA++; + } + + // Free our temporary DH params. + DHMap::iterator iDH = _tempDHKeys.begin(); + DHMap::iterator eDH = _tempDHKeys.end(); + + while (iDH != eDH) + { + DH_free((*iDH).second); + iDH++; + } +} + +bool +IceSSL::OpenSSL::System::isConfigured(ContextType contextType) +{ + bool retCode = false; + + switch (contextType) + { + case Client : + { + retCode = _clientContext.isConfigured(); + break; + } + + case Server : + { + retCode = _serverContext.isConfigured(); + break; + } + + case ClientServer : + { + retCode = _clientContext.isConfigured() && _serverContext.isConfigured(); + break; + } + } + + return retCode; +} + +void +IceSSL::OpenSSL::System::configure(ContextType contextType) +{ + switch (contextType) + { + case Client : + { + string configFile = _properties->getProperty("Ice.SSL.Client.Config"); + string certPath = _properties->getProperty("Ice.SSL.Client.CertPath"); + loadConfig(Client, configFile, certPath); + break; + } + + case Server : + { + string configFile = _properties->getProperty("Ice.SSL.Server.Config"); + string certPath = _properties->getProperty("Ice.SSL.Server.CertPath"); + loadConfig(Server, configFile, certPath); + break; + } + + case ClientServer : + { + string clientConfigFile = _properties->getProperty("Ice.SSL.Client.Config"); + string clientCertPath = _properties->getProperty("Ice.SSL.Client.CertPath"); + string serverConfigFile = _properties->getProperty("Ice.SSL.Server.Config"); + string serverCertPath = _properties->getProperty("Ice.SSL.Server.CertPath"); + + // Short cut, so that we only have to load the file once. + if ((clientConfigFile == serverConfigFile) && (clientCertPath == serverCertPath)) + { + loadConfig(ClientServer, clientConfigFile, clientCertPath); + } + else + { + loadConfig(Client, clientConfigFile, clientCertPath); + loadConfig(Server, serverConfigFile, serverCertPath); + } + break; + } + } +} + +void +IceSSL::OpenSSL::System::loadConfig(ContextType contextType, + const std::string& configFile, + const std::string& certPath) +{ + if (configFile.empty()) + { + IceSSL::ConfigurationLoadingException configEx(__FILE__, __LINE__); + + string contextString; + + switch (contextType) + { + case Client : + { + contextString = "Client"; + break; + } + + case Server : + { + contextString = "Server"; + break; + } + + case ClientServer : + { + contextString = "Client/Server"; + break; + } + } + + configEx._message = "No SSL configuration file specified for "; + configEx._message += contextString; + configEx._message += "."; + + throw configEx; + } + + ConfigParser sslConfig(configFile, certPath); + + sslConfig.setTrace(_traceLevels); + sslConfig.setLogger(_logger); + + // Actually parse the file now. + sslConfig.process(); + + if (contextType == Client || contextType == ClientServer) + { + GeneralConfig clientGeneral; + CertificateAuthority clientCertAuth; + BaseCertificates clientBaseCerts; + + // Walk the parse tree, get the Client configuration. + if (sslConfig.loadClientConfig(clientGeneral, clientCertAuth, clientBaseCerts)) + { + initRandSystem(clientGeneral.getRandomBytesFiles()); + + _clientContext.configure(clientGeneral, clientCertAuth, clientBaseCerts); + } + } + + if (contextType == Server || contextType == ClientServer) + { + GeneralConfig serverGeneral; + CertificateAuthority serverCertAuth; + BaseCertificates serverBaseCerts; + TempCertificates serverTempCerts; + + // Walk the parse tree, get the Server configuration. + if (sslConfig.loadServerConfig(serverGeneral, serverCertAuth, serverBaseCerts, serverTempCerts)) + { + initRandSystem(serverGeneral.getRandomBytesFiles()); + + loadTempCerts(serverTempCerts); + + _serverContext.configure(serverGeneral, serverCertAuth, serverBaseCerts); + + if (_traceLevels->security >= IceSSL::SECURITY_PROTOCOL) + { + ostringstream s; + + s << "Temp Certificates - Server" << endl; + s << "--------------------------" << endl; + s << serverTempCerts << endl; + + _logger->trace(_traceLevels->securityCat, s.str()); + } + } + } +} + +RSA* +IceSSL::OpenSSL::System::getRSAKey(int isExport, int keyLength) +{ + IceUtil::Mutex::Lock sync(_tempRSAKeysMutex); + + RSA* rsa_tmp = 0; + + RSAMap::iterator retVal = _tempRSAKeys.find(keyLength); + + // Does the key already exist? + if (retVal != _tempRSAKeys.end()) + { + // Yes! Use it. + rsa_tmp = (*retVal).second; + + assert(rsa_tmp != 0); + } + else + { + const RSACertMap::iterator& it = _tempRSAFileMap.find(keyLength); + + // First we try to load a private and public key from specified files + if (it != _tempRSAFileMap.end()) + { + CertificateDesc& rsaKeyCert = (*it).second; + + const string& privKeyFile = rsaKeyCert.getPrivate().getFileName(); + const string& pubCertFile = rsaKeyCert.getPublic().getFileName(); + + RSA* rsaCert = 0; + RSA* rsaKey = 0; + BIO* bio = 0; + + if ((bio = BIO_new_file(pubCertFile.c_str(), "r")) != 0) + { + BIOJanitor bioJanitor(bio); + + rsaCert = PEM_read_bio_RSAPublicKey(bio, 0, 0, 0); + } + + if (rsaCert != 0) + { + if ((bio = BIO_new_file(privKeyFile.c_str(), "r")) != 0) + { + BIOJanitor bioJanitor(bio); + + rsaKey = PEM_read_bio_RSAPrivateKey(bio, &rsaCert, 0, 0); + } + } + + // Now, if all was well, the Certificate and Key should both be loaded into + // rsaCert. We check to ensure that both are not 0, because if either are, + // one of the reads failed. + + if ((rsaCert != 0) && (rsaKey != 0)) + { + rsa_tmp = rsaCert; + } + else + { + RSA_free(rsaCert); + rsaCert = 0; + } + } + + // Couldn't load file, last ditch effort - generate a key on the fly. + if (rsa_tmp == 0) + { + rsa_tmp = RSA_generate_key(keyLength, RSA_F4, 0, 0); + } + + // Save in our temporary key cache. + if (rsa_tmp != 0) + { + _tempRSAKeys[keyLength] = rsa_tmp; + } + } + + return rsa_tmp; +} + +DH* +IceSSL::OpenSSL::System::getDHParams(int isExport, int keyLength) +{ + IceUtil::Mutex::Lock sync(_tempDHKeysMutex); + + DH *dh_tmp = 0; + + const DHMap::iterator& retVal = _tempDHKeys.find(keyLength); + + // Does the key already exist? + if (retVal != _tempDHKeys.end()) + { + // Yes! Use it. + dh_tmp = (*retVal).second; + } + else + { + const DHParamsMap::iterator& it = _tempDHParamsFileMap.find(keyLength); + + // First we try to load params from specified files + if (it != _tempDHParamsFileMap.end()) + { + DiffieHellmanParamsFile& dhParamsFile = (*it).second; + + string dhFile = dhParamsFile.getFileName(); + + dh_tmp = loadDHParam(dhFile.c_str()); + + if (dh_tmp != 0) + { + _tempDHKeys[keyLength] = dh_tmp; + } + } + } + + return dh_tmp; +} + +void +IceSSL::OpenSSL::System::setCertificateVerifier(ContextType contextType, + const IceSSL::CertificateVerifierPtr& verifier) +{ + CertificateVerifierPtr castVerifier = CertificateVerifierPtr::dynamicCast(verifier); + + if (!castVerifier.get()) + { + IceSSL::CertificateVerifierTypeException cvtEx(__FILE__, __LINE__); + throw cvtEx; + } + + if (contextType == Client || contextType == ClientServer) + { + _clientContext.setCertificateVerifier(castVerifier); + } + + if (contextType == Server || contextType == ClientServer) + { + _serverContext.setCertificateVerifier(castVerifier); + } +} + +void +IceSSL::OpenSSL::System::addTrustedCertificate(ContextType contextType, const string& certString) +{ + if (contextType == Client || contextType == ClientServer) + { + _clientContext.addTrustedCertificate(certString); + } + + if (contextType == Server || contextType == ClientServer) + { + _serverContext.addTrustedCertificate(certString); + } +} + +void +IceSSL::OpenSSL::System::setRSAKeysBase64(ContextType contextType, + const std::string& privateKey, + const std::string& publicKey) +{ + if (contextType == Client || contextType == ClientServer) + { + _clientContext.setRSAKeysBase64(privateKey, publicKey); + } + + if (contextType == Server || contextType == ClientServer) + { + _serverContext.setRSAKeysBase64(privateKey, publicKey); + } +} + +void +IceSSL::OpenSSL::System::setRSAKeys(ContextType contextType, + const ::Ice::ByteSeq& privateKey, + const ::Ice::ByteSeq& publicKey) +{ + if (contextType == Client || contextType == ClientServer) + { + _clientContext.setRSAKeys(privateKey, publicKey); + } + + if (contextType == Server || contextType == ClientServer) + { + _serverContext.setRSAKeys(privateKey, publicKey); + } +} + +// +// Protected +// + +IceSSL::OpenSSL::System::System(const IceInternal::InstancePtr& instance) : + IceSSL::SystemInternal(instance), + _serverContext(instance), + _clientContext(instance) +{ + _randSeeded = 0; + + SSL_load_error_strings(); + + OpenSSL_add_ssl_algorithms(); +} + +IceSSL::OpenSSL::System::~System() +{ + shutdown(); +} + +// +// Private +// + +int +IceSSL::OpenSSL::System::seedRand() +{ + int retCode = 1; + char buffer[1024]; + +#ifdef WINDOWS + RAND_screen(); +#endif + + const char* file = RAND_file_name(buffer, sizeof(buffer)); + + if (file == 0 || !RAND_load_file(file, -1)) + { + retCode = 0; + } + else + { + _randSeeded = 1; + } + + return retCode; +} + +long +IceSSL::OpenSSL::System::loadRandFiles(const string& names) +{ + long tot = 0; + + if (!names.empty()) + { + int egd; + + // Make a modifiable copy of the string. + char* namesString = new char[names.length() + 1]; + assert(namesString != 0); + + strcpy(namesString, names.c_str()); + + char seps[5]; + + sprintf(seps, "%c", LIST_SEPARATOR_CHAR); + + char* token = strtok(namesString, seps); + + while (token != 0) + { + egd = RAND_egd(token); + + if (egd > 0) + { + tot += egd; + } + else + { + tot += RAND_load_file(token, -1); + } + + token = strtok(0, seps); + } + + if (tot > 512) + { + _randSeeded = 1; + } + + delete []namesString; + } + + return tot; +} + +void +IceSSL::OpenSSL::System::initRandSystem(const string& randBytesFiles) +{ + if (!_randSeeded) + { + long randBytesLoaded = 0; + + if (!seedRand() && randBytesFiles.empty() && !RAND_status() && + (_traceLevels->security >= IceSSL::SECURITY_WARNINGS)) + { + _logger->trace(_traceLevels->securityCat, + "WRN There is a lack of random data, consider specifying a random data file."); + } + + if (!randBytesFiles.empty()) + { + randBytesLoaded = loadRandFiles(randBytesFiles); + } + } +} + +void +IceSSL::OpenSSL::System::loadTempCerts(TempCertificates& tempCerts) +{ + RSAVector::iterator iRSA = tempCerts.getRSACerts().begin(); + RSAVector::iterator eRSA = tempCerts.getRSACerts().end(); + + while (iRSA != eRSA) + { + _tempRSAFileMap[(*iRSA).getKeySize()] = *iRSA; + iRSA++; + } + + DHVector::iterator iDHP = tempCerts.getDHParams().begin(); + DHVector::iterator eDHP = tempCerts.getDHParams().end(); + + while (iDHP != eDHP) + { + _tempDHParamsFileMap[(*iDHP).getKeySize()] = *iDHP; + iDHP++; + } +} |