1
// **********************************************************************
3
// Copyright (c) 2003-2010 ZeroC, Inc. All rights reserved.
5
// This copy of Ice is licensed to you under the terms described in the
6
// ICE_LICENSE file included in this distribution.
8
// **********************************************************************
10
#include <IceUtil/Config.h>
12
# include <winsock2.h>
15
#include <IceSSL/Instance.h>
16
#include <IceSSL/EndpointI.h>
17
#include <IceSSL/Util.h>
18
#include <IceSSL/TrustManager.h>
20
#include <Ice/Communicator.h>
21
#include <Ice/LocalException.h>
22
#include <Ice/Logger.h>
23
#include <Ice/LoggerUtil.h>
24
#include <Ice/Properties.h>
25
#include <Ice/ProtocolPluginFacade.h>
26
#include <Ice/StringConverter.h>
28
#include <IceUtil/Mutex.h>
29
#include <IceUtil/MutexPtrLock.h>
30
#include <IceUtil/StringUtil.h>
32
#include <openssl/rand.h>
33
#include <openssl/err.h>
35
#include <IceUtil/DisableWarnings.h>
39
using namespace IceSSL;
41
IceUtil::Shared* IceInternal::upCast(IceSSL::Instance* p) { return p; }
46
IceUtil::Mutex* staticMutex = 0;
47
int instanceCount = 0;
48
IceUtil::Mutex* locks = 0;
56
staticMutex = new IceUtil::Mutex;
80
// OpenSSL mutex callback.
83
IceSSL_opensslLockCallback(int mode, int n, const char* file, int line)
86
if(mode & CRYPTO_LOCK)
97
// OpenSSL thread id callback.
100
IceSSL_opensslThreadIdCallback()
103
return static_cast<unsigned long>(GetCurrentThreadId());
104
#elif defined(__FreeBSD__) || defined(__APPLE__) || defined(__osf1__)
106
// On some platforms, pthread_t is a pointer to a per-thread structure.
108
return reinterpret_cast<unsigned long>(pthread_self());
109
#elif (defined(__linux) || defined(__sun) || defined(__hpux)) || defined(_AIX)
111
// On Linux, Solaris, HP-UX and AIX, pthread_t is an integer.
113
return static_cast<unsigned long>(pthread_self());
115
# error "Unknown platform"
120
IceSSL_opensslPasswordCallback(char* buf, int size, int flag, void* userData)
122
IceSSL::Instance* p = reinterpret_cast<IceSSL::Instance*>(userData);
123
string passwd = p->password(flag == 1);
124
int sz = static_cast<int>(passwd.size());
129
strncpy(buf, passwd.c_str(), sz);
132
for(string::iterator i = passwd.begin(); i != passwd.end(); ++i)
140
#ifndef OPENSSL_NO_DH
142
IceSSL_opensslDHCallback(SSL* ssl, int /*isExport*/, int keyLength)
144
IceSSL::Instance* p = reinterpret_cast<IceSSL::Instance*>(SSL_CTX_get_ex_data(ssl->ctx, 0));
145
return p->dhParams(keyLength);
150
IceSSL_opensslVerifyCallback(int ok, X509_STORE_CTX* ctx)
152
SSL* ssl = reinterpret_cast<SSL*>(X509_STORE_CTX_get_ex_data(ctx, SSL_get_ex_data_X509_STORE_CTX_idx()));
153
IceSSL::Instance* p = reinterpret_cast<IceSSL::Instance*>(SSL_CTX_get_ex_data(ssl->ctx, 0));
154
return p->verifyCallback(ok, ssl, ctx);
162
int reason = ERR_GET_REASON(ERR_peek_error());
163
return (reason == PEM_R_BAD_BASE64_DECODE ||
164
reason == PEM_R_BAD_DECRYPT ||
165
reason == PEM_R_BAD_PASSWORD_READ ||
166
reason == PEM_R_PROBLEMS_GETTING_PASSWORD);
169
IceSSL::Instance::Instance(const CommunicatorPtr& communicator) :
170
_logger(communicator->getLogger()),
177
// Initialize OpenSSL if necessary.
179
IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(staticMutex);
182
if(instanceCount == 1)
184
PropertiesPtr properties = communicator->getProperties();
187
// Create the mutexes and set the callbacks.
191
locks = new IceUtil::Mutex[CRYPTO_num_locks()];
192
CRYPTO_set_locking_callback(IceSSL_opensslLockCallback);
193
CRYPTO_set_id_callback(IceSSL_opensslThreadIdCallback);
197
// Load human-readable error messages.
199
SSL_load_error_strings();
202
// Initialize the SSL library.
207
// This is necessary to allow programs that use OpenSSL 0.9.x to
208
// load private key files generated by OpenSSL 1.x.
210
OpenSSL_add_all_algorithms();
213
// Initialize the PRNG.
216
RAND_screen(); // Uses data from the screen if possible.
219
if(RAND_file_name(randFile, sizeof(randFile))) // Gets the name of a default seed file.
221
RAND_load_file(randFile, 1024);
223
string randFiles = Ice::nativeToUTF8(communicator, properties->getProperty("IceSSL.Random"));
225
if(!randFiles.empty())
227
vector<string> files;
229
const string sep = ";";
231
const string sep = ":";
233
string defaultDir = Ice::nativeToUTF8(communicator, properties->getProperty("IceSSL.DefaultDir"));
235
if(!IceUtilInternal::splitString(randFiles, sep, files))
237
PluginInitializationException ex(__FILE__, __LINE__);
238
ex.reason = "IceSSL: invalid value for IceSSL.Random:\n" + randFiles;
241
for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
244
if(!checkPath(file, defaultDir, false))
246
PluginInitializationException ex(__FILE__, __LINE__);
247
ex.reason = "IceSSL: entropy data file not found:\n" + file;
250
if(!RAND_load_file(file.c_str(), 1024))
252
PluginInitializationException ex(__FILE__, __LINE__);
253
ex.reason = "IceSSL: unable to load entropy data from " + file;
260
// The Entropy Gathering Daemon (EGD) is not available on Windows.
261
// The file should be a Unix domain socket for the daemon.
263
string entropyDaemon = properties->getProperty("IceSSL.EntropyDaemon");
264
if(!entropyDaemon.empty())
266
if(RAND_egd(entropyDaemon.c_str()) <= 0)
268
PluginInitializationException ex(__FILE__, __LINE__);
269
ex.reason = "IceSSL: EGD failure using file " + entropyDaemon;
276
communicator->getLogger()->warning("IceSSL: insufficient data to initialize PRNG");
280
_facade = IceInternal::getProtocolPluginFacade(communicator);
281
_securityTraceLevel = communicator->getProperties()->getPropertyAsInt("IceSSL.Trace.Security");
282
_securityTraceCategory = "Security";
283
_trustManager = new TrustManager(communicator);
286
// Register the endpoint factory. We have to do this now, rather than
287
// in initialize, because the communicator may need to interpret
288
// proxies before the plug-in is fully initialized.
290
_facade->addEndpointFactory(new EndpointFactoryI(this));
292
__setNoDelete(false);
295
IceSSL::Instance::~Instance()
298
// Clean up OpenSSL resources.
300
IceUtilInternal::MutexPtrLock<IceUtil::Mutex> sync(staticMutex);
302
if(--instanceCount == 0)
305
// NOTE: We can't destroy the locks here: threads which might have called openssl methods
306
// might access openssl locks upon termination (from DllMain/THREAD_DETACHED). Instead,
307
// we release the locks in the ~Init() static destructor. See bug #4156.
309
//CRYPTO_set_locking_callback(0);
310
//CRYPTO_set_id_callback(0);
314
CRYPTO_cleanup_all_ex_data();
322
IceSSL::Instance::initialize()
331
const string propPrefix = "IceSSL.";
332
PropertiesPtr properties = communicator()->getProperties();
335
// CheckCertName determines whether we compare the name in a peer's
336
// certificate against its hostname.
338
_checkCertName = properties->getPropertyAsIntWithDefault(propPrefix + "CheckCertName", 0) > 0;
341
// VerifyDepthMax establishes the maximum length of a peer's certificate
342
// chain, including the peer's certificate. A value of 0 means there is
345
_verifyDepthMax = properties->getPropertyAsIntWithDefault(propPrefix + "VerifyDepthMax", 2);
348
// VerifyPeer determines whether certificate validation failures abort a connection.
350
_verifyPeer = properties->getPropertyAsIntWithDefault(propPrefix + "VerifyPeer", 2);
353
// Create an SSL context if the application hasn't supplied one.
357
_ctx = SSL_CTX_new(SSLv23_method());
360
PluginInitializationException ex(__FILE__, __LINE__);
361
ex.reason = "IceSSL: unable to create SSL context:\n" + sslErrors();
366
// Check for a default directory. We look in this directory for
367
// files mentioned in the configuration.
369
string defaultDir = properties->getProperty(propPrefix + "DefaultDir");
372
// If the configuration defines a password, or the application has supplied
373
// a password prompt object, then register a password callback. Otherwise,
374
// let OpenSSL use its default behavior.
377
// TODO: Support quoted value?
378
string password = properties->getProperty(propPrefix + "Password");
379
if(!password.empty() || _prompt)
381
SSL_CTX_set_default_passwd_cb(_ctx, IceSSL_opensslPasswordCallback);
382
SSL_CTX_set_default_passwd_cb_userdata(_ctx, this);
383
_password = password;
387
int passwordRetryMax = properties->getPropertyAsIntWithDefault(propPrefix + "PasswordRetryMax", 3);
390
// Establish the location of CA certificates.
393
string caFile = properties->getProperty(propPrefix + "CertAuthFile");
394
string caDir = properties->getPropertyWithDefault(propPrefix + "CertAuthDir", defaultDir);
395
const char* file = 0;
399
if(!checkPath(caFile, defaultDir, false))
401
PluginInitializationException ex(__FILE__, __LINE__);
402
ex.reason = "IceSSL: CA certificate file not found:\n" + caFile;
405
file = caFile.c_str();
409
if(!checkPath(caDir, defaultDir, true))
411
PluginInitializationException ex(__FILE__, __LINE__);
412
ex.reason = "IceSSL: CA certificate directory not found:\n" + caDir;
420
// The certificate may be stored in an encrypted file, so handle
425
while(count < passwordRetryMax)
428
err = SSL_CTX_load_verify_locations(_ctx, file, dir);
437
string msg = "IceSSL: unable to establish CA certificates";
440
msg += ":\ninvalid password";
444
string err = sslErrors();
450
PluginInitializationException ex(__FILE__, __LINE__);
458
// Establish the certificate chains and private keys. One RSA certificate and
459
// one DSA certificate are allowed.
463
const string sep = ";";
465
const string sep = ":";
467
string certFile = properties->getProperty(propPrefix + "CertFile");
468
string keyFile = properties->getProperty(propPrefix + "KeyFile");
469
vector<string>::size_type numCerts = 0;
470
if(!certFile.empty())
472
vector<string> files;
473
if(!IceUtilInternal::splitString(certFile, sep, files) || files.size() > 2)
475
PluginInitializationException ex(__FILE__, __LINE__);
476
ex.reason = "IceSSL: invalid value for " + propPrefix + "CertFile:\n" + certFile;
479
numCerts = files.size();
480
for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
483
if(!checkPath(file, defaultDir, false))
485
PluginInitializationException ex(__FILE__, __LINE__);
486
ex.reason = "IceSSL: certificate file not found:\n" + file;
490
// The certificate may be stored in an encrypted file, so handle
495
while(count < passwordRetryMax)
498
err = SSL_CTX_use_certificate_chain_file(_ctx, file.c_str());
507
string msg = "IceSSL: unable to load certificate chain from file " + file;
510
msg += ":\ninvalid password";
514
string err = sslErrors();
520
PluginInitializationException ex(__FILE__, __LINE__);
528
keyFile = certFile; // Assume the certificate file also contains the private key.
532
vector<string> files;
533
if(!IceUtilInternal::splitString(keyFile, sep, files) || files.size() > 2)
535
PluginInitializationException ex(__FILE__, __LINE__);
536
ex.reason = "IceSSL: invalid value for " + propPrefix + "KeyFile:\n" + keyFile;
539
if(files.size() != numCerts)
541
PluginInitializationException ex(__FILE__, __LINE__);
542
ex.reason = "IceSSL: " + propPrefix + "KeyFile does not agree with " + propPrefix + "CertFile";
545
for(vector<string>::iterator p = files.begin(); p != files.end(); ++p)
548
if(!checkPath(file, defaultDir, false))
550
PluginInitializationException ex(__FILE__, __LINE__);
551
ex.reason = "IceSSL: key file not found:\n" + file;
555
// The private key may be stored in an encrypted file, so handle
560
while(count < passwordRetryMax)
563
err = SSL_CTX_use_PrivateKey_file(_ctx, file.c_str(), SSL_FILETYPE_PEM);
572
string msg = "IceSSL: unable to load private key from file " + file;
575
msg += ":\ninvalid password";
579
string err = sslErrors();
585
PluginInitializationException ex(__FILE__, __LINE__);
590
if(!SSL_CTX_check_private_key(_ctx))
592
PluginInitializationException ex(__FILE__, __LINE__);
593
ex.reason = "IceSSL: unable to validate private key(s):\n" + sslErrors();
600
// Diffie Hellman configuration.
603
#ifndef OPENSSL_NO_DH
604
_dhParams = new DHParams;
605
SSL_CTX_set_options(_ctx, SSL_OP_SINGLE_DH_USE);
606
SSL_CTX_set_tmp_dh_callback(_ctx, IceSSL_opensslDHCallback);
609
// Properties have the following form:
611
// ...DH.<keyLength>=file
613
const string dhPrefix = propPrefix + "DH.";
614
PropertyDict d = properties->getPropertiesForPrefix(dhPrefix);
618
_logger->warning("IceSSL: OpenSSL is not configured for Diffie Hellman");
620
for(PropertyDict::iterator p = d.begin(); p != d.end(); ++p)
622
string s = p->first.substr(dhPrefix.size());
623
int keyLength = atoi(s.c_str());
626
string file = p->second;
627
if(!checkPath(file, defaultDir, false))
629
PluginInitializationException ex(__FILE__, __LINE__);
630
ex.reason = "IceSSL: DH parameter file not found:\n" + file;
633
if(!_dhParams->add(keyLength, file))
635
PluginInitializationException ex(__FILE__, __LINE__);
636
ex.reason = "IceSSL: unable to read DH parameter file " + file;
647
// Store a pointer to ourself for use in OpenSSL callbacks.
649
SSL_CTX_set_ex_data(_ctx, 0, this);
652
// This is necessary for successful interop with Java. Without it, a Java
653
// client would fail to reestablish a connection: the server gets the
654
// error "session id context uninitialized" and the client receives
655
// "SSLHandshakeException: Remote host closed connection during handshake".
657
SSL_CTX_set_session_cache_mode(_ctx, SSL_SESS_CACHE_OFF);
662
StringSeq protocols = properties->getPropertyAsList(propPrefix + "Protocols");
663
if(!protocols.empty())
665
parseProtocols(protocols);
669
// Establish the cipher list.
671
string ciphers = properties->getProperty(propPrefix + "Ciphers");
674
if(!SSL_CTX_set_cipher_list(_ctx, ciphers.c_str()))
676
PluginInitializationException ex(__FILE__, __LINE__);
677
ex.reason = "IceSSL: unable to set ciphers using `" + ciphers + "':\n" + sslErrors();
683
// Determine whether a certificate is required from the peer.
690
sslVerifyMode = SSL_VERIFY_NONE;
693
sslVerifyMode = SSL_VERIFY_PEER;
696
sslVerifyMode = SSL_VERIFY_PEER|SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
700
PluginInitializationException ex(__FILE__, __LINE__);
701
ex.reason = "IceSSL: invalid value for " + propPrefix + "VerifyPeer";
705
SSL_CTX_set_verify(_ctx, sslVerifyMode, IceSSL_opensslVerifyCallback);
711
// We free the SSL context regardless of whether the plugin created it
712
// or the application supplied it.
723
IceSSL::Instance::context(SSL_CTX* context)
727
PluginInitializationException ex(__FILE__, __LINE__);
728
ex.reason = "IceSSL: plug-in is already initialized";
737
IceSSL::Instance::context() const
743
IceSSL::Instance::setCertificateVerifier(const CertificateVerifierPtr& verifier)
745
_verifier = verifier;
749
IceSSL::Instance::setPasswordPrompt(const PasswordPromptPtr& prompt)
755
IceSSL::Instance::communicator() const
757
return _facade->getCommunicator();
760
IceInternal::EndpointHostResolverPtr
761
IceSSL::Instance::endpointHostResolver() const
763
return _facade->getEndpointHostResolver();
766
IceInternal::ProtocolSupport
767
IceSSL::Instance::protocolSupport() const
769
return _facade->getProtocolSupport();
773
IceSSL::Instance::defaultHost() const
775
return _facade->getDefaultHost();
779
IceSSL::Instance::networkTraceLevel() const
781
return _facade->getNetworkTraceLevel();
785
IceSSL::Instance::networkTraceCategory() const
787
return _facade->getNetworkTraceCategory();
791
IceSSL::Instance::securityTraceLevel() const
793
return _securityTraceLevel;
797
IceSSL::Instance::securityTraceCategory() const
799
return _securityTraceCategory;
803
IceSSL::Instance::verifyPeer(SSL* ssl, SOCKET fd, const string& address, const NativeConnectionInfoPtr& info)
805
long result = SSL_get_verify_result(ssl);
806
if(result != X509_V_OK)
810
if(_securityTraceLevel >= 1)
813
ostr << "IceSSL: ignoring certificate verification failure:\n" << X509_verify_cert_error_string(result);
814
_logger->trace(_securityTraceCategory, ostr.str());
820
ostr << "IceSSL: certificate verification failed:\n" << X509_verify_cert_error_string(result);
821
string msg = ostr.str();
822
if(_securityTraceLevel >= 1)
824
_logger->trace(_securityTraceCategory, msg);
826
SecurityException ex(__FILE__, __LINE__);
832
X509* rawCert = SSL_get_peer_certificate(ssl);
836
cert = new Certificate(rawCert);
840
// For an outgoing connection, we compare the proxy address (if any) against
841
// fields in the server's certificate (if any).
843
if(cert && !address.empty())
846
// Extract the IP addresses and the DNS names from the subject
847
// alternative names.
849
vector<pair<int, string> > subjectAltNames = cert->getSubjectAlternativeNames();
850
vector<string> ipAddresses;
851
vector<string> dnsNames;
852
for(vector<pair<int, string> >::const_iterator p = subjectAltNames.begin(); p != subjectAltNames.end(); ++p)
856
ipAddresses.push_back(IceUtilInternal::toLower(p->second));
858
else if(p->first == 2)
860
dnsNames.push_back(IceUtilInternal::toLower(p->second));
865
// Compare the peer's address against the common name.
867
bool certNameOK = false;
869
string addrLower = IceUtilInternal::toLower(address);
871
DistinguishedName d = cert->getSubjectDN();
872
dn = IceUtilInternal::toLower(string(d));
873
string cn = "cn=" + addrLower;
874
string::size_type pos = dn.find(cn);
875
if(pos != string::npos)
878
// Ensure we match the entire common name.
880
certNameOK = (pos + cn.size() == dn.size()) || (dn[pos + cn.size()] == ',');
885
// Compare the peer's address against the the dnsName and ipAddress
886
// values in the subject alternative name.
890
certNameOK = find(ipAddresses.begin(), ipAddresses.end(), addrLower) != ipAddresses.end();
894
certNameOK = find(dnsNames.begin(), dnsNames.end(), addrLower) != dnsNames.end();
898
// Log a message if the name comparison fails. If CheckCertName is defined,
899
// we also raise an exception to abort the connection. Don't log a message if
900
// CheckCertName is not defined and a verifier is present.
902
if(!certNameOK && (_checkCertName || (_securityTraceLevel >= 1 && !_verifier)))
910
ostr << "certificate validation failure:\npeer certificate does not have `" << address
911
<< "' as its commonName or in its subjectAltName extension";
914
ostr << "\nSubject DN: " << dn;
916
if(!dnsNames.empty())
918
ostr << "\nDNS names found in certificate: ";
919
for(vector<string>::const_iterator p = dnsNames.begin(); p != dnsNames.end(); ++p)
921
if(p != dnsNames.begin())
928
if(!ipAddresses.empty())
930
ostr << "\nIP addresses found in certificate: ";
931
for(vector<string>::const_iterator p = ipAddresses.begin(); p != ipAddresses.end(); ++p)
933
if(p != ipAddresses.begin())
940
string msg = ostr.str();
941
if(_securityTraceLevel >= 1)
943
Trace out(_logger, _securityTraceCategory);
948
SecurityException ex(__FILE__, __LINE__);
955
if(_verifyDepthMax > 0 && static_cast<int>(info->certs.size()) > _verifyDepthMax)
958
ostr << (info->incoming ? "incoming" : "outgoing") << " connection rejected:\n"
959
<< "length of peer's certificate chain (" << info->certs.size() << ") exceeds maximum of "
961
string msg = ostr.str();
962
if(_securityTraceLevel >= 1)
964
_logger->trace(_securityTraceCategory, msg + "\n" + IceInternal::fdToString(fd));
966
SecurityException ex(__FILE__, __LINE__);
971
if(!_trustManager->verify(info))
973
string msg = string(info->incoming ? "incoming" : "outgoing") + " connection rejected by trust manager";
974
if(_securityTraceLevel >= 1)
976
_logger->trace(_securityTraceCategory, msg + "\n" + IceInternal::fdToString(fd));
978
SecurityException ex(__FILE__, __LINE__);
983
if(_verifier && !_verifier->verify(info))
985
string msg = string(info->incoming ? "incoming" : "outgoing") + " connection rejected by certificate verifier";
986
if(_securityTraceLevel >= 1)
988
_logger->trace(_securityTraceCategory, msg + "\n" + IceInternal::fdToString(fd));
990
SecurityException ex(__FILE__, __LINE__);
997
IceSSL::Instance::sslErrors() const
999
return getSslErrors(_securityTraceLevel >= 1);
1003
IceSSL::Instance::destroy()
1014
IceSSL::Instance::password(bool /*encrypting*/)
1020
return _prompt->getPassword();
1025
// Don't allow exceptions to cross an OpenSSL boundary.
1037
IceSSL::Instance::verifyCallback(int ok, SSL* ssl, X509_STORE_CTX* c)
1039
if(!ok && _securityTraceLevel >= 1)
1041
X509* cert = X509_STORE_CTX_get_current_cert(c);
1042
int err = X509_STORE_CTX_get_error(c);
1045
Trace out(_logger, _securityTraceCategory);
1046
out << "certificate verification failure\n";
1048
X509_NAME_oneline(X509_get_issuer_name(cert), buf, static_cast<int>(sizeof(buf)));
1049
out << "issuer = " << buf << '\n';
1050
X509_NAME_oneline(X509_get_subject_name(cert), buf, static_cast<int>(sizeof(buf)));
1051
out << "subject = " << buf << '\n';
1052
out << "depth = " << X509_STORE_CTX_get_error_depth(c) << '\n';
1053
out << "error = " << X509_verify_cert_error_string(err) << '\n';
1054
out << IceInternal::fdToString(SSL_get_fd(ssl));
1059
#ifndef OPENSSL_NO_DH
1061
IceSSL::Instance::dhParams(int keyLength)
1063
return _dhParams->get(keyLength);
1068
IceSSL::Instance::traceConnection(SSL* ssl, bool incoming)
1070
Trace out(_logger, _securityTraceCategory);
1071
out << "SSL summary for " << (incoming ? "incoming" : "outgoing") << " connection\n";
1074
// The const_cast is necesary because Solaris still uses OpenSSL 0.9.7.
1076
//const SSL_CIPHER *cipher = SSL_get_current_cipher(ssl);
1077
SSL_CIPHER *cipher = const_cast<SSL_CIPHER*>(SSL_get_current_cipher(ssl));
1080
out << "unknown cipher\n";
1084
out << "cipher = " << SSL_CIPHER_get_name(cipher) << "\n";
1085
out << "bits = " << SSL_CIPHER_get_bits(cipher, 0) << "\n";
1086
out << "protocol = " << SSL_get_version(ssl) << "\n";
1088
out << IceInternal::fdToString(SSL_get_fd(ssl));
1092
IceSSL::Instance::parseProtocols(const StringSeq& protocols)
1094
bool sslv3 = false, tlsv1 = false;
1095
for(Ice::StringSeq::const_iterator p = protocols.begin(); p != protocols.end(); ++p)
1099
if(prot == "ssl3" || prot == "sslv3")
1103
else if(prot == "tls" || prot == "tls1" || prot == "tlsv1")
1109
PluginInitializationException ex(__FILE__, __LINE__);
1110
ex.reason = "IceSSL: unrecognized protocol `" + prot + "'";
1115
long opts = SSL_OP_NO_SSLv2; // SSLv2 is not supported.
1118
opts |= SSL_OP_NO_SSLv3;
1122
opts |= SSL_OP_NO_TLSv1;
1124
SSL_CTX_set_options(_ctx, opts);