summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
authorbeck <>2022-06-28 07:56:34 +0000
committerbeck <>2022-06-28 07:56:34 +0000
commitb88f8532734e13a9a2fcc8470d64c546b9d15ab3 (patch)
tree435b35111450a62496cf4ac38a00aa704fe6980a /src/lib
parent63d6cdd50ac3d7dec72bc659f9c851f2d7ef2f5e (diff)
downloadopenbsd-b88f8532734e13a9a2fcc8470d64c546b9d15ab3.tar.gz
openbsd-b88f8532734e13a9a2fcc8470d64c546b9d15ab3.tar.bz2
openbsd-b88f8532734e13a9a2fcc8470d64c546b9d15ab3.zip
Fix the legacy verifier callback behaviour for untrusted certs.
The verifier callback is used by mutt to do a form of certificate pinning where the callback gets fired and depending on a cert saved to a file will decide to accept an untrusted cert. This corrects two problems that affected this. The callback was not getting the correct depth and chain for the error where mutt would save the certificate in the first place, and then the callback was not getting fired to allow it to override the failing certificate validation. thanks to Avon Robertson <avon.r@xtra.co.nz> for the report and sthen@ for analysis. "The callback is not an API, it's a gordian knot - tb@" ok jsing@
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/libcrypto/x509/x509_verify.c61
1 files changed, 44 insertions, 17 deletions
diff --git a/src/lib/libcrypto/x509/x509_verify.c b/src/lib/libcrypto/x509/x509_verify.c
index 83030672ef..aa14bc1933 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.57 2022/06/27 14:10:22 tb Exp $ */ 1/* $OpenBSD: x509_verify.c,v 1.58 2022/06/28 07:56:34 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2020-2021 Bob Beck <beck@openbsd.org> 3 * Copyright (c) 2020-2021 Bob Beck <beck@openbsd.org>
4 * 4 *
@@ -258,6 +258,25 @@ x509_verify_cert_self_signed(X509 *cert)
258 return (cert->ex_flags & EXFLAG_SS) ? 1 : 0; 258 return (cert->ex_flags & EXFLAG_SS) ? 1 : 0;
259} 259}
260 260
261/* XXX beck - clean up this mess of is_root */
262static int
263x509_verify_check_chain_end(X509 *cert, int full_chain)
264{
265 if (full_chain)
266 return x509_verify_cert_self_signed(cert);
267 return 1;
268}
269
270static int
271x509_verify_check_legacy_chain_end(struct x509_verify_ctx *ctx, X509 *cert,
272 int full_chain)
273{
274 if (X509_check_trust(cert, ctx->xsc->param->trust, 0) !=
275 X509_TRUST_TRUSTED)
276 return 0;
277 return x509_verify_check_chain_end(cert, full_chain);
278}
279
261static int 280static int
262x509_verify_ctx_cert_is_root(struct x509_verify_ctx *ctx, X509 *cert, 281x509_verify_ctx_cert_is_root(struct x509_verify_ctx *ctx, X509 *cert,
263 int full_chain) 282 int full_chain)
@@ -273,15 +292,16 @@ x509_verify_ctx_cert_is_root(struct x509_verify_ctx *ctx, X509 *cert,
273 if ((match = x509_vfy_lookup_cert_match(ctx->xsc, 292 if ((match = x509_vfy_lookup_cert_match(ctx->xsc,
274 cert)) != NULL) { 293 cert)) != NULL) {
275 X509_free(match); 294 X509_free(match);
276 return !full_chain || 295 return x509_verify_check_legacy_chain_end(ctx, cert,
277 x509_verify_cert_self_signed(cert); 296 full_chain);
297
278 } 298 }
279 } else { 299 } else {
280 /* Check the provided roots */ 300 /* Check the provided roots */
281 for (i = 0; i < sk_X509_num(ctx->roots); i++) { 301 for (i = 0; i < sk_X509_num(ctx->roots); i++) {
282 if (X509_cmp(sk_X509_value(ctx->roots, i), cert) == 0) 302 if (X509_cmp(sk_X509_value(ctx->roots, i), cert) == 0)
283 return !full_chain || 303 return x509_verify_check_chain_end(cert,
284 x509_verify_cert_self_signed(cert); 304 full_chain);
285 } 305 }
286 } 306 }
287 307
@@ -393,14 +413,23 @@ x509_verify_ctx_validate_legacy_chain(struct x509_verify_ctx *ctx,
393 ctx->xsc->error = X509_V_OK; 413 ctx->xsc->error = X509_V_OK;
394 ctx->xsc->error_depth = 0; 414 ctx->xsc->error_depth = 0;
395 415
396 trust = x509_vfy_check_trust(ctx->xsc);
397 if (trust == X509_TRUST_REJECTED)
398 goto err;
399
400 if (!x509_verify_ctx_set_xsc_chain(ctx, chain, 0, 1)) 416 if (!x509_verify_ctx_set_xsc_chain(ctx, chain, 0, 1))
401 goto err; 417 goto err;
402 418
403 /* 419 /*
420 * Call the legacy code to walk the chain and check trust
421 * in the legacy way to handle partial chains and get the
422 * callback fired correctly.
423 */
424 trust = x509_vfy_check_trust(ctx->xsc);
425 if (trust == X509_TRUST_REJECTED)
426 goto err; /* callback was called in x509_vfy_check_trust */
427 if (trust != X509_TRUST_TRUSTED) {
428 /* NOTREACHED */
429 goto err; /* should not happen if we get in here - abort? */
430 }
431
432 /*
404 * XXX currently this duplicates some work done in chain 433 * XXX currently this duplicates some work done in chain
405 * build, but we keep it here until we have feature parity 434 * build, but we keep it here until we have feature parity
406 */ 435 */
@@ -432,10 +461,6 @@ x509_verify_ctx_validate_legacy_chain(struct x509_verify_ctx *ctx,
432 if (!x509_vfy_check_policy(ctx->xsc)) 461 if (!x509_vfy_check_policy(ctx->xsc))
433 goto err; 462 goto err;
434 463
435 if ((!(ctx->xsc->param->flags & X509_V_FLAG_PARTIAL_CHAIN)) &&
436 trust != X509_TRUST_TRUSTED)
437 goto err;
438
439 ret = 1; 464 ret = 1;
440 465
441 err: 466 err:
@@ -688,8 +713,8 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert,
688 } 713 }
689 if (ret > 0) { 714 if (ret > 0) {
690 if (x509_verify_potential_parent(ctx, candidate, cert)) { 715 if (x509_verify_potential_parent(ctx, candidate, cert)) {
691 is_root = !full_chain || 716 is_root = x509_verify_check_legacy_chain_end(
692 x509_verify_cert_self_signed(candidate); 717 ctx, candidate, full_chain);
693 x509_verify_consider_candidate(ctx, cert, 718 x509_verify_consider_candidate(ctx, cert,
694 is_root, candidate, current_chain, 719 is_root, candidate, current_chain,
695 full_chain, name); 720 full_chain, name);
@@ -701,8 +726,8 @@ x509_verify_build_chains(struct x509_verify_ctx *ctx, X509 *cert,
701 for (i = 0; i < sk_X509_num(ctx->roots); i++) { 726 for (i = 0; i < sk_X509_num(ctx->roots); i++) {
702 candidate = sk_X509_value(ctx->roots, i); 727 candidate = sk_X509_value(ctx->roots, i);
703 if (x509_verify_potential_parent(ctx, candidate, cert)) { 728 if (x509_verify_potential_parent(ctx, candidate, cert)) {
704 is_root = !full_chain || 729 is_root = x509_verify_check_chain_end(candidate,
705 x509_verify_cert_self_signed(candidate); 730 full_chain);
706 x509_verify_consider_candidate(ctx, cert, 731 x509_verify_consider_candidate(ctx, cert,
707 is_root, candidate, current_chain, 732 is_root, candidate, current_chain,
708 full_chain, name); 733 full_chain, name);
@@ -1168,6 +1193,8 @@ x509_verify(struct x509_verify_ctx *ctx, X509 *leaf, char *name)
1168 * on failure and will be needed for 1193 * on failure and will be needed for
1169 * that. 1194 * that.
1170 */ 1195 */
1196 ctx->xsc->error = ctx->error;
1197 ctx->xsc->error_depth = ctx->error_depth;
1171 if (!x509_verify_ctx_save_xsc_error(ctx)) { 1198 if (!x509_verify_ctx_save_xsc_error(ctx)) {
1172 x509_verify_chain_free(current_chain); 1199 x509_verify_chain_free(current_chain);
1173 goto err; 1200 goto err;