diff --git a/CHANGES.md b/CHANGES.md index d3e5f18ffda30..274f4ac042bd4 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -70,6 +70,14 @@ OpenSSL 3.5 *David von Oheimb* + * `X509_PURPOSE_add()` has been fixed to take as the primary purpose identifier + not the `id` but the `sname` parameter. + For its convenient use, `X509_PURPOSE_get_fresh_id()` has been added. + + This work was sponsored by Siemens AG. + + *David von Oheimb* + * Optionally allow the FIPS provider to use the `JITTER` entropy source. Note that using this option will require the resulting FIPS provider to undergo entropy source validation [ESV] by the [CMVP], without this diff --git a/crypto/err/openssl.txt b/crypto/err/openssl.txt index 85157a19fbadd..dda5229b5d6cb 100644 --- a/crypto/err/openssl.txt +++ b/crypto/err/openssl.txt @@ -1811,6 +1811,7 @@ X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED:157:\ policy path length already defined X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY:159:\ policy when proxy language requires no policy +X509V3_R_PURPOSE_NOT_UNIQUE:173:purpose not unique X509V3_R_SECTION_NOT_FOUND:150:section not found X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS:122:unable to get issuer details X509V3_R_UNABLE_TO_GET_ISSUER_KEYID:123:unable to get issuer keyid diff --git a/crypto/x509/v3_purp.c b/crypto/x509/v3_purp.c index c633474bdcf4f..1eb4c36fc19f3 100644 --- a/crypto/x509/v3_purp.c +++ b/crypto/x509/v3_purp.c @@ -42,6 +42,7 @@ 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); +/* note that the id must be unique and for the standard entries == idx + 1 */ static X509_PURPOSE xstandard[] = { {X509_PURPOSE_SSL_CLIENT, X509_TRUST_SSL_CLIENT, 0, check_purpose_ssl_client, "SSL client", "sslclient", NULL}, @@ -70,6 +71,7 @@ static X509_PURPOSE xstandard[] = { #define X509_PURPOSE_COUNT OSSL_NELEM(xstandard) +/* the id must be unique, but there may be gaps and maybe table is not sorted */ static STACK_OF(X509_PURPOSE) *xptable = NULL; static int xp_cmp(const X509_PURPOSE *const *a, const X509_PURPOSE *const *b) @@ -118,6 +120,16 @@ int X509_PURPOSE_get_count(void) return sk_X509_PURPOSE_num(xptable) + X509_PURPOSE_COUNT; } +/* find smallest identifier not yet taken - note there might be gaps */ +int X509_PURPOSE_get_fresh_id(void) +{ + int id = X509_PURPOSE_MAX + 1; + + while (X509_PURPOSE_get_by_id(id) != -1) + id++; + return id; /* is guaranteed to be unique and > X509_PURPOSE_MAX and != 0 */ +} + X509_PURPOSE *X509_PURPOSE_get0(int idx) { if (idx < 0) @@ -157,26 +169,49 @@ int X509_PURPOSE_get_by_id(int purpose) return idx + X509_PURPOSE_COUNT; } +/* + * Add purpose entry identified by |sname|. |id| must be >= X509_PURPOSE_MIN. + * May also be used to modify existing entry, including changing its id. + */ int X509_PURPOSE_add(int id, int trust, int flags, int (*ck) (const X509_PURPOSE *, const X509 *, int), const char *name, const char *sname, void *arg) { + int old_id = 0; int idx; X509_PURPOSE *ptmp; + if (id < X509_PURPOSE_MIN) { + ERR_raise(ERR_LIB_X509V3, X509V3_R_INVALID_PURPOSE); + return 0; + } + if (trust < X509_TRUST_DEFAULT || name == NULL || sname == NULL || ck == NULL) { + ERR_raise(ERR_LIB_X509, ERR_R_PASSED_INVALID_ARGUMENT); + return 0; + } + /* This is set according to what we change: application can't set it */ flags &= ~X509_PURPOSE_DYNAMIC; /* This will always be set for application modified trust entries */ flags |= X509_PURPOSE_DYNAMIC_NAME; + /* Get existing entry if any */ - idx = X509_PURPOSE_get_by_id(id); - /* Need a new entry */ - if (idx == -1) { + idx = X509_PURPOSE_get_by_sname(sname); + if (idx == -1) { /* Need a new entry */ + if (X509_PURPOSE_get_by_id(id) != -1) { + ERR_raise(ERR_LIB_X509V3, X509V3_R_PURPOSE_NOT_UNIQUE); + return 0; + } if ((ptmp = OPENSSL_malloc(sizeof(*ptmp))) == NULL) return 0; ptmp->flags = X509_PURPOSE_DYNAMIC; } else { ptmp = X509_PURPOSE_get0(idx); + old_id = ptmp->purpose; + if (id != old_id && X509_PURPOSE_get_by_id(id) != -1) { + ERR_raise(ERR_LIB_X509V3, X509V3_R_PURPOSE_NOT_UNIQUE); + return 0; + } } /* OPENSSL_free existing name if dynamic */ @@ -210,6 +245,9 @@ int X509_PURPOSE_add(int id, int trust, int flags, ERR_raise(ERR_LIB_X509V3, ERR_R_CRYPTO_LIB); goto err; } + } else if (id != old_id) { + /* on changing existing entry id, make sure to reset 'sorted' */ + (void)sk_X509_PURPOSE_set(xptable, idx, ptmp); } return 1; err: diff --git a/crypto/x509/v3err.c b/crypto/x509/v3err.c index 6a75af4168349..5512f1b317b87 100644 --- a/crypto/x509/v3err.c +++ b/crypto/x509/v3err.c @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2024 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 @@ -21,119 +21,121 @@ static const ERR_STRING_DATA X509V3_str_reasons[] = { {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BAD_VALUE), "bad value"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BN_DEC2BN_ERROR), "bn dec2bn error"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_BN_TO_ASN1_INTEGER_ERROR), - "bn to asn1 integer error"}, + "bn to asn1 integer error"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_DIRNAME_ERROR), "dirname error"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_DISTPOINT_ALREADY_SET), - "distpoint already set"}, + "distpoint already set"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_DUPLICATE_ZONE_ID), - "duplicate zone id"}, + "duplicate zone id"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EMPTY_KEY_USAGE), "empty key usage"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ERROR_CONVERTING_ZONE), - "error converting zone"}, + "error converting zone"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ERROR_CREATING_EXTENSION), - "error creating extension"}, + "error creating extension"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ERROR_IN_EXTENSION), - "error in extension"}, + "error in extension"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXPECTED_A_SECTION_NAME), - "expected a section name"}, + "expected a section name"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_EXISTS), - "extension exists"}, + "extension exists"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_NAME_ERROR), - "extension name error"}, + "extension name error"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_NOT_FOUND), - "extension not found"}, + "extension not found"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_SETTING_NOT_SUPPORTED), - "extension setting not supported"}, + "extension setting not supported"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_EXTENSION_VALUE_ERROR), - "extension value error"}, + "extension value error"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ILLEGAL_EMPTY_EXTENSION), - "illegal empty extension"}, + "illegal empty extension"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INCORRECT_POLICY_SYNTAX_TAG), - "incorrect policy syntax tag"}, + "incorrect policy syntax tag"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_ASNUMBER), - "invalid asnumber"}, + "invalid asnumber"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_ASRANGE), "invalid asrange"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_BOOLEAN_STRING), - "invalid boolean string"}, + "invalid boolean string"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_CERTIFICATE), - "invalid certificate"}, + "invalid certificate"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_EMPTY_NAME), - "invalid empty name"}, + "invalid empty name"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_EXTENSION_STRING), - "invalid extension string"}, + "invalid extension string"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_INHERITANCE), - "invalid inheritance"}, + "invalid inheritance"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_IPADDRESS), - "invalid ipaddress"}, + "invalid ipaddress"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_MULTIPLE_RDNS), - "invalid multiple rdns"}, + "invalid multiple rdns"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NAME), "invalid name"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NULL_ARGUMENT), - "invalid null argument"}, + "invalid null argument"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NULL_VALUE), - "invalid null value"}, + "invalid null value"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NUMBER), "invalid number"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_NUMBERS), "invalid numbers"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_OBJECT_IDENTIFIER), - "invalid object identifier"}, + "invalid object identifier"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_OPTION), "invalid option"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_POLICY_IDENTIFIER), - "invalid policy identifier"}, + "invalid policy identifier"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_PROXY_POLICY_SETTING), - "invalid proxy policy setting"}, + "invalid proxy policy setting"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_PURPOSE), "invalid purpose"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SAFI), "invalid safi"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SECTION), "invalid section"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_INVALID_SYNTAX), "invalid syntax"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_ISSUER_DECODE_ERROR), - "issuer decode error"}, + "issuer decode error"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_MISSING_VALUE), "missing value"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NEED_ORGANIZATION_AND_NUMBERS), - "need organization and numbers"}, + "need organization and numbers"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NEGATIVE_PATHLEN), - "negative pathlen"}, + "negative pathlen"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_CONFIG_DATABASE), - "no config database"}, + "no config database"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_ISSUER_CERTIFICATE), - "no issuer certificate"}, + "no issuer certificate"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_ISSUER_DETAILS), - "no issuer details"}, + "no issuer details"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_POLICY_IDENTIFIER), - "no policy identifier"}, + "no policy identifier"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_PROXY_CERT_POLICY_LANGUAGE_DEFINED), - "no proxy cert policy language defined"}, + "no proxy cert policy language defined"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_PUBLIC_KEY), "no public key"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_NO_SUBJECT_DETAILS), - "no subject details"}, + "no subject details"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_OPERATION_NOT_DEFINED), - "operation not defined"}, + "operation not defined"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_OTHERNAME_ERROR), "othername error"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_LANGUAGE_ALREADY_DEFINED), - "policy language already defined"}, + "policy language already defined"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_PATH_LENGTH), - "policy path length"}, + "policy path length"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED), - "policy path length already defined"}, + "policy path length already defined"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY), - "policy when proxy language requires no policy"}, + "policy when proxy language requires no policy"}, + {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_PURPOSE_NOT_UNIQUE), + "purpose not unique"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_SECTION_NOT_FOUND), - "section not found"}, + "section not found"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS), - "unable to get issuer details"}, + "unable to get issuer details"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNABLE_TO_GET_ISSUER_KEYID), - "unable to get issuer keyid"}, + "unable to get issuer keyid"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_BIT_STRING_ARGUMENT), - "unknown bit string argument"}, + "unknown bit string argument"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_EXTENSION), - "unknown extension"}, + "unknown extension"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_EXTENSION_NAME), - "unknown extension name"}, + "unknown extension name"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_OPTION), "unknown option"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNKNOWN_VALUE), "unknown value"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNSUPPORTED_OPTION), - "unsupported option"}, + "unsupported option"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_UNSUPPORTED_TYPE), - "unsupported type"}, + "unsupported type"}, {ERR_PACK(ERR_LIB_X509V3, 0, X509V3_R_USER_TOO_LONG), "user too long"}, {0, NULL} }; diff --git a/doc/man3/X509_check_purpose.pod b/doc/man3/X509_check_purpose.pod index 4331cfad92c90..01a0d99762380 100644 --- a/doc/man3/X509_check_purpose.pod +++ b/doc/man3/X509_check_purpose.pod @@ -2,7 +2,19 @@ =head1 NAME -X509_check_purpose - Check the purpose of a certificate +X509_check_purpose, +X509_PURPOSE_get_count, +X509_PURPOSE_get_fresh_id, +X509_PURPOSE_get_by_sname, +X509_PURPOSE_get_by_id, +X509_PURPOSE_add, +X509_PURPOSE_cleanup, +X509_PURPOSE_get0, +X509_PURPOSE_get_id, +X509_PURPOSE_get0_name, +X509_PURPOSE_get0_sname, +X509_PURPOSE_get_trust, +X509_PURPOSE_set - functions related to checking the purpose of a certificate =head1 SYNOPSIS @@ -10,9 +22,25 @@ X509_check_purpose - Check the purpose of a certificate int X509_check_purpose(X509 *x, int id, int ca); + int X509_PURPOSE_get_count(void); + int X509_PURPOSE_get_fresh_id(void); + int X509_PURPOSE_get_by_sname(const char *sname); + int X509_PURPOSE_get_by_id(int id); + int X509_PURPOSE_add(int id, int trust, int flags, + int (*ck) (const X509_PURPOSE *, const X509 *, int), + const char *name, const char *sname, void *arg); + void X509_PURPOSE_cleanup(void); + + X509_PURPOSE *X509_PURPOSE_get0(int idx); + int X509_PURPOSE_get_id(const X509_PURPOSE *); + char *X509_PURPOSE_get0_name(const X509_PURPOSE *xp); + char *X509_PURPOSE_get0_sname(const X509_PURPOSE *xp); + int X509_PURPOSE_get_trust(const X509_PURPOSE *xp); + int X509_PURPOSE_set(int *p, int purpose); + =head1 DESCRIPTION -This function checks if certificate I was created with the purpose +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 @@ -34,8 +62,43 @@ Below are the potential ID's that can be checked: The checks performed take into account the X.509 extensions keyUsage, extendedKeyUsage, and basicConstraints. +X509_PURPOSE_get_count() returns the number of currently defined purposes. + +X509_PURPOSE_get_fresh_id() returns the smallest purpose id not yet used. + +X509_PURPOSE_get_by_sname() returns the index of +the purpose with the given short name or -1 if not found. + +X509_PURPOSE_get_by_id() returns the index of +the purpose with the given id or -1 if not found. + +X509_PURPOSE_add() adds or modifies a purpose entry identified by I. +Unless the id stays the same for an existing entry, I must be fresh, +which can be achieved by using the result of X509_PURPOSE_get_fresh_id(). +The function also sets in the entry the trust id I, the given I, +the purpose (long) name I, the short name I, the purpose checking +funktion I of type B, +and its user data I which may be retrieved via the B pointer. + +X509_PURPOSE_cleanup() removes all purposes that are not pre-defined. + +X509_PURPOSE_get0() returns an B pointer or NULL on error. + +X509_PURPOSE_get_id() returns the id of the given B structure. + +X509_PURPOSE_get0_name() returns the (long) name of the given B. + +X509_PURPOSE_get0_sname() returns the short name of the given B. + +X509_PURPOSE_get_trust() returns the trust id of the given B. + +X509_PURPOSE_set() assigns the given I id to the location pointed at by +I

. +This resets to the any purpose if I is B. + =head1 RETURN VALUES +X509_check_purpose() returns the following values. For non-CA checks =over 4 @@ -69,9 +132,39 @@ For CA checks the below integers could be returned with the following meanings: =back +X509_PURPOSE_get_count() returns the number of currently defined purposes. + +X509_PURPOSE_get_fresh_id() returns the smallest purpose id not yet used. + +X509_PURPOSE_get_by_sname() returns the index of +the purpose with the given short name or -1 if not found. + +X509_PURPOSE_get_by_id() returns the index of +the purpose with the given id or -1 if not found. + +int X509_PURPOSE_add() returns 1 on success, 0 on error. + +X509_PURPOSE_cleanup() does not return anything. + +X509_PURPOSE_get0() returns an B pointer or NULL on error. + +X509_PURPOSE_get_id() returns the id of the given B structure. + +X509_PURPOSE_get0_name() returns the (long) name of the given B. + +X509_PURPOSE_get0_sname() returns the short name of the given B. + +X509_PURPOSE_get_trust() returns the trust id of the given B. + +X509_PURPOSE_set() returns 1 on success, 0 on error. + +=head1 HISTORY + +X509_PURPOSE_get_fresh_id() was added in OpensSL 3.5. + =head1 COPYRIGHT -Copyright 2019-2021 The OpenSSL Project Authors. All Rights Reserved. +Copyright 2019-2024 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. diff --git a/include/openssl/x509v3.h.in b/include/openssl/x509v3.h.in index 6e1654bb2b613..21c628a7856e4 100644 --- a/include/openssl/x509v3.h.in +++ b/include/openssl/x509v3.h.in @@ -727,7 +727,6 @@ int X509V3_extensions_print(BIO *out, const char *title, int X509_check_ca(X509 *x); 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); int X509_check_issued(X509 *issuer, X509 *subject); int X509_check_akid(const X509 *issuer, const AUTHORITY_KEYID *akid); void X509_set_proxy_flag(X509 *x); @@ -743,22 +742,26 @@ const GENERAL_NAMES *X509_get0_authority_issuer(X509 *x); const ASN1_INTEGER *X509_get0_authority_serial(X509 *x); int X509_PURPOSE_get_count(void); -X509_PURPOSE *X509_PURPOSE_get0(int idx); +int X509_PURPOSE_get_fresh_id(void); int X509_PURPOSE_get_by_sname(const char *sname); int X509_PURPOSE_get_by_id(int id); int X509_PURPOSE_add(int id, int trust, int flags, int (*ck) (const X509_PURPOSE *, const X509 *, int), const char *name, const char *sname, void *arg); +void X509_PURPOSE_cleanup(void); + +X509_PURPOSE *X509_PURPOSE_get0(int idx); +int X509_PURPOSE_get_id(const X509_PURPOSE *); char *X509_PURPOSE_get0_name(const X509_PURPOSE *xp); char *X509_PURPOSE_get0_sname(const X509_PURPOSE *xp); int X509_PURPOSE_get_trust(const X509_PURPOSE *xp); -void X509_PURPOSE_cleanup(void); -int X509_PURPOSE_get_id(const X509_PURPOSE *); +int X509_PURPOSE_set(int *p, int purpose); STACK_OF(OPENSSL_STRING) *X509_get1_email(X509 *x); STACK_OF(OPENSSL_STRING) *X509_REQ_get1_email(X509_REQ *x); void X509_email_free(STACK_OF(OPENSSL_STRING) *sk); STACK_OF(OPENSSL_STRING) *X509_get1_ocsp(X509 *x); + /* Flags for X509_check_* functions */ /* diff --git a/include/openssl/x509v3err.h b/include/openssl/x509v3err.h index deede27952852..1ed1b2e5b0190 100644 --- a/include/openssl/x509v3err.h +++ b/include/openssl/x509v3err.h @@ -1,6 +1,6 @@ /* * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-2022 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 1995-2024 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 @@ -81,6 +81,7 @@ # define X509V3_R_POLICY_PATH_LENGTH 156 # define X509V3_R_POLICY_PATH_LENGTH_ALREADY_DEFINED 157 # define X509V3_R_POLICY_WHEN_PROXY_LANGUAGE_REQUIRES_NO_POLICY 159 +# define X509V3_R_PURPOSE_NOT_UNIQUE 173 # define X509V3_R_SECTION_NOT_FOUND 150 # define X509V3_R_UNABLE_TO_GET_ISSUER_DETAILS 122 # define X509V3_R_UNABLE_TO_GET_ISSUER_KEYID 123 diff --git a/test/x509_internal_test.c b/test/x509_internal_test.c index dfc8c0bb60d4a..ea5e3172617ea 100644 --- a/test/x509_internal_test.c +++ b/test/x509_internal_test.c @@ -172,9 +172,58 @@ static int test_a2i_ipaddress(int idx) return good; } +static int ck_purp(ossl_unused const X509_PURPOSE *purpose, + ossl_unused const X509 *x, int ca) +{ + return 1; +} + +static int tests_X509_PURPOSE(void) +{ + int id, idx, *p; + X509_PURPOSE *xp; + +#undef LN +#define LN "LN_test" +#undef SN +#define SN "SN_test" +#undef ARGS +#define ARGS(id, sn) id, X509_TRUST_MAX, 0, ck_purp, LN, sn, NULL + return TEST_int_gt((id = X509_PURPOSE_get_fresh_id()), X509_PURPOSE_MAX) + && TEST_int_eq(X509_PURPOSE_get_count() + 1, id) + && TEST_int_eq(X509_PURPOSE_get_by_id(id), -1) + && TEST_int_eq(X509_PURPOSE_get_by_sname(SN), -1) + + /* add new entry with fresh id and fresh sname: */ + && TEST_int_eq(X509_PURPOSE_add(ARGS(id, SN)), 1) + && TEST_int_ne((idx = X509_PURPOSE_get_by_sname(SN)), -1) + && TEST_int_eq(X509_PURPOSE_get_by_id(id), idx) + + /* overwrite same entry, should be idempotent: */ + && TEST_int_eq(X509_PURPOSE_add(ARGS(id, SN)), 1) + && TEST_int_eq(X509_PURPOSE_get_by_sname(SN), idx) + && TEST_int_eq(X509_PURPOSE_get_by_id(id), idx) + + /* fail adding entry with same sname but existing conflicting id: */ + && TEST_int_eq(X509_PURPOSE_add(ARGS(X509_PURPOSE_MAX, SN)), 0) + /* fail adding entry with same existing id but conflicting sname: */ + && TEST_int_eq(X509_PURPOSE_add(ARGS(id, SN"_different")), 0) + + && TEST_ptr((xp = X509_PURPOSE_get0(idx))) + && TEST_int_eq(X509_PURPOSE_get_id(xp), id) + && TEST_str_eq(X509_PURPOSE_get0_name(xp), LN) + && TEST_str_eq(X509_PURPOSE_get0_sname(xp), SN) + && TEST_int_eq(X509_PURPOSE_get_trust(xp), X509_TRUST_MAX) + + && TEST_int_eq(*(p = &xp->purpose), id) + && TEST_int_eq(X509_PURPOSE_set(p, X509_PURPOSE_DEFAULT_ANY), 1) + && TEST_int_eq(X509_PURPOSE_get_id(xp), X509_PURPOSE_DEFAULT_ANY); +} + int setup_tests(void) { ADD_TEST(test_standard_exts); ADD_ALL_TESTS(test_a2i_ipaddress, OSSL_NELEM(a2i_ipaddress_tests)); + ADD_TEST(tests_X509_PURPOSE); return 1; } diff --git a/util/libcrypto.num b/util/libcrypto.num index 663fbfbbaf1b5..fc9ec34f5427e 100644 --- a/util/libcrypto.num +++ b/util/libcrypto.num @@ -5735,6 +5735,7 @@ EVP_PKEY_CTX_set_algor_params 5862 3_4_0 EXIST::FUNCTION: EVP_PKEY_CTX_get_algor_params 5863 3_4_0 EXIST::FUNCTION: EVP_PKEY_CTX_get_algor 5864 3_4_0 EXIST::FUNCTION: EVP_get1_default_properties ? 3_5_0 EXIST::FUNCTION: +X509_PURPOSE_get_fresh_id ? 3_5_0 EXIST::FUNCTION: d2i_OSSL_AUTHORITY_ATTRIBUTE_ID_SYNTAX ? 3_5_0 EXIST::FUNCTION: i2d_OSSL_AUTHORITY_ATTRIBUTE_ID_SYNTAX ? 3_5_0 EXIST::FUNCTION: OSSL_AUTHORITY_ATTRIBUTE_ID_SYNTAX_free ? 3_5_0 EXIST::FUNCTION: diff --git a/util/missingcrypto.txt b/util/missingcrypto.txt index a56491d0f8b94..3dd997b1927b3 100644 --- a/util/missingcrypto.txt +++ b/util/missingcrypto.txt @@ -1108,17 +1108,6 @@ X509_PKEY_free(3) X509_PKEY_new(3) X509_POLICY_NODE_print(3) X509_PUBKEY_it(3) -X509_PURPOSE_add(3) -X509_PURPOSE_cleanup(3) -X509_PURPOSE_get0(3) -X509_PURPOSE_get0_name(3) -X509_PURPOSE_get0_sname(3) -X509_PURPOSE_get_by_id(3) -X509_PURPOSE_get_by_sname(3) -X509_PURPOSE_get_count(3) -X509_PURPOSE_get_id(3) -X509_PURPOSE_get_trust(3) -X509_PURPOSE_set(3) X509_REQ_INFO_it(3) X509_REQ_extension_nid(3) X509_REQ_get1_email(3)