From: Christos Tsantilas Date: Thu, 6 Sep 2012 13:12:26 +0000 (+0300) Subject: Bug fix: TLS/SSL Options does not apply to the dynamically generated certificates X-Git-Tag: sourceformat-review-1~9^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=86660d64fb95f949de9820e44233a273e97ebf91;p=thirdparty%2Fsquid.git Bug fix: TLS/SSL Options does not apply to the dynamically generated certificates The TLS/SSL options configured with http_port configuration parameter does not used to generate SSL_CTX context objects used to establish SSL connections. This is means that certificate based authentication, or SSL version selection and other SSL/TLS http_port options does not work for ssl-bumped connection. This patch fixes this problem. This is a Measurement Factory project --- diff --git a/src/anyp/PortCfg.cc b/src/anyp/PortCfg.cc index f128a788d1..8a90b72226 100644 --- a/src/anyp/PortCfg.cc +++ b/src/anyp/PortCfg.cc @@ -96,20 +96,6 @@ AnyP::PortCfg::clone() const #if USE_SSL void AnyP::PortCfg::configureSslServerContext() { - staticSslContext.reset( - sslCreateServerContext(cert, key, - version, cipher, options, sslflags, clientca, - cafile, capath, crlfile, dhfile, - sslContextSessionId)); - - if (!staticSslContext) { - char buf[128]; - fatalf("%s_port %s initialization error", protocol, s.ToURL(buf, sizeof(buf))); - } - - if (!sslBump) - return; - if (cert) Ssl::readCertChainAndPrivateKeyFromFiles(signingCert, signPkey, certsToChain, cert, key); @@ -128,6 +114,35 @@ void AnyP::PortCfg::configureSslServerContext() char buf[128]; fatalf("Unable to generate signing SSL certificate for untrusted sites for %s_port %s", protocol, s.ToURL(buf, sizeof(buf))); } + + if (crlfile) + clientVerifyCrls.reset(Ssl::loadCrl(crlfile, sslContextFlags)); + + if (clientca) { + clientCA.reset(SSL_load_client_CA_file(clientca)); + if (clientCA.get() == NULL) { + fatalf("Unable to read client CAs! from %s", clientca); + } + } + + contextMethod = Ssl::contextMethod(version); + if (!contextMethod) + fatalf("Unable to compute context method to use"); + + if (dhfile) + dhParams.reset(Ssl::readDHParams(dhfile)); + + if (sslflags) + sslContextFlags = Ssl::parse_flags(sslflags); + + sslOptions = Ssl::parse_options(options); + + staticSslContext.reset(sslCreateServerContext(*this)); + + if (!staticSslContext) { + char buf[128]; + fatalf("%s_port %s initialization error", protocol, s.ToURL(buf, sizeof(buf))); + } } #endif diff --git a/src/anyp/PortCfg.h b/src/anyp/PortCfg.h index 032e1dc54c..f94a816e87 100644 --- a/src/anyp/PortCfg.h +++ b/src/anyp/PortCfg.h @@ -76,6 +76,13 @@ struct PortCfg { Ssl::X509_STACK_Pointer certsToChain; ///< x509 certificates to send with the generated cert Ssl::X509_Pointer untrustedSigningCert; ///< x509 certificate for signing untrusted generated certificates Ssl::EVP_PKEY_Pointer untrustedSignPkey; ///< private key for signing untrusted generated certificates + + Ssl::X509_CRL_STACK_Pointer clientVerifyCrls; ///< additional CRL lists to use when verifying the client certificate + Ssl::X509_NAME_STACK_Pointer clientCA; ///< CA certificates to use when verifying client certificates + Ssl::DH_Pointer dhParams; ///< DH parameters for temporary/ephemeral DH key exchanges + Ssl::ContextMethod contextMethod; ///< The context method (SSL_METHOD) to use when creating certificates + long sslContextFlags; ///< flags modifying the use of SSL + long sslOptions; ///< SSL engine options #endif CBDATA_CLASS2(PortCfg); // namespaced diff --git a/src/client_side.cc b/src/client_side.cc index f3a68c26de..7fa712b1c6 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -3700,7 +3700,7 @@ ConnStateData::sslCrtdHandleReply(const char * reply) debugs(33, 5, HERE << "Certificate for " << sslConnectHostOrIp << " cannot be generated. ssl_crtd response: " << reply_message.getBody()); } else { debugs(33, 5, HERE << "Certificate for " << sslConnectHostOrIp << " was successfully recieved from ssl_crtd"); - SSL_CTX *ctx = Ssl::generateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str()); + SSL_CTX *ctx = Ssl::generateSslContextUsingPkeyAndCertFromMemory(reply_message.getBody().c_str(), *port); getSslContextDone(ctx, true); return; } @@ -3844,7 +3844,7 @@ ConnStateData::getSslContextStart() #endif // USE_SSL_CRTD debugs(33, 5, HERE << "Generating SSL certificate for " << certProperties.commonName); - dynCtx = Ssl::generateSslContext(certProperties); + dynCtx = Ssl::generateSslContext(certProperties, *port); getSslContextDone(dynCtx, true); return; } diff --git a/src/ssl/gadgets.h b/src/ssl/gadgets.h index fd6ce209c7..4df8bbacef 100644 --- a/src/ssl/gadgets.h +++ b/src/ssl/gadgets.h @@ -26,6 +26,12 @@ namespace Ssl because they are used by ssl_crtd. */ +#if OPENSSL_VERSION_NUMBER < 0x00909000L +typedef SSL_METHOD * ContextMethod; +#else +typedef const SSL_METHOD * ContextMethod; +#endif + /** \ingroup SslCrtdSslAPI * Add SSL locking (a.k.a. reference counting) to TidyPointer @@ -55,6 +61,14 @@ public: function(a); \ } +// Macro to be used to define the C++ wrapper function of a sk_*_pop_free +// openssl family functions. The C++ function suffixed with the _free_wrapper +// extension +#define sk_free_wrapper(sk_object, argument, freefunction) \ + extern "C++" inline void sk_object ## _free_wrapper(argument a) { \ + sk_object ## _pop_free(a, freefunction); \ + } + /** \ingroup SslCrtdSslAPI * TidyPointer typedefs for common SSL objects @@ -62,8 +76,8 @@ public: CtoCpp1(X509_free, X509 *) typedef LockingPointer X509_Pointer; -CtoCpp1(sk_X509_free, STACK_OF(X509) *) -typedef TidyPointer X509_STACK_Pointer; +sk_free_wrapper(sk_X509, STACK_OF(X509) *, X509_free) +typedef TidyPointer X509_STACK_Pointer; CtoCpp1(EVP_PKEY_free, EVP_PKEY *) typedef LockingPointer EVP_PKEY_Pointer; @@ -95,6 +109,15 @@ typedef TidyPointer SSL_CTX_Pointer; CtoCpp1(SSL_free, SSL *) typedef TidyPointer SSL_Pointer; +CtoCpp1(DH_free, DH *); +typedef TidyPointer DH_Pointer; + +sk_free_wrapper(sk_X509_CRL, STACK_OF(X509_CRL) *, X509_CRL_free) +typedef TidyPointer X509_CRL_STACK_Pointer; + +sk_free_wrapper(sk_X509_NAME, STACK_OF(X509_NAME) *, X509_NAME_free) +typedef TidyPointer X509_NAME_STACK_Pointer; + /** \ingroup SslCrtdSslAPI * Create 1024 bits rsa key. diff --git a/src/ssl/support.cc b/src/ssl/support.cc index bafb75ed70..b913aed133 100644 --- a/src/ssl/support.cc +++ b/src/ssl/support.cc @@ -41,6 +41,7 @@ #if USE_SSL #include "acl/FilledChecklist.h" +#include "anyp/PortCfg.h" #include "fde.h" #include "globals.h" #include "protos.h" @@ -451,8 +452,8 @@ ssl_options[] = { }; /// \ingroup ServerProtocolSSLInternal -static long -ssl_parse_options(const char *options) +long +Ssl::parse_options(const char *options) { long op = 0; char *tmp; @@ -545,8 +546,8 @@ no_options: #define SSL_FLAG_VERIFY_CRL_ALL (1<<6) /// \ingroup ServerProtocolSSLInternal -static long -ssl_parse_flags(const char *flags) +long +Ssl::parse_flags(const char *flags) { long fl = 0; char *tmp; @@ -705,99 +706,71 @@ ssl_load_crl(SSL_CTX *sslContext, const char *CRLfile) return count; } -SSL_CTX * -sslCreateServerContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *clientCA, const char *CAfile, const char *CApath, const char *CRLfile, const char *dhfile, const char *context) +STACK_OF(X509_CRL) * +Ssl::loadCrl(const char *CRLFile, long &flags) { - int ssl_error; -#if OPENSSL_VERSION_NUMBER < 0x00909000L - SSL_METHOD *method; -#else - const SSL_METHOD *method; -#endif - SSL_CTX *sslContext; - long fl = ssl_parse_flags(flags); - - ssl_initialize(); - - if (!keyfile) - keyfile = certfile; - - if (!certfile) - certfile = keyfile; - - if (!CAfile) - CAfile = clientCA; - - if (!certfile) { - debugs(83, DBG_CRITICAL, "ERROR: No certificate file"); + X509_CRL *crl; + BIO *in = BIO_new_file(CRLFile, "r"); + if (!in) { + debugs(83, 2, "WARNING: Failed to open CRL file '" << CRLFile << "'"); return NULL; } - switch (version) { - - case 2: -#ifndef OPENSSL_NO_SSL2 - debugs(83, 5, "Using SSLv2."); - method = SSLv2_server_method(); -#else - debugs(83, DBG_IMPORTANT, "SSLv2 is not available in this Proxy."); + STACK_OF(X509_CRL) *CRLs = sk_X509_CRL_new_null(); + if (!CRLs) { + debugs(83, 2, "WARNING: Failed to allocate X509_CRL stack to load file '" << CRLFile << "'"); return NULL; -#endif - break; - - case 3: - debugs(83, 5, "Using SSLv3."); - method = SSLv3_server_method(); - break; + } - case 4: - debugs(83, 5, "Using TLSv1."); - method = TLSv1_server_method(); - break; + int count = 0; + while ((crl = PEM_read_bio_X509_CRL(in,NULL,NULL,NULL))) { + if (!sk_X509_CRL_push(CRLs, crl)) + debugs(83, 2, "WARNING: Failed to add CRL from file '" << CRLFile << "'"); + else + ++count; + } + BIO_free(in); - case 5: -#if OPENSSL_VERSION_NUMBER >= 0x10001000L // NP: not sure exactly which sub-version yet. - debugs(83, 5, "Using TLSv1.1."); - method = TLSv1_1_server_method(); -#else - debugs(83, DBG_IMPORTANT, "TLSv1.1 is not available in this Proxy."); - return NULL; -#endif - break; + if (count) + flags |= SSL_FLAG_VERIFY_CRL; - case 6: -#if OPENSSL_VERSION_NUMBER >= 0x10001000L // NP: not sure exactly which sub-version yet. - debugs(83, 5, "Using TLSv1.2"); - method = TLSv1_2_server_method(); -#else - debugs(83, DBG_IMPORTANT, "TLSv1.2 is not available in this Proxy."); - return NULL; -#endif - break; + return CRLs; +} - case 1: +DH * +Ssl::readDHParams(const char *dhfile) +{ + FILE *in = fopen(dhfile, "r"); + DH *dh = NULL; + int codes; - default: - debugs(83, 5, "Using SSLv2/SSLv3."); - method = SSLv23_server_method(); - break; + if (in) { + dh = PEM_read_DHparams(in, NULL, NULL, NULL); + fclose(in); } - sslContext = SSL_CTX_new(method); - - if (sslContext == NULL) { - ssl_error = ERR_get_error(); - debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate SSL context: " << ERR_error_string(ssl_error, NULL)); - return NULL; + if (!dh) + debugs(83, DBG_IMPORTANT, "WARNING: Failed to read DH parameters '" << dhfile << "'"); + else if (dh && DH_check(dh, &codes) == 0) { + if (codes) { + debugs(83, DBG_IMPORTANT, "WARNING: Failed to verify DH parameters '" << dhfile << "' (" << std::hex << codes << ")"); + DH_free(dh); + dh = NULL; + } } + return dh; +} - SSL_CTX_set_options(sslContext, ssl_parse_options(options)); +static bool +configureSslContext(SSL_CTX *sslContext, AnyP::PortCfg &port) +{ + int ssl_error; + SSL_CTX_set_options(sslContext, port.sslOptions); - if (context && *context) { - SSL_CTX_set_session_id_context(sslContext, (const unsigned char *)context, strlen(context)); - } + if (port.sslContextSessionId) + SSL_CTX_set_session_id_context(sslContext, (const unsigned char *)port.sslContextSessionId, strlen(port.sslContextSessionId)); - if (fl & SSL_FLAG_NO_SESSION_REUSE) { + if (port.sslContextFlags & SSL_FLAG_NO_SESSION_REUSE) { SSL_CTX_set_session_cache_mode(sslContext, SSL_SESS_CACHE_OFF); } @@ -807,77 +780,38 @@ sslCreateServerContext(const char *certfile, const char *keyfile, int version, c SSL_CTX_set_quiet_shutdown(sslContext, 1); } - if (cipher) { - debugs(83, 5, "Using chiper suite " << cipher << "."); + if (port.cipher) { + debugs(83, 5, "Using chiper suite " << port.cipher << "."); - if (!SSL_CTX_set_cipher_list(sslContext, cipher)) { + if (!SSL_CTX_set_cipher_list(sslContext, port.cipher)) { ssl_error = ERR_get_error(); - debugs(83, DBG_CRITICAL, "ERROR: Failed to set SSL cipher suite '" << cipher << "': " << ERR_error_string(ssl_error, NULL)); - SSL_CTX_free(sslContext); - return NULL; + debugs(83, DBG_CRITICAL, "ERROR: Failed to set SSL cipher suite '" << port.cipher << "': " << ERR_error_string(ssl_error, NULL)); + return false; } } - debugs(83, DBG_IMPORTANT, "Using certificate in " << certfile); - - if (!SSL_CTX_use_certificate_chain_file(sslContext, certfile)) { - ssl_error = ERR_get_error(); - debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL certificate '" << certfile << "': " << ERR_error_string(ssl_error, NULL)); - SSL_CTX_free(sslContext); - return NULL; - } - - debugs(83, DBG_IMPORTANT, "Using private key in " << keyfile); - ssl_ask_password(sslContext, keyfile); - - if (!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)) { - ssl_error = ERR_get_error(); - debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL private key '" << keyfile << "': " << ERR_error_string(ssl_error, NULL)); - SSL_CTX_free(sslContext); - return NULL; - } - - debugs(83, 5, "Comparing private and public SSL keys."); - - if (!SSL_CTX_check_private_key(sslContext)) { - ssl_error = ERR_get_error(); - debugs(83, DBG_CRITICAL, "ERROR: SSL private key '" << certfile << "' does not match public key '" << - keyfile << "': " << ERR_error_string(ssl_error, NULL)); - SSL_CTX_free(sslContext); - return NULL; - } - debugs(83, 9, "Setting RSA key generation callback."); SSL_CTX_set_tmp_rsa_callback(sslContext, ssl_temp_rsa_cb); debugs(83, 9, "Setting CA certificate locations."); - if ((CAfile || CApath) && !SSL_CTX_load_verify_locations(sslContext, CAfile, CApath)) { + const char *cafile = port.cafile ? port.cafile : port.clientca; + if ((cafile || port.capath) && !SSL_CTX_load_verify_locations(sslContext, cafile, port.capath)) { ssl_error = ERR_get_error(); debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting CA certificate locations: " << ERR_error_string(ssl_error, NULL)); } - if (!(fl & SSL_FLAG_NO_DEFAULT_CA) && + if (!(port.sslContextFlags & SSL_FLAG_NO_DEFAULT_CA) && !SSL_CTX_set_default_verify_paths(sslContext)) { ssl_error = ERR_get_error(); debugs(83, DBG_IMPORTANT, "WARNING: Ignoring error setting default CA certificate location: " << ERR_error_string(ssl_error, NULL)); } - if (clientCA) { - STACK_OF(X509_NAME) *cert_names; - debugs(83, 9, "Set client certifying authority list."); - cert_names = SSL_load_client_CA_file(clientCA); - - if (cert_names == NULL) { - debugs(83, DBG_IMPORTANT, "ERROR: loading the client CA certificates from '" << clientCA << "\': " << ERR_error_string(ERR_get_error(),NULL)); - SSL_CTX_free(sslContext); - return NULL; - } - + if (port.clientCA.get()) { ERR_clear_error(); - SSL_CTX_set_client_CA_list(sslContext, cert_names); + SSL_CTX_set_client_CA_list(sslContext, port.clientCA.get()); - if (fl & SSL_FLAG_DELAYED_AUTH) { + if (port.sslContextFlags & SSL_FLAG_DELAYED_AUTH) { debugs(83, 9, "Not requesting client certificates until acl processing requires one"); SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL); } else { @@ -885,17 +819,20 @@ sslCreateServerContext(const char *certfile, const char *keyfile, int version, c SSL_CTX_set_verify(sslContext, SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT, ssl_verify_cb); } - if (CRLfile) { - ssl_load_crl(sslContext, CRLfile); - fl |= SSL_FLAG_VERIFY_CRL; + if (port.clientVerifyCrls.get()) { + X509_STORE *st = SSL_CTX_get_cert_store(sslContext); + for (int i = 0; i < sk_X509_CRL_num(port.clientVerifyCrls.get()); ++i) { + X509_CRL *crl = sk_X509_CRL_value(port.clientVerifyCrls.get(), i); + if (!X509_STORE_add_crl(st, crl)) + debugs(83, 2, "WARNING: Failed to add CRL"); + } } #if X509_V_FLAG_CRL_CHECK - if (fl & SSL_FLAG_VERIFY_CRL_ALL) + if (port.sslContextFlags & SSL_FLAG_VERIFY_CRL_ALL) X509_STORE_set_flags(SSL_CTX_get_cert_store(sslContext), X509_V_FLAG_CRL_CHECK|X509_V_FLAG_CRL_CHECK_ALL); - else if (fl & SSL_FLAG_VERIFY_CRL) + else if (port.sslContextFlags & SSL_FLAG_VERIFY_CRL) X509_STORE_set_flags(SSL_CTX_get_cert_store(sslContext), X509_V_FLAG_CRL_CHECK); - #endif } else { @@ -903,32 +840,93 @@ sslCreateServerContext(const char *certfile, const char *keyfile, int version, c SSL_CTX_set_verify(sslContext, SSL_VERIFY_NONE, NULL); } - if (dhfile) { - FILE *in = fopen(dhfile, "r"); - DH *dh = NULL; - int codes; + if (port.dhParams.get()) { + SSL_CTX_set_tmp_dh(sslContext, port.dhParams.get()); + } - if (in) { - dh = PEM_read_DHparams(in, NULL, NULL, NULL); - fclose(in); + if (port.sslContextFlags & SSL_FLAG_DONT_VERIFY_DOMAIN) + SSL_CTX_set_ex_data(sslContext, ssl_ctx_ex_index_dont_verify_domain, (void *) -1); + + return true; +} + +SSL_CTX * +sslCreateServerContext(AnyP::PortCfg &port) +{ + int ssl_error; + SSL_CTX *sslContext; + const char *keyfile, *certfile; + certfile = port.cert; + keyfile = port.key; + + ssl_initialize(); + + if (!keyfile) + keyfile = certfile; + + if (!certfile) + certfile = keyfile; + + sslContext = SSL_CTX_new(port.contextMethod); + + if (sslContext == NULL) { + ssl_error = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Failed to allocate SSL context: " << ERR_error_string(ssl_error, NULL)); + return NULL; + } + + if (!SSL_CTX_use_certificate(sslContext, port.signingCert.get())) { + ssl_error = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL certificate '" << certfile << "': " << ERR_error_string(ssl_error, NULL)); + SSL_CTX_free(sslContext); + return NULL; + } + + if (!SSL_CTX_use_PrivateKey(sslContext, port.signPkey.get())) { + ssl_error = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL private key '" << keyfile << "': " << ERR_error_string(ssl_error, NULL)); + SSL_CTX_free(sslContext); + return NULL; + } + + Ssl::addChainToSslContext(sslContext, port.certsToChain.get()); + + /* Alternate code; + debugs(83, DBG_IMPORTANT, "Using certificate in " << certfile); + + if (!SSL_CTX_use_certificate_chain_file(sslContext, certfile)) { + ssl_error = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL certificate '" << certfile << "': " << ERR_error_string(ssl_error, NULL)); + SSL_CTX_free(sslContext); + return NULL; } - if (!dh) - debugs(83, DBG_IMPORTANT, "WARNING: Failed to read DH parameters '" << dhfile << "'"); - else if (dh && DH_check(dh, &codes) == 0) { - if (codes) { - debugs(83, DBG_IMPORTANT, "WARNING: Failed to verify DH parameters '" << dhfile << "' (" << std::hex << codes << ")"); - DH_free(dh); - dh = NULL; - } + debugs(83, DBG_IMPORTANT, "Using private key in " << keyfile); + ssl_ask_password(sslContext, keyfile); + + if (!SSL_CTX_use_PrivateKey_file(sslContext, keyfile, SSL_FILETYPE_PEM)) { + ssl_error = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire SSL private key '" << keyfile << "': " << ERR_error_string(ssl_error, NULL)); + SSL_CTX_free(sslContext); + return NULL; } - if (dh) - SSL_CTX_set_tmp_dh(sslContext, dh); - } + debugs(83, 5, "Comparing private and public SSL keys."); - if (fl & SSL_FLAG_DONT_VERIFY_DOMAIN) - SSL_CTX_set_ex_data(sslContext, ssl_ctx_ex_index_dont_verify_domain, (void *) -1); + if (!SSL_CTX_check_private_key(sslContext)) { + ssl_error = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: SSL private key '" << certfile << "' does not match public key '" << + keyfile << "': " << ERR_error_string(ssl_error, NULL)); + SSL_CTX_free(sslContext); + return NULL; + } + */ + + if (!configureSslContext(sslContext, port)) { + debugs(83, DBG_CRITICAL, "ERROR: Configuring static SSL context"); + SSL_CTX_free(sslContext); + return NULL; + } return sslContext; } @@ -943,7 +941,7 @@ sslCreateClientContext(const char *certfile, const char *keyfile, int version, c const SSL_METHOD *method; #endif SSL_CTX *sslContext; - long fl = ssl_parse_flags(flags); + long fl = Ssl::parse_flags(flags); ssl_initialize(); @@ -1011,7 +1009,7 @@ sslCreateClientContext(const char *certfile, const char *keyfile, int version, c ERR_error_string(ssl_error, NULL)); } - SSL_CTX_set_options(sslContext, ssl_parse_options(options)); + SSL_CTX_set_options(sslContext, Ssl::parse_options(options)); if (cipher) { debugs(83, 5, "Using chiper suite " << cipher << "."); @@ -1299,21 +1297,84 @@ sslGetUserCertificateChainPEM(SSL *ssl) return str; } +Ssl::ContextMethod +Ssl::contextMethod(int version) +{ + Ssl::ContextMethod method; + + switch (version) { + + case 2: +#ifndef OPENSSL_NO_SSL2 + debugs(83, 5, "Using SSLv2."); + method = SSLv2_server_method(); +#else + debugs(83, DBG_IMPORTANT, "SSLv2 is not available in this Proxy."); + return NULL; +#endif + break; + + case 3: + debugs(83, 5, "Using SSLv3."); + method = SSLv3_server_method(); + break; + + case 4: + debugs(83, 5, "Using TLSv1."); + method = TLSv1_server_method(); + break; + + case 5: +#if OPENSSL_VERSION_NUMBER >= 0x10001000L // NP: not sure exactly which sub-version yet. + debugs(83, 5, "Using TLSv1.1."); + method = TLSv1_1_server_method(); +#else + debugs(83, DBG_IMPORTANT, "TLSv1.1 is not available in this Proxy."); + return NULL; +#endif + break; + + case 6: +#if OPENSSL_VERSION_NUMBER >= 0x10001000L // NP: not sure exactly which sub-version yet. + debugs(83, 5, "Using TLSv1.2"); + method = TLSv1_2_server_method(); +#else + debugs(83, DBG_IMPORTANT, "TLSv1.2 is not available in this Proxy."); + return NULL; +#endif + break; + + case 1: + + default: + debugs(83, 5, "Using SSLv2/SSLv3."); + method = SSLv23_server_method(); + break; + } + return method; +} + /// \ingroup ServerProtocolSSLInternal /// Create SSL context and apply ssl certificate and private key to it. -static SSL_CTX * createSSLContext(Ssl::X509_Pointer & x509, Ssl::EVP_PKEY_Pointer & pkey) +static SSL_CTX * +createSSLContext(Ssl::X509_Pointer & x509, Ssl::EVP_PKEY_Pointer & pkey, AnyP::PortCfg &port) { - Ssl::SSL_CTX_Pointer sslContext(SSL_CTX_new(SSLv23_server_method())); + Ssl::SSL_CTX_Pointer sslContext(SSL_CTX_new(port.contextMethod)); 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(); } -SSL_CTX * Ssl::generateSslContextUsingPkeyAndCertFromMemory(const char * data) +SSL_CTX * +Ssl::generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port) { Ssl::X509_Pointer cert; Ssl::EVP_PKEY_Pointer pkey; @@ -1323,10 +1384,11 @@ SSL_CTX * Ssl::generateSslContextUsingPkeyAndCertFromMemory(const char * data) if (!cert || !pkey) return NULL; - return createSSLContext(cert, pkey); + return createSSLContext(cert, pkey, port); } -SSL_CTX * Ssl::generateSslContext(CertificateProperties const &properties) +SSL_CTX * +Ssl::generateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port) { Ssl::X509_Pointer cert; Ssl::EVP_PKEY_Pointer pkey; @@ -1339,7 +1401,7 @@ SSL_CTX * Ssl::generateSslContext(CertificateProperties const &properties) if (!pkey) return NULL; - return createSSLContext(cert, pkey); + return createSSLContext(cert, pkey, port); } bool Ssl::verifySslCertificate(SSL_CTX * sslContext, CertificateProperties const &properties) @@ -1432,6 +1494,12 @@ void Ssl::readCertChainAndPrivateKeyFromFiles(X509_Pointer & cert, EVP_PKEY_Poin { if (keyFilename == NULL) keyFilename = certFilename; + + if (certFilename == NULL) + certFilename = keyFilename; + + debugs(83, DBG_IMPORTANT, "Using certificate in " << certFilename); + if (!chain) chain.reset(sk_X509_new_null()); if (!chain) diff --git a/src/ssl/support.h b/src/ssl/support.h index 3068b03aba..4a49b9574f 100644 --- a/src/ssl/support.h +++ b/src/ssl/support.h @@ -64,6 +64,11 @@ #define SQUID_SSL_ERROR_MIN SQUID_X509_V_ERR_CERT_CHANGE #define SQUID_SSL_ERROR_MAX INT_MAX +namespace AnyP +{ +class PortCfg; +}; + namespace Ssl { /// Squid defined error code (<0), an error code returned by SSL X509 api, or SSL_ERROR_NONE @@ -74,7 +79,7 @@ typedef CbDataList Errors; } //namespace Ssl /// \ingroup ServerProtocolSSLAPI -SSL_CTX *sslCreateServerContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *clientCA, const char *CAfile, const char *CApath, const char *CRLfile, const char *dhpath, const char *context); +SSL_CTX *sslCreateServerContext(AnyP::PortCfg &port); /// \ingroup ServerProtocolSSLAPI SSL_CTX *sslCreateClientContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *CAfile, const char *CApath, const char *CRLfile); @@ -129,6 +134,36 @@ inline const char *bumpMode(int bm) return (0 <= bm && bm < Ssl::bumpEnd) ? Ssl::BumpModeStr[bm] : NULL; } +/** + \ingroup ServerProtocolSSLAPI + * Parses the SSL flags. + */ +long parse_flags(const char *flags); + +/** + \ingroup ServerProtocolSSLAPI + * Parses the SSL options. + */ +long parse_options(const char *options); + +/** + \ingroup ServerProtocolSSLAPI + * Load a CRLs list stored in a file + */ +STACK_OF(X509_CRL) *loadCrl(const char *CRLFile, long &flags); + +/** + \ingroup ServerProtocolSSLAPI + * Load DH params from file + */ +DH *readDHParams(const char *dhfile); + +/** + \ingroup ServerProtocolSSLAPI + * Compute the Ssl::ContextMethod (SSL_METHOD) from SSL version + */ +ContextMethod contextMethod(int version); + /** \ingroup ServerProtocolSSLAPI * Generate a certificate to be used as untrusted signing certificate, based on a trusted CA @@ -139,7 +174,7 @@ bool generateUntrustedCert(X509_Pointer & untrustedCert, EVP_PKEY_Pointer & untr \ingroup ServerProtocolSSLAPI * Decide on the kind of certificate and generate a CA- or self-signed one */ -SSL_CTX * generateSslContext(CertificateProperties const &properties); +SSL_CTX * generateSslContext(CertificateProperties const &properties, AnyP::PortCfg &port); /** \ingroup ServerProtocolSSLAPI @@ -155,7 +190,7 @@ bool verifySslCertificate(SSL_CTX * sslContext, CertificateProperties const &pr * Read private key and certificate from memory and generate SSL context * using their. */ -SSL_CTX * generateSslContextUsingPkeyAndCertFromMemory(const char * data); +SSL_CTX * generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &port); /** \ingroup ServerProtocolSSLAPI diff --git a/src/tests/stub_libsslsquid.cc b/src/tests/stub_libsslsquid.cc index cb4c0c69ce..be72326115 100644 --- a/src/tests/stub_libsslsquid.cc +++ b/src/tests/stub_libsslsquid.cc @@ -42,7 +42,7 @@ Ssl::ErrorDetail::ErrorDetail(ErrorDetail const &) STUB const String & Ssl::ErrorDetail::toString() const STUB_RETSTATREF(String) #include "ssl/support.h" -SSL_CTX *sslCreateServerContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *clientCA, const char *CAfile, const char *CApath, const char *CRLfile, const char *dhpath, const char *context) STUB_RETVAL(NULL) +SSL_CTX *sslCreateServerContext(AnyP::PortCfg &) STUB_RETVAL(NULL) SSL_CTX *sslCreateClientContext(const char *certfile, const char *keyfile, int version, const char *cipher, const char *options, const char *flags, const char *CAfile, const char *CApath, const char *CRLfile) STUB_RETVAL(NULL) int ssl_read_method(int, char *, int) STUB_RETVAL(0) int ssl_write_method(int, const char *, int) STUB_RETVAL(0) @@ -53,8 +53,8 @@ const char *sslGetUserEmail(SSL *ssl) STUB_RETVAL(NULL) // SSLGETATTRIBUTE sslGetCAAttribute; const char *sslGetUserCertificatePEM(SSL *ssl) STUB_RETVAL(NULL) const char *sslGetUserCertificateChainPEM(SSL *ssl) STUB_RETVAL(NULL) -SSL_CTX * Ssl::generateSslContext(CertificateProperties const &properties) STUB_RETVAL(NULL) -SSL_CTX * Ssl::generateSslContextUsingPkeyAndCertFromMemory(const char * data) STUB_RETVAL(NULL) +SSL_CTX * Ssl::generateSslContext(CertificateProperties const &properties, AnyP::PortCfg &) STUB_RETVAL(NULL) +SSL_CTX * Ssl::generateSslContextUsingPkeyAndCertFromMemory(const char * data, AnyP::PortCfg &) STUB_RETVAL(NULL) int Ssl::matchX509CommonNames(X509 *peer_cert, void *check_data, int (*check_func)(void *check_data, ASN1_STRING *cn_data)) STUB_RETVAL(0) int Ssl::asn1timeToString(ASN1_TIME *tm, char *buf, int len) STUB_RETVAL(0)