Support setting per-connection SCT list
Right now the only way to set an SCT list is the per-context function
SSL_CTX_set_signed_cert_timestamp_list. However this assumes that all the
SSLs generated from a SSL_CTX share the same SCT list, which is wrong.
In order to avoid memory duplication in case SSL_CTX has its own list, a
CRYPTO_BUFFER is used for both SSL_CTX and SSL.
Change-Id: Id20e6f128c33cf3e5bff1be390645441be6518c6
Reviewed-on: https://boringssl-review.googlesource.com/13642
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 01aa3e8..e34636e 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -904,6 +904,14 @@
const uint8_t *list,
size_t list_len);
+/* SSL_set_signed_cert_timestamp_list sets the list of signed certificate
+ * timestamps that is sent to clients that request is. The same format as the
+ * one used for |SSL_CTX_set_signed_cert_timestamp_list| applies. The caller
+ * retains ownership of |list|. */
+OPENSSL_EXPORT int SSL_set_signed_cert_timestamp_list(SSL *ctx,
+ const uint8_t *list,
+ size_t list_len);
+
/* SSL_CTX_set_ocsp_response sets the OCSP response that is sent to clients
* which request it. It returns one on success and zero on error. The caller
* retains ownership of |response|. */
@@ -4050,8 +4058,7 @@
EVP_PKEY *tlsext_channel_id_private;
/* Signed certificate timestamp list to be sent to the client, if requested */
- uint8_t *signed_cert_timestamp_list;
- size_t signed_cert_timestamp_list_length;
+ CRYPTO_BUFFER *signed_cert_timestamp_list;
/* OCSP response to be sent to the client, if requested. */
CRYPTO_BUFFER *ocsp_response;
diff --git a/ssl/internal.h b/ssl/internal.h
index 50ab3cd..b3f3b0f 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1836,6 +1836,9 @@
* session space. Only effective on the server side. */
unsigned retain_only_sha256_of_client_certs:1;
+ /* Signed certificate timestamp list to be sent to the client, if requested */
+ CRYPTO_BUFFER *signed_cert_timestamp_list;
+
/* OCSP response to be sent to the client, if requested. */
CRYPTO_BUFFER *ocsp_response;
};
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c
index 912d934..96ea64b 100644
--- a/ssl/ssl_lib.c
+++ b/ssl/ssl_lib.c
@@ -362,8 +362,8 @@
OPENSSL_free(ctx->psk_identity_hint);
OPENSSL_free(ctx->supported_group_list);
OPENSSL_free(ctx->alpn_client_proto_list);
+ CRYPTO_BUFFER_free(ctx->signed_cert_timestamp_list);
CRYPTO_BUFFER_free(ctx->ocsp_response);
- OPENSSL_free(ctx->signed_cert_timestamp_list);
EVP_PKEY_free(ctx->tlsext_channel_id_private);
OPENSSL_free(ctx);
@@ -471,6 +471,12 @@
ssl->signed_cert_timestamps_enabled = ctx->signed_cert_timestamps_enabled;
ssl->ocsp_stapling_enabled = ctx->ocsp_stapling_enabled;
+ /* If the context has an SCT list, use it. */
+ if (ctx->signed_cert_timestamp_list != NULL) {
+ CRYPTO_BUFFER_up_ref(ctx->signed_cert_timestamp_list);
+ ssl->signed_cert_timestamp_list = ctx->signed_cert_timestamp_list;
+ }
+
/* If the context has an OCSP response, use it. */
if (ctx->ocsp_response != NULL) {
CRYPTO_BUFFER_up_ref(ctx->ocsp_response);
@@ -515,6 +521,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->signed_cert_timestamp_list);
CRYPTO_BUFFER_free(ssl->ocsp_response);
if (ssl->method != NULL) {
@@ -1625,8 +1632,27 @@
return 0;
}
- return CBS_stow(&sct_list, &ctx->signed_cert_timestamp_list,
- &ctx->signed_cert_timestamp_list_length);
+ CRYPTO_BUFFER_free(ctx->signed_cert_timestamp_list);
+ ctx->signed_cert_timestamp_list = CRYPTO_BUFFER_new(CBS_data(&sct_list),
+ CBS_len(&sct_list),
+ NULL);
+ return ctx->signed_cert_timestamp_list != NULL;
+}
+
+int SSL_set_signed_cert_timestamp_list(SSL *ssl, const uint8_t *list,
+ size_t list_len) {
+ CBS sct_list;
+ CBS_init(&sct_list, list, list_len);
+ if (!ssl_is_sct_list_valid(&sct_list)) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_SCT_LIST);
+ return 0;
+ }
+
+ CRYPTO_BUFFER_free(ssl->signed_cert_timestamp_list);
+ ssl->signed_cert_timestamp_list = CRYPTO_BUFFER_new(CBS_data(&sct_list),
+ CBS_len(&sct_list),
+ NULL);
+ return ssl->signed_cert_timestamp_list != NULL;
}
int SSL_CTX_set_ocsp_response(SSL_CTX *ctx, const uint8_t *response,
diff --git a/ssl/t1_lib.c b/ssl/t1_lib.c
index 8091787..d66a2e6 100644
--- a/ssl/t1_lib.c
+++ b/ssl/t1_lib.c
@@ -1371,15 +1371,16 @@
/* The extension shouldn't be sent when resuming sessions. */
if (ssl3_protocol_version(ssl) >= TLS1_3_VERSION ||
ssl->s3->session_reused ||
- ssl->ctx->signed_cert_timestamp_list_length == 0) {
+ ssl->signed_cert_timestamp_list == NULL) {
return 1;
}
CBB contents;
return CBB_add_u16(out, TLSEXT_TYPE_certificate_timestamp) &&
CBB_add_u16_length_prefixed(out, &contents) &&
- CBB_add_bytes(&contents, ssl->ctx->signed_cert_timestamp_list,
- ssl->ctx->signed_cert_timestamp_list_length) &&
+ CBB_add_bytes(&contents,
+ CRYPTO_BUFFER_data(ssl->signed_cert_timestamp_list),
+ CRYPTO_BUFFER_len(ssl->signed_cert_timestamp_list)) &&
CBB_flush(out);
}
diff --git a/ssl/tls13_both.c b/ssl/tls13_both.c
index a49ee14..1c4168c 100644
--- a/ssl/tls13_both.c
+++ b/ssl/tls13_both.c
@@ -451,13 +451,13 @@
goto err;
}
- if (hs->scts_requested &&
- ssl->ctx->signed_cert_timestamp_list_length != 0) {
+ if (hs->scts_requested && ssl->signed_cert_timestamp_list != NULL) {
CBB contents;
if (!CBB_add_u16(&extensions, TLSEXT_TYPE_certificate_timestamp) ||
!CBB_add_u16_length_prefixed(&extensions, &contents) ||
- !CBB_add_bytes(&contents, ssl->ctx->signed_cert_timestamp_list,
- ssl->ctx->signed_cert_timestamp_list_length) ||
+ !CBB_add_bytes(&contents,
+ CRYPTO_BUFFER_data(ssl->signed_cert_timestamp_list),
+ CRYPTO_BUFFER_len(ssl->signed_cert_timestamp_list)) ||
!CBB_flush(&extensions)) {
OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR);
goto err;