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,
};