diff options
author | Dr. David von Oheimb <David.von.Oheimb@siemens.com> | 2021-01-28 00:28:25 +0100 |
---|---|---|
committer | Dr. David von Oheimb <dev@ddvo.net> | 2021-02-06 18:53:51 +0100 |
commit | 11ddbf84597d26c937ecb8f266424dea7f72cbdf (patch) | |
tree | cb23d927c8c8b85f6ca4947a313b0fe7fb36a07c | |
parent | 2bb05a9668323ac2719f84cf8e9ccffc2bc99916 (diff) |
Add X509_STORE_CTX_verify(), which takes the first untrusted cert as default target
Reviewed-by: Tomas Mraz <tomas@openssl.org>
(Merged from https://github.com/openssl/openssl/pull/14021)
-rw-r--r-- | crypto/x509/x509_vfy.c | 18 | ||||
-rw-r--r-- | doc/man3/X509_STORE_CTX_get_error.pod | 12 | ||||
-rw-r--r-- | doc/man3/X509_STORE_CTX_new.pod | 44 | ||||
-rw-r--r-- | doc/man3/X509_verify_cert.pod | 41 | ||||
-rw-r--r-- | include/openssl/x509.h.in | 2 | ||||
-rw-r--r-- | include/openssl/x509_vfy.h.in | 3 | ||||
-rw-r--r-- | test/danetest.c | 6 | ||||
-rw-r--r-- | util/libcrypto.num | 1 |
8 files changed, 79 insertions, 48 deletions
diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index ec7df5caa6..d55808e524 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -237,11 +237,25 @@ static int verify_chain(X509_STORE_CTX *ctx) return ok; } +int X509_STORE_CTX_verify(X509_STORE_CTX *ctx) +{ + if (ctx == NULL) { + ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER); + return -1; + } + if (ctx->cert == NULL && sk_X509_num(ctx->untrusted) >= 1) + ctx->cert = sk_X509_value(ctx->untrusted, 0); + return X509_verify_cert(ctx); +} + int X509_verify_cert(X509_STORE_CTX *ctx) { - SSL_DANE *dane = ctx->dane; int ret; + if (ctx == NULL) { + ERR_raise(ERR_LIB_X509, ERR_R_PASSED_NULL_PARAMETER); + return -1; + } if (ctx->cert == NULL) { ERR_raise(ERR_LIB_X509, X509_R_NO_CERT_SET_FOR_US_TO_VERIFY); ctx->error = X509_V_ERR_INVALID_CALL; @@ -268,7 +282,7 @@ int X509_verify_cert(X509_STORE_CTX *ctx) CB_FAIL_IF(!check_key_level(ctx, ctx->cert), ctx, ctx->cert, 0, X509_V_ERR_EE_KEY_TOO_SMALL); - ret = DANETLS_ENABLED(dane) ? dane_verify(ctx) : verify_chain(ctx); + ret = DANETLS_ENABLED(ctx->dane) ? dane_verify(ctx) : verify_chain(ctx); /* * Safety-net. If we are returning an error, we must also set ctx->error, diff --git a/doc/man3/X509_STORE_CTX_get_error.pod b/doc/man3/X509_STORE_CTX_get_error.pod index e6a6b6b0ca..8d0e2ad2dc 100644 --- a/doc/man3/X509_STORE_CTX_get_error.pod +++ b/doc/man3/X509_STORE_CTX_get_error.pod @@ -27,7 +27,8 @@ information =head1 DESCRIPTION -These functions are typically called after X509_verify_cert() has indicated +These functions are typically called after certificate or chain verification +using L<X509_verify_cert(3)> or L<X509_STORE_CTX_verify(3)> has indicated an error or in a verification callback to determine the nature of an error. X509_STORE_CTX_get_error() returns the error code of B<ctx>, see @@ -65,10 +66,9 @@ X509_STORE_CTX_get0_cert() retrieves an internal pointer to the certificate being verified by the B<ctx>. X509_STORE_CTX_get1_chain() returns a complete validate chain if a previous -call to X509_verify_cert() is successful. If the call to X509_verify_cert() -is B<not> successful the returned chain may be incomplete or invalid. The -returned chain persists after the B<ctx> structure is freed, when it is -no longer needed it should be free up using: +verification is successful. Otherwise the returned chain may be incomplete or +invalid. The returned chain persists after the B<ctx> structure is freed, +when it is no longer needed it should be free up using: sk_X509_pop_free(chain, X509_free); @@ -459,7 +459,7 @@ thread safe but will never happen unless an invalid code is passed. =head1 SEE ALSO -L<X509_verify_cert(3)>, +L<X509_verify_cert(3)>, L<X509_STORE_CTX_verify(3)>, L<X509_up_ref(3)>, L<X509_free(3)>. diff --git a/doc/man3/X509_STORE_CTX_new.pod b/doc/man3/X509_STORE_CTX_new.pod index b5ef577310..e98dcc7cfa 100644 --- a/doc/man3/X509_STORE_CTX_new.pod +++ b/doc/man3/X509_STORE_CTX_new.pod @@ -23,8 +23,8 @@ X509_STORE_CTX_verify_fn void X509_STORE_CTX_cleanup(X509_STORE_CTX *ctx); void X509_STORE_CTX_free(X509_STORE_CTX *ctx); - int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *store, - X509 *x509, STACK_OF(X509) *chain); + int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *trust_store, + X509 *target, STACK_OF(X509) *untrusted); void X509_STORE_CTX_set0_trusted_stack(X509_STORE_CTX *ctx, STACK_OF(X509) *sk); @@ -48,7 +48,7 @@ X509_STORE_CTX_verify_fn =head1 DESCRIPTION These functions initialise an B<X509_STORE_CTX> structure for subsequent use -by X509_verify_cert(). +by L<X509_verify_cert(3)> or L<X509_STORE_CTX_verify(3)>. X509_STORE_CTX_new_ex() returns a newly initialised B<X509_STORE_CTX> structure associated with the specified library context I<libctx> and property @@ -67,22 +67,31 @@ is no longer valid. If I<ctx> is NULL nothing is done. X509_STORE_CTX_init() sets up I<ctx> for a subsequent verification operation. -It must be called before each call to X509_verify_cert(), i.e. a I<ctx> is only -good for one call to X509_verify_cert(); if you want to verify a second -certificate with the same I<ctx> then you must call X509_STORE_CTX_cleanup() +It must be called before each call to L<X509_verify_cert(3)>, i.e., a I<ctx> is +only good for one verification; if you want to verify a second certificate +or chain with the same I<ctx> then you must call X509_STORE_CTX_cleanup() and then X509_STORE_CTX_init() again before the second call to -X509_verify_cert(). The trusted certificate store is set to I<store>, the end -entity certificate to be verified is set to I<x509> and a set of additional -certificates (which will be untrusted but may be used to build the chain) in -I<chain>. Any or all of the I<store>, I<x509> and I<chain> parameters can be -B<NULL>. +L<X509_verify_cert(3)> or L<X509_STORE_CTX_verify(3)>. +The trusted certificate store is set to I<trust_store> of type B<X509_STORE>. +This may be NULL because there are no trusted certificates or because +they are provided simply as a list using X509_STORE_CTX_set0_trusted_stack(). +The end entity certificate to be verified is set to I<target>, +and a list of additional certificates may be provided in I<untrusted>, +which will not be trusted but may be used to build the chain. +Each of the I<trust_store>, I<target> and I<untrusted> parameters can be +B<NULL>. Yet note that L<X509_verify_cert(3)> and L<X509_STORE_CTX_verify(3)> +will need a verification target. +This can also be set using X509_STORE_CTX_set_cert(). +For L<X509_STORE_CTX_verify(3)>, which takes by default the first element of the +list of untrusted certificates as its verification target, +this can be also set indirectly using X509_STORE_CTX_set0_untrusted(). X509_STORE_CTX_set0_trusted_stack() sets the set of trusted certificates of I<ctx> to I<sk>. This is an alternative way of specifying trusted certificates instead of using an B<X509_STORE>. -X509_STORE_CTX_set_cert() sets the certificate to be verified in I<ctx> to -I<x>. +X509_STORE_CTX_set_cert() sets the target certificate to be verified in I<ctx> +to I<x>. X509_STORE_CTX_set0_verified_chain() sets the validated chain used by I<ctx> to be I<chain>. @@ -103,8 +112,10 @@ to the verification parameters associated with I<ctx>. X509_STORE_CTX_get0_untrusted() retrieves an internal pointer to the stack of untrusted certificates associated with I<ctx>. -X509_STORE_CTX_set0_untrusted() sets the internal point to the stack +X509_STORE_CTX_set0_untrusted() sets the internal pointer to the stack of untrusted certificates associated with I<ctx> to I<sk>. +X509_STORE_CTX_verify() will take the first element, if any, +as its default target if the target certificate is not set explicitly. X509_STORE_CTX_set0_param() sets the internal verification parameter pointer to I<param>. After this call B<param> should not be used. @@ -114,7 +125,8 @@ method to I<name>. This uses the function X509_VERIFY_PARAM_lookup() to find an appropriate set of parameters from I<name>. X509_STORE_CTX_get_num_untrusted() returns the number of untrusted certificates -that were used in building the chain following a call to X509_verify_cert(). +that were used in building the chain following a call to L<X509_verify_cert(3)>. +With L<X509_STORE_CTX_verify(3)>, this does not count the first chain element. X509_STORE_CTX_set_verify() provides the capability for overriding the default verify function. This function is responsible for verifying chain signatures and @@ -162,7 +174,7 @@ used. =head1 SEE ALSO -L<X509_verify_cert(3)> +L<X509_verify_cert(3)>, L<X509_STORE_CTX_verify(3)>, L<X509_VERIFY_PARAM_set_flags(3)> =head1 HISTORY diff --git a/doc/man3/X509_verify_cert.pod b/doc/man3/X509_verify_cert.pod index c60d27ac12..13854f5ed6 100644 --- a/doc/man3/X509_verify_cert.pod +++ b/doc/man3/X509_verify_cert.pod @@ -2,22 +2,25 @@ =head1 NAME -X509_verify_cert - discover and verify X509 certificate chain +X509_verify_cert, +X509_STORE_CTX_verify - discover and verify X509 certificate chain =head1 SYNOPSIS - #include <openssl/x509.h> + #include <openssl/x509_vfy.h> int X509_verify_cert(X509_STORE_CTX *ctx); + int X509_STORE_CTX_verify(X509_STORE_CTX *ctx); =head1 DESCRIPTION The X509_verify_cert() function attempts to discover and validate a -certificate chain based on parameters in B<ctx>. +certificate chain based on parameters in I<ctx>. The verification context, of type B<X509_STORE_CTX>, can be constructed using L<X509_STORE_CTX_new(3)> and L<X509_STORE_CTX_init(3)>. -It usually includes a set of certificates serving as trust anchors, -a set of non-trusted certificates that may be needed for chain construction, +It usually includes a target certificate to be verified, +a set of certificates serving as trust anchors, +a list of non-trusted certificates that may be helpful for chain construction, flags such as X509_V_FLAG_X509_STRICT, and various other optional components such as a callback function that allows customizing the verification outcome. A complete description of the certificate verification process is contained in @@ -28,33 +31,35 @@ OpenSSL internally for certificate validation, in both the S/MIME and SSL/TLS code. A negative return value from X509_verify_cert() can occur if it is invoked -incorrectly, such as with no certificate set in B<ctx>, or when it is called -twice in succession without reinitialising B<ctx> for the second call. +incorrectly, such as with no certificate set in I<ctx>, or when it is called +twice in succession without reinitialising I<ctx> for the second call. A negative return value can also happen due to internal resource problems or if a retry operation is requested during internal lookups (which never happens with standard lookup methods). Applications must check for <= 0 return value on error. -=head1 RETURN VALUES - -If a complete chain can be built and validated this function returns 1, -otherwise it return zero, in exceptional circumstances it can also -return a negative code. +The X509_STORE_CTX_verify() behaves like X509_verify_cert() except that its +target certificate is the first element of the list of untrusted certificates +in I<ctx> unless a target certificate is set explicitly. -If the function fails additional error information can be obtained by -examining B<ctx> using, for example L<X509_STORE_CTX_get_error(3)>. +=head1 RETURN VALUES -=head1 BUGS +Both functions return 1 if a complete chain can be built and validated, +otherwise they return 0, and in exceptional circumstances (such as malloc +failure and internal errors) they can also return a negative code. -This function uses the header F<< <openssl/x509.h> >> -as opposed to most chain verification -functions which use F<< <openssl/x509_vfy.h> >>. +On error or failure additional error information can be obtained by +examining I<ctx> using, for example, L<X509_STORE_CTX_get_error(3)>. =head1 SEE ALSO L<X509_STORE_CTX_new(3)>, L<X509_STORE_CTX_init(3)>, L<X509_STORE_CTX_get_error(3)> +=head1 HISTORY + +X509_STORE_CTX_verify() was added in OpenSSL 3.0. + =head1 COPYRIGHT Copyright 2009-2021 The OpenSSL Project Authors. All Rights Reserved. diff --git a/include/openssl/x509.h.in b/include/openssl/x509.h.in index 7aef798e5b..7fc1558b18 100644 --- a/include/openssl/x509.h.in +++ b/include/openssl/x509.h.in @@ -1042,8 +1042,6 @@ int EVP_PKEY_add1_attr_by_txt(EVP_PKEY *key, const char *attrname, int type, const unsigned char *bytes, int len); -int X509_verify_cert(X509_STORE_CTX *ctx); - /* lookup a cert from a X509 STACK */ X509 *X509_find_by_issuer_and_serial(STACK_OF(X509) *sk, const X509_NAME *name, const ASN1_INTEGER *serial); diff --git a/include/openssl/x509_vfy.h.in b/include/openssl/x509_vfy.h.in index f4ab746f75..b72513272f 100644 --- a/include/openssl/x509_vfy.h.in +++ b/include/openssl/x509_vfy.h.in @@ -72,6 +72,9 @@ typedef enum { .generate_stack_macros("X509_VERIFY_PARAM"); -} +int X509_verify_cert(X509_STORE_CTX *ctx); +int X509_STORE_CTX_verify(X509_STORE_CTX *ctx); + int X509_STORE_set_depth(X509_STORE *store, int depth); typedef int (*X509_STORE_CTX_verify_cb)(int, X509_STORE_CTX *); diff --git a/test/danetest.c b/test/danetest.c index b0d6ffe563..25fd16a411 100644 --- a/test/danetest.c +++ b/test/danetest.c @@ -57,15 +57,13 @@ static int verify_chain(SSL *ssl, STACK_OF(X509) *chain) X509_STORE_CTX *store_ctx = NULL; SSL_CTX *ssl_ctx = NULL; X509_STORE *store = NULL; - X509 *cert = NULL; int ret = 0; int store_ctx_idx = SSL_get_ex_data_X509_STORE_CTX_idx(); if (!TEST_ptr(store_ctx = X509_STORE_CTX_new()) || !TEST_ptr(ssl_ctx = SSL_get_SSL_CTX(ssl)) || !TEST_ptr(store = SSL_CTX_get_cert_store(ssl_ctx)) - || !TEST_ptr(cert = sk_X509_value(chain, 0)) - || !TEST_true(X509_STORE_CTX_init(store_ctx, store, cert, chain)) + || !TEST_true(X509_STORE_CTX_init(store_ctx, store, NULL, chain)) || !TEST_true(X509_STORE_CTX_set_ex_data(store_ctx, store_ctx_idx, ssl))) goto end; @@ -80,7 +78,7 @@ static int verify_chain(SSL *ssl, STACK_OF(X509) *chain) X509_STORE_CTX_set_verify_cb(store_ctx, SSL_get_verify_callback(ssl)); /* Mask "internal failures" (-1) from our return value. */ - if (!TEST_int_ge(ret = X509_verify_cert(store_ctx), 0)) + if (!TEST_int_ge(ret = X509_STORE_CTX_verify(store_ctx), 0)) ret = 0; SSL_set_verify_result(ssl, X509_STORE_CTX_get_error(store_ctx)); diff --git a/util/libcrypto.num b/util/libcrypto.num index 32e7779bce..c591ab8ec5 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -4996,6 +4996,7 @@ EVP_PKEY_get_octet_string_param ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_is_a ? 3_0_0 EXIST::FUNCTION: EVP_PKEY_can_sign ? 3_0_0 EXIST::FUNCTION: X509_STORE_CTX_new_ex ? 3_0_0 EXIST::FUNCTION: +X509_STORE_CTX_verify ? 3_0_0 EXIST::FUNCTION: CT_POLICY_EVAL_CTX_new_ex ? 3_0_0 EXIST::FUNCTION:CT CTLOG_new_ex ? 3_0_0 EXIST::FUNCTION:CT CTLOG_new_from_base64_ex ? 3_0_0 EXIST::FUNCTION:CT |