diff options
author | tb <> | 2023-06-25 13:52:27 +0000 |
---|---|---|
committer | tb <> | 2023-06-25 13:52:27 +0000 |
commit | 8919d61b9c2ddf1361401516b4966661c64921e2 (patch) | |
tree | 0a021ec29597e06c18b7ca843457986e9d026455 | |
parent | ee2a1487217437d0cbc8d2cba036b6b755509997 (diff) | |
download | openbsd-8919d61b9c2ddf1361401516b4966661c64921e2.tar.gz openbsd-8919d61b9c2ddf1361401516b4966661c64921e2.tar.bz2 openbsd-8919d61b9c2ddf1361401516b4966661c64921e2.zip |
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
-rw-r--r-- | src/lib/libcrypto/x509/x509_purp.c | 46 |
1 files changed, 45 insertions, 1 deletions
diff --git a/src/lib/libcrypto/x509/x509_purp.c b/src/lib/libcrypto/x509/x509_purp.c index 75d229b03b..f7bc7ea538 100644 --- a/src/lib/libcrypto/x509/x509_purp.c +++ b/src/lib/libcrypto/x509/x509_purp.c | |||
@@ -1,4 +1,4 @@ | |||
1 | /* $OpenBSD: x509_purp.c,v 1.26 2023/06/20 14:21:19 tb Exp $ */ | 1 | /* $OpenBSD: x509_purp.c,v 1.27 2023/06/25 13:52:27 tb Exp $ */ |
2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL | 2 | /* Written by Dr Stephen N Henson (steve@openssl.org) for the OpenSSL |
3 | * project 2001. | 3 | * project 2001. |
4 | */ | 4 | */ |
@@ -441,6 +441,47 @@ setup_crldp(X509 *x) | |||
441 | setup_dp(x, sk_DIST_POINT_value(x->crldp, i)); | 441 | setup_dp(x, sk_DIST_POINT_value(x->crldp, i)); |
442 | } | 442 | } |
443 | 443 | ||
444 | static int | ||
445 | x509_extension_oid_cmp(const X509_EXTENSION *const *a, | ||
446 | const X509_EXTENSION *const *b) | ||
447 | { | ||
448 | return OBJ_cmp((*a)->object, (*b)->object); | ||
449 | } | ||
450 | |||
451 | static int | ||
452 | x509_extension_oids_are_unique(X509 *x509) | ||
453 | { | ||
454 | STACK_OF(X509_EXTENSION) *exts = NULL; | ||
455 | const X509_EXTENSION *prev_ext, *curr_ext; | ||
456 | int i; | ||
457 | int ret = 0; | ||
458 | |||
459 | if (X509_get_ext_count(x509) <= 1) | ||
460 | goto done; | ||
461 | |||
462 | if ((exts = sk_X509_EXTENSION_dup(x509->cert_info->extensions)) == NULL) | ||
463 | goto err; | ||
464 | |||
465 | (void)sk_X509_EXTENSION_set_cmp_func(exts, x509_extension_oid_cmp); | ||
466 | sk_X509_EXTENSION_sort(exts); | ||
467 | |||
468 | prev_ext = sk_X509_EXTENSION_value(exts, 0); | ||
469 | for (i = 1; i < sk_X509_EXTENSION_num(exts); i++) { | ||
470 | curr_ext = sk_X509_EXTENSION_value(exts, i); | ||
471 | if (x509_extension_oid_cmp(&prev_ext, &curr_ext) == 0) | ||
472 | goto err; | ||
473 | prev_ext = curr_ext; | ||
474 | } | ||
475 | |||
476 | done: | ||
477 | ret = 1; | ||
478 | |||
479 | err: | ||
480 | sk_X509_EXTENSION_free(exts); | ||
481 | |||
482 | return ret; | ||
483 | } | ||
484 | |||
444 | static void | 485 | static void |
445 | x509v3_cache_extensions_internal(X509 *x) | 486 | x509v3_cache_extensions_internal(X509 *x) |
446 | { | 487 | { |
@@ -612,6 +653,9 @@ x509v3_cache_extensions_internal(X509 *x) | |||
612 | } | 653 | } |
613 | } | 654 | } |
614 | 655 | ||
656 | if (!x509_extension_oids_are_unique(x)) | ||
657 | x->ex_flags |= EXFLAG_INVALID; | ||
658 | |||
615 | x509_verify_cert_info_populate(x); | 659 | x509_verify_cert_info_populate(x); |
616 | 660 | ||
617 | x->ex_flags |= EXFLAG_SET; | 661 | x->ex_flags |= EXFLAG_SET; |