summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbeck <>2022-11-11 12:02:34 +0000
committerbeck <>2022-11-11 12:02:34 +0000
commit8162acf7813e6b117517a092921aebf84fb21de9 (patch)
tree0a9a1c7b34e523947e5dbb8897374c8c5c2fec2d
parent1a9769d129da2a93d07c48740bab17bcf753bbc6 (diff)
downloadopenbsd-8162acf7813e6b117517a092921aebf84fb21de9.tar.gz
openbsd-8162acf7813e6b117517a092921aebf84fb21de9.tar.bz2
openbsd-8162acf7813e6b117517a092921aebf84fb21de9.zip
Start CBS-ifying the name constraints code.
ok jsing@ tb@
-rw-r--r--src/lib/libcrypto/x509/x509_alt.c8
-rw-r--r--src/lib/libcrypto/x509/x509_constraints.c230
-rw-r--r--src/lib/libcrypto/x509/x509_internal.h12
-rw-r--r--src/regress/lib/libcrypto/x509/Makefile3
-rw-r--r--src/regress/lib/libcrypto/x509/constraints.c83
5 files changed, 198 insertions, 138 deletions
diff --git a/src/lib/libcrypto/x509/x509_alt.c b/src/lib/libcrypto/x509/x509_alt.c
index 8656df82b3..cf8cbf0ce2 100644
--- a/src/lib/libcrypto/x509/x509_alt.c
+++ b/src/lib/libcrypto/x509/x509_alt.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: x509_alt.c,v 1.12 2022/03/26 16:34:21 tb Exp $ */ 1/* $OpenBSD: x509_alt.c,v 1.13 2022/11/11 12:02:34 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. 3 * project.
4 */ 4 */
@@ -619,6 +619,7 @@ v2i_GENERAL_NAME_ex(GENERAL_NAME *out, const X509V3_EXT_METHOD *method,
619 GENERAL_NAME *ret; 619 GENERAL_NAME *ret;
620 size_t len = 0; 620 size_t len = 0;
621 int type; 621 int type;
622 CBS cbs;
622 623
623 name = cnf->name; 624 name = cnf->name;
624 value = cnf->value; 625 value = cnf->value;
@@ -669,9 +670,10 @@ v2i_GENERAL_NAME_ex(GENERAL_NAME *out, const X509V3_EXT_METHOD *method,
669 } 670 }
670 671
671 type = x509_constraints_general_to_bytes(ret, &bytes, &len); 672 type = x509_constraints_general_to_bytes(ret, &bytes, &len);
673 CBS_init(&cbs, bytes, len);
672 switch (type) { 674 switch (type) {
673 case GEN_DNS: 675 case GEN_DNS:
674 if (!x509_constraints_valid_sandns(bytes, len)) { 676 if (!x509_constraints_valid_sandns(&cbs)) {
675 X509V3error(X509V3_R_BAD_OBJECT); 677 X509V3error(X509V3_R_BAD_OBJECT);
676 ERR_asprintf_error_data("name=%s value='%.*s'", name, 678 ERR_asprintf_error_data("name=%s value='%.*s'", name,
677 (int)len, bytes); 679 (int)len, bytes);
@@ -687,7 +689,7 @@ v2i_GENERAL_NAME_ex(GENERAL_NAME *out, const X509V3_EXT_METHOD *method,
687 } 689 }
688 break; 690 break;
689 case GEN_EMAIL: 691 case GEN_EMAIL:
690 if (!x509_constraints_parse_mailbox(bytes, len, NULL)) { 692 if (!x509_constraints_parse_mailbox(&cbs, NULL)) {
691 X509V3error(X509V3_R_BAD_OBJECT); 693 X509V3error(X509V3_R_BAD_OBJECT);
692 ERR_asprintf_error_data("name=%s value='%.*s'", name, 694 ERR_asprintf_error_data("name=%s value='%.*s'", name,
693 (int)len, bytes); 695 (int)len, bytes);
diff --git a/src/lib/libcrypto/x509/x509_constraints.c b/src/lib/libcrypto/x509/x509_constraints.c
index 8cd8413dfa..e0560c1578 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.28 2022/06/27 15:03:11 beck Exp $ */ 1/* $OpenBSD: x509_constraints.c,v 1.29 2022/11/11 12:02:34 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org> 3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org>
4 * 4 *
@@ -29,11 +29,33 @@
29#include <openssl/x509.h> 29#include <openssl/x509.h>
30#include <openssl/x509v3.h> 30#include <openssl/x509v3.h>
31 31
32#include "bytestring.h"
32#include "x509_internal.h" 33#include "x509_internal.h"
33 34
34/* RFC 2821 section 4.5.3.1 */ 35/* RFC 2821 section 4.5.3.1 */
35#define LOCAL_PART_MAX_LEN 64 36#define LOCAL_PART_MAX_LEN (size_t)64
36#define DOMAIN_PART_MAX_LEN 255 37#define DOMAIN_PART_MAX_LEN (size_t)255
38#define MAX_IP_ADDRESS_LENGTH (size_t)46
39
40static int
41cbs_is_ip_address(CBS *cbs)
42{
43 struct sockaddr_in6 sin6;
44 struct sockaddr_in sin4;
45 char *name = NULL;
46 int ret = 0;
47
48 if (CBS_len(cbs) > MAX_IP_ADDRESS_LENGTH)
49 return 0;
50 if (!CBS_strdup(cbs, &name))
51 return 0;
52 if (inet_pton(AF_INET, name, &sin4) == 1 ||
53 inet_pton(AF_INET6, name, &sin6) == 1)
54 ret = 1;
55
56 free(name);
57 return ret;
58}
37 59
38struct x509_constraints_name * 60struct x509_constraints_name *
39x509_constraints_name_new(void) 61x509_constraints_name_new(void)
@@ -165,7 +187,6 @@ x509_constraints_names_dup(struct x509_constraints_names *names)
165 return NULL; 187 return NULL;
166} 188}
167 189
168
169/* 190/*
170 * Validate that the name contains only a hostname consisting of RFC 191 * Validate that the name contains only a hostname consisting of RFC
171 * 5890 compliant A-labels (see RFC 6066 section 3). This is more 192 * 5890 compliant A-labels (see RFC 6066 section 3). This is more
@@ -177,19 +198,23 @@ x509_constraints_names_dup(struct x509_constraints_names *names)
177 * component. 198 * component.
178 */ 199 */
179static int 200static int
180x509_constraints_valid_domain_internal(uint8_t *name, size_t len, int wildcards) 201x509_constraints_valid_domain_internal(CBS *cbs, int wildcards)
181{ 202{
203 int first, component = 0;
182 uint8_t prev, c = 0; 204 uint8_t prev, c = 0;
183 int component = 0; 205 size_t i, len;
184 int first; 206 CBS copy;
185 size_t i; 207
208 CBS_dup(cbs, &copy);
209
210 len = CBS_len(cbs);
186 211
187 if (len > DOMAIN_PART_MAX_LEN) 212 if (len > DOMAIN_PART_MAX_LEN)
188 return 0; 213 return 0;
189
190 for (i = 0; i < len; i++) { 214 for (i = 0; i < len; i++) {
191 prev = c; 215 prev = c;
192 c = name[i]; 216 if (!CBS_get_u8(&copy, &c))
217 return 0;
193 218
194 first = (i == 0); 219 first = (i == 0);
195 220
@@ -234,61 +259,42 @@ x509_constraints_valid_domain_internal(uint8_t *name, size_t len, int wildcards)
234 if (++component > 63) 259 if (++component > 63)
235 return 0; 260 return 0;
236 } 261 }
262
237 return 1; 263 return 1;
238} 264}
239 265
240int 266int
241x509_constraints_valid_domain(uint8_t *name, size_t len) 267x509_constraints_valid_host(CBS *cbs)
242{ 268{
243 if (len == 0) 269 uint8_t first;
244 return 0;
245 /*
246 * A domain may not be less than two characters, so you can't
247 * have a require subdomain name with less than that.
248 */
249 if (len < 3 && name[0] == '.')
250 return 0;
251 return x509_constraints_valid_domain_internal(name, len, 0);
252}
253 270
254int 271 if (!CBS_peek_u8(cbs, &first))
255x509_constraints_valid_host(uint8_t *name, size_t len)
256{
257 struct sockaddr_in sin4;
258 struct sockaddr_in6 sin6;
259
260 if (len == 0)
261 return 0;
262 if (name[0] == '.') /* leading . not allowed in a host name*/
263 return 0; 272 return 0;
264 if (inet_pton(AF_INET, name, &sin4) == 1) 273 if (first == '.')
274 return 0; /* leading . not allowed in a host name */
275 if (cbs_is_ip_address(cbs))
265 return 0; 276 return 0;
266 if (inet_pton(AF_INET6, name, &sin6) == 1) 277
267 return 0; 278 return x509_constraints_valid_domain_internal(cbs, 0);
268 return x509_constraints_valid_domain_internal(name, len, 0);
269} 279}
270 280
271int 281int
272x509_constraints_valid_sandns(uint8_t *name, size_t len) 282x509_constraints_valid_sandns(CBS *cbs)
273{ 283{
274 if (len == 0) 284 uint8_t first;
275 return 0;
276 285
277 if (name[0] == '.') /* leading . not allowed in a SAN DNS name */ 286 if (!CBS_peek_u8(cbs, &first))
278 return 0; 287 return 0;
288 if (first == '.')
289 return 0; /* leading . not allowed in a SAN DNS name */
279 /* 290 /*
280 * A domain may not be less than two characters, so you 291 * A domain may not be less than two characters, so you
281 * can't wildcard a single domain of less than that 292 * can't wildcard a single domain of less than that
282 */ 293 */
283 if (len < 4 && name[0] == '*') 294 if (CBS_len(cbs) < 4 && first == '*')
284 return 0;
285 /*
286 * A wildcard may only be followed by a '.'
287 */
288 if (len >= 4 && name[0] == '*' && name[1] != '.')
289 return 0; 295 return 0;
290 296
291 return x509_constraints_valid_domain_internal(name, len, 1); 297 return x509_constraints_valid_domain_internal(cbs, 1);
292} 298}
293 299
294static inline int 300static inline int
@@ -297,7 +303,7 @@ local_part_ok(char c)
297 return (('0' <= c && c <= '9') || ('a' <= c && c <= 'z') || 303 return (('0' <= c && c <= '9') || ('a' <= c && c <= 'z') ||
298 ('A' <= c && c <= 'Z') || c == '!' || c == '#' || c == '$' || 304 ('A' <= c && c <= 'Z') || c == '!' || c == '#' || c == '$' ||
299 c == '%' || c == '&' || c == '\'' || c == '*' || c == '+' || 305 c == '%' || c == '&' || c == '\'' || c == '*' || c == '+' ||
300 c == '-' || c == '/' || c == '=' || c == '?' || c == '^' || 306 c == '-' || c == '/' || c == '=' || c == '?' || c == '^' ||
301 c == '_' || c == '`' || c == '{' || c == '|' || c == '}' || 307 c == '_' || c == '`' || c == '{' || c == '|' || c == '}' ||
302 c == '~' || c == '.'); 308 c == '~' || c == '.');
303} 309}
@@ -309,25 +315,35 @@ local_part_ok(char c)
309 * local and domain parts of the mailbox to "name->local" and name->name" 315 * local and domain parts of the mailbox to "name->local" and name->name"
310 */ 316 */
311int 317int
312x509_constraints_parse_mailbox(uint8_t *candidate, size_t len, 318x509_constraints_parse_mailbox(CBS *candidate,
313 struct x509_constraints_name *name) 319 struct x509_constraints_name *name)
314{ 320{
315 char working[DOMAIN_PART_MAX_LEN + 1] = { 0 }; 321 char working[DOMAIN_PART_MAX_LEN + 1] = { 0 };
316 char *candidate_local = NULL; 322 char *candidate_local = NULL;
317 char *candidate_domain = NULL; 323 char *candidate_domain = NULL;
318 size_t i, wi = 0; 324 CBS domain_cbs;
325 size_t i, len, wi = 0;
319 int accept = 0; 326 int accept = 0;
320 int quoted = 0; 327 int quoted = 0;
328 CBS copy;
321 329
330 /* XXX This should not be necessary - revisit and remove */
322 if (candidate == NULL) 331 if (candidate == NULL)
323 return 0; 332 return 0;
324 333
334 CBS_dup(candidate, &copy);
335
336 if ((len = CBS_len(&copy)) == 0)
337 return 0;
338
325 /* It can't be bigger than the local part, domain part and the '@' */ 339 /* It can't be bigger than the local part, domain part and the '@' */
326 if (len > LOCAL_PART_MAX_LEN + DOMAIN_PART_MAX_LEN + 1) 340 if (len > LOCAL_PART_MAX_LEN + DOMAIN_PART_MAX_LEN + 1)
327 return 0; 341 return 0;
328 342
329 for (i = 0; i < len; i++) { 343 for (i = 0; i < len; i++) {
330 char c = candidate[i]; 344 char c;
345 if (!CBS_get_u8(&copy, &c))
346 goto bad;
331 /* non ascii, cr, lf, or nul is never allowed */ 347 /* non ascii, cr, lf, or nul is never allowed */
332 if (!isascii(c) || c == '\r' || c == '\n' || c == '\0') 348 if (!isascii(c) || c == '\r' || c == '\n' || c == '\0')
333 goto bad; 349 goto bad;
@@ -372,8 +388,11 @@ x509_constraints_parse_mailbox(uint8_t *candidate, size_t len,
372 continue; 388 continue;
373 } 389 }
374 if (c == '"' && i != 0) { 390 if (c == '"' && i != 0) {
391 uint8_t next;
375 /* end the quoted part. @ must be next */ 392 /* end the quoted part. @ must be next */
376 if (i + 1 == len || candidate[i + 1] != '@') 393 if (!CBS_peek_u8(&copy, &next))
394 goto bad;
395 if (next != '@')
377 goto bad; 396 goto bad;
378 quoted = 0; 397 quoted = 0;
379 } 398 }
@@ -401,14 +420,15 @@ x509_constraints_parse_mailbox(uint8_t *candidate, size_t len,
401 continue; 420 continue;
402 } 421 }
403 if (c == '\\') { 422 if (c == '\\') {
423 uint8_t next;
404 /* 424 /*
405 * RFC 3936 hints these can happen outside of 425 * RFC 2821 hints these can happen outside of
406 * quotend string. don't include the \ but 426 * quoted string. Don't include the \ but
407 * next character must be ok. 427 * next character must be ok.
408 */ 428 */
409 if (i + 1 == len) 429 if (!CBS_peek_u8(&copy, &next))
410 goto bad; 430 goto bad;
411 if (!local_part_ok(candidate[i + 1])) 431 if (!local_part_ok(next))
412 goto bad; 432 goto bad;
413 accept = 1; 433 accept = 1;
414 } 434 }
@@ -420,8 +440,8 @@ x509_constraints_parse_mailbox(uint8_t *candidate, size_t len,
420 } 440 }
421 if (candidate_local == NULL || candidate_domain == NULL) 441 if (candidate_local == NULL || candidate_domain == NULL)
422 goto bad; 442 goto bad;
423 if (!x509_constraints_valid_host(candidate_domain, 443 CBS_init(&domain_cbs, candidate_domain, strlen(candidate_domain));
424 strlen(candidate_domain))) 444 if (!x509_constraints_valid_host(&domain_cbs))
425 goto bad; 445 goto bad;
426 446
427 if (name != NULL) { 447 if (name != NULL) {
@@ -440,18 +460,24 @@ x509_constraints_parse_mailbox(uint8_t *candidate, size_t len,
440} 460}
441 461
442int 462int
443x509_constraints_valid_domain_constraint(uint8_t *constraint, size_t len) 463x509_constraints_valid_domain_constraint(CBS *cbs)
444{ 464{
445 if (len == 0) 465 uint8_t first;
466
467 if (CBS_len(cbs) == 0)
446 return 1; /* empty constraints match */ 468 return 1; /* empty constraints match */
447 469
448 /* 470 /*
449 * A domain may not be less than two characters, so you 471 * A domain may not be less than two characters, so you
450 * can't match a single domain of less than that 472 * can't match a single domain of less than that
451 */ 473 */
452 if (len < 3 && constraint[0] == '.') 474 if (CBS_len(cbs) < 3) {
453 return 0; 475 if (!CBS_peek_u8(cbs, &first))
454 return x509_constraints_valid_domain_internal(constraint, len, 0); 476 return 0;
477 if (first == '.')
478 return 0;
479 }
480 return x509_constraints_valid_domain_internal(cbs, 0);
455} 481}
456 482
457/* 483/*
@@ -480,6 +506,7 @@ x509_constraints_uri_host(uint8_t *uri, size_t len, char **hostpart)
480 size_t i, hostlen = 0; 506 size_t i, hostlen = 0;
481 uint8_t *authority = NULL; 507 uint8_t *authority = NULL;
482 char *host = NULL; 508 char *host = NULL;
509 CBS host_cbs;
483 510
484 /* 511 /*
485 * Find first '//'. there must be at least a '//' and 512 * Find first '//'. there must be at least a '//' and
@@ -529,10 +556,11 @@ x509_constraints_uri_host(uint8_t *uri, size_t len, char **hostpart)
529 return 0; 556 return 0;
530 if (host == NULL) 557 if (host == NULL)
531 host = authority; 558 host = authority;
532 if (!x509_constraints_valid_host(host, hostlen)) 559 CBS_init(&host_cbs, host, hostlen);
560 if (!x509_constraints_valid_host(&host_cbs))
561 return 0;
562 if (hostpart != NULL && !CBS_strdup(&host_cbs, hostpart))
533 return 0; 563 return 0;
534 if (hostpart != NULL)
535 *hostpart = strndup(host, hostlen);
536 return 1; 564 return 1;
537} 565}
538 566
@@ -593,12 +621,15 @@ x509_constraints_domain(char *domain, size_t dlen, char *constraint, size_t len)
593} 621}
594 622
595int 623int
596x509_constraints_uri(uint8_t *uri, size_t ulen, uint8_t *constraint, size_t len, 624x509_constraints_uri(uint8_t *uri, size_t ulen, uint8_t *constraint,
625 size_t len,
597 int *error) 626 int *error)
598{ 627{
599 int ret = 0; 628 int ret = 0;
600 char *hostpart = NULL; 629 char *hostpart = NULL;
630 CBS cbs;
601 631
632 CBS_init(&cbs, constraint, len);
602 if (!x509_constraints_uri_host(uri, ulen, &hostpart)) { 633 if (!x509_constraints_uri_host(uri, ulen, &hostpart)) {
603 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; 634 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
604 goto err; 635 goto err;
@@ -607,7 +638,7 @@ x509_constraints_uri(uint8_t *uri, size_t ulen, uint8_t *constraint, size_t len,
607 *error = X509_V_ERR_OUT_OF_MEM; 638 *error = X509_V_ERR_OUT_OF_MEM;
608 goto err; 639 goto err;
609 } 640 }
610 if (!x509_constraints_valid_domain_constraint(constraint, len)) { 641 if (!x509_constraints_valid_domain_constraint(&cbs)) {
611 *error = X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX; 642 *error = X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX;
612 goto err; 643 goto err;
613 } 644 }
@@ -714,7 +745,6 @@ x509_constraints_general_to_bytes(GENERAL_NAME *name, uint8_t **bytes,
714 return 0; 745 return 0;
715} 746}
716 747
717
718/* 748/*
719 * Extract the relevant names for constraint checking from "cert", 749 * Extract the relevant names for constraint checking from "cert",
720 * validate them, and add them to the list of cert names for "chain". 750 * validate them, and add them to the list of cert names for "chain".
@@ -734,6 +764,7 @@ x509_constraints_extract_names(struct x509_constraints_names *names,
734 while ((name = sk_GENERAL_NAME_value(cert->altname, i++)) != NULL) { 764 while ((name = sk_GENERAL_NAME_value(cert->altname, i++)) != NULL) {
735 uint8_t *bytes = NULL; 765 uint8_t *bytes = NULL;
736 size_t len = 0; 766 size_t len = 0;
767 CBS cbs;
737 768
738 if ((vname = x509_constraints_name_new()) == NULL) { 769 if ((vname = x509_constraints_name_new()) == NULL) {
739 *error = X509_V_ERR_OUT_OF_MEM; 770 *error = X509_V_ERR_OUT_OF_MEM;
@@ -742,30 +773,31 @@ x509_constraints_extract_names(struct x509_constraints_names *names,
742 773
743 name_type = x509_constraints_general_to_bytes(name, &bytes, 774 name_type = x509_constraints_general_to_bytes(name, &bytes,
744 &len); 775 &len);
745 switch(name_type) { 776 CBS_init(&cbs, bytes, len);
777 switch (name_type) {
746 case GEN_DNS: 778 case GEN_DNS:
747 if (!x509_constraints_valid_sandns(bytes, len)) { 779 if (!x509_constraints_valid_sandns(&cbs)) {
748 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; 780 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
749 goto err; 781 goto err;
750 } 782 }
751 if ((vname->name = strndup(bytes, len)) == NULL) { 783 if (!CBS_strdup(&cbs, &vname->name)) {
752 *error = X509_V_ERR_OUT_OF_MEM; 784 *error = X509_V_ERR_OUT_OF_MEM;
753 goto err; 785 goto err;
754 } 786 }
755 vname->type = GEN_DNS; 787 vname->type = GEN_DNS;
756 include_cn = 0; /* don't use cn from subject */ 788 include_cn = 0; /* Don't use cn from subject */
757 break; 789 break;
758 case GEN_EMAIL: 790 case GEN_EMAIL:
759 if (!x509_constraints_parse_mailbox(bytes, len, 791 if (!x509_constraints_parse_mailbox(&cbs, vname)) {
760 vname)) {
761 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; 792 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
762 goto err; 793 goto err;
763 } 794 }
764 vname->type = GEN_EMAIL; 795 vname->type = GEN_EMAIL;
765 include_email = 0; /* don't use email from subject */ 796 include_email = 0; /* Don't use email from subject */
766 break; 797 break;
767 case GEN_URI: 798 case GEN_URI:
768 if (!x509_constraints_uri_host(bytes, len, &vname->name)) { 799 if (!x509_constraints_uri_host(bytes, len,
800 &vname->name)) {
769 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; 801 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
770 goto err; 802 goto err;
771 } 803 }
@@ -850,19 +882,21 @@ x509_constraints_extract_names(struct x509_constraints_names *names,
850 */ 882 */
851 while (include_email && 883 while (include_email &&
852 (i = X509_NAME_get_index_by_NID(subject_name, 884 (i = X509_NAME_get_index_by_NID(subject_name,
853 NID_pkcs9_emailAddress, i)) >= 0) { 885 NID_pkcs9_emailAddress, i)) >= 0) {
854 ASN1_STRING *aname; 886 ASN1_STRING *aname;
855 if ((email = X509_NAME_get_entry(subject_name, i)) == NULL || 887 CBS cbs;
888 if ((email = X509_NAME_get_entry(subject_name, i)) ==
889 NULL ||
856 (aname = X509_NAME_ENTRY_get_data(email)) == NULL) { 890 (aname = X509_NAME_ENTRY_get_data(email)) == NULL) {
857 *error = X509_V_ERR_OUT_OF_MEM; 891 *error = X509_V_ERR_OUT_OF_MEM;
858 goto err; 892 goto err;
859 } 893 }
894 CBS_init(&cbs, aname->data, aname->length);
860 if ((vname = x509_constraints_name_new()) == NULL) { 895 if ((vname = x509_constraints_name_new()) == NULL) {
861 *error = X509_V_ERR_OUT_OF_MEM; 896 *error = X509_V_ERR_OUT_OF_MEM;
862 goto err; 897 goto err;
863 } 898 }
864 if (!x509_constraints_parse_mailbox(aname->data, 899 if (!x509_constraints_parse_mailbox(&cbs, vname)) {
865 aname->length, vname)) {
866 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX; 900 *error = X509_V_ERR_UNSUPPORTED_NAME_SYNTAX;
867 goto err; 901 goto err;
868 } 902 }
@@ -879,22 +913,23 @@ x509_constraints_extract_names(struct x509_constraints_names *names,
879 */ 913 */
880 while (include_cn && 914 while (include_cn &&
881 (i = X509_NAME_get_index_by_NID(subject_name, 915 (i = X509_NAME_get_index_by_NID(subject_name,
882 NID_commonName, i)) >= 0) { 916 NID_commonName, i)) >= 0) {
917 CBS cbs;
883 ASN1_STRING *aname; 918 ASN1_STRING *aname;
884 if ((cn = X509_NAME_get_entry(subject_name, i)) == NULL || 919 if ((cn = X509_NAME_get_entry(subject_name, i)) ==
920 NULL ||
885 (aname = X509_NAME_ENTRY_get_data(cn)) == NULL) { 921 (aname = X509_NAME_ENTRY_get_data(cn)) == NULL) {
886 *error = X509_V_ERR_OUT_OF_MEM; 922 *error = X509_V_ERR_OUT_OF_MEM;
887 goto err; 923 goto err;
888 } 924 }
889 if (!x509_constraints_valid_host(aname->data, 925 CBS_init(&cbs, aname->data, aname->length);
890 aname->length)) 926 if (!x509_constraints_valid_host(&cbs))
891 continue; /* ignore it if not a hostname */ 927 continue; /* ignore it if not a hostname */
892 if ((vname = x509_constraints_name_new()) == NULL) { 928 if ((vname = x509_constraints_name_new()) == NULL) {
893 *error = X509_V_ERR_OUT_OF_MEM; 929 *error = X509_V_ERR_OUT_OF_MEM;
894 goto err; 930 goto err;
895 } 931 }
896 if ((vname->name = strndup(aname->data, 932 if (!CBS_strdup(&cbs, &vname->name)) {
897 aname->length)) == NULL) {
898 *error = X509_V_ERR_OUT_OF_MEM; 933 *error = X509_V_ERR_OUT_OF_MEM;
899 goto err; 934 goto err;
900 } 935 }
@@ -923,11 +958,12 @@ int
923x509_constraints_validate(GENERAL_NAME *constraint, 958x509_constraints_validate(GENERAL_NAME *constraint,
924 struct x509_constraints_name **out_name, int *out_error) 959 struct x509_constraints_name **out_name, int *out_error)
925{ 960{
926 uint8_t *bytes = NULL; 961 uint8_t next, *bytes = NULL;
927 size_t len = 0; 962 size_t len = 0;
928 struct x509_constraints_name *name; 963 struct x509_constraints_name *name;
929 int error = X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX; 964 int error = X509_V_ERR_UNSUPPORTED_CONSTRAINT_SYNTAX;
930 int name_type; 965 int name_type;
966 CBS cbs;
931 967
932 if (out_name == NULL || *out_name != NULL) 968 if (out_name == NULL || *out_name != NULL)
933 return 0; 969 return 0;
@@ -941,6 +977,7 @@ x509_constraints_validate(GENERAL_NAME *constraint,
941 } 977 }
942 978
943 name_type = x509_constraints_general_to_bytes(constraint, &bytes, &len); 979 name_type = x509_constraints_general_to_bytes(constraint, &bytes, &len);
980 CBS_init(&cbs, bytes, len);
944 switch (name_type) { 981 switch (name_type) {
945 case GEN_DIRNAME: 982 case GEN_DIRNAME:
946 if (len == 0) 983 if (len == 0)
@@ -954,7 +991,7 @@ x509_constraints_validate(GENERAL_NAME *constraint,
954 name->type = GEN_DIRNAME; 991 name->type = GEN_DIRNAME;
955 break; 992 break;
956 case GEN_DNS: 993 case GEN_DNS:
957 if (!x509_constraints_valid_domain_constraint(bytes, len)) 994 if (!x509_constraints_valid_domain_constraint(&cbs))
958 goto err; 995 goto err;
959 if ((name->name = strndup(bytes, len)) == NULL) { 996 if ((name->name = strndup(bytes, len)) == NULL) {
960 error = X509_V_ERR_OUT_OF_MEM; 997 error = X509_V_ERR_OUT_OF_MEM;
@@ -964,7 +1001,7 @@ x509_constraints_validate(GENERAL_NAME *constraint,
964 break; 1001 break;
965 case GEN_EMAIL: 1002 case GEN_EMAIL:
966 if (len > 0 && memchr(bytes + 1, '@', len - 1) != NULL) { 1003 if (len > 0 && memchr(bytes + 1, '@', len - 1) != NULL) {
967 if (!x509_constraints_parse_mailbox(bytes, len, name)) 1004 if (!x509_constraints_parse_mailbox(&cbs, name))
968 goto err; 1005 goto err;
969 break; 1006 break;
970 } 1007 }
@@ -972,13 +1009,17 @@ x509_constraints_validate(GENERAL_NAME *constraint,
972 * Mail constraints of the form @domain.com are accepted by 1009 * Mail constraints of the form @domain.com are accepted by
973 * OpenSSL and Microsoft. 1010 * OpenSSL and Microsoft.
974 */ 1011 */
975 if (len > 0 && bytes[0] == '@') { 1012 if (CBS_len(&cbs) > 0) {
976 bytes++; 1013 if (!CBS_peek_u8(&cbs, &next))
977 len--; 1014 goto err;
1015 if (next == '@') {
1016 if (!CBS_skip(&cbs, 1))
1017 goto err;
1018 }
978 } 1019 }
979 if (!x509_constraints_valid_domain_constraint(bytes, len)) 1020 if (!x509_constraints_valid_domain_constraint(&cbs))
980 goto err; 1021 goto err;
981 if ((name->name = strndup(bytes, len)) == NULL) { 1022 if (!CBS_strdup(&cbs, &name->name)) {
982 error = X509_V_ERR_OUT_OF_MEM; 1023 error = X509_V_ERR_OUT_OF_MEM;
983 goto err; 1024 goto err;
984 } 1025 }
@@ -996,7 +1037,7 @@ x509_constraints_validate(GENERAL_NAME *constraint,
996 name->type = GEN_IPADD; 1037 name->type = GEN_IPADD;
997 break; 1038 break;
998 case GEN_URI: 1039 case GEN_URI:
999 if (!x509_constraints_valid_domain_constraint(bytes, len)) 1040 if (!x509_constraints_valid_domain_constraint(&cbs))
1000 goto err; 1041 goto err;
1001 if ((name->name = strndup(bytes, len)) == NULL) { 1042 if ((name->name = strndup(bytes, len)) == NULL) {
1002 error = X509_V_ERR_OUT_OF_MEM; 1043 error = X509_V_ERR_OUT_OF_MEM;
@@ -1035,7 +1076,6 @@ x509_constraints_extract_constraints(X509 *cert,
1035 return 1; 1076 return 1;
1036 1077
1037 for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++) { 1078 for (i = 0; i < sk_GENERAL_SUBTREE_num(nc->permittedSubtrees); i++) {
1038
1039 subtree = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i); 1079 subtree = sk_GENERAL_SUBTREE_value(nc->permittedSubtrees, i);
1040 if (subtree->minimum || subtree->maximum) { 1080 if (subtree->minimum || subtree->maximum) {
1041 *error = X509_V_ERR_SUBTREE_MINMAX; 1081 *error = X509_V_ERR_SUBTREE_MINMAX;
diff --git a/src/lib/libcrypto/x509/x509_internal.h b/src/lib/libcrypto/x509/x509_internal.h
index 030f24c470..beafd365ed 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.19 2022/06/27 14:10:22 tb Exp $ */ 1/* $OpenBSD: x509_internal.h,v 1.20 2022/11/11 12:02:34 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org> 3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org>
4 * 4 *
@@ -22,6 +22,7 @@
22 22
23#include <openssl/x509_verify.h> 23#include <openssl/x509_verify.h>
24 24
25#include "bytestring.h"
25#include "x509_lcl.h" 26#include "x509_lcl.h"
26 27
27/* Hard limits on structure size and number of signature checks. */ 28/* Hard limits on structure size and number of signature checks. */
@@ -111,14 +112,13 @@ struct x509_constraints_names *x509_constraints_names_new(size_t names_max);
111int x509_constraints_general_to_bytes(GENERAL_NAME *name, uint8_t **bytes, 112int x509_constraints_general_to_bytes(GENERAL_NAME *name, uint8_t **bytes,
112 size_t *len); 113 size_t *len);
113void x509_constraints_names_free(struct x509_constraints_names *names); 114void x509_constraints_names_free(struct x509_constraints_names *names);
114int x509_constraints_valid_host(uint8_t *name, size_t len); 115int x509_constraints_valid_host(CBS *cbs);
115int x509_constraints_valid_sandns(uint8_t *name, size_t len); 116int x509_constraints_valid_sandns(CBS *cbs);
116int x509_constraints_domain(char *domain, size_t dlen, char *constraint, 117int x509_constraints_domain(char *domain, size_t dlen, char *constraint,
117 size_t len); 118 size_t len);
118int x509_constraints_parse_mailbox(uint8_t *candidate, size_t len, 119int x509_constraints_parse_mailbox(CBS *candidate,
119 struct x509_constraints_name *name); 120 struct x509_constraints_name *name);
120int x509_constraints_valid_domain_constraint(uint8_t *constraint, 121int x509_constraints_valid_domain_constraint(CBS *cbs);
121 size_t len);
122int x509_constraints_uri_host(uint8_t *uri, size_t len, char **hostp); 122int x509_constraints_uri_host(uint8_t *uri, size_t len, char **hostp);
123int x509_constraints_uri(uint8_t *uri, size_t ulen, uint8_t *constraint, 123int x509_constraints_uri(uint8_t *uri, size_t ulen, uint8_t *constraint,
124 size_t len, int *error); 124 size_t len, int *error);
diff --git a/src/regress/lib/libcrypto/x509/Makefile b/src/regress/lib/libcrypto/x509/Makefile
index 4635d63ed0..a465b37874 100644
--- a/src/regress/lib/libcrypto/x509/Makefile
+++ b/src/regress/lib/libcrypto/x509/Makefile
@@ -1,4 +1,4 @@
1# $OpenBSD: Makefile,v 1.14 2022/06/28 07:56:34 beck Exp $ 1# $OpenBSD: Makefile,v 1.15 2022/11/11 12:02:34 beck Exp $
2 2
3PROGS = constraints verify x509attribute x509name x509req_ext callback 3PROGS = constraints verify x509attribute x509name x509req_ext callback
4PROGS += expirecallback callbackfailures 4PROGS += expirecallback callbackfailures
@@ -10,6 +10,7 @@ LDADD_verify = ${CRYPTO_INT}
10 10
11WARNINGS = Yes 11WARNINGS = Yes
12CFLAGS += -DLIBRESSL_INTERNAL -Wall -Werror -I$(BSDSRCDIR)/lib/libcrypto/x509 12CFLAGS += -DLIBRESSL_INTERNAL -Wall -Werror -I$(BSDSRCDIR)/lib/libcrypto/x509
13CFLAGS += -I$(BSDSRCDIR)/lib/libcrypto/bytestring
13 14
14SUBDIR += bettertls rfc3779 15SUBDIR += bettertls rfc3779
15 16
diff --git a/src/regress/lib/libcrypto/x509/constraints.c b/src/regress/lib/libcrypto/x509/constraints.c
index 8f7017dd7e..933c4f47c8 100644
--- a/src/regress/lib/libcrypto/x509/constraints.c
+++ b/src/regress/lib/libcrypto/x509/constraints.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: constraints.c,v 1.12 2022/10/30 13:27:15 kn Exp $ */ 1/* $OpenBSD: constraints.c,v 1.13 2022/11/11 12:02:34 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org> 3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org>
4 * 4 *
@@ -23,11 +23,10 @@
23#include <openssl/x509v3.h> 23#include <openssl/x509v3.h>
24#include "x509_internal.h" 24#include "x509_internal.h"
25 25
26 26#define FAIL(msg, ...) \
27#define FAIL(msg, ...) \ 27do { \
28do { \ 28 fprintf(stderr, "[%s:%d] FAIL: ", __FILE__, __LINE__); \
29 fprintf(stderr, "[%s:%d] FAIL: ", __FILE__, __LINE__); \ 29 fprintf(stderr, msg, ##__VA_ARGS__); \
30 fprintf(stderr, msg, ##__VA_ARGS__); \
31} while(0) 30} while(0)
32 31
33unsigned char *valid_hostnames[] = { 32unsigned char *valid_hostnames[] = {
@@ -168,15 +167,16 @@ test_valid_hostnames(void)
168 int i, failure = 0; 167 int i, failure = 0;
169 168
170 for (i = 0; valid_hostnames[i] != NULL; i++) { 169 for (i = 0; valid_hostnames[i] != NULL; i++) {
171 if (!x509_constraints_valid_host(valid_hostnames[i], 170 CBS cbs;
172 strlen(valid_hostnames[i]))) { 171 CBS_init(&cbs, valid_hostnames[i], strlen(valid_hostnames[i]));
172 if (!x509_constraints_valid_host(&cbs)) {
173 FAIL("Valid hostname '%s' rejected\n", 173 FAIL("Valid hostname '%s' rejected\n",
174 valid_hostnames[i]); 174 valid_hostnames[i]);
175 failure = 1; 175 failure = 1;
176 goto done; 176 goto done;
177 } 177 }
178 if (!x509_constraints_valid_sandns(valid_hostnames[i], 178 CBS_init(&cbs, valid_hostnames[i], strlen(valid_hostnames[i]));
179 strlen(valid_hostnames[i]))) { 179 if (!x509_constraints_valid_sandns(&cbs)) {
180 FAIL("Valid sandns '%s' rejected\n", 180 FAIL("Valid sandns '%s' rejected\n",
181 valid_hostnames[i]); 181 valid_hostnames[i]);
182 failure = 1; 182 failure = 1;
@@ -192,8 +192,10 @@ test_valid_sandns_names(void)
192{ 192{
193 int i, failure = 0; 193 int i, failure = 0;
194 for (i = 0; valid_sandns_names[i] != NULL; i++) { 194 for (i = 0; valid_sandns_names[i] != NULL; i++) {
195 if (!x509_constraints_valid_sandns(valid_sandns_names[i], 195 CBS cbs;
196 strlen(valid_sandns_names[i]))) { 196 CBS_init(&cbs, valid_sandns_names[i],
197 strlen(valid_sandns_names[i]));
198 if (!x509_constraints_valid_sandns(&cbs)) {
197 FAIL("Valid dnsname '%s' rejected\n", 199 FAIL("Valid dnsname '%s' rejected\n",
198 valid_sandns_names[i]); 200 valid_sandns_names[i]);
199 failure = 1; 201 failure = 1;
@@ -209,8 +211,10 @@ test_valid_domain_constraints(void)
209{ 211{
210 int i, failure = 0; 212 int i, failure = 0;
211 for (i = 0; valid_domain_constraints[i] != NULL; i++) { 213 for (i = 0; valid_domain_constraints[i] != NULL; i++) {
212 if (!x509_constraints_valid_domain_constraint(valid_domain_constraints[i], 214 CBS cbs;
213 strlen(valid_domain_constraints[i]))) { 215 CBS_init(&cbs, valid_domain_constraints[i],
216 strlen(valid_domain_constraints[i]));
217 if (!x509_constraints_valid_domain_constraint(&cbs)) {
214 FAIL("Valid dnsname '%s' rejected\n", 218 FAIL("Valid dnsname '%s' rejected\n",
215 valid_domain_constraints[i]); 219 valid_domain_constraints[i]);
216 failure = 1; 220 failure = 1;
@@ -227,8 +231,10 @@ test_valid_mbox_names(void)
227 struct x509_constraints_name name = {0}; 231 struct x509_constraints_name name = {0};
228 int i, failure = 0; 232 int i, failure = 0;
229 for (i = 0; valid_mbox_names[i] != NULL; i++) { 233 for (i = 0; valid_mbox_names[i] != NULL; i++) {
230 if (!x509_constraints_parse_mailbox(valid_mbox_names[i], 234 CBS cbs;
231 strlen(valid_mbox_names[i]), &name)) { 235 CBS_init(&cbs, valid_mbox_names[i],
236 strlen(valid_mbox_names[i]));
237 if (!x509_constraints_parse_mailbox(&cbs, &name)) {
232 FAIL("Valid mailbox name '%s' rejected\n", 238 FAIL("Valid mailbox name '%s' rejected\n",
233 valid_mbox_names[i]); 239 valid_mbox_names[i]);
234 failure = 1; 240 failure = 1;
@@ -250,22 +256,25 @@ test_invalid_hostnames(void)
250 char *nulhost = "www.openbsd.org\0"; 256 char *nulhost = "www.openbsd.org\0";
251 257
252 for (i = 0; invalid_hostnames[i] != NULL; i++) { 258 for (i = 0; invalid_hostnames[i] != NULL; i++) {
253 if (x509_constraints_valid_host(invalid_hostnames[i], 259 CBS cbs;
254 strlen(invalid_hostnames[i]))) { 260 CBS_init(&cbs, invalid_hostnames[i],
261 strlen(invalid_hostnames[i]));
262 if (x509_constraints_valid_host(&cbs)) {
255 FAIL("Invalid hostname '%s' accepted\n", 263 FAIL("Invalid hostname '%s' accepted\n",
256 invalid_hostnames[i]); 264 invalid_hostnames[i]);
257 failure = 1; 265 failure = 1;
258 goto done; 266 goto done;
259 } 267 }
260 } 268 }
261 if (x509_constraints_valid_host(nulhost, 269 CBS cbs;
262 strlen(nulhost) + 1)) { 270 CBS_init(&cbs, nulhost, strlen(nulhost) + 1);
271 if (x509_constraints_valid_host(&cbs)) {
263 FAIL("hostname with NUL byte accepted\n"); 272 FAIL("hostname with NUL byte accepted\n");
264 failure = 1; 273 failure = 1;
265 goto done; 274 goto done;
266 } 275 }
267 if (x509_constraints_valid_sandns(nulhost, 276 CBS_init(&cbs, nulhost, strlen(nulhost) + 1);
268 strlen(nulhost) + 1)) { 277 if (x509_constraints_valid_sandns(&cbs)) {
269 FAIL("sandns with NUL byte accepted\n"); 278 FAIL("sandns with NUL byte accepted\n");
270 failure = 1; 279 failure = 1;
271 goto done; 280 goto done;
@@ -279,8 +288,10 @@ test_invalid_sandns_names(void)
279{ 288{
280 int i, failure = 0; 289 int i, failure = 0;
281 for (i = 0; invalid_sandns_names[i] != NULL; i++) { 290 for (i = 0; invalid_sandns_names[i] != NULL; i++) {
282 if (x509_constraints_valid_sandns(invalid_sandns_names[i], 291 CBS cbs;
283 strlen(invalid_sandns_names[i]))) { 292 CBS_init(&cbs, invalid_sandns_names[i],
293 strlen(invalid_sandns_names[i]));
294 if (x509_constraints_valid_sandns(&cbs)) {
284 FAIL("Valid dnsname '%s' rejected\n", 295 FAIL("Valid dnsname '%s' rejected\n",
285 invalid_sandns_names[i]); 296 invalid_sandns_names[i]);
286 failure = 1; 297 failure = 1;
@@ -297,8 +308,10 @@ test_invalid_mbox_names(void)
297 int i, failure = 0; 308 int i, failure = 0;
298 struct x509_constraints_name name = {0}; 309 struct x509_constraints_name name = {0};
299 for (i = 0; invalid_mbox_names[i] != NULL; i++) { 310 for (i = 0; invalid_mbox_names[i] != NULL; i++) {
300 if (x509_constraints_parse_mailbox(invalid_mbox_names[i], 311 CBS cbs;
301 strlen(invalid_mbox_names[i]), &name)) { 312 CBS_init(&cbs, invalid_mbox_names[i],
313 strlen(invalid_mbox_names[i]));
314 if (x509_constraints_parse_mailbox(&cbs, &name)) {
302 FAIL("invalid mailbox name '%s' accepted\n", 315 FAIL("invalid mailbox name '%s' accepted\n",
303 invalid_mbox_names[i]); 316 invalid_mbox_names[i]);
304 failure = 1; 317 failure = 1;
@@ -318,8 +331,10 @@ test_invalid_domain_constraints(void)
318{ 331{
319 int i, failure = 0; 332 int i, failure = 0;
320 for (i = 0; invalid_domain_constraints[i] != NULL; i++) { 333 for (i = 0; invalid_domain_constraints[i] != NULL; i++) {
321 if (x509_constraints_valid_domain_constraint(invalid_domain_constraints[i], 334 CBS cbs;
322 strlen(invalid_domain_constraints[i]))) { 335 CBS_init(&cbs, invalid_domain_constraints[i],
336 strlen(invalid_domain_constraints[i]));
337 if (x509_constraints_valid_domain_constraint(&cbs)) {
323 FAIL("invalid dnsname '%s' accepted\n", 338 FAIL("invalid dnsname '%s' accepted\n",
324 invalid_domain_constraints[i]); 339 invalid_domain_constraints[i]);
325 failure = 1; 340 failure = 1;
@@ -333,12 +348,12 @@ test_invalid_domain_constraints(void)
333static int 348static int
334test_invalid_uri(void) 349test_invalid_uri(void)
335{ 350{
336 int j, failure=0; 351 int j, failure = 0;
337 char *hostpart = NULL; 352 char *hostpart = NULL;
338 353
339 for (j = 0; invaliduri[j] != NULL; j++) { 354 for (j = 0; invaliduri[j] != NULL; j++) {
340 if (x509_constraints_uri_host(invaliduri[j], 355 if (x509_constraints_uri_host(invaliduri[j],
341 strlen(invaliduri[j]), &hostpart) != 0) { 356 strlen(invaliduri[j]), &hostpart) != 0) {
342 FAIL("invalid URI '%s' accepted\n", 357 FAIL("invalid URI '%s' accepted\n",
343 invaliduri[j]); 358 invaliduri[j]);
344 failure = 1; 359 failure = 1;
@@ -355,8 +370,10 @@ test_invalid_uri(void)
355static int 370static int
356test_constraints1(void) 371test_constraints1(void)
357{ 372{
358 char *c; size_t cl; 373 char *c;
359 char *d; size_t dl; 374 size_t cl;
375 char *d;
376 size_t dl;
360 int failure = 0; 377 int failure = 0;
361 int error = 0; 378 int error = 0;
362 int i, j; 379 int i, j;
@@ -450,7 +467,7 @@ test_constraints1(void)
450 char *hostpart = NULL; 467 char *hostpart = NULL;
451 error = 0; 468 error = 0;
452 if (!x509_constraints_uri_host(noauthority[j], 469 if (!x509_constraints_uri_host(noauthority[j],
453 strlen(noauthority[j]), &hostpart)) { 470 strlen(noauthority[j]), &hostpart)) {
454 FAIL("name '%s' should parse as a URI", 471 FAIL("name '%s' should parse as a URI",
455 noauthority[j]); 472 noauthority[j]);
456 failure = 1; 473 failure = 1;