From: Matt Caswell Date: Fri, 3 Feb 2017 11:21:07 +0000 (+0000) Subject: Provide a test for the Encrypt-Then-Mac renegotiation crash X-Git-Tag: OpenSSL_1_1_0e~4 X-Git-Url: https://git.librecmc.org/?a=commitdiff_plain;h=9c5a691d578a4debfd6ecacc030a85900906bf0d;p=oweals%2Fopenssl.git Provide a test for the Encrypt-Then-Mac renegotiation crash Changing the ciphersuite during a renegotiation can result in a crash leading to a DoS attack. ETM has not been implemented in 1.1.0 for DTLS so this is TLS only. This commit provides a test for the issue. CVE-2017-3733 Reviewed-by: Richard Levitte --- diff --git a/test/handshake_helper.c b/test/handshake_helper.c index 0a421b1597..7ef015f8a4 100644 --- a/test/handshake_helper.c +++ b/test/handshake_helper.c @@ -607,10 +607,20 @@ static void do_reneg_setup_step(const SSL_TEST_CTX *test_ctx, PEER *peer) * session. The server may or may not resume dependant on the * setting of SSL_OP_NO_SESSION_RESUMPTION_ON_RENEGOTIATION */ - if (SSL_is_server(peer->ssl)) + if (SSL_is_server(peer->ssl)) { ret = SSL_renegotiate(peer->ssl); - else - ret = SSL_renegotiate_abbreviated(peer->ssl); + } else { + if (test_ctx->extra.client.reneg_ciphers != NULL) { + if (!SSL_set_cipher_list(peer->ssl, + test_ctx->extra.client.reneg_ciphers)) { + peer->status = PEER_ERROR; + return; + } + ret = SSL_renegotiate(peer->ssl); + } else { + ret = SSL_renegotiate_abbreviated(peer->ssl); + } + } if (!ret) { peer->status = PEER_ERROR; return; diff --git a/test/ssl-tests/17-renegotiate.conf b/test/ssl-tests/17-renegotiate.conf index fb9f97ba19..9ea1d8c7c8 100644 --- a/test/ssl-tests/17-renegotiate.conf +++ b/test/ssl-tests/17-renegotiate.conf @@ -1,6 +1,6 @@ # Generated with generate_ssl_tests.pl -num_tests = 6 +num_tests = 10 test-0 = 0-renegotiate-client-no-resume test-1 = 1-renegotiate-client-resume @@ -8,6 +8,10 @@ test-2 = 2-renegotiate-server-no-resume test-3 = 3-renegotiate-server-resume test-4 = 4-renegotiate-client-auth-require test-5 = 5-renegotiate-client-auth-once +test-6 = 6-renegotiate-aead-to-non-aead +test-7 = 7-renegotiate-non-aead-to-aead +test-8 = 8-renegotiate-non-aead-to-non-aead +test-9 = 9-renegotiate-aead-to-aead # =========================================================== [0-renegotiate-client-no-resume] @@ -178,3 +182,131 @@ Method = TLS ResumptionExpected = No +# =========================================================== + +[6-renegotiate-aead-to-non-aead] +ssl_conf = 6-renegotiate-aead-to-non-aead-ssl + +[6-renegotiate-aead-to-non-aead-ssl] +server = 6-renegotiate-aead-to-non-aead-server +client = 6-renegotiate-aead-to-non-aead-client + +[6-renegotiate-aead-to-non-aead-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +MaxProtocol = TLSv1.2 +Options = NoResumptionOnRenegotiation +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[6-renegotiate-aead-to-non-aead-client] +CipherString = AES128-GCM-SHA256 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-6] +ExpectedResult = Success +HandshakeMode = RenegotiateClient +Method = TLS +ResumptionExpected = No +client = 6-renegotiate-aead-to-non-aead-client-extra + +[6-renegotiate-aead-to-non-aead-client-extra] +RenegotiateCiphers = AES128-SHA + + +# =========================================================== + +[7-renegotiate-non-aead-to-aead] +ssl_conf = 7-renegotiate-non-aead-to-aead-ssl + +[7-renegotiate-non-aead-to-aead-ssl] +server = 7-renegotiate-non-aead-to-aead-server +client = 7-renegotiate-non-aead-to-aead-client + +[7-renegotiate-non-aead-to-aead-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +MaxProtocol = TLSv1.2 +Options = NoResumptionOnRenegotiation +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[7-renegotiate-non-aead-to-aead-client] +CipherString = AES128-SHA +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-7] +ExpectedResult = Success +HandshakeMode = RenegotiateClient +Method = TLS +ResumptionExpected = No +client = 7-renegotiate-non-aead-to-aead-client-extra + +[7-renegotiate-non-aead-to-aead-client-extra] +RenegotiateCiphers = AES128-GCM-SHA256 + + +# =========================================================== + +[8-renegotiate-non-aead-to-non-aead] +ssl_conf = 8-renegotiate-non-aead-to-non-aead-ssl + +[8-renegotiate-non-aead-to-non-aead-ssl] +server = 8-renegotiate-non-aead-to-non-aead-server +client = 8-renegotiate-non-aead-to-non-aead-client + +[8-renegotiate-non-aead-to-non-aead-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +MaxProtocol = TLSv1.2 +Options = NoResumptionOnRenegotiation +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[8-renegotiate-non-aead-to-non-aead-client] +CipherString = AES128-SHA +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-8] +ExpectedResult = Success +HandshakeMode = RenegotiateClient +Method = TLS +ResumptionExpected = No +client = 8-renegotiate-non-aead-to-non-aead-client-extra + +[8-renegotiate-non-aead-to-non-aead-client-extra] +RenegotiateCiphers = AES256-SHA + + +# =========================================================== + +[9-renegotiate-aead-to-aead] +ssl_conf = 9-renegotiate-aead-to-aead-ssl + +[9-renegotiate-aead-to-aead-ssl] +server = 9-renegotiate-aead-to-aead-server +client = 9-renegotiate-aead-to-aead-client + +[9-renegotiate-aead-to-aead-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +MaxProtocol = TLSv1.2 +Options = NoResumptionOnRenegotiation +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[9-renegotiate-aead-to-aead-client] +CipherString = AES128-GCM-SHA256 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-9] +ExpectedResult = Success +HandshakeMode = RenegotiateClient +Method = TLS +ResumptionExpected = No +client = 9-renegotiate-aead-to-aead-client-extra + +[9-renegotiate-aead-to-aead-client-extra] +RenegotiateCiphers = AES256-GCM-SHA384 + + diff --git a/test/ssl-tests/17-renegotiate.conf.in b/test/ssl-tests/17-renegotiate.conf.in index 104b1fe89c..fde57bc083 100644 --- a/test/ssl-tests/17-renegotiate.conf.in +++ b/test/ssl-tests/17-renegotiate.conf.in @@ -102,5 +102,81 @@ our @tests = ( "ResumptionExpected" => "No", "ExpectedResult" => "Success" } - } + }, + { + name => "renegotiate-aead-to-non-aead", + server => { + "Options" => "NoResumptionOnRenegotiation", + "MaxProtocol" => "TLSv1.2" + }, + client => { + "CipherString" => "AES128-GCM-SHA256", + extra => { + "RenegotiateCiphers" => "AES128-SHA" + } + }, + test => { + "Method" => "TLS", + "HandshakeMode" => "RenegotiateClient", + "ResumptionExpected" => "No", + "ExpectedResult" => "Success" + } + }, + { + name => "renegotiate-non-aead-to-aead", + server => { + "Options" => "NoResumptionOnRenegotiation", + "MaxProtocol" => "TLSv1.2" + }, + client => { + "CipherString" => "AES128-SHA", + extra => { + "RenegotiateCiphers" => "AES128-GCM-SHA256" + } + }, + test => { + "Method" => "TLS", + "HandshakeMode" => "RenegotiateClient", + "ResumptionExpected" => "No", + "ExpectedResult" => "Success" + } + }, + { + name => "renegotiate-non-aead-to-non-aead", + server => { + "Options" => "NoResumptionOnRenegotiation", + "MaxProtocol" => "TLSv1.2" + }, + client => { + "CipherString" => "AES128-SHA", + extra => { + "RenegotiateCiphers" => "AES256-SHA" + } + }, + test => { + "Method" => "TLS", + "HandshakeMode" => "RenegotiateClient", + "ResumptionExpected" => "No", + "ExpectedResult" => "Success" + } + }, + { + name => "renegotiate-aead-to-aead", + server => { + "Options" => "NoResumptionOnRenegotiation", + "MaxProtocol" => "TLSv1.2" + }, + client => { + "CipherString" => "AES128-GCM-SHA256", + extra => { + "RenegotiateCiphers" => "AES256-GCM-SHA384" + } + }, + test => { + "Method" => "TLS", + "HandshakeMode" => "RenegotiateClient", + "ResumptionExpected" => "No", + "ExpectedResult" => "Success" + } + }, ); diff --git a/test/ssl-tests/18-dtls-renegotiate.conf b/test/ssl-tests/18-dtls-renegotiate.conf index fbde68a5b3..3d8ebd74c4 100644 --- a/test/ssl-tests/18-dtls-renegotiate.conf +++ b/test/ssl-tests/18-dtls-renegotiate.conf @@ -1,12 +1,16 @@ # Generated with generate_ssl_tests.pl -num_tests = 5 +num_tests = 9 test-0 = 0-renegotiate-client-no-resume test-1 = 1-renegotiate-client-resume test-2 = 2-renegotiate-server-resume test-3 = 3-renegotiate-client-auth-require test-4 = 4-renegotiate-client-auth-once +test-5 = 5-renegotiate-aead-to-non-aead +test-6 = 6-renegotiate-non-aead-to-aead +test-7 = 7-renegotiate-non-aead-to-non-aead +test-8 = 8-renegotiate-aead-to-aead # =========================================================== [0-renegotiate-client-no-resume] @@ -146,3 +150,127 @@ Method = DTLS ResumptionExpected = No +# =========================================================== + +[5-renegotiate-aead-to-non-aead] +ssl_conf = 5-renegotiate-aead-to-non-aead-ssl + +[5-renegotiate-aead-to-non-aead-ssl] +server = 5-renegotiate-aead-to-non-aead-server +client = 5-renegotiate-aead-to-non-aead-client + +[5-renegotiate-aead-to-non-aead-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +Options = NoResumptionOnRenegotiation +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[5-renegotiate-aead-to-non-aead-client] +CipherString = AES128-GCM-SHA256 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-5] +ExpectedResult = Success +HandshakeMode = RenegotiateClient +Method = DTLS +ResumptionExpected = No +client = 5-renegotiate-aead-to-non-aead-client-extra + +[5-renegotiate-aead-to-non-aead-client-extra] +RenegotiateCiphers = AES128-SHA + + +# =========================================================== + +[6-renegotiate-non-aead-to-aead] +ssl_conf = 6-renegotiate-non-aead-to-aead-ssl + +[6-renegotiate-non-aead-to-aead-ssl] +server = 6-renegotiate-non-aead-to-aead-server +client = 6-renegotiate-non-aead-to-aead-client + +[6-renegotiate-non-aead-to-aead-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +Options = NoResumptionOnRenegotiation +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[6-renegotiate-non-aead-to-aead-client] +CipherString = AES128-SHA +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-6] +ExpectedResult = Success +HandshakeMode = RenegotiateClient +Method = DTLS +ResumptionExpected = No +client = 6-renegotiate-non-aead-to-aead-client-extra + +[6-renegotiate-non-aead-to-aead-client-extra] +RenegotiateCiphers = AES128-GCM-SHA256 + + +# =========================================================== + +[7-renegotiate-non-aead-to-non-aead] +ssl_conf = 7-renegotiate-non-aead-to-non-aead-ssl + +[7-renegotiate-non-aead-to-non-aead-ssl] +server = 7-renegotiate-non-aead-to-non-aead-server +client = 7-renegotiate-non-aead-to-non-aead-client + +[7-renegotiate-non-aead-to-non-aead-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +Options = NoResumptionOnRenegotiation +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[7-renegotiate-non-aead-to-non-aead-client] +CipherString = AES128-SHA +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-7] +ExpectedResult = Success +HandshakeMode = RenegotiateClient +Method = DTLS +ResumptionExpected = No +client = 7-renegotiate-non-aead-to-non-aead-client-extra + +[7-renegotiate-non-aead-to-non-aead-client-extra] +RenegotiateCiphers = AES256-SHA + + +# =========================================================== + +[8-renegotiate-aead-to-aead] +ssl_conf = 8-renegotiate-aead-to-aead-ssl + +[8-renegotiate-aead-to-aead-ssl] +server = 8-renegotiate-aead-to-aead-server +client = 8-renegotiate-aead-to-aead-client + +[8-renegotiate-aead-to-aead-server] +Certificate = ${ENV::TEST_CERTS_DIR}/servercert.pem +CipherString = DEFAULT +Options = NoResumptionOnRenegotiation +PrivateKey = ${ENV::TEST_CERTS_DIR}/serverkey.pem + +[8-renegotiate-aead-to-aead-client] +CipherString = AES128-GCM-SHA256 +VerifyCAFile = ${ENV::TEST_CERTS_DIR}/rootcert.pem +VerifyMode = Peer + +[test-8] +ExpectedResult = Success +HandshakeMode = RenegotiateClient +Method = DTLS +ResumptionExpected = No +client = 8-renegotiate-aead-to-aead-client-extra + +[8-renegotiate-aead-to-aead-client-extra] +RenegotiateCiphers = AES256-GCM-SHA384 + + diff --git a/test/ssl-tests/18-dtls-renegotiate.conf.in b/test/ssl-tests/18-dtls-renegotiate.conf.in index 3f877f6b0d..43046e3a02 100644 --- a/test/ssl-tests/18-dtls-renegotiate.conf.in +++ b/test/ssl-tests/18-dtls-renegotiate.conf.in @@ -94,5 +94,77 @@ our @tests = ( "ResumptionExpected" => "No", "ExpectedResult" => "Success" } - } + }, + { + name => "renegotiate-aead-to-non-aead", + server => { + "Options" => "NoResumptionOnRenegotiation" + }, + client => { + "CipherString" => "AES128-GCM-SHA256", + extra => { + "RenegotiateCiphers" => "AES128-SHA" + } + }, + test => { + "Method" => "DTLS", + "HandshakeMode" => "RenegotiateClient", + "ResumptionExpected" => "No", + "ExpectedResult" => "Success" + } + }, + { + name => "renegotiate-non-aead-to-aead", + server => { + "Options" => "NoResumptionOnRenegotiation" + }, + client => { + "CipherString" => "AES128-SHA", + extra => { + "RenegotiateCiphers" => "AES128-GCM-SHA256" + } + }, + test => { + "Method" => "DTLS", + "HandshakeMode" => "RenegotiateClient", + "ResumptionExpected" => "No", + "ExpectedResult" => "Success" + } + }, + { + name => "renegotiate-non-aead-to-non-aead", + server => { + "Options" => "NoResumptionOnRenegotiation" + }, + client => { + "CipherString" => "AES128-SHA", + extra => { + "RenegotiateCiphers" => "AES256-SHA" + } + }, + test => { + "Method" => "DTLS", + "HandshakeMode" => "RenegotiateClient", + "ResumptionExpected" => "No", + "ExpectedResult" => "Success" + } + }, + { + name => "renegotiate-aead-to-aead", + server => { + "Options" => "NoResumptionOnRenegotiation" + }, + client => { + "CipherString" => "AES128-GCM-SHA256", + extra => { + "RenegotiateCiphers" => "AES256-GCM-SHA384" + } + }, + test => { + "Method" => "DTLS", + "HandshakeMode" => "RenegotiateClient", + "ResumptionExpected" => "No", + "ExpectedResult" => "Success" + } + }, ); diff --git a/test/ssl_test_ctx.c b/test/ssl_test_ctx.c index 09e7a89e9b..c21decf522 100644 --- a/test/ssl_test_ctx.c +++ b/test/ssl_test_ctx.c @@ -88,9 +88,7 @@ static const char *enum_name(const test_enum *enums, size_t num_enums, } -/*******************/ -/* ExpectedResult. */ -/*******************/ +/* ExpectedResult */ static const test_enum ssl_test_results[] = { {"Success", SSL_TEST_SUCCESS}, @@ -115,9 +113,7 @@ const char *ssl_test_result_name(ssl_test_result_t result) return enum_name(ssl_test_results, OSSL_NELEM(ssl_test_results), result); } -/**********************************************/ -/* ExpectedClientAlert / ExpectedServerAlert. */ -/**********************************************/ +/* ExpectedClientAlert / ExpectedServerAlert */ static const test_enum ssl_alerts[] = { {"UnknownCA", SSL_AD_UNKNOWN_CA}, @@ -147,9 +143,7 @@ const char *ssl_alert_name(int alert) return enum_name(ssl_alerts, OSSL_NELEM(ssl_alerts), alert); } -/********************/ /* ExpectedProtocol */ -/********************/ static const test_enum ssl_protocols[] = { {"TLSv1.2", TLS1_2_VERSION}, @@ -171,9 +165,7 @@ const char *ssl_protocol_name(int protocol) return enum_name(ssl_protocols, OSSL_NELEM(ssl_protocols), protocol); } -/***********************/ -/* VerifyCallback. */ -/***********************/ +/* VerifyCallback */ static const test_enum ssl_verify_callbacks[] = { {"None", SSL_TEST_VERIFY_NONE}, @@ -199,9 +191,7 @@ const char *ssl_verify_callback_name(ssl_verify_callback_t callback) callback); } -/**************/ /* ServerName */ -/**************/ static const test_enum ssl_servername[] = { {"None", SSL_TEST_SERVERNAME_NONE}, @@ -240,9 +230,7 @@ const char *ssl_servername_name(ssl_servername_t server) server); } -/**********************/ /* ServerNameCallback */ -/**********************/ static const test_enum ssl_servername_callbacks[] = { {"None", SSL_TEST_SERVERNAME_CB_NONE}, @@ -268,9 +256,7 @@ const char *ssl_servername_callback_name(ssl_servername_callback_t callback) OSSL_NELEM(ssl_servername_callbacks), callback); } -/*************************/ /* SessionTicketExpected */ -/*************************/ static const test_enum ssl_session_ticket[] = { {"Ignore", SSL_TEST_SESSION_TICKET_IGNORE}, @@ -296,9 +282,7 @@ const char *ssl_session_ticket_name(ssl_session_ticket_t server) server); } -/***********************/ -/* Method */ -/***********************/ +/* Method */ static const test_enum ssl_test_methods[] = { {"TLS", SSL_TEST_METHOD_TLS}, @@ -321,9 +305,7 @@ const char *ssl_test_method_name(ssl_test_method_t method) return enum_name(ssl_test_methods, OSSL_NELEM(ssl_test_methods), method); } -/************************************/ -/* NPN and ALPN options */ -/************************************/ +/* NPN and ALPN options */ IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_CLIENT_CONF, client, npn_protocols) IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_SERVER_CONF, server, npn_protocols) @@ -332,9 +314,7 @@ IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_CLIENT_CONF, client, alpn_protocols) IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_SERVER_CONF, server, alpn_protocols) IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_CTX, test, expected_alpn_protocol) -/***********************/ -/* Handshake mode */ -/***********************/ +/* Handshake mode */ static const test_enum ssl_handshake_modes[] = { {"Simple", SSL_TEST_HANDSHAKE_SIMPLE}, @@ -360,9 +340,11 @@ const char *ssl_handshake_mode_name(ssl_handshake_mode_t mode) mode); } -/***********************/ -/* CT Validation */ -/***********************/ +/* Renegotiation Ciphersuites */ + +IMPLEMENT_SSL_TEST_STRING_OPTION(SSL_TEST_CLIENT_CONF, client, reneg_ciphers) + +/* CT Validation */ static const test_enum ssl_ct_validation_modes[] = { {"None", SSL_TEST_CT_VALIDATION_NONE}, @@ -391,9 +373,7 @@ const char *ssl_ct_validation_name(ssl_ct_validation_t mode) IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_CTX, test, resumption_expected) IMPLEMENT_SSL_TEST_BOOL_OPTION(SSL_TEST_SERVER_CONF, server, broken_session_ticket) -/**************/ /* CertStatus */ -/**************/ static const test_enum ssl_certstatus[] = { {"None", SSL_TEST_CERT_STATUS_NONE}, @@ -419,21 +399,17 @@ const char *ssl_certstatus_name(ssl_cert_status_t cert_status) OSSL_NELEM(ssl_certstatus), cert_status); } -/***********************/ -/* ApplicationData */ -/***********************/ +/* ApplicationData */ IMPLEMENT_SSL_TEST_INT_OPTION(SSL_TEST_CTX, test, app_data_size) -/***********************/ -/* MaxFragmentSize */ -/***********************/ + +/* MaxFragmentSize */ IMPLEMENT_SSL_TEST_INT_OPTION(SSL_TEST_CTX, test, max_fragment_size) -/***********************/ -/* ExpectedTmpKeyType */ -/***********************/ + +/* ExpectedTmpKeyType */ __owur static int parse_expected_tmp_key_type(SSL_TEST_CTX *test_ctx, const char *value) @@ -455,9 +431,7 @@ __owur static int parse_expected_tmp_key_type(SSL_TEST_CTX *test_ctx, return 1; } -/*************************************************************/ /* Known test options and their corresponding parse methods. */ -/*************************************************************/ /* Top-level options. */ typedef struct { @@ -494,6 +468,7 @@ static const ssl_test_client_option ssl_test_client_options[] = { { "NPNProtocols", &parse_client_npn_protocols }, { "ALPNProtocols", &parse_client_alpn_protocols }, { "CTValidation", &parse_ct_validation }, + { "RenegotiateCiphers", &parse_client_reneg_ciphers}, }; /* Nested server options. */ diff --git a/test/ssl_test_ctx.h b/test/ssl_test_ctx.h index 995d518ed3..28a4566716 100644 --- a/test/ssl_test_ctx.h +++ b/test/ssl_test_ctx.h @@ -84,6 +84,8 @@ typedef struct { char *npn_protocols; char *alpn_protocols; ssl_ct_validation_t ct_validation; + /* Ciphersuites to set on a renegotiation */ + char *reneg_ciphers; } SSL_TEST_CLIENT_CONF; typedef struct {