BUG=chromium:659593 Change-Id: I73a4751609b85df7cd40f0f60dc3f3046a490940 Reviewed-on: https://boringssl-review.googlesource.com/11861 Reviewed-by: David Benjamin <davidben@google.com> Commit-Queue: David Benjamin <davidben@google.com> CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>kris/onging/CECPQ3_patch15
@@ -771,7 +771,10 @@ static int ssl3_get_client_hello(SSL *ssl) { | |||||
ssl->version == session->ssl_version && | ssl->version == session->ssl_version && | ||||
/* If the client offers the EMS extension, but the previous session | /* If the client offers the EMS extension, but the previous session | ||||
* didn't use it, then negotiate a new session. */ | * didn't use it, then negotiate a new session. */ | ||||
have_extended_master_secret == session->extended_master_secret; | |||||
have_extended_master_secret == session->extended_master_secret && | |||||
/* Only resume if the session's cipher is still valid under the | |||||
* current configuration. */ | |||||
ssl_is_valid_cipher(ssl, session->cipher); | |||||
} | } | ||||
if (has_session) { | if (has_session) { | ||||
@@ -1695,6 +1695,11 @@ int ssl3_read_handshake_bytes(SSL *ssl, uint8_t *buf, int len); | |||||
int ssl3_write_app_data(SSL *ssl, const void *buf, int len); | int ssl3_write_app_data(SSL *ssl, const void *buf, int len); | ||||
int ssl3_write_bytes(SSL *ssl, int type, const void *buf, int len); | int ssl3_write_bytes(SSL *ssl, int type, const void *buf, int len); | ||||
int ssl3_output_cert_chain(SSL *ssl); | int ssl3_output_cert_chain(SSL *ssl); | ||||
/* ssl_is_valid_cipher checks that |cipher| is valid according to the current | |||||
* server configuration in |ssl|. It returns 1 if valid, and 0 otherwise. */ | |||||
int ssl_is_valid_cipher(SSL *ssl, const SSL_CIPHER *cipher); | |||||
const SSL_CIPHER *ssl3_choose_cipher( | const SSL_CIPHER *ssl3_choose_cipher( | ||||
SSL *ssl, const struct ssl_early_callback_ctx *client_hello, | SSL *ssl, const struct ssl_early_callback_ctx *client_hello, | ||||
const struct ssl_cipher_preference_list_st *srvr); | const struct ssl_cipher_preference_list_st *srvr); | ||||
@@ -240,6 +240,17 @@ struct ssl_cipher_preference_list_st *ssl_get_cipher_preferences(SSL *ssl) { | |||||
return NULL; | return NULL; | ||||
} | } | ||||
int ssl_is_valid_cipher(SSL *ssl, const SSL_CIPHER *cipher) { | |||||
/* Check the TLS version. */ | |||||
if (SSL_CIPHER_get_min_version(cipher) > ssl3_protocol_version(ssl) || | |||||
SSL_CIPHER_get_max_version(cipher) < ssl3_protocol_version(ssl)) { | |||||
return 0; | |||||
} | |||||
return sk_SSL_CIPHER_find(ssl_get_cipher_preferences(ssl)->ciphers, | |||||
NULL, cipher); | |||||
} | |||||
const SSL_CIPHER *ssl3_choose_cipher( | const SSL_CIPHER *ssl3_choose_cipher( | ||||
SSL *ssl, const struct ssl_early_callback_ctx *client_hello, | SSL *ssl, const struct ssl_early_callback_ctx *client_hello, | ||||
const struct ssl_cipher_preference_list_st *server_pref) { | const struct ssl_cipher_preference_list_st *server_pref) { | ||||
@@ -1456,6 +1456,11 @@ static bool DoExchange(bssl::UniquePtr<SSL_SESSION> *out_session, | |||||
if (config->max_cert_list > 0) { | if (config->max_cert_list > 0) { | ||||
SSL_set_max_cert_list(ssl.get(), config->max_cert_list); | SSL_set_max_cert_list(ssl.get(), config->max_cert_list); | ||||
} | } | ||||
if (is_resume && | |||||
!config->resume_cipher.empty() && | |||||
!SSL_set_cipher_list(ssl.get(), config->resume_cipher.c_str())) { | |||||
return false; | |||||
} | |||||
int sock = Connect(config->port); | int sock = Connect(config->port); | ||||
if (sock == -1) { | if (sock == -1) { | ||||
@@ -5367,6 +5367,31 @@ func addResumptionVersionTests() { | |||||
} | } | ||||
} | } | ||||
// Sessions with disabled ciphers are not resumed. | |||||
testCases = append(testCases, testCase{ | |||||
testType: serverTest, | |||||
name: "Resume-Server-CipherMismatch", | |||||
resumeSession: true, | |||||
config: Config{ | |||||
MaxVersion: VersionTLS12, | |||||
}, | |||||
flags: []string{"-cipher", "AES128", "-resume-cipher", "AES256"}, | |||||
shouldFail: false, | |||||
expectResumeRejected: true, | |||||
}) | |||||
testCases = append(testCases, testCase{ | |||||
testType: serverTest, | |||||
name: "Resume-Server-CipherMismatch-TLS13", | |||||
resumeSession: true, | |||||
config: Config{ | |||||
MaxVersion: VersionTLS13, | |||||
}, | |||||
flags: []string{"-cipher", "AES128", "-resume-cipher", "AES256"}, | |||||
shouldFail: false, | |||||
expectResumeRejected: true, | |||||
}) | |||||
testCases = append(testCases, testCase{ | testCases = append(testCases, testCase{ | ||||
name: "Resume-Client-CipherMismatch", | name: "Resume-Client-CipherMismatch", | ||||
resumeSession: true, | resumeSession: true, | ||||
@@ -128,6 +128,7 @@ const Flag<std::string> kStringFlags[] = { | |||||
{ "-cipher", &TestConfig::cipher }, | { "-cipher", &TestConfig::cipher }, | ||||
{ "-cipher-tls10", &TestConfig::cipher_tls10 }, | { "-cipher-tls10", &TestConfig::cipher_tls10 }, | ||||
{ "-cipher-tls11", &TestConfig::cipher_tls11 }, | { "-cipher-tls11", &TestConfig::cipher_tls11 }, | ||||
{ "-resume-cipher", &TestConfig::resume_cipher }, | |||||
{ "-export-label", &TestConfig::export_label }, | { "-export-label", &TestConfig::export_label }, | ||||
{ "-export-context", &TestConfig::export_context }, | { "-export-context", &TestConfig::export_context }, | ||||
}; | }; | ||||
@@ -76,6 +76,7 @@ struct TestConfig { | |||||
std::string cipher; | std::string cipher; | ||||
std::string cipher_tls10; | std::string cipher_tls10; | ||||
std::string cipher_tls11; | std::string cipher_tls11; | ||||
std::string resume_cipher; | |||||
bool handshake_never_done = false; | bool handshake_never_done = false; | ||||
int export_keying_material = 0; | int export_keying_material = 0; | ||||
std::string export_label; | std::string export_label; | ||||
@@ -123,7 +123,8 @@ static enum ssl_hs_wait_t do_process_client_hello(SSL *ssl, SSL_HANDSHAKE *hs) { | |||||
/* Only resume if the session's version matches. */ | /* Only resume if the session's version matches. */ | ||||
(session->ssl_version != ssl->version || | (session->ssl_version != ssl->version || | ||||
!ssl_client_cipher_list_contains_cipher( | !ssl_client_cipher_list_contains_cipher( | ||||
&client_hello, (uint16_t)SSL_CIPHER_get_id(session->cipher)))) { | |||||
&client_hello, (uint16_t)SSL_CIPHER_get_id(session->cipher)) || | |||||
!ssl_is_valid_cipher(ssl, session->cipher))) { | |||||
SSL_SESSION_free(session); | SSL_SESSION_free(session); | ||||
session = NULL; | session = NULL; | ||||
} | } | ||||