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>
diff --git a/crypto/err/ssl.errordata b/crypto/err/ssl.errordata
index 7949cc7..a528874 100644
--- a/crypto/err/ssl.errordata
+++ b/crypto/err/ssl.errordata
@@ -34,7 +34,6 @@
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,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
diff --git a/include/openssl/ssl.h b/include/openssl/ssl.h
index 63651b5..9a414ca 100644
--- a/include/openssl/ssl.h
+++ b/include/openssl/ssl.h
@@ -4878,7 +4878,7 @@
#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
diff --git a/ssl/custom_extensions.cc b/ssl/custom_extensions.cc
index d86bd48..dff7041 100644
--- a/ssl/custom_extensions.cc
+++ b/ssl/custom_extensions.cc
@@ -71,14 +71,6 @@
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);
diff --git a/ssl/internal.h b/ssl/internal.h
index 931ac82..534a1ce 100644
--- a/ssl/internal.h
+++ b/ssl/internal.h
@@ -1249,6 +1249,8 @@
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;
diff --git a/ssl/s3_both.cc b/ssl/s3_both.cc
index 9c4aa7f..80e6f7b 100644
--- a/ssl/s3_both.cc
+++ b/ssl/s3_both.cc
@@ -137,6 +137,7 @@
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),
diff --git a/ssl/t1_lib.cc b/ssl/t1_lib.cc
index 39f4be6..1dd834b 100644
--- a/ssl/t1_lib.cc
+++ b/ssl/t1_lib.cc
@@ -2795,7 +2795,6 @@
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 @@
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;
}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 7e64fe5..2ae697c 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -8980,22 +8980,6 @@
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 @@
})
}
+ // 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 @@
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",
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc
index 83066be..98e70a7 100644
--- a/ssl/tls13_client.cc
+++ b/ssl/tls13_client.cc
@@ -417,8 +417,8 @@
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;
}
}
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc
index 2b802c4..a3ed8a7 100644
--- a/ssl/tls13_server.cc
+++ b/ssl/tls13_server.cc
@@ -380,6 +380,8 @@
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,