diff options
author | beck <> | 2021-04-27 03:35:29 +0000 |
---|---|---|
committer | beck <> | 2021-04-27 03:35:29 +0000 |
commit | 05d12eaff3684c531b3d36e69fa663830294b6bd (patch) | |
tree | 4a1f8797d9eb5049de6166919597895e05f86d6c /src/lib | |
parent | ebe128ca73ce7d178a186b93684c8bf8577f3b80 (diff) | |
download | openbsd-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@
Diffstat (limited to 'src/lib')
-rw-r--r-- | src/lib/libcrypto/x509/x509_constraints.c | 40 |
1 files changed, 21 insertions, 19 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 | */ |
177 | static int | 179 | static int |
178 | x509_constraints_valid_domain_internal(uint8_t *name, size_t len) | 180 | x509_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 | ||
247 | int | 254 | int |
@@ -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 | ||
266 | int | 271 | int |
@@ -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 | ||
289 | static inline int | 294 | static 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 | /* |