diff --git a/crypto/x509/x509_lu.c b/crypto/x509/x509_lu.c index bfe6b11b..ec3f300b 100644 --- a/crypto/x509/x509_lu.c +++ b/crypto/x509/x509_lu.c @@ -217,6 +217,11 @@ X509_STORE *X509_STORE_new(void) return NULL; } +void X509_STORE_up_ref(X509_STORE *store) +{ + CRYPTO_refcount_inc(&store->references); +} + static void cleanup(X509_OBJECT *a) { if (a == NULL) { diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h index 158c72d5..a21b6ee2 100644 --- a/include/openssl/ssl.h +++ b/include/openssl/ssl.h @@ -2065,6 +2065,28 @@ OPENSSL_EXPORT int SSL_enable_ocsp_stapling(SSL *ssl); * handshake. */ OPENSSL_EXPORT void SSL_CTX_enable_ocsp_stapling(SSL_CTX *ctx); +/* SSL_CTX_set0_verify_cert_store sets an |X509_STORE| that will be used + * exclusively for certificate verification and returns one. Ownership of + * |store| is transferred to the |SSL_CTX|. */ +OPENSSL_EXPORT int SSL_CTX_set0_verify_cert_store(SSL_CTX *ctx, + X509_STORE *store); + +/* SSL_CTX_set1_verify_cert_store sets an |X509_STORE| that will be used + * exclusively for certificate verification and returns one. An additional + * reference to |store| will be taken. */ +OPENSSL_EXPORT int SSL_CTX_set1_verify_cert_store(SSL_CTX *ctx, + X509_STORE *store); + +/* SSL_set0_verify_cert_store sets an |X509_STORE| that will be used + * exclusively for certificate verification and returns one. Ownership of + * |store| is transferred to the |SSL|. */ +OPENSSL_EXPORT int SSL_set0_verify_cert_store(SSL *ssl, X509_STORE *store); + +/* SSL_set1_verify_cert_store sets an |X509_STORE| that will be used + * exclusively for certificate verification and returns one. An additional + * reference to |store| will be taken. */ +OPENSSL_EXPORT int SSL_set1_verify_cert_store(SSL *ssl, X509_STORE *store); + /* Client certificate CA list. * diff --git a/include/openssl/x509_vfy.h b/include/openssl/x509_vfy.h index bd7ded76..a9d05195 100644 --- a/include/openssl/x509_vfy.h +++ b/include/openssl/x509_vfy.h @@ -436,6 +436,7 @@ OPENSSL_EXPORT X509_OBJECT *X509_OBJECT_retrieve_match(STACK_OF(X509_OBJECT) *h, OPENSSL_EXPORT void X509_OBJECT_up_ref_count(X509_OBJECT *a); OPENSSL_EXPORT void X509_OBJECT_free_contents(X509_OBJECT *a); OPENSSL_EXPORT X509_STORE *X509_STORE_new(void ); +OPENSSL_EXPORT void X509_STORE_up_ref(X509_STORE *store); OPENSSL_EXPORT void X509_STORE_free(X509_STORE *v); OPENSSL_EXPORT STACK_OF(X509)* X509_STORE_get1_certs(X509_STORE_CTX *st, X509_NAME *nm); diff --git a/ssl/internal.h b/ssl/internal.h index 03240613..982f3040 100644 --- a/ssl/internal.h +++ b/ssl/internal.h @@ -803,6 +803,10 @@ typedef struct cert_st { * supported signature algorithms or curves. */ int (*cert_cb)(SSL *ssl, void *arg); void *cert_cb_arg; + + /* Optional X509_STORE for certificate validation. If NULL the parent SSL_CTX + * store is used instead. */ + X509_STORE *verify_store; } CERT; /* SSL_METHOD is a compatibility structure to support the legacy version-locked diff --git a/ssl/ssl_cert.c b/ssl/ssl_cert.c index 983e1a7b..28a33c95 100644 --- a/ssl/ssl_cert.c +++ b/ssl/ssl_cert.c @@ -188,6 +188,11 @@ CERT *ssl_cert_dup(CERT *cert) { ret->cert_cb = cert->cert_cb; ret->cert_cb_arg = cert->cert_cb_arg; + if (cert->verify_store != NULL) { + X509_STORE_up_ref(cert->verify_store); + ret->verify_store = cert->verify_store; + } + return ret; err: @@ -220,6 +225,7 @@ void ssl_cert_free(CERT *c) { ssl_cert_clear_certs(c); OPENSSL_free(c->peer_sigalgs); OPENSSL_free(c->digest_nids); + X509_STORE_free(c->verify_store); OPENSSL_free(c); } @@ -279,10 +285,15 @@ int ssl_verify_cert_chain(SSL *ssl, STACK_OF(X509) *cert_chain) { return 0; } + X509_STORE *verify_store = ssl->ctx->cert_store; + if (ssl->cert->verify_store != NULL) { + verify_store = ssl->cert->verify_store; + } + X509 *leaf = sk_X509_value(cert_chain, 0); int ret = 0; X509_STORE_CTX ctx; - if (!X509_STORE_CTX_init(&ctx, ssl->ctx->cert_store, leaf, cert_chain)) { + if (!X509_STORE_CTX_init(&ctx, verify_store, leaf, cert_chain)) { OPENSSL_PUT_ERROR(SSL, ERR_R_X509_LIB); return 0; } @@ -475,6 +486,33 @@ int ssl_add_cert_chain(SSL *ssl, unsigned long *l) { return 1; } +static int set_cert_store(X509_STORE **store_ptr, X509_STORE *new_store, int take_ref) { + X509_STORE_free(*store_ptr); + *store_ptr = new_store; + + if (new_store != NULL && take_ref) { + X509_STORE_up_ref(new_store); + } + + return 1; +} + +int SSL_CTX_set0_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) { + return set_cert_store(&ctx->cert->verify_store, store, 0); +} + +int SSL_CTX_set1_verify_cert_store(SSL_CTX *ctx, X509_STORE *store) { + return set_cert_store(&ctx->cert->verify_store, store, 1); +} + +int SSL_set0_verify_cert_store(SSL *ssl, X509_STORE *store) { + return set_cert_store(&ssl->cert->verify_store, store, 0); +} + +int SSL_set1_verify_cert_store(SSL *ssl, X509_STORE *store) { + return set_cert_store(&ssl->cert->verify_store, store, 1); +} + int SSL_CTX_set0_chain(SSL_CTX *ctx, STACK_OF(X509) *chain) { return ssl_cert_set0_chain(ctx->cert, chain); }