summaryrefslogtreecommitdiff
path: root/src/lib
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib')
-rw-r--r--src/lib/libcrypto/x509/x509_constraints.c101
1 files changed, 72 insertions, 29 deletions
diff --git a/src/lib/libcrypto/x509/x509_constraints.c b/src/lib/libcrypto/x509/x509_constraints.c
index c4f32c9cfc..61a08cacef 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.33 2026/04/13 17:04:23 beck Exp $ */ 1/* $OpenBSD: x509_constraints.c,v 1.34 2026/07/14 15:52:52 jsing Exp $ */
2/* 2/*
3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org> 3 * Copyright (c) 2020 Bob Beck <beck@openbsd.org>
4 * 4 *
@@ -38,21 +38,40 @@
38#define MAX_IP_ADDRESS_LENGTH (size_t)46 38#define MAX_IP_ADDRESS_LENGTH (size_t)46
39 39
40static int 40static int
41cbs_is_ip_address(CBS *cbs, int *is_ip) 41host_is_ip_address(CBS *cbs, int *is_ip)
42{ 42{
43 struct sockaddr_in6 sin6; 43 struct sockaddr_in6 sin6;
44 struct sockaddr_in sin4; 44 struct sockaddr_in sin4;
45 uint8_t first, last;
45 char *name = NULL; 46 char *name = NULL;
47 CBS ipv6_cbs;
46 48
47 *is_ip = 0; 49 *is_ip = 0;
50
48 if (CBS_len(cbs) > MAX_IP_ADDRESS_LENGTH) 51 if (CBS_len(cbs) > MAX_IP_ADDRESS_LENGTH)
49 return 1; 52 return 1;
53
54 /* Must be an IPv6 literal. */
55 CBS_dup(cbs, &ipv6_cbs);
56 if (!CBS_get_u8(&ipv6_cbs, &first))
57 return 1;
58 if (!CBS_get_last_u8(&ipv6_cbs, &last))
59 return 1;
60 if (first == '[' && last == ']') {
61 if (!CBS_strdup(&ipv6_cbs, &name))
62 return 0;
63 if (inet_pton(AF_INET6, name, &sin6) == 1)
64 *is_ip = 1;
65 goto done;
66 }
67
68 /* Or an IPv4 address. */
50 if (!CBS_strdup(cbs, &name)) 69 if (!CBS_strdup(cbs, &name))
51 return 0; 70 return 0;
52 if (inet_pton(AF_INET, name, &sin4) == 1 || 71 if (inet_pton(AF_INET, name, &sin4) == 1)
53 inet_pton(AF_INET6, name, &sin6) == 1)
54 *is_ip = 1; 72 *is_ip = 1;
55 73
74 done:
56 free(name); 75 free(name);
57 return 1; 76 return 1;
58} 77}
@@ -273,13 +292,13 @@ x509_constraints_valid_host(CBS *cbs, int permit_ip)
273 return 0; 292 return 0;
274 if (first == '.') 293 if (first == '.')
275 return 0; /* leading . not allowed in a host name or IP */ 294 return 0; /* leading . not allowed in a host name or IP */
276 if (!permit_ip) { 295 if (!host_is_ip_address(cbs, &is_ip))
277 if (!cbs_is_ip_address(cbs, &is_ip)) 296 return 0;
278 return 0; 297 if (is_ip) {
279 if (is_ip) 298 if (permit_ip)
280 return 0; 299 return 1;
300 return 0;
281 } 301 }
282
283 return x509_constraints_valid_domain_internal(cbs, 0); 302 return x509_constraints_valid_domain_internal(cbs, 0);
284} 303}
285 304
@@ -508,10 +527,11 @@ x509_constraints_valid_domain_constraint(CBS *cbs)
508int 527int
509x509_constraints_uri_host(uint8_t *uri, size_t len, char **hostpart) 528x509_constraints_uri_host(uint8_t *uri, size_t len, char **hostpart)
510{ 529{
511 size_t i, hostlen = 0;
512 uint8_t *authority = NULL; 530 uint8_t *authority = NULL;
513 char *host = NULL; 531 uint8_t *host = NULL;
532 size_t hostlen = 0;
514 CBS host_cbs; 533 CBS host_cbs;
534 size_t i;
515 535
516 /* 536 /*
517 * Find first '//'. there must be at least a '//' and 537 * Find first '//'. there must be at least a '//' and
@@ -542,31 +562,55 @@ x509_constraints_uri_host(uint8_t *uri, size_t len, char **hostpart)
542 for (i = authority - uri; i < len; i++) { 562 for (i = authority - uri; i < len; i++) {
543 if (!isascii(uri[i])) 563 if (!isascii(uri[i]))
544 return 0; 564 return 0;
545 /* it has a userinfo part */ 565 /*
546 if (uri[i] == '@') { 566 * Per RFC 3986 section 3.2, authority is terminated
547 hostlen = 0; 567 * by a slash (/), question mark (?), hash (#) or by
548 /* it can only have one */ 568 * the end of the URI.
549 if (host != NULL) 569 */
550 break; 570 if (uri[i] == '/' || uri[i] == '?' || uri[i] == '#')
551 /* start after the userinfo part */
552 host = uri + i + 1;
553 continue;
554 }
555 /* did we find the end? */
556 if (uri[i] == ':' || uri[i] == '/' || uri[i] == '?' ||
557 uri[i] == '#')
558 break; 571 break;
572
559 hostlen++; 573 hostlen++;
560 } 574 }
575
576 host = authority;
577
578 /* Remove any leading userinfo part. */
579 for (i = 0; i < hostlen; i++) {
580 if (authority[i] != '@')
581 continue;
582
583 /* Only one at-sign (@) is permitted. */
584 if (host != authority)
585 return 0;
586
587 /* Start after the userinfo part. */
588 host = authority + i + 1;
589 }
590 hostlen = hostlen - (host - authority);
591
561 if (hostlen == 0) 592 if (hostlen == 0)
562 return 0; 593 return 0;
563 if (host == NULL) 594
564 host = authority; 595 /* Remove any port part, respecting IPv6 literals. */
596 for (i = hostlen - 1; i > 0; i--) {
597 if (host[i] == ']')
598 break;
599 if (host[i] == ':') {
600 hostlen = i;
601 break;
602 }
603 }
604
605 if (hostlen == 0)
606 return 0;
607
565 CBS_init(&host_cbs, host, hostlen); 608 CBS_init(&host_cbs, host, hostlen);
566 if (!x509_constraints_valid_host(&host_cbs, 1)) 609 if (!x509_constraints_valid_host(&host_cbs, 1))
567 return 0; 610 return 0;
568 if (hostpart != NULL && !CBS_strdup(&host_cbs, hostpart)) 611 if (hostpart != NULL && !CBS_strdup(&host_cbs, hostpart))
569 return 0; 612 return 0;
613
570 return 1; 614 return 1;
571} 615}
572 616
@@ -647,8 +691,7 @@ x509_constraints_domain(char *domain, size_t dlen, char *constraint, size_t len)
647 691
648int 692int
649x509_constraints_uri(uint8_t *uri, size_t ulen, uint8_t *constraint, 693x509_constraints_uri(uint8_t *uri, size_t ulen, uint8_t *constraint,
650 size_t len, 694 size_t len, int *error)
651 int *error)
652{ 695{
653 int ret = 0; 696 int ret = 0;
654 char *hostpart = NULL; 697 char *hostpart = NULL;