summaryrefslogtreecommitdiff
path: root/cpp/src/IceSSL/Context.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'cpp/src/IceSSL/Context.cpp')
-rw-r--r--cpp/src/IceSSL/Context.cpp570
1 files changed, 289 insertions, 281 deletions
diff --git a/cpp/src/IceSSL/Context.cpp b/cpp/src/IceSSL/Context.cpp
index 8f508bedcf2..c70fd1f3992 100644
--- a/cpp/src/IceSSL/Context.cpp
+++ b/cpp/src/IceSSL/Context.cpp
@@ -104,110 +104,54 @@ IceSSL::Context::Context(const InstancePtr& instance, const string& propPrefix,
throw ex;
}
- //
- // Store a pointer to ourself for use in OpenSSL callbacks.
- //
- SSL_CTX_set_ex_data(_ctx, 0, this);
-
- PropertiesPtr properties = _instance->communicator()->getProperties();
-
- //
- // Check for a default directory. We look in this directory for
- // files mentioned in the configuration.
- //
+ try
{
- _defaultDir = properties->getProperty(propPrefix + "DefaultDir");
- }
+ //
+ // Store a pointer to ourself for use in OpenSSL callbacks.
+ //
+ SSL_CTX_set_ex_data(_ctx, 0, this);
- //
- // Select protocols.
- //
- {
- string protocols = properties->getProperty(propPrefix + "Protocols");
- if(!protocols.empty())
+ PropertiesPtr properties = _instance->communicator()->getProperties();
+
+ //
+ // Check for a default directory. We look in this directory for
+ // files mentioned in the configuration.
+ //
{
- parseProtocols(protocols);
+ _defaultDir = properties->getProperty(propPrefix + "DefaultDir");
}
- }
- //
- // Determine whether a certificate is required from the peer.
- //
- {
- int verifyPeer = properties->getPropertyAsIntWithDefault(propPrefix + "VerifyPeer", 2);
- int sslVerifyMode;
- switch(verifyPeer)
- {
- case 0:
- sslVerifyMode = SSL_VERIFY_NONE;
- break;
- case 1:
- sslVerifyMode = SSL_VERIFY_PEER;
- break;
- case 2:
- sslVerifyMode = SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
- break;
- default:
+ //
+ // Select protocols.
+ //
{
- string msg = "IceSSL: invalid value for " + propPrefix + "VerifyPeer";
- if(_instance->securityTraceLevel() >= 1)
+ string protocols = properties->getProperty(propPrefix + "Protocols");
+ if(!protocols.empty())
{
- _logger->trace(_instance->securityTraceCategory(), msg);
+ parseProtocols(protocols);
}
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
- }
- }
- SSL_CTX_set_verify(_ctx, sslVerifyMode, opensslVerifyCallback);
- }
-
- //
- // If the configuration defines a password, or the application has supplied
- // a password prompt object, then register a password callback. Otherwise,
- // let OpenSSL use its default behavior.
- //
- {
- // TODO: Support quoted value?
- string password = properties->getProperty(propPrefix + "Password");
- if(!password.empty() || _instance->passwordPrompt())
- {
- SSL_CTX_set_default_passwd_cb(_ctx, opensslPasswordCallback);
- SSL_CTX_set_default_passwd_cb_userdata(_ctx, this);
- _password = password;
}
- }
- int passwordRetryMax = properties->getPropertyAsIntWithDefault(propPrefix + "PasswordRetryMax", 3);
-
- //
- // Establish the location of CA certificates.
- //
- {
- string caFile = properties->getProperty(propPrefix + "CertAuthFile");
- string caDir = properties->getPropertyWithDefault(propPrefix + "CertAuthDir", _defaultDir);
- const char* file = 0;
- const char* dir = 0;
- if(!caFile.empty())
+ //
+ // Determine whether a certificate is required from the peer.
+ //
{
- if(!checkPath(caFile, false))
+ int verifyPeer = properties->getPropertyAsIntWithDefault(propPrefix + "VerifyPeer", 2);
+ int sslVerifyMode;
+ switch(verifyPeer)
{
- string msg = "IceSSL: CA certificate file not found:\n" + caFile;
- if(_instance->securityTraceLevel() >= 1)
- {
- _logger->trace(_instance->securityTraceCategory(), msg);
- }
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
- }
- file = caFile.c_str();
- }
- if(!caDir.empty())
- {
- if(!checkPath(caDir, true))
+ case 0:
+ sslVerifyMode = SSL_VERIFY_NONE;
+ break;
+ case 1:
+ sslVerifyMode = SSL_VERIFY_PEER;
+ break;
+ case 2:
+ sslVerifyMode = SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
+ break;
+ default:
{
- string msg = "IceSSL: CA certificate directory not found:\n" + caDir;
+ string msg = "IceSSL: invalid value for " + propPrefix + "VerifyPeer";
if(_instance->securityTraceLevel() >= 1)
{
_logger->trace(_instance->securityTraceCategory(), msg);
@@ -216,86 +160,56 @@ IceSSL::Context::Context(const InstancePtr& instance, const string& propPrefix,
ex.reason = msg;
throw ex;
}
- dir = caDir.c_str();
+ }
+ SSL_CTX_set_verify(_ctx, sslVerifyMode, opensslVerifyCallback);
}
- if(file || dir)
+
+ //
+ // If the configuration defines a password, or the application has supplied
+ // a password prompt object, then register a password callback. Otherwise,
+ // let OpenSSL use its default behavior.
+ //
{
- //
- // The certificate may be stored in an encrypted file, so handle
- // password retries.
- //
- int count = 0;
- int err;
- while(count < passwordRetryMax)
+ // TODO: Support quoted value?
+ string password = properties->getProperty(propPrefix + "Password");
+ if(!password.empty() || _instance->passwordPrompt())
{
- ERR_clear_error();
- err = SSL_CTX_load_verify_locations(_ctx, file, dir);
- if(err || !passwordError())
- {
- break;
- }
- ++count;
- }
- if(err == 0)
- {
- string msg = "IceSSL: unable to establish CA certificates";
- if(passwordError())
- {
- msg += ":\ninvalid password";
- }
- else
- {
- string err = _instance->sslErrors();
- if(!err.empty())
- {
- msg += ":\n" + err;
- }
- }
- if(_instance->securityTraceLevel() >= 1)
- {
- _logger->trace(_instance->securityTraceCategory(), msg);
- }
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
+ SSL_CTX_set_default_passwd_cb(_ctx, opensslPasswordCallback);
+ SSL_CTX_set_default_passwd_cb_userdata(_ctx, this);
+ _password = password;
}
}
- }
- //
- // Establish the certificate chains and private keys. One RSA certificate and
- // one DSA certificate are allowed.
- //
- {
-#ifdef _WIN32
- const string sep = ";";
-#else
- const string sep = ":";
-#endif
- string certFile = properties->getProperty(propPrefix + "CertFile");
- string keyFile = properties->getProperty(propPrefix + "KeyFile");
- vector<string>::size_type numCerts = 0;
- if(!certFile.empty())
+ int passwordRetryMax = properties->getPropertyAsIntWithDefault(propPrefix + "PasswordRetryMax", 3);
+
+ //
+ // Establish the location of CA certificates.
+ //
{
- vector<string> files;
- if(!splitString(certFile, sep, false, files) || files.size() > 2)
+ string caFile = properties->getProperty(propPrefix + "CertAuthFile");
+ string caDir = properties->getPropertyWithDefault(propPrefix + "CertAuthDir", _defaultDir);
+ const char* file = 0;
+ const char* dir = 0;
+ if(!caFile.empty())
{
- string msg = "IceSSL: invalid value for " + propPrefix + "CertFile:\n" + certFile;
- if(_instance->securityTraceLevel() >= 1)
+ if(!checkPath(caFile, false))
{
- _logger->trace(_instance->securityTraceCategory(), msg);
+ string msg = "IceSSL: CA certificate file not found:\n" + caFile;
+ if(_instance->securityTraceLevel() >= 1)
+ {
+ _logger->trace(_instance->securityTraceCategory(), msg);
+ }
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
}
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
+ file = caFile.c_str();
}
- numCerts = files.size();
- for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
+ if(!caDir.empty())
{
- string file = *p;
- if(!checkPath(file, false))
+ if(!checkPath(caDir, true))
{
- string msg = "IceSSL: certificate file not found:\n" + file;
+ string msg = "IceSSL: CA certificate directory not found:\n" + caDir;
if(_instance->securityTraceLevel() >= 1)
{
_logger->trace(_instance->securityTraceCategory(), msg);
@@ -304,6 +218,10 @@ IceSSL::Context::Context(const InstancePtr& instance, const string& propPrefix,
ex.reason = msg;
throw ex;
}
+ dir = caDir.c_str();
+ }
+ if(file || dir)
+ {
//
// The certificate may be stored in an encrypted file, so handle
// password retries.
@@ -313,7 +231,7 @@ IceSSL::Context::Context(const InstancePtr& instance, const string& propPrefix,
while(count < passwordRetryMax)
{
ERR_clear_error();
- err = SSL_CTX_use_certificate_chain_file(_ctx, file.c_str());
+ err = SSL_CTX_load_verify_locations(_ctx, file, dir);
if(err || !passwordError())
{
break;
@@ -322,7 +240,7 @@ IceSSL::Context::Context(const InstancePtr& instance, const string& propPrefix,
}
if(err == 0)
{
- string msg = "IceSSL: unable to load certificate chain from file " + file;
+ string msg = "IceSSL: unable to establish CA certificates";
if(passwordError())
{
msg += ":\ninvalid password";
@@ -345,41 +263,100 @@ IceSSL::Context::Context(const InstancePtr& instance, const string& propPrefix,
}
}
}
- if(keyFile.empty())
- {
- keyFile = certFile; // Assume the certificate file also contains the private key.
- }
- if(!keyFile.empty())
+
+ //
+ // Establish the certificate chains and private keys. One RSA certificate and
+ // one DSA certificate are allowed.
+ //
{
- vector<string> files;
- if(!splitString(keyFile, sep, false, files) || files.size() > 2)
+#ifdef _WIN32
+ const string sep = ";";
+#else
+ const string sep = ":";
+#endif
+ string certFile = properties->getProperty(propPrefix + "CertFile");
+ string keyFile = properties->getProperty(propPrefix + "KeyFile");
+ vector<string>::size_type numCerts = 0;
+ if(!certFile.empty())
{
- string msg = "IceSSL: invalid value for " + propPrefix + "KeyFile:\n" + keyFile;
- if(_instance->securityTraceLevel() >= 1)
+ vector<string> files;
+ if(!splitString(certFile, sep, false, files) || files.size() > 2)
{
- _logger->trace(_instance->securityTraceCategory(), msg);
+ string msg = "IceSSL: invalid value for " + propPrefix + "CertFile:\n" + certFile;
+ if(_instance->securityTraceLevel() >= 1)
+ {
+ _logger->trace(_instance->securityTraceCategory(), msg);
+ }
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
}
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
- }
- if(files.size() != numCerts)
- {
- string msg = "IceSSL: " + propPrefix + "KeyFile does not agree with " + propPrefix + "CertFile";
- if(_instance->securityTraceLevel() >= 1)
+ numCerts = files.size();
+ for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
{
- _logger->trace(_instance->securityTraceCategory(), msg);
+ string file = *p;
+ if(!checkPath(file, false))
+ {
+ string msg = "IceSSL: certificate file not found:\n" + file;
+ if(_instance->securityTraceLevel() >= 1)
+ {
+ _logger->trace(_instance->securityTraceCategory(), msg);
+ }
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
+ }
+ //
+ // The certificate may be stored in an encrypted file, so handle
+ // password retries.
+ //
+ int count = 0;
+ int err;
+ while(count < passwordRetryMax)
+ {
+ ERR_clear_error();
+ err = SSL_CTX_use_certificate_chain_file(_ctx, file.c_str());
+ if(err || !passwordError())
+ {
+ break;
+ }
+ ++count;
+ }
+ if(err == 0)
+ {
+ string msg = "IceSSL: unable to load certificate chain from file " + file;
+ if(passwordError())
+ {
+ msg += ":\ninvalid password";
+ }
+ else
+ {
+ string err = _instance->sslErrors();
+ if(!err.empty())
+ {
+ msg += ":\n" + err;
+ }
+ }
+ if(_instance->securityTraceLevel() >= 1)
+ {
+ _logger->trace(_instance->securityTraceCategory(), msg);
+ }
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
+ }
}
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
}
- for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
+ if(keyFile.empty())
{
- string file = *p;
- if(!checkPath(file, false))
+ keyFile = certFile; // Assume the certificate file also contains the private key.
+ }
+ if(!keyFile.empty())
+ {
+ vector<string> files;
+ if(!splitString(keyFile, sep, false, files) || files.size() > 2)
{
- string msg = "IceSSL: key file not found:\n" + file;
+ string msg = "IceSSL: invalid value for " + propPrefix + "KeyFile:\n" + keyFile;
if(_instance->securityTraceLevel() >= 1)
{
_logger->trace(_instance->securityTraceCategory(), msg);
@@ -388,37 +365,75 @@ IceSSL::Context::Context(const InstancePtr& instance, const string& propPrefix,
ex.reason = msg;
throw ex;
}
- //
- // The private key may be stored in an encrypted file, so handle
- // password retries.
- //
- int count = 0;
- int err;
- while(count < passwordRetryMax)
+ if(files.size() != numCerts)
{
- ERR_clear_error();
- err = SSL_CTX_use_PrivateKey_file(_ctx, file.c_str(), SSL_FILETYPE_PEM);
- if(err || !passwordError())
+ string msg = "IceSSL: " + propPrefix + "KeyFile does not agree with " + propPrefix + "CertFile";
+ if(_instance->securityTraceLevel() >= 1)
{
- break;
+ _logger->trace(_instance->securityTraceCategory(), msg);
}
- ++count;
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
}
- if(err == 0)
+ for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
{
- string msg = "IceSSL: unable to load private key from file " + file;
- if(passwordError())
+ string file = *p;
+ if(!checkPath(file, false))
{
- msg += ":\ninvalid password";
+ string msg = "IceSSL: key file not found:\n" + file;
+ if(_instance->securityTraceLevel() >= 1)
+ {
+ _logger->trace(_instance->securityTraceCategory(), msg);
+ }
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
}
- else
+ //
+ // The private key may be stored in an encrypted file, so handle
+ // password retries.
+ //
+ int count = 0;
+ int err;
+ while(count < passwordRetryMax)
{
- string err = _instance->sslErrors();
- if(!err.empty())
+ ERR_clear_error();
+ err = SSL_CTX_use_PrivateKey_file(_ctx, file.c_str(), SSL_FILETYPE_PEM);
+ if(err || !passwordError())
{
- msg += ":\n" + err;
+ break;
}
+ ++count;
}
+ if(err == 0)
+ {
+ string msg = "IceSSL: unable to load private key from file " + file;
+ if(passwordError())
+ {
+ msg += ":\ninvalid password";
+ }
+ else
+ {
+ string err = _instance->sslErrors();
+ if(!err.empty())
+ {
+ msg += ":\n" + err;
+ }
+ }
+ if(_instance->securityTraceLevel() >= 1)
+ {
+ _logger->trace(_instance->securityTraceCategory(), msg);
+ }
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
+ }
+ }
+ if(!SSL_CTX_check_private_key(_ctx))
+ {
+ string err = _instance->sslErrors();
+ string msg = "IceSSL: unable to validate private key(s):\n" + err;
if(_instance->securityTraceLevel() >= 1)
{
_logger->trace(_instance->securityTraceCategory(), msg);
@@ -428,109 +443,102 @@ IceSSL::Context::Context(const InstancePtr& instance, const string& propPrefix,
throw ex;
}
}
- if(!SSL_CTX_check_private_key(_ctx))
- {
- string err = _instance->sslErrors();
- string msg = "IceSSL: unable to validate private key(s):\n" + err;
- if(_instance->securityTraceLevel() >= 1)
- {
- _logger->trace(_instance->securityTraceCategory(), msg);
- }
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
- }
}
- }
- //
- // Establish the cipher list.
- //
- {
- string ciphers = properties->getProperty(propPrefix + "Ciphers");
- if(!ciphers.empty())
+ //
+ // Establish the cipher list.
+ //
{
- if(!SSL_CTX_set_cipher_list(_ctx, ciphers.c_str()))
+ string ciphers = properties->getProperty(propPrefix + "Ciphers");
+ if(!ciphers.empty())
{
- string err = _instance->sslErrors();
- string msg = "IceSSL: unable to set ciphers using `" + ciphers + "':\n" + err;
- if(_instance->securityTraceLevel() >= 1)
+ if(!SSL_CTX_set_cipher_list(_ctx, ciphers.c_str()))
{
- _logger->trace(_instance->securityTraceCategory(), msg);
+ string err = _instance->sslErrors();
+ string msg = "IceSSL: unable to set ciphers using `" + ciphers + "':\n" + err;
+ if(_instance->securityTraceLevel() >= 1)
+ {
+ _logger->trace(_instance->securityTraceCategory(), msg);
+ }
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
}
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
}
}
- }
- //
- // Establish the maximum verify depth.
- //
- {
- int depth = properties->getPropertyAsIntWithDefault(propPrefix + "VerifyDepthMax", -1);
- if(depth >= 0)
+ //
+ // Establish the maximum verify depth.
+ //
{
- SSL_CTX_set_verify_depth(_ctx, depth);
+ int depth = properties->getPropertyAsIntWithDefault(propPrefix + "VerifyDepthMax", -1);
+ if(depth >= 0)
+ {
+ SSL_CTX_set_verify_depth(_ctx, depth);
+ }
}
- }
- //
- // Diffie Hellman configuration.
- //
- {
-#ifndef OPENSSL_NO_DH
- _dhParams = new DHParams;
- SSL_CTX_set_options(_ctx, SSL_OP_SINGLE_DH_USE);
- SSL_CTX_set_tmp_dh_callback(_ctx, opensslDHCallback);
-#endif
//
- // Properties have the following form:
+ // Diffie Hellman configuration.
//
- // ...DH.<keyLength>=file
- //
- const string dhPrefix = propPrefix + "DH.";
- PropertyDict d = properties->getPropertiesForPrefix(dhPrefix);
- if(!d.empty())
{
+#ifndef OPENSSL_NO_DH
+ _dhParams = new DHParams;
+ SSL_CTX_set_options(_ctx, SSL_OP_SINGLE_DH_USE);
+ SSL_CTX_set_tmp_dh_callback(_ctx, opensslDHCallback);
+#endif
+ //
+ // Properties have the following form:
+ //
+ // ...DH.<keyLength>=file
+ //
+ const string dhPrefix = propPrefix + "DH.";
+ PropertyDict d = properties->getPropertiesForPrefix(dhPrefix);
+ if(!d.empty())
+ {
#ifdef OPENSSL_NO_DH
- _logger->warning("IceSSL: OpenSSL is not configured for Diffie Hellman");
+ _logger->warning("IceSSL: OpenSSL is not configured for Diffie Hellman");
#else
- for(PropertyDict::iterator p = d.begin(); p != d.end(); ++p)
- {
- string s = p->first.substr(dhPrefix.size());
- int keyLength = atoi(s.c_str());
- if(keyLength > 0)
+ for(PropertyDict::iterator p = d.begin(); p != d.end(); ++p)
{
- string file = p->second;
- if(!checkPath(file, false))
+ string s = p->first.substr(dhPrefix.size());
+ int keyLength = atoi(s.c_str());
+ if(keyLength > 0)
{
- string msg = "IceSSL: DH parameter file not found:\n" + file;
- if(_instance->securityTraceLevel() >= 1)
+ string file = p->second;
+ if(!checkPath(file, false))
{
- _logger->trace(_instance->securityTraceCategory(), msg);
+ string msg = "IceSSL: DH parameter file not found:\n" + file;
+ if(_instance->securityTraceLevel() >= 1)
+ {
+ _logger->trace(_instance->securityTraceCategory(), msg);
+ }
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
}
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
- }
- if(!_dhParams->add(keyLength, file))
- {
- string msg = "IceSSL: unable to read DH parameter file " + file;
- if(_instance->securityTraceLevel() >= 1)
+ if(!_dhParams->add(keyLength, file))
{
- _logger->trace(_instance->securityTraceCategory(), msg);
+ string msg = "IceSSL: unable to read DH parameter file " + file;
+ if(_instance->securityTraceLevel() >= 1)
+ {
+ _logger->trace(_instance->securityTraceCategory(), msg);
+ }
+ PluginInitializationException ex(__FILE__, __LINE__);
+ ex.reason = msg;
+ throw ex;
}
- PluginInitializationException ex(__FILE__, __LINE__);
- ex.reason = msg;
- throw ex;
}
}
- }
#endif
+ }
}
}
+ catch(...)
+ {
+ SSL_CTX_free(_ctx);
+ throw;
+ }
}
IceSSL::Context::~Context()