From a7f5be1e7fa305450c9df264a8350f39e4793333 Mon Sep 17 00:00:00 2001 From: tb Date: Sun, 25 Jun 2023 13:52:27 +0000 Subject: [PATCH] Check for duplicate X.509v3 extension OIDs Per RFC 5280, 4.2: A certificate MUST NOT include more than one instance of a particular extension. This implements such a check in x509v3_cache_extensions() by sorting the list of extensions and looking for duplicate neighbors. This sidesteps complications from extensions we do not know about and keeps algorithmic complexity reasonable. If the check fails, EXFLAG_INVALID is set on the certificate, which means that the verifier will not validate it. ok jsing --- lib/libcrypto/x509/x509_purp.c | 46 +++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/lib/libcrypto/x509/x509_purp.c b/lib/libcrypto/x509/x509_purp.c index 75d229b03bd..f7bc7ea538d 100644 --- a/lib/libcrypto/x509/x509_purp.c +++ b/lib/libcrypto/x509/x509_purp.c @@ -1,4 +1,4 @@ -/* $OpenBSD: x509_purp.c,v 1.26 2023/06/20 14:21:19 tb Exp $ */ +/* $OpenBSD: x509_purp.c,v 1.27 2023/06/25 13:52:27 tb Exp $ */ /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL * project 2001. */ @@ -441,6 +441,47 @@ setup_crldp(X509 *x) setup_dp(x, sk_DIST_POINT_value(x->crldp, i)); } +static int +x509_extension_oid_cmp(const X509_EXTENSION *const *a, + const X509_EXTENSION *const *b) +{ + return OBJ_cmp((*a)->object, (*b)->object); +} + +static int +x509_extension_oids_are_unique(X509 *x509) +{ + STACK_OF(X509_EXTENSION) *exts = NULL; + const X509_EXTENSION *prev_ext, *curr_ext; + int i; + int ret = 0; + + if (X509_get_ext_count(x509) <= 1) + goto done; + + if ((exts = sk_X509_EXTENSION_dup(x509->cert_info->extensions)) == NULL) + goto err; + + (void)sk_X509_EXTENSION_set_cmp_func(exts, x509_extension_oid_cmp); + sk_X509_EXTENSION_sort(exts); + + prev_ext = sk_X509_EXTENSION_value(exts, 0); + for (i = 1; i < sk_X509_EXTENSION_num(exts); i++) { + curr_ext = sk_X509_EXTENSION_value(exts, i); + if (x509_extension_oid_cmp(&prev_ext, &curr_ext) == 0) + goto err; + prev_ext = curr_ext; + } + + done: + ret = 1; + + err: + sk_X509_EXTENSION_free(exts); + + return ret; +} + static void x509v3_cache_extensions_internal(X509 *x) { @@ -612,6 +653,9 @@ x509v3_cache_extensions_internal(X509 *x) } } + if (!x509_extension_oids_are_unique(x)) + x->ex_flags |= EXFLAG_INVALID; + x509_verify_cert_info_populate(x); x->ex_flags |= EXFLAG_SET; -- 2.20.1