1 |
From c927a3492698c254637da836762f9b1f86cffabc Mon Sep 17 00:00:00 2001 |
2 |
From: Viktor Dukhovni <openssl-users@dukhovni.org> |
3 |
Date: Tue, 13 Dec 2022 08:49:13 +0100 |
4 |
Subject: [PATCH 01/18] Fix type confusion in nc_match_single() |
5 |
|
6 |
This function assumes that if the "gen" is an OtherName, then the "base" |
7 |
is a rfc822Name constraint. This assumption is not true in all cases. |
8 |
If the end-entity certificate contains an OtherName SAN of any type besides |
9 |
SmtpUtf8Mailbox and the CA certificate contains a name constraint of |
10 |
OtherName (of any type), then "nc_email_eai" will be invoked, with the |
11 |
OTHERNAME "base" being incorrectly interpreted as a ASN1_IA5STRING. |
12 |
|
13 |
Reported by Corey Bonnell from Digicert. |
14 |
|
15 |
CVE-2022-4203 |
16 |
|
17 |
Reviewed-by: Paul Dale <pauli@openssl.org> |
18 |
Reviewed-by: Hugo Landau <hlandau@openssl.org> |
19 |
Reviewed-by: Tomas Mraz <tomas@openssl.org> |
20 |
--- |
21 |
crypto/x509/v3_ncons.c | 45 +++++++++++++++++++++++++++++------------- |
22 |
1 file changed, 31 insertions(+), 14 deletions(-) |
23 |
|
24 |
diff --git a/crypto/x509/v3_ncons.c b/crypto/x509/v3_ncons.c |
25 |
index 70a7e8304e..5101598512 100644 |
26 |
--- a/crypto/x509/v3_ncons.c |
27 |
+++ b/crypto/x509/v3_ncons.c |
28 |
@@ -31,7 +31,8 @@ static int do_i2r_name_constraints(const X509V3_EXT_METHOD *method, |
29 |
static int print_nc_ipadd(BIO *bp, ASN1_OCTET_STRING *ip); |
30 |
|
31 |
static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc); |
32 |
-static int nc_match_single(GENERAL_NAME *sub, GENERAL_NAME *gen); |
33 |
+static int nc_match_single(int effective_type, GENERAL_NAME *sub, |
34 |
+ GENERAL_NAME *gen); |
35 |
static int nc_dn(const X509_NAME *sub, const X509_NAME *nm); |
36 |
static int nc_dns(ASN1_IA5STRING *sub, ASN1_IA5STRING *dns); |
37 |
static int nc_email(ASN1_IA5STRING *sub, ASN1_IA5STRING *eml); |
38 |
@@ -472,14 +473,17 @@ static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc) |
39 |
{ |
40 |
GENERAL_SUBTREE *sub; |
41 |
int i, r, match = 0; |
42 |
+ int effective_type = gen->type; |
43 |
+ |
44 |
/* |
45 |
* We need to compare not gen->type field but an "effective" type because |
46 |
* the otherName field may contain EAI email address treated specially |
47 |
* according to RFC 8398, section 6 |
48 |
*/ |
49 |
- int effective_type = ((gen->type == GEN_OTHERNAME) && |
50 |
- (OBJ_obj2nid(gen->d.otherName->type_id) == |
51 |
- NID_id_on_SmtpUTF8Mailbox)) ? GEN_EMAIL : gen->type; |
52 |
+ if (effective_type == GEN_OTHERNAME && |
53 |
+ (OBJ_obj2nid(gen->d.otherName->type_id) == NID_id_on_SmtpUTF8Mailbox)) { |
54 |
+ effective_type = GEN_EMAIL; |
55 |
+ } |
56 |
|
57 |
/* |
58 |
* Permitted subtrees: if any subtrees exist of matching the type at |
59 |
@@ -488,7 +492,10 @@ static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc) |
60 |
|
61 |
for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++) { |
62 |
sub = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i); |
63 |
- if (effective_type != sub->base->type) |
64 |
+ if (effective_type != sub->base->type |
65 |
+ || (effective_type == GEN_OTHERNAME && |
66 |
+ OBJ_cmp(gen->d.otherName->type_id, |
67 |
+ sub->base->d.otherName->type_id) != 0)) |
68 |
continue; |
69 |
if (!nc_minmax_valid(sub)) |
70 |
return X509_V_ERR_SUBTREE_MINMAX; |
71 |
@@ -497,7 +504,7 @@ static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc) |
72 |
continue; |
73 |
if (match == 0) |
74 |
match = 1; |
75 |
- r = nc_match_single(gen, sub->base); |
76 |
+ r = nc_match_single(effective_type, gen, sub->base); |
77 |
if (r == X509_V_OK) |
78 |
match = 2; |
79 |
else if (r != X509_V_ERR_PERMITTED_VIOLATION) |
80 |
@@ -511,12 +518,15 @@ static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc) |
81 |
|
82 |
for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->excludedSubtrees); i++) { |
83 |
sub = sk_GENERAL_SUBTREE_value(nc->excludedSubtrees, i); |
84 |
- if (effective_type != sub->base->type) |
85 |
+ if (effective_type != sub->base->type |
86 |
+ || (effective_type == GEN_OTHERNAME && |
87 |
+ OBJ_cmp(gen->d.otherName->type_id, |
88 |
+ sub->base->d.otherName->type_id) != 0)) |
89 |
continue; |
90 |
if (!nc_minmax_valid(sub)) |
91 |
return X509_V_ERR_SUBTREE_MINMAX; |
92 |
|
93 |
- r = nc_match_single(gen, sub->base); |
94 |
+ r = nc_match_single(effective_type, gen, sub->base); |
95 |
if (r == X509_V_OK) |
96 |
return X509_V_ERR_EXCLUDED_VIOLATION; |
97 |
else if (r != X509_V_ERR_PERMITTED_VIOLATION) |
98 |
@@ -528,15 +538,22 @@ static int nc_match(GENERAL_NAME *gen, NAME_CONSTRAINTS *nc) |
99 |
|
100 |
} |
101 |
|
102 |
-static int nc_match_single(GENERAL_NAME *gen, GENERAL_NAME *base) |
103 |
+static int nc_match_single(int effective_type, GENERAL_NAME *gen, |
104 |
+ GENERAL_NAME *base) |
105 |
{ |
106 |
switch (gen->type) { |
107 |
case GEN_OTHERNAME: |
108 |
- /* |
109 |
- * We are here only when we have SmtpUTF8 name, |
110 |
- * so we match the value of othername with base->d.rfc822Name |
111 |
- */ |
112 |
- return nc_email_eai(gen->d.otherName->value, base->d.rfc822Name); |
113 |
+ switch (effective_type) { |
114 |
+ case GEN_EMAIL: |
115 |
+ /* |
116 |
+ * We are here only when we have SmtpUTF8 name, |
117 |
+ * so we match the value of othername with base->d.rfc822Name |
118 |
+ */ |
119 |
+ return nc_email_eai(gen->d.otherName->value, base->d.rfc822Name); |
120 |
+ |
121 |
+ default: |
122 |
+ return X509_V_ERR_UNSUPPORTED_CONSTRAINT_TYPE; |
123 |
+ } |
124 |
|
125 |
case GEN_DIRNAME: |
126 |
return nc_dn(gen->d.directoryName, base->d.directoryName); |
127 |
-- |
128 |
2.39.1 |
129 |
|
130 |
From fe6842f5a5dc2fb66da7fb24bf4343a3aeedd50a Mon Sep 17 00:00:00 2001 |
131 |
From: Tomas Mraz <tomas@openssl.org> |
132 |
Date: Tue, 13 Dec 2022 19:45:09 +0100 |
133 |
Subject: [PATCH 02/18] Add testcase for nc_match_single type confusion |
134 |
|
135 |
Reviewed-by: Paul Dale <pauli@openssl.org> |
136 |
Reviewed-by: Hugo Landau <hlandau@openssl.org> |
137 |
--- |
138 |
test/certs/bad-othername-cert.pem | 20 ++++++++++++++++++++ |
139 |
test/certs/nccaothername-cert.pem | 20 ++++++++++++++++++++ |
140 |
test/certs/nccaothername-key.pem | 28 ++++++++++++++++++++++++++++ |
141 |
test/certs/setup.sh | 11 +++++++++++ |
142 |
test/recipes/25-test_verify.t | 5 ++++- |
143 |
5 files changed, 83 insertions(+), 1 deletion(-) |
144 |
create mode 100644 test/certs/bad-othername-cert.pem |
145 |
create mode 100644 test/certs/nccaothername-cert.pem |
146 |
create mode 100644 test/certs/nccaothername-key.pem |
147 |
|
148 |
diff --git a/test/certs/bad-othername-cert.pem b/test/certs/bad-othername-cert.pem |
149 |
new file mode 100644 |
150 |
index 0000000000..cf279de5ea |
151 |
--- /dev/null |
152 |
+++ b/test/certs/bad-othername-cert.pem |
153 |
@@ -0,0 +1,20 @@ |
154 |
+-----BEGIN CERTIFICATE----- |
155 |
+MIIDRDCCAiygAwIBAgIBAjANBgkqhkiG9w0BAQsFADAfMR0wGwYDVQQDDBRUZXN0 |
156 |
+IE5DIENBIG90aGVybmFtZTAgFw0yMjEyMTMxODMzMTZaGA8yMTIyMTIxNDE4MzMx |
157 |
+NlowMTEvMC0GA1UECgwmTkMgZW1haWwgaW4gb3RoZXJuYW1lIFRlc3QgQ2VydGlm |
158 |
+aWNhdGUwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDPgeoakqHk1zYt |
159 |
+JZpEC0qkJPU/X0lfI+6GY2LHFY9KOSFqqmTXxrUtjQc3SdpQvBZhPuMZ8p82Jid2 |
160 |
+kkRHnWs0uqX9NtLO923yQalYvP6Mt3fokcYgw/C9b+I/q1PKUyN0kPB6McROguD5 |
161 |
+Jz2DcEufJBhbpyay1bFjEI2DAQJKDP/U7uH0EA7kH/27UMk0vfvL5uVjDvlo8i6S |
162 |
+Ul8+u0cDV5ZFJW2VAJKLU3wp6IY4fZl9UqkHZuRQpMJGqAjAleWOIEpyyvfGGh0b |
163 |
+75n3GJ+4YZ7CIBEgY7K0nIbKxtcDZPvmtbYg3g1tkPMTHcodFT7yEdqkBTJ5AGL7 |
164 |
+6U850OhjAgMBAAGjdzB1MB0GA1UdDgQWBBTBz0k+q6d4c3aM+s2IyOF/QP6zCTAf |
165 |
+BgNVHSMEGDAWgBTwhghX7uNdMejZ3f4XorqOQoMqwTAJBgNVHRMEAjAAMCgGA1Ud |
166 |
+EQQhMB+gHQYIKwYBBQUHCAegEQwPZm9vQGV4YW1wbGUub3JnMA0GCSqGSIb3DQEB |
167 |
+CwUAA4IBAQAhxbCEVH8pq0aUMaLWaodyXdCqA0AKTFG6Mz9Rpwn89OwC8FylTEru |
168 |
+t+Bqx/ZuTo8YzON8h9m7DIrQIjZKDLW/g5YbvIsxIVV9gWhAGohdsIyMKRBepSmr |
169 |
+NxJQkO74RLBTamfl0WUCVM4HqroflFjBBG67CTJaQ9cH9ug3TKxaXCK1L6iQAXtq |
170 |
+enILGai98Byo0LCFH4MQOhmhV1BDT2boIG/iYb5VKCTSX25vhaF+PNBhUoysjW0O |
171 |
+vhQX8vrw42QRr4Qi7VfUBXzrbRTzxjOc4yqki7h2DcEdpginqe+aGyaFY+H9m/ka |
172 |
+1AR5KN8h5SYKltSXknjs0pp1w4k49aHl |
173 |
+-----END CERTIFICATE----- |
174 |
diff --git a/test/certs/nccaothername-cert.pem b/test/certs/nccaothername-cert.pem |
175 |
new file mode 100644 |
176 |
index 0000000000..f9b9b07b80 |
177 |
--- /dev/null |
178 |
+++ b/test/certs/nccaothername-cert.pem |
179 |
@@ -0,0 +1,20 @@ |
180 |
+-----BEGIN CERTIFICATE----- |
181 |
+MIIDPjCCAiagAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDDAdSb290 |
182 |
+IENBMCAXDTIyMTIxMzE4MTgwM1oYDzIxMjIxMjE0MTgxODAzWjAfMR0wGwYDVQQD |
183 |
+DBRUZXN0IE5DIENBIG90aGVybmFtZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCC |
184 |
+AQoCggEBAN0Dx+ei8CgtRKnDcYiLwX4vrA48at/o/zfX24X/WZZM1o9HUKo1FQBN |
185 |
+vhESJu+gqPxuIePrk+/L25XdRqwCKk8wkWX0XIz18q5orOHUUFAWNK3g0FDj6N8H |
186 |
+d8urNIbDJ44FCx+/0n8Ppiht/EYN3aVOW5enqbgZ+EEt+3AUG6ibieRdGri9g4oh |
187 |
+IIx60MmVHLbuT/TcVZxaeWyTl6iWmsYosUyqlhTtu1uGtbVtkCAhBYloVvz4J5eA |
188 |
+mVu/JuJbsNxbxVeO9Q8Kj6nb4jPPdGvZ3JPcabbWrz5LwaereBf5IPrXEVdQTlYB |
189 |
+gI0pTz2CEDHSIrd7jzRUX/9EC2gMk6UCAwEAAaOBjzCBjDAPBgNVHRMBAf8EBTAD |
190 |
+AQH/MAsGA1UdDwQEAwIBBjAdBgNVHQ4EFgQU8IYIV+7jXTHo2d3+F6K6jkKDKsEw |
191 |
+HwYDVR0jBBgwFoAUjvUlrx6ba4Q9fICayVOcTXL3o1IwLAYDVR0eBCUwI6EhMB+g |
192 |
+HQYIKwYBBQUHCAegEQwPZm9vQGV4YW1wbGUub3JnMA0GCSqGSIb3DQEBCwUAA4IB |
193 |
+AQDPI5uZd8DhSNKMvYF5bxOshd6h6UJ7YzZS7K6fhiygltdqzkHQ/5+4yiuUkDe4 |
194 |
+hOZlH8MCfXQy5jVZDTk24yNchpdfie5Bswn4SmQVQh3QyzOLxizoh0rLCf2PHueu |
195 |
+dNVNhfiiJNJ5kd8MIuVG7CPK68dP0QrVR+DihROuJgvGB3ClKttLrgle19t4PFRR |
196 |
+2wW6hJT9aXEjzLNyN1QFZKoShuiGX4xwjZh7VyKkV64p8hjojhcLk6dQkel+Jw4y |
197 |
+OP26XbVfM8/6KG8f6WAZ8P0qJwHlhmi0EvRTnEpAM8WuenOeZH6ERZ9uZbRGh6xx |
198 |
+LKQu2Aw2+bOEZ2vUtz0dBhX8 |
199 |
+-----END CERTIFICATE----- |
200 |
diff --git a/test/certs/nccaothername-key.pem b/test/certs/nccaothername-key.pem |
201 |
new file mode 100644 |
202 |
index 0000000000..d3e300ac2f |
203 |
--- /dev/null |
204 |
+++ b/test/certs/nccaothername-key.pem |
205 |
@@ -0,0 +1,28 @@ |
206 |
+-----BEGIN PRIVATE KEY----- |
207 |
+MIIEvwIBADANBgkqhkiG9w0BAQEFAASCBKkwggSlAgEAAoIBAQDdA8fnovAoLUSp |
208 |
+w3GIi8F+L6wOPGrf6P8319uF/1mWTNaPR1CqNRUATb4REibvoKj8biHj65Pvy9uV |
209 |
+3UasAipPMJFl9FyM9fKuaKzh1FBQFjSt4NBQ4+jfB3fLqzSGwyeOBQsfv9J/D6Yo |
210 |
+bfxGDd2lTluXp6m4GfhBLftwFBuom4nkXRq4vYOKISCMetDJlRy27k/03FWcWnls |
211 |
+k5eolprGKLFMqpYU7btbhrW1bZAgIQWJaFb8+CeXgJlbvybiW7DcW8VXjvUPCo+p |
212 |
+2+Izz3Rr2dyT3Gm21q8+S8Gnq3gX+SD61xFXUE5WAYCNKU89ghAx0iK3e480VF// |
213 |
+RAtoDJOlAgMBAAECggEAMFSJlCyEFlER3Qq9asXe9eRgXEuXdmfZ2aEVIuf8M/sR |
214 |
+B0tpxxKtCUA24j5FL+0CzxKZTCFBnDRIzCyTbf1aOa9t+CzXyUZmP3/p4EdgmabF |
215 |
+dcl93FZ+X7kfF/VUGu0Vmv+c12BH3Fu0cs5cVohlMecg7diu6zCYok43F+L5ymRy |
216 |
+2mTcKkGc0ShWizj8Z9R3WJGssZOlxbxa/Zr4rZwRC24UVhfN8AfGWYx/StyQPQIw |
217 |
+gtbbtOmwbyredQmY4jwNqgrnfZS9bkWwJbRuCmD5l7lxubBgcHQpoM+DQVeOLZIq |
218 |
+uksFXeNfal9G5Bo747MMzpD7dJMCGmX+gbMY5oZF+QKBgQDs2MbY4nbxi+fV+KuV |
219 |
+zUvis8m8Lpzf3T6NLkgSkUPRN9tGr95iLIrB/bRPJg5Ne02q/cT7d86B9rpE42w7 |
220 |
+eeIF9fANezX2AF8LUqNZhIR23J3tfB/eqGlJRZeMNia+lD09a7SWGwrS7sufY1I+ |
221 |
+JQGcHx77ntt+eQT1MUJ1skF06QKBgQDu4z+TW4QIA5ItxIReVdcfh5e3xLkzDEVP |
222 |
+3KNo9tpXxvPwqapdeBh6c9z4Lqe3MKr5UPlDvVW+o40t6OjKxDCXczB8+JAM0OyX |
223 |
+8V+K3zXXUxRgieSd3oMncTylSWIvouPP3aW37B67TKdRlRHgaBrpJT2wdk3kYR4t |
224 |
+62J1eDdjXQKBgQDMsY0pZI/nskJrar7geM1c4IU5Xg+2aj/lRFqFsYYrC1s3fEd2 |
225 |
+EYjan6l1vi4eSLKXVTspGiIfsFzLrMGdpXjyLduJyzKXqTp7TrBebWkOUR0sYloo |
226 |
+1OQprzuKskJJ81P6AVvRXw27vyW8Wtp5WwJJK5xbWq/YXj8qqagGkEiCAQKBgQCc |
227 |
+RK3XAFurPmLGa7JHX5Hc/z8BKMAZo6JHrsZ6qFiGaRA0U1it0hz5JYfcFfECheSi |
228 |
+ORUF+fn4PlbhPGXkFljPCbwjVBovOBA9CNl+J6u50pAW4r1ZhDB5gbqxSQLgtIaf |
229 |
++JcqbFxiG6+sT36lNJS+BO2I3KrxhZJPaZY7z8szxQKBgQDRy70XzwOk8jXayiF2 |
230 |
+ej2IN7Ow9cgSE4tLEwR/vCjxvOlWhA3jC3wxoggshGJkpbP3DqLkQtwQm0h1lM8J |
231 |
+QNtFwKzjtpf//bTlfFq08/YxWimTPMqzcV2PgRacB8P3yf1r8T7M4fA5TORCDWpW |
232 |
+5FtOCFEmwQHTR8lu4c63qfxkEQ== |
233 |
+-----END PRIVATE KEY----- |
234 |
diff --git a/test/certs/setup.sh b/test/certs/setup.sh |
235 |
index b9766aab20..2240cd9df0 100755 |
236 |
--- a/test/certs/setup.sh |
237 |
+++ b/test/certs/setup.sh |
238 |
@@ -388,6 +388,17 @@ REQMASK=MASK:0x800 ./mkcert.sh req badalt7-key "O = Bad NC Test Certificate 7" \ |
239 |
"email.1 = good@good.org" "email.2 = any@good.com" \ |
240 |
"IP = 127.0.0.1" "IP = 192.168.0.1" |
241 |
|
242 |
+# Certs for CVE-2022-4203 testcase |
243 |
+ |
244 |
+NC="excluded;otherName:SRVName;UTF8STRING:foo@example.org" ./mkcert.sh genca \ |
245 |
+ "Test NC CA othername" nccaothername-key nccaothername-cert \ |
246 |
+ root-key root-cert |
247 |
+ |
248 |
+./mkcert.sh req alt-email-key "O = NC email in othername Test Certificate" | \ |
249 |
+ ./mkcert.sh geneealt bad-othername-key bad-othername-cert \ |
250 |
+ nccaothername-key nccaothername-cert \ |
251 |
+ "otherName.1 = SRVName;UTF8STRING:foo@example.org" |
252 |
+ |
253 |
# RSA-PSS signatures |
254 |
# SHA1 |
255 |
./mkcert.sh genee PSS-SHA1 ee-key ee-pss-sha1-cert ca-key ca-cert \ |
256 |
diff --git a/test/recipes/25-test_verify.t b/test/recipes/25-test_verify.t |
257 |
index 4613489f57..e6a2bca731 100644 |
258 |
--- a/test/recipes/25-test_verify.t |
259 |
+++ b/test/recipes/25-test_verify.t |
260 |
@@ -29,7 +29,7 @@ sub verify { |
261 |
run(app([@args])); |
262 |
} |
263 |
|
264 |
-plan tests => 162; |
265 |
+plan tests => 163; |
266 |
|
267 |
# Canonical success |
268 |
ok(verify("ee-cert", "sslserver", ["root-cert"], ["ca-cert"]), |
269 |
@@ -402,6 +402,9 @@ ok(!verify("badalt9-cert", "", ["root-cert"], ["ncca1-cert", "ncca3-cert"], ), |
270 |
ok(!verify("badalt10-cert", "", ["root-cert"], ["ncca1-cert", "ncca3-cert"], ), |
271 |
"Name constraints nested DNS name excluded"); |
272 |
|
273 |
+ok(!verify("bad-othername-cert", "", ["root-cert"], ["nccaothername-cert"], ), |
274 |
+ "CVE-2022-4203 type confusion test"); |
275 |
+ |
276 |
#Check that we get the expected failure return code |
277 |
with({ exit_checker => sub { return shift == 2; } }, |
278 |
sub { |
279 |
-- |
280 |
2.39.1 |
281 |
|