From 70fb75990d18c88d13d3cb50faa95440b2651836 Mon Sep 17 00:00:00 2001 From: "Dr. David von Oheimb" Date: Wed, 17 Feb 2021 21:16:38 +0100 Subject: [PATCH] X509: Add support for directly checking leaf cert EKU --- apps/include/opt.h | 7 +++- apps/lib/opt.c | 19 +++++++-- crypto/x509/v3_purp.c | 24 ++++++++--- crypto/x509/x509_local.h | 1 + crypto/x509/x509_txt.c | 3 +- crypto/x509/x509_vfy.c | 18 ++++++--- crypto/x509/x509_vpm.c | 14 +++++++ crypto/x509/x_x509.c | 3 ++ doc/build.info | 6 +++ doc/man1/openssl-verification-options.pod | 9 +++-- doc/man3/SSL_CTX_set_eku.pod | 49 +++++++++++++++++++++++ doc/man3/X509_STORE_CTX_get_error.pod | 4 ++ doc/man3/X509_VERIFY_PARAM_set_flags.pod | 16 ++++++-- doc/man3/X509_check_purpose.pod | 14 +++++-- doc/perlvars.pm | 3 +- include/crypto/x509.h | 3 +- include/openssl/ssl.h.in | 2 + include/openssl/x509_vfy.h.in | 2 + include/openssl/x509v3.h.in | 1 + ssl/ssl_lib.c | 10 +++++ test/certs/ca_anyEKU.pem | 19 +++++++++ test/certs/ee_anyEKU.pem | 19 +++++++++ test/certs/ee_noEKU.pem | 18 +++++++++ test/certs/root_anyEKU.pem | 19 +++++++++ test/certs/setup.sh | 9 +++++ test/recipes/25-test_verify.t | 22 +++++++++- util/libcrypto.num | 2 + util/libssl.num | 2 + 28 files changed, 290 insertions(+), 28 deletions(-) create mode 100644 doc/man3/SSL_CTX_set_eku.pod create mode 100644 test/certs/ca_anyEKU.pem create mode 100644 test/certs/ee_anyEKU.pem create mode 100644 test/certs/ee_noEKU.pem create mode 100644 test/certs/root_anyEKU.pem diff --git a/apps/include/opt.h b/apps/include/opt.h index 2bd2fb24849266..2eb16f035b249e 100644 --- a/apps/include/opt.h +++ b/apps/include/opt.h @@ -21,7 +21,8 @@ */ # define OPT_V_ENUM \ OPT_V__FIRST=2000, \ - OPT_V_POLICY, OPT_V_PURPOSE, OPT_V_VERIFY_NAME, OPT_V_VERIFY_DEPTH, \ + OPT_V_POLICY, OPT_V_PURPOSE, OPT_V_EKU, \ + OPT_V_VERIFY_NAME, OPT_V_VERIFY_DEPTH, \ OPT_V_ATTIME, OPT_V_VERIFY_HOSTNAME, OPT_V_VERIFY_EMAIL, \ OPT_V_VERIFY_IP, OPT_V_IGNORE_CRITICAL, OPT_V_ISSUER_CHECKS, \ OPT_V_CRL_CHECK, OPT_V_CRL_CHECK_ALL, OPT_V_POLICY_CHECK, \ @@ -38,6 +39,8 @@ { "policy", OPT_V_POLICY, 's', "adds policy to the acceptable policy set"}, \ { "purpose", OPT_V_PURPOSE, 's', \ "certificate chain purpose"}, \ + { "eku", OPT_V_EKU, 's', \ + "certificate Extended Key Usage, e.g., serverAuth"}, \ { "verify_name", OPT_V_VERIFY_NAME, 's', "verification policy name"}, \ { "verify_depth", OPT_V_VERIFY_DEPTH, 'n', \ "chain depth limit" }, \ @@ -88,6 +91,7 @@ OPT_V__FIRST: case OPT_V__LAST: break; \ case OPT_V_POLICY: \ case OPT_V_PURPOSE: \ + case OPT_V_EKU: \ case OPT_V_VERIFY_NAME: \ case OPT_V_VERIFY_DEPTH: \ case OPT_V_VERIFY_AUTH_LEVEL: \ @@ -409,6 +413,7 @@ int opt_cipher_silent(const char *name, EVP_CIPHER **cipherp); int opt_check_md(const char *name); int opt_md(const char *name, EVP_MD **mdp); int opt_md_silent(const char *name, EVP_MD **mdp); +int opt_oid(const char *name, const char *desc); int opt_int(const char *arg, int *result); void opt_set_unknown_name(const char *name); diff --git a/apps/lib/opt.c b/apps/lib/opt.c index d72b624a9e59a0..9ae1f520a9cbf6 100644 --- a/apps/lib/opt.c +++ b/apps/lib/opt.c @@ -446,9 +446,7 @@ int opt_cipher(const char *name, EVP_CIPHER **cipherp) return ret; } -/* - * Parse message digest name, put it in *EVP_MD; return 0 on failure, else 1. - */ +/* Parse message digest name, put it in *EVP_MD; return 0 on failure, else 1. */ int opt_md_silent(const char *name, EVP_MD **mdp) { EVP_MD *md; @@ -490,6 +488,16 @@ int opt_check_md(const char *name) return 0; } +/* Parse an OID name; returns its NID or 0 on failure. */ +int opt_oid(const char *name, const char *desc) +{ + int nid = OBJ_txt2nid(name); + + if (nid == 0) + opt_printf_stderr("%s: Invalid OID name for %s: %s\n", prog, desc, name); + return nid; +} + /* Look through a list of name/value pairs. */ int opt_pair(const char *name, const OPT_PAIR* pairs, int *result) { @@ -753,6 +761,11 @@ int opt_verify(int opt, X509_VERIFY_PARAM *vpm) return 0; } break; + case OPT_V_EKU: + if ((i = opt_oid(opt_arg(), "Extended Key Usage")) == 0) + return 0; + X509_VERIFY_PARAM_set_eku(vpm, i); + break; case OPT_V_VERIFY_NAME: vtmp = X509_VERIFY_PARAM_lookup(opt_arg()); if (vtmp == NULL) { diff --git a/crypto/x509/v3_purp.c b/crypto/x509/v3_purp.c index e917c455dec7ce..90a1b2ab3cc5d2 100644 --- a/crypto/x509/v3_purp.c +++ b/crypto/x509/v3_purp.c @@ -42,6 +42,21 @@ static int check_purpose_ocsp_helper(const X509_PURPOSE *xp, const X509 *x, static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b); static void xptable_free(X509_PURPOSE *p); +/* Directly check for allowed extended key usage (EKU) */ +int X509_check_eku(X509 *x, int nid) +{ + int eku, i, n = sk_ASN1_OBJECT_num(x->ex_ekus); + + if (nid == NID_anyExtendedKeyUsage || n <= 0) + return 1; + for (i = 0; i < n; i++) { + eku = OBJ_obj2nid(sk_ASN1_OBJECT_value(x->ex_ekus, i)); + if (eku == NID_anyExtendedKeyUsage || eku == nid) + return 1; + } + return 0; +} + static X509_PURPOSE xstandard[] = { {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0, check_purpose_ssl_client, "SSL client", "sslclient", NULL}, @@ -403,7 +418,6 @@ int ossl_x509v3_cache_extensions(X509 *x) PROXY_CERT_INFO_EXTENSION *pci; ASN1_BIT_STRING *usage; ASN1_BIT_STRING *ns; - EXTENDED_KEY_USAGE *extusage; int i; int res; @@ -491,10 +505,11 @@ int ossl_x509v3_cache_extensions(X509 *x) /* Handle extended key usage */ x->ex_xkusage = 0; - if ((extusage = X509_get_ext_d2i(x, NID_ext_key_usage, &i, NULL)) != NULL) { + x->ex_ekus = X509_get_ext_d2i(x, NID_ext_key_usage, &i, NULL); + if (x->ex_ekus != NULL) { x->ex_flags |= EXFLAG_XKUSAGE; - for (i = 0; i < sk_ASN1_OBJECT_num(extusage); i++) { - switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(extusage, i))) { + for (i = 0; i < sk_ASN1_OBJECT_num(x->ex_ekus); i++) { + switch (OBJ_obj2nid(sk_ASN1_OBJECT_value(x->ex_ekus, i))) { case NID_server_auth: x->ex_xkusage |= XKU_SSL_SERVER; break; @@ -528,7 +543,6 @@ int ossl_x509v3_cache_extensions(X509 *x) break; } } - sk_ASN1_OBJECT_pop_free(extusage, ASN1_OBJECT_free); } else if (i != -1) { x->ex_flags |= EXFLAG_INVALID; } diff --git a/crypto/x509/x509_local.h b/crypto/x509/x509_local.h index 6d602e1d8ef591..f623cf29fe7923 100644 --- a/crypto/x509/x509_local.h +++ b/crypto/x509/x509_local.h @@ -23,6 +23,7 @@ struct X509_VERIFY_PARAM_st { time_t check_time; /* Time to use */ uint32_t inh_flags; /* Inheritance flags */ unsigned long flags; /* Various verify flags */ + int eku; /* Extended Key Usage NID to check leaf certs */ int purpose; /* purpose to check untrusted certificates */ int trust; /* trust setting to check */ int depth; /* Verify depth */ diff --git a/crypto/x509/x509_txt.c b/crypto/x509/x509_txt.c index e825ce2db8b987..27563cdc033505 100644 --- a/crypto/x509/x509_txt.c +++ b/crypto/x509/x509_txt.c @@ -214,7 +214,8 @@ const char *X509_verify_cert_error_string(long n) return "Certificate public key has explicit ECC parameters"; case X509_V_ERR_RPK_UNTRUSTED: return "Raw public key untrusted, no trusted keys configured"; - + case X509_V_ERR_INVALID_EXTENDED_KEY_USAGE: + return "unsupported certificate Extended Key Usage"; /* * Entries must be kept consistent with include/openssl/x509_vfy.h.in * and with doc/man3/X509_STORE_CTX_get_error.pod diff --git a/crypto/x509/x509_vfy.c b/crypto/x509/x509_vfy.c index 1794c14e9920ae..562f1ae591426c 100644 --- a/crypto/x509/x509_vfy.c +++ b/crypto/x509/x509_vfy.c @@ -170,8 +170,10 @@ static int verify_cb_cert(X509_STORE_CTX *ctx, X509 *x, int depth, int err) } #define CB_FAIL_IF(cond, ctx, cert, depth, err) \ - if ((cond) && verify_cb_cert(ctx, cert, depth, err) == 0) \ - return 0 + do { \ + if ((cond) && verify_cb_cert(ctx, cert, depth, err) == 0) \ + return 0; \ + } while (0) /*- * Inform the verify callback of an error, CRL-specific variant. Here, the @@ -456,7 +458,7 @@ static STACK_OF(X509) *lookup_certs_sk(X509_STORE_CTX *ctx, const X509_NAME *nm) /* * Check EE or CA certificate purpose. For trusted certificates explicit local - * auxiliary trust can be used to override EKU-restrictions. + * auxiliary trust can be used to override EKU-restrictions in these certs. * Sadly, returns 0 also on internal error in ctx->verify_cb(). */ static int check_purpose(X509_STORE_CTX *ctx, X509 *x, int purpose, int depth, @@ -507,7 +509,8 @@ static int check_purpose(X509_STORE_CTX *ctx, X509 *x, int purpose, int depth, } /*- - * Check extensions of a cert chain for consistency with the supplied purpose. + * Check extensions of a cert chain for consistency with the supplied purpose + * and leaf cert EKU. * Sadly, returns 0 also on internal error in ctx->verify_cb(). */ static int check_extensions(X509_STORE_CTX *ctx) @@ -515,6 +518,7 @@ static int check_extensions(X509_STORE_CTX *ctx) int i, must_be_ca, plen = 0; X509 *x; int ret, proxy_path_length = 0; + int eku = ctx->param->eku; int purpose, allow_proxy_certs, num = sk_X509_num(ctx->chain); /*- @@ -642,8 +646,12 @@ static int check_extensions(X509_STORE_CTX *ctx) } } + if (eku != 0 && i < ctx->num_untrusted) + /* EKU requirement overrides purpose check for untrusted certs */ + CB_FAIL_IF(X509_check_eku(x, eku) <= 0, ctx, x, i, + X509_V_ERR_INVALID_EXTENDED_KEY_USAGE); /* check_purpose() makes the callback as needed */ - if (purpose > 0 && !check_purpose(ctx, x, purpose, i, must_be_ca)) + else if (purpose > 0 && !check_purpose(ctx, x, purpose, i, must_be_ca)) return 0; /* Check path length */ CB_FAIL_IF(i > 1 && x->ex_pathlen != -1 diff --git a/crypto/x509/x509_vpm.c b/crypto/x509/x509_vpm.c index 023a38a1c9fc80..479a41a00d8666 100644 --- a/crypto/x509/x509_vpm.c +++ b/crypto/x509/x509_vpm.c @@ -167,6 +167,7 @@ int X509_VERIFY_PARAM_inherit(X509_VERIFY_PARAM *dest, to_default = (inh_flags & X509_VP_FLAG_DEFAULT) != 0; to_overwrite = (inh_flags & X509_VP_FLAG_OVERWRITE) != 0; + x509_verify_param_copy(eku, 0); x509_verify_param_copy(purpose, 0); x509_verify_param_copy(trust, X509_TRUST_DEFAULT); x509_verify_param_copy(depth, -1); @@ -296,6 +297,13 @@ int X509_VERIFY_PARAM_set_inh_flags(X509_VERIFY_PARAM *param, uint32_t flags) return 1; } +int X509_VERIFY_PARAM_set_eku(X509_VERIFY_PARAM *param, int eku) +{ + /* Should check range of acceptable EKU OIDs, but this is fuzzy */ + param->eku = eku; + return 1; +} + int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose) { return X509_PURPOSE_set(¶m->purpose, purpose); @@ -509,6 +517,7 @@ static const X509_VERIFY_PARAM default_table[] = { 0, /* check time to use */ 0, /* inheritance flags */ 0, /* flags */ + 0, /* eku */ X509_PURPOSE_CODE_SIGN, /* purpose */ X509_TRUST_OBJECT_SIGN, /* trust */ -1, /* depth */ @@ -521,6 +530,7 @@ static const X509_VERIFY_PARAM default_table[] = { 0, /* check time to use */ 0, /* inheritance flags */ X509_V_FLAG_TRUSTED_FIRST, /* flags */ + 0, /* eku */ 0, /* purpose */ 0, /* trust */ 100, /* depth */ @@ -533,6 +543,7 @@ static const X509_VERIFY_PARAM default_table[] = { 0, /* check time to use */ 0, /* inheritance flags */ 0, /* flags */ + 0, /* eku */ X509_PURPOSE_SMIME_SIGN, /* purpose */ X509_TRUST_EMAIL, /* trust */ -1, /* depth */ @@ -545,6 +556,7 @@ static const X509_VERIFY_PARAM default_table[] = { 0, /* check time to use */ 0, /* inheritance flags */ 0, /* flags */ + 0, /* eku */ X509_PURPOSE_SMIME_SIGN, /* purpose */ X509_TRUST_EMAIL, /* trust */ -1, /* depth */ @@ -557,6 +569,7 @@ static const X509_VERIFY_PARAM default_table[] = { 0, /* check time to use */ 0, /* inheritance flags */ 0, /* flags */ + 0, /* eku */ X509_PURPOSE_SSL_CLIENT, /* purpose */ X509_TRUST_SSL_CLIENT, /* trust */ -1, /* depth */ @@ -569,6 +582,7 @@ static const X509_VERIFY_PARAM default_table[] = { 0, /* check time to use */ 0, /* inheritance flags */ 0, /* flags */ + 0, /* eku */ X509_PURPOSE_SSL_SERVER, /* purpose */ X509_TRUST_SSL_SERVER, /* trust */ -1, /* depth */ diff --git a/crypto/x509/x_x509.c b/crypto/x509/x_x509.c index 75c5c9223acce8..484dda6ab1cbd5 100644 --- a/crypto/x509/x_x509.c +++ b/crypto/x509/x_x509.c @@ -45,6 +45,7 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, X509_CERT_AUX_free(ret->aux); ASN1_OCTET_STRING_free(ret->skid); AUTHORITY_KEYID_free(ret->akid); + sk_ASN1_OBJECT_pop_free(ret->ex_ekus, ASN1_OBJECT_free); CRL_DIST_POINTS_free(ret->crldp); ossl_policy_cache_free(ret->policy_cache); GENERAL_NAMES_free(ret->altname); @@ -76,6 +77,7 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, #endif ret->distinguishing_id = NULL; ret->aux = NULL; + ret->ex_ekus = NULL; ret->crldp = NULL; if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_X509, ret, &ret->ex_data)) return 0; @@ -86,6 +88,7 @@ static int x509_cb(int operation, ASN1_VALUE **pval, const ASN1_ITEM *it, X509_CERT_AUX_free(ret->aux); ASN1_OCTET_STRING_free(ret->skid); AUTHORITY_KEYID_free(ret->akid); + sk_ASN1_OBJECT_pop_free(ret->ex_ekus, ASN1_OBJECT_free); CRL_DIST_POINTS_free(ret->crldp); ossl_policy_cache_free(ret->policy_cache); GENERAL_NAMES_free(ret->altname); diff --git a/doc/build.info b/doc/build.info index d47371e88aa9f0..3c7d928c33a068 100644 --- a/doc/build.info +++ b/doc/build.info @@ -2319,6 +2319,10 @@ DEPEND[html/man3/SSL_CTX_set_default_passwd_cb.html]=man3/SSL_CTX_set_default_pa GENERATE[html/man3/SSL_CTX_set_default_passwd_cb.html]=man3/SSL_CTX_set_default_passwd_cb.pod DEPEND[man/man3/SSL_CTX_set_default_passwd_cb.3]=man3/SSL_CTX_set_default_passwd_cb.pod GENERATE[man/man3/SSL_CTX_set_default_passwd_cb.3]=man3/SSL_CTX_set_default_passwd_cb.pod +DEPEND[html/man3/SSL_CTX_set_eku.html]=man3/SSL_CTX_set_eku.pod +GENERATE[html/man3/SSL_CTX_set_eku.html]=man3/SSL_CTX_set_eku.pod +DEPEND[man/man3/SSL_CTX_set_eku.3]=man3/SSL_CTX_set_eku.pod +GENERATE[man/man3/SSL_CTX_set_eku.3]=man3/SSL_CTX_set_eku.pod DEPEND[html/man3/SSL_CTX_set_generate_session_id.html]=man3/SSL_CTX_set_generate_session_id.pod GENERATE[html/man3/SSL_CTX_set_generate_session_id.html]=man3/SSL_CTX_set_generate_session_id.pod DEPEND[man/man3/SSL_CTX_set_generate_session_id.3]=man3/SSL_CTX_set_generate_session_id.pod @@ -3571,6 +3575,7 @@ html/man3/SSL_CTX_set_client_hello_cb.html \ html/man3/SSL_CTX_set_ct_validation_callback.html \ html/man3/SSL_CTX_set_ctlog_list_file.html \ html/man3/SSL_CTX_set_default_passwd_cb.html \ +html/man3/SSL_CTX_set_eku.html \ html/man3/SSL_CTX_set_generate_session_id.html \ html/man3/SSL_CTX_set_info_callback.html \ html/man3/SSL_CTX_set_keylog_callback.html \ @@ -4231,6 +4236,7 @@ man/man3/SSL_CTX_set_client_hello_cb.3 \ man/man3/SSL_CTX_set_ct_validation_callback.3 \ man/man3/SSL_CTX_set_ctlog_list_file.3 \ man/man3/SSL_CTX_set_default_passwd_cb.3 \ +man/man3/SSL_CTX_set_eku.3 \ man/man3/SSL_CTX_set_generate_session_id.3 \ man/man3/SSL_CTX_set_info_callback.3 \ man/man3/SSL_CTX_set_keylog_callback.3 \ diff --git a/doc/man1/openssl-verification-options.pod b/doc/man1/openssl-verification-options.pod index 4bb4e9c4714363..d578a184d58679 100644 --- a/doc/man1/openssl-verification-options.pod +++ b/doc/man1/openssl-verification-options.pod @@ -151,12 +151,13 @@ The first step is to check that each certificate is well-formed. Part of these checks are enabled only if the B<-x509_strict> option is given. The second step is to check the extensions of every untrusted certificate -for consistency with the supplied purpose. -If the B<-purpose> option is not given then no such checks are done -except for SSL/TLS connection setup, +for consistency with the supplied purpose or Extended Key Usage (EKU), +where the latter overrides any purpose requirements for untrusted certificates. +If the B<-purpose> and B<-eku> options are not given +then no such checks are done except for SSL/TLS connection setup, where by default C or C, are checked. The target or "leaf" certificate, as well as any other untrusted certificates, -must have extensions compatible with the specified purpose. +must have extensions compatible with the given EKU or specified purpose. All certificates except the target or "leaf" must also be valid CA certificates. The precise extensions required are described in more detail in L. diff --git a/doc/man3/SSL_CTX_set_eku.pod b/doc/man3/SSL_CTX_set_eku.pod new file mode 100644 index 00000000000000..ff33e6278d465b --- /dev/null +++ b/doc/man3/SSL_CTX_set_eku.pod @@ -0,0 +1,49 @@ +=pod + +=head1 NAME + +SSL_CTX_set_eku, +SSL_set_eku +- set peer certificate usage requirements to be verified + +=head1 SYNOPSIS + + #include + + int SSL_CTX_set_eku(SSL_CTX *ctx, int nid); + int SSL_set_eku(SSL *ssl, int nid); + +=head1 DESCRIPTION + +SSL_CTX_set_eku() and SSL_CTX_set_eku() sets the Extended Key Usage (EKU) +in the verification parameters of I or I, respectively, to I. +This must be an NID corresponding to an EKU OID, for example B, +which may have been obtained by parsing a text string using L. +It determines the acceptable EKU for the peer certificate and its chain, +If provided, it overrides any purpose requirements for untrusted certificates. + +=head1 RETURN VALUES + +SSL_CTX_set_eku() and SSL_CTX_set_eku() +return 1 for success and 0 for failure. + +=head1 SEE ALSO + +L, +L + +=head1 HISTORY + +The SSL_CTX_set_eku() and SSL_CTX_set_eku() +functions were added in OpenSSL 3.0. + +=head1 COPYRIGHT + +Copyright 2000-2018 The OpenSSL Project Authors. All Rights Reserved. + +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 +L. + +=cut diff --git a/doc/man3/X509_STORE_CTX_get_error.pod b/doc/man3/X509_STORE_CTX_get_error.pod index 1ecea800046c4e..66a68296d1bf1a 100644 --- a/doc/man3/X509_STORE_CTX_get_error.pod +++ b/doc/man3/X509_STORE_CTX_get_error.pod @@ -466,6 +466,10 @@ consistent with the supplied purpose. No TLS records were configured to validate the raw public key, or DANE was not enabled on the connection. +=item B + +The target certificate cannot be used for the specified Extended Key Usage (EKU). + =back =head1 NOTES diff --git a/doc/man3/X509_VERIFY_PARAM_set_flags.pod b/doc/man3/X509_VERIFY_PARAM_set_flags.pod index fcbbfc4c306734..8e54f161e1fb8a 100644 --- a/doc/man3/X509_VERIFY_PARAM_set_flags.pod +++ b/doc/man3/X509_VERIFY_PARAM_set_flags.pod @@ -3,7 +3,8 @@ =head1 NAME X509_VERIFY_PARAM_set_flags, X509_VERIFY_PARAM_clear_flags, -X509_VERIFY_PARAM_get_flags, X509_VERIFY_PARAM_set_purpose, +X509_VERIFY_PARAM_get_flags, +X509_VERIFY_PARAM_set_eku, X509_VERIFY_PARAM_set_purpose, X509_VERIFY_PARAM_get_inh_flags, X509_VERIFY_PARAM_set_inh_flags, X509_VERIFY_PARAM_set_trust, X509_VERIFY_PARAM_set_depth, X509_VERIFY_PARAM_get_depth, X509_VERIFY_PARAM_set_auth_level, @@ -34,6 +35,7 @@ X509_VERIFY_PARAM_set1_ip_asc uint32_t flags); uint32_t X509_VERIFY_PARAM_get_inh_flags(const X509_VERIFY_PARAM *param); + int X509_VERIFY_PARAM_set_eku(X509_VERIFY_PARAM *param, int nid); int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose); int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust); @@ -87,6 +89,12 @@ See the B section for a description of these bits. X509_VERIFY_PARAM_clear_flags() clears the flags B in B. +X509_VERIFY_PARAM_set_eku() sets the Extended Key Usage (EKU) in I to I. +This must be an NID corresponding to an EKU OID, for example B, +which may have been obtained by parsing a text string using L. +It determines the acceptable EKU for the certificate chain to be verified. +If provided, it overrides any purpose requirements for untrusted certificates. + X509_VERIFY_PARAM_set_purpose() sets the verification purpose in B to B. This determines the acceptable purpose of the certificate chain, for example B. @@ -214,7 +222,7 @@ IPv6. The condensed "::" notation is supported for IPv6 addresses. =head1 RETURN VALUES X509_VERIFY_PARAM_set_flags(), X509_VERIFY_PARAM_clear_flags(), -X509_VERIFY_PARAM_set_inh_flags(), +X509_VERIFY_PARAM_set_inh_flags(), X509_VERIFY_PARAM_set_eku(), X509_VERIFY_PARAM_set_purpose(), X509_VERIFY_PARAM_set_trust(), X509_VERIFY_PARAM_add0_policy() X509_VERIFY_PARAM_set1_policies(), X509_VERIFY_PARAM_set1_host(), X509_VERIFY_PARAM_add1_host(), @@ -388,6 +396,7 @@ L, L, L, L, +L, L =head1 HISTORY @@ -398,7 +407,8 @@ and has no effect. The X509_VERIFY_PARAM_get_hostflags() function was added in OpenSSL 1.1.0i. -The X509_VERIFY_PARAM_get0_host(), X509_VERIFY_PARAM_get0_email(), +The X509_VERIFY_PARAM_set_eku(), +X509_VERIFY_PARAM_get0_host(), X509_VERIFY_PARAM_get0_email(), and X509_VERIFY_PARAM_get1_ip_asc() functions were added in OpenSSL 3.0. The function X509_VERIFY_PARAM_add0_policy() was historically documented as diff --git a/doc/man3/X509_check_purpose.pod b/doc/man3/X509_check_purpose.pod index 4331cfad92c907..a131649c5b70e3 100644 --- a/doc/man3/X509_check_purpose.pod +++ b/doc/man3/X509_check_purpose.pod @@ -2,17 +2,23 @@ =head1 NAME -X509_check_purpose - Check the purpose of a certificate +X509_check_eku, +X509_check_purpose - Check the EKU or purpose of a certificate =head1 SYNOPSIS #include + int X509_check_eku(X509 *x, int nid); int X509_check_purpose(X509 *x, int id, int ca); =head1 DESCRIPTION -This function checks if certificate I was created with the purpose +X509_check_eku() checks if certificate I supports +the Extended Key Usage (EKU) represented by I. +This must be an NID corresponding to an EKU OID, for example B. + +X509_check_purpose() checks if certificate I was created with the purpose represented by I. If I is nonzero, then certificate I is checked to determine if it's a possible CA with various levels of certainty possibly returned. The certificate I must be a complete certificate @@ -36,7 +42,9 @@ keyUsage, extendedKeyUsage, and basicConstraints. =head1 RETURN VALUES -For non-CA checks +X509_check_eku() returns 1 on allowed, 0 if not, and -1 on internal error. + +X509_check_purpose() returns for non-CA checks =over 4 diff --git a/doc/perlvars.pm b/doc/perlvars.pm index 06dac990cfafdd..9fe13d519cf97b 100644 --- a/doc/perlvars.pm +++ b/doc/perlvars.pm @@ -28,6 +28,7 @@ $OpenSSL::safe::opt_v_synopsis = "" . "[B<-policy_check>]\n" . "[B<-policy_print>]\n" . "[B<-purpose> I]\n" +. "[B<-eku> I]\n" . "[B<-suiteB_128>]\n" . "[B<-suiteB_128_only>]\n" . "[B<-suiteB_192>]\n" @@ -47,7 +48,7 @@ $OpenSSL::safe::opt_v_item = "" . "B<-check_ss_sig>, B<-crl_check>, B<-crl_check_all>,\n" . "B<-explicit_policy>, B<-extended_crl>, B<-ignore_critical>, B<-inhibit_any>,\n" . "B<-inhibit_map>, B<-no_alt_chains>, B<-partial_chain>, B<-policy>,\n" -. "B<-policy_check>, B<-policy_print>, B<-purpose>, B<-suiteB_128>,\n" +. "B<-policy_check>, B<-policy_print>, B<-purpose>, B<-eku>, B<-suiteB_128>,\n" . "B<-suiteB_128_only>, B<-suiteB_192>, B<-trusted_first>, B<-use_deltas>,\n" . "B<-auth_level>, B<-verify_depth>, B<-verify_email>, B<-verify_hostname>,\n" . "B<-verify_ip>, B<-verify_name>, B<-x509_strict> B<-issuer_checks>\n" diff --git a/include/crypto/x509.h b/include/crypto/x509.h index 338e58b4919f9a..882591fdbfdfd0 100644 --- a/include/crypto/x509.h +++ b/include/crypto/x509.h @@ -13,7 +13,7 @@ # include "internal/refcount.h" # include -# include +# include # include # include "crypto/types.h" @@ -184,6 +184,7 @@ struct x509_st { uint32_t ex_flags; uint32_t ex_kusage; uint32_t ex_xkusage; + EXTENDED_KEY_USAGE *ex_ekus; uint32_t ex_nscert; ASN1_OCTET_STRING *skid; AUTHORITY_KEYID *akid; diff --git a/include/openssl/ssl.h.in b/include/openssl/ssl.h.in index 4bab2ac767f558..15c001617dc1e5 100644 --- a/include/openssl/ssl.h.in +++ b/include/openssl/ssl.h.in @@ -1816,6 +1816,8 @@ int SSL_is_quic(const SSL *s); __owur int SSL_set_session_id_context(SSL *ssl, const unsigned char *sid_ctx, unsigned int sid_ctx_len); +__owur int SSL_CTX_set_eku(SSL_CTX *ctx, int nid); +__owur int SSL_set_eku(SSL *ssl, int nid); __owur int SSL_CTX_set_purpose(SSL_CTX *ctx, int purpose); __owur int SSL_set_purpose(SSL *ssl, int purpose); __owur int SSL_CTX_set_trust(SSL_CTX *ctx, int trust); diff --git a/include/openssl/x509_vfy.h.in b/include/openssl/x509_vfy.h.in index a396193b86d131..1f8896ba6670df 100644 --- a/include/openssl/x509_vfy.h.in +++ b/include/openssl/x509_vfy.h.in @@ -315,6 +315,7 @@ X509_LOOKUP_ctrl_ex((x), X509_L_ADD_STORE, (name), 0, NULL, \ # define X509_V_ERR_EXTENSIONS_REQUIRE_VERSION_3 93 # define X509_V_ERR_EC_KEY_EXPLICIT_PARAMS 94 # define X509_V_ERR_RPK_UNTRUSTED 95 +# define X509_V_ERR_INVALID_EXTENDED_KEY_USAGE 96 /* Certificate verify flags */ # ifndef OPENSSL_NO_DEPRECATED_1_1_0 @@ -714,6 +715,7 @@ int X509_VERIFY_PARAM_set_flags(X509_VERIFY_PARAM *param, int X509_VERIFY_PARAM_clear_flags(X509_VERIFY_PARAM *param, unsigned long flags); unsigned long X509_VERIFY_PARAM_get_flags(const X509_VERIFY_PARAM *param); +int X509_VERIFY_PARAM_set_eku(X509_VERIFY_PARAM *param, int eku); int X509_VERIFY_PARAM_set_purpose(X509_VERIFY_PARAM *param, int purpose); int X509_VERIFY_PARAM_set_trust(X509_VERIFY_PARAM *param, int trust); void X509_VERIFY_PARAM_set_depth(X509_VERIFY_PARAM *param, int depth); diff --git a/include/openssl/x509v3.h.in b/include/openssl/x509v3.h.in index 37626aa8375937..2f4e00fdf1b62e 100644 --- a/include/openssl/x509v3.h.in +++ b/include/openssl/x509v3.h.in @@ -724,6 +724,7 @@ int X509V3_extensions_print(BIO *out, const char *title, unsigned long flag, int indent); int X509_check_ca(X509 *x); +int X509_check_eku(X509 *x, int nid); int X509_check_purpose(X509 *x, int id, int ca); int X509_supported_extension(X509_EXTENSION *ex); int X509_PURPOSE_set(int *p, int purpose); diff --git a/ssl/ssl_lib.c b/ssl/ssl_lib.c index f1fe7186601563..781f7cffefc897 100644 --- a/ssl/ssl_lib.c +++ b/ssl/ssl_lib.c @@ -1062,6 +1062,16 @@ int SSL_has_matching_session_id(const SSL *ssl, const unsigned char *id, return (p != NULL); } +int SSL_CTX_set_eku(SSL_CTX *ctx, int nid) +{ + return X509_VERIFY_PARAM_set_eku(ctx->param, nid); +} + +int SSL_set_eku(SSL *ssl, int nid) +{ + return X509_VERIFY_PARAM_set_eku(SSL_get0_param(ssl), nid); +} + int SSL_CTX_set_purpose(SSL_CTX *s, int purpose) { return X509_VERIFY_PARAM_set_purpose(s->param, purpose); diff --git a/test/certs/ca_anyEKU.pem b/test/certs/ca_anyEKU.pem new file mode 100644 index 00000000000000..e34eb0dd12cbff --- /dev/null +++ b/test/certs/ca_anyEKU.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDDTCCAfWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290 +IENBMCAXDTIxMDMwMjE0NTYwN1oYDzIxMjEwMzAzMTQ1NjA3WjANMQswCQYDVQQD +DAJDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJadpD0ASxxfxsvd +j9IxsogVzMSGLFziaYuE9KejU9+R479RifvwfBANO62sNWJ19X//9G5UjwWmkiOz +n1k50DkYsBBA3mJzik6wjt/c58lBIlSEgAgpvDU8ht8w3t20JP9+YqXAeugqFj/W +l9rFQtsvaWSRywjXVlp5fxuEQelNnXcJEKhsKTNExsBUZebo4/J1BWpklWzA9P0l +YW5INvDAAwcF1nzlEf0Y6Eot03IMNyg2MTE4hehxjdgCSci8GYnFirE/ojXqqpAc +ZGh7r2dqWgZUD1Dh+bT2vjrUzj8eTH3GdzI+oljt29102JIUaqj3yzRYkah8FLF9 +CLNNsUcCAwEAAaNxMG8wDwYDVR0TAQH/BAUwAwEB/zALBgNVHQ8EBAMCAQYwHQYD +VR0OBBYEFLQRM/HX4l73U54gIhBPhga/H8leMB8GA1UdIwQYMBaAFI71Ja8em2uE +PXyAmslTnE1y96NSMA8GA1UdJQQIMAYGBFUdJQAwDQYJKoZIhvcNAQELBQADggEB +ADiTcpY5NjjRPA+w/gjqpvjumXgzbivV9mIoTKYjLnxdqPTIwmQW7I71iMYyy6i1 +UcycYF1bC/faCXrBBaEiRt4Q83ok8ACgJ/TgTfybj/qFL5vS19TJWXrQqfjjehHh +fWbuSnatxJYtfsgcEoMDVtAf3y08KwBzRg4qpYHw6IawFrxD1TQQ10j8OOITVhRA +w4h70sWGYKiMODhWy4UkXcKjpUNk+NTl2vVVadBjy5o5bjB8A697aBfQD4d9c6D/ +pHXgdCvHK9+niavrQiU+wHdGvWmKddSWQCLI+DdYXq7Sy7K2R8bOThd+pcaAa65r +u8v1dbY144XKW4327z5PZrM= +-----END CERTIFICATE----- diff --git a/test/certs/ee_anyEKU.pem b/test/certs/ee_anyEKU.pem new file mode 100644 index 00000000000000..ec906de7ec6dbc --- /dev/null +++ b/test/certs/ee_anyEKU.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDHDCCAgSgAwIBAgIBAjANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJDQTAg +Fw0yMTAzMDIxMTU2MDBaGA8yMTIxMDMwMzExNTYwMFowGTEXMBUGA1UEAwwOYW55 +RUtVLmV4YW1wbGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCo/4lY +YYWu3tssD9Vz++K3qBt6dWAr1H08c3a1rt6TL38kkG3JHPSKOM2fooAWVsu0LLuT +5Rcf/w3GQ/4xNPgo2HXpo7uIgu+jcuJTYgVFTeAxl++qnRDSWA2eBp4yuxsIVl1l +Dz9mjsI2oBH/wFk1/Ukc3RxCMwZ4rgQ4I+XndWfTlK1aqUAfrFkQ9QzBZK1KxMY1 +U7OWaoIbFYvRmavknm+UqtKW5Vf7jJFkijwkFsbSGb6CYBM7YrDtPh2zyvlr3zG5 +ep5LR2inKcc/SuIiJ7TvkGPX79ByST5brbkb1Ctvhmjd1XMSuEPJ3EEPoqNGT4tn +iIQPYf55NB9KiR+3AgMBAAGjeTB3MB0GA1UdDgQWBBTnm+IqrYpsOst2UeWOB5gi +l+FzojAfBgNVHSMEGDAWgBS0ETPx1+Je91OeICIQT4YGvx/JXjAJBgNVHRMEAjAA +MA8GA1UdJQQIMAYGBFUdJQAwGQYDVR0RBBIwEIIOYW55RUtVLmV4YW1wbGUwDQYJ +KoZIhvcNAQELBQADggEBAHsj3+ADaGADLg4o08JMlfQTjm5wLYiceuN8Xh9VYLCs +of5TN81iE88aRdFIdIMXCWC8rgadtIPA4W+OgDr032R9eAO7TbIOBGgfDePoo508 +lKXwR8dwDovNVHpLMOQNLpXKn7XTt1h4pd6OfQmyTm7tvjuoGMP3M4lH51P2BweI +V/wNi2DqJ3qc+Cmsc0HPfpN+f07v9WoamScFgiPT0gqAoWOWeB3sfrRoB2tvyc3E +zk6aSqFMVc/Bz5dY6Z0PCXs4dDEu24imibCnwbEfFnB69+1bRC1L+EJWAoIey7ZY +WrwcwC+lmuA4F+TDfTpTb12FmMLkyS3eaUOoFZj3RGo= +-----END CERTIFICATE----- diff --git a/test/certs/ee_noEKU.pem b/test/certs/ee_noEKU.pem new file mode 100644 index 00000000000000..cb6cff04dbce89 --- /dev/null +++ b/test/certs/ee_noEKU.pem @@ -0,0 +1,18 @@ +-----BEGIN CERTIFICATE----- +MIIC7zCCAdegAwIBAgIBAjANBgkqhkiG9w0BAQsFADANMQswCQYDVQQDDAJDQTAg +Fw0yMTAzMDIxMTMxMjRaGA8yMTIxMDMwMzExMzEyNFowGDEWMBQGA1UEAwwNbm9F +S1UuZXhhbXBsZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKj/iVhh +ha7e2ywP1XP74reoG3p1YCvUfTxzdrWu3pMvfySQbckc9Io4zZ+igBZWy7Qsu5Pl +Fx//DcZD/jE0+CjYdemju4iC76Ny4lNiBUVN4DGX76qdENJYDZ4GnjK7GwhWXWUP +P2aOwjagEf/AWTX9SRzdHEIzBniuBDgj5ed1Z9OUrVqpQB+sWRD1DMFkrUrExjVT +s5ZqghsVi9GZq+Seb5Sq0pblV/uMkWSKPCQWxtIZvoJgEztisO0+HbPK+WvfMbl6 +nktHaKcpxz9K4iIntO+QY9fv0HJJPlutuRvUK2+GaN3VcxK4Q8ncQQ+io0ZPi2eI +hA9h/nk0H0qJH7cCAwEAAaNNMEswCQYDVR0TBAIwADAdBgNVHQ4EFgQU55viKq2K +bDrLdlHljgeYIpfhc6IwHwYDVR0jBBgwFoAUtBEz8dfiXvdTniAiEE+GBr8fyV4w +DQYJKoZIhvcNAQELBQADggEBAB+IN5irwpexB0AciBm+2ViGta+p1Fg+BNvRQ/s+ +zOyY7Vb+sVqHaUDhPiwAnzKNf2stFwop0yCIu0qC6pWb+AGr/PWGWEfs8toka5yf +MmiPpLzaVBDzIyctByEJcitoGf1GtGeebXjK+0R7a9OZ73ZXwBGq6nSnG5zLDDw6 +Ak30kF6UlFa8rclViDFaNo+NW7Cnz+V++jIUE5f2nuJgToHB9B6LmfqtoNt0l8h8 +bWpkUIDFWZ8nkW1EmZSyc26M8URvaWimtL+w+WuQGOAaaY6KMYadKiRI1O6xSEtZ +vlj+B3eEHDOM9sVteFeqU878gaC2Cdnwr8oixT5iT7XK0tA= +-----END CERTIFICATE----- diff --git a/test/certs/root_anyEKU.pem b/test/certs/root_anyEKU.pem new file mode 100644 index 00000000000000..b8662de878fbd0 --- /dev/null +++ b/test/certs/root_anyEKU.pem @@ -0,0 +1,19 @@ +-----BEGIN CERTIFICATE----- +MIIDEjCCAfqgAwIBAgIBATANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290 +IENBMCAXDTIxMDMwMjE0NTg1OVoYDzIxMjEwMzAzMTQ1ODU5WjASMRAwDgYDVQQD +DAdSb290IENBMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4eYA9Qa8 +oEY4eQ8/HnEZE20C3yubdmv8rLAh7daRCEI7pWM17FJboKJKxdYAlAOXWj25ZyjS +feMhXKTtxjyNjoTRnVTDPdl0opZ2Z3H5xhpQd7P9eO5b4OOMiSPCmiLsPtQ3ngfN +wCtVERc6NEIcaQ06GLDtFZRexv2eh8Yc55QaksBfBcFzQ+UD3gmRySTO2I6Lfi7g +MUjRhipqVSZ66As2Tpex4KTJ2lxpSwOACFaDox+yKrjBTP7FsU3UwAGq7b7OJb3u +aa32B81uK6GJVPVo65gJ7clgZsszYkoDsGjWDqtfwTVVfv1G7rrr3Laio+2Ff3ff +tWgiQ35mJCOvxQIDAQABo3EwbzAPBgNVHRMBAf8EBTADAQH/MAsGA1UdDwQEAwIB +BjAdBgNVHQ4EFgQUjvUlrx6ba4Q9fICayVOcTXL3o1IwHwYDVR0jBBgwFoAUjvUl +rx6ba4Q9fICayVOcTXL3o1IwDwYDVR0lBAgwBgYEVR0lADANBgkqhkiG9w0BAQsF +AAOCAQEADm1f/mfxf0Yk/EJgHGOLNBAq4Ows5LRQ62YgpAZc6+U4tyc5NGdGnmtd +4SH0w+/IC8gZ/B0Kj2Hyb0EX2yW+ukohJJQ4ETt8Y58Qj1mM83tAeC1TLokzLLJ5 +iFovUOaPfv3Oycdr2dOVMjHDZtWcpNrPdMwTaDI7UiVp9EdJHTy7TwQCxHz6XQxJ +DkY/Djo2Y0pfYuVHb1lhcnRZJim0Y7Zv/F79A7q76OZr4mQOrxtlQdt2S+bOgqMv +g3U3/riAhNTWEJlKtJh80xSnSVrgxohv0D2tNrTkPCWWIGFZeayVOIfvuItmmmhq +ykEU07qzpFJaUZwAeK233vEZ+C1cLA== +-----END CERTIFICATE----- diff --git a/test/certs/setup.sh b/test/certs/setup.sh index 4280ac3a8d30c2..8f525234d17d55 100755 --- a/test/certs/setup.sh +++ b/test/certs/setup.sh @@ -11,6 +11,8 @@ DAYS=-1 ./mkcert.sh genroot "Root CA" root-key root-expired ./mkcert.sh genroot "Cross Root" cross-key cross-root ./mkcert.sh genca "Root CA" root-key root-cross-cert cross-key cross-root # trust variants: +serverAuth -serverAuth +clientAuth -clientAuth +# +./mkcert.sh genroot "Root CA" root-key root_anyEKU anyExtendedKeyUsage openssl x509 -in root-cert.pem -trustout \ -addtrust serverAuth -out root+serverAuth.pem openssl x509 -in root-cert.pem -trustout \ @@ -87,6 +89,8 @@ openssl x509 -in sroot-cert.pem -trustout \ ./mkcert.sh genca "CA" ca-key ca-root2 root-key2 root-cert2 DAYS=-1 ./mkcert.sh genca "CA" ca-key ca-expired root-key root-cert # trust variants: +serverAuth, -serverAuth, +clientAuth, -clientAuth +# +./mkcert.sh genca -p anyExtendedKeyUsage "CA" ca-key ca_anyEKU root-key root-cert openssl x509 -in ca-cert.pem -trustout \ -addtrust serverAuth -out ca+serverAuth.pem openssl x509 -in ca-cert.pem -trustout \ @@ -165,6 +169,11 @@ openssl x509 -in sca-cert.pem -trustout \ # purpose variants: clientAuth ./mkcert.sh genee -p clientAuth server.example ee-key ee-client ca-key ca-cert # trust variants: +serverAuth, -serverAuth, +clientAuth, -clientAuth +# +# EKU variants: anyExtendedKeyUsage, none +./mkcert.sh genee -p anyExtendedKeyUsage anyEKU.example ee-key ee_anyEKU ca-key ca-cert +./mkcert.sh genee noEKU.example ee-key ee_noEKU ca-key ca-cert \ + -extfile <(echo "basicConstraints=CA:false") # bash needed here openssl x509 -in ee-cert.pem -trustout \ -addtrust serverAuth -out ee+serverAuth.pem openssl x509 -in ee-cert.pem -trustout \ diff --git a/test/recipes/25-test_verify.t b/test/recipes/25-test_verify.t index 1c8fce86fd86a1..cf8e8fec490650 100644 --- a/test/recipes/25-test_verify.t +++ b/test/recipes/25-test_verify.t @@ -29,7 +29,7 @@ sub verify { run(app([@args])); } -plan tests => 193; +plan tests => 202; # Canonical success ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"]), @@ -104,6 +104,26 @@ ok(!verify("ee-cert", "sslserver", [qw(sroot-anyEKU)], [qw(ca-cert)]), ok(!verify("ee-cert", "sslserver", [qw(croot-anyEKU)], [qw(ca-cert)]), "fail wildcard mistrust with client purpose"); +# Directly checking Extended Key Usage +ok(verify("ee-cert", "", ["root-cert"], ["ca-cert"], "-eku", "serverAuth"), + "accept required EKU OID contained in EE cert, no EKU in CA cert"); +ok(verify("ee-cert", "sslclient", ["root-cert"], ["ca-cert"], "-eku", "serverAuth"), + "accept required EKU OID contained in EE cert, overriding -purpose"); +ok(verify("ee-cert", "", ["root-cert"], ["ca-cert"], "-eku", "anyExtendedKeyUsage"), + "accept required anyExtendedKeyUsage OID, which is not contained in EE cert"); +ok(verify("ee_anyEKU", "", ["root-cert"], ["ca-cert"], "-eku", "serverAuth"), + "accept required EKU OID with anyEKU contained in EE cert"); +ok(verify("ee_noEKU", "", ["root-cert"], ["ca-cert"], "-eku", "serverAuth"), + "accept required EKU OID with no EKU contained in EE cert"); +ok(!verify("ee-cert", "", ["root-cert"], ["ca-cert"], "-eku", "clientAuth"), + "reject required EKU OID not contained in EE cert"); +ok(verify("ee-cert", "", ["root-cert"], ["sca-cert"], "-eku", "serverAuth"), + "accept required EKU OID contained in CA cert"); +ok(!verify("ee-cert", "", ["root-cert"], ["cca-cert"], "-eku", "serverAuth"), + "reject required EKU OID not contained in CA cert"); +ok(verify("ee-cert", "", ["root-cert"], ["ca_anyEKU"], "-eku", "serverAuth"), + "accept required EKU OID with anyEKU contained in CA cert"); + # Check that trusted-first is on by setting up paths to different roots # depending on whether the intermediate is the trusted or untrusted one. # diff --git a/util/libcrypto.num b/util/libcrypto.num index 72ebbe037eb472..a2545eb71d778e 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5650,6 +5650,8 @@ X509_ACERT_get_ext_d2i ? 3_4_0 EXIST::FUNCTION: X509_ACERT_add1_ext_i2d ? 3_4_0 EXIST::FUNCTION: X509_ACERT_get0_extensions ? 3_4_0 EXIST::FUNCTION: X509v3_add_extensions ? 3_4_0 EXIST::FUNCTION: +X509_VERIFY_PARAM_set_eku ? 3_4_0 EXIST::FUNCTION: +X509_check_eku ? 3_4_0 EXIST::FUNCTION: OSSL_IETF_ATTR_SYNTAX_VALUE_it ? 3_4_0 EXIST::FUNCTION: OSSL_IETF_ATTR_SYNTAX_VALUE_free ? 3_4_0 EXIST::FUNCTION: OSSL_IETF_ATTR_SYNTAX_VALUE_new ? 3_4_0 EXIST::FUNCTION: diff --git a/util/libssl.num b/util/libssl.num index cd2c7f06a16d7c..857e3a91517a81 100644 --- a/util/libssl.num +++ b/util/libssl.num @@ -584,5 +584,7 @@ SSL_poll 584 3_3_0 EXIST::FUNCTION: SSL_SESSION_get_time_ex 585 3_3_0 EXIST::FUNCTION: SSL_SESSION_set_time_ex 586 3_3_0 EXIST::FUNCTION: SSL_CTX_flush_sessions_ex 587 3_4_0 EXIST::FUNCTION: +SSL_CTX_set_eku ? 3_4_0 EXIST::FUNCTION: +SSL_set_eku ? 3_4_0 EXIST::FUNCTION: SSL_CTX_set_block_padding_ex ? 3_4_0 EXIST::FUNCTION: SSL_set_block_padding_ex ? 3_4_0 EXIST::FUNCTION: