summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbeck <>2022-11-13 18:37:32 +0000
committerbeck <>2022-11-13 18:37:32 +0000
commitb10fff2d2486c7f66b4a443e8ad68ef2b2021928 (patch)
tree92c8eb7340d7ea5f92ee37794cea4b1cb98a4c26
parentb2adf01da2682fbf7809dc301d850a728803bffd (diff)
downloadopenbsd-b10fff2d2486c7f66b4a443e8ad68ef2b2021928.tar.gz
openbsd-b10fff2d2486c7f66b4a443e8ad68ef2b2021928.tar.bz2
openbsd-b10fff2d2486c7f66b4a443e8ad68ef2b2021928.zip
Check certificate extensions in trusted certificates.
Historically the standards let the implementation decide to either check or ignore the certificate properties of trust anchors. You could either use them simply as a source of a public key which was trusted for everything, or you were also permitted to check the certificate properties and fully enforce them. Hooray for freedumb. OpenSSL changed to checking these with : commit 0daccd4dc1f1ac62181738a91714f35472e50f3c Author: Viktor Dukhovni <openssl-users@dukhovni.org> Date: Thu Jan 28 03:01:45 2016 -0500 BoringSSL currently does not check them, as it also inherited the previous OpenSSL behaviour. It will change to check them in the future. (https://bugs.chromium.org/p/boringssl/issues/detail?id=533)
-rw-r--r--src/lib/libcrypto/x509/x509_internal.h3
-rw-r--r--src/lib/libcrypto/x509/x509_trs.c20
-rw-r--r--src/lib/libcrypto/x509/x509_vfy.c49
3 files changed, 64 insertions, 8 deletions
diff --git a/src/lib/libcrypto/x509/x509_internal.h b/src/lib/libcrypto/x509/x509_internal.h
index beafd365ed..9e80b2d2cf 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.20 2022/11/11 12:02:34 beck Exp $ */ 1/* $OpenBSD: x509_internal.h,v 1.21 2022/11/13 18:37:32 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org> 3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org>
4 * 4 *
@@ -134,6 +134,7 @@ int x509_constraints_check(struct x509_constraints_names *names,
134 struct x509_constraints_names *excluded, int *error); 134 struct x509_constraints_names *excluded, int *error);
135int x509_constraints_chain(STACK_OF(X509) *chain, int *error, 135int x509_constraints_chain(STACK_OF(X509) *chain, int *error,
136 int *depth); 136 int *depth);
137int x509_check_trust_no_compat(X509 *x, int id, int flags);
137void x509_verify_cert_info_populate(X509 *cert); 138void x509_verify_cert_info_populate(X509 *cert);
138int x509_vfy_check_security_level(X509_STORE_CTX *ctx); 139int x509_vfy_check_security_level(X509_STORE_CTX *ctx);
139 140
diff --git a/src/lib/libcrypto/x509/x509_trs.c b/src/lib/libcrypto/x509/x509_trs.c
index a967edf933..23eca4927b 100644
--- a/src/lib/libcrypto/x509/x509_trs.c
+++ b/src/lib/libcrypto/x509/x509_trs.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: x509_trs.c,v 1.26 2022/11/10 16:52:19 beck Exp $ */ 1/* $OpenBSD: x509_trs.c,v 1.27 2022/11/13 18:37:32 beck 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 1999. 3 * project 1999.
4 */ 4 */
@@ -110,8 +110,8 @@ int
110 return oldtrust; 110 return oldtrust;
111} 111}
112 112
113int 113static int
114X509_check_trust(X509 *x, int id, int flags) 114X509_check_trust_internal(X509 *x, int id, int flags, int compat)
115{ 115{
116 X509_TRUST *pt; 116 X509_TRUST *pt;
117 int idx; 117 int idx;
@@ -132,7 +132,7 @@ X509_check_trust(X509 *x, int id, int flags)
132 rv = obj_trust(NID_anyExtendedKeyUsage, x, 0); 132 rv = obj_trust(NID_anyExtendedKeyUsage, x, 0);
133 if (rv != X509_TRUST_UNTRUSTED) 133 if (rv != X509_TRUST_UNTRUSTED)
134 return rv; 134 return rv;
135 return trust_compat(NULL, x, 0); 135 return compat && trust_compat(NULL, x, 0);
136 } 136 }
137 idx = X509_TRUST_get_by_id(id); 137 idx = X509_TRUST_get_by_id(id);
138 if (idx == -1) 138 if (idx == -1)
@@ -142,6 +142,18 @@ X509_check_trust(X509 *x, int id, int flags)
142} 142}
143 143
144int 144int
145X509_check_trust(X509 *x, int id, int flags)
146{
147 return X509_check_trust_internal(x, id, flags, /*compat =*/1);
148}
149
150int
151x509_check_trust_no_compat(X509 *x, int id, int flags)
152{
153 return X509_check_trust_internal(x, id, flags, /*compat =*/0);
154}
155
156int
145X509_TRUST_get_count(void) 157X509_TRUST_get_count(void)
146{ 158{
147 if (!trtable) 159 if (!trtable)
diff --git a/src/lib/libcrypto/x509/x509_vfy.c b/src/lib/libcrypto/x509/x509_vfy.c
index fb87877e72..11bf3d9292 100644
--- a/src/lib/libcrypto/x509/x509_vfy.c
+++ b/src/lib/libcrypto/x509/x509_vfy.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: x509_vfy.c,v 1.103 2022/08/31 07:15:31 tb Exp $ */ 1/* $OpenBSD: x509_vfy.c,v 1.104 2022/11/13 18:37:32 beck Exp $ */
2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com) 2/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
3 * All rights reserved. 3 * All rights reserved.
4 * 4 *
@@ -724,6 +724,43 @@ get_issuer_sk(X509 **issuer, X509_STORE_CTX *ctx, X509 *x)
724 return 0; 724 return 0;
725} 725}
726 726
727/*
728 * X509_check_purpose is special.
729 * 0 is bad, 1 is good, values > 1 are maybe good for web pki necromancy
730 * and certificates that were checked into software unit tests years ago
731 * that nobody knows how to change. (Netscape Server Gated Crypto Forever!)
732 */
733#define PURPOSE_GOOD(x) (x == 1)
734#define PURPOSE_BAD(x) (x == 0)
735static int
736check_purpose(X509_STORE_CTX *ctx, X509 *x, int purpose, int depth,
737 int must_be_ca)
738{
739 int purpose_check, trust;
740
741 purpose_check = X509_check_purpose(x, purpose, must_be_ca > 0);
742 trust = X509_TRUST_UNTRUSTED;
743
744 /*
745 * For trusted certificates we want to see whether any auxiliary trust
746 * settings for the desired purpose override the purpose constraints
747 * from the certificate EKU.
748 */
749 if (depth >= ctx->num_untrusted && purpose == ctx->param->purpose)
750 trust = x509_check_trust_no_compat(x, ctx->param->trust, 0);
751
752 /* XXX STRICT should really be the default */
753 if (trust != X509_TRUST_REJECTED && !PURPOSE_BAD(purpose_check)) {
754 return PURPOSE_GOOD(purpose_check) ||
755 (ctx->param->flags & X509_V_FLAG_X509_STRICT) == 0;
756 }
757
758 ctx->error = X509_V_ERR_INVALID_PURPOSE;
759 ctx->error_depth = depth;
760 ctx->current_cert = x;
761 return ctx->verify_cb(0, ctx);
762}
763
727/* Check a certificate chains extensions for consistency 764/* Check a certificate chains extensions for consistency
728 * with the supplied purpose 765 * with the supplied purpose
729 */ 766 */
@@ -740,6 +777,7 @@ x509_vfy_check_chain_extensions(X509_STORE_CTX *ctx)
740 int proxy_path_length = 0; 777 int proxy_path_length = 0;
741 int purpose; 778 int purpose;
742 int allow_proxy_certs; 779 int allow_proxy_certs;
780 size_t chain_len;
743 781
744 cb = ctx->verify_cb; 782 cb = ctx->verify_cb;
745 783
@@ -763,8 +801,8 @@ x509_vfy_check_chain_extensions(X509_STORE_CTX *ctx)
763 purpose = ctx->param->purpose; 801 purpose = ctx->param->purpose;
764 } 802 }
765 803
766 /* Check all untrusted certificates */ 804 chain_len = sk_X509_num(ctx->chain);
767 for (i = 0; i < ctx->num_untrusted; i++) { 805 for (i = 0; i < chain_len; i++) {
768 int ret; 806 int ret;
769 x = sk_X509_value(ctx->chain, i); 807 x = sk_X509_value(ctx->chain, i);
770 if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) && 808 if (!(ctx->param->flags & X509_V_FLAG_IGNORE_CRITICAL) &&
@@ -818,6 +856,11 @@ x509_vfy_check_chain_extensions(X509_STORE_CTX *ctx)
818 if (!ok) 856 if (!ok)
819 goto end; 857 goto end;
820 } 858 }
859 if (purpose > 0) {
860 ok = check_purpose(ctx, x, purpose, i, must_be_ca);
861 if (!ok)
862 goto end;
863 }
821 if (ctx->param->purpose > 0) { 864 if (ctx->param->purpose > 0) {
822 ret = X509_check_purpose(x, purpose, must_be_ca > 0); 865 ret = X509_check_purpose(x, purpose, must_be_ca > 0);
823 if ((ret == 0) || 866 if ((ret == 0) ||