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_1-pre1~2383 X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=commitdiff_plain;h=cc22cd546bd0b0e1b55c1835403ab564d5f30581 Provide a test for the Encrypt-Then-Mac renegotiation crash In 1.1.0 changing the ciphersuite during a renegotiation can result in a crash leading to a DoS attack. In master this does not occur with TLS (instead you get an internal error, which is still wrong but not a security issue) - but the problem still exists in the DTLS code. 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 a7898991e0..2b869a4247 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 58992c0409..8376eeaf89 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] @@ -182,3 +186,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 3f76cb8860..77264c486b 100644 --- a/test/ssl-tests/17-renegotiate.conf.in +++ b/test/ssl-tests/17-renegotiate.conf.in @@ -108,5 +108,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 e88e577eab..1f3495fa5c 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.3", TLS1_3_VERSION}, @@ -172,9 +166,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}, @@ -200,9 +192,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}, @@ -241,9 +231,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}, @@ -269,9 +257,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}, @@ -297,9 +283,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}, @@ -322,9 +306,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) @@ -333,9 +315,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}, @@ -361,9 +341,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}, @@ -392,9 +374,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}, @@ -420,21 +400,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) -/*************************************/ -/* Expected key and signature types */ -/*************************************/ + +/* Expected key and signature types */ __owur static int parse_expected_key_type(int *ptype, const char *value) { @@ -494,9 +470,8 @@ __owur static int parse_expected_client_sign_type(SSL_TEST_CTX *test_ctx, value); } -/*************************/ + /* Expected signing hash */ -/*************************/ __owur static int parse_expected_sign_hash(int *ptype, const char *value) { @@ -527,9 +502,8 @@ __owur static int parse_expected_client_sign_hash(SSL_TEST_CTX *test_ctx, value); } -/*************************************************************/ + /* Known test options and their corresponding parse methods. */ -/*************************************************************/ /* Top-level options. */ typedef struct { @@ -572,6 +546,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 13652b0528..6036a02bc9 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 {