diff options
-rw-r--r-- | test/handshake_helper.c | 118 | ||||
-rw-r--r-- | test/ssl-tests/05-sni.conf | 107 | ||||
-rw-r--r-- | test/ssl-tests/05-sni.conf.in | 57 | ||||
-rw-r--r-- | test/ssl_test_ctx.c | 3 | ||||
-rw-r--r-- | test/ssl_test_ctx.h | 5 |
5 files changed, 287 insertions, 3 deletions
diff --git a/test/handshake_helper.c b/test/handshake_helper.c index c82581c576..88f6aec894 100644 --- a/test/handshake_helper.c +++ b/test/handshake_helper.c @@ -123,6 +123,67 @@ static int select_server_ctx(SSL *s, void *arg, int ignore) } } +static int early_select_server_ctx(SSL *s, void *arg, int ignore) +{ + const char *servername; + const unsigned char *p; + size_t len, remaining; + HANDSHAKE_EX_DATA *ex_data = + (HANDSHAKE_EX_DATA*)(SSL_get_ex_data(s, ex_data_idx)); + + /* + * The server_name extension was given too much extensibility when it + * was written, so parsing the normal case is a bit complex. + */ + if (!SSL_early_get0_ext(s, TLSEXT_TYPE_server_name, &p, &remaining) || + remaining <= 2) + return 0; + /* Extract the length of the supplied list of names. */ + len = (*(p++) << 1); + len += *(p++); + if (len + 2 != remaining) + return 0; + remaining = len; + /* + * The list in practice only has a single element, so we only consider + * the first one. + */ + if (remaining == 0 || *p++ != TLSEXT_NAMETYPE_host_name) + return 0; + remaining--; + /* Now we can finally pull out the byte array with the actual hostname. */ + if (remaining <= 2) + return 0; + len = (*(p++) << 1); + len += *(p++); + if (len + 2 > remaining) + return 0; + remaining = len; + servername = (const char *)p; + + if (len == strlen("server2") && strncmp(servername, "server2", len) == 0) { + SSL_CTX *new_ctx = arg; + SSL_set_SSL_CTX(s, new_ctx); + /* + * Copy over all the SSL_CTX options - reasonable behavior + * allows testing of cases where the options between two + * contexts differ/conflict + */ + SSL_clear_options(s, 0xFFFFFFFFL); + SSL_set_options(s, SSL_CTX_get_options(new_ctx)); + + ex_data->servername = SSL_TEST_SERVERNAME_SERVER2; + return 1; + } else if (len == strlen("server1") && + strncmp(servername, "server1", len) == 0) { + ex_data->servername = SSL_TEST_SERVERNAME_SERVER1; + return 1; + } else if (ignore) { + ex_data->servername = SSL_TEST_SERVERNAME_SERVER1; + return 1; + } + return 0; +} /* * (RFC 6066): * If the server understood the ClientHello extension but @@ -144,6 +205,50 @@ static int servername_reject_cb(SSL *s, int *ad, void *arg) return select_server_ctx(s, arg, 0); } +static int early_ignore_cb(SSL *s, int *al, void *arg) +{ + if (!early_select_server_ctx(s, arg, 1)) { + *al = SSL_AD_UNRECOGNIZED_NAME; + return 0; + } + return 1; +} + +static int early_reject_cb(SSL *s, int *al, void *arg) +{ + if (!early_select_server_ctx(s, arg, 0)) { + *al = SSL_AD_UNRECOGNIZED_NAME; + return 0; + } + return 1; +} + +static int early_nov12_cb(SSL *s, int *al, void *arg) +{ + int ret; + unsigned int v; + const unsigned char *p; + + v = SSL_early_get0_legacy_version(s); + if (v > TLS1_2_VERSION || v < SSL3_VERSION) { + *al = SSL_AD_PROTOCOL_VERSION; + return 0; + } + (void)SSL_early_get0_session_id(s, &p); + if (p == NULL || + SSL_early_get0_random(s, &p) == 0 || + SSL_early_get0_ciphers(s, &p) == 0 || + SSL_early_get0_compression_methods(s, &p) == 0) { + *al = SSL_AD_INTERNAL_ERROR; + return 0; + } + ret = early_select_server_ctx(s, arg, 0); + SSL_set_max_proto_version(s, TLS1_1_VERSION); + if (!ret) + *al = SSL_AD_UNRECOGNIZED_NAME; + return ret; +} + static unsigned char dummy_ocsp_resp_good_val = 0xff; static unsigned char dummy_ocsp_resp_bad_val = 0xfe; @@ -337,7 +442,10 @@ static void configure_handshake_ctx(SSL_CTX *server_ctx, SSL_CTX *server2_ctx, break; } - /* link the two contexts for SNI purposes */ + /* + * Link the two contexts for SNI purposes. + * Also do early callbacks here, as setting both early and SNI is bad. + */ switch (extra->server.servername_callback) { case SSL_TEST_SERVERNAME_IGNORE_MISMATCH: SSL_CTX_set_tlsext_servername_callback(server_ctx, servername_ignore_cb); @@ -349,6 +457,14 @@ static void configure_handshake_ctx(SSL_CTX *server_ctx, SSL_CTX *server2_ctx, break; case SSL_TEST_SERVERNAME_CB_NONE: break; + case SSL_TEST_SERVERNAME_EARLY_IGNORE_MISMATCH: + SSL_CTX_set_early_cb(server_ctx, early_ignore_cb, server2_ctx); + break; + case SSL_TEST_SERVERNAME_EARLY_REJECT_MISMATCH: + SSL_CTX_set_early_cb(server_ctx, early_reject_cb, server2_ctx); + break; + case SSL_TEST_SERVERNAME_EARLY_NO_V12: + SSL_CTX_set_early_cb(server_ctx, early_nov12_cb, server2_ctx); } if (extra->server.cert_status != SSL_TEST_CERT_STATUS_NONE) { diff --git a/test/ssl-tests/05-sni.conf b/test/ssl-tests/05-sni.conf index e1fb3d9d89..d5d350e399 100644 --- a/test/ssl-tests/05-sni.conf +++ b/test/ssl-tests/05-sni.conf @@ -1,6 +1,6 @@ # Generated with generate_ssl_tests.pl -num_tests = 6 +num_tests = 9 test-0 = 0-SNI-switch-context test-1 = 1-SNI-keep-context @@ -8,6 +8,9 @@ test-2 = 2-SNI-no-server-support test-3 = 3-SNI-no-client-support test-4 = 4-SNI-bad-sni-ignore-mismatch test-5 = 5-SNI-bad-sni-reject-mismatch +test-6 = 6-SNI-bad-early-sni-ignore-mismatch +test-7 = 7-SNI-bad-early-sni-reject-mismatch +test-8 = 8-SNI-early-disable-v12 # =========================================================== [0-SNI-switch-context] @@ -201,3 +204,105 @@ ServerNameCallback = RejectMismatch ServerName = invalid +# =========================================================== + +[6-SNI-bad-early-sni-ignore-mismatch] +ssl_conf = 6-SNI-bad-early-sni-ignore-mismatch-ssl + +[6-SNI-bad-early-sni-ignore-mismatch-ssl] +server = 6-SNI-bad-early-sni-ignore-mismatch-server +client = 6-SNI-bad-early-sni-ignore-mismatch-client +server2 = 6-SNI-bad-early-sni-ignore-mismatch-server + +[6-SNI-bad-early-sni-ignore-mismatch-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[6-SNI-bad-early-sni-ignore-mismatch-client] +CipherString = DEFAULT +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-6] +ExpectedResult = Success +ExpectedServerName = server1 +server = 6-SNI-bad-early-sni-ignore-mismatch-server-extra +server2 = 6-SNI-bad-early-sni-ignore-mismatch-server-extra +client = 6-SNI-bad-early-sni-ignore-mismatch-client-extra + +[6-SNI-bad-early-sni-ignore-mismatch-server-extra] +ServerNameCallback = EarlyIgnoreMismatch + +[6-SNI-bad-early-sni-ignore-mismatch-client-extra] +ServerName = invalid + + +# =========================================================== + +[7-SNI-bad-early-sni-reject-mismatch] +ssl_conf = 7-SNI-bad-early-sni-reject-mismatch-ssl + +[7-SNI-bad-early-sni-reject-mismatch-ssl] +server = 7-SNI-bad-early-sni-reject-mismatch-server +client = 7-SNI-bad-early-sni-reject-mismatch-client +server2 = 7-SNI-bad-early-sni-reject-mismatch-server + +[7-SNI-bad-early-sni-reject-mismatch-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[7-SNI-bad-early-sni-reject-mismatch-client] +CipherString = DEFAULT +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-7] +ExpectedResult = ServerFail +ExpectedServerAlert = UnrecognizedName +server = 7-SNI-bad-early-sni-reject-mismatch-server-extra +server2 = 7-SNI-bad-early-sni-reject-mismatch-server-extra +client = 7-SNI-bad-early-sni-reject-mismatch-client-extra + +[7-SNI-bad-early-sni-reject-mismatch-server-extra] +ServerNameCallback = EarlyRejectMismatch + +[7-SNI-bad-early-sni-reject-mismatch-client-extra] +ServerName = invalid + + +# =========================================================== + +[8-SNI-early-disable-v12] +ssl_conf = 8-SNI-early-disable-v12-ssl + +[8-SNI-early-disable-v12-ssl] +server = 8-SNI-early-disable-v12-server +client = 8-SNI-early-disable-v12-client +server2 = 8-SNI-early-disable-v12-server + +[8-SNI-early-disable-v12-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[8-SNI-early-disable-v12-client] +CipherString = DEFAULT +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-8] +ExpectedProtocol = TLSv1.1 +ExpectedServerName = server2 +server = 8-SNI-early-disable-v12-server-extra +server2 = 8-SNI-early-disable-v12-server-extra +client = 8-SNI-early-disable-v12-client-extra + +[8-SNI-early-disable-v12-server-extra] +ServerNameCallback = EarlyNoV12 + +[8-SNI-early-disable-v12-client-extra] +ServerName = server2 + + diff --git a/test/ssl-tests/05-sni.conf.in b/test/ssl-tests/05-sni.conf.in index 76003e7623..63b295dac8 100644 --- a/test/ssl-tests/05-sni.conf.in +++ b/test/ssl-tests/05-sni.conf.in @@ -13,6 +13,7 @@ use strict; use warnings; package ssltests; +use OpenSSL::Test::Utils; our @tests = ( { @@ -109,4 +110,60 @@ our @tests = ( "ExpectedServerAlert" => "UnrecognizedName" }, }, + { + name => "SNI-bad-early-sni-ignore-mismatch", + server => { + extra => { + "ServerNameCallback" => "EarlyIgnoreMismatch", + }, + }, + client => { + extra => { + "ServerName" => "invalid", + }, + }, + test => { + "ExpectedServerName" => "server1", + "ExpectedResult" => "Success" + }, + }, + { + name => "SNI-bad-early-sni-reject-mismatch", + server => { + extra => { + "ServerNameCallback" => "EarlyRejectMismatch", + }, + }, + client => { + extra => { + "ServerName" => "invalid", + }, + }, + test => { + "ExpectedResult" => "ServerFail", + "ExpectedServerAlert" => "UnrecognizedName" + }, + }, ); + +our @tests_tls_1_1 = ( + { + name => "SNI-early-disable-v12", + server => { + extra => { + "ServerNameCallback" => "EarlyNoV12", + }, + }, + client => { + extra => { + "ServerName" => "server2", + }, + }, + test => { + "ExpectedProtocol" => "TLSv1.1", + "ExpectedServerName" => "server2", + }, + }, +); + +push @tests, @tests_tls_1_1 unless disabled("tls1_1"); diff --git a/test/ssl_test_ctx.c b/test/ssl_test_ctx.c index 66fb31ce5a..f9e74d11fd 100644 --- a/test/ssl_test_ctx.c +++ b/test/ssl_test_ctx.c @@ -237,6 +237,9 @@ static const test_enum ssl_servername_callbacks[] = { {"None", SSL_TEST_SERVERNAME_CB_NONE}, {"IgnoreMismatch", SSL_TEST_SERVERNAME_IGNORE_MISMATCH}, {"RejectMismatch", SSL_TEST_SERVERNAME_REJECT_MISMATCH}, + {"EarlyIgnoreMismatch", SSL_TEST_SERVERNAME_EARLY_IGNORE_MISMATCH}, + {"EarlyRejectMismatch", SSL_TEST_SERVERNAME_EARLY_REJECT_MISMATCH}, + {"EarlyNoV12", SSL_TEST_SERVERNAME_EARLY_NO_V12}, }; __owur static int parse_servername_callback(SSL_TEST_SERVER_CONF *server_conf, diff --git a/test/ssl_test_ctx.h b/test/ssl_test_ctx.h index 1c66740fb7..499e314e3c 100644 --- a/test/ssl_test_ctx.h +++ b/test/ssl_test_ctx.h @@ -38,7 +38,10 @@ typedef enum { typedef enum { SSL_TEST_SERVERNAME_CB_NONE = 0, /* Default */ SSL_TEST_SERVERNAME_IGNORE_MISMATCH, - SSL_TEST_SERVERNAME_REJECT_MISMATCH + SSL_TEST_SERVERNAME_REJECT_MISMATCH, + SSL_TEST_SERVERNAME_EARLY_IGNORE_MISMATCH, + SSL_TEST_SERVERNAME_EARLY_REJECT_MISMATCH, + SSL_TEST_SERVERNAME_EARLY_NO_V12 } ssl_servername_callback_t; typedef enum { |