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 | |
| 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')
| -rw-r--r-- | src/lib/libcrypto/x509/x509_constraints.c | 40 | ||||
| -rw-r--r-- | src/regress/lib/libcrypto/x509/constraints.c | 12 |
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 | */ |
| 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 | /* |
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[] = { | |||
| 49 | unsigned char *valid_sandns_names[] = { | 49 | unsigned 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)) { |
