summaryrefslogtreecommitdiffstats
path: root/modules/ssl/ssl_util_stapling.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/ssl/ssl_util_stapling.c')
-rw-r--r--modules/ssl/ssl_util_stapling.c190
1 files changed, 144 insertions, 46 deletions
diff --git a/modules/ssl/ssl_util_stapling.c b/modules/ssl/ssl_util_stapling.c
index c3e2cfa..563de55 100644
--- a/modules/ssl/ssl_util_stapling.c
+++ b/modules/ssl/ssl_util_stapling.c
@@ -29,16 +29,32 @@
-- Alexei Sayle */
#include "ssl_private.h"
+
#include "ap_mpm.h"
#include "apr_thread_mutex.h"
+APR_IMPLEMENT_OPTIONAL_HOOK_RUN_ALL(ssl, SSL, int, init_stapling_status,
+ (server_rec *s, apr_pool_t *p,
+ X509 *cert, X509 *issuer),
+ (s, p, cert, issuer),
+ 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, X509 *cert),
+ (pder, pderlen, c, s, cert),
+ 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
+ * Maximum OCSP stapling response size. This should be the response for a
* single certificate and will typically include the responder certificate chain
* so 10K should be more than enough.
*
@@ -101,8 +117,10 @@ static X509 *stapling_get_issuer(modssl_ctx_t *mctx, X509 *x)
}
inctx = X509_STORE_CTX_new();
- if (!X509_STORE_CTX_init(inctx, st, NULL, NULL))
+ if (!X509_STORE_CTX_init(inctx, st, NULL, NULL)) {
+ X509_STORE_CTX_free(inctx);
return 0;
+ }
if (X509_STORE_CTX_get1_issuer(&issuer, inctx, x) <= 0)
issuer = NULL;
X509_STORE_CTX_cleanup(inctx);
@@ -118,10 +136,51 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp,
X509 *issuer = NULL;
OCSP_CERTID *cid = NULL;
STACK_OF(OPENSSL_STRING) *aia = NULL;
+ const char *pem = NULL;
+ int rv = 1; /* until further notice */
- 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 (X509_digest(x, EVP_sha1(), idx, NULL) != 1) {
+ rv = 0;
+ goto cleanup;
+ }
+
+ if (modssl_cert_get_pem(ptemp, x, issuer, &pem) != APR_SUCCESS) {
+ rv = 0;
+ goto cleanup;
+ }
+
+ if (ap_ssl_ocsp_prime(s, p, (const char*)idx, sizeof(idx), pem) == APR_SUCCESS
+ || ssl_run_init_stapling_status(s, p, x, issuer) == OK) {
+ /* 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(10177) "OCSP stapling added via hook");
+ }
+ goto cleanup;
+ }
+
+ if (mctx->stapling_enabled != TRUE) {
+ /* mod_ssl's own implementation is not enabled */
+ goto cleanup;
+ }
+
cinf = apr_hash_get(stapling_certinfo, idx, sizeof(idx));
if (cinf) {
/*
@@ -134,25 +193,18 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp,
APLOGNO(02814) "ssl_stapling_init_cert: no OCSP URI "
"in certificate and no SSLStaplingForceURL "
"configured for server %s", mctx->sc->vhost_id);
- return 0;
+ rv = 0;
}
- 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;
+ goto cleanup;
}
cid = OCSP_cert_to_id(NULL, x, issuer);
- X509_free(issuer);
if (!cid) {
ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x, APLOGNO(02815)
"ssl_stapling_init_cert: can't create CertID "
"for OCSP request");
- return 0;
+ rv = 0;
+ goto cleanup;
}
aia = X509_get1_ocsp(x);
@@ -161,7 +213,8 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp,
ssl_log_xerror(SSLLOG_MARK, APLOG_ERR, 0, ptemp, s, x,
APLOGNO(02218) "ssl_stapling_init_cert: no OCSP URI "
"in certificate and no SSLStaplingForceURL set");
- return 0;
+ rv = 0;
+ goto cleanup;
}
/* At this point, we have determined that there's something to store */
@@ -183,19 +236,16 @@ int ssl_stapling_init_cert(server_rec *s, apr_pool_t *p, apr_pool_t *ptemp,
apr_hash_set(stapling_certinfo, cinf->idx, sizeof(cinf->idx), cinf);
- return 1;
+cleanup:
+ X509_free(issuer);
+ return rv;
}
-static certinfo *stapling_get_certinfo(server_rec *s, modssl_ctx_t *mctx,
- SSL *ssl)
+static certinfo *stapling_get_certinfo(server_rec *s, UCHAR *idx, apr_size_t idx_len,
+ 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))
- return NULL;
- cinf = apr_hash_get(stapling_certinfo, idx, sizeof(idx));
+ cinf = apr_hash_get(stapling_certinfo, idx, idx_len);
if (cinf && cinf->cid)
return cinf;
ap_log_error(APLOG_MARK, APLOG_INFO, 0, s, APLOGNO(01926)
@@ -397,7 +447,7 @@ static int stapling_check_response(server_rec *s, modssl_ctx_t *mctx,
rv = SSL_TLSEXT_ERR_NOACK;
}
- if (status != V_OCSP_CERTSTATUS_GOOD) {
+ if (status != V_OCSP_CERTSTATUS_GOOD && pok) {
char snum[MAX_STRING_LEN] = { '\0' };
BIO *bio = BIO_new(BIO_s_mem());
@@ -418,12 +468,6 @@ static int stapling_check_response(server_rec *s, modssl_ctx_t *mctx,
(reason != OCSP_REVOKED_STATUS_NOSTATUS) ?
OCSP_crl_reason_str(reason) : "n/a",
snum[0] ? snum : "[n/a]");
-
- if (mctx->stapling_return_errors == FALSE) {
- if (pok)
- *pok = FALSE;
- rv = SSL_TLSEXT_ERR_NOACK;
- }
}
}
@@ -482,6 +526,7 @@ static BOOL stapling_renew_response(server_rec *s, modssl_ctx_t *mctx, SSL *ssl,
/* Create a temporary pool to constrain memory use */
apr_pool_create(&vpool, conn->pool);
+ apr_pool_tag(vpool, "modssl_stapling_renew");
if (apr_uri_parse(vpool, ocspuri, &uri) != APR_SUCCESS) {
ap_log_error(APLOG_MARK, APLOG_ERR, 0, s, APLOGNO(01939)
@@ -732,6 +777,23 @@ static int get_and_check_cached_response(server_rec *s, modssl_ctx_t *mctx,
return 0;
}
+typedef struct {
+ unsigned char *data;
+ apr_size_t len;
+} ocsp_resp;
+
+static void copy_ocsp_resp(const unsigned char *der, apr_size_t der_len, void *userdata)
+{
+ ocsp_resp *resp = userdata;
+
+ resp->len = 0;
+ resp->data = der? OPENSSL_malloc(der_len) : NULL;
+ if (resp->data) {
+ memcpy(resp->data, der, der_len);
+ resp->len = der_len;
+ }
+}
+
/* Certificate Status callback. This is called when a client includes a
* certificate status request extension.
*
@@ -744,24 +806,53 @@ static int stapling_cb(SSL *ssl, void *arg)
conn_rec *conn = (conn_rec *)SSL_get_app_data(ssl);
server_rec *s = mySrvFromConn(conn);
SSLSrvConfigRec *sc = mySrvConfig(s);
- SSLConnRec *sslconn = myConnConfig(conn);
- modssl_ctx_t *mctx = myCtxConfig(sslconn, sc);
+ modssl_ctx_t *mctx = myConnCtxConfig(conn, sc);
+ UCHAR idx[SHA_DIGEST_LENGTH];
+ ocsp_resp resp;
certinfo *cinf = NULL;
OCSP_RESPONSE *rsp = NULL;
int rv;
BOOL ok = TRUE;
+ X509 *x;
+ int rspderlen, provided = 0;
+
+ 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 (X509_digest(x, EVP_sha1(), idx, NULL) != 1) {
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+
+ if (ap_ssl_ocsp_get_resp(s, conn, (const char*)idx, sizeof(idx),
+ copy_ocsp_resp, &resp) == APR_SUCCESS) {
+ provided = 1;
+ }
+ else if (ssl_run_get_stapling_status(&resp.data, &rspderlen, conn, s, x) == APR_SUCCESS) {
+ resp.len = (apr_size_t)rspderlen;
+ provided = 1;
+ }
+ if (provided) {
+ /* a hook handles stapling for this certificate and determines the response */
+ if (resp.data == NULL || resp.len == 0) {
+ return SSL_TLSEXT_ERR_NOACK;
+ }
+ SSL_set_tlsext_status_ocsp_resp(ssl, resp.data, (int)resp.len);
+ 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, idx, sizeof(idx), mctx, ssl)) == NULL) {
return SSL_TLSEXT_ERR_NOACK;
}
@@ -818,15 +909,21 @@ static int stapling_cb(SSL *ssl, void *arg)
if (rsp && ((ok == TRUE) || (mctx->stapling_return_errors == TRUE))) {
ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01956)
"stapling_cb: setting response");
- if (!stapling_set_response(ssl, rsp))
- return SSL_TLSEXT_ERR_ALERT_FATAL;
- return SSL_TLSEXT_ERR_OK;
+ if (!stapling_set_response(ssl, rsp)) {
+ rv = SSL_TLSEXT_ERR_ALERT_FATAL;
+ }
+ else {
+ rv = SSL_TLSEXT_ERR_OK;
+ }
}
- ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01957)
- "stapling_cb: no suitable response available");
-
- return SSL_TLSEXT_ERR_NOACK;
+ else {
+ ap_log_error(APLOG_MARK, APLOG_DEBUG, 0, s, APLOGNO(01957)
+ "stapling_cb: no suitable response available");
+ rv = SSL_TLSEXT_ERR_NOACK;
+ }
+ OCSP_RESPONSE_free(rsp); /* NULL safe */
+ return rv;
}
apr_status_t modssl_init_stapling(server_rec *s, apr_pool_t *p,
@@ -864,9 +961,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;
}