summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbeck <>2021-04-27 03:35:29 +0000
committerbeck <>2021-04-27 03:35:29 +0000
commit05d12eaff3684c531b3d36e69fa663830294b6bd (patch)
tree4a1f8797d9eb5049de6166919597895e05f86d6c
parentebe128ca73ce7d178a186b93684c8bf8577f3b80 (diff)
downloadopenbsd-05d12eaff3684c531b3d36e69fa663830294b6bd.tar.gz
openbsd-05d12eaff3684c531b3d36e69fa663830294b6bd.tar.bz2
openbsd-05d12eaff3684c531b3d36e69fa663830294b6bd.zip
Relax SAN DNSname validation and constraints to permit non leading *
wildcards. While we may choose not to support them the standards appear to permit them optionally so we can't declare a certificate containing them invalid. Noticed by jeremy@, and Steffan Ulrich and others. Modify the regression tests to test these cases and not check the SAN DNSnames as "hostnames" anymore (which don't support wildcards). ok jsing@, tb@
-rw-r--r--src/lib/libcrypto/x509/x509_constraints.c40
-rw-r--r--src/regress/lib/libcrypto/x509/constraints.c12
2 files changed, 25 insertions, 27 deletions
diff --git a/src/lib/libcrypto/x509/x509_constraints.c b/src/lib/libcrypto/x509/x509_constraints.c
index 5fbcef304f..fade58c620 100644
--- a/src/lib/libcrypto/x509/x509_constraints.c
+++ b/src/lib/libcrypto/x509/x509_constraints.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: x509_constraints.c,v 1.15 2021/03/12 15:57:30 tb Exp $ */ 1/* $OpenBSD: x509_constraints.c,v 1.16 2021/04/27 03:35:29 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org> 3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org>
4 * 4 *
@@ -169,13 +169,15 @@ x509_constraints_names_dup(struct x509_constraints_names *names)
169/* 169/*
170 * Validate that the name contains only a hostname consisting of RFC 170 * Validate that the name contains only a hostname consisting of RFC
171 * 5890 compliant A-labels (see RFC 6066 section 3). This is more 171 * 5890 compliant A-labels (see RFC 6066 section 3). This is more
172 * permissive to allow for a leading '*' for a SAN DNSname wildcard, 172 * permissive to allow for a leading '.' for a subdomain based
173 * or a leading '.' for a subdomain based constraint, as well as 173 * constraint, as well as allowing for '_' which is commonly accepted
174 * allowing for '_' which is commonly accepted by nonconformant 174 * by nonconformant DNS implementaitons.
175 * DNS implementaitons. 175 *
176 * if "wildcards" is set it allows '*' to occur in the string at the end of a
177 * component.
176 */ 178 */
177static int 179static int
178x509_constraints_valid_domain_internal(uint8_t *name, size_t len) 180x509_constraints_valid_domain_internal(uint8_t *name, size_t len, int wildcards)
179{ 181{
180 uint8_t prev, c = 0; 182 uint8_t prev, c = 0;
181 int component = 0; 183 int component = 0;
@@ -198,8 +200,8 @@ x509_constraints_valid_domain_internal(uint8_t *name, size_t len)
198 if (!isalnum(c) && c != '-' && c != '.' && c != '_' && c != '*') 200 if (!isalnum(c) && c != '-' && c != '.' && c != '_' && c != '*')
199 return 0; 201 return 0;
200 202
201 /* '*' can only be the first thing. */ 203 /* if it is a '*', fail if not wildcards */
202 if (c == '*' && !first) 204 if (!wildcards && c == '*')
203 return 0; 205 return 0;
204 206
205 /* '-' must not start a component or be at the end. */ 207 /* '-' must not start a component or be at the end. */
@@ -221,6 +223,13 @@ x509_constraints_valid_domain_internal(uint8_t *name, size_t len)
221 component = 0; 223 component = 0;
222 continue; 224 continue;
223 } 225 }
226 /*
227 * Wildcards can only occur at the end of a component.
228 * c*.com is valid, c*c.com is not.
229 */
230 if (prev == '*')
231 return 0;
232
224 /* Components must be 63 chars or less. */ 233 /* Components must be 63 chars or less. */
225 if (++component > 63) 234 if (++component > 63)
226 return 0; 235 return 0;
@@ -233,15 +242,13 @@ x509_constraints_valid_domain(uint8_t *name, size_t len)
233{ 242{
234 if (len == 0) 243 if (len == 0)
235 return 0; 244 return 0;
236 if (name[0] == '*') /* wildcard not allowed in a domain name */
237 return 0;
238 /* 245 /*
239 * A domain may not be less than two characters, so you can't 246 * A domain may not be less than two characters, so you can't
240 * have a require subdomain name with less than that. 247 * have a require subdomain name with less than that.
241 */ 248 */
242 if (len < 3 && name[0] == '.') 249 if (len < 3 && name[0] == '.')
243 return 0; 250 return 0;
244 return x509_constraints_valid_domain_internal(name, len); 251 return x509_constraints_valid_domain_internal(name, len, 0);
245} 252}
246 253
247int 254int
@@ -252,15 +259,13 @@ x509_constraints_valid_host(uint8_t *name, size_t len)
252 259
253 if (len == 0) 260 if (len == 0)
254 return 0; 261 return 0;
255 if (name[0] == '*') /* wildcard not allowed in a host name */
256 return 0;
257 if (name[0] == '.') /* leading . not allowed in a host name*/ 262 if (name[0] == '.') /* leading . not allowed in a host name*/
258 return 0; 263 return 0;
259 if (inet_pton(AF_INET, name, &sin4) == 1) 264 if (inet_pton(AF_INET, name, &sin4) == 1)
260 return 0; 265 return 0;
261 if (inet_pton(AF_INET6, name, &sin6) == 1) 266 if (inet_pton(AF_INET6, name, &sin6) == 1)
262 return 0; 267 return 0;
263 return x509_constraints_valid_domain_internal(name, len); 268 return x509_constraints_valid_domain_internal(name, len, 0);
264} 269}
265 270
266int 271int
@@ -283,7 +288,7 @@ x509_constraints_valid_sandns(uint8_t *name, size_t len)
283 if (len >= 4 && name[0] == '*' && name[1] != '.') 288 if (len >= 4 && name[0] == '*' && name[1] != '.')
284 return 0; 289 return 0;
285 290
286 return x509_constraints_valid_domain_internal(name, len); 291 return x509_constraints_valid_domain_internal(name, len, 1);
287} 292}
288 293
289static inline int 294static inline int
@@ -431,16 +436,13 @@ x509_constraints_valid_domain_constraint(uint8_t *constraint, size_t len)
431 if (len == 0) 436 if (len == 0)
432 return 1; /* empty constraints match */ 437 return 1; /* empty constraints match */
433 438
434 if (constraint[0] == '*') /* wildcard not allowed in a constraint */
435 return 0;
436
437 /* 439 /*
438 * A domain may not be less than two characters, so you 440 * A domain may not be less than two characters, so you
439 * can't match a single domain of less than that 441 * can't match a single domain of less than that
440 */ 442 */
441 if (len < 3 && constraint[0] == '.') 443 if (len < 3 && constraint[0] == '.')
442 return 0; 444 return 0;
443 return x509_constraints_valid_domain_internal(constraint, len); 445 return x509_constraints_valid_domain_internal(constraint, len, 0);
444} 446}
445 447
446/* 448/*
diff --git a/src/regress/lib/libcrypto/x509/constraints.c b/src/regress/lib/libcrypto/x509/constraints.c
index 7eef55d591..c4dedeb1fa 100644
--- a/src/regress/lib/libcrypto/x509/constraints.c
+++ b/src/regress/lib/libcrypto/x509/constraints.c
@@ -49,6 +49,8 @@ unsigned char *valid_hostnames[] = {
49unsigned char *valid_sandns_names[] = { 49unsigned char *valid_sandns_names[] = {
50 "*.ca", 50 "*.ca",
51 "*.op3nbsd.org", 51 "*.op3nbsd.org",
52 "c*.openbsd.org",
53 "foo.*.d*.c*.openbsd.org",
52 NULL, 54 NULL,
53}; 55};
54 56
@@ -96,6 +98,7 @@ unsigned char *invalid_hostnames[] = {
96 "openbsd\n.org", 98 "openbsd\n.org",
97 "open\178bsd.org", 99 "open\178bsd.org",
98 "open\255bsd.org", 100 "open\255bsd.org",
101 "*.openbsd.org",
99 NULL, 102 NULL,
100}; 103};
101 104
@@ -110,10 +113,10 @@ unsigned char *invalid_sandns_names[] = {
110 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa." 113 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
111 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a", 114 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a",
112 "*.-p3nbsd.org", 115 "*.-p3nbsd.org",
113 "a*.openbsd.org",
114 "*.*..openbsd.org", 116 "*.*..openbsd.org",
115 "*..openbsd.org", 117 "*..openbsd.org",
116 ".openbsd.org", 118 ".openbsd.org",
119 "c*c.openbsd.org",
117 NULL, 120 NULL,
118}; 121};
119 122
@@ -254,13 +257,6 @@ test_invalid_hostnames(void)
254 failure = 1; 257 failure = 1;
255 goto done; 258 goto done;
256 } 259 }
257 if (x509_constraints_valid_sandns(invalid_hostnames[i],
258 strlen(invalid_hostnames[i]))) {
259 FAIL("Invalid sandns '%s' accepted\n",
260 invalid_hostnames[i]);
261 failure = 1;
262 goto done;
263 }
264 } 260 }
265 if (x509_constraints_valid_host(nulhost, 261 if (x509_constraints_valid_host(nulhost,
266 strlen(nulhost) + 1)) { 262 strlen(nulhost) + 1)) {