yuezonghe | 824eb0c | 2024-06-27 02:32:26 -0700 | [diff] [blame] | 1 | /* |
| 2 | * Copyright 2017-2019 The OpenSSL Project Authors. All Rights Reserved. |
| 3 | * Copyright 2017 BaishanCloud. All rights reserved. |
| 4 | * |
| 5 | * Licensed under the OpenSSL license (the "License"). You may not use |
| 6 | * this file except in compliance with the License. You can obtain a copy |
| 7 | * in the file LICENSE in the source distribution or at |
| 8 | * https://www.openssl.org/source/license.html |
| 9 | */ |
| 10 | |
| 11 | #include <string.h> |
| 12 | |
| 13 | #include <openssl/opensslconf.h> |
| 14 | #include <openssl/bio.h> |
| 15 | #include <openssl/crypto.h> |
| 16 | #include <openssl/evp.h> |
| 17 | #include <openssl/ssl.h> |
| 18 | #include <openssl/err.h> |
| 19 | #include <time.h> |
| 20 | |
| 21 | #include "../ssl/packet_local.h" |
| 22 | |
| 23 | #include "testutil.h" |
| 24 | #include "internal/nelem.h" |
| 25 | #include "ssltestlib.h" |
| 26 | |
| 27 | #define CLIENT_VERSION_LEN 2 |
| 28 | |
| 29 | static const char *host = "dummy-host"; |
| 30 | |
| 31 | static char *cert = NULL; |
| 32 | static char *privkey = NULL; |
| 33 | |
| 34 | static int get_sni_from_client_hello(BIO *bio, char **sni) |
| 35 | { |
| 36 | long len; |
| 37 | unsigned char *data; |
| 38 | PACKET pkt = {0}, pkt2 = {0}, pkt3 = {0}, pkt4 = {0}, pkt5 = {0}; |
| 39 | unsigned int servname_type = 0, type = 0; |
| 40 | int ret = 0; |
| 41 | |
| 42 | len = BIO_get_mem_data(bio, (char **)&data); |
| 43 | if (!TEST_true(PACKET_buf_init(&pkt, data, len)) |
| 44 | /* Skip the record header */ |
| 45 | || !PACKET_forward(&pkt, SSL3_RT_HEADER_LENGTH) |
| 46 | /* Skip the handshake message header */ |
| 47 | || !TEST_true(PACKET_forward(&pkt, SSL3_HM_HEADER_LENGTH)) |
| 48 | /* Skip client version and random */ |
| 49 | || !TEST_true(PACKET_forward(&pkt, CLIENT_VERSION_LEN |
| 50 | + SSL3_RANDOM_SIZE)) |
| 51 | /* Skip session id */ |
| 52 | || !TEST_true(PACKET_get_length_prefixed_1(&pkt, &pkt2)) |
| 53 | /* Skip ciphers */ |
| 54 | || !TEST_true(PACKET_get_length_prefixed_2(&pkt, &pkt2)) |
| 55 | /* Skip compression */ |
| 56 | || !TEST_true(PACKET_get_length_prefixed_1(&pkt, &pkt2)) |
| 57 | /* Extensions len */ |
| 58 | || !TEST_true(PACKET_as_length_prefixed_2(&pkt, &pkt2))) |
| 59 | goto end; |
| 60 | |
| 61 | /* Loop through all extensions for SNI */ |
| 62 | while (PACKET_remaining(&pkt2)) { |
| 63 | if (!TEST_true(PACKET_get_net_2(&pkt2, &type)) |
| 64 | || !TEST_true(PACKET_get_length_prefixed_2(&pkt2, &pkt3))) |
| 65 | goto end; |
| 66 | if (type == TLSEXT_TYPE_server_name) { |
| 67 | if (!TEST_true(PACKET_get_length_prefixed_2(&pkt3, &pkt4)) |
| 68 | || !TEST_uint_ne(PACKET_remaining(&pkt4), 0) |
| 69 | || !TEST_true(PACKET_get_1(&pkt4, &servname_type)) |
| 70 | || !TEST_uint_eq(servname_type, TLSEXT_NAMETYPE_host_name) |
| 71 | || !TEST_true(PACKET_get_length_prefixed_2(&pkt4, &pkt5)) |
| 72 | || !TEST_uint_le(PACKET_remaining(&pkt5), TLSEXT_MAXLEN_host_name) |
| 73 | || !TEST_false(PACKET_contains_zero_byte(&pkt5)) |
| 74 | || !TEST_true(PACKET_strndup(&pkt5, sni))) |
| 75 | goto end; |
| 76 | ret = 1; |
| 77 | goto end; |
| 78 | } |
| 79 | } |
| 80 | end: |
| 81 | return ret; |
| 82 | } |
| 83 | |
| 84 | static int client_setup_sni_before_state(void) |
| 85 | { |
| 86 | SSL_CTX *ctx; |
| 87 | SSL *con = NULL; |
| 88 | BIO *rbio; |
| 89 | BIO *wbio; |
| 90 | char *hostname = NULL; |
| 91 | int ret = 0; |
| 92 | |
| 93 | /* use TLS_method to blur 'side' */ |
| 94 | ctx = SSL_CTX_new(TLS_method()); |
| 95 | if (!TEST_ptr(ctx)) |
| 96 | goto end; |
| 97 | |
| 98 | con = SSL_new(ctx); |
| 99 | if (!TEST_ptr(con)) |
| 100 | goto end; |
| 101 | |
| 102 | /* set SNI before 'client side' is set */ |
| 103 | SSL_set_tlsext_host_name(con, host); |
| 104 | |
| 105 | rbio = BIO_new(BIO_s_mem()); |
| 106 | wbio = BIO_new(BIO_s_mem()); |
| 107 | if (!TEST_ptr(rbio)|| !TEST_ptr(wbio)) { |
| 108 | BIO_free(rbio); |
| 109 | BIO_free(wbio); |
| 110 | goto end; |
| 111 | } |
| 112 | |
| 113 | SSL_set_bio(con, rbio, wbio); |
| 114 | |
| 115 | if (!TEST_int_le(SSL_connect(con), 0)) |
| 116 | /* This shouldn't succeed because we don't have a server! */ |
| 117 | goto end; |
| 118 | if (!TEST_true(get_sni_from_client_hello(wbio, &hostname))) |
| 119 | /* no SNI in client hello */ |
| 120 | goto end; |
| 121 | if (!TEST_str_eq(hostname, host)) |
| 122 | /* incorrect SNI value */ |
| 123 | goto end; |
| 124 | ret = 1; |
| 125 | end: |
| 126 | OPENSSL_free(hostname); |
| 127 | SSL_free(con); |
| 128 | SSL_CTX_free(ctx); |
| 129 | return ret; |
| 130 | } |
| 131 | |
| 132 | static int client_setup_sni_after_state(void) |
| 133 | { |
| 134 | SSL_CTX *ctx; |
| 135 | SSL *con = NULL; |
| 136 | BIO *rbio; |
| 137 | BIO *wbio; |
| 138 | char *hostname = NULL; |
| 139 | int ret = 0; |
| 140 | |
| 141 | /* use TLS_method to blur 'side' */ |
| 142 | ctx = SSL_CTX_new(TLS_method()); |
| 143 | if (!TEST_ptr(ctx)) |
| 144 | goto end; |
| 145 | |
| 146 | con = SSL_new(ctx); |
| 147 | if (!TEST_ptr(con)) |
| 148 | goto end; |
| 149 | |
| 150 | rbio = BIO_new(BIO_s_mem()); |
| 151 | wbio = BIO_new(BIO_s_mem()); |
| 152 | if (!TEST_ptr(rbio)|| !TEST_ptr(wbio)) { |
| 153 | BIO_free(rbio); |
| 154 | BIO_free(wbio); |
| 155 | goto end; |
| 156 | } |
| 157 | |
| 158 | SSL_set_bio(con, rbio, wbio); |
| 159 | SSL_set_connect_state(con); |
| 160 | |
| 161 | /* set SNI after 'client side' is set */ |
| 162 | SSL_set_tlsext_host_name(con, host); |
| 163 | |
| 164 | if (!TEST_int_le(SSL_connect(con), 0)) |
| 165 | /* This shouldn't succeed because we don't have a server! */ |
| 166 | goto end; |
| 167 | if (!TEST_true(get_sni_from_client_hello(wbio, &hostname))) |
| 168 | /* no SNI in client hello */ |
| 169 | goto end; |
| 170 | if (!TEST_str_eq(hostname, host)) |
| 171 | /* incorrect SNI value */ |
| 172 | goto end; |
| 173 | ret = 1; |
| 174 | end: |
| 175 | OPENSSL_free(hostname); |
| 176 | SSL_free(con); |
| 177 | SSL_CTX_free(ctx); |
| 178 | return ret; |
| 179 | } |
| 180 | |
| 181 | static int server_setup_sni(void) |
| 182 | { |
| 183 | SSL_CTX *cctx = NULL, *sctx = NULL; |
| 184 | SSL *clientssl = NULL, *serverssl = NULL; |
| 185 | int testresult = 0; |
| 186 | |
| 187 | if (!TEST_true(create_ssl_ctx_pair(TLS_server_method(), |
| 188 | TLS_client_method(), |
| 189 | TLS1_VERSION, TLS_MAX_VERSION, |
| 190 | &sctx, &cctx, cert, privkey)) |
| 191 | || !TEST_true(create_ssl_objects(sctx, cctx, &serverssl, &clientssl, |
| 192 | NULL, NULL))) |
| 193 | goto end; |
| 194 | |
| 195 | /* set SNI at server side */ |
| 196 | SSL_set_tlsext_host_name(serverssl, host); |
| 197 | |
| 198 | if (!TEST_true(create_ssl_connection(serverssl, clientssl, SSL_ERROR_NONE))) |
| 199 | goto end; |
| 200 | |
| 201 | if (!TEST_ptr_null(SSL_get_servername(serverssl, |
| 202 | TLSEXT_NAMETYPE_host_name))) { |
| 203 | /* SNI should have been cleared during handshake */ |
| 204 | goto end; |
| 205 | } |
| 206 | |
| 207 | testresult = 1; |
| 208 | end: |
| 209 | SSL_free(serverssl); |
| 210 | SSL_free(clientssl); |
| 211 | SSL_CTX_free(sctx); |
| 212 | SSL_CTX_free(cctx); |
| 213 | |
| 214 | return testresult; |
| 215 | } |
| 216 | |
| 217 | typedef int (*sni_test_fn)(void); |
| 218 | |
| 219 | static sni_test_fn sni_test_fns[3] = { |
| 220 | client_setup_sni_before_state, |
| 221 | client_setup_sni_after_state, |
| 222 | server_setup_sni |
| 223 | }; |
| 224 | |
| 225 | static int test_servername(int test) |
| 226 | { |
| 227 | /* |
| 228 | * For each test set up an SSL_CTX and SSL and see |
| 229 | * what SNI behaves. |
| 230 | */ |
| 231 | return sni_test_fns[test](); |
| 232 | } |
| 233 | |
| 234 | int setup_tests(void) |
| 235 | { |
| 236 | if (!TEST_ptr(cert = test_get_argument(0)) |
| 237 | || !TEST_ptr(privkey = test_get_argument(1))) |
| 238 | return 0; |
| 239 | |
| 240 | ADD_ALL_TESTS(test_servername, OSSL_NELEM(sni_test_fns)); |
| 241 | return 1; |
| 242 | } |