Support setting per-connection OCSP staple Right now the only way to set an OCSP response is SSL_CTX_set_ocsp_response however this assumes that all the SSLs generated from a SSL_CTX share the same OCSP response, which is wrong. This is similar to the OpenSSL "function" SSL_get_tlsext_status_ocsp_resp, the main difference being that this doesn't take ownership of the OCSP buffer. In order to avoid memory duplication in case SSL_CTX has its own response, a CRYPTO_BUFFER is used for both SSL_CTX and SSL. Change-Id: I3a0697f82b805ac42a22be9b6bb596aa0b530025 Reviewed-on: https://boringssl-review.googlesource.com/12660 Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index c29040a..8b443fd 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h
@@ -901,6 +901,13 @@ const uint8_t *response, size_t response_len); +/* SSL_set_ocsp_response sets the OCSP reponse that is sent to clients which + * request it. It returns one on success and zero on error. The caller retains + * ownership of |response|. */ +OPENSSL_EXPORT int SSL_set_ocsp_response(SSL *ssl, + const uint8_t *response, + size_t response_len); + /* SSL_SIGN_* are signature algorithm values as defined in TLS 1.3. */ #define SSL_SIGN_RSA_PKCS1_SHA1 0x0201 #define SSL_SIGN_RSA_PKCS1_SHA256 0x0401 @@ -4009,8 +4016,7 @@ size_t signed_cert_timestamp_list_length; /* OCSP response to be sent to the client, if requested. */ - uint8_t *ocsp_response; - size_t ocsp_response_length; + CRYPTO_BUFFER *ocsp_response; /* keylog_callback, if not NULL, is the key logging callback. See * |SSL_CTX_set_keylog_callback|. */ @@ -4224,6 +4230,9 @@ /* session_timeout is the default lifetime in seconds of the session * created in this connection. */ long session_timeout; + + /* OCSP response to be sent to the client, if requested. */ + CRYPTO_BUFFER *ocsp_response; };
diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c index c114074..1c1c708 100644 --- a/ssl/handshake_server.c +++ b/ssl/handshake_server.c
@@ -1143,8 +1143,8 @@ SSL3_MT_CERTIFICATE_STATUS) || !CBB_add_u8(&body, TLSEXT_STATUSTYPE_ocsp) || !CBB_add_u24_length_prefixed(&body, &ocsp_response) || - !CBB_add_bytes(&ocsp_response, ssl->ctx->ocsp_response, - ssl->ctx->ocsp_response_length) || + !CBB_add_bytes(&ocsp_response, CRYPTO_BUFFER_data(ssl->ocsp_response), + CRYPTO_BUFFER_len(ssl->ocsp_response)) || !ssl_complete_message(ssl, &cbb)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); CBB_cleanup(&cbb);
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index b0c0906..ac5a7dd 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c
@@ -364,7 +364,7 @@ OPENSSL_free(ctx->psk_identity_hint); OPENSSL_free(ctx->supported_group_list); OPENSSL_free(ctx->alpn_client_proto_list); - OPENSSL_free(ctx->ocsp_response); + CRYPTO_BUFFER_free(ctx->ocsp_response); OPENSSL_free(ctx->signed_cert_timestamp_list); EVP_PKEY_free(ctx->tlsext_channel_id_private); @@ -484,6 +484,12 @@ ssl->session_timeout = ctx->session_timeout; } + /* If the context has an OCSP response, use it. */ + if (ctx->ocsp_response != NULL) { + CRYPTO_BUFFER_up_ref(ctx->ocsp_response); + ssl->ocsp_response = ctx->ocsp_response; + } + return ssl; err: @@ -525,6 +531,7 @@ OPENSSL_free(ssl->psk_identity_hint); sk_X509_NAME_pop_free(ssl->client_CA, X509_NAME_free); sk_SRTP_PROTECTION_PROFILE_free(ssl->srtp_profiles); + CRYPTO_BUFFER_free(ssl->ocsp_response); if (ssl->method != NULL) { ssl->method->ssl_free(ssl); @@ -1791,16 +1798,16 @@ int SSL_CTX_set_ocsp_response(SSL_CTX *ctx, const uint8_t *response, size_t response_len) { - OPENSSL_free(ctx->ocsp_response); - ctx->ocsp_response_length = 0; + CRYPTO_BUFFER_free(ctx->ocsp_response); + ctx->ocsp_response = CRYPTO_BUFFER_new(response, response_len, NULL); + return ctx->ocsp_response != NULL; +} - ctx->ocsp_response = BUF_memdup(response, response_len); - if (ctx->ocsp_response == NULL) { - return 0; - } - ctx->ocsp_response_length = response_len; - - return 1; +int SSL_set_ocsp_response(SSL *ssl, const uint8_t *response, + size_t response_len) { + CRYPTO_BUFFER_free(ssl->ocsp_response); + ssl->ocsp_response = CRYPTO_BUFFER_new(response, response_len, NULL); + return ssl->ocsp_response != NULL; } int SSL_set_tlsext_host_name(SSL *ssl, const char *name) {
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c index 3530ff5..086af3c 100644 --- a/ssl/t1_lib.c +++ b/ssl/t1_lib.c
@@ -1212,7 +1212,7 @@ SSL *const ssl = hs->ssl; if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION || !hs->ocsp_stapling_requested || - ssl->ctx->ocsp_response_length == 0 || + ssl->ocsp_response == NULL || ssl->s3->session_reused || !ssl_cipher_uses_certificate_auth(ssl->s3->tmp.new_cipher)) { return 1;
diff --git a/ssl/test/bssl_shim.cc b/ssl/test/bssl_shim.cc index b7f9c9d..dbfaf10 100644 --- a/ssl/test/bssl_shim.cc +++ b/ssl/test/bssl_shim.cc
@@ -398,9 +398,8 @@ return false; } if (!config->ocsp_response.empty() && - !SSL_CTX_set_ocsp_response(SSL_get_SSL_CTX(ssl), - (const uint8_t *)config->ocsp_response.data(), - config->ocsp_response.size())) { + !SSL_set_ocsp_response(ssl, (const uint8_t *)config->ocsp_response.data(), + config->ocsp_response.size())) { return false; } return true;
diff --git a/ssl/tls13_both.c b/ssl/tls13_both.c index ea3eb77..1a1d8b9 100644 --- a/ssl/tls13_both.c +++ b/ssl/tls13_both.c
@@ -466,14 +466,14 @@ } if (hs->ocsp_stapling_requested && - ssl->ctx->ocsp_response_length != 0) { + ssl->ocsp_response != NULL) { CBB contents, ocsp_response; if (!CBB_add_u16(&extensions, TLSEXT_TYPE_status_request) || !CBB_add_u16_length_prefixed(&extensions, &contents) || !CBB_add_u8(&contents, TLSEXT_STATUSTYPE_ocsp) || !CBB_add_u24_length_prefixed(&contents, &ocsp_response) || - !CBB_add_bytes(&ocsp_response, ssl->ctx->ocsp_response, - ssl->ctx->ocsp_response_length) || + !CBB_add_bytes(&ocsp_response, CRYPTO_BUFFER_data(ssl->ocsp_response), + CRYPTO_BUFFER_len(ssl->ocsp_response)) || !CBB_flush(&extensions)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); goto err;