From 3a2b47ab5be5c75edacb8cdc246dc2dc8fb2c0cd Mon Sep 17 00:00:00 2001 From: Adam Langley Date: Tue, 24 Jan 2017 13:59:42 -0800 Subject: [PATCH] Don't use |X509| objects in |CERT|, by default. This change converts the |CERT| struct to holding certificates as binary blobs, rather than in parsed form. The members for holding the parsed form are still there, however, but are only used as a cache for the event that someone asks us for a non-owning pointer to the parsed leaf or chain. Next steps: * Move more functions in to ssl_x509.c * Create an X509_OPS struct of function pointers that will hang off the |SSL_METHOD| to abstract out the current calls to crypto/x509 operations. BUG=chromium:671420 Change-Id: Ifa05d88c49a987fd561b349705c9c48f106ec868 Reviewed-on: https://boringssl-review.googlesource.com/13280 Reviewed-by: Adam Langley --- ssl/handshake_server.c | 2 +- ssl/internal.h | 26 ++- ssl/ssl_cert.c | 355 ++++++++++++++++++++++++++++++++--------- ssl/ssl_lib.c | 26 +-- ssl/ssl_rsa.c | 50 ++++-- ssl/ssl_x509.c | 19 +-- ssl/tls13_both.c | 10 +- 7 files changed, 355 insertions(+), 133 deletions(-) diff --git a/ssl/handshake_server.c b/ssl/handshake_server.c index e3889bbc..dc39c932 100644 --- a/ssl/handshake_server.c +++ b/ssl/handshake_server.c @@ -698,7 +698,7 @@ static void ssl_get_compatible_server_ciphers(SSL_HANDSHAKE *hs, uint32_t mask_k = 0; uint32_t mask_a = 0; - if (ssl->cert->x509_leaf != NULL && ssl_has_private_key(ssl)) { + if (ssl_has_certificate(ssl)) { int type = ssl_private_key_type(ssl); if (type == NID_rsaEncryption) { mask_k |= SSL_kRSA; diff --git a/ssl/internal.h b/ssl/internal.h index ed3f62c5..8b946890 100644 --- a/ssl/internal.h +++ b/ssl/internal.h @@ -773,10 +773,6 @@ STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert, CBS *cbs, CRYPTO_BUFFER_POOL *pool); -/* ssl_add_cert_to_cbb adds |x509| to |cbb|. It returns one on success and zero - * on error. */ -int ssl_add_cert_to_cbb(CBB *cbb, X509 *x509); - /* ssl_add_cert_chain adds |ssl|'s certificate chain to |cbb| in the format used * by a TLS Certificate message. If there is no certificate chain, it emits an * empty certificate list. It returns one on success and zero on error. */ @@ -1235,9 +1231,25 @@ enum ssl_hash_message_t { typedef struct cert_st { EVP_PKEY *privatekey; - X509 *x509_leaf; + + /* chain contains the certificate chain, with the leaf at the beginning. The + * first element of |chain| may be NULL to indicate that the leaf certificate + * has not yet been set. + * If |chain| != NULL -> len(chain) >= 1 + * If |chain[0]| == NULL -> len(chain) >= 2. + * |chain[1..]| != NULL */ + STACK_OF(CRYPTO_BUFFER) *chain; + + /* x509_chain may contain a parsed copy of |chain[1..]|. This is only used as + * a cache in order to implement “get0” functions that return a non-owning + * pointer to the certificate chain. */ STACK_OF(X509) *x509_chain; + /* x509_leaf may contain a parsed copy of the first element of |chain|. This + * is only used as a cache in order to implement “get0” functions that return + * a non-owning pointer to the certificate chain. */ + X509 *x509_leaf; + /* key_method, if non-NULL, is a set of callbacks to call for private key * operations. */ const SSL_PRIVATE_KEY_METHOD *key_method; @@ -1685,6 +1697,10 @@ CERT *ssl_cert_new(void); CERT *ssl_cert_dup(CERT *cert); void ssl_cert_clear_certs(CERT *c); void ssl_cert_free(CERT *c); +CRYPTO_BUFFER *x509_to_buffer(X509 *x509); +void ssl_cert_flush_cached_x509_leaf(CERT *cert); +int ssl_cert_cache_leaf_cert(CERT *cert); +int ssl_cert_check_private_key(const CERT *cert, const EVP_PKEY *privkey); int ssl_get_new_session(SSL_HANDSHAKE *hs, int is_server); int ssl_encrypt_ticket(SSL *ssl, CBB *out, const SSL_SESSION *session); diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index 048bf95c..52a386bd 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -152,6 +152,11 @@ CERT *ssl_cert_new(void) { return ret; } +static CRYPTO_BUFFER *buffer_up_ref(CRYPTO_BUFFER *buffer) { + CRYPTO_BUFFER_up_ref(buffer); + return buffer; +} + CERT *ssl_cert_dup(CERT *cert) { CERT *ret = OPENSSL_malloc(sizeof(CERT)); if (ret == NULL) { @@ -160,24 +165,14 @@ CERT *ssl_cert_dup(CERT *cert) { } OPENSSL_memset(ret, 0, sizeof(CERT)); - if (cert->x509_leaf != NULL) { - X509_up_ref(cert->x509_leaf); - ret->x509_leaf = cert->x509_leaf; - } + ret->chain = sk_CRYPTO_BUFFER_deep_copy(cert->chain, buffer_up_ref, + CRYPTO_BUFFER_free); if (cert->privatekey != NULL) { EVP_PKEY_up_ref(cert->privatekey); ret->privatekey = cert->privatekey; } - if (cert->x509_chain) { - ret->x509_chain = X509_chain_up_ref(cert->x509_chain); - if (!ret->x509_chain) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - goto err; - } - } - ret->key_method = cert->key_method; if (cert->dh_tmp != NULL) { @@ -213,18 +208,29 @@ err: return NULL; } +void ssl_cert_flush_cached_x509_leaf(CERT *cert) { + X509_free(cert->x509_leaf); + cert->x509_leaf = NULL; +} + +static void ssl_cert_flush_cached_x509_chain(CERT *cert) { + sk_X509_pop_free(cert->x509_chain, X509_free); + cert->x509_chain = NULL; +} + /* Free up and clear all certificates and chains */ void ssl_cert_clear_certs(CERT *cert) { if (cert == NULL) { return; } - X509_free(cert->x509_leaf); - cert->x509_leaf = NULL; + ssl_cert_flush_cached_x509_leaf(cert); + ssl_cert_flush_cached_x509_chain(cert); + + sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free); + cert->chain = NULL; EVP_PKEY_free(cert->privatekey); cert->privatekey = NULL; - sk_X509_pop_free(cert->x509_chain, X509_free); - cert->x509_chain = NULL; cert->key_method = NULL; } @@ -242,25 +248,122 @@ void ssl_cert_free(CERT *c) { OPENSSL_free(c); } +/* new_leafless_chain returns a fresh stack of buffers set to {NULL}. */ +static STACK_OF(CRYPTO_BUFFER) *new_leafless_chain(void) { + STACK_OF(CRYPTO_BUFFER) *chain = sk_CRYPTO_BUFFER_new_null(); + if (chain == NULL) { + return NULL; + } + + if (!sk_CRYPTO_BUFFER_push(chain, NULL)) { + sk_CRYPTO_BUFFER_free(chain); + return NULL; + } + + return chain; +} + +/* x509_to_buffer returns a |CRYPTO_BUFFER| that contains the serialised + * contents of |x509|. */ +CRYPTO_BUFFER *x509_to_buffer(X509 *x509) { + uint8_t *buf = NULL; + int cert_len = i2d_X509(x509, &buf); + if (cert_len <= 0) { + return 0; + } + + CRYPTO_BUFFER *buffer = CRYPTO_BUFFER_new(buf, cert_len, NULL); + OPENSSL_free(buf); + + return buffer; +} + +/* ssl_cert_set_chain sets elements 1.. of |cert->chain| to the serialised + * forms of elements of |chain|. It returns one on success or zero on error, in + * which case no change to |cert->chain| is made. It preverses the existing + * leaf from |cert->chain|, if any. */ +static int ssl_cert_set_chain(CERT *cert, STACK_OF(X509) *chain) { + STACK_OF(CRYPTO_BUFFER) *new_chain = NULL; + + if (cert->chain != NULL) { + new_chain = sk_CRYPTO_BUFFER_new_null(); + if (new_chain == NULL) { + return 0; + } + + CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0); + if (!sk_CRYPTO_BUFFER_push(new_chain, leaf)) { + goto err; + } + CRYPTO_BUFFER_up_ref(leaf); + } + + for (size_t i = 0; i < sk_X509_num(chain); i++) { + if (new_chain == NULL) { + new_chain = new_leafless_chain(); + if (new_chain == NULL) { + goto err; + } + } + + CRYPTO_BUFFER *buffer = x509_to_buffer(sk_X509_value(chain, i)); + if (buffer == NULL || + !sk_CRYPTO_BUFFER_push(new_chain, buffer)) { + CRYPTO_BUFFER_free(buffer); + goto err; + } + } + + sk_CRYPTO_BUFFER_pop_free(cert->chain, CRYPTO_BUFFER_free); + cert->chain = new_chain; + + return 1; + +err: + sk_CRYPTO_BUFFER_pop_free(new_chain, CRYPTO_BUFFER_free); + return 0; +} + static int ssl_cert_set0_chain(CERT *cert, STACK_OF(X509) *chain) { - sk_X509_pop_free(cert->x509_chain, X509_free); - cert->x509_chain = chain; + if (!ssl_cert_set_chain(cert, chain)) { + return 0; + } + + sk_X509_pop_free(chain, X509_free); + ssl_cert_flush_cached_x509_chain(cert); return 1; } static int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) { - STACK_OF(X509) *dchain; - if (chain == NULL) { - return ssl_cert_set0_chain(cert, NULL); + if (!ssl_cert_set_chain(cert, chain)) { + return 0; } - dchain = X509_chain_up_ref(chain); - if (dchain == NULL) { + ssl_cert_flush_cached_x509_chain(cert); + return 1; +} + +static int ssl_cert_append_cert(CERT *cert, X509 *x509) { + CRYPTO_BUFFER *buffer = x509_to_buffer(x509); + if (buffer == NULL) { return 0; } - if (!ssl_cert_set0_chain(cert, dchain)) { - sk_X509_pop_free(dchain, X509_free); + if (cert->chain != NULL) { + if (!sk_CRYPTO_BUFFER_push(cert->chain, buffer)) { + CRYPTO_BUFFER_free(buffer); + return 0; + } + + return 1; + } + + cert->chain = new_leafless_chain(); + if (cert->chain == NULL || + !sk_CRYPTO_BUFFER_push(cert->chain, buffer)) { + CRYPTO_BUFFER_free(buffer); + sk_CRYPTO_BUFFER_free(cert->chain); + cert->chain = NULL; return 0; } @@ -268,22 +371,21 @@ static int ssl_cert_set1_chain(CERT *cert, STACK_OF(X509) *chain) { } static int ssl_cert_add0_chain_cert(CERT *cert, X509 *x509) { - if (cert->x509_chain == NULL) { - cert->x509_chain = sk_X509_new_null(); - } - if (cert->x509_chain == NULL || !sk_X509_push(cert->x509_chain, x509)) { + if (!ssl_cert_append_cert(cert, x509)) { return 0; } + X509_free(x509); + ssl_cert_flush_cached_x509_chain(cert); return 1; } static int ssl_cert_add1_chain_cert(CERT *cert, X509 *x509) { - if (!ssl_cert_add0_chain_cert(cert, x509)) { + if (!ssl_cert_append_cert(cert, x509)) { return 0; } - X509_up_ref(x509); + ssl_cert_flush_cached_x509_chain(cert); return 1; } @@ -443,7 +545,9 @@ int SSL_CTX_add_client_CA(SSL_CTX *ctx, X509 *x509) { } int ssl_has_certificate(const SSL *ssl) { - return ssl->cert->x509_leaf != NULL && ssl_has_private_key(ssl); + return ssl->cert->chain != NULL && + sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0) != NULL && + ssl_has_private_key(ssl); } STACK_OF(CRYPTO_BUFFER) *ssl_parse_cert_chain(uint8_t *out_alert, @@ -512,49 +616,33 @@ err: return NULL; } -int ssl_add_cert_to_cbb(CBB *cbb, X509 *x509) { - int len = i2d_X509(x509, NULL); - if (len < 0) { - return 0; - } - uint8_t *buf; - if (!CBB_add_space(cbb, &buf, len)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_MALLOC_FAILURE); - return 0; - } - if (buf != NULL && i2d_X509(x509, &buf) < 0) { - return 0; - } - return 1; -} - -static int ssl_add_cert_with_length(CBB *cbb, X509 *x509) { - CBB child; - return CBB_add_u24_length_prefixed(cbb, &child) && - ssl_add_cert_to_cbb(&child, x509) && - CBB_flush(cbb); -} - int ssl_add_cert_chain(SSL *ssl, CBB *cbb) { if (!ssl_has_certificate(ssl)) { return CBB_add_u24(cbb, 0); } - CBB child; - if (!CBB_add_u24_length_prefixed(cbb, &child) || - !ssl_add_cert_with_length(&child, ssl->cert->x509_leaf)) { - OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); - return 0; + CBB certs; + if (!CBB_add_u24_length_prefixed(cbb, &certs)) { + goto err; } - STACK_OF(X509) *chain = ssl->cert->x509_chain; - for (size_t i = 0; i < sk_X509_num(chain); i++) { - if (!ssl_add_cert_with_length(&child, sk_X509_value(chain, i))) { - return 0; + STACK_OF(CRYPTO_BUFFER) *chain = ssl->cert->chain; + for (size_t i = 0; i < sk_CRYPTO_BUFFER_num(chain); i++) { + CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(chain, i); + CBB child; + if (!CBB_add_u24_length_prefixed(&certs, &child) || + !CBB_add_bytes(&child, CRYPTO_BUFFER_data(buffer), + CRYPTO_BUFFER_len(buffer)) || + !CBB_flush(&certs)) { + goto err; } } return CBB_flush(cbb); + +err: + OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); + return 0; } int ssl_auto_chain_if_needed(SSL *ssl) { @@ -562,30 +650,41 @@ int ssl_auto_chain_if_needed(SSL *ssl) { * isn't disabled. */ if ((ssl->mode & SSL_MODE_NO_AUTO_CHAIN) || !ssl_has_certificate(ssl) || - ssl->cert->x509_chain != NULL) { + ssl->cert->chain == NULL || + sk_CRYPTO_BUFFER_num(ssl->cert->chain) > 1) { return 1; } + X509 *leaf = + X509_parse_from_buffer(sk_CRYPTO_BUFFER_value(ssl->cert->chain, 0)); + if (!leaf) { + OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB); + return 0; + } + X509_STORE_CTX ctx; - if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, ssl->cert->x509_leaf, - NULL)) { + if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, leaf, NULL)) { + X509_free(leaf); OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB); return 0; } /* Attempt to build a chain, ignoring the result. */ X509_verify_cert(&ctx); + X509_free(leaf); ERR_clear_error(); - /* Configure the intermediates from any partial chain we managed to build. */ - for (size_t i = 1; i < sk_X509_num(ctx.chain); i++) { - if (!SSL_add1_chain_cert(ssl, sk_X509_value(ctx.chain, i))) { - X509_STORE_CTX_cleanup(&ctx); - return 0; - } - } + /* Remove the leaf from the generated chain. */ + X509_free(sk_X509_shift(ctx.chain)); + const int ok = ssl_cert_set_chain(ssl->cert, ctx.chain); X509_STORE_CTX_cleanup(&ctx); + if (!ok) { + return 0; + } + + ssl_cert_flush_cached_x509_chain(ssl->cert); + return 1; } @@ -644,6 +743,55 @@ EVP_PKEY *ssl_cert_parse_pubkey(const CBS *in) { return EVP_parse_public_key(&tbs_cert); } +static int ssl_check_cert_and_private_key_match(const CRYPTO_BUFFER *cert, + const EVP_PKEY *privkey) { + CBS cert_cbs; + CRYPTO_BUFFER_init_CBS(cert, &cert_cbs); + EVP_PKEY *pubkey = ssl_cert_parse_pubkey(&cert_cbs); + if (!pubkey) { + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE); + return 0; + } + + int ret = 0; + + switch (EVP_PKEY_cmp(pubkey, privkey)) { + case 1: + ret = 1; + break; + case 0: + OPENSSL_PUT_ERROR(X509, X509_R_KEY_VALUES_MISMATCH); + break; + case -1: + OPENSSL_PUT_ERROR(X509, X509_R_KEY_TYPE_MISMATCH); + break; + case -2: + OPENSSL_PUT_ERROR(X509, X509_R_UNKNOWN_KEY_TYPE); + default: + assert(0); + break; + } + + EVP_PKEY_free(pubkey); + return ret; +} + +int ssl_cert_check_private_key(const CERT *cert, const EVP_PKEY *privkey) { + if (privkey == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED); + return 0; + } + + if (cert->chain == NULL || + sk_CRYPTO_BUFFER_value(cert->chain, 0) == NULL) { + OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED); + return 0; + } + + return ssl_check_cert_and_private_key_match( + sk_CRYPTO_BUFFER_value(cert->chain, 0), privkey); +} + int ssl_cert_check_digital_signature_key_usage(const CBS *in) { CBS buf = *in; @@ -888,7 +1036,61 @@ void SSL_set_cert_cb(SSL *ssl, int (*cb)(SSL *ssl, void *arg), void *arg) { ssl_cert_set_cert_cb(ssl->cert, cb, arg); } +/* ssl_cert_cache_leaf_cert sets |cert->x509_leaf|, if currently NULL, from the + * first element of |cert->chain|. */ +int ssl_cert_cache_leaf_cert(CERT *cert) { + if (cert->x509_leaf != NULL || + cert->chain == NULL) { + return 1; + } + + CRYPTO_BUFFER *leaf = sk_CRYPTO_BUFFER_value(cert->chain, 0); + if (!leaf) { + return 1; + } + + cert->x509_leaf = X509_parse_from_buffer(leaf); + return cert->x509_leaf != NULL; +} + +/* ssl_cert_cache_chain_certs fills in |cert->x509_chain| from elements 1.. of + * |cert->chain|. */ +static int ssl_cert_cache_chain_certs(CERT *cert) { + if (cert->x509_chain != NULL || + cert->chain == NULL || + sk_CRYPTO_BUFFER_num(cert->chain) < 2) { + return 1; + } + + STACK_OF(X509) *chain = sk_X509_new_null(); + if (chain == NULL) { + return 0; + } + + for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(cert->chain); i++) { + CRYPTO_BUFFER *buffer = sk_CRYPTO_BUFFER_value(cert->chain, i); + X509 *x509 = X509_parse_from_buffer(buffer); + if (x509 == NULL || + !sk_X509_push(chain, x509)) { + X509_free(x509); + goto err; + } + } + + cert->x509_chain = chain; + return 1; + +err: + sk_X509_pop_free(chain, X509_free); + return 0; +} + int SSL_CTX_get0_chain_certs(const SSL_CTX *ctx, STACK_OF(X509) **out_chain) { + if (!ssl_cert_cache_chain_certs(ctx->cert)) { + *out_chain = NULL; + return 0; + } + *out_chain = ctx->cert->x509_chain; return 1; } @@ -899,6 +1101,11 @@ int SSL_CTX_get_extra_chain_certs(const SSL_CTX *ctx, } int SSL_get0_chain_certs(const SSL *ssl, STACK_OF(X509) **out_chain) { + if (!ssl_cert_cache_chain_certs(ssl->cert)) { + *out_chain = NULL; + return 0; + } + *out_chain = ssl->cert->x509_chain; return 1; } diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index 101ee4da..a60caf0a 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1272,34 +1272,12 @@ int SSL_pending(const SSL *ssl) { /* Fix this so it checks all the valid key/cert options */ int SSL_CTX_check_private_key(const SSL_CTX *ctx) { - if (ctx->cert->privatekey == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED); - return 0; - } - - X509 *x509 = ctx->cert->x509_leaf; - if (x509 == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED); - return 0; - } - - return X509_check_private_key(x509, ctx->cert->privatekey); + return ssl_cert_check_private_key(ctx->cert, ctx->cert->privatekey); } /* Fix this function so that it takes an optional type parameter */ int SSL_check_private_key(const SSL *ssl) { - if (ssl->cert->privatekey == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_PRIVATE_KEY_ASSIGNED); - return 0; - } - - X509 *x509 = ssl->cert->x509_leaf; - if (x509 == NULL) { - OPENSSL_PUT_ERROR(SSL, SSL_R_NO_CERTIFICATE_ASSIGNED); - return 0; - } - - return X509_check_private_key(x509, ssl->cert->privatekey); + return ssl_cert_check_private_key(ssl->cert, ssl->cert->privatekey); } long SSL_get_default_timeout(const SSL *ssl) { diff --git a/ssl/ssl_rsa.c b/ssl/ssl_rsa.c index 34d1f860..876212dc 100644 --- a/ssl/ssl_rsa.c +++ b/ssl/ssl_rsa.c @@ -134,16 +134,13 @@ static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) { return 0; } - X509 *x509_leaf = c->x509_leaf; - if (x509_leaf != NULL) { - /* Sanity-check that the private key and the certificate match, unless the - * key is opaque (in case of, say, a smartcard). */ - if (!EVP_PKEY_is_opaque(pkey) && - !X509_check_private_key(x509_leaf, pkey)) { - X509_free(c->x509_leaf); - c->x509_leaf = NULL; - return 0; - } + if (c->chain != NULL && + sk_CRYPTO_BUFFER_value(c->chain, 0) != NULL && + /* Sanity-check that the private key and the certificate match, unless + * the key is opaque (in case of, say, a smartcard). */ + !EVP_PKEY_is_opaque(pkey) && + !ssl_cert_check_private_key(c, pkey)) { + return 0; } EVP_PKEY_free(c->privatekey); @@ -154,15 +151,12 @@ static int ssl_set_pkey(CERT *c, EVP_PKEY *pkey) { } int SSL_use_PrivateKey(SSL *ssl, EVP_PKEY *pkey) { - int ret; - if (pkey == NULL) { OPENSSL_PUT_ERROR(SSL, ERR_R_PASSED_NULL_PARAMETER); return 0; } - ret = ssl_set_pkey(ssl->cert, pkey); - return ret; + return ssl_set_pkey(ssl->cert, pkey); } int SSL_use_PrivateKey_ASN1(int type, SSL *ssl, const uint8_t *der, @@ -237,9 +231,31 @@ static int ssl_set_cert(CERT *c, X509 *x) { EVP_PKEY_free(pkey); - X509_free(c->x509_leaf); - X509_up_ref(x); - c->x509_leaf = x; + CRYPTO_BUFFER *buffer = x509_to_buffer(x); + if (!buffer) { + return 0; + } + + ssl_cert_flush_cached_x509_leaf(c); + + if (c->chain != NULL) { + CRYPTO_BUFFER_free(sk_CRYPTO_BUFFER_value(c->chain, 0)); + sk_CRYPTO_BUFFER_set(c->chain, 0, buffer); + return 1; + } + + c->chain = sk_CRYPTO_BUFFER_new_null(); + if (c->chain == NULL) { + CRYPTO_BUFFER_free(buffer); + return 0; + } + + if (!sk_CRYPTO_BUFFER_push(c->chain, buffer)) { + CRYPTO_BUFFER_free(buffer); + sk_CRYPTO_BUFFER_free(c->chain); + c->chain = NULL; + return 0; + } return 1; } diff --git a/ssl/ssl_x509.c b/ssl/ssl_x509.c index 3fc62b7e..5d78deb2 100644 --- a/ssl/ssl_x509.c +++ b/ssl/ssl_x509.c @@ -281,20 +281,21 @@ void SSL_CTX_set_verify_depth(SSL_CTX *ctx, int depth) { X509_VERIFY_PARAM_set_depth(ctx->param, depth); } -X509 *SSL_get_certificate(const SSL *ssl) { - if (ssl->cert != NULL) { - return ssl->cert->x509_leaf; +static X509 *ssl_cert_get0_leaf(CERT *cert) { + if (cert->x509_leaf == NULL && + !ssl_cert_cache_leaf_cert(cert)) { + return NULL; } - return NULL; + return cert->x509_leaf; } -X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) { - if (ctx->cert != NULL) { - return ctx->cert->x509_leaf; - } +X509 *SSL_get_certificate(const SSL *ssl) { + return ssl_cert_get0_leaf(ssl->cert); +} - return NULL; +X509 *SSL_CTX_get0_certificate(const SSL_CTX *ctx) { + return ssl_cert_get0_leaf(ctx->cert); } int SSL_CTX_set_default_verify_paths(SSL_CTX *ctx) { diff --git a/ssl/tls13_both.c b/ssl/tls13_both.c index 4b44f39e..d4c1f1a4 100644 --- a/ssl/tls13_both.c +++ b/ssl/tls13_both.c @@ -453,9 +453,11 @@ int tls13_add_certificate(SSL_HANDSHAKE *hs) { } CERT *cert = ssl->cert; + CRYPTO_BUFFER *leaf_buf = sk_CRYPTO_BUFFER_value(cert->chain, 0); CBB leaf, extensions; if (!CBB_add_u24_length_prefixed(&certificate_list, &leaf) || - !ssl_add_cert_to_cbb(&leaf, cert->x509_leaf) || + !CBB_add_bytes(&leaf, CRYPTO_BUFFER_data(leaf_buf), + CRYPTO_BUFFER_len(leaf_buf)) || !CBB_add_u16_length_prefixed(&certificate_list, &extensions)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); goto err; @@ -489,10 +491,12 @@ int tls13_add_certificate(SSL_HANDSHAKE *hs) { } } - for (size_t i = 0; i < sk_X509_num(cert->x509_chain); i++) { + for (size_t i = 1; i < sk_CRYPTO_BUFFER_num(cert->chain); i++) { + CRYPTO_BUFFER *cert_buf = sk_CRYPTO_BUFFER_value(cert->chain, i); CBB child; if (!CBB_add_u24_length_prefixed(&certificate_list, &child) || - !ssl_add_cert_to_cbb(&child, sk_X509_value(cert->x509_chain, i)) || + !CBB_add_bytes(&child, CRYPTO_BUFFER_data(cert_buf), + CRYPTO_BUFFER_len(cert_buf)) || !CBB_add_u16(&certificate_list, 0 /* no extensions */)) { OPENSSL_PUT_ERROR(SSL, ERR_R_INTERNAL_ERROR); goto err;