diff options
Diffstat (limited to 'src/lib')
| -rw-r--r-- | src/lib/libcrypto/x509/x509_constraints.c | 101 |
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 | ||
| 40 | static int | 40 | static int |
| 41 | cbs_is_ip_address(CBS *cbs, int *is_ip) | 41 | host_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) | |||
| 508 | int | 527 | int |
| 509 | x509_constraints_uri_host(uint8_t *uri, size_t len, char **hostpart) | 528 | x509_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 | ||
| 648 | int | 692 | int |
| 649 | x509_constraints_uri(uint8_t *uri, size_t ulen, uint8_t *constraint, | 693 | x509_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; |
