summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorbeck <>2020-05-23 17:13:24 +0000
committerbeck <>2020-05-23 17:13:24 +0000
commitce471c0da7f905a6a1c11b47e709a521f8a706af (patch)
treecc3cb487c96b80cc2e522f8bfd09a58f7d2f7ab2 /src
parent6aaa71524fb63f15a7b380ada15b019cfa250176 (diff)
downloadopenbsd-ce471c0da7f905a6a1c11b47e709a521f8a706af.tar.gz
openbsd-ce471c0da7f905a6a1c11b47e709a521f8a706af.tar.bz2
openbsd-ce471c0da7f905a6a1c11b47e709a521f8a706af.zip
Enforce that SNI hostnames be correct as per rfc 6066 and 5980.
Correct SNI alerts to differentiate between illegal parameter and an unknown name. ok tb@`
Diffstat (limited to 'src')
-rw-r--r--src/lib/libssl/ssl_tlsext.c94
-rw-r--r--src/lib/libssl/ssl_tlsext.h3
-rw-r--r--src/regress/lib/libssl/tlsext/tlsexttest.c80
3 files changed, 159 insertions, 18 deletions
diff --git a/src/lib/libssl/ssl_tlsext.c b/src/lib/libssl/ssl_tlsext.c
index f5343c81ab..2184e65a2c 100644
--- a/src/lib/libssl/ssl_tlsext.c
+++ b/src/lib/libssl/ssl_tlsext.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssl_tlsext.c,v 1.71 2020/05/23 08:47:19 tb Exp $ */ 1/* $OpenBSD: ssl_tlsext.c,v 1.72 2020/05/23 17:13:24 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2016, 2017, 2019 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2016, 2017, 2019 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> 4 * Copyright (c) 2017 Doug Hogan <doug@openbsd.org>
@@ -18,6 +18,7 @@
18 */ 18 */
19 19
20#include <openssl/ocsp.h> 20#include <openssl/ocsp.h>
21#include <ctype.h>
21 22
22#include "ssl_locl.h" 23#include "ssl_locl.h"
23 24
@@ -672,6 +673,53 @@ tlsext_sni_client_build(SSL *s, CBB *cbb)
672 return 1; 673 return 1;
673} 674}
674 675
676/*
677 * Does the CBS contain only of a hostname consisting of RFC 5890
678 * compliant A-labels? (see RFC 6066 section 3). Not a complete check
679 * since we don't parse punycode to verify its validity but limits to
680 * correct structure and character set.
681 */
682int
683tlsext_sni_is_valid_hostname(CBS *cbs)
684{
685 uint8_t prev, c = 0;
686 int component = 0;
687 CBS hostname;
688
689 if (CBS_len(cbs) > TLSEXT_MAXLEN_host_name)
690 return 0;
691
692 CBS_dup(cbs, &hostname);
693 while(CBS_len(&hostname) > 0) {
694 prev = c;
695 if (!CBS_get_u8(&hostname, &c))
696 return 0;
697 /* Everything has to be ASCII, with no NUL byte. */
698 if (!isascii(c) || c == '\0')
699 return 0;
700 /* It must be alphanumeric, a '-', or a '.' */
701 if (!(isalnum(c) || c == '-' || c == '.'))
702 return 0;
703 /* '-' and '.' must not start a component or be at the end. */
704 if (component == 0 || CBS_len(&hostname) == 0) {
705 if (c == '-' || c == '.')
706 return 0;
707 }
708 if (c == '.') {
709 /* Components can not end with a dash. */
710 if (prev == '-')
711 return 0;
712 /* Start new component */
713 component = 0;
714 continue;
715 }
716 /* Components must be 63 chars or less. */
717 if (++component > 63)
718 return 0;
719 }
720 return 1;
721}
722
675int 723int
676tlsext_sni_server_parse(SSL *s, CBS *cbs, int *alert) 724tlsext_sni_server_parse(SSL *s, CBS *cbs, int *alert)
677{ 725{
@@ -681,52 +729,66 @@ tlsext_sni_server_parse(SSL *s, CBS *cbs, int *alert)
681 if (!CBS_get_u16_length_prefixed(cbs, &server_name_list)) 729 if (!CBS_get_u16_length_prefixed(cbs, &server_name_list))
682 goto err; 730 goto err;
683 731
684 /*
685 * RFC 6066 section 3 forbids multiple host names with the same type.
686 * Additionally, only one type (host_name) is specified.
687 */
688 if (!CBS_get_u8(&server_name_list, &name_type)) 732 if (!CBS_get_u8(&server_name_list, &name_type))
689 goto err; 733 goto err;
690 if (name_type != TLSEXT_NAMETYPE_host_name) 734 /*
735 * RFC 6066 section 3, only one type (host_name) is specified.
736 * We do not tolerate unknown types, neither does BoringSSL.
737 * other implementations appear more tolerant.
738 */
739 if (name_type != TLSEXT_NAMETYPE_host_name) {
740 *alert = SSL3_AD_ILLEGAL_PARAMETER;
691 goto err; 741 goto err;
742 }
743
692 744
693 if (!CBS_get_u16_length_prefixed(&server_name_list, &host_name)) 745 if (!CBS_get_u16_length_prefixed(&server_name_list, &host_name))
694 goto err; 746 goto err;
695 if (CBS_len(&host_name) == 0 || 747 /*
696 CBS_len(&host_name) > TLSEXT_MAXLEN_host_name || 748 * RFC 6066 section 3 specifies a host name must be at least 1 byte
697 CBS_contains_zero_byte(&host_name)) { 749 * so 0 length is a decode error.
698 *alert = TLS1_AD_UNRECOGNIZED_NAME; 750 */
699 return 0; 751 if (CBS_len(&host_name) == 0)
752 goto err;
753
754 if (!tlsext_sni_is_valid_hostname(&host_name)) {
755 *alert = SSL3_AD_ILLEGAL_PARAMETER;
756 goto err;
700 } 757 }
701 758
702 if (s->internal->hit || S3I(s)->hs_tls13.hrr) { 759 if (s->internal->hit || S3I(s)->hs_tls13.hrr) {
703 if (s->session->tlsext_hostname == NULL) { 760 if (s->session->tlsext_hostname == NULL) {
704 *alert = TLS1_AD_UNRECOGNIZED_NAME; 761 *alert = TLS1_AD_UNRECOGNIZED_NAME;
705 return 0; 762 goto err;
706 } 763 }
707 if (!CBS_mem_equal(&host_name, s->session->tlsext_hostname, 764 if (!CBS_mem_equal(&host_name, s->session->tlsext_hostname,
708 strlen(s->session->tlsext_hostname))) { 765 strlen(s->session->tlsext_hostname))) {
709 *alert = TLS1_AD_UNRECOGNIZED_NAME; 766 *alert = TLS1_AD_UNRECOGNIZED_NAME;
710 return 0; 767 goto err;
711 } 768 }
712 } else { 769 } else {
713 if (s->session->tlsext_hostname != NULL) 770 if (s->session->tlsext_hostname != NULL)
714 goto err; 771 goto err;
715 if (!CBS_strdup(&host_name, &s->session->tlsext_hostname)) { 772 if (!CBS_strdup(&host_name, &s->session->tlsext_hostname)) {
716 *alert = TLS1_AD_INTERNAL_ERROR; 773 *alert = TLS1_AD_INTERNAL_ERROR;
717 return 0; 774 goto err;
718 } 775 }
719 } 776 }
720 777
721 if (CBS_len(&server_name_list) != 0) 778 /*
779 * RFC 6066 section 3 forbids multiple host names with the same type,
780 * therefore we allow only one entry.
781 */
782 if (CBS_len(&server_name_list) != 0) {
783 *alert = SSL3_AD_ILLEGAL_PARAMETER;
722 goto err; 784 goto err;
785 }
723 if (CBS_len(cbs) != 0) 786 if (CBS_len(cbs) != 0)
724 goto err; 787 goto err;
725 788
726 return 1; 789 return 1;
727 790
728 err: 791 err:
729 *alert = SSL_AD_DECODE_ERROR;
730 return 0; 792 return 0;
731} 793}
732 794
diff --git a/src/lib/libssl/ssl_tlsext.h b/src/lib/libssl/ssl_tlsext.h
index aa40f6b1a6..15e0257e63 100644
--- a/src/lib/libssl/ssl_tlsext.h
+++ b/src/lib/libssl/ssl_tlsext.h
@@ -1,4 +1,4 @@
1/* $OpenBSD: ssl_tlsext.h,v 1.22 2020/01/25 12:58:27 jsing Exp $ */ 1/* $OpenBSD: ssl_tlsext.h,v 1.23 2020/05/23 17:13:24 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2016, 2017 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> 4 * Copyright (c) 2017 Doug Hogan <doug@openbsd.org>
@@ -58,6 +58,7 @@ int tlsext_sni_client_parse(SSL *s, CBS *cbs, int *alert);
58int tlsext_sni_server_needs(SSL *s); 58int tlsext_sni_server_needs(SSL *s);
59int tlsext_sni_server_build(SSL *s, CBB *cbb); 59int tlsext_sni_server_build(SSL *s, CBB *cbb);
60int tlsext_sni_server_parse(SSL *s, CBS *cbs, int *alert); 60int tlsext_sni_server_parse(SSL *s, CBS *cbs, int *alert);
61int tlsext_sni_is_valid_hostname(CBS *cbs);
61 62
62int tlsext_supportedgroups_client_needs(SSL *s); 63int tlsext_supportedgroups_client_needs(SSL *s);
63int tlsext_supportedgroups_client_build(SSL *s, CBB *cbb); 64int tlsext_supportedgroups_client_build(SSL *s, CBB *cbb);
diff --git a/src/regress/lib/libssl/tlsext/tlsexttest.c b/src/regress/lib/libssl/tlsext/tlsexttest.c
index 3d03c2c0d3..5cf39e63ae 100644
--- a/src/regress/lib/libssl/tlsext/tlsexttest.c
+++ b/src/regress/lib/libssl/tlsext/tlsexttest.c
@@ -1,4 +1,4 @@
1/* $OpenBSD: tlsexttest.c,v 1.36 2020/05/11 18:20:01 jsing Exp $ */ 1/* $OpenBSD: tlsexttest.c,v 1.37 2020/05/23 17:13:24 beck Exp $ */
2/* 2/*
3 * Copyright (c) 2017 Joel Sing <jsing@openbsd.org> 3 * Copyright (c) 2017 Joel Sing <jsing@openbsd.org>
4 * Copyright (c) 2017 Doug Hogan <doug@openbsd.org> 4 * Copyright (c) 2017 Doug Hogan <doug@openbsd.org>
@@ -3544,6 +3544,81 @@ done:
3544 return (failure); 3544 return (failure);
3545} 3545}
3546 3546
3547unsigned char *valid_hostnames[] = {
3548 "openbsd.org",
3549 "op3nbsd.org",
3550 "org",
3551 "3openbsd.com",
3552 "3-0penb-d.c-m",
3553 "a",
3554 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
3555 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
3556 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
3557 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
3558 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
3559 NULL,
3560};
3561
3562static int
3563test_tlsext_valid_hostnames(void) {
3564 int i, failure = 0;
3565 for (i = 0; valid_hostnames[i] != NULL; i++) {
3566 CBS cbs;
3567 CBS_init(&cbs, valid_hostnames[i], strlen(valid_hostnames[i]));
3568 if (!tlsext_sni_is_valid_hostname(&cbs)) {
3569 fprintf(stderr, "FAIL: %s\n", valid_hostnames[i]);
3570 FAIL("Valid hostname rejected");
3571 failure = 1;
3572 goto done;
3573 }
3574 }
3575 done:
3576 return failure;
3577}
3578
3579unsigned char *invalid_hostnames[] = {
3580 "openbsd.org.",
3581 "openbsd..org",
3582 "openbsd.org-",
3583 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.com",
3584 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
3585 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
3586 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa."
3587 "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.a",
3588 "-p3nbsd.org",
3589 "openbs-.org",
3590 "openbsd\n.org",
3591 "open_bsd.org",
3592 "open\178bsd.org",
3593 "open\255bsd.org",
3594 NULL,
3595};
3596
3597static int
3598test_tlsext_invalid_hostnames(void) {
3599 int i, failure = 0;
3600 CBS cbs;
3601 for (i = 0; invalid_hostnames[i] != NULL; i++) {
3602 CBS_init(&cbs, invalid_hostnames[i],
3603 strlen(invalid_hostnames[i]));
3604 if (tlsext_sni_is_valid_hostname(&cbs)) {
3605 fprintf(stderr, "%s\n", invalid_hostnames[i]);
3606 FAIL("Invalid hostname accepted");
3607 failure = 1;
3608 goto done;
3609 }
3610 }
3611 CBS_init(&cbs, valid_hostnames[0],
3612 strlen(valid_hostnames[0]) + 1);
3613 if (tlsext_sni_is_valid_hostname(&cbs)) {
3614 FAIL("hostname with NUL byte accepted");
3615 failure = 1;
3616 goto done;
3617 }
3618 done:
3619 return failure;
3620}
3621
3547 3622
3548int 3623int
3549main(int argc, char **argv) 3624main(int argc, char **argv)
@@ -3595,5 +3670,8 @@ main(int argc, char **argv)
3595 failed |= test_tlsext_clienthello_build(); 3670 failed |= test_tlsext_clienthello_build();
3596 failed |= test_tlsext_serverhello_build(); 3671 failed |= test_tlsext_serverhello_build();
3597 3672
3673 failed |= test_tlsext_valid_hostnames();
3674 failed |= test_tlsext_invalid_hostnames();
3675
3598 return (failed); 3676 return (failed);
3599} 3677}