summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorjsing <>2021-01-05 16:45:59 +0000
committerjsing <>2021-01-05 16:45:59 +0000
commit90ef40ae9d614b7e8df22be569d2596374073170 (patch)
tree5a414cc80415ce1baabbba3babc15cc0a7244cee /src/lib
parent8c63e949ca60ff58f50aea6e577f86c886f0a174 (diff)
downloadopenbsd-90ef40ae9d614b7e8df22be569d2596374073170.tar.gz
openbsd-90ef40ae9d614b7e8df22be569d2596374073170.tar.bz2
openbsd-90ef40ae9d614b7e8df22be569d2596374073170.zip
Gracefully handle root certificates being both trusted and untrusted.
When a certificate (namely a root) is specified as both a trusted and untrusted certificate, the new verifier will find multiple chains - the first being back to the trusted root certificate and a second via the root that is untrusted, followed by the trusted root certificate. This situation can be triggered by a server that (unnecessarily) includes the root certificate in its certificate list. While this validates correctly (using the first chain), it means that we encounter a failure while building the second chain due to the root certificate already being in the chain. When this occurs we call the verify callback indicating a bad certificate. Some sensitive software (including bacula and icinga), treat this single bad chain callback as terminal, even though we successfully verify the certificate. Avoid this problem by simply dumping the chain if we encounter a situation where the certificate is already in the chain and also a trusted root - we'll have already picked up the trusted root as a shorter path. Issue with icinga2 initially reported by Theodore Wynnychenko. Fix tested by sthen@ for both bacula and icinga2. ok tb@
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/libcrypto/x509/x509_internal.h3
-rw-r--r--src/lib/libcrypto/x509/x509_verify.c17
2 files changed, 16 insertions, 4 deletions
diff --git a/src/lib/libcrypto/x509/x509_internal.h b/src/lib/libcrypto/x509/x509_internal.h
index 2f2fe47a8f..1ede7b6bad 100644
--- a/src/lib/libcrypto/x509/x509_internal.h
+++ b/src/lib/libcrypto/x509/x509_internal.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: x509_internal.h,v 1.5 2020/11/18 17:00:59 tb Exp $ */ 1/* $OpenBSD: x509_internal.h,v 1.6 2021/01/05 16:45:59 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org> 3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org>
4 * 4 *
@@ -65,6 +65,7 @@ struct x509_verify_ctx {
65 X509_STORE_CTX *xsc; 65 X509_STORE_CTX *xsc;
66 struct x509_verify_chain **chains; /* Validated chains */ 66 struct x509_verify_chain **chains; /* Validated chains */
67 size_t chains_count; 67 size_t chains_count;
68 int dump_chain; /* Dump current chain without erroring */
68 STACK_OF(X509) *roots; /* Trusted roots for this validation */ 69 STACK_OF(X509) *roots; /* Trusted roots for this validation */
69 STACK_OF(X509) *intermediates; /* Intermediates provided by peer */ 70 STACK_OF(X509) *intermediates; /* Intermediates provided by peer */
70 time_t *check_time; /* Time for validity checks */ 71 time_t *check_time; /* Time for validity checks */
diff --git a/src/lib/libcrypto/x509/x509_verify.c b/src/lib/libcrypto/x509/x509_verify.c
index 88a7ef034d..a5b41afb85 100644
--- a/src/lib/libcrypto/x509/x509_verify.c
+++ b/src/lib/libcrypto/x509/x509_verify.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: x509_verify.c,v 1.25 2020/12/16 18:46:29 tb Exp $ */ 1/* $OpenBSD: x509_verify.c,v 1.26 2021/01/05 16:45:59 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org> 3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org>
4 * 4 *
@@ -381,8 +381,18 @@ x509_verify_consider_candidate(struct x509_verify_ctx *ctx, X509 *cert,
381 /* Fail if the certificate is already in the chain */ 381 /* Fail if the certificate is already in the chain */
382 for (i = 0; i < sk_X509_num(current_chain->certs); i++) { 382 for (i = 0; i < sk_X509_num(current_chain->certs); i++) {
383 if (X509_cmp(sk_X509_value(current_chain->certs, i), 383 if (X509_cmp(sk_X509_value(current_chain->certs, i),
384 candidate) == 0) 384 candidate) == 0) {
385 if (is_root_cert) {
386 /*
387 * Someone made a boo-boo and put their root
388 * in with their intermediates - handle this
389 * gracefully as we'll have already picked
390 * this up as a shorter chain.
391 */
392 ctx->dump_chain = 1;
393 }
385 return 0; 394 return 0;
395 }
386 } 396 }
387 397
388 if (ctx->sig_checks++ > X509_VERIFY_MAX_SIGCHECKS) { 398 if (ctx->sig_checks++ > X509_VERIFY_MAX_SIGCHECKS) {
@@ -475,6 +485,7 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert,
475 return; 485 return;
476 486
477 count = ctx->chains_count; 487 count = ctx->chains_count;
488 ctx->dump_chain = 0;
478 ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY; 489 ctx->error = X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT_LOCALLY;
479 ctx->error_depth = depth; 490 ctx->error_depth = depth;
480 if (ctx->xsc != NULL) { 491 if (ctx->xsc != NULL) {
@@ -528,7 +539,7 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert,
528 ctx->xsc->current_cert = cert; 539 ctx->xsc->current_cert = cert;
529 (void) ctx->xsc->verify_cb(1, ctx->xsc); 540 (void) ctx->xsc->verify_cb(1, ctx->xsc);
530 } 541 }
531 } else if (ctx->error_depth == depth) { 542 } else if (ctx->error_depth == depth && !ctx->dump_chain) {
532 (void) x509_verify_cert_error(ctx, cert, depth, 543 (void) x509_verify_cert_error(ctx, cert, depth,
533 ctx->error, 0); 544 ctx->error, 0);
534 } 545 }