Prevent both early data and custom extensions from being accepted.

This loosens the earlier restriction to match Channel ID. Both may be
configured and offered, but the server is obligated to select only one
of them. This aligns with the current tokbind + 0-RTT draft where the
combination is signaled by a separate extension.

Bug: 183
Change-Id: I786102a679999705d399f0091f76da236be091c2
Reviewed-on: https://boringssl-review.googlesource.com/19124
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
This commit is contained in:
Steven Valdez 2017-08-10 14:02:56 -04:00
parent 78f5e75739
commit f4ecc84644
9 changed files with 126 additions and 30 deletions

View File

@ -34,7 +34,6 @@ SSL,125,CERTIFICATE_VERIFY_FAILED
SSL,126,CERT_CB_ERROR
SSL,127,CERT_LENGTH_MISMATCH
SSL,128,CHANNEL_ID_NOT_P256
SSL,279,CHANNEL_ID_ON_EARLY_DATA
SSL,129,CHANNEL_ID_SIGNATURE_INVALID
SSL,130,CIPHER_OR_HASH_UNAVAILABLE
SSL,131,CLIENTHELLO_PARSE_FAILED
@ -183,6 +182,7 @@ SSL,1117,TOO_MUCH_READ_EARLY_DATA
SSL,270,TOO_MUCH_SKIPPED_EARLY_DATA
SSL,221,UNABLE_TO_FIND_ECDH_PARAMETERS
SSL,222,UNEXPECTED_EXTENSION
SSL,279,UNEXPECTED_EXTENSION_ON_EARLY_DATA
SSL,223,UNEXPECTED_MESSAGE
SSL,224,UNEXPECTED_OPERATOR_IN_GROUP
SSL,225,UNEXPECTED_RECORD

View File

@ -4878,7 +4878,7 @@ OPENSSL_EXPORT bool SealRecord(SSL *ssl, Span<uint8_t> out_prefix,
#define SSL_R_TICKET_ENCRYPTION_FAILED 276
#define SSL_R_ALPN_MISMATCH_ON_EARLY_DATA 277
#define SSL_R_WRONG_VERSION_ON_EARLY_DATA 278
#define SSL_R_CHANNEL_ID_ON_EARLY_DATA 279
#define SSL_R_UNEXPECTED_EXTENSION_ON_EARLY_DATA 279
#define SSL_R_NO_SUPPORTED_VERSIONS_ENABLED 280
#define SSL_R_APPLICATION_DATA_INSTEAD_OF_HANDSHAKE 281
#define SSL_R_SSLV3_ALERT_CLOSE_NOTIFY 1000

View File

@ -71,14 +71,6 @@ static int custom_ext_add_hello(SSL_HANDSHAKE *hs, CBB *extensions) {
return 1;
}
if (ssl->cert->enable_early_data) {
/* TODO(svaldez): Support Custom Extensions with 0-RTT. For now the caller
* is expected not to configure both together.
* https://crbug.com/boringssl/173. */
OPENSSL_PUT_ERROR(SSL, SSL_R_CUSTOM_EXTENSION_ERROR);
return 0;
}
for (size_t i = 0; i < sk_SSL_CUSTOM_EXTENSION_num(stack); i++) {
const SSL_CUSTOM_EXTENSION *ext = sk_SSL_CUSTOM_EXTENSION_value(stack, i);

View File

@ -1249,6 +1249,8 @@ struct SSL_HANDSHAKE {
unsigned received_hello_retry_request:1;
unsigned received_custom_extension:1;
/* accept_psk_mode stores whether the client's PSK mode is compatible with our
* preferences. */
unsigned accept_psk_mode:1;

View File

@ -137,6 +137,7 @@ SSL_HANDSHAKE::SSL_HANDSHAKE(SSL *ssl_arg)
scts_requested(0),
needs_psk_binder(0),
received_hello_retry_request(0),
received_custom_extension(0),
accept_psk_mode(0),
cert_request(0),
certificate_status_expected(0),

View File

@ -2795,7 +2795,6 @@ static int ssl_scan_clienthello_tlsext(SSL_HANDSHAKE *hs,
hs->extensions.received = 0;
hs->custom_extensions.received = 0;
CBS extensions;
CBS_init(&extensions, client_hello->extensions, client_hello->extensions_len);
while (CBS_len(&extensions) != 0) {
@ -2919,6 +2918,7 @@ static int ssl_scan_serverhello_tlsext(SSL_HANDSHAKE *hs, CBS *cbs,
tls_extension_find(&ext_index, type);
if (ext == NULL) {
hs->received_custom_extension = 1;
if (!custom_ext_parse_serverhello(hs, out_alert, type, &extension)) {
return 0;
}

View File

@ -8980,22 +8980,6 @@ func addCustomExtensionTests() {
flags: []string{flag},
})
// 0-RTT is not currently supported with Custom Extensions.
testCases = append(testCases, testCase{
testType: testType,
name: "CustomExtensions-" + suffix + "-EarlyData",
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
CustomExtension: expectedContents,
ExpectedCustomExtension: &expectedContents,
},
},
shouldFail: true,
expectedError: ":CUSTOM_EXTENSION_ERROR:",
flags: []string{flag, "-enable-early-data"},
})
// If the parse callback fails, the handshake should also fail.
testCases = append(testCases, testCase{
testType: testType,
@ -9090,6 +9074,121 @@ func addCustomExtensionTests() {
})
}
// If the client sends both early data and custom extension, the handshake
// should succeed as long as both the extensions aren't returned by the
// server.
testCases = append(testCases, testCase{
testType: clientTest,
name: "CustomExtensions-Client-EarlyData-None",
config: Config{
MaxVersion: VersionTLS13,
MaxEarlyDataSize: 16384,
Bugs: ProtocolBugs{
ExpectedCustomExtension: &expectedContents,
AlwaysRejectEarlyData: true,
},
},
resumeSession: true,
flags: []string{
"-enable-client-custom-extension",
"-enable-early-data",
"-expect-early-data-info",
"-expect-reject-early-data",
},
})
testCases = append(testCases, testCase{
testType: clientTest,
name: "CustomExtensions-Client-EarlyData-EarlyDataAccepted",
config: Config{
MaxVersion: VersionTLS13,
MaxEarlyDataSize: 16384,
Bugs: ProtocolBugs{
ExpectedCustomExtension: &expectedContents,
},
},
resumeSession: true,
flags: []string{
"-enable-client-custom-extension",
"-enable-early-data",
"-expect-early-data-info",
"-expect-accept-early-data",
},
})
testCases = append(testCases, testCase{
testType: clientTest,
name: "CustomExtensions-Client-EarlyData-CustomExtensionAccepted",
config: Config{
MaxVersion: VersionTLS13,
MaxEarlyDataSize: 16384,
Bugs: ProtocolBugs{
AlwaysRejectEarlyData: true,
CustomExtension: expectedContents,
ExpectedCustomExtension: &expectedContents,
},
},
resumeSession: true,
flags: []string{
"-enable-client-custom-extension",
"-enable-early-data",
"-expect-early-data-info",
"-expect-reject-early-data",
},
})
testCases = append(testCases, testCase{
testType: clientTest,
name: "CustomExtensions-Client-EarlyDataAndCustomExtensions",
config: Config{
MaxVersion: VersionTLS13,
MaxEarlyDataSize: 16384,
Bugs: ProtocolBugs{
CustomExtension: expectedContents,
ExpectedCustomExtension: &expectedContents,
},
},
resumeConfig: &Config{
MaxVersion: VersionTLS13,
MaxEarlyDataSize: 16384,
Bugs: ProtocolBugs{
CustomExtension: expectedContents,
ExpectedCustomExtension: &expectedContents,
SendEarlyDataExtension: true,
},
},
resumeSession: true,
shouldFail: true,
expectedError: ":UNEXPECTED_EXTENSION_ON_EARLY_DATA:",
flags: []string{
"-enable-client-custom-extension",
"-enable-early-data",
"-expect-early-data-info",
},
})
// If the server receives both early data and custom extension, only the
// custom extension should be accepted.
testCases = append(testCases, testCase{
testType: serverTest,
name: "CustomExtensions-Server-EarlyDataAccepted",
config: Config{
MaxVersion: VersionTLS13,
MaxEarlyDataSize: 16384,
Bugs: ProtocolBugs{
CustomExtension: expectedContents,
ExpectedCustomExtension: &expectedContents,
ExpectEarlyDataAccepted: false,
},
},
resumeSession: true,
flags: []string{
"-enable-server-custom-extension",
"-enable-early-data",
"-expect-early-data-info",
},
})
// The custom extension add callback should not be called if the client
// doesn't send the extension.
testCases = append(testCases, testCase{
@ -11661,7 +11760,7 @@ func addTLS13HandshakeTests() {
resumeSession: true,
expectChannelID: true,
shouldFail: true,
expectedError: ":CHANNEL_ID_ON_EARLY_DATA:",
expectedError: ":UNEXPECTED_EXTENSION_ON_EARLY_DATA:",
flags: []string{
"-enable-early-data",
"-expect-early-data-info",

View File

@ -417,8 +417,8 @@ static enum ssl_hs_wait_t do_read_encrypted_extensions(SSL_HANDSHAKE *hs) {
OPENSSL_PUT_ERROR(SSL, SSL_R_ALPN_MISMATCH_ON_EARLY_DATA);
return ssl_hs_error;
}
if (ssl->s3->tlsext_channel_id_valid) {
OPENSSL_PUT_ERROR(SSL, SSL_R_CHANNEL_ID_ON_EARLY_DATA);
if (ssl->s3->tlsext_channel_id_valid || hs->received_custom_extension) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION_ON_EARLY_DATA);
return ssl_hs_error;
}
}

View File

@ -380,6 +380,8 @@ static enum ssl_hs_wait_t do_select_session(SSL_HANDSHAKE *hs) {
hs->early_data_offered &&
/* Channel ID is incompatible with 0-RTT. */
!ssl->s3->tlsext_channel_id_valid &&
/* Custom extensions is incompatible with 0-RTT. */
hs->custom_extensions.received == 0 &&
/* The negotiated ALPN must match the one in the ticket. */
ssl->s3->alpn_selected_len == session->early_alpn_len &&
OPENSSL_memcmp(ssl->s3->alpn_selected, session->early_alpn,