From: Amos Jeffries Date: Thu, 1 Feb 2018 09:51:54 +0000 (+1300) Subject: TLS: GnuTLS implementation for listening ports and client connections (#81) X-Git-Tag: M-staged-PR71~3 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=51e09c08a5e6c582e7d93af99a8f2cfcb14ea9e6;p=thirdparty%2Fsquid.git TLS: GnuTLS implementation for listening ports and client connections (#81) Move the http_port cert= and key= options logic to libsecurity and add GnuTLS implementation for PEM file loading. Also adds some extra debugging to clarify listening port initialization problems with the PEM files. Enable most of the http(s)_port listening socket logic to always build except where OpenSSL-specific dependency still exists. It may seem reasonable to leave it optionally excluded for minimal builds, however a minimal proxy that does not support HTTPS in any way is increasingly useless in the modern web so preference is given to building the generic TLS related code. This also simplifies the required testing to detect code portability issues. GnuTLS implementation is added for https_port configured with static cert=/key= parameters and the resulting TLS handshake behaviour. Squid built with GnuTLS can now act as useful parent proxies behind a SSL-Bump'ing frontend or for other clients which require a TLS explicit proxy. Also fixes the definitions for the CertPointer and PrivateKeyPointer. --- diff --git a/configure.ac b/configure.ac index bef2087da9..b45f33c763 100644 --- a/configure.ac +++ b/configure.ac @@ -1253,7 +1253,7 @@ if test "x$with_gnutls" != "xno"; then ## by testing for a 3.1.5+ function which we use AC_CHECK_LIB(gnutls,gnutls_certificate_verify_peers3,[LIBGNUTLS_LIBS="-lgnutls"]) ]) - AC_CHECK_HEADERS(gnutls/gnutls.h gnutls/x509.h) + AC_CHECK_HEADERS(gnutls/gnutls.h gnutls/x509.h gnutls/abstract.h) SQUID_STATE_ROLLBACK(squid_gnutls_state) #de-pollute LIBS diff --git a/src/cache_cf.cc b/src/cache_cf.cc index 319b81c8a6..5e17f04441 100644 --- a/src/cache_cf.cc +++ b/src/cache_cf.cc @@ -915,8 +915,8 @@ configDoConfigure(void) for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) { if (!s->secure.encryptTransport) continue; - debugs(3, DBG_IMPORTANT, "Initializing " << AnyP::UriScheme(s->transport.protocol) << "_port " << s->s << " TLS context"); - s->secure.createSigningContexts(*s); + debugs(3, DBG_IMPORTANT, "Initializing " << AnyP::UriScheme(s->transport.protocol) << "_port " << s->s << " TLS contexts"); + s->secure.initServerContexts(*s); } // prevent infinite fetch loops in the request parser diff --git a/src/cf.data.pre b/src/cf.data.pre index fdecc02e7b..4f8a218377 100644 --- a/src/cf.data.pre +++ b/src/cf.data.pre @@ -2223,12 +2223,33 @@ DOC_START TLS / SSL Options: - cert= Path to SSL certificate (PEM format). + tls-cert= Path to file containing an X.509 certificate (PEM format) + to be used in the TLS handshake ServerHello. - key= Path to SSL private key file (PEM format) - if not specified, the certificate file is - assumed to be a combined certificate and - key file. + If this certificate is constrained by KeyUsage TLS + feature it must allow HTTP server usage, along with + any additional restrictions imposed by your choice + of options= settings. + + When OpenSSL is used this file may also contain a + chain of intermediate CA certificates to send in the + TLS handshake. + + When GnuTLS is used this option (and any paired + tls-key= option) may be repeated to load multiple + certificates for different domains. + + Also, when generate-host-certificates=on is configured + the first tls-cert= option must be a CA certificate + capable of signing the automatically generated + certificates. + + tls-key= Path to a file containing private key file (PEM format) + for the previous tls-cert= option. + + If tls-key= is not specified tls-cert= is assumed to + reference a PEM file containing both the certificate + and private key. cipher= Colon separated list of supported ciphers. NOTE: some ciphers such as EDH ciphers depend on @@ -2372,18 +2393,19 @@ TYPE: PortCfg DEFAULT: none LOC: HttpPortList DOC_START - Usage: [ip:]port [mode] cert=certificate.pem [options] + Usage: [ip:]port [mode] tls-cert=certificate.pem [options] The socket address where Squid will listen for client requests made over TLS or SSL connections. Commonly referred to as HTTPS. This is most useful for situations where you are running squid in - accelerator mode and you want to do the TLS work at the accelerator level. + accelerator mode and you want to do the TLS work at the accelerator + level. You may specify multiple socket addresses on multiple lines, each with their own certificate and/or options. - The TLS cert= option is mandatory on HTTPS ports. + The tls-cert= option is mandatory on HTTPS ports. See http_port for a list of modes and options. DOC_END @@ -2794,12 +2816,14 @@ DOC_START disable Do not support https:// URLs. cert=/path/to/client/certificate - A client TLS certificate to use when connecting. + A client X.509 certificate to use when connecting. key=/path/to/client/private_key - The private TLS key corresponding to the cert= above. - If key= is not specified cert= is assumed to reference - a PEM file containing both the certificate and the key. + The private key corresponding to the cert= above. + + If key= is not specified cert= is assumed to + reference a PEM file containing both the certificate + and private key. cipher=... The list of valid TLS ciphers to use. @@ -3568,14 +3592,15 @@ DOC_START tls Encrypt connections to this peer with TLS. sslcert=/path/to/ssl/certificate - A client SSL certificate to use when connecting to + A client X.509 certificate to use when connecting to this peer. sslkey=/path/to/ssl/key - The private SSL key corresponding to sslcert above. - If 'sslkey' is not specified 'sslcert' is assumed to - reference a combined file containing both the - certificate and the key. + The private key corresponding to sslcert above. + + If sslkey= is not specified sslcert= is assumed to + reference a PEM file containing both the certificate + and private key. sslcipher=... The list of valid SSL ciphers to use when connecting to this peer. @@ -8974,14 +8999,16 @@ DOC_START These options are used for Secure ICAP (icaps://....) services only. tls-cert=/path/to/ssl/certificate - A client SSL certificate to use when connecting to - this icap server. + A client X.509 certificate to use when connecting to + this ICAP server. tls-key=/path/to/ssl/key - The private TLS/SSL key corresponding to sslcert above. - If 'tls-key' is not specified 'tls-cert' is assumed to - reference a combined PEM format file containing both the - certificate and the key. + The private key corresponding to the previous + tls-cert= option. + + If tls-key= is not specified tls-cert= is assumed to + reference a PEM file containing both the certificate + and private key. tls-cipher=... The list of valid TLS/SSL ciphers to use when connecting to this icap server. diff --git a/src/client_side.cc b/src/client_side.cc index dc77cf9926..5a1c799a95 100644 --- a/src/client_side.cc +++ b/src/client_side.cc @@ -171,9 +171,6 @@ private: static void clientListenerConnectionOpened(AnyP::PortCfgPointer &s, const Ipc::FdNoteId portTypeNote, const Subscription::Pointer &sub); static IOACB httpAccept; -#if USE_OPENSSL -static IOACB httpsAccept; -#endif static CTCB clientLifetimeTimeout; #if USE_IDENT static IDCB clientIdentDone; @@ -2531,7 +2528,6 @@ httpAccept(const CommAcceptCbParams ¶ms) AsyncJob::Start(srv); // usually async-calls readSomeData() } -#if USE_OPENSSL /// Create TLS connection structure and update fd_table static bool httpsCreate(const Comm::ConnectionPointer &conn, const Security::ContextPointer &ctx) @@ -2541,61 +2537,87 @@ httpsCreate(const Comm::ConnectionPointer &conn, const Security::ContextPointer return true; } + debugs(33, DBG_IMPORTANT, "ERROR: could not create TLS server context for " << conn); conn->close(); return false; } /** * - * \retval 1 on success - * \retval 0 when needs more data - * \retval -1 on error + * \retval true on success + * \retval false when needs more data + * \retval false when an error occurred (and closes the TCP connection) */ -static int -Squid_SSL_accept(ConnStateData *conn, PF *callback) +static bool +tlsAttemptHandshake(ConnStateData *conn, PF *callback) { + // TODO: maybe throw instead of just closing the TCP connection. + // see https://github.com/squid-cache/squid/pull/81#discussion_r153053278 int fd = conn->clientConnection->fd; - auto ssl = fd_table[fd].ssl.get(); - int ret; + auto session = fd_table[fd].ssl.get(); errno = 0; - if ((ret = SSL_accept(ssl)) <= 0) { - const int xerrno = errno; - const int ssl_error = SSL_get_error(ssl, ret); - switch (ssl_error) { +#if USE_OPENSSL + const auto ret = SSL_accept(session); + if (ret > 0) + return true; - case SSL_ERROR_WANT_READ: - Comm::SetSelect(fd, COMM_SELECT_READ, callback, (callback != NULL ? conn : NULL), 0); - return 0; + const int xerrno = errno; + const auto ssl_error = SSL_get_error(session, ret); - case SSL_ERROR_WANT_WRITE: - Comm::SetSelect(fd, COMM_SELECT_WRITE, callback, (callback != NULL ? conn : NULL), 0); - return 0; + switch (ssl_error) { - case SSL_ERROR_SYSCALL: - if (ret == 0) { - debugs(83, 2, "Error negotiating SSL connection on FD " << fd << ": Aborted by client: " << ssl_error); - } else { - debugs(83, (xerrno == ECONNRESET) ? 1 : 2, "Error negotiating SSL connection on FD " << fd << ": " << - (xerrno == 0 ? Security::ErrorString(ssl_error) : xstrerr(xerrno))); - } - return -1; + case SSL_ERROR_WANT_READ: + Comm::SetSelect(fd, COMM_SELECT_READ, callback, (callback ? conn : nullptr), 0); + return false; - case SSL_ERROR_ZERO_RETURN: - debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " << fd << ": Closed by client"); - return -1; + case SSL_ERROR_WANT_WRITE: + Comm::SetSelect(fd, COMM_SELECT_WRITE, callback, (callback ? conn : nullptr), 0); + return false; - default: - debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " << - fd << ": " << Security::ErrorString(ERR_get_error()) << - " (" << ssl_error << "/" << ret << ")"); - return -1; + case SSL_ERROR_SYSCALL: + if (ret == 0) { + debugs(83, 2, "Error negotiating SSL connection on FD " << fd << ": Aborted by client: " << ssl_error); + } else { + debugs(83, (xerrno == ECONNRESET) ? 1 : 2, "Error negotiating SSL connection on FD " << fd << ": " << + (xerrno == 0 ? Security::ErrorString(ssl_error) : xstrerr(xerrno))); } + break; + + case SSL_ERROR_ZERO_RETURN: + debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " << fd << ": Closed by client"); + break; + + default: + debugs(83, DBG_IMPORTANT, "Error negotiating SSL connection on FD " << + fd << ": " << Security::ErrorString(ssl_error) << + " (" << ssl_error << "/" << ret << ")"); + } + +#elif USE_GNUTLS + + const auto x = gnutls_handshake(session); + if (x == GNUTLS_E_SUCCESS) + return true; + + if (gnutls_error_is_fatal(x)) { + debugs(83, 2, "Error negotiating TLS on " << conn->clientConnection << ": Aborted by client: " << Security::ErrorString(x)); - /* NOTREACHED */ + } else if (x == GNUTLS_E_INTERRUPTED || x == GNUTLS_E_AGAIN) { + const auto ioAction = (gnutls_record_get_direction(session)==0 ? COMM_SELECT_READ : COMM_SELECT_WRITE); + Comm::SetSelect(fd, ioAction, callback, (callback ? conn : nullptr), 0); + return false; } - return 1; + +#else + // Performing TLS handshake should never be reachable without a TLS/SSL library. + (void)session; // avoid compiler and static analysis complaints + fatal("FATAL: HTTPS not supported by this Squid."); +#endif + + conn->clientConnection->close(); + return false; } /** negotiate an SSL connection */ @@ -2603,14 +2625,13 @@ static void clientNegotiateSSL(int fd, void *data) { ConnStateData *conn = (ConnStateData *)data; - int ret; - if ((ret = Squid_SSL_accept(conn, clientNegotiateSSL)) <= 0) { - if (ret < 0) // An error - conn->clientConnection->close(); + + if (!tlsAttemptHandshake(conn, clientNegotiateSSL)) return; - } Security::SessionPointer session(fd_table[fd].ssl); + +#if USE_OPENSSL if (Security::SessionIsResumed(session)) { debugs(83, 2, "Session " << SSL_get_session(session.get()) << " reused on FD " << fd << " (" << fd_table[fd].ipaddr << @@ -2655,10 +2676,14 @@ clientNegotiateSSL(int fd, void *data) " on FD " << fd << " (" << fd_table[fd].ipaddr << ":" << fd_table[fd].remote_port << ")"); } +#else + debugs(83, 2, "TLS session reuse not yet implemented."); +#endif // Connection established. Retrieve TLS connection parameters for logging. conn->clientConnection->tlsNegotiations()->retrieveNegotiatedInfo(session); +#if USE_OPENSSL X509 *client_cert = SSL_get_peer_certificate(session.get()); if (client_cert) { @@ -2670,8 +2695,11 @@ clientNegotiateSSL(int fd, void *data) X509_free(client_cert); } else { - debugs(83, 5, "FD " << fd << " has no certificate."); + debugs(83, 5, "FD " << fd << " has no client certificate."); } +#else + debugs(83, 2, "Client certificate requesting not yet implemented."); +#endif conn->readSomeData(); } @@ -2697,6 +2725,7 @@ httpsEstablish(ConnStateData *connState, const Security::ContextPointer &ctx) Comm::SetSelect(details->fd, COMM_SELECT_READ, clientNegotiateSSL, connState, 0); } +#if USE_OPENSSL /** * A callback function to use with the ACLFilledChecklist callback. */ @@ -2725,6 +2754,7 @@ httpsSslBumpAccessCheckDone(allow_t answer, void *data) if (!connState->fakeAConnectRequest("ssl-bump", connState->inBuf)) connState->clientConnection->close(); } +#endif /** handle a new HTTPS connection */ static void @@ -2758,6 +2788,7 @@ void ConnStateData::postHttpsAccept() { if (port->flags.tunnelSslBumping) { +#if USE_OPENSSL debugs(33, 5, "accept transparent connection: " << clientConnection); if (!Config.accessList.ssl_bump) { @@ -2789,12 +2820,16 @@ ConnStateData::postHttpsAccept() acl_checklist->al->request = request; HTTPMSGLOCK(acl_checklist->al->request); acl_checklist->nonBlockingCheck(httpsSslBumpAccessCheckDone, this); +#else + fatal("FATAL: SSL-Bump requires --with-openssl"); +#endif return; } else { httpsEstablish(this, port->secure.staticContext); } } +#if USE_OPENSSL void ConnStateData::sslCrtdHandleReplyWrapper(void *data, const Helper::Reply &reply) { @@ -2907,15 +2942,15 @@ void ConnStateData::buildSslCertGenerationParams(Ssl::CertificateProperties &cer assert(certProperties.signAlgorithm != Ssl::algSignEnd); if (certProperties.signAlgorithm == Ssl::algSignUntrusted) { - assert(port->secure.untrustedSigningCert); - certProperties.signWithX509.resetAndLock(port->secure.untrustedSigningCert.get()); - certProperties.signWithPkey.resetAndLock(port->secure.untrustedSignPkey.get()); + assert(port->secure.untrustedSigningCa.cert); + certProperties.signWithX509.resetAndLock(port->secure.untrustedSigningCa.cert.get()); + certProperties.signWithPkey.resetAndLock(port->secure.untrustedSigningCa.pkey.get()); } else { - assert(port->secure.signingCert.get()); - certProperties.signWithX509.resetAndLock(port->secure.signingCert.get()); + assert(port->secure.signingCa.cert.get()); + certProperties.signWithX509.resetAndLock(port->secure.signingCa.cert.get()); - if (port->secure.signPkey) - certProperties.signWithPkey.resetAndLock(port->secure.signPkey.get()); + if (port->secure.signingCa.pkey) + certProperties.signWithPkey.resetAndLock(port->secure.signingCa.pkey.get()); } signAlgorithm = certProperties.signAlgorithm; @@ -3254,7 +3289,7 @@ ConnStateData::startPeekAndSplice() } // will call httpsPeeked() with certificate and connection, eventually - Security::ContextPointer unConfiguredCTX(Ssl::createSSLContext(port->secure.signingCert, port->secure.signPkey, port->secure)); + Security::ContextPointer unConfiguredCTX(Ssl::createSSLContext(port->secure.signingCa.cert, port->secure.signingCa.pkey, port->secure)); fd_table[clientConnection->fd].dynamicTlsContext = unConfiguredCTX; if (!httpsCreate(clientConnection, unConfiguredCTX)) @@ -3269,12 +3304,11 @@ ConnStateData::startPeekAndSplice() bio->hold(true); // Here squid should have all of the client hello message so the - // Squid_SSL_accept should return 0; + // tlsAttemptHandshake() should return false; // This block exist only to force openSSL parse client hello and detect // ERR_SECURE_ACCEPT_FAIL error, which should be checked and splice if required. - int ret = 0; - if ((ret = Squid_SSL_accept(this, NULL)) < 0) { - debugs(83, 2, "SSL_accept failed."); + if (!tlsAttemptHandshake(this, nullptr)) { + debugs(83, 2, "TLS handshake failed."); HttpRequest::Pointer request(http ? http->request : nullptr); if (!clientTunnelOnError(this, context, request, HttpRequestMethod(), ERR_SECURE_ACCEPT_FAIL)) clientConnection->close(); @@ -3497,12 +3531,12 @@ clientHttpConnectionsOpen(void) Ssl::TheGlobalContextStorage.addLocalStorage(s->s, s->secure.dynamicCertMemCacheSize); } } +#endif if (s->secure.encryptTransport && !s->secure.staticContext) { debugs(1, DBG_CRITICAL, "ERROR: Ignoring " << scheme << "_port " << s->s << " due to TLS context initialization failure."); continue; } -#endif // Fill out a Comm::Connection which IPC will open as a listener for us // then pass back when active so we can start a TcpAcceptor subscription. @@ -3522,7 +3556,6 @@ clientHttpConnectionsOpen(void) ListeningStartedDialer(&clientListenerConnectionOpened, s, Ipc::fdnHttpSocket, sub)); Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpSocket, listenCall); -#if USE_OPENSSL } else if (s->transport.protocol == AnyP::PROTO_HTTPS) { // setup the subscriptions such that new connections accepted by listenConn are handled by HTTPS RefCount subCall = commCbCall(5, 5, "httpsAccept", CommAcceptCbPtrFun(httpsAccept, CommAcceptCbParams(NULL))); @@ -3532,7 +3565,6 @@ clientHttpConnectionsOpen(void) ListeningStartedDialer(&clientListenerConnectionOpened, s, Ipc::fdnHttpsSocket, sub)); Ipc::StartListening(SOCK_STREAM, IPPROTO_TCP, s->listenConn, Ipc::fdnHttpsSocket, listenCall); -#endif } HttpSockets[NHttpSockets] = -1; // set in clientListenerConnectionOpened diff --git a/src/client_side.h b/src/client_side.h index e36a0a3d12..d8a2ebc8b9 100644 --- a/src/client_side.h +++ b/src/client_side.h @@ -219,10 +219,10 @@ public: /// The caller assumes responsibility for connection closure detection. void stopPinnedConnectionMonitoring(); -#if USE_OPENSSL /// the second part of old httpsAccept, waiting for future HttpsServer home void postHttpsAccept(); +#if USE_OPENSSL /// Initializes and starts a peek-and-splice negotiation with the SSL client void startPeekAndSplice(); diff --git a/src/security/KeyData.cc b/src/security/KeyData.cc new file mode 100644 index 0000000000..e763ebef89 --- /dev/null +++ b/src/security/KeyData.cc @@ -0,0 +1,187 @@ +/* + * Copyright (C) 1996-2017 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 "anyp/PortCfg.h" +#include "fatal.h" +#include "security/KeyData.h" +#include "SquidConfig.h" +#include "ssl/bio.h" + +/** + * Read certificate from file. + * See also: Ssl::ReadX509Certificate function, gadgets.cc file + */ +bool +Security::KeyData::loadX509CertFromFile() +{ + debugs(83, DBG_IMPORTANT, "Using certificate in " << certFile); + +#if USE_OPENSSL + const char *certFilename = certFile.c_str(); + Ssl::BIO_Pointer bio(BIO_new(BIO_s_file())); + if (!bio || !BIO_read_filename(bio.get(), certFilename)) { + const auto x = ERR_get_error(); + debugs(83, DBG_IMPORTANT, "ERROR: unable to load certificate file '" << certFile << "': " << ErrorString(x)); + return false; + } + + if (X509 *certificate = PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr)) { + if (X509_check_issued(certificate, certificate) == X509_V_OK) + debugs(83, 5, "Certificate is self-signed, will not be chained"); + else + cert.resetWithoutLocking(certificate); + } + +#elif USE_GNUTLS + const char *certFilename = certFile.c_str(); + gnutls_datum_t data; + Security::ErrorCode x = gnutls_load_file(certFilename, &data); + if (x != GNUTLS_E_SUCCESS) { + debugs(83, DBG_IMPORTANT, "ERROR: unable to load certificate file '" << certFile << "': " << ErrorString(x)); + return false; + } + + gnutls_pcert_st pcrt; + x = gnutls_pcert_import_x509_raw(&pcrt, &data, GNUTLS_X509_FMT_PEM, 0); + if (x != GNUTLS_E_SUCCESS) { + debugs(83, DBG_IMPORTANT, "ERROR: unable to import certificate from '" << certFile << "': " << ErrorString(x)); + return false; + } + gnutls_free(data.data); + + gnutls_x509_crt_t certificate; + x = gnutls_pcert_export_x509(&pcrt, &certificate); + if (x != GNUTLS_E_SUCCESS) { + debugs(83, DBG_IMPORTANT, "ERROR: unable to X.509 convert certificate from '" << certFile << "': " << ErrorString(x)); + return false; + } + + if (certificate) { + cert = Security::CertPointer(certificate, [](gnutls_x509_crt_t p) { + debugs(83, 5, "gnutls_x509_crt_deinit cert=" << (void*)p); + gnutls_x509_crt_deinit(p); + }); + } else { + cert.reset(); // paranoid: ensure cert is unset + } + +#else + // do nothing. +#endif + + if (!cert) { + debugs(83, DBG_IMPORTANT, "ERROR: unable to load certificate from '" << certFile << "'"); + } + + return bool(cert); +} + +/** + * Read certificate from file. + * See also: Ssl::ReadX509Certificate function, gadgets.cc file + */ +void +Security::KeyData::loadX509ChainFromFile() +{ +#if USE_OPENSSL + // XXX: This BIO loads the public cert as first chain cert, + // so the code appending chains sends it twice in handshakes. + const char *certFilename = certFile.c_str(); + Ssl::BIO_Pointer bio(BIO_new(BIO_s_file())); + if (!bio || !BIO_read_filename(bio.get(), certFilename)) { + const auto x = ERR_get_error(); + debugs(83, DBG_IMPORTANT, "ERROR: unable to load chain file '" << certFile << "': " << ErrorString(x)); + return; + } + + if (X509_check_issued(cert.get(), cert.get()) == X509_V_OK) + debugs(83, 5, "Certificate is self-signed, will not be chained"); + else { + // and add to the chain any other certificate exist in the file + while (X509 *ca = PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr)) { + // XXX: self-signed check should be applied to all certs loaded. + // XXX: missing checks that the chained certs are actually part of a chain for validating cert. + chain.emplace_front(Security::CertPointer(ca)); + } + } + +#elif USE_GNUTLS + // XXX: implement chain loading + debugs(83, 2, "Loading certificate chain from PEM files not implemented in this Squid."); + +#else + // nothing to do. +#endif +} + +/** + * Read X.509 private key from file. + */ +bool +Security::KeyData::loadX509PrivateKeyFromFile() +{ + debugs(83, DBG_IMPORTANT, "Using key in " << privateKeyFile); + +#if USE_OPENSSL + const char *keyFilename = privateKeyFile.c_str(); + // XXX: Ssl::AskPasswordCb needs SSL_CTX_set_default_passwd_cb_userdata() + // so this may not fully work iff Config.Program.ssl_password is set. + pem_password_cb *cb = ::Config.Program.ssl_password ? &Ssl::AskPasswordCb : nullptr; + Ssl::ReadPrivateKeyFromFile(keyFilename, pkey, cb); + + if (pkey && !X509_check_private_key(cert.get(), pkey.get())) { + debugs(83, DBG_IMPORTANT, "WARNING: '" << privateKeyFile << "' X509_check_private_key() failed"); + pkey.reset(); + } + +#elif USE_GNUTLS + const char *keyFilename = privateKeyFile.c_str(); + gnutls_datum_t data; + if (gnutls_load_file(keyFilename, &data) == GNUTLS_E_SUCCESS) { + gnutls_privkey_t key; + (void)gnutls_privkey_init(&key); + Security::ErrorCode x = gnutls_privkey_import_x509_raw(key, &data, GNUTLS_X509_FMT_PEM, nullptr, 0); + if (x == GNUTLS_E_SUCCESS) { + gnutls_x509_privkey_t xkey; + gnutls_privkey_export_x509(key, &xkey); + gnutls_privkey_deinit(key); + pkey = Security::PrivateKeyPointer(xkey, [](gnutls_x509_privkey_t p) { + debugs(83, 5, "gnutls_x509_privkey_deinit pkey=" << (void*)p); + gnutls_x509_privkey_deinit(p); + }); + } + } + gnutls_free(data.data); + +#else + // nothing to do. +#endif + + return bool(pkey); +} + +void +Security::KeyData::loadFromFiles(const AnyP::PortCfg &port, const char *portType) +{ + char buf[128]; + if (!loadX509CertFromFile()) { + debugs(83, DBG_IMPORTANT, "WARNING: '" << portType << "_port " << port.s.toUrl(buf, sizeof(buf)) << "' missing certificate in '" << certFile << "'"); + return; + } + + // certificate chain in the PEM file is optional + loadX509ChainFromFile(); + + // pkey is mandatory, not having it makes cert and chain pointless. + if (!loadX509PrivateKeyFromFile()) { + debugs(83, DBG_IMPORTANT, "WARNING: '" << portType << "_port " << port.s.toUrl(buf, sizeof(buf)) << "' missing private key in '" << privateKeyFile << "'"); + cert.reset(); + chain.clear(); + } +} diff --git a/src/security/KeyData.h b/src/security/KeyData.h index 6707d30ce6..2a13bb613f 100644 --- a/src/security/KeyData.h +++ b/src/security/KeyData.h @@ -9,6 +9,7 @@ #ifndef SQUID_SRC_SECURITY_KEYDATA_H #define SQUID_SRC_SECURITY_KEYDATA_H +#include "anyp/forward.h" #include "sbuf/SBuf.h" #include "security/forward.h" @@ -18,9 +19,25 @@ namespace Security /// TLS certificate and private key details from squid.conf class KeyData { +public: + /// load the contents of certFile and privateKeyFile into memory cert, pkey and chain + void loadFromFiles(const AnyP::PortCfg &, const char *portType); + public: SBuf certFile; ///< path of file containing PEM format X.509 certificate SBuf privateKeyFile; ///< path of file containing private key in PEM format + + /// public X.509 certificate from certFile + Security::CertPointer cert; + /// private key from privateKeyFile + Security::PrivateKeyPointer pkey; + /// any certificates which must be chained from cert + Security::CertList chain; + +private: + bool loadX509CertFromFile(); + void loadX509ChainFromFile(); + bool loadX509PrivateKeyFromFile(); }; } // namespace Security diff --git a/src/security/Makefile.am b/src/security/Makefile.am index c41207757e..b56aa13e74 100644 --- a/src/security/Makefile.am +++ b/src/security/Makefile.am @@ -22,6 +22,7 @@ libsecurity_la_SOURCES= \ Handshake.cc \ Handshake.h \ forward.h \ + KeyData.cc \ KeyData.h \ LockingPointer.h \ NegotiationHistory.cc \ diff --git a/src/security/PeerOptions.h b/src/security/PeerOptions.h index 57b2a45c83..891d0fab96 100644 --- a/src/security/PeerOptions.h +++ b/src/security/PeerOptions.h @@ -66,6 +66,7 @@ private: void parseOptions(); ///< parsed value of sslOptions long parseFlags(); void loadCrlFile(); + void loadKeysFile(); public: SBuf sslOptions; ///< library-specific options string diff --git a/src/security/ServerOptions.cc b/src/security/ServerOptions.cc index c22a39f49b..46e5625851 100644 --- a/src/security/ServerOptions.cc +++ b/src/security/ServerOptions.cc @@ -44,11 +44,8 @@ Security::ServerOptions::operator =(const Security::ServerOptions &old) { staticContextSessionId = old.staticContextSessionId; generateHostCertificates = old.generateHostCertificates; - signingCert = old.signingCert; - signPkey = old.signPkey; - certsToChain = old.certsToChain; - untrustedSigningCert = old.untrustedSigningCert; - untrustedSignPkey = old.untrustedSignPkey; + signingCa = old.signingCa; + untrustedSigningCa = old.untrustedSigningCa; dynamicCertMemCacheSize = old.dynamicCertMemCacheSize; } return *this; @@ -189,6 +186,23 @@ Security::ServerOptions::createBlankContext() const return ctx; } +void +Security::ServerOptions::initServerContexts(AnyP::PortCfg &port) +{ + const char *portType = AnyP::ProtocolType_str[port.transport.protocol]; + for (auto &keyData : certs) { + keyData.loadFromFiles(port, portType); + } + + if (generateHostCertificates) { + createSigningContexts(port); + + } else if (!createStaticServerContext(port)) { + char buf[128]; + fatalf("%s_port %s initialization error", portType, port.s.toUrl(buf, sizeof(buf))); + } +} + bool Security::ServerOptions::createStaticServerContext(AnyP::PortCfg &port) { @@ -196,10 +210,61 @@ Security::ServerOptions::createStaticServerContext(AnyP::PortCfg &port) Security::ContextPointer t(createBlankContext()); if (t) { + #if USE_OPENSSL - if (!Ssl::InitServerContext(t, port)) + if (certs.size() > 1) { + // NOTE: calling SSL_CTX_use_certificate() repeatedly _replaces_ the previous cert details. + // so we cannot use it and support multiple server certificates with OpenSSL. + debugs(83, DBG_CRITICAL, "ERROR: OpenSSL does not support multiple server certificates. Ignoring addional cert= parameters."); + } + + const auto &keys = certs.front(); + + if (!SSL_CTX_use_certificate(t.get(), keys.cert.get())) { + const auto x = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire TLS certificate '" << keys.certFile << "': " << Security::ErrorString(x)); return false; + } + + if (!SSL_CTX_use_PrivateKey(t.get(), keys.pkey.get())) { + const auto x = ERR_get_error(); + debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire TLS private key '" << keys.privateKeyFile << "': " << Security::ErrorString(x)); + return false; + } + + for (auto cert : keys.chain) { + if (SSL_CTX_add_extra_chain_cert(t.get(), cert.get())) { + // increase the certificate lock + X509_up_ref(cert.get()); + } else { + const auto error = ERR_get_error(); + debugs(83, DBG_IMPORTANT, "WARNING: can not add certificate to SSL context chain: " << Security::ErrorString(error)); + } + } + +#elif USE_GNUTLS + for (auto &keys : certs) { + gnutls_x509_crt_t crt = keys.cert.get(); + gnutls_x509_privkey_t xkey = keys.pkey.get(); + const auto x = gnutls_certificate_set_x509_key(t.get(), &crt, 1, xkey); + if (x != GNUTLS_E_SUCCESS) { + SBuf whichFile = keys.certFile; + if (keys.certFile != keys.privateKeyFile) { + whichFile.appendf(" and "); + whichFile.append(keys.privateKeyFile); + } + debugs(83, DBG_CRITICAL, "ERROR: Failed to initialize server context with keys from " << whichFile << ": " << Security::ErrorString(x)); + return false; + } + // XXX: add cert chain to the context + } #endif + + if (!updateContextConfig(t)) { + debugs(83, DBG_CRITICAL, "ERROR: Configuring static TLS context"); + return false; + } + if (!loadClientCaFile()) return false; } @@ -209,39 +274,40 @@ Security::ServerOptions::createStaticServerContext(AnyP::PortCfg &port) } void -Security::ServerOptions::createSigningContexts(AnyP::PortCfg &port) +Security::ServerOptions::createSigningContexts(const AnyP::PortCfg &port) { - const char *portType = AnyP::ProtocolType_str[port.transport.protocol]; - if (!certs.empty()) { -#if USE_OPENSSL - Security::KeyData &keys = certs.front(); - Ssl::readCertChainAndPrivateKeyFromFiles(signingCert, signPkey, certsToChain, keys.certFile.c_str(), keys.privateKeyFile.c_str()); -#else - char buf[128]; - fatalf("Directive '%s_port %s' requires --with-openssl.", portType, port.s.toUrl(buf, sizeof(buf))); -#endif - } + // For signing we do not have a pre-initialized context object. Instead + // contexts are generated as needed. This method initializes the cert + // and key pointers used to sign those contexts later. - if (!signingCert) { + signingCa = certs.front(); + + const char *portType = AnyP::ProtocolType_str[port.transport.protocol]; + if (!signingCa.cert) { char buf[128]; - fatalf("No valid signing SSL certificate configured for %s_port %s", portType, port.s.toUrl(buf, sizeof(buf))); + // XXX: we never actually checked that the cert is capable of signing! + fatalf("No valid signing certificate configured for %s_port %s", portType, port.s.toUrl(buf, sizeof(buf))); } - if (!signPkey) - debugs(3, DBG_IMPORTANT, "No SSL private key configured for " << portType << "_port " << port.s); + if (!signingCa.pkey) + debugs(3, DBG_IMPORTANT, "No TLS private key configured for " << portType << "_port " << port.s); #if USE_OPENSSL - Ssl::generateUntrustedCert(untrustedSigningCert, untrustedSignPkey, signingCert, signPkey); + Ssl::generateUntrustedCert(untrustedSigningCa.cert, untrustedSigningCa.pkey, signingCa.cert, signingCa.pkey); +#elif USE_GNUTLS + // TODO: implement for GnuTLS. Just a warning for now since generate is implicitly on for all crypto builds. + signingCa.cert.reset(); + signingCa.pkey.reset(); + debugs(83, DBG_CRITICAL, "WARNING: Dynamic TLS certificate generation requires --with-openssl."); + return; +#else + debugs(83, DBG_CRITICAL, "ERROR: Dynamic TLS certificate generation requires --with-openssl."); + return; #endif - if (!untrustedSigningCert) { + if (!untrustedSigningCa.cert) { char buf[128]; - fatalf("Unable to generate signing SSL certificate for untrusted sites for %s_port %s", portType, port.s.toUrl(buf, sizeof(buf))); - } - - if (!createStaticServerContext(port)) { - char buf[128]; - fatalf("%s_port %s initialization error", portType, port.s.toUrl(buf, sizeof(buf))); + fatalf("Unable to generate signing certificate for untrusted sites for %s_port %s", portType, port.s.toUrl(buf, sizeof(buf))); } } diff --git a/src/security/ServerOptions.h b/src/security/ServerOptions.h index 941bf671b6..fbfc587443 100644 --- a/src/security/ServerOptions.h +++ b/src/security/ServerOptions.h @@ -41,14 +41,8 @@ public: virtual Security::ContextPointer createBlankContext() const; virtual void dumpCfg(Packable *, const char *pfx) const; - /// generate a security server-context from these configured options - /// the resulting context is stored in staticContext - /// \returns true if a context could be created - bool createStaticServerContext(AnyP::PortCfg &); - - /// initialize contexts for signing dynamic TLS certificates (if needed) - /// the resulting context is stored in signingCert, signPKey, untrustedSigningCert, untrustedSignPKey - void createSigningContexts(AnyP::PortCfg &); + /// initialize all server contexts as-needed + void initServerContexts(AnyP::PortCfg &); /// update the given TLS security context using squid.conf settings bool updateContextConfig(Security::ContextPointer &); @@ -70,13 +64,21 @@ public: Security::ContextPointer staticContext; SBuf staticContextSessionId; ///< "session id context" for staticContext +#if USE_OPENSSL + bool generateHostCertificates = true; ///< dynamically make host cert +#elif USE_GNUTLS + // TODO: GnuTLS does implement TLS server connections so the cert + // generate vs static choice can be reached in the code now. + // But this feature is not fully working implemented so must not + // be enabled by default for production installations. + bool generateHostCertificates = false; ///< dynamically make host cert +#else + // same as OpenSSL so config errors show up easily bool generateHostCertificates = true; ///< dynamically make host cert +#endif - Security::CertPointer signingCert; ///< x509 certificate for signing generated certificates - Security::PrivateKeyPointer signPkey; ///< private key for signing generated certificates - Security::CertList certsToChain; ///< x509 certificates to send with the generated cert - Security::CertPointer untrustedSigningCert; ///< x509 certificate for signing untrusted generated certificates - Security::PrivateKeyPointer untrustedSignPkey; ///< private key for signing untrusted generated certificates + Security::KeyData signingCa; ///< x509 certificate and key for signing generated certificates + Security::KeyData untrustedSigningCa; ///< x509 certificate and key for signing untrusted generated certificates /// max size of generated certificates memory cache (4 MB default) size_t dynamicCertMemCacheSize = 4*1024*1024; @@ -85,6 +87,15 @@ private: bool loadClientCaFile(); void loadDhParams(); + /// generate a security server-context from these configured options + /// the resulting context is stored in staticContext + /// \returns true if a context could be created + bool createStaticServerContext(AnyP::PortCfg &); + + /// initialize contexts for signing dynamic TLS certificates (if needed) + /// the resulting keys are stored in signingCa and untrustedSigningCa + void createSigningContexts(const AnyP::PortCfg &); + private: SBuf clientCaFile; ///< name of file to load client CAs from #if USE_OPENSSL diff --git a/src/security/forward.h b/src/security/forward.h index 275b6d8db0..7bf3f0e194 100644 --- a/src/security/forward.h +++ b/src/security/forward.h @@ -13,8 +13,8 @@ #include "security/Context.h" #include "security/Session.h" -#if USE_GNUTLS && HAVE_GNUTLS_X509_H -#include +#if USE_GNUTLS && HAVE_GNUTLS_ABSTRACT_H +#include #endif #include #if USE_OPENSSL && HAVE_OPENSSL_ERR_H @@ -86,10 +86,9 @@ typedef CbDataList CertErrors; CtoCpp1(X509_free, X509 *) typedef Security::LockingPointer > CertPointer; #elif USE_GNUTLS -CtoCpp1(gnutls_x509_crt_deinit, gnutls_x509_crt_t) -typedef Security::LockingPointer CertPointer; +typedef std::shared_ptr CertPointer; #else -typedef void * CertPointer; +typedef std::shared_ptr CertPointer; #endif #if USE_OPENSSL @@ -167,9 +166,10 @@ class PeerOptions; #if USE_OPENSSL CtoCpp1(EVP_PKEY_free, EVP_PKEY *) typedef Security::LockingPointer > PrivateKeyPointer; +#elif USE_GNUTLS +typedef std::shared_ptr PrivateKeyPointer; #else -// XXX: incompatible with the other PrivateKeyPointer declaration (lacks self-initialization) -typedef void *PrivateKeyPointer; +typedef std::shared_ptr PrivateKeyPointer; #endif class ServerOptions; diff --git a/src/servers/Http1Server.cc b/src/servers/Http1Server.cc index c53cd1c1ee..aff5a272c2 100644 --- a/src/servers/Http1Server.cc +++ b/src/servers/Http1Server.cc @@ -42,14 +42,12 @@ Http::One::Server::start() { ConnStateData::start(); -#if USE_OPENSSL // XXX: Until we create an HttpsServer class, use this hack to allow old // client_side.cc code to manipulate ConnStateData object directly if (isHttpsServer) { postHttpsAccept(); return; } -#endif typedef CommCbMemFunT TimeoutDialer; AsyncCall::Pointer timeoutCall = JobCallback(33, 5, diff --git a/src/ssl/bio.h b/src/ssl/bio.h index 92f68a540a..fb311b0d99 100644 --- a/src/ssl/bio.h +++ b/src/ssl/bio.h @@ -13,7 +13,9 @@ #include "FadingCounter.h" #include "fd.h" +#include "MemBuf.h" #include "security/Handshake.h" +#include "ssl/support.h" #include #include diff --git a/src/ssl/support.cc b/src/ssl/support.cc index 566d54907b..8c9647d061 100644 --- a/src/ssl/support.cc +++ b/src/ssl/support.cc @@ -59,15 +59,14 @@ std::vector Ssl::BumpModeStr = { \ingroup ServerProtocolSSLAPI */ -/// \ingroup ServerProtocolSSLInternal -static int -ssl_ask_password_cb(char *buf, int size, int rwflag, void *userdata) +int +Ssl::AskPasswordCb(char *buf, int size, int rwflag, void *userdata) { FILE *in; int len = 0; char cmdline[1024]; - snprintf(cmdline, sizeof(cmdline), "\"%s\" \"%s\"", Config.Program.ssl_password, (const char *)userdata); + snprintf(cmdline, sizeof(cmdline), "\"%s\" \"%s\"", ::Config.Program.ssl_password, (const char *)userdata); in = popen(cmdline, "r"); if (fgets(buf, size, in)) @@ -89,7 +88,7 @@ static void ssl_ask_password(SSL_CTX * context, const char * prompt) { if (Config.Program.ssl_password) { - SSL_CTX_set_default_passwd_cb(context, ssl_ask_password_cb); + SSL_CTX_set_default_passwd_cb(context, Ssl::AskPasswordCb); SSL_CTX_set_default_passwd_cb_userdata(context, (void *)prompt); } } @@ -512,27 +511,6 @@ Ssl::InitServerContext(Security::ContextPointer &ctx, AnyP::PortCfg &port) if (!ctx) return false; - if (!SSL_CTX_use_certificate(ctx.get(), port.secure.signingCert.get())) { - const int ssl_error = ERR_get_error(); - const auto &keys = port.secure.certs.front(); - debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire TLS certificate '" << keys.certFile << "': " << Security::ErrorString(ssl_error)); - return false; - } - - if (!SSL_CTX_use_PrivateKey(ctx.get(), port.secure.signPkey.get())) { - const int ssl_error = ERR_get_error(); - const auto &keys = port.secure.certs.front(); - debugs(83, DBG_CRITICAL, "ERROR: Failed to acquire TLS private key '" << keys.privateKeyFile << "': " << Security::ErrorString(ssl_error)); - return false; - } - - Ssl::addChainToSslContext(ctx, port.secure.certsToChain); - - if (!port.secure.updateContextConfig(ctx)) { - debugs(83, DBG_CRITICAL, "ERROR: Configuring static SSL context"); - return false; - } - return true; } @@ -837,7 +815,7 @@ Ssl::chainCertificatesToSSLContext(Security::ContextPointer &ctx, Security::Serv { assert(ctx); // Add signing certificate to the certificates chain - X509 *signingCert = options.signingCert.get(); + X509 *signingCert = options.signingCa.cert.get(); if (SSL_CTX_add_extra_chain_cert(ctx.get(), signingCert)) { // increase the certificate lock X509_up_ref(signingCert); @@ -845,7 +823,16 @@ Ssl::chainCertificatesToSSLContext(Security::ContextPointer &ctx, Security::Serv const int ssl_error = ERR_get_error(); debugs(33, DBG_IMPORTANT, "WARNING: can not add signing certificate to SSL context chain: " << Security::ErrorString(ssl_error)); } - Ssl::addChainToSslContext(ctx, options.certsToChain); + + for (auto cert : options.signingCa.chain) { + if (SSL_CTX_add_extra_chain_cert(ctx.get(), cert.get())) { + // increase the certificate lock + X509_up_ref(cert.get()); + } else { + const auto error = ERR_get_error(); + debugs(83, DBG_IMPORTANT, "WARNING: can not add certificate to SSL dynamic context chain: " << Security::ErrorString(error)); + } + } } void @@ -943,23 +930,6 @@ Ssl::setClientSNI(SSL *ssl, const char *fqdn) #endif } -void -Ssl::addChainToSslContext(Security::ContextPointer &ctx, Security::CertList &chain) -{ - if (chain.empty()) - return; - - for (auto cert : chain) { - if (SSL_CTX_add_extra_chain_cert(ctx.get(), cert.get())) { - // increase the certificate lock - X509_up_ref(cert.get()); - } else { - const int ssl_error = ERR_get_error(); - debugs(83, DBG_IMPORTANT, "WARNING: can not add certificate to SSL context chain: " << Security::ErrorString(ssl_error)); - } - } -} - static const char * hasAuthorityInfoAccessCaIssuers(X509 *cert) { @@ -1236,65 +1206,6 @@ Ssl::unloadSquidUntrusted() } } -/** - \ingroup ServerProtocolSSLInternal - * Read certificate from file. - * See also: static readSslX509Certificate function, gadgets.cc file - */ -static X509 * readSslX509CertificatesChain(char const * certFilename, Security::CertList &chain) -{ - if (!certFilename) - return NULL; - Ssl::BIO_Pointer bio(BIO_new(BIO_s_file())); - if (!bio) - return NULL; - if (!BIO_read_filename(bio.get(), certFilename)) - return NULL; - X509 *certificate = PEM_read_bio_X509(bio.get(), NULL, NULL, NULL); - - if (certificate) { - - if (X509_check_issued(certificate, certificate) == X509_V_OK) - debugs(83, 5, "Certificate is self-signed, will not be chained"); - else { - // and add to the chain any other certificate exist in the file - while (X509 *ca = PEM_read_bio_X509(bio.get(), nullptr, nullptr, nullptr)) - chain.emplace_front(Security::CertPointer(ca)); - } - } - - return certificate; -} - -void -Ssl::readCertChainAndPrivateKeyFromFiles(Security::CertPointer & cert, Security::PrivateKeyPointer & pkey, Security::CertList &chain, char const * certFilename, char const * keyFilename) -{ - if (keyFilename == NULL) - keyFilename = certFilename; - - if (certFilename == NULL) - certFilename = keyFilename; - - debugs(83, DBG_IMPORTANT, "Using certificate in " << certFilename); - - // XXX: ssl_ask_password_cb needs SSL_CTX_set_default_passwd_cb_userdata() - // so this may not fully work iff Config.Program.ssl_password is set. - pem_password_cb *cb = ::Config.Program.ssl_password ? &ssl_ask_password_cb : NULL; - Ssl::ReadPrivateKeyFromFile(keyFilename, pkey, cb); - cert.resetWithoutLocking(readSslX509CertificatesChain(certFilename, chain)); - if (!cert) { - debugs(83, DBG_IMPORTANT, "WARNING: missing cert in '" << certFilename << "'"); - } else if (!pkey) { - debugs(83, DBG_IMPORTANT, "WARNING: missing private key in '" << keyFilename << "'"); - } else if (!X509_check_private_key(cert.get(), pkey.get())) { - debugs(83, DBG_IMPORTANT, "WARNING: X509_check_private_key() failed to verify signing cert"); - } else - return; // everything is okay - - pkey.reset(); - cert.reset(); -} - bool Ssl::generateUntrustedCert(Security::CertPointer &untrustedCert, Security::PrivateKeyPointer &untrustedPkey, Security::CertPointer const &cert, Security::PrivateKeyPointer const & pkey) { // Generate the self-signed certificate, using a hard-coded subject prefix diff --git a/src/ssl/support.h b/src/ssl/support.h index 33075d7ba2..38c080bfb9 100644 --- a/src/ssl/support.h +++ b/src/ssl/support.h @@ -65,6 +65,11 @@ class MemMap; namespace Ssl { + +/// callback for receiving password to access password secured PEM files +/// XXX: Requires SSL_CTX_set_default_passwd_cb_userdata()! +int AskPasswordCb(char *buf, int size, int rwflag, void *userdata); + /// initialize the SSL library global state. /// call before generating any SSL context void Initialize(); @@ -264,12 +269,6 @@ bool configureSSL(SSL *ssl, CertificateProperties const &properties, AnyP::PortC */ bool configureSSLUsingPkeyAndCertFromMemory(SSL *ssl, const char *data, AnyP::PortCfg &port); -/** - \ingroup ServerProtocolSSLAPI - * Adds the certificates in certList to the certificate chain of the SSL context - */ -void addChainToSslContext(Security::ContextPointer &, Security::CertList &); - /** \ingroup ServerProtocolSSLAPI * Configures sslContext to use squid untrusted certificates internal list @@ -277,15 +276,6 @@ void addChainToSslContext(Security::ContextPointer &, Security::CertList &); */ void useSquidUntrusted(SSL_CTX *sslContext); -/** - \ingroup ServerProtocolSSLAPI - * Read certificate, private key and any certificates which must be chained from files. - * See also: Ssl::readCertAndPrivateKeyFromFiles function, defined in gadgets.h - * \param certFilename name of file with certificate and certificates which must be chainned. - * \param keyFilename name of file with private key. - */ -void readCertChainAndPrivateKeyFromFiles(Security::CertPointer & cert, Security::PrivateKeyPointer & pkey, Security::CertList &chain, char const * certFilename, char const * keyFilename); - /** \ingroup ServerProtocolSSLAPI * Iterates over the X509 common and alternate names and to see if matches with given data diff --git a/src/tests/stub_libsecurity.cc b/src/tests/stub_libsecurity.cc index f4db58dee5..33caad1a20 100644 --- a/src/tests/stub_libsecurity.cc +++ b/src/tests/stub_libsecurity.cc @@ -31,6 +31,12 @@ std::ostream &Security::operator <<(std::ostream &os, const Security::EncryptorA Security::HandshakeParser::HandshakeParser() STUB bool Security::HandshakeParser::parseHello(const SBuf &) STUB_RETVAL(false) +#include "security/KeyData.h" +namespace Security +{ +void KeyData::loadFromFiles(const AnyP::PortCfg &, const char *) STUB +} + #include "security/NegotiationHistory.h" Security::NegotiationHistory::NegotiationHistory() STUB void Security::NegotiationHistory::retrieveNegotiatedInfo(const Security::SessionPointer &) STUB @@ -91,8 +97,9 @@ Security::ServerOptions &Security::ServerOptions::operator=(Security::ServerOpti void Security::ServerOptions::parse(const char *) STUB void Security::ServerOptions::dumpCfg(Packable *, const char *) const STUB Security::ContextPointer Security::ServerOptions::createBlankContext() const STUB_RETVAL(Security::ContextPointer()) +void Security::ServerOptions::initServerContexts(AnyP::PortCfg&) STUB bool Security::ServerOptions::createStaticServerContext(AnyP::PortCfg &) STUB_RETVAL(false) -void Security::ServerOptions::createSigningContexts(AnyP::PortCfg &) STUB +void Security::ServerOptions::createSigningContexts(const AnyP::PortCfg &) STUB bool Security::ServerOptions::updateContextConfig(Security::ContextPointer &) STUB_RETVAL(false) void Security::ServerOptions::updateContextEecdh(Security::ContextPointer &) STUB void Security::ServerOptions::updateContextClientCa(Security::ContextPointer &) STUB diff --git a/src/tests/stub_libsslsquid.cc b/src/tests/stub_libsslsquid.cc index 64601d7c42..fb47a924c7 100644 --- a/src/tests/stub_libsslsquid.cc +++ b/src/tests/stub_libsslsquid.cc @@ -50,6 +50,7 @@ const String & Ssl::ErrorDetail::toString() const STUB_RETSTATREF(String) #include "ssl/support.h" namespace Ssl { +int AskPasswordCb(char *, int, int, void *) STUB_RETVAL(0) bool InitServerContext(Security::ContextPointer &, AnyP::PortCfg &) STUB_RETVAL(false) bool InitClientContext(Security::ContextPointer &, Security::PeerOptions &, const char *) STUB_RETVAL(false) void SetupVerifyCallback(Security::ContextPointer &) STUB @@ -70,8 +71,6 @@ bool generateUntrustedCert(Security::CertPointer &, Security::PrivateKeyPointer Security::ContextPointer GenerateSslContext(CertificateProperties const &, Security::ServerOptions &, bool) STUB_RETVAL(Security::ContextPointer()) bool verifySslCertificate(Security::ContextPointer &, CertificateProperties const &) STUB_RETVAL(false) Security::ContextPointer GenerateSslContextUsingPkeyAndCertFromMemory(const char *, Security::ServerOptions &, bool) STUB_RETVAL(Security::ContextPointer()) -void addChainToSslContext(Security::ContextPointer &, STACK_OF(X509) *) STUB -void readCertChainAndPrivateKeyFromFiles(Security::CertPointer &, Security::PrivateKeyPointer &, Security::CertList &, char const *, char const *) STUB int matchX509CommonNames(X509 *peer_cert, void *check_data, int (*check_func)(void *check_data, ASN1_STRING *cn_data)) STUB_RETVAL(0) bool checkX509ServerValidity(X509 *cert, const char *server) STUB_RETVAL(false) int asn1timeToString(ASN1_TIME *tm, char *buf, int len) STUB_RETVAL(0)