Hold CA names as |CRYPTO_BUFFER|s. This change converts the CA names that are parsed from a server's CertificateRequest, as well as the CA names that are configured for sending to clients in the same, to use |CRYPTO_BUFFER|. The |X509_NAME|-based interfaces are turned into compatibility wrappers. Change-Id: I95304ecc988ee39320499739a0866c7f8ff5ed98 Reviewed-on: https://boringssl-review.googlesource.com/13585 Reviewed-by: Adam Langley <agl@google.com> Commit-Queue: Adam Langley <agl@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 3131539..ef22e8f 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h
@@ -3969,7 +3969,11 @@ void (*info_callback)(const SSL *ssl, int type, int value); /* what we put in client cert requests */ - STACK_OF(X509_NAME) *client_CA; + STACK_OF(CRYPTO_BUFFER) *client_CA; + + /* cached_x509_client_CA is a cache of parsed versions of the elements of + * |client_CA|. */ + STACK_OF(X509_NAME) *cached_x509_client_CA; /* Default values to use in SSL structures follow (these are copied by
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c index c4f5e8e..fcc65bc 100644 --- a/ssl/handshake_client.c +++ b/ssl/handshake_client.c
@@ -1403,22 +1403,24 @@ } uint8_t alert = SSL_AD_DECODE_ERROR; - STACK_OF(X509_NAME) *ca_sk = ssl_parse_client_CA_list(ssl, &alert, &cbs); - if (ca_sk == NULL) { + STACK_OF(CRYPTO_BUFFER) *ca_names = + ssl_parse_client_CA_list(ssl, &alert, &cbs); + if (ca_names == NULL) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return -1; } if (CBS_len(&cbs) != 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - sk_X509_NAME_pop_free(ca_sk, X509_NAME_free); + sk_CRYPTO_BUFFER_pop_free(ca_names, CRYPTO_BUFFER_free); OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); return -1; } hs->cert_request = 1; - sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free); - hs->ca_names = ca_sk; + sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free); + hs->ca_names = ca_names; + ssl->ctx->x509_method->hs_flush_cached_ca_names(hs); return 1; }
diff --git a/ssl/internal.h b/ssl/internal.h index a6dfad5..db526a8 100644 --- a/ssl/internal.h +++ b/ssl/internal.h
@@ -844,9 +844,9 @@ /* ssl_parse_client_CA_list parses a CA list from |cbs| in the format used by a * TLS CertificateRequest message. On success, it returns a newly-allocated - * |X509_NAME| list and advances |cbs|. Otherwise, it returns NULL and sets + * |CRYPTO_BUFFER| list and advances |cbs|. Otherwise, it returns NULL and sets * |*out_alert| to an alert to send to the peer. */ -STACK_OF(X509_NAME) * +STACK_OF(CRYPTO_BUFFER) * ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs); /* ssl_add_client_CA_list adds the configured CA list to |cbb| in the format @@ -1037,7 +1037,11 @@ /* ca_names, on the client, contains the list of CAs received in a * CertificateRequest message. */ - STACK_OF(X509_NAME) *ca_names; + STACK_OF(CRYPTO_BUFFER) *ca_names; + + /* cached_x509_ca_names contains a cache of parsed versions of the elements + * of |ca_names|. */ + STACK_OF(X509_NAME) *cached_x509_ca_names; /* certificate_types, on the client, contains the set of certificate types * received in a CertificateRequest message. */ @@ -1460,6 +1464,13 @@ int (*session_dup)(SSL_SESSION *new_session, const SSL_SESSION *session); /* session_clear frees any X509-related state from |session|. */ void (*session_clear)(SSL_SESSION *session); + + /* hs_flush_cached_ca_names drops any cached |X509_NAME|s from |hs|. */ + void (*hs_flush_cached_ca_names)(SSL_HANDSHAKE *hs); + /* ssl_flush_cached_client_CA drops any cached |X509_NAME|s from |ssl|. */ + void (*ssl_flush_cached_client_CA)(SSL *ssl); + /* ssl_ctx_flush_cached_client_CA drops any cached |X509_NAME|s from |ctx|. */ + void (*ssl_ctx_flush_cached_client_CA)(SSL_CTX *ssl); }; /* ssl_noop_x509_method is implements the |ssl_x509_method_st| functions by @@ -1832,7 +1843,11 @@ CRYPTO_EX_DATA ex_data; /* for server side, keep the list of CA_dn we can use */ - STACK_OF(X509_NAME) *client_CA; + STACK_OF(CRYPTO_BUFFER) *client_CA; + + /* cached_x509_client_CA is a cache of parsed versions of the elements of + * |client_CA|. */ + STACK_OF(X509_NAME) *cached_x509_client_CA; uint32_t options; /* protocol behaviour */ uint32_t mode; /* API behaviour */
diff --git a/ssl/s3_both.c b/ssl/s3_both.c index 7fd09c6..6b03030 100644 --- a/ssl/s3_both.c +++ b/ssl/s3_both.c
@@ -173,7 +173,8 @@ OPENSSL_free(hs->peer_key); OPENSSL_free(hs->server_params); OPENSSL_free(hs->peer_psk_identity_hint); - sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free); + sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free); + hs->ssl->ctx->x509_method->hs_flush_cached_ca_names(hs); OPENSSL_free(hs->certificate_types); if (hs->key_block != NULL) {
diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index c60c6fa..c334ea6 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c
@@ -406,96 +406,6 @@ return ret; } -static void set_client_CA_list(STACK_OF(X509_NAME) **ca_list, - STACK_OF(X509_NAME) *name_list) { - sk_X509_NAME_pop_free(*ca_list, X509_NAME_free); - *ca_list = name_list; -} - -STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list) { - STACK_OF(X509_NAME) *ret = sk_X509_NAME_new_null(); - if (ret == NULL) { - return NULL; - } - - for (size_t i = 0; i < sk_X509_NAME_num(list); i++) { - X509_NAME *name = X509_NAME_dup(sk_X509_NAME_value(list, i)); - if (name == NULL || !sk_X509_NAME_push(ret, name)) { - X509_NAME_free(name); - sk_X509_NAME_pop_free(ret, X509_NAME_free); - return NULL; - } - } - - return ret; -} - -void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list) { - set_client_CA_list(&ssl->client_CA, name_list); -} - -void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list) { - set_client_CA_list(&ctx->client_CA, name_list); -} - -STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx) { - return ctx->client_CA; -} - -STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl) { - /* For historical reasons, this function is used both to query configuration - * state on a server as well as handshake state on a client. However, whether - * |ssl| is a client or server is not known until explicitly configured with - * |SSL_set_connect_state|. If |handshake_func| is NULL, |ssl| is in an - * indeterminate mode and |ssl->server| is unset. */ - if (ssl->handshake_func != NULL && !ssl->server) { - if (ssl->s3->hs != NULL) { - return ssl->s3->hs->ca_names; - } - - return NULL; - } - - if (ssl->client_CA != NULL) { - return ssl->client_CA; - } - return ssl->ctx->client_CA; -} - -static int add_client_CA(STACK_OF(X509_NAME) **sk, X509 *x509) { - X509_NAME *name; - - if (x509 == NULL) { - return 0; - } - if (*sk == NULL) { - *sk = sk_X509_NAME_new_null(); - if (*sk == NULL) { - return 0; - } - } - - name = X509_NAME_dup(X509_get_subject_name(x509)); - if (name == NULL) { - return 0; - } - - if (!sk_X509_NAME_push(*sk, name)) { - X509_NAME_free(name); - return 0; - } - - return 1; -} - -int SSL_add_client_CA(SSL *ssl, X509 *x509) { - return add_client_CA(&ssl->client_CA, x509); -} - -int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x509) { - return add_client_CA(&ctx->client_CA, x509); -} - int ssl_has_certificate(const SSL *ssl) { return ssl->cert->chain != NULL && sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0) != NULL && @@ -779,14 +689,11 @@ return 0; } -static int ca_dn_cmp(const X509_NAME **a, const X509_NAME **b) { - return X509_NAME_cmp(*a, *b); -} - -STACK_OF(X509_NAME) * +STACK_OF(CRYPTO_BUFFER) * ssl_parse_client_CA_list(SSL *ssl, uint8_t *out_alert, CBS *cbs) { - STACK_OF(X509_NAME) *ret = sk_X509_NAME_new(ca_dn_cmp); - X509_NAME *name = NULL; + CRYPTO_BUFFER_POOL *const pool = ssl->ctx->pool; + + STACK_OF(CRYPTO_BUFFER) *ret = sk_CRYPTO_BUFFER_new_null(); if (ret == NULL) { *out_alert = SSL_AD_INTERNAL_ERROR; OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); @@ -808,29 +715,21 @@ goto err; } - const uint8_t *ptr = CBS_data(&distinguished_name); - /* A u16 length cannot overflow a long. */ - name = d2i_X509_NAME(NULL, &ptr, (long)CBS_len(&distinguished_name)); - if (name == NULL || - ptr != CBS_data(&distinguished_name) + CBS_len(&distinguished_name)) { - *out_alert = SSL_AD_DECODE_ERROR; - OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); - goto err; - } - - if (!sk_X509_NAME_push(ret, name)) { + CRYPTO_BUFFER *buffer = + CRYPTO_BUFFER_new_from_CBS(&distinguished_name, pool); + if (buffer == NULL || + !sk_CRYPTO_BUFFER_push(ret, buffer)) { + CRYPTO_BUFFER_free(buffer); *out_alert = SSL_AD_INTERNAL_ERROR; OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); goto err; } - name = NULL; } return ret; err: - X509_NAME_free(name); - sk_X509_NAME_pop_free(ret, X509_NAME_free); + sk_CRYPTO_BUFFER_pop_free(ret, CRYPTO_BUFFER_free); return NULL; } @@ -840,21 +739,20 @@ return 0; } - STACK_OF(X509_NAME) *sk = SSL_get_client_CA_list(ssl); - if (sk == NULL) { + STACK_OF(CRYPTO_BUFFER) *names = ssl->client_CA; + if (names == NULL) { + names = ssl->ctx->client_CA; + } + if (names == NULL) { return CBB_flush(cbb); } - for (size_t i = 0; i < sk_X509_NAME_num(sk); i++) { - X509_NAME *name = sk_X509_NAME_value(sk, i); - int len = i2d_X509_NAME(name, NULL); - if (len < 0) { - return 0; - } - uint8_t *ptr; + for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(names); i++) { + const CRYPTO_BUFFER *name = sk_CRYPTO_BUFFER_value(names, i); + if (!CBB_add_u16_length_prefixed(&child, &name_cbb) || - !CBB_add_space(&name_cbb, &ptr, (size_t)len) || - (len > 0 && i2d_X509_NAME(name, &ptr) < 0)) { + !CBB_add_bytes(&name_cbb, CRYPTO_BUFFER_data(name), + CRYPTO_BUFFER_len(name))) { return 0; } }
diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index e37f9f9..cd9d4c4 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c
@@ -289,7 +289,7 @@ goto err; } - ret->client_CA = sk_X509_NAME_new_null(); + ret->client_CA = sk_CRYPTO_BUFFER_new_null(); if (ret->client_CA == NULL) { goto err; } @@ -358,7 +358,8 @@ SSL_CUSTOM_EXTENSION_free); sk_SSL_CUSTOM_EXTENSION_pop_free(ctx->server_custom_extensions, SSL_CUSTOM_EXTENSION_free); - sk_X509_NAME_pop_free(ctx->client_CA, X509_NAME_free); + sk_CRYPTO_BUFFER_pop_free(ctx->client_CA, CRYPTO_BUFFER_free); + ctx->x509_method->ssl_ctx_flush_cached_client_CA(ctx); sk_SRTP_PROTECTION_PROFILE_free(ctx->srtp_profiles); OPENSSL_free(ctx->psk_identity_hint); OPENSSL_free(ctx->supported_group_list); @@ -503,7 +504,8 @@ OPENSSL_free(ssl->alpn_client_proto_list); EVP_PKEY_free(ssl->tlsext_channel_id_private); OPENSSL_free(ssl->psk_identity_hint); - sk_X509_NAME_pop_free(ssl->client_CA, X509_NAME_free); + sk_CRYPTO_BUFFER_pop_free(ssl->client_CA, CRYPTO_BUFFER_free); + ssl->ctx->x509_method->ssl_flush_cached_client_CA(ssl); sk_SRTP_PROTECTION_PROFILE_free(ssl->srtp_profiles); if (ssl->method != NULL) {
diff --git a/ssl/ssl_test.cc b/ssl/ssl_test.cc index 97bcab3..4180463 100644 --- a/ssl/ssl_test.cc +++ b/ssl/ssl_test.cc
@@ -990,12 +990,25 @@ bssl::UniquePtr<SSL> ssl(SSL_new(ctx.get())); ASSERT_TRUE(ssl); - STACK_OF(X509_NAME) *stack = sk_X509_NAME_new_null(); - ASSERT_TRUE(stack); - // |SSL_set_client_CA_list| takes ownership. - SSL_set_client_CA_list(ssl.get(), stack); + bssl::UniquePtr<X509_NAME> name(X509_NAME_new()); + ASSERT_TRUE(name); - EXPECT_EQ(stack, SSL_get_client_CA_list(ssl.get())); + bssl::UniquePtr<X509_NAME> name_dup(X509_NAME_dup(name.get())); + ASSERT_TRUE(name_dup); + + bssl::UniquePtr<STACK_OF(X509_NAME)> stack(sk_X509_NAME_new_null()); + ASSERT_TRUE(stack); + + ASSERT_TRUE(sk_X509_NAME_push(stack.get(), name_dup.get())); + name_dup.release(); + + // |SSL_set_client_CA_list| takes ownership. + SSL_set_client_CA_list(ssl.get(), stack.release()); + + STACK_OF(X509_NAME) *result = SSL_get_client_CA_list(ssl.get()); + ASSERT_TRUE(result); + ASSERT_EQ(1u, sk_X509_NAME_num(result)); + EXPECT_EQ(0, X509_NAME_cmp(sk_X509_NAME_value(result, 0), name.get())); } static void AppendSession(SSL_SESSION *session, void *arg) {
diff --git a/ssl/ssl_x509.c b/ssl/ssl_x509.c index 2955c21..8a132ff 100644 --- a/ssl/ssl_x509.c +++ b/ssl/ssl_x509.c
@@ -152,6 +152,7 @@ #include <openssl/x509_vfy.h> #include "internal.h" +#include "../crypto/internal.h" X509 *SSL_get_peer_certificate(const SSL *ssl) { @@ -410,6 +411,21 @@ session->x509_chain_without_leaf = NULL; } +static void ssl_crypto_x509_hs_flush_cached_ca_names(SSL_HANDSHAKE *hs) { + sk_X509_NAME_pop_free(hs->cached_x509_ca_names, X509_NAME_free); + hs->cached_x509_ca_names = NULL; +} + +static void ssl_crypto_x509_ssl_flush_cached_client_CA(SSL *ssl) { + sk_X509_NAME_pop_free(ssl->cached_x509_client_CA, X509_NAME_free); + ssl->cached_x509_client_CA = NULL; +} + +static void ssl_crypto_x509_ssl_ctx_flush_cached_client_CA(SSL_CTX *ctx) { + sk_X509_NAME_pop_free(ctx->cached_x509_client_CA, X509_NAME_free); + ctx->cached_x509_client_CA = NULL; +} + const SSL_X509_METHOD ssl_crypto_x509_method = { ssl_crypto_x509_clear, ssl_crypto_x509_flush_cached_chain, @@ -417,6 +433,9 @@ ssl_crypto_x509_session_cache_objects, ssl_crypto_x509_session_dup, ssl_crypto_x509_session_clear, + ssl_crypto_x509_hs_flush_cached_ca_names, + ssl_crypto_x509_ssl_flush_cached_client_CA, + ssl_crypto_x509_ssl_ctx_flush_cached_client_CA, }; /* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised @@ -491,7 +510,10 @@ } X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) { - return ssl_cert_get0_leaf(ctx->cert); + CRYPTO_MUTEX_lock_write((CRYPTO_MUTEX *) &ctx->lock); + X509 *ret = ssl_cert_get0_leaf(ctx->cert); + CRYPTO_MUTEX_unlock_write((CRYPTO_MUTEX *) &ctx->lock); + return ret; } /* new_leafless_chain returns a fresh stack of buffers set to {NULL}. */ @@ -752,7 +774,11 @@ } int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, STACK_OF(X509) **out_chain) { - if (!ssl_cert_cache_chain_certs(ctx->cert)) { + CRYPTO_MUTEX_lock_write((CRYPTO_MUTEX *) &ctx->lock); + const int ret = ssl_cert_cache_chain_certs(ctx->cert); + CRYPTO_MUTEX_unlock_write((CRYPTO_MUTEX *) &ctx->lock); + + if (!ret) { *out_chain = NULL; return 0; } @@ -813,3 +839,179 @@ *pp = CBS_data(&cbs); return ret; } + +STACK_OF(X509_NAME) *SSL_dup_CA_list(STACK_OF(X509_NAME) *list) { + return sk_X509_NAME_deep_copy(list, X509_NAME_dup, X509_NAME_free); +} + +static void set_client_CA_list(STACK_OF(CRYPTO_BUFFER) **ca_list, + const STACK_OF(X509_NAME) *name_list, + CRYPTO_BUFFER_POOL *pool) { + STACK_OF(CRYPTO_BUFFER) *buffers = sk_CRYPTO_BUFFER_new_null(); + if (buffers == NULL) { + return; + } + + for (size_t i = 0; i < sk_X509_NAME_num(name_list); i++) { + X509_NAME *name = sk_X509_NAME_value(name_list, i); + uint8_t *outp = NULL; + int len = i2d_X509_NAME(name, &outp); + if (len < 0) { + goto err; + } + + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(outp, len, pool); + OPENSSL_free(outp); + if (buffer == NULL || + !sk_CRYPTO_BUFFER_push(buffers, buffer)) { + CRYPTO_BUFFER_free(buffer); + goto err; + } + } + + sk_CRYPTO_BUFFER_pop_free(*ca_list, CRYPTO_BUFFER_free); + *ca_list = buffers; + return; + +err: + sk_CRYPTO_BUFFER_pop_free(buffers, CRYPTO_BUFFER_free); +} + +void SSL_set_client_CA_list(SSL *ssl, STACK_OF(X509_NAME) *name_list) { + ssl->ctx->x509_method->ssl_flush_cached_client_CA(ssl); + set_client_CA_list(&ssl->client_CA, name_list, ssl->ctx->pool); + sk_X509_NAME_pop_free(name_list, X509_NAME_free); +} + +void SSL_CTX_set_client_CA_list(SSL_CTX *ctx, STACK_OF(X509_NAME) *name_list) { + ctx->x509_method->ssl_ctx_flush_cached_client_CA(ctx); + set_client_CA_list(&ctx->client_CA, name_list, ctx->pool); + sk_X509_NAME_pop_free(name_list, X509_NAME_free); +} + +static STACK_OF(X509_NAME) * + buffer_names_to_x509(const STACK_OF(CRYPTO_BUFFER) *names, + STACK_OF(X509_NAME) **cached) { + if (names == NULL) { + return NULL; + } + + if (*cached != NULL) { + return *cached; + } + + STACK_OF(X509_NAME) *new_cache = sk_X509_NAME_new_null(); + if (new_cache == NULL) { + OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); + return NULL; + } + + for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(names); i++) { + const CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(names, i); + const uint8_t *inp = CRYPTO_BUFFER_data(buffer); + X509_NAME *name = d2i_X509_NAME(NULL, &inp, CRYPTO_BUFFER_len(buffer)); + if (name == NULL || + inp != CRYPTO_BUFFER_data(buffer) + CRYPTO_BUFFER_len(buffer) || + !sk_X509_NAME_push(new_cache, name)) { + X509_NAME_free(name); + goto err; + } + } + + *cached = new_cache; + return new_cache; + +err: + sk_X509_NAME_pop_free(new_cache, X509_NAME_free); + return NULL; +} + +STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *ssl) { + /* For historical reasons, this function is used both to query configuration + * state on a server as well as handshake state on a client. However, whether + * |ssl| is a client or server is not known until explicitly configured with + * |SSL_set_connect_state|. If |handshake_func| is NULL, |ssl| is in an + * indeterminate mode and |ssl->server| is unset. */ + if (ssl->handshake_func != NULL && !ssl->server) { + if (ssl->s3->hs != NULL) { + return buffer_names_to_x509(ssl->s3->hs->ca_names, + &ssl->s3->hs->cached_x509_ca_names); + } + + return NULL; + } + + if (ssl->client_CA != NULL) { + return buffer_names_to_x509( + ssl->client_CA, (STACK_OF(X509_NAME) **)&ssl->cached_x509_client_CA); + } + return buffer_names_to_x509(ssl->ctx->client_CA, + &ssl->ctx->cached_x509_client_CA); +} + +STACK_OF(X509_NAME) *SSL_CTX_get_client_CA_list(const SSL_CTX *ctx) { + CRYPTO_MUTEX_lock_write((CRYPTO_MUTEX *) &ctx->lock); + STACK_OF(X509_NAME) *ret = buffer_names_to_x509( + ctx->client_CA, (STACK_OF(X509_NAME) **)&ctx->cached_x509_client_CA); + CRYPTO_MUTEX_unlock_write((CRYPTO_MUTEX *) &ctx->lock); + return ret; +} + +static int add_client_CA(STACK_OF(CRYPTO_BUFFER) **names, X509 *x509, + CRYPTO_BUFFER_POOL *pool) { + if (x509 == NULL) { + return 0; + } + + uint8_t *outp = NULL; + int len = i2d_X509_NAME(X509_get_subject_name(x509), &outp); + if (len < 0) { + return 0; + } + + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(outp, len, pool); + OPENSSL_free(outp); + if (buffer == NULL) { + return 0; + } + + int alloced = 0; + if (*names == NULL) { + *names = sk_CRYPTO_BUFFER_new_null(); + alloced = 1; + + if (*names == NULL) { + CRYPTO_BUFFER_free(buffer); + return 0; + } + } + + if (!sk_CRYPTO_BUFFER_push(*names, buffer)) { + CRYPTO_BUFFER_free(buffer); + if (alloced) { + sk_CRYPTO_BUFFER_pop_free(*names, CRYPTO_BUFFER_free); + *names = NULL; + } + return 0; + } + + return 1; +} + +int SSL_add_client_CA(SSL *ssl, X509 *x509) { + if (!add_client_CA(&ssl->client_CA, x509, ssl->ctx->pool)) { + return 0; + } + + ssl_crypto_x509_ssl_flush_cached_client_CA(ssl); + return 1; +} + +int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x509) { + if (!add_client_CA(&ctx->client_CA, x509, ctx->pool)) { + return 0; + } + + ssl_crypto_x509_ssl_ctx_flush_cached_client_CA(ctx); + return 1; +}
diff --git a/ssl/tls13_client.c b/ssl/tls13_client.c index 8e994e5..ac70348 100644 --- a/ssl/tls13_client.c +++ b/ssl/tls13_client.c
@@ -402,8 +402,9 @@ } uint8_t alert = SSL_AD_DECODE_ERROR; - STACK_OF(X509_NAME) *ca_sk = ssl_parse_client_CA_list(ssl, &alert, &cbs); - if (ca_sk == NULL) { + STACK_OF(CRYPTO_BUFFER) *ca_names = + ssl_parse_client_CA_list(ssl, &alert, &cbs); + if (ca_names == NULL) { ssl3_send_alert(ssl, SSL3_AL_FATAL, alert); return ssl_hs_error; } @@ -413,14 +414,15 @@ if (!CBS_get_u16_length_prefixed(&cbs, &extensions) || CBS_len(&cbs) != 0) { ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR); - sk_X509_NAME_pop_free(ca_sk, X509_NAME_free); + sk_CRYPTO_BUFFER_pop_free(ca_names, CRYPTO_BUFFER_free); OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR); return ssl_hs_error; } hs->cert_request = 1; - sk_X509_NAME_pop_free(hs->ca_names, X509_NAME_free); - hs->ca_names = ca_sk; + sk_CRYPTO_BUFFER_pop_free(hs->ca_names, CRYPTO_BUFFER_free); + hs->ca_names = ca_names; + ssl->ctx->x509_method->hs_flush_cached_ca_names(hs); if (!ssl_hash_current_message(hs)) { return ssl_hs_error;
diff --git a/ssl/tls_method.c b/ssl/tls_method.c index eaad2ca..d7e4701 100644 --- a/ssl/tls_method.c +++ b/ssl/tls_method.c
@@ -270,6 +270,10 @@ } static void ssl_noop_x509_session_clear(SSL_SESSION *session) {} +static void ssl_noop_x509_hs_flush_cached_ca_names(SSL_HANDSHAKE *hs) {} +static void ssl_noop_x509_ssl_flush_cached_client_CA(SSL *ssl) {} +static void ssl_noop_x509_ssl_ctx_flush_cached_client_CA(SSL_CTX *ctx) {} + const SSL_X509_METHOD ssl_noop_x509_method = { ssl_noop_x509_clear, ssl_noop_x509_flush_cached_chain, @@ -277,4 +281,7 @@ ssl_noop_x509_session_cache_objects, ssl_noop_x509_session_dup, ssl_noop_x509_session_clear, + ssl_noop_x509_hs_flush_cached_ca_names, + ssl_noop_x509_ssl_flush_cached_client_CA, + ssl_noop_x509_ssl_ctx_flush_cached_client_CA, };