[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#772487: unblock: resiprocate/1.9.8-1



Package: release.debian.org
User: release.debian.org@packages.debian.org
UserTags: unblock


This has just been uploaded to unstable

The main reason for this unblock request:

http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=772480

This improves administrative control (in the /etc/repro/repro.config)
over the TLS options.  It means that during the life of jessie (up to
perhaps 2017/2018) if more ciphers or protocols become vulnerable the
administrator can disable them just by changing the config.

The update enables TLS v1.1 and v1.2 while disabling SSL v3.0 by
default.  The configuration options also let the administrator bring
back SSL v3.0 if really needed.

The debdiff is about 900 lines but this includes a lot of comments as
I've explained what I was doing throughout the security code and about
30% of that is a new test case, testSecurity.cxx, to validate the new
config string parsing.

The debdiff is attached, it was generated with filterdiff to remove
autotools stuff:


debdiff resiprocate_1.9.7-1.dsc resiprocate_1.9.8-1.dsc | filterdiff -x
'*/aclocal.m4' -x '*/config.*' -x '*/configure' -x '*/depcomp' -x
'*/*.in' -x '*/install-sh' -x '*/ltmain.sh' -x '*/m4/*' -x '*/missing'
-x '*/repro/repro.config' -x '*/resiprocate.spec'  >
/tmp/resiprocate-1.9.8-1.debdiff

diff -Nru resiprocate-1.9.7/ChangeLog resiprocate-1.9.8/ChangeLog
--- resiprocate-1.9.7/ChangeLog	2014-05-31 12:47:51.000000000 +0200
+++ resiprocate-1.9.8/ChangeLog	2014-12-07 17:48:36.000000000 +0100
@@ -1,4 +1,11 @@
 = Release Notes v 1.9 =
+==1.9.8 Changes==
+resip/stack: add static fields on BaseSecurity for setting OpenSSL CTX options
+resip/stack: explicitly disable SSLv2 and SSLv3 by default when using SSLv23
+resip/stack: allow application to provide OpenSSL certificate verification callback
+repro: change default OpenSSL method from TLSv1_method to SSLv23_method (enables TLS v1.1 and v1.2)
+repro: add configuration options OpenSSLCTXSetOptions and OpenSSLCTXClearOptions to control OpenSSL CTX options
+repro: add configuration OpenSSLCipherList to manually configure the OpenSSL cipher list
 ==1.9.7 Changes==
 rpm: Indicate that b2bua package is obsolete
 resip/stack: TlsConnection: correctly handle OpenSSL error queue after SSL_read
diff -Nru resiprocate-1.9.7/configure resiprocate-1.9.8/configure
diff -Nru resiprocate-1.9.7/configure.ac resiprocate-1.9.8/configure.ac
--- resiprocate-1.9.7/configure.ac	2014-05-31 12:47:51.000000000 +0200
+++ resiprocate-1.9.8/configure.ac	2014-12-07 17:48:36.000000000 +0100
@@ -1,5 +1,5 @@
 
-AC_INIT(resiprocate,1.9.7)
+AC_INIT(resiprocate,1.9.8)
 AC_CONFIG_SRCDIR(repro/repro.cxx)
 
 SO_RELEASE=`echo $PACKAGE_VERSION | cut -f1,2 -d.`
diff -Nru resiprocate-1.9.7/debian/changelog resiprocate-1.9.8/debian/changelog
--- resiprocate-1.9.7/debian/changelog	2014-05-31 12:51:11.000000000 +0200
+++ resiprocate-1.9.8/debian/changelog	2014-12-07 18:08:40.000000000 +0100
@@ -1,3 +1,10 @@
+resiprocate (1.9.8-1) unstable; urgency=medium
+
+  * New upstream release.
+  * Improve administrative control over TLS. (Closes: #772480)
+
+ -- Daniel Pocock <daniel@pocock.pro>  Sun, 07 Dec 2014 18:08:04 +0100
+
 resiprocate (1.9.7-1) unstable; urgency=medium
 
   * New upstream release.
diff -Nru resiprocate-1.9.7/debian/conf/repro.config resiprocate-1.9.8/debian/conf/repro.config
--- resiprocate-1.9.7/debian/conf/repro.config	2014-05-31 12:47:22.000000000 +0200
+++ resiprocate-1.9.8/debian/conf/repro.config	2014-12-07 18:31:38.000000000 +0100
@@ -89,6 +89,24 @@
 #    SIP messages coming from the peer
 TLSClientVerification = None
 
+# The SSL or TLS connection mode to use
+# SSL v2 and v3 are deprecated and SSL v2 is particularly insecure
+# and should be avoided.
+# TLSv1 was the default up to and including reSIProcate v1.9.7.
+# With the setting TLSv1, only TLS v1.0 could be used
+# and not TLS v1.1 or newer versions.
+# The value SSLv23 works as a catch-all and gives the potential
+# to allow all the SSL and TLS versions.  Despite the name SSLv23, it
+# does not allow SSL v2.0 or v3.0 if the SSL_CTX_set_options method is used
+# to prohibit them.
+# See the page https://www.openssl.org/docs/ssl/SSL_CTX_new.html
+# for a more detailed discussion of how repro will behave when
+# using the values SSLv23 or TLSv1 here.
+# For optimal security and compatibility, set SSLv23 here and make sure
+# that the parameter OpenSSLCTXSetOptions (later in repro.config)
+# contains the values SSL_OP_NO_SSLv2 and SSL_OP_NO_SSLv3
+TLSConnectionMethod = SSLv23
+
 # Whether we accept the subjectAltName email address as if it was a SIP
 # address (when checking the validity of a client certificate)
 # Very few commercial CAs offer support for SIP addresses in subjectAltName
@@ -109,6 +127,7 @@
 # Transport<Num>TlsCertificate = <TLSCertificate> - only for TLS, DTLS or WSS
 # Transport<Num>TlsPrivateKey = <TLSPrivateKey> - only for TLS, DTLS or WSS
 # Transport<Num>TlsClientVerification = <'None'|'Optional'|'Mandatory'> - default is None
+# Transport<Num>TlsConnectionMethod = <'TLSv1'|'SSLv23'> - default is SSLv23
 # Transport<Num>RecordRouteUri = <'auto'|URI> - if set to auto then record route URI
 #                                               is automatically generated from the other
 #                                               transport settings.  Otherwise explicity
@@ -316,6 +335,41 @@
 # includes the class 1 root and the class 3 root (signed by the class 1 root)
 #CAFile = /etc/ssl/certs/cacert.org.pem
 
+# This option specifies flags to be passed to OpenSSL's
+# SSL_CTX_set_options method after creating the SSL context
+# for a transport.
+#
+# The flags here are added (logical OR) to any existing flags already
+# set by default within the OpenSSL stack.
+#
+# By default, the reSIProcate stack adds flags SSL_OP_NO_SSLv2
+# and SSL_OP_NO_SSLv3 flags which disable deprecated and insecure
+# SSL versions.  To add more flags, uncomment the line below and add
+# the flags required, separated by commas.
+#OpenSSLCTXSetOptions = SSL_OP_NO_SSLv2, SSL_OP_NO_SSLv3
+
+# This option specifies flags to be passed to OpenSSL's
+# SSL_CTX_clear_options method after creating the SSL context
+# for a transport.
+#
+# The flags here are removed from any existing flags
+# already set by default within the OpenSSL stack.
+#
+# To clear the option SSL_OP_NO_SSLv3 and get SSLv3 support
+# (not recommended for security reasons), uncomment the example below:
+#OpenSSLCTXClearOptions = SSL_OP_NO_SSLv3
+
+# This parameter specifies the cipher list to be passed to
+# SSL_CTX_set_cipher_list.
+# The default value is defined in the code as BaseSecurity::ExportableSuite
+# Uncomment the line below and add or remove cipher names as required.
+# See https://www.openssl.org/docs/apps/ciphers.html for details
+# of the format of this parameter.
+#OpenSSLCipherList = !SSLv2:aRSA+AES:aDSS+AES:@STRENGTH:aRSA+3DES:aDSS+3DES:aRSA+RC4+MEDIUM:aDSS+RC4+MEDIUM:aRSA+DES:aDSS+DES:aRSA+RC4:aDSS+RC4
+
+# and a slightly strong cipher list:
+#OpenSSLCipherList = !SSLv2:aRSA+AES:aDSS+AES:@STRENGTH:aRSA+3DES:aDSS+3DES
+
 # The Path to read and write Berkely DB database files
 DatabasePath = /var/lib/repro
 
diff -Nru resiprocate-1.9.7/repro/repro.config resiprocate-1.9.8/repro/repro.config
diff -Nru resiprocate-1.9.7/repro/ReproRunner.cxx resiprocate-1.9.8/repro/ReproRunner.cxx
--- resiprocate-1.9.7/repro/ReproRunner.cxx	2014-05-31 12:47:44.000000000 +0200
+++ resiprocate-1.9.8/repro/ReproRunner.cxx	2014-12-07 17:48:37.000000000 +0100
@@ -84,6 +84,7 @@
 #if defined(USE_SSL)
 #include "repro/stateAgents/CertServer.hxx"
 #include "resip/stack/ssl/Security.hxx"
+#define DEFAULT_TLS_METHOD "SSLv23"
 #endif
 
 #if defined(USE_MYSQL)
@@ -521,6 +522,21 @@
 #endif
 }
 
+void
+ReproRunner::setOpenSSLCTXOptionsFromConfig(const Data& configVar, long& opts)
+{
+   std::set<Data> values;
+   if(mProxyConfig->getConfigValue(configVar, values))
+   {
+      opts = 0;
+      for(std::set<Data>::iterator it = values.begin();
+            it != values.end(); it++)
+      {
+         opts |= Security::parseOpenSSLCTXOption(*it);
+      }
+   }
+}
+
 bool
 ReproRunner::createSipStack()
 {
@@ -545,14 +561,24 @@
    Security* security = 0;
    Compression* compression = 0;
 #ifdef USE_SSL
+   setOpenSSLCTXOptionsFromConfig(
+         "OpenSSLCTXSetOptions", BaseSecurity::OpenSSLCTXSetOptions);
+   setOpenSSLCTXOptionsFromConfig(
+         "OpenSSLCTXClearOptions", BaseSecurity::OpenSSLCTXClearOptions);
+   Security::CipherList cipherList = Security::ExportableSuite;
+   Data ciphers = mProxyConfig->getConfigData("OpenSSLCipherList", "");
+   if(!ciphers.empty())
+   {
+      cipherList = ciphers;
+   }
    Data certPath = mProxyConfig->getConfigData("CertificatePath", "");
    if(certPath.empty())
    {
-      security = new Security();
+      security = new Security(cipherList);
    }
    else
    {
-      security = new Security(certPath);
+      security = new Security(certPath, cipherList);
    }
    Data caDir;
    mProxyConfig->getConfigValue("CADirectory", caDir);
@@ -1372,6 +1398,7 @@
             Data tlsCertificateSettingKey(settingKeyBase + "TlsCertificate");
             Data tlsPrivateKeySettingKey(settingKeyBase + "TlsPrivateKey");
             Data tlsCVMSettingKey(settingKeyBase + "TlsClientVerification");
+            Data tlsConnectionMethodKey(settingKeyBase + "TlsConnectionMethod");
             Data recordRouteUriSettingKey(settingKeyBase + "RecordRouteUri");
             Data rcvBufSettingKey(settingKeyBase + "RcvBufLen");
 
@@ -1409,6 +1436,8 @@
                Data tlsPrivateKey = mProxyConfig->getConfigData(tlsPrivateKeySettingKey, "");
                Data tlsCVMValue = mProxyConfig->getConfigData(tlsCVMSettingKey, "NONE");
                SecurityTypes::TlsClientVerificationMode cvm = SecurityTypes::None;
+               SecurityTypes::SSLType sslType = Security::parseSSLType(
+                  mProxyConfig->getConfigData(tlsConnectionMethodKey, DEFAULT_TLS_METHOD));
                if(isEqualNoCase(tlsCVMValue, "Optional"))
                {
                   cvm = SecurityTypes::Optional;
@@ -1448,7 +1477,7 @@
                                  ipAddr,       // interface to bind to
                                  tlsDomain,
                                  Data::Empty,  // private key passphrase - not currently used
-                                 SecurityTypes::TLSv1, // sslType
+                                 sslType, // sslType
                                  0,            // transport flags
                                  tlsCertificate, tlsPrivateKey,
                                  cvm,          // tls client verification mode
@@ -1530,6 +1559,8 @@
          Data tlsPrivateKey = mProxyConfig->getConfigData("TLSPrivateKey", "");
          Data tlsCVMValue = mProxyConfig->getConfigData("TLSClientVerification", "NONE");
          SecurityTypes::TlsClientVerificationMode cvm = SecurityTypes::None;
+         SecurityTypes::SSLType sslType = Security::parseSSLType(
+            mProxyConfig->getConfigData("TLSConnectionMethod", DEFAULT_TLS_METHOD));
          if(isEqualNoCase(tlsCVMValue, "Optional"))
          {
             cvm = SecurityTypes::Optional;
@@ -1576,8 +1607,8 @@
          }
          if (tlsPort)
          {
-            if (mUseV4) mSipStack->addTransport(TLS, tlsPort, V4, StunEnabled, Data::Empty, tlsDomain, Data::Empty, SecurityTypes::TLSv1, 0, tlsCertificate, tlsPrivateKey, cvm, useEmailAsSIP);
-            if (mUseV6) mSipStack->addTransport(TLS, tlsPort, V6, StunEnabled, Data::Empty, tlsDomain, Data::Empty, SecurityTypes::TLSv1, 0, tlsCertificate, tlsPrivateKey, cvm, useEmailAsSIP);
+            if (mUseV4) mSipStack->addTransport(TLS, tlsPort, V4, StunEnabled, Data::Empty, tlsDomain, Data::Empty, sslType, 0, tlsCertificate, tlsPrivateKey, cvm, useEmailAsSIP);
+            if (mUseV6) mSipStack->addTransport(TLS, tlsPort, V6, StunEnabled, Data::Empty, tlsDomain, Data::Empty, sslType, 0, tlsCertificate, tlsPrivateKey, cvm, useEmailAsSIP);
          }
          if (wsPort)
          {
@@ -1586,13 +1617,13 @@
          }
          if (wssPort)
          {
-            if (mUseV4) mSipStack->addTransport(WSS, wssPort, V4, StunEnabled, Data::Empty, tlsDomain, Data::Empty, SecurityTypes::TLSv1, 0, tlsCertificate, tlsPrivateKey, cvm, useEmailAsSIP, basicWsConnectionValidator, wsCookieContextFactory);
-            if (mUseV6) mSipStack->addTransport(WSS, wssPort, V6, StunEnabled, Data::Empty, tlsDomain, Data::Empty, SecurityTypes::TLSv1, 0, tlsCertificate, tlsPrivateKey, cvm, useEmailAsSIP, basicWsConnectionValidator, wsCookieContextFactory);
+            if (mUseV4) mSipStack->addTransport(WSS, wssPort, V4, StunEnabled, Data::Empty, tlsDomain, Data::Empty, sslType, 0, tlsCertificate, tlsPrivateKey, cvm, useEmailAsSIP, basicWsConnectionValidator, wsCookieContextFactory);
+            if (mUseV6) mSipStack->addTransport(WSS, wssPort, V6, StunEnabled, Data::Empty, tlsDomain, Data::Empty, sslType, 0, tlsCertificate, tlsPrivateKey, cvm, useEmailAsSIP, basicWsConnectionValidator, wsCookieContextFactory);
          }
          if (dtlsPort)
          {
-            if (mUseV4) mSipStack->addTransport(DTLS, dtlsPort, V4, StunEnabled, Data::Empty, tlsDomain, Data::Empty, SecurityTypes::TLSv1, 0, tlsCertificate, tlsPrivateKey);
-            if (mUseV6) mSipStack->addTransport(DTLS, dtlsPort, V6, StunEnabled, Data::Empty, tlsDomain, Data::Empty, SecurityTypes::TLSv1, 0, tlsCertificate, tlsPrivateKey);
+            if (mUseV4) mSipStack->addTransport(DTLS, dtlsPort, V4, StunEnabled, Data::Empty, tlsDomain, Data::Empty, sslType, 0, tlsCertificate, tlsPrivateKey);
+            if (mUseV6) mSipStack->addTransport(DTLS, dtlsPort, V6, StunEnabled, Data::Empty, tlsDomain, Data::Empty, sslType, 0, tlsCertificate, tlsPrivateKey);
          }
       }
    }
diff -Nru resiprocate-1.9.7/repro/ReproRunner.hxx resiprocate-1.9.8/repro/ReproRunner.hxx
--- resiprocate-1.9.7/repro/ReproRunner.hxx	2014-05-31 12:47:45.000000000 +0200
+++ resiprocate-1.9.8/repro/ReproRunner.hxx	2014-12-07 17:48:37.000000000 +0100
@@ -64,6 +64,7 @@
    virtual void cleanupObjects();
 
    virtual bool loadPlugins();
+   virtual void setOpenSSLCTXOptionsFromConfig(const resip::Data& configVar, long& opts);
    virtual bool createSipStack();
    virtual bool createDatastore();
    virtual bool createProxy();
diff -Nru resiprocate-1.9.7/resip/stack/SecurityTypes.hxx resiprocate-1.9.8/resip/stack/SecurityTypes.hxx
--- resiprocate-1.9.7/resip/stack/SecurityTypes.hxx	2014-05-31 12:46:13.000000000 +0200
+++ resiprocate-1.9.8/resip/stack/SecurityTypes.hxx	2014-12-07 17:19:44.000000000 +0100
@@ -6,6 +6,16 @@
 
 namespace SecurityTypes 
 { 
+typedef enum
+{
+   OpenSSL
+} SSLVendor;
+
+/**
+ * Note:
+ * Before adding to the SSLType enum, please see the comments
+ * about mTlsCtx in resip/stack/ssl/Security.hxx
+ */
 typedef enum 
 { 
    NoSSL = 0,
diff -Nru resiprocate-1.9.7/resip/stack/ssl/Security.cxx resiprocate-1.9.8/resip/stack/ssl/Security.cxx
--- resiprocate-1.9.7/resip/stack/ssl/Security.cxx	2014-05-31 12:46:11.000000000 +0200
+++ resiprocate-1.9.8/resip/stack/ssl/Security.cxx	2014-12-07 17:48:37.000000000 +0100
@@ -8,6 +8,7 @@
 
 #include <ostream>
 #include <fstream>
+#include <stdexcept>
 
 #include "resip/stack/Contents.hxx"
 #include "resip/stack/MultipartSignedContents.hxx"
@@ -127,6 +128,21 @@
 BaseSecurity::CipherList BaseSecurity::ExportableSuite("!SSLv2:aRSA+AES:aDSS+AES:@STRENGTH:aRSA+3DES:aDSS+3DES:aRSA+RC4+MEDIUM:aDSS+RC4+MEDIUM:aRSA+DES:aDSS+DES:aRSA+RC4:aDSS+RC4");
 BaseSecurity::CipherList BaseSecurity::StrongestSuite("!SSLv2:aRSA+AES:aDSS+AES:@STRENGTH:aRSA+3DES:aDSS+3DES");
 
+/**
+ * Note:
+ *
+ * When SSLv23 mode is selected and the options flags SSL_OP_NO_SSLv2
+ * and SSL_OP_NO_SSLv3 are set, SSLv23_method() will allow a dynamic
+ * choice of TLS v1.0, v1.1 or v1.2 on each connection.
+ *
+ * If SSL_OP_NO_SSLv3 is removed (by an application changing the value
+ * of BaseSecurity::OpenSSLCTXSetOptions before instantiating
+ * resip::Security) then using SSLv23_method() will allow a dynamic
+ * choice of SSL v3.0 or any of the TLS versions on each connection.
+ */
+long BaseSecurity::OpenSSLCTXSetOptions = SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3;
+long BaseSecurity::OpenSSLCTXClearOptions = 0;
+
 Security::Security(const CipherList& cipherSuite) : BaseSecurity(cipherSuite)
 {
 #ifdef WIN32
@@ -311,6 +327,8 @@
 
    SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verifyCallback);
    SSL_CTX_set_cipher_list(ctx, mCipherList.cipherList().c_str());
+   SSL_CTX_set_options(ctx, BaseSecurity::OpenSSLCTXSetOptions);
+   SSL_CTX_clear_options(ctx, BaseSecurity::OpenSSLCTXClearOptions);
 
    return ctx;
 }
@@ -999,6 +1017,8 @@
    SSL_CTX_set_verify(mTlsCtx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verifyCallback);
    ret = SSL_CTX_set_cipher_list(mTlsCtx, cipherSuite.cipherList().c_str());
    assert(ret);
+   SSL_CTX_set_options(mTlsCtx, BaseSecurity::OpenSSLCTXSetOptions);
+   SSL_CTX_clear_options(mTlsCtx, BaseSecurity::OpenSSLCTXClearOptions);
    
    mSslCtx = SSL_CTX_new( SSLv23_method() );
    assert(mSslCtx);
@@ -1006,6 +1026,8 @@
    SSL_CTX_set_verify(mSslCtx, SSL_VERIFY_PEER|SSL_VERIFY_CLIENT_ONCE, verifyCallback);
    ret = SSL_CTX_set_cipher_list(mSslCtx,cipherSuite.cipherList().c_str());
    assert(ret);
+   SSL_CTX_set_options(mSslCtx, BaseSecurity::OpenSSLCTXSetOptions);
+   SSL_CTX_clear_options(mSslCtx, BaseSecurity::OpenSSLCTXClearOptions);
 }
 
 
@@ -2610,6 +2632,174 @@
    return isEqualNoCase(certificateName,domainName);
 }
 /**
+   Converts a string containing an SSL type name to the corresponding
+   enum value.
+*/
+SecurityTypes::SSLType
+BaseSecurity::parseSSLType(const Data& typeName)
+{
+   if(typeName == "TLSv1")
+   {
+      return SecurityTypes::TLSv1;
+   }
+   if(typeName == "SSLv23")
+   {
+      return SecurityTypes::SSLv23;
+   }
+   Data error = "Not a recognized SSL type: " + typeName;
+   throw invalid_argument(error.c_str());
+}
+/**
+   Converts a string containing an OpenSSL option name
+   (for SSL_CTX_set_options) to the numeric value from ssl.h
+*/
+long
+BaseSecurity::parseOpenSSLCTXOption(const Data& optionName)
+{
+   if(optionName == "SSL_OP_ALL")
+   {
+      return SSL_OP_ALL;
+   }
+   if(optionName == "SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION")
+   {
+      return SSL_OP_ALLOW_UNSAFE_LEGACY_RENEGOTIATION;
+   }
+   if(optionName == "SSL_OP_CIPHER_SERVER_PREFERENCE")
+   {
+      return SSL_OP_CIPHER_SERVER_PREFERENCE;
+   }
+   if(optionName == "SSL_OP_CISCO_ANYCONNECT")
+   {
+      return SSL_OP_CISCO_ANYCONNECT;
+   }
+   if(optionName == "SSL_OP_COOKIE_EXCHANGE")
+   {
+      return SSL_OP_COOKIE_EXCHANGE;
+   }
+   if(optionName == "SSL_OP_CRYPTOPRO_TLSEXT_BUG")
+   {
+      return SSL_OP_CRYPTOPRO_TLSEXT_BUG;
+   }
+   if(optionName == "SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS")
+   {
+      return SSL_OP_DONT_INSERT_EMPTY_FRAGMENTS;
+   }
+   if(optionName == "SSL_OP_EPHEMERAL_RSA")
+   {
+      return SSL_OP_EPHEMERAL_RSA;
+   }
+   if(optionName == "SSL_OP_LEGACY_SERVER_CONNECT")
+   {
+      return SSL_OP_LEGACY_SERVER_CONNECT;
+   }
+   if(optionName == "SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER")
+   {
+      return SSL_OP_MICROSOFT_BIG_SSLV3_BUFFER;
+   }
+   if(optionName == "SSL_OP_MICROSOFT_SESS_ID_BUG")
+   {
+      return SSL_OP_MICROSOFT_SESS_ID_BUG;
+   }
+   if(optionName == "SSL_OP_MSIE_SSLV2_RSA_PADDING")
+   {
+      return SSL_OP_MSIE_SSLV2_RSA_PADDING;
+   }
+   if(optionName == "SSL_OP_NETSCAPE_CA_DN_BUG")
+   {
+      return SSL_OP_NETSCAPE_CA_DN_BUG;
+   }
+   if(optionName == "SSL_OP_NETSCAPE_CHALLENGE_BUG")
+   {
+      return SSL_OP_NETSCAPE_CHALLENGE_BUG;
+   }
+   if(optionName == "SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG")
+   {
+      return SSL_OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG;
+   }
+   if(optionName == "SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG")
+   {
+      return SSL_OP_NETSCAPE_REUSE_CIPHER_CHANGE_BUG;
+   }
+   if(optionName == "SSL_OP_NO_COMPRESSION")
+   {
+      return SSL_OP_NO_COMPRESSION;
+   }
+   if(optionName == "SSL_OP_NO_QUERY_MTU")
+   {
+      return SSL_OP_NO_QUERY_MTU;
+   }
+   if(optionName == "SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION")
+   {
+      return SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION;
+   }
+   if(optionName == "SSL_OP_NO_SSLv2")
+   {
+      return SSL_OP_NO_SSLv2;
+   }
+   if(optionName == "SSL_OP_NO_SSLv3")
+   {
+      return SSL_OP_NO_SSLv3;
+   }
+   if(optionName == "SSL_OP_NO_TICKET")
+   {
+      return SSL_OP_NO_TICKET;
+   }
+   if(optionName == "SSL_OP_NO_TLSv1")
+   {
+      return SSL_OP_NO_TLSv1;
+   }
+   if(optionName == "SSL_OP_NO_TLSv1_1")
+   {
+      return SSL_OP_NO_TLSv1_1;
+   }
+   if(optionName == "SSL_OP_NO_TLSv1_2")
+   {
+      return SSL_OP_NO_TLSv1_2;
+   }
+   if(optionName == "SSL_OP_PKCS1_CHECK_1")
+   {
+      return SSL_OP_PKCS1_CHECK_1;
+   }
+   if(optionName == "SSL_OP_PKCS1_CHECK_2")
+   {
+      return SSL_OP_PKCS1_CHECK_2;
+   }
+   if(optionName == "SSL_OP_SAFARI_ECDHE_ECDSA_BUG")
+   {
+      return SSL_OP_SAFARI_ECDHE_ECDSA_BUG;
+   }
+   if(optionName == "SSL_OP_SINGLE_DH_USE")
+   {
+      return SSL_OP_SINGLE_DH_USE;
+   }
+   if(optionName == "SSL_OP_SINGLE_ECDH_USE")
+   {
+      return SSL_OP_SINGLE_ECDH_USE;
+   }
+   if(optionName == "SSL_OP_SSLEAY_080_CLIENT_DH_BUG")
+   {
+      return SSL_OP_SSLEAY_080_CLIENT_DH_BUG;
+   }
+   if(optionName == "SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG")
+   {
+      return SSL_OP_SSLREF2_REUSE_CERT_TYPE_BUG;
+   }
+   if(optionName == "SSL_OP_TLS_BLOCK_PADDING_BUG")
+   {
+      return SSL_OP_TLS_BLOCK_PADDING_BUG;
+   }
+   if(optionName == "SSL_OP_TLS_D5_BUG")
+   {
+      return SSL_OP_TLS_D5_BUG;
+   }
+   if(optionName == "SSL_OP_TLS_ROLLBACK_BUG")
+   {
+      return SSL_OP_TLS_ROLLBACK_BUG;
+   }
+   Data error = "Not a recognized OpenSSL option name: " + optionName;
+   throw invalid_argument(error.c_str());
+}
+/**
    Does a wildcard match on domain and certificate name
    @todo    looks incomplete, make better
 */
diff -Nru resiprocate-1.9.7/resip/stack/ssl/Security.hxx resiprocate-1.9.8/resip/stack/ssl/Security.hxx
--- resiprocate-1.9.7/resip/stack/ssl/Security.hxx	2014-05-31 12:46:11.000000000 +0200
+++ resiprocate-1.9.8/resip/stack/ssl/Security.hxx	2014-12-07 17:48:37.000000000 +0100
@@ -79,6 +79,17 @@
       static CipherList ExportableSuite;
       static CipherList StrongestSuite;
       
+      /**
+       * Note:
+       *
+       * To allow these to be backported to v1.9.x without ABI breakage,
+       * they are implemented as static fields.  In the next release branch,
+       * non-static versions could be added and the static values
+       * used as defaults.
+       */
+      static long OpenSSLCTXSetOptions;
+      static long OpenSSLCTXClearOptions;
+
       BaseSecurity(const CipherList& cipherSuite = ExportableSuite);
       virtual ~BaseSecurity();
 
@@ -181,6 +192,9 @@
       static void setAllowWildcardCertificates(bool bEnable) { mAllowWildcardCertificates = bEnable; }
       static bool allowWildcardCertificates() { return mAllowWildcardCertificates; }
 
+      static SecurityTypes::SSLType parseSSLType(const Data& typeName);
+      static long parseOpenSSLCTXOption(const Data& optionName);
+
    public:
       SSL_CTX*       getTlsCtx ();
       SSL_CTX*       getSslCtx ();
@@ -197,6 +211,16 @@
       typedef std::map<Data,Data>      PassPhraseMap;
 
    protected:
+      /**
+       * Note:
+       *
+       * mTlsCtx is being used when TLSv1 is requested.
+       * Adding more non-static fields like mTlsCtx for subsequent
+       * versions (e.g. for OpenSSL TLSv1_1_method()) breaks ABI
+       * compatability and is therefore difficult to backport onto
+       * release branches.  Better to use SSLv23_method and use OpenSSL
+       * options flags to specify the exact protocol versions to support.
+       */
       SSL_CTX*       mTlsCtx;
       SSL_CTX*       mSslCtx;
       static void dumpAsn(char*, Data);
diff -Nru resiprocate-1.9.7/resip/stack/ssl/TlsBaseTransport.cxx resiprocate-1.9.8/resip/stack/ssl/TlsBaseTransport.cxx
--- resiprocate-1.9.7/resip/stack/ssl/TlsBaseTransport.cxx	2014-05-31 12:46:11.000000000 +0200
+++ resiprocate-1.9.8/resip/stack/ssl/TlsBaseTransport.cxx	2014-12-07 17:48:37.000000000 +0100
@@ -5,6 +5,7 @@
 #ifdef USE_SSL
 
 #include <memory>
+#include <stdexcept>
 
 #include "rutil/compat.hxx"
 #include "rutil/Data.hxx"
@@ -50,13 +51,18 @@
    // otherwise we will use the SSL Ctx or TLS Ctx created in the Security class
    if(!sipDomain.empty())
    {
-      if (sslType == SecurityTypes::SSLv23)
-      {
-         mDomainCtx = mSecurity->createDomainCtx(SSLv23_method(), sipDomain, certificateFilename, privateKeyFilename);
-      }
-      else
+      switch(sslType)
       {
+      case SecurityTypes::SSLv23:
+         DebugLog(<<"Using SSLv23_method");
+         mDomainCtx = mSecurity->createDomainCtx(SSLv23_method(), sipDomain, certificateFilename, privateKeyFilename );
+         break;
+      case SecurityTypes::TLSv1:
+         DebugLog(<<"Using TLSv1_method");
          mDomainCtx = mSecurity->createDomainCtx(TLSv1_method(), sipDomain, certificateFilename, privateKeyFilename);
+         break;
+      default:
+         throw invalid_argument("Unrecognised SecurityTypes::SSLType value");
       }
    }
 }
@@ -75,15 +81,37 @@
 { 
    if(mDomainCtx)
    {
+      DebugLog(<<"Using TlsDomain-transport SSL_CTX");
       return mDomainCtx;
    }
    else if(mSslType == SecurityTypes::SSLv23)
    {
+      DebugLog(<<"Using SSLv23_method");
       return mSecurity->getSslCtx();
    }
+   DebugLog(<<"Using TLSv1_method");
    return mSecurity->getTlsCtx();
 }
 
+bool
+TlsBaseTransport::setPeerCertificateVerificationCallback(
+   SecurityTypes::SSLVendor vendor, void *func, void *arg)
+{
+   // Only OpenSSL is supported at present
+   if(vendor != SecurityTypes::OpenSSL)
+   {
+      ErrLog(<<"refusing to set SSL callback for unknown SSL stack vendor");
+      return false;
+   }
+
+   // For full details of this callback see:
+   // https://www.openssl.org/docs/ssl/SSL_CTX_set_cert_verify_callback.html
+   SSL_CTX_set_cert_verify_callback(getCtx(),
+      (int (*)(X509_STORE_CTX *,void *))func, arg);
+
+   return true;
+}
+
 Connection* 
 TlsBaseTransport::createConnection(const Tuple& who, Socket fd, bool server)
 {
diff -Nru resiprocate-1.9.7/resip/stack/ssl/TlsBaseTransport.hxx resiprocate-1.9.8/resip/stack/ssl/TlsBaseTransport.hxx
--- resiprocate-1.9.7/resip/stack/ssl/TlsBaseTransport.hxx	2014-05-31 12:46:11.000000000 +0200
+++ resiprocate-1.9.8/resip/stack/ssl/TlsBaseTransport.hxx	2014-12-07 17:48:37.000000000 +0100
@@ -47,6 +47,31 @@
       bool isUseEmailAsSIP()
          { return mUseEmailAsSIP; };
 
+      /** @brief Set a custom callback function to be used by the SSL stack
+          to inspect the peer certificate.
+
+          callback semantics (the arguments and return values) are very
+          specific to the SSL stack in use.  If the vendor parameter does
+          not match the SSL stack then this method returns false and does not
+          use the callback.
+
+          This method should be called before the stack starts accepting
+          connections, otherwise, any connection received before setting the
+          callback would be validated using the default validation function
+          provided by the SSL stack.
+
+          @param vendor the SSL stack vendor,
+                        for example, SecurityTypes::OpenSSL
+          @param func a pointer to the callback function, 0 to disable callback
+          @param arg an argument to be passed to the callback if the
+                     vendor API supports this
+          @return true if successful, false on failure
+      */
+      bool setPeerCertificateVerificationCallback(
+         SecurityTypes::SSLVendor vendor,
+         void *func,
+         void *arg);
+
    protected:
       Connection* createConnection(const Tuple& who, Socket fd, bool server=false);
 
diff -Nru resiprocate-1.9.7/resip/stack/ssl/TlsConnection.cxx resiprocate-1.9.8/resip/stack/ssl/TlsConnection.cxx
--- resiprocate-1.9.7/resip/stack/ssl/TlsConnection.cxx	2014-05-31 12:46:11.000000000 +0200
+++ resiprocate-1.9.8/resip/stack/ssl/TlsConnection.cxx	2014-12-07 17:10:43.000000000 +0100
@@ -124,7 +124,11 @@
    }
 
    mBio = BIO_new_socket((int)fd,0/*close flag*/);
-   assert( mBio );
+   if( !mBio )
+   {
+      throw Transport::Exception("Failed to create OpenSSL BIO for socket",
+         __FILE__, __LINE__);
+   }
    
    SSL_set_bio( mSsl, mBio, mBio );
 
diff -Nru resiprocate-1.9.7/resip/stack/test/Makefile.am resiprocate-1.9.8/resip/stack/test/Makefile.am
--- resiprocate-1.9.7/resip/stack/test/Makefile.am	2014-05-31 12:46:06.000000000 +0200
+++ resiprocate-1.9.8/resip/stack/test/Makefile.am	2014-12-07 17:48:37.000000000 +0100
@@ -115,8 +115,10 @@
 	testWsCookieContext
 
 if USE_SSL
-TESTS += testSocketFunc
-check_PROGRAMS += testSocketFunc
+TESTS += testSocketFunc \
+	testSecurity
+check_PROGRAMS += testSocketFunc \
+	testSecurity
 endif
 
 UAS_SOURCES = UAS.cxx
@@ -148,6 +150,7 @@
 testResponses_SOURCES = testResponses.cxx
 testRlmi_SOURCES = testRlmi.cxx TestSupport.cxx
 testSdp_SOURCES = testSdp.cxx TestSupport.cxx
+testSecurity_SOURCES = testSecurity.cxx
 testSelect_SOURCES = testSelect.cxx
 testSelectInterruptor_SOURCES = testSelectInterruptor.cxx
 testServer_SOURCES = testServer.cxx
diff -Nru resiprocate-1.9.7/resip/stack/test/Makefile.in resiprocate-1.9.8/resip/stack/test/Makefile.in
diff -Nru resiprocate-1.9.7/resip/stack/test/testSecurity.cxx resiprocate-1.9.8/resip/stack/test/testSecurity.cxx
--- resiprocate-1.9.7/resip/stack/test/testSecurity.cxx	1970-01-01 01:00:00.000000000 +0100
+++ resiprocate-1.9.8/resip/stack/test/testSecurity.cxx	2014-12-07 17:24:25.000000000 +0100
@@ -0,0 +1,190 @@
+#if defined(HAVE_CONFIG_H)
+#include "config.h"
+#endif
+
+#include <iostream>
+#include <stdexcept>
+
+#include "resip/stack/ssl/Security.hxx"
+//#include "rutil/ssl/OpenSSLInit.hxx"
+#include "rutil/ThreadIf.hxx"
+#include "rutil/Log.hxx"
+#include "rutil/Logger.hxx"
+
+#ifdef USE_SSL
+#include <openssl/evp.h>
+#endif
+
+using namespace std;
+using namespace resip;
+
+#define RESIPROCATE_SUBSYSTEM Subsystem::TEST
+
+// the destructor in BaseSecurity started crashing on the Mac and Windows
+// at Revision 5785. The crash can be reproduced by creating 2 security
+// objects, one after another.
+void testMultiple()
+{
+   {
+      Security security;
+   }
+#ifdef WIN32
+      Sleep(10000);
+#else
+      sleep(10);      
+#endif
+   {
+      Security security;
+   }
+}
+
+class HashThread : public ThreadIf
+{
+   public:
+      void thread()
+      {
+         Security security;
+         for(int i = 0; i < 500000; i++)
+         {
+            if (i % 1000 == 0)
+            {
+               DebugLog(<< "1000 digest calculations complete. ");               
+            }
+            makeMD5Digest("I don't give a damn about digest");
+         }
+      }
+   private:
+      void makeMD5Digest(const char *pBuf)
+      {
+
+#ifdef USE_SSL
+         unsigned char MD5_digest[EVP_MAX_MD_SIZE+1];
+         unsigned int iDigest = 0;
+         memset(MD5_digest, 0, sizeof(MD5_digest));
+
+         if(0 == pBuf)
+            return;
+
+         const EVP_MD *pDigest = EVP_md5();
+         if( 0 == pDigest)
+            return;
+
+         EVP_MD_CTX cCtx;
+         EVP_DigestInit(&cCtx, pDigest);
+         EVP_DigestUpdate(&cCtx, pBuf, strlen(pBuf));
+         EVP_DigestFinal(&cCtx, MD5_digest, &iDigest);
+         EVP_MD_CTX_cleanup(&cCtx);
+
+//         cout << "Your digest is: " << MD5_digest << endl;
+#else
+//         cout << "OpenSSL not enabled; cannot calculate digest !!!";
+#endif
+      }
+};
+
+class DumbInitThread : public ThreadIf
+{
+   public:
+      void thread()
+      {
+         for(int i = 0; i < 500; i++)
+         {
+            DebugLog(<< "Creating Security object on stack");           
+            Security security;
+         }
+      }
+};
+
+void testSecurityMultiThread()
+{
+   HashThread t1;
+   DumbInitThread t2;
+
+   t1.run();
+   t2.run();
+
+   t1.join();
+   t2.join();
+}
+
+
+int
+main(int argc, const char** argv)
+{
+   Log::initialize(Log::Cout, Log::Debug, argv[0]);
+   assert(Security::parseSSLType("TLSv1") == SecurityTypes::TLSv1);
+   assert(Security::parseSSLType("SSLv23") == SecurityTypes::SSLv23);
+   try
+   {
+      SecurityTypes::SSLType val = BaseSecurity::parseSSLType("BigBrotherIsWatching");
+      assert(0); // should have thrown an exception
+   }
+   catch (const invalid_argument& ia) { } // ignore, expected exception
+
+   assert(Security::parseOpenSSLCTXOption("SSL_OP_NO_SSLv2") == SSL_OP_NO_SSLv2);
+   assert(Security::parseOpenSSLCTXOption("SSL_OP_NO_SSLv3") == SSL_OP_NO_SSLv3);
+   try
+   {
+      SecurityTypes::SSLType val = BaseSecurity::parseSSLType("BigBrotherIsWatching");
+      assert(0); // should have thrown an exception
+   }
+   catch (const invalid_argument& ia) { } // ignore, expected exception
+
+#if 0
+   testMultiple();
+#else
+   testSecurityMultiThread();
+#endif
+   return 0;
+}
+
+
+/* ====================================================================
+ * The Vovida Software License, Version 1.0 
+ * 
+ * Copyright (c) 2000 Vovida Networks, Inc.  All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in
+ *    the documentation and/or other materials provided with the
+ *    distribution.
+ * 
+ * 3. The names "VOCAL", "Vovida Open Communication Application Library",
+ *    and "Vovida Open Communication Application Library (VOCAL)" must
+ *    not be used to endorse or promote products derived from this
+ *    software without prior written permission. For written
+ *    permission, please contact vocal@vovida.org.
+ *
+ * 4. Products derived from this software may not be called "VOCAL", nor
+ *    may "VOCAL" appear in their name, without prior written
+ *    permission of Vovida Networks, Inc.
+ * 
+ * THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESSED OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE, TITLE AND
+ * NON-INFRINGEMENT ARE DISCLAIMED.  IN NO EVENT SHALL VOVIDA
+ * NETWORKS, INC. OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT DAMAGES
+ * IN EXCESS OF $1,000, NOR FOR ANY INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ * 
+ * ====================================================================
+ * 
+ * This software consists of voluntary contributions made by Vovida
+ * Networks, Inc. and many individuals on behalf of Vovida Networks,
+ * Inc.  For more information on Vovida Networks, Inc., please see
+ * <http://www.vovida.org/>.
+ *
+ */
diff -Nru resiprocate-1.9.7/resiprocate.spec resiprocate-1.9.8/resiprocate.spec

Reply to: