From f19829e5634995f227e49018138bbb2585d3ba0f Mon Sep 17 00:00:00 2001 From: Nathan Hoad Date: Wed, 20 Apr 2016 03:04:09 +1200 Subject: [PATCH] Add chained certificates and signing certificate to peek-then-bumped connections. The scenario this patch addresses is when Squid is configured with an intermediate signing CA certificate, and clients have the root CA installed on their machines. What happens is that the generated certificates come down with an unknown issuer (the intermediate signing certificate), with no intermediates, so they are rejected. By adding the configured certificate chain as old client-first mode did, the intermediate and root certificates come down as well, resulting in the issuer being identified and the connection being established "securely". This work is submitted on behalf of Bloomberg L.P. --- src/client_side.cc | 21 ++++++++++----------- src/ssl/support.cc | 24 ++++++++++++++++++++++++ src/ssl/support.h | 12 ++++++++++++ 3 files changed, 46 insertions(+), 11 deletions(-) diff --git a/src/client_side.cc b/src/client_side.cc index f8bc43b301..92528c5ad0 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -3997,6 +3997,9 @@ ConnStateData::sslCrtdHandleReply(const Helper::Reply &reply) bool ret = Ssl::configureSSLUsingPkeyAndCertFromMemory(ssl, reply_message.getBody().c_str(), *port); if (!ret) debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode"); + + SSL_CTX *sslContext = SSL_get_SSL_CTX(ssl); + Ssl::configureUnconfiguredSslContext(sslContext, signAlgorithm, *port); } else { SSL_CTX *ctx = Ssl::generateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str(), *port); getSslContextDone(ctx, true); @@ -4155,6 +4158,9 @@ ConnStateData::getSslContextStart() SSL *ssl = fd_table[clientConnection->fd].ssl; if (!Ssl::configureSSL(ssl, certProperties, *port)) debugs(33, 5, "Failed to set certificates to ssl object for PeekAndSplice mode"); + + SSL_CTX *sslContext = SSL_get_SSL_CTX(ssl); + Ssl::configureUnconfiguredSslContext(sslContext, certProperties.signAlgorithm, *port); } else { SSL_CTX *dynCtx = Ssl::generateSslContext(certProperties, *port); getSslContextDone(dynCtx, true); @@ -4170,17 +4176,10 @@ ConnStateData::getSslContextDone(SSL_CTX * sslContext, bool isNew) // Try to add generated ssl context to storage. if (port->generateHostCertificates && isNew) { - if (signAlgorithm == Ssl::algSignTrusted) { - // Add signing certificate to the certificates chain - X509 *cert = port->signingCert.get(); - if (SSL_CTX_add_extra_chain_cert(sslContext, cert)) { - // increase the certificate lock - CRYPTO_add(&(cert->references),1,CRYPTO_LOCK_X509); - } else { - const int ssl_error = ERR_get_error(); - debugs(33, DBG_IMPORTANT, "WARNING: can not add signing certificate to SSL context chain: " << ERR_error_string(ssl_error, NULL)); - } - Ssl::addChainToSslContext(sslContext, port->certsToChain.get()); + 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 diff --git a/src/ssl/support.cc b/src/ssl/support.cc index 3faf64acd5..60ee84c3bc 100644 --- a/src/ssl/support.cc +++ b/src/ssl/support.cc @@ -1697,6 +1697,30 @@ Ssl::generateSslContext(CertificateProperties const &properties, AnyP::PortCfg & return createSSLContext(cert, pkey, port); } +void +Ssl::chainCertificatesToSSLContext(SSL_CTX *sslContext, AnyP::PortCfg &port) +{ + assert(sslContext != NULL); + // Add signing certificate to the certificates chain + X509 *signingCert = port.signingCert.get(); + if (SSL_CTX_add_extra_chain_cert(sslContext, signingCert)) { + // increase the certificate lock + CRYPTO_add(&(signingCert->references),1,CRYPTO_LOCK_X509); + } else { + const int ssl_error = ERR_get_error(); + debugs(33, DBG_IMPORTANT, "WARNING: can not add signing certificate to SSL context chain: " << ERR_error_string(ssl_error, NULL)); + } + Ssl::addChainToSslContext(sslContext, port.certsToChain.get()); +} + +void +Ssl::configureUnconfiguredSslContext(SSL_CTX *sslContext, Ssl::CertSignAlgorithm signAlgorithm,AnyP::PortCfg &port) +{ + if (sslContext && signAlgorithm == Ssl::algSignTrusted) { + Ssl::chainCertificatesToSSLContext(sslContext, port); + } +} + bool Ssl::configureSSL(SSL *ssl, CertificateProperties const &properties, AnyP::PortCfg &port) { diff --git a/src/ssl/support.h b/src/ssl/support.h index 324a9b2182..e23791f268 100644 --- a/src/ssl/support.h +++ b/src/ssl/support.h @@ -246,6 +246,18 @@ SSL_CTX * generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP:: */ SSL_CTX * createSSLContext(Ssl::X509_Pointer & x509, Ssl::EVP_PKEY_Pointer & pkey, AnyP::PortCfg &port); +/** + \ingroup ServerProtocolSSLAPI + * Chain signing certificate and chained certificates to an SSL Context + */ +void chainCertificatesToSSLContext(SSL_CTX *sslContext, AnyP::PortCfg &port); + +/** + \ingroup ServerProtocolSSLAPI + * Configure a previously unconfigured SSL context object. + */ +void configureUnconfiguredSslContext(SSL_CTX *sslContext, Ssl::CertSignAlgorithm signAlgorithm,AnyP::PortCfg &port); + /** \ingroup ServerProtocolSSLAPI * Generates a certificate and a private key using provided properies and set it -- 2.47.2