[squid-dev] [RFC] [PREVIEW] LockingPointer round 3.

Amos Jeffries squid3 at treenet.co.nz
Wed Jul 20 04:45:56 UTC 2016


On 19/07/2016 7:14 p.m., Amos Jeffries wrote:
> On 19/07/2016 6:58 a.m., Christos Tsantilas wrote:
>> On 07/18/2016 08:32 PM, Alex Rousskov wrote:
> 
> Dropping the non-locking constructor and forcing explicit resetFoo() is
> probably for the best. Though it would not have helped in this case. I
> did think the 'ssl' variable being passed in there was pre-locked so
> would have coded as resetWithoutLocking().
>  Would that difference in syntax have helped in the (brief) review?
> 
> 
>>>
>>> I can only repeat my earlier suggestions to hide that dangerous
>>> constructor behind an explicit static method like
>>> LockingPointer::NewWithoutLocking() and to assert that
>>> resetWithoutLocking() method is fed a previously locked object.
>>
>> something like that.
> 
> Nod. I'm about to try a build with dropped construtor to see what
> breaks. That should highlight if a builder function is actually
> necessary. I hope we can avoid it.
> 

Attached is a patch showing what that constructor removal would look
like for current Squid trunk.

I've added "// X locks" comments on new resetWithoutLocking() to be
clearer where the non-locking comes from. OpenSSL API explicitly
mentions that it "increments a reference" / locks.

There are some new XXX points where I got ambiguous documentation about
OpenSSL behaviour, or our code starts to show problems. Most notably
client_side.cc shows up some weird behaviour going on with
dynamicSslContext.

Amos

-------------- next part --------------
=== modified file 'src/client_side.cc'
--- src/client_side.cc	2016-07-18 12:36:38 +0000
+++ src/client_side.cc	2016-07-19 12:28:26 +0000
@@ -3043,43 +3043,50 @@
     }
     getSslContextDone(NULL);
 }
 
 void
 ConnStateData::getSslContextDone(Security::ContextPtr sslContext, bool isNew)
 {
     // Try to add generated ssl context to storage.
     if (port->generateHostCertificates && isNew) {
 
         if (sslContext && (signAlgorithm == Ssl::algSignTrusted)) {
             Ssl::chainCertificatesToSSLContext(sslContext, *port);
         } else if (signAlgorithm == Ssl::algSignTrusted) {
             debugs(33, DBG_IMPORTANT, "WARNING: can not add signing certificate to SSL context chain because SSL context chain is invalid!");
         }
         //else it is self-signed or untrusted do not attrach any certificate
 
         Ssl::LocalContextStorage *ssl_ctx_cache = Ssl::TheGlobalContextStorage.getLocalStorage(port->s);
         assert(sslBumpCertKey.size() > 0 && sslBumpCertKey[0] != '\0');
         if (sslContext) {
-            if (!ssl_ctx_cache || !ssl_ctx_cache->add(sslBumpCertKey.termedBuf(), new Security::ContextPointer(sslContext))) {
-                // If it is not in storage delete after using. Else storage deleted it.
+            if (!ssl_ctx_cache)
+                // if there is no storage, just use
                 fd_table[clientConnection->fd].dynamicSslContext = sslContext;
+            else {
+                Security::ContextPointer *ctx = new Security::ContextPointer;
+                ctx->resetWithoutLocking(sslContext);
+                if (!ssl_ctx_cache->add(sslBumpCertKey.termedBuf(), ctx)) {
+                    // If it is not in storage delete after using. Else storage deleted it.
+                    fd_table[clientConnection->fd].dynamicSslContext = sslContext;
+                } // XXX: why not set fd_table if that add() succeeded ?
             }
         } else {
             debugs(33, 2, HERE << "Failed to generate SSL cert for " << sslConnectHostOrIp);
         }
     }
 
     // If generated ssl context = NULL, try to use static ssl context.
     if (!sslContext) {
         if (!port->secure.staticContext) {
             debugs(83, DBG_IMPORTANT, "Closing " << clientConnection->remote << " as lacking TLS context");
             clientConnection->close();
             return;
         } else {
             debugs(33, 5, "Using static TLS context.");
             sslContext = port->secure.staticContext.get();
         }
     }
 
     if (!httpsCreate(clientConnection, sslContext))
         return;

=== modified file 'src/security/LockingPointer.h'
--- src/security/LockingPointer.h	2016-07-13 12:39:22 +0000
+++ src/security/LockingPointer.h	2016-07-19 07:56:37 +0000
@@ -34,78 +34,80 @@
 namespace Security
 {
 
 /**
  * A shared pointer to a reference-counting Object with library-specific
  * absorption, locking, and unlocking implementations. The API largely
  * follows std::shared_ptr.
  *
  * The constructor and the resetWithoutLocking() method import a raw Object pointer.
  * Normally, reset() would lock(), but libraries like OpenSSL
  * pre-lock objects before they are fed to LockingPointer, necessitating
  * this resetWithoutLocking() customization hook.
  */
 template <typename T, void (*UnLocker)(T *t), int lockId>
 class LockingPointer
 {
 public:
     /// a helper label to simplify this objects API definitions below
     typedef Security::LockingPointer<T, UnLocker, lockId> SelfType;
 
-    /**
-     * Construct directly from a raw pointer.
-     * This action requires that the producer of that pointer has already
-     * created one reference lock for the object pointed to.
-     * Our destructor will do the matching unlock.
-     */
-    explicit LockingPointer(T *t = nullptr): raw(nullptr) {
-        // de-optimized for clarity about non-locking
-        resetWithoutLocking(t);
-    }
+    explicit LockingPointer() : raw(nullptr) {}
 
     /// use the custom UnLocker to unlock any value still stored.
     ~LockingPointer() { unlock(); }
 
+    /**
+     * Construct directly from a raw pointer is forbidden.
+     * Use the appropriate reset method instead.
+     */
+    explicit LockingPointer(T *) = delete;
+
     // copy semantics are okay only when adding a lock reference
     explicit LockingPointer(const SelfType &o) : raw(nullptr) {
         resetAndLock(o.get());
     }
     const SelfType &operator =(const SelfType &o) {
         resetAndLock(o.get());
         return *this;
     }
 
     // move semantics are definitely okay, when possible
     explicit LockingPointer(SelfType &&) = default;
     SelfType &operator =(SelfType &&o) {
         if (o.get() != raw)
             resetWithoutLocking(o.release());
         return *this;
     }
 
     bool operator !() const { return !raw; }
     explicit operator bool() const { return raw; }
 
     /// Returns raw and possibly nullptr pointer
     T *get() const { return raw; }
 
-    /// Reset raw pointer - unlock any previous one and save new one without locking.
+    /**
+     * Reset raw pointer - unlock any previous one and save new one without locking.
+     * This requires that the producer of that pointer has already
+     * created one reference lock for the object pointed to.
+     * Our destructor will do the matching unlock.
+     */
     void resetWithoutLocking(T *t) {
         unlock();
         raw = t;
     }
 
     void resetAndLock(T *t) {
         if (t != get()) {
             resetWithoutLocking(t);
             lock(t);
         }
     }
 
     /// Forget the raw pointer - unlock if any value was set. Become a nil pointer.
     void reset() { unlock(); }
 
     /// Forget the raw pointer without unlocking it. Become a nil pointer.
     T *release() {
         T *ret = raw;
         raw = nullptr;
         return ret;

=== modified file 'src/security/PeerOptions.cc'
--- src/security/PeerOptions.cc	2016-06-15 14:31:34 +0000
+++ src/security/PeerOptions.cc	2016-07-19 11:23:48 +0000
@@ -198,40 +198,41 @@
             add = "NO_SSLv3,NO_TLSv1_1,NO_TLSv1_2";
             break;
         case 5:
             add = "NO_SSLv3,NO_TLSv1,NO_TLSv1_2";
             break;
         case 6:
             add = "NO_SSLv3,NO_TLSv1,NO_TLSv1_1";
             break;
         default: // nothing
             break;
         }
         if (add) {
             if (!sslOptions.isEmpty())
                 sslOptions.append(",",1);
             sslOptions.append(add, strlen(add));
         }
         sslVersion = 0; // prevent sslOptions being repeatedly appended
     }
 }
 
+// XXX: fix to return a Pointer instead of Ptr
 Security::ContextPtr
 Security::PeerOptions::createBlankContext() const
 {
     Security::ContextPtr t = nullptr;
 
 #if USE_OPENSSL
     Ssl::Initialize();
 
 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
     t = SSL_CTX_new(TLS_client_method());
 #else
     t = SSL_CTX_new(SSLv23_client_method());
 #endif
     if (!t) {
         const auto x = ERR_error_string(ERR_get_error(), nullptr);
         fatalf("Failed to allocate TLS client context: %s\n", x);
     }
 
 #elif USE_GNUTLS
     // Initialize for X.509 certificate exchange
@@ -519,41 +520,43 @@
     return fl;
 }
 
 /// Load a CRLs list stored in the file whose /path/name is in crlFile
 /// replaces any CRL loaded previously
 void
 Security::PeerOptions::loadCrlFile()
 {
     parsedCrl.clear();
     if (crlFile.isEmpty())
         return;
 
 #if USE_OPENSSL
     BIO *in = BIO_new_file(crlFile.c_str(), "r");
     if (!in) {
         debugs(83, 2, "WARNING: Failed to open CRL file " << crlFile);
         return;
     }
 
     while (X509_CRL *crl = PEM_read_bio_X509_CRL(in,NULL,NULL,NULL)) {
-        parsedCrl.emplace_back(Security::CrlPointer(crl));
+        Security::CrlPointer tmp;
+        tmp.resetWithoutLocking(crl); // XXX: does PEM_read_bio_X509_CRL lock ??
+        parsedCrl.emplace_back(tmp);
     }
     BIO_free(in);
 #endif
 }
 
 #if USE_OPENSSL && defined(TLSEXT_TYPE_next_proto_neg)
 // Dummy next_proto_neg callback
 static int
 ssl_next_proto_cb(SSL *s, unsigned char **out, unsigned char *outlen, const unsigned char *in, unsigned int inlen, void *arg)
 {
     static const unsigned char supported_protos[] = {8, 'h','t','t', 'p', '/', '1', '.', '1'};
     (void)SSL_select_next_proto(out, outlen, in, inlen, supported_protos, sizeof(supported_protos));
     return SSL_TLSEXT_ERR_OK;
 }
 #endif
 
 void
 Security::PeerOptions::updateContextNpn(Security::ContextPtr &ctx)
 {
     if (!flags.tlsNpn)

=== modified file 'src/security/ServerOptions.cc'
--- src/security/ServerOptions.cc	2016-07-07 19:03:02 +0000
+++ src/security/ServerOptions.cc	2016-07-19 11:21:35 +0000
@@ -105,41 +105,42 @@
 
 #elif USE_GNUTLS
     // Initialize for X.509 certificate exchange
     if (const int x = gnutls_certificate_allocate_credentials(&t)) {
         debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: error=" << x);
     }
 
 #else
     debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate TLS server context: No TLS library");
 
 #endif
 
     return t;
 }
 
 bool
 Security::ServerOptions::createStaticServerContext(AnyP::PortCfg &port)
 {
     updateTlsVersionLimits();
 
-    Security::ContextPointer t(createBlankContext());
+    Security::ContextPointer t;
+    t.resetWithoutLocking(createBlankContext()); // createBlankContext locks
     if (t) {
 #if USE_OPENSSL
         if (!Ssl::InitServerContext(t, port))
             return false;
 #endif
     }
 
     staticContext = std::move(t);
     return bool(staticContext);
 }
 
 void
 Security::ServerOptions::loadDhParams()
 {
     if (dhParamsFile.isEmpty())
         return;
 
 #if USE_OPENSSL
     DH *dhp = nullptr;
     if (FILE *in = fopen(dhParamsFile.c_str(), "r")) {

=== modified file 'src/ssl/PeekingPeerConnector.cc'
--- src/ssl/PeekingPeerConnector.cc	2016-07-13 12:39:22 +0000
+++ src/ssl/PeekingPeerConnector.cc	2016-07-19 09:39:01 +0000
@@ -292,84 +292,86 @@
     if (srvBio->bumpMode() == Ssl::bumpPeek && (resumingSession = srvBio->resumingSession())) {
         // we currently splice all resumed sessions unconditionally
         if (const bool spliceResumed = true) {
             bypassCertValidator();
             checkForPeekAndSpliceMatched(Ssl::bumpSplice);
             return;
         } // else fall through to find a matching ssl_bump action (with limited info)
     }
 
     // If we are in peek-and-splice mode and still we did not write to
     // server yet, try to see if we should splice.
     // In this case the connection can be saved.
     // If the checklist decision is do not splice a new error will
     // occur in the next SSL_connect call, and we will fail again.
     // Abort on certificate validation errors to avoid splicing and
     // thus hiding them.
     // Abort if no certificate found probably because of malformed or
     // unsupported server Hello message (TODO: make configurable).
     if (!SSL_get_ex_data(ssl, ssl_ex_index_ssl_error_detail) &&
             (srvBio->bumpMode() == Ssl::bumpPeek  || srvBio->bumpMode() == Ssl::bumpStare) && srvBio->holdWrite()) {
-        Security::CertPointer serverCert(SSL_get_peer_certificate(ssl));
-        if (serverCert.get()) {
+        Security::CertPointer serverCert;
+        serverCert.resetWithoutLocking(SSL_get_peer_certificate(ssl)); // SSL_get_peer_certificate locks.
+        if (serverCert) {
             debugs(81, 3, "Error ("  << ERR_error_string(ssl_lib_error, NULL) <<  ") but, hold write on SSL connection on FD " << fd);
             checkForPeekAndSplice();
             return;
         }
     }
 
     // else call parent noteNegotiationError to produce an error page
     Ssl::PeerConnector::noteSslNegotiationError(result, ssl_error, ssl_lib_error);
 }
 
 void
 Ssl::PeekingPeerConnector::handleServerCertificate()
 {
     if (serverCertificateHandled)
         return;
 
     if (ConnStateData *csd = request->clientConnectionManager.valid()) {
         const int fd = serverConnection()->fd;
         Security::SessionPtr ssl = fd_table[fd].ssl.get();
-        Security::CertPointer serverCert(SSL_get_peer_certificate(ssl));
-        if (!serverCert.get())
+        Security::CertPointer serverCert;
+        serverCert.resetWithoutLocking(SSL_get_peer_certificate(ssl)); // SSL_get_peer_certificate locks
+        if (!serverCert)
             return;
 
         serverCertificateHandled = true;
 
         // remember the server certificate for later use
         if (Ssl::ServerBump *serverBump = csd->serverBump()) {
             serverBump->serverCert = std::move(serverCert);
         }
     }
 }
 
 void
 Ssl::PeekingPeerConnector::serverCertificateVerified()
 {
     if (ConnStateData *csd = request->clientConnectionManager.valid()) {
         Security::CertPointer serverCert;
         if(Ssl::ServerBump *serverBump = csd->serverBump())
             serverCert.resetAndLock(serverBump->serverCert.get());
         else {
             const int fd = serverConnection()->fd;
             Security::SessionPtr ssl = fd_table[fd].ssl.get();
-            serverCert.resetWithoutLocking(SSL_get_peer_certificate(ssl));
+            serverCert.resetWithoutLocking(SSL_get_peer_certificate(ssl)); // SSL_get_peer_certificate locks
         }
         if (serverCert.get()) {
             csd->resetSslCommonName(Ssl::CommonHostName(serverCert.get()));
             debugs(83, 5, "HTTPS server CN: " << csd->sslCommonName() <<
                    " bumped: " << *serverConnection());
         }
     }
 }
 
 void
 Ssl::PeekingPeerConnector::tunnelInsteadOfNegotiating()
 {
     Must(callback != NULL);
     CbDialer *dialer = dynamic_cast<CbDialer*>(callback->getDialer());
     Must(dialer);
     dialer->answer().tunneled = true;
     debugs(83, 5, "The SSL negotiation with server aborted");
 }
 

=== modified file 'src/ssl/PeerConnector.cc'
--- src/ssl/PeerConnector.cc	2016-07-13 12:39:22 +0000
+++ src/ssl/PeerConnector.cc	2016-07-19 09:47:20 +0000
@@ -279,41 +279,42 @@
     for (SVCRECI i = resp.errors.begin(); i != resp.errors.end(); ++i) {
         debugs(83, 7, "Error item: " << i->error_no << " " << i->error_reason);
 
         assert(i->error_no != SSL_ERROR_NONE);
 
         if (!errDetails) {
             bool allowed = false;
             if (check) {
                 check->sslErrors = new Ssl::CertErrors(Ssl::CertError(i->error_no, i->cert.get(), i->error_depth));
                 if (check->fastCheck() == ACCESS_ALLOWED)
                     allowed = true;
             }
             // else the Config.ssl_client.cert_error access list is not defined
             // and the first error will cause the error page
 
             if (allowed) {
                 debugs(83, 3, "bypassing SSL error " << i->error_no << " in " << "buffer");
             } else {
                 debugs(83, 5, "confirming SSL error " << i->error_no);
                 X509 *brokenCert = i->cert.get();
-                Security::CertPointer peerCert(SSL_get_peer_certificate(ssl));
+                Security::CertPointer peerCert;;
+                peerCert.resetWithoutLocking(SSL_get_peer_certificate(ssl)); // SSL_get_peer_certificate locks
                 const char *aReason = i->error_reason.empty() ? NULL : i->error_reason.c_str();
                 errDetails = new Ssl::ErrorDetail(i->error_no, peerCert.get(), brokenCert, aReason);
             }
             if (check) {
                 delete check->sslErrors;
                 check->sslErrors = NULL;
             }
         }
 
         if (!errs)
             errs = new Ssl::CertErrors(Ssl::CertError(i->error_no, i->cert.get(), i->error_depth));
         else
             errs->push_back_unique(Ssl::CertError(i->error_no, i->cert.get(), i->error_depth));
     }
     if (check)
         delete check;
 
     return errs;
 }
 

=== modified file 'src/ssl/cert_validate_message.h'
--- src/ssl/cert_validate_message.h	2016-01-01 00:12:18 +0000
+++ src/ssl/cert_validate_message.h	2016-07-19 09:14:48 +0000
@@ -31,79 +31,79 @@
     std::string domainName; ///< The server name
     CertValidationRequest() : ssl(NULL), errors(NULL) {}
 };
 
 /**
  * This class is used to store informations found in certificate validation
  * response messages read from certificate validator helper
  */
 class CertValidationResponse: public RefCountable
 {
 public:
     typedef RefCount<CertValidationResponse> Pointer;
 
     /**
      * This class used to hold error informations returned from
      * cert validator helper.
      */
     class  RecvdError
     {
     public:
-        RecvdError(): id(0), error_no(SSL_ERROR_NONE), cert(NULL), error_depth(-1) {}
+        RecvdError(): id(0), error_no(SSL_ERROR_NONE), error_depth(-1) {}
         RecvdError(const RecvdError &);
         RecvdError & operator =(const RecvdError &);
         void setCert(X509 *);  ///< Sets cert to the given certificate
         int id; ///<  The id of the error
         ssl_error_t error_no; ///< The OpenSSL error code
         std::string error_reason; ///< A string describing the error
         Security::CertPointer cert; ///< The broken certificate
         int error_depth; ///< The error depth
     };
 
     typedef std::vector<RecvdError> RecvdErrors;
 
     /// Search in errors list for the error item with id=errorId.
     /// If none found a new RecvdError item added with the given id;
     RecvdError &getError(int errorId);
     RecvdErrors errors; ///< The list of parsed errors
     Helper::ResultCode resultCode; ///< The helper result code
 };
 
 /**
  * This class is responsible for composing or parsing messages destined to
  * or comming from a cert validator helper.
  * The messages format is:
  *   response/request-code SP body-length SP [key=value ...] \x01
  */
 class CertValidationMsg : public CrtdMessage
 {
 private:
     /**
      * This class used to hold the certId/cert pairs found
      * in cert validation messages.
      */
     class CertItem
     {
     public:
         std::string name; ///< The certificate Id to use
         Security::CertPointer cert;       ///< A pointer to certificate
-        CertItem(): cert(NULL) {}
+        CertItem() = default;
         CertItem(const CertItem &);
         CertItem & operator =(const CertItem &);
         void setCert(X509 *); ///< Sets cert to the given certificate
     };
 
 public:
     CertValidationMsg(MessageKind kind): CrtdMessage(kind) {}
 
     /// Build a request message for the cert validation helper
     /// using informations provided by vcert object
     void composeRequest(CertValidationRequest const &vcert);
 
     /// Parse a response message and fill the resp object with parsed informations
     bool parseResponse(CertValidationResponse &resp, STACK_OF(X509) *peerCerts, std::string &error);
 
     /// Search a CertItems list for the certificate with ID "name"
     X509 *getCertByName(std::vector<CertItem> const &, std::string const & name);
 
     /// String code for "cert_validate" messages
     static const std::string code_cert_validate;

=== modified file 'src/ssl/gadgets.cc'
--- src/ssl/gadgets.cc	2016-07-08 06:24:33 +0000
+++ src/ssl/gadgets.cc	2016-07-19 11:11:52 +0000
@@ -1,51 +1,52 @@
 /*
  * Copyright (C) 1996-2016 The Squid Software Foundation and contributors
  *
  * Squid software is distributed under GPLv2+ license and includes
  * contributions from numerous individuals and organizations.
  * Please see the COPYING and CONTRIBUTORS files for details.
  */
 
 #include "squid.h"
 #include "ssl/gadgets.h"
 
 #if HAVE_OPENSSL_X509V3_H
 #include <openssl/x509v3.h>
 #endif
 
 EVP_PKEY * Ssl::createSslPrivateKey()
 {
-    Ssl::EVP_PKEY_Pointer pkey(EVP_PKEY_new());
+    Ssl::EVP_PKEY_Pointer pkey;
+    pkey.resetWithoutLocking(EVP_PKEY_new()); // EVP_PKEY_new locks
 
     if (!pkey)
         return NULL;
 
     Ssl::RSA_Pointer rsa(RSA_generate_key(1024, RSA_F4, NULL, NULL));
 
     if (!rsa)
         return NULL;
 
     if (!EVP_PKEY_assign_RSA(pkey.get(), (rsa.get())))
         return NULL;
 
-    rsa.release();
+    rsa.release(); // XXX: because EVP_PKEY_assign_RSA steals ptr without locking? we leak?
     return pkey.release();
 }
 
 /**
  \ingroup ServerProtocolSSLInternal
  * Set serial random serial number or set random serial number.
  */
 static bool setSerialNumber(ASN1_INTEGER *ai, BIGNUM const* serial)
 {
     if (!ai)
         return false;
     Ssl::BIGNUM_Pointer bn(BN_new());
     if (serial) {
         bn.reset(BN_dup(serial));
     } else {
         if (!bn)
             return false;
 
         if (!BN_pseudo_rand(bn.get(), 64, 0, 0))
             return false;
@@ -499,41 +500,42 @@
         // According to RFC 5280, using extensions requires v3 certificate.
         if (addedExtensions)
             X509_set_version(cert.get(), 2); // value 2 means v3
     }
 
     return true;
 }
 
 static bool generateFakeSslCertificate(Security::CertPointer & certToStore, Ssl::EVP_PKEY_Pointer & pkeyToStore, Ssl::CertificateProperties const &properties,  Ssl::BIGNUM_Pointer const &serial)
 {
     Ssl::EVP_PKEY_Pointer pkey;
     // Use signing certificates private key as generated certificate private key
     if (properties.signWithPkey.get())
         pkey.resetAndLock(properties.signWithPkey.get());
     else // if not exist generate one
         pkey.resetWithoutLocking(Ssl::createSslPrivateKey());
 
     if (!pkey)
         return false;
 
-    Security::CertPointer cert(X509_new());
+    Security::CertPointer cert;
+    cert.resetWithoutLocking(X509_new()); // X509_new locks
     if (!cert)
         return false;
 
     // Set pub key and serial given by the caller
     if (!X509_set_pubkey(cert.get(), pkey.get()))
         return false;
     if (!setSerialNumber(X509_get_serialNumber(cert.get()), serial.get()))
         return false;
 
     // Fill the certificate with the required properties
     if (!buildCertificate(cert, properties))
         return false;
 
     int ret = 0;
     // Set issuer name, from CA or our subject name for self signed cert
     if (properties.signAlgorithm != Ssl::algSignSelf && properties.signWithX509.get())
         ret = X509_set_issuer_name(cert.get(), X509_get_subject_name(properties.signWithX509.get()));
     else // Self signed certificate, set issuer to self
         ret = X509_set_issuer_name(cert.get(), X509_get_subject_name(cert.get()));
     if (!ret)

=== modified file 'src/ssl/support.cc'
--- src/ssl/support.cc	2016-07-11 10:57:11 +0000
+++ src/ssl/support.cc	2016-07-19 10:08:19 +0000
@@ -904,44 +904,45 @@
     for (i = 0; i < sk_X509_num(chain); ++i) {
         X509 *cert = sk_X509_value(chain, i);
         PEM_write_bio_X509(mem, cert);
     }
 
     len = BIO_get_mem_data(mem, &ptr);
 
     str = (char *)xmalloc(len + 1);
     memcpy(str, ptr, len);
     str[len] = '\0';
 
     BIO_free(mem);
 
     return str;
 }
 
 /// Create SSL context and apply ssl certificate and private key to it.
 Security::ContextPtr
 Ssl::createSSLContext(Security::CertPointer & x509, Ssl::EVP_PKEY_Pointer & pkey, AnyP::PortCfg &port)
 {
+    Security::ContextPointer sslContext;
 #if (OPENSSL_VERSION_NUMBER >= 0x10100000L)
-    Security::ContextPointer sslContext(SSL_CTX_new(TLS_server_method()));
+    sslContext.resetWithoutLocking(SSL_CTX_new(TLS_server_method())); // SSL_CTX_new locks
 #else
-    Security::ContextPointer sslContext(SSL_CTX_new(SSLv23_server_method()));
+    sslContext.resetWithoutLocking(SSL_CTX_new(SSLv23_server_method())); // SSL_CTX_new locks
 #endif
 
     if (!SSL_CTX_use_certificate(sslContext.get(), x509.get()))
         return NULL;
 
     if (!SSL_CTX_use_PrivateKey(sslContext.get(), pkey.get()))
         return NULL;
 
     if (!configureSslContext(sslContext.get(), port))
         return NULL;
 
     return sslContext.release();
 }
 
 Security::ContextPtr
 Ssl::generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port)
 {
     Security::CertPointer cert;
     Ssl::EVP_PKEY_Pointer pkey;
     if (!readCertAndPrivateKeyFromMemory(cert, pkey, data) || !cert || !pkey)



More information about the squid-dev mailing list