From: Stefan Eissing Date: Mon, 1 Jul 2019 14:22:04 +0000 (+0000) Subject: *) mod_ssl/mod_md: X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=360986b1918c6683ac69827174facb77a059e451;p=apache *) mod_ssl/mod_md: Adding 2 new hooks for init/get of OCSP stapling status information when other modules want to provide those. Falls back to own implementation with same behaviour as before. git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@1862384 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/CHANGES b/CHANGES index a77b77e204..2134b3472d 100644 --- a/CHANGES +++ b/CHANGES @@ -4,6 +4,9 @@ Changes with Apache 2.5.1 *) mod_ssl/mod_md: reversing dependency by letting mod_ssl offer hooks for adding certificates and keys to a virtual host. An additional hook allows answering special TLS connections as used in ACME challenges. + Adding 2 new hooks for init/get of OCSP stapling status information when + other modules want to provide those. Falls back to own implementation with + same behaviour as before. [Stefan Eissing] *) mod_md: bringing over v2.0.6 from github. diff --git a/modules/ssl/mod_ssl.h b/modules/ssl/mod_ssl.h index 5ae7ba6a71..5856680870 100644 --- a/modules/ssl/mod_ssl.h +++ b/modules/ssl/mod_ssl.h @@ -121,10 +121,41 @@ APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, add_fallback_cert_files, /** On TLS connections that do not relate to a configured virtual host, * allow other modules to provide a X509 certificate and EVP_PKEY to * be used on the connection. This first hook which does not - * return DECLINDED will determine the outcome. */ + * return DECLINED will determine the outcome. */ APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, answer_challenge, (conn_rec *c, const char *server_name, void **pX509, void **pEVP_PKEY)) + +/** During post_config phase, ask around if someone wants to provide + * OCSP stapling status information for the given cert (with the also + * provided issuer certificate). The first hook which does not + * return DECLINED promises to take responsibility (and respond + * in later calls via hook ssl_get_stapling_status). + * If no hook takes over, mod_ssl's own stapling implementation will + * be applied (if configured). + */ +APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, init_stapling_status, + (server_rec *s, apr_pool_t *p, + void *x509cert, void *x509issuer)) + +/** Anyone answering positive to ssl_init_stapling_status for a + * certificate, needs to register here and supply the actual OCSP stapling + * status data (OCSP_RESP) for a new connection. + * The data is returned in DER encoded bytes via pder and pderlen. The + * returned pointer may be NULL, which indicates that data is (currently) + * unavailable. + * If DER data is returned, it MUST come from a response with + * status OCSP_RESPONSE_STATUS_SUCCESSFUL and V_OCSP_CERTSTATUS_GOOD + * or V_OCSP_CERTSTATUS_REVOKED, not V_OCSP_CERTSTATUS_UNKNOWN. This means + * errors in OCSP retrieval are to be handled/logged by the hook and + * are not done by mod_ssl. + * Any DER bytes returned MUST be allocated via malloc() and ownership + * passes to mod_ssl. Meaning, the hook must return a malloced copy of + * the data it has. mod_ssl (or OpenSSL) will free it. + */ +APR_DECLARE_EXTERNAL_HOOK(ssl, SSL, int, get_stapling_status, + (unsigned char **pder, int *pderlen, + conn_rec *c, server_rec *s, void *x509cert)) #endif /* SSL_CERT_HOOKS */ diff --git a/modules/ssl/ssl_engine_init.c b/modules/ssl/ssl_engine_init.c index bb9b4ab385..eb9d2dc38c 100644 --- a/modules/ssl/ssl_engine_init.c +++ b/modules/ssl/ssl_engine_init.c @@ -59,7 +59,6 @@ APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, answer_challenge, DECLINED, DECLINED) - /* _________________________________________________________________ ** ** Module Initialization @@ -1423,8 +1422,7 @@ static apr_status_t ssl_init_server_certs(server_rec *s, * loaded via SSLOpenSSLConfCmd Certificate), so for 1.0.2 and * later, we defer to the code in ssl_init_server_ctx. */ - if ((mctx->stapling_enabled == TRUE) && - !ssl_stapling_init_cert(s, p, ptemp, mctx, cert)) { + if (!ssl_stapling_init_cert(s, p, ptemp, mctx, cert)) { ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(02567) "Unable to configure certificate %s for stapling", key_id); @@ -1833,8 +1831,8 @@ static apr_status_t ssl_init_server_ctx(server_rec *s, pks->service_unavailable = 1; ap_log_error(APLOG_MARK, APLOG_WARNING, 0, s, APLOGNO(10085) - "Init: %s will respond with '503 Service Unavailable' for now. This " - "has no SSL certificate configured and no other module contributed any.", + "Init: %s will respond with '503 Service Unavailable' for now. There " + "are no SSL certificates configured and no other module contributed any.", ssl_util_vhostid(p, s)); } @@ -1887,7 +1885,7 @@ static apr_status_t ssl_init_server_ctx(server_rec *s, * (late) point makes sure that we catch both certificates loaded * via SSLCertificateFile and SSLOpenSSLConfCmd Certificate. */ - if (sc->server->stapling_enabled == TRUE) { + do { X509 *cert; int i = 0; int ret = SSL_CTX_set_current_cert(sc->server->ssl_ctx, @@ -1904,7 +1902,7 @@ static apr_status_t ssl_init_server_ctx(server_rec *s, SSL_CERT_SET_NEXT); i++; } - } + } while(0); #endif #ifdef HAVE_TLS_SESSION_TICKETS diff --git a/modules/ssl/ssl_util_stapling.c b/modules/ssl/ssl_util_stapling.c index aecf5d324c..4105c80157 100644 --- a/modules/ssl/ssl_util_stapling.c +++ b/modules/ssl/ssl_util_stapling.c @@ -31,12 +31,28 @@ #include "ssl_private.h" #include "ap_mpm.h" #include "apr_thread_mutex.h" +#include "mod_ssl.h" + +APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, init_stapling_status, + (server_rec *s, apr_pool_t *p, + void *x509cert, void *x509issuer), + (s, p, x509cert, x509issuer), + DECLINED, DECLINED) + +APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, get_stapling_status, + (unsigned char **pder, int *pderlen, + conn_rec *c, server_rec *s, void *x509cert), + (pder, pderlen, c, s, x509cert), + DECLINED, DECLINED) + #ifdef HAVE_OCSP_STAPLING static int stapling_cache_mutex_on(server_rec *s); static int stapling_cache_mutex_off(server_rec *s); +static int stapling_cb(SSL *ssl, void *arg); + /** * Maxiumum OCSP stapling response size. This should be the response for a * single certificate and will typically include the responder certificate chain @@ -119,7 +135,38 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, OCSP_CERTID *cid = NULL; STACK_OF(OPENSSL_STRING) *aia = NULL; - if ((x == NULL) || (X509_digest(x, EVP_sha1(), idx, NULL) != 1)) + if (x == NULL) + return 0; + + if (!(issuer = stapling_get_issuer(mctx, x))) { + /* In Apache pre 2.4.40, we use to come here only when mod_ssl stapling + * was enabled. With the new hooks, we give other modules the chance + * to provide stapling status. However, we do not want to log ssl errors + * where we did not do so in the past. */ + if (mctx->stapling_enabled == TRUE) { + ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, APLOGNO(02217) + "ssl_stapling_init_cert: can't retrieve issuer " + "certificate!"); + return 0; + } + return 1; + } + + if (ssl_run_init_stapling_status(s, p, x, issuer) == APR_SUCCESS) { + /* Someone's taken over or mod_ssl's own implementation is not enabled */ + if (mctx->stapling_enabled != TRUE) { + SSL_CTX_set_tlsext_status_cb(mctx->ssl_ctx, stapling_cb); + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO() "OCSP stapling added via hook"); + } + return 1; + } + + if (mctx->stapling_enabled != TRUE) { + /* mod_ssl's own implementation is not enabled */ + return 1; + } + + if (X509_digest(x, EVP_sha1(), idx, NULL) != 1) return 0; cinf = apr_hash_get(stapling_certinfo, idx, sizeof(idx)); @@ -139,13 +186,6 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, return 1; } - if (!(issuer = stapling_get_issuer(mctx, x))) { - ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, APLOGNO(02217) - "ssl_stapling_init_cert: can't retrieve issuer " - "certificate!"); - return 0; - } - cid = OCSP_cert_to_id(NULL, x, issuer); X509_free(issuer); if (!cid) { @@ -182,18 +222,16 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp, mctx->sc->vhost_id); apr_hash_set(stapling_certinfo, cinf->idx, sizeof(cinf->idx), cinf); - + return 1; } -static certinfo *stapling_get_certinfo(server_rec *s, modssl_ctx_t *mctx, +static certinfo *stapling_get_certinfo(server_rec *s, X509 *x, modssl_ctx_t *mctx, SSL *ssl) { certinfo *cinf; - X509 *x; UCHAR idx[SHA_DIGEST_LENGTH]; - x = SSL_get_certificate(ssl); - if ((x == NULL) || (X509_digest(x, EVP_sha1(), idx, NULL) != 1)) + if (X509_digest(x, EVP_sha1(), idx, NULL) != 1) return NULL; cinf = apr_hash_get(stapling_certinfo, idx, sizeof(idx)); if (cinf && cinf->cid) @@ -751,18 +789,34 @@ static int stapling_cb(SSL *ssl, void *arg) OCSP_RESPONSE *rsp = NULL; int rv; BOOL ok = TRUE; + X509 *x; + unsigned char *rspder = NULL; + int rspderlen; + ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01951) + "stapling_cb: OCSP Stapling callback called"); + + x = SSL_get_certificate(ssl); + if (x == NULL) { + return SSL_TLSEXT_ERR_NOACK; + } + + if (ssl_run_get_stapling_status(&rspder, &rspderlen, conn, s, x) == APR_SUCCESS) { + /* a hook handles stapling for this certicate and determines the response */ + if (rspder == NULL || rspderlen <= 0) { + return SSL_TLSEXT_ERR_NOACK; + } + SSL_set_tlsext_status_ocsp_resp(ssl, rspder, rspderlen); + return SSL_TLSEXT_ERR_OK; + } + if (sc->server->stapling_enabled != TRUE) { ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01950) "stapling_cb: OCSP Stapling disabled"); return SSL_TLSEXT_ERR_NOACK; } - ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01951) - "stapling_cb: OCSP Stapling callback called"); - - cinf = stapling_get_certinfo(s, mctx, ssl); - if (cinf == NULL) { + if ((cinf = stapling_get_certinfo(s, x, mctx, ssl)) == NULL) { return SSL_TLSEXT_ERR_NOACK; } @@ -865,9 +919,10 @@ apr_status_t modssl_init_stapling(server_rec *s, apr_pool_t *p, if (mctx->stapling_responder_timeout == UNSET) { mctx->stapling_responder_timeout = 10 * APR_USEC_PER_SEC; } + SSL_CTX_set_tlsext_status_cb(ctx, stapling_cb); ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01960) "OCSP stapling initialized"); - + return APR_SUCCESS; }