diff options
Diffstat (limited to 'crypto/openssl/ssl/ssl_cert.c')
-rw-r--r-- | crypto/openssl/ssl/ssl_cert.c | 241 |
1 files changed, 185 insertions, 56 deletions
diff --git a/crypto/openssl/ssl/ssl_cert.c b/crypto/openssl/ssl/ssl_cert.c index eba96b207eee..2e2d09a32ee4 100644 --- a/crypto/openssl/ssl/ssl_cert.c +++ b/crypto/openssl/ssl/ssl_cert.c @@ -1,8 +1,8 @@ /* - * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2023 The OpenSSL Project Authors. All Rights Reserved. * Copyright (c) 2002, Oracle and/or its affiliates. All rights reserved * - * Licensed under the OpenSSL license (the "License"). You may not use + * Licensed under the Apache License 2.0 (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy * in the file LICENSE in the source distribution or at * https://www.openssl.org/source/license.html @@ -15,6 +15,7 @@ #include "internal/o_dir.h" #include <openssl/bio.h> #include <openssl/pem.h> +#include <openssl/store.h> #include <openssl/x509v3.h> #include <openssl/dh.h> #include <openssl/bn.h> @@ -23,6 +24,16 @@ #include "ssl_local.h" #include "ssl_cert_table.h" #include "internal/thread_once.h" +#ifndef OPENSSL_NO_POSIX_IO +# include <sys/stat.h> +# ifdef _WIN32 +# define stat _stat +# endif +# ifndef S_ISDIR +# define S_ISDIR(a) (((a) & S_IFMT) == S_IFDIR) +# endif +#endif + static int ssl_security_default_callback(const SSL *s, const SSL_CTX *ctx, int op, int bits, int nid, void *other, @@ -52,7 +63,7 @@ CERT *ssl_cert_new(void) CERT *ret = OPENSSL_zalloc(sizeof(*ret)); if (ret == NULL) { - SSLerr(SSL_F_SSL_CERT_NEW, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); return NULL; } @@ -63,7 +74,7 @@ CERT *ssl_cert_new(void) ret->sec_ex = NULL; ret->lock = CRYPTO_THREAD_lock_new(); if (ret->lock == NULL) { - SSLerr(SSL_F_SSL_CERT_NEW, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); OPENSSL_free(ret); return NULL; } @@ -77,7 +88,7 @@ CERT *ssl_cert_dup(CERT *cert) int i; if (ret == NULL) { - SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); return NULL; } @@ -85,18 +96,18 @@ CERT *ssl_cert_dup(CERT *cert) ret->key = &ret->pkeys[cert->key - cert->pkeys]; ret->lock = CRYPTO_THREAD_lock_new(); if (ret->lock == NULL) { - SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); OPENSSL_free(ret); return NULL; } -#ifndef OPENSSL_NO_DH + if (cert->dh_tmp != NULL) { ret->dh_tmp = cert->dh_tmp; EVP_PKEY_up_ref(ret->dh_tmp); } + ret->dh_tmp_cb = cert->dh_tmp_cb; ret->dh_tmp_auto = cert->dh_tmp_auto; -#endif for (i = 0; i < SSL_PKEY_NUM; i++) { CERT_PKEY *cpk = cert->pkeys + i; @@ -114,7 +125,7 @@ CERT *ssl_cert_dup(CERT *cert) if (cpk->chain) { rpk->chain = X509_chain_up_ref(cpk->chain); if (!rpk->chain) { - SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); goto err; } } @@ -123,7 +134,7 @@ CERT *ssl_cert_dup(CERT *cert) ret->pkeys[i].serverinfo = OPENSSL_malloc(cert->pkeys[i].serverinfo_length); if (ret->pkeys[i].serverinfo == NULL) { - SSLerr(SSL_F_SSL_CERT_DUP, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); goto err; } ret->pkeys[i].serverinfo_length = cert->pkeys[i].serverinfo_length; @@ -231,9 +242,7 @@ void ssl_cert_free(CERT *c) return; REF_ASSERT_ISNT(i < 0); -#ifndef OPENSSL_NO_DH EVP_PKEY_free(c->dh_tmp); -#endif ssl_cert_clear_certs(c); OPENSSL_free(c->conf_sigalgs); @@ -252,13 +261,16 @@ void ssl_cert_free(CERT *c) int ssl_cert_set0_chain(SSL *s, SSL_CTX *ctx, STACK_OF(X509) *chain) { int i, r; - CERT_PKEY *cpk = s ? s->cert->key : ctx->cert->key; + CERT_PKEY *cpk = s != NULL ? s->cert->key : ctx->cert->key; + if (!cpk) return 0; for (i = 0; i < sk_X509_num(chain); i++) { - r = ssl_security_cert(s, ctx, sk_X509_value(chain, i), 0, 0); + X509 *x = sk_X509_value(chain, i); + + r = ssl_security_cert(s, ctx, x, 0, 0); if (r != 1) { - SSLerr(SSL_F_SSL_CERT_SET0_CHAIN, r); + ERR_raise(ERR_LIB_SSL, r); return 0; } } @@ -290,7 +302,7 @@ int ssl_cert_add0_chain_cert(SSL *s, SSL_CTX *ctx, X509 *x) return 0; r = ssl_security_cert(s, ctx, x, 0, 0); if (r != 1) { - SSLerr(SSL_F_SSL_CERT_ADD0_CHAIN_CERT, r); + ERR_raise(ERR_LIB_SSL, r); return 0; } if (!cpk->chain) @@ -360,6 +372,13 @@ void ssl_cert_set_cert_cb(CERT *c, int (*cb) (SSL *ssl, void *arg), void *arg) c->cert_cb_arg = arg; } +/* + * Verify a certificate chain + * Return codes: + * 1: Verify success + * 0: Verify failure or error + * -1: Retry required + */ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) { X509 *x; @@ -376,15 +395,15 @@ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) else verify_store = s->ctx->cert_store; - ctx = X509_STORE_CTX_new(); + ctx = X509_STORE_CTX_new_ex(s->ctx->libctx, s->ctx->propq); if (ctx == NULL) { - SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); return 0; } x = sk_X509_value(sk, 0); if (!X509_STORE_CTX_init(ctx, verify_store, x, sk)) { - SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN, ERR_R_X509_LIB); + ERR_raise(ERR_LIB_SSL, ERR_R_X509_LIB); goto end; } param = X509_STORE_CTX_get0_param(ctx); @@ -421,10 +440,14 @@ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) if (s->verify_callback) X509_STORE_CTX_set_verify_cb(ctx, s->verify_callback); - if (s->ctx->app_verify_callback != NULL) + if (s->ctx->app_verify_callback != NULL) { i = s->ctx->app_verify_callback(ctx, s->ctx->app_verify_arg); - else + } else { i = X509_verify_cert(ctx); + /* We treat an error in the same way as a failure to verify */ + if (i < 0) + i = 0; + } s->verify_result = X509_STORE_CTX_get_error(ctx); sk_X509_pop_free(s->verified_chain, X509_free); @@ -432,7 +455,7 @@ int ssl_verify_cert_chain(SSL *s, STACK_OF(X509) *sk) if (X509_STORE_CTX_get0_chain(ctx) != NULL) { s->verified_chain = X509_STORE_CTX_get1_chain(ctx); if (s->verified_chain == NULL) { - SSLerr(SSL_F_SSL_VERIFY_CERT_CHAIN, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); i = 0; } } @@ -461,13 +484,13 @@ STACK_OF(X509_NAME) *SSL_dup_CA_list(const STACK_OF(X509_NAME) *sk) ret = sk_X509_NAME_new_reserve(NULL, num); if (ret == NULL) { - SSLerr(SSL_F_SSL_DUP_CA_LIST, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); return NULL; } for (i = 0; i < num; i++) { name = X509_NAME_dup(sk_X509_NAME_value(sk, i)); if (name == NULL) { - SSLerr(SSL_F_SSL_DUP_CA_LIST, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); sk_X509_NAME_pop_free(ret, X509_NAME_free); return NULL; } @@ -513,13 +536,13 @@ void SSL_set_client_CA_list(SSL *s, STACK_OF(X509_NAME) *name_list) const STACK_OF(X509_NAME) *SSL_get0_peer_CA_list(const SSL *s) { - return s->s3 != NULL ? s->s3->tmp.peer_ca_names : NULL; + return s->s3.tmp.peer_ca_names; } STACK_OF(X509_NAME) *SSL_get_client_CA_list(const SSL *s) { if (!s->server) - return s->s3 != NULL ? s->s3->tmp.peer_ca_names : NULL; + return s->s3.tmp.peer_ca_names; return s->client_ca_names != NULL ? s->client_ca_names : s->ctx->client_ca_names; } @@ -598,32 +621,43 @@ static int xname_sk_cmp(const X509_NAME *const *a, const X509_NAME *const *b) static unsigned long xname_hash(const X509_NAME *a) { - return X509_NAME_hash((X509_NAME *)a); + /* This returns 0 also if SHA1 is not available */ + return X509_NAME_hash_ex((X509_NAME *)a, NULL, NULL, NULL); } -STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) +STACK_OF(X509_NAME) *SSL_load_client_CA_file_ex(const char *file, + OSSL_LIB_CTX *libctx, + const char *propq) { BIO *in = BIO_new(BIO_s_file()); X509 *x = NULL; X509_NAME *xn = NULL; STACK_OF(X509_NAME) *ret = NULL; LHASH_OF(X509_NAME) *name_hash = lh_X509_NAME_new(xname_hash, xname_cmp); + OSSL_LIB_CTX *prev_libctx = NULL; if ((name_hash == NULL) || (in == NULL)) { - SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); goto err; } - if (!BIO_read_filename(in, file)) + x = X509_new_ex(libctx, propq); + if (x == NULL) { + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); + goto err; + } + if (BIO_read_filename(in, file) <= 0) goto err; + /* Internally lh_X509_NAME_retrieve() needs the libctx to retrieve SHA1 */ + prev_libctx = OSSL_LIB_CTX_set0_default(libctx); for (;;) { if (PEM_read_bio_X509(in, &x, NULL, NULL) == NULL) break; if (ret == NULL) { ret = sk_X509_NAME_new_null(); if (ret == NULL) { - SSLerr(SSL_F_SSL_LOAD_CLIENT_CA_FILE, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); goto err; } } @@ -650,6 +684,8 @@ STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) sk_X509_NAME_pop_free(ret, X509_NAME_free); ret = NULL; done: + /* restore the old libctx */ + OSSL_LIB_CTX_set0_default(prev_libctx); BIO_free(in); X509_free(x); lh_X509_NAME_free(name_hash); @@ -658,6 +694,11 @@ STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) return ret; } +STACK_OF(X509_NAME) *SSL_load_client_CA_file(const char *file) +{ + return SSL_load_client_CA_file_ex(file, NULL, NULL); +} + int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, const char *file) { @@ -672,11 +713,11 @@ int SSL_add_file_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, in = BIO_new(BIO_s_file()); if (in == NULL) { - SSLerr(SSL_F_SSL_ADD_FILE_CERT_SUBJECTS_TO_STACK, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); goto err; } - if (!BIO_read_filename(in, file)) + if (BIO_read_filename(in, file) <= 0) goto err; for (;;) { @@ -720,10 +761,16 @@ int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, while ((filename = OPENSSL_DIR_read(&d, dir))) { char buf[1024]; int r; +#ifndef OPENSSL_NO_POSIX_IO + struct stat st; +#else + /* Cannot use stat so just skip current and parent directories */ + if (strcmp(filename, ".") == 0 || strcmp(filename, "..") == 0) + continue; +#endif if (strlen(dir) + strlen(filename) + 2 > sizeof(buf)) { - SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK, - SSL_R_PATH_TOO_LONG); + ERR_raise(ERR_LIB_SSL, SSL_R_PATH_TOO_LONG); goto err; } #ifdef OPENSSL_SYS_VMS @@ -731,6 +778,11 @@ int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, #else r = BIO_snprintf(buf, sizeof(buf), "%s/%s", dir, filename); #endif +#ifndef OPENSSL_NO_POSIX_IO + /* Skip subdirectories */ + if (!stat(buf, &st) && S_ISDIR(st.st_mode)) + continue; +#endif if (r <= 0 || r >= (int)sizeof(buf)) goto err; if (!SSL_add_file_cert_subjects_to_stack(stack, buf)) @@ -738,9 +790,9 @@ int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, } if (errno) { - SYSerr(SYS_F_OPENDIR, get_last_sys_error()); - ERR_add_error_data(3, "OPENSSL_DIR_read(&ctx, '", dir, "')"); - SSLerr(SSL_F_SSL_ADD_DIR_CERT_SUBJECTS_TO_STACK, ERR_R_SYS_LIB); + ERR_raise_data(ERR_LIB_SYS, get_last_sys_error(), + "calling OPENSSL_dir_read(%s)", dir); + ERR_raise(ERR_LIB_SSL, ERR_R_SYS_LIB); goto err; } @@ -753,6 +805,71 @@ int SSL_add_dir_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, return ret; } +static int add_uris_recursive(STACK_OF(X509_NAME) *stack, + const char *uri, int depth) +{ + int ok = 1; + OSSL_STORE_CTX *ctx = NULL; + X509 *x = NULL; + X509_NAME *xn = NULL; + + if ((ctx = OSSL_STORE_open(uri, NULL, NULL, NULL, NULL)) == NULL) + goto err; + + while (!OSSL_STORE_eof(ctx) && !OSSL_STORE_error(ctx)) { + OSSL_STORE_INFO *info = OSSL_STORE_load(ctx); + int infotype = info == 0 ? 0 : OSSL_STORE_INFO_get_type(info); + + if (info == NULL) + continue; + + if (infotype == OSSL_STORE_INFO_NAME) { + /* + * This is an entry in the "directory" represented by the current + * uri. if |depth| allows, dive into it. + */ + if (depth > 0) + ok = add_uris_recursive(stack, OSSL_STORE_INFO_get0_NAME(info), + depth - 1); + } else if (infotype == OSSL_STORE_INFO_CERT) { + if ((x = OSSL_STORE_INFO_get0_CERT(info)) == NULL + || (xn = X509_get_subject_name(x)) == NULL + || (xn = X509_NAME_dup(xn)) == NULL) + goto err; + if (sk_X509_NAME_find(stack, xn) >= 0) { + /* Duplicate. */ + X509_NAME_free(xn); + } else if (!sk_X509_NAME_push(stack, xn)) { + X509_NAME_free(xn); + goto err; + } + } + + OSSL_STORE_INFO_free(info); + } + + ERR_clear_error(); + goto done; + + err: + ok = 0; + done: + OSSL_STORE_close(ctx); + + return ok; +} + +int SSL_add_store_cert_subjects_to_stack(STACK_OF(X509_NAME) *stack, + const char *store) +{ + int (*oldcmp) (const X509_NAME *const *a, const X509_NAME *const *b) + = sk_X509_NAME_set_cmp_func(stack, xname_sk_cmp); + int ret = add_uris_recursive(stack, store, 1); + + (void)sk_X509_NAME_set_cmp_func(stack, oldcmp); + return ret; +} + /* Build a certificate chain for current certificate */ int ssl_build_cert_chain(SSL *s, SSL_CTX *ctx, int flags) { @@ -762,10 +879,11 @@ int ssl_build_cert_chain(SSL *s, SSL_CTX *ctx, int flags) X509_STORE_CTX *xs_ctx = NULL; STACK_OF(X509) *chain = NULL, *untrusted = NULL; X509 *x; + SSL_CTX *real_ctx = (s == NULL) ? ctx : s->ctx; int i, rv = 0; if (!cpk->x509) { - SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, SSL_R_NO_CERTIFICATE_SET); + ERR_raise(ERR_LIB_SSL, SSL_R_NO_CERTIFICATE_SET); goto err; } /* Rearranging and check the chain: add everything to a store */ @@ -793,13 +911,13 @@ int ssl_build_cert_chain(SSL *s, SSL_CTX *ctx, int flags) untrusted = cpk->chain; } - xs_ctx = X509_STORE_CTX_new(); + xs_ctx = X509_STORE_CTX_new_ex(real_ctx->libctx, real_ctx->propq); if (xs_ctx == NULL) { - SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, ERR_R_MALLOC_FAILURE); + ERR_raise(ERR_LIB_SSL, ERR_R_MALLOC_FAILURE); goto err; } if (!X509_STORE_CTX_init(xs_ctx, chain_store, cpk->x509, untrusted)) { - SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, ERR_R_X509_LIB); + ERR_raise(ERR_LIB_SSL, ERR_R_X509_LIB); goto err; } /* Set suite B flags if needed */ @@ -816,10 +934,9 @@ int ssl_build_cert_chain(SSL *s, SSL_CTX *ctx, int flags) if (i > 0) chain = X509_STORE_CTX_get1_chain(xs_ctx); if (i <= 0) { - SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, SSL_R_CERTIFICATE_VERIFY_FAILED); i = X509_STORE_CTX_get_error(xs_ctx); - ERR_add_error_data(2, "Verify error:", - X509_verify_cert_error_string(i)); + ERR_raise_data(ERR_LIB_SSL, SSL_R_CERTIFICATE_VERIFY_FAILED, + "Verify error:%s", X509_verify_cert_error_string(i)); goto err; } @@ -844,7 +961,7 @@ int ssl_build_cert_chain(SSL *s, SSL_CTX *ctx, int flags) x = sk_X509_value(chain, i); rv = ssl_security_cert(s, ctx, x, 0, 0); if (rv != 1) { - SSLerr(SSL_F_SSL_BUILD_CERT_CHAIN, rv); + ERR_raise(ERR_LIB_SSL, rv); sk_X509_pop_free(chain, X509_free); rv = 0; goto err; @@ -876,9 +993,20 @@ int ssl_cert_set_cert_store(CERT *c, X509_STORE *store, int chain, int ref) return 1; } +int ssl_cert_get_cert_store(CERT *c, X509_STORE **pstore, int chain) +{ + *pstore = (chain ? c->chain_store : c->verify_store); + return 1; +} + int ssl_get_security_level_bits(const SSL *s, const SSL_CTX *ctx, int *levelp) { int level; + /* + * note that there's a corresponding minbits_table + * in crypto/x509/x509_vfy.c that's used for checking the security level + * of RSA and DSA keys + */ static const int minbits_table[5 + 1] = { 0, 80, 112, 128, 192, 256 }; if (ctx != NULL) @@ -1002,19 +1130,20 @@ int ssl_cert_lookup_by_nid(int nid, size_t *pidx) const SSL_CERT_LOOKUP *ssl_cert_lookup_by_pkey(const EVP_PKEY *pk, size_t *pidx) { - int nid = EVP_PKEY_id(pk); - size_t tmpidx; - - if (nid == NID_undef) - return NULL; + size_t i; - if (!ssl_cert_lookup_by_nid(nid, &tmpidx)) - return NULL; + for (i = 0; i < OSSL_NELEM(ssl_cert_info); i++) { + const SSL_CERT_LOOKUP *tmp_lu = &ssl_cert_info[i]; - if (pidx != NULL) - *pidx = tmpidx; + if (EVP_PKEY_is_a(pk, OBJ_nid2sn(tmp_lu->nid)) + || EVP_PKEY_is_a(pk, OBJ_nid2ln(tmp_lu->nid))) { + if (pidx != NULL) + *pidx = i; + return tmp_lu; + } + } - return &ssl_cert_info[tmpidx]; + return NULL; } const SSL_CERT_LOOKUP *ssl_cert_lookup_by_idx(size_t idx) |