Move the version to an extension in the experimental TLS 1.3 encoding.
Change-Id: I0726e11006235db9309a8370a11e00ede0216279
Reviewed-on: https://boringssl-review.googlesource.com/17704
Reviewed-by: David Benjamin <davidben@google.com>
diff --git a/ssl/handshake_client.c b/ssl/handshake_client.c
index 51f7cc8..0738e42 100644
--- a/ssl/handshake_client.c
+++ b/ssl/handshake_client.c
@@ -846,6 +846,47 @@
return -1;
}
+ /* Parse out server version from supported_versions if available. */
+ if (ssl->s3->tmp.message_type == SSL3_MT_SERVER_HELLO &&
+ server_version == TLS1_2_VERSION) {
+ CBS copy = server_hello;
+ CBS extensions;
+ uint8_t sid_length;
+ if (!CBS_skip(©, SSL3_RANDOM_SIZE) ||
+ !CBS_get_u8(©, &sid_length) ||
+ !CBS_skip(©, sid_length + 2 /* cipher_suite */ +
+ 1 /* compression_method */) ||
+ !CBS_get_u16_length_prefixed(©, &extensions) ||
+ CBS_len(©) != 0) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DECODE_ERROR);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return -1;
+ }
+
+ int have_supported_versions;
+ CBS supported_versions;
+ const SSL_EXTENSION_TYPE ext_types[] = {
+ {TLSEXT_TYPE_supported_versions, &have_supported_versions,
+ &supported_versions},
+ };
+
+ uint8_t alert = SSL_AD_DECODE_ERROR;
+ if (!ssl_parse_extensions(&extensions, &alert, ext_types,
+ OPENSSL_ARRAY_SIZE(ext_types),
+ 1 /* ignore unknown */)) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, alert);
+ return -1;
+ }
+
+ if (have_supported_versions) {
+ if (!CBS_get_u16(&supported_versions, &server_version) ||
+ CBS_len(&supported_versions) != 0) {
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
+ return -1;
+ }
+ }
+ }
+
if (!ssl_supports_version(hs, server_version)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNSUPPORTED_PROTOCOL);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_PROTOCOL_VERSION);
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index 2be474c..b40f222 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -1262,6 +1262,10 @@
// specified value in ServerHello version field.
SendServerHelloVersion uint16
+ // SendServerSupportedExtensionVersion, if non-zero, causes the server to send
+ // the specified value in supported_versions extension in the ServerHello.
+ SendServerSupportedExtensionVersion uint16
+
// SkipHelloRetryRequest, if true, causes the TLS 1.3 server to not send
// HelloRetryRequest.
SkipHelloRetryRequest bool
diff --git a/ssl/test/runner/handshake_messages.go b/ssl/test/runner/handshake_messages.go
index 92bbdca..1e36f08 100644
--- a/ssl/test/runner/handshake_messages.go
+++ b/ssl/test/runner/handshake_messages.go
@@ -813,21 +813,22 @@
}
type serverHelloMsg struct {
- raw []byte
- isDTLS bool
- vers uint16
- versOverride uint16
- random []byte
- sessionId []byte
- cipherSuite uint16
- hasKeyShare bool
- keyShare keyShareEntry
- hasPSKIdentity bool
- pskIdentity uint16
- compressionMethod uint8
- customExtension string
- unencryptedALPN string
- extensions serverExtensions
+ raw []byte
+ isDTLS bool
+ vers uint16
+ versOverride uint16
+ supportedVersOverride uint16
+ random []byte
+ sessionId []byte
+ cipherSuite uint16
+ hasKeyShare bool
+ keyShare keyShareEntry
+ hasPSKIdentity bool
+ pskIdentity uint16
+ compressionMethod uint8
+ customExtension string
+ unencryptedALPN string
+ extensions serverExtensions
}
func (m *serverHelloMsg) marshal() []byte {
@@ -848,6 +849,8 @@
}
if m.versOverride != 0 {
hello.addU16(m.versOverride)
+ } else if m.vers == tls13ExperimentVersion {
+ hello.addU16(VersionTLS12)
} else {
hello.addU16(m.vers)
}
@@ -877,6 +880,15 @@
extensions.addU16(2) // Length
extensions.addU16(m.pskIdentity)
}
+ if m.vers == tls13ExperimentVersion || m.supportedVersOverride != 0 {
+ extensions.addU16(extensionSupportedVersions)
+ extensions.addU16(2) // Length
+ if m.supportedVersOverride != 0 {
+ extensions.addU16(m.supportedVersOverride)
+ } else {
+ extensions.addU16(m.vers)
+ }
+ }
if len(m.customExtension) > 0 {
extensions.addU16(extensionCustom)
customExt := extensions.addU16LengthPrefixed()
@@ -949,6 +961,36 @@
return false
}
+ // Parse out the version from supported_versions if available.
+ if m.vers == VersionTLS12 {
+ vdata := data
+ for len(vdata) != 0 {
+ if len(vdata) < 4 {
+ return false
+ }
+ extension := uint16(vdata[0])<<8 | uint16(vdata[1])
+ length := int(vdata[2])<<8 | int(vdata[3])
+ vdata = vdata[4:]
+
+ if len(vdata) < length {
+ return false
+ }
+ d := vdata[:length]
+ vdata = vdata[length:]
+
+ if extension == extensionSupportedVersions {
+ if len(d) < 2 {
+ return false
+ }
+ m.vers = uint16(d[0])<<8 | uint16(d[1])
+ vers, ok = wireToVersion(m.vers, m.isDTLS)
+ if !ok {
+ return false
+ }
+ }
+ }
+ }
+
if vers >= VersionTLS13 {
for len(data) != 0 {
if len(data) < 4 {
@@ -983,6 +1025,10 @@
}
m.pskIdentity = uint16(d[0])<<8 | uint16(d[1])
m.hasPSKIdentity = true
+ case extensionSupportedVersions:
+ if m.vers != tls13ExperimentVersion {
+ return false
+ }
default:
// Only allow the 3 extensions that are sent in
// the clear in TLS 1.3.
@@ -1059,6 +1105,7 @@
hasKeyShare bool
hasEarlyData bool
keyShare keyShareEntry
+ supportedVersion uint16
supportedPoints []uint8
serverNameAck bool
}
@@ -1155,6 +1202,11 @@
keyExchange := keyShare.addU16LengthPrefixed()
keyExchange.addBytes(m.keyShare.keyExchange)
}
+ if m.supportedVersion != 0 {
+ extensions.addU16(extensionSupportedVersions)
+ extensions.addU16(2) // Length
+ extensions.addU16(m.supportedVersion)
+ }
if len(m.supportedPoints) > 0 {
// http://tools.ietf.org/html/rfc4492#section-5.1.2
extensions.addU16(extensionSupportedPoints)
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index f6692e1..25230a4 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -359,12 +359,13 @@
config := c.config
hs.hello = &serverHelloMsg{
- isDTLS: c.isDTLS,
- vers: c.wireVersion,
- sessionId: hs.clientHello.sessionId,
- versOverride: config.Bugs.SendServerHelloVersion,
- customExtension: config.Bugs.CustomUnencryptedExtension,
- unencryptedALPN: config.Bugs.SendUnencryptedALPN,
+ isDTLS: c.isDTLS,
+ vers: c.wireVersion,
+ sessionId: hs.clientHello.sessionId,
+ versOverride: config.Bugs.SendServerHelloVersion,
+ supportedVersOverride: config.Bugs.SendServerSupportedExtensionVersion,
+ customExtension: config.Bugs.CustomUnencryptedExtension,
+ unencryptedALPN: config.Bugs.SendUnencryptedALPN,
}
hs.hello.random = make([]byte, 32)
@@ -1056,6 +1057,9 @@
vers: c.wireVersion,
versOverride: config.Bugs.SendServerHelloVersion,
compressionMethod: config.Bugs.SendCompressionMethod,
+ extensions: serverExtensions{
+ supportedVersion: config.Bugs.SendServerSupportedExtensionVersion,
+ },
}
hs.hello.random = make([]byte, 32)
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index acf1fa8..be74ffe 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -5032,7 +5032,6 @@
flags: []string{"-tls13-variant", strconv.Itoa(vers.tls13Variant)},
})
}
-
}
// If all versions are unknown, negotiation fails.
@@ -5112,6 +5111,36 @@
expectedVersion: VersionTLS12,
})
+ // Test that TLS 1.2 isn't negotiated by the supported_versions extension in
+ // the ServerHello.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "SupportedVersionSelection-TLS12",
+ config: Config{
+ MaxVersion: VersionTLS12,
+ Bugs: ProtocolBugs{
+ SendServerSupportedExtensionVersion: VersionTLS12,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
+
+ // Test that the non-experimental TLS 1.3 isn't negotiated by the
+ // supported_versions extension in the ServerHello.
+ testCases = append(testCases, testCase{
+ testType: clientTest,
+ name: "SupportedVersionSelection-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendServerSupportedExtensionVersion: tls13DraftVersion,
+ },
+ },
+ shouldFail: true,
+ expectedError: ":UNEXPECTED_EXTENSION:",
+ })
+
// Test that the maximum version is selected regardless of the
// client-sent order.
testCases = append(testCases, testCase{
diff --git a/ssl/tls13_client.c b/ssl/tls13_client.c
index 0010ccb..c92b539 100644
--- a/ssl/tls13_client.c
+++ b/ssl/tls13_client.c
@@ -56,9 +56,9 @@
}
CBS cbs, extensions;
- uint16_t server_wire_version;
+ uint16_t server_version;
CBS_init(&cbs, ssl->init_msg, ssl->init_num);
- if (!CBS_get_u16(&cbs, &server_wire_version) ||
+ if (!CBS_get_u16(&cbs, &server_version) ||
!CBS_get_u16_length_prefixed(&cbs, &extensions) ||
/* HelloRetryRequest may not be empty. */
CBS_len(&extensions) == 0 ||
@@ -167,11 +167,11 @@
}
CBS cbs, server_random, session_id, extensions;
- uint16_t server_wire_version;
+ uint16_t server_version;
uint16_t cipher_suite;
uint8_t compression_method;
CBS_init(&cbs, ssl->init_msg, ssl->init_num);
- if (!CBS_get_u16(&cbs, &server_wire_version) ||
+ if (!CBS_get_u16(&cbs, &server_version) ||
!CBS_get_bytes(&cbs, &server_random, SSL3_RANDOM_SIZE) ||
(ssl->version == TLS1_3_EXPERIMENT_VERSION &&
!CBS_get_u8_length_prefixed(&cbs, &session_id)) ||
@@ -185,7 +185,9 @@
return ssl_hs_error;
}
- if (server_wire_version != ssl->version) {
+ uint16_t expected_version =
+ ssl->version == TLS1_3_EXPERIMENT_VERSION ? TLS1_2_VERSION : ssl->version;
+ if (server_version != expected_version) {
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_DECODE_ERROR);
OPENSSL_PUT_ERROR(SSL, SSL_R_WRONG_VERSION_NUMBER);
return ssl_hs_error;
@@ -211,11 +213,13 @@
}
/* Parse out the extensions. */
- int have_key_share = 0, have_pre_shared_key = 0;
- CBS key_share, pre_shared_key;
+ int have_key_share = 0, have_pre_shared_key = 0, have_supported_versions = 0;
+ CBS key_share, pre_shared_key, supported_versions;
const SSL_EXTENSION_TYPE ext_types[] = {
{TLSEXT_TYPE_key_share, &have_key_share, &key_share},
{TLSEXT_TYPE_pre_shared_key, &have_pre_shared_key, &pre_shared_key},
+ {TLSEXT_TYPE_supported_versions, &have_supported_versions,
+ &supported_versions},
};
uint8_t alert = SSL_AD_DECODE_ERROR;
@@ -226,6 +230,14 @@
return ssl_hs_error;
}
+ /* supported_versions is parsed in handshake_client to select the experimental
+ * TLS 1.3 version. */
+ if (have_supported_versions && ssl->version != TLS1_3_EXPERIMENT_VERSION) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_EXTENSION);
+ ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNSUPPORTED_EXTENSION);
+ return ssl_hs_error;
+ }
+
alert = SSL_AD_DECODE_ERROR;
if (have_pre_shared_key) {
if (ssl->session == NULL) {
diff --git a/ssl/tls13_server.c b/ssl/tls13_server.c
index 58e062d..25a7c2c 100644
--- a/ssl/tls13_server.c
+++ b/ssl/tls13_server.c
@@ -85,6 +85,19 @@
return ok;
}
+static int ssl_ext_supported_versions_add_serverhello(SSL_HANDSHAKE *hs,
+ CBB *out) {
+ CBB contents;
+ if (!CBB_add_u16(out, TLSEXT_TYPE_supported_versions) ||
+ !CBB_add_u16_length_prefixed(out, &contents) ||
+ !CBB_add_u16(&contents, hs->ssl->version) ||
+ !CBB_flush(out)) {
+ return 0;
+ }
+
+ return 1;
+}
+
static const SSL_CIPHER *choose_tls13_cipher(
const SSL *ssl, const SSL_CLIENT_HELLO *client_hello) {
if (client_hello->cipher_suites_len % 2 != 0) {
@@ -514,10 +527,15 @@
static enum ssl_hs_wait_t do_send_server_hello(SSL_HANDSHAKE *hs) {
SSL *const ssl = hs->ssl;
+ uint16_t version = ssl->version;
+ if (ssl->version == TLS1_3_EXPERIMENT_VERSION) {
+ version = TLS1_2_VERSION;
+ }
+
/* Send a ServerHello. */
CBB cbb, body, extensions, session_id;
if (!ssl->method->init_message(ssl, &cbb, &body, SSL3_MT_SERVER_HELLO) ||
- !CBB_add_u16(&body, ssl->version) ||
+ !CBB_add_u16(&body, version) ||
!RAND_bytes(ssl->s3->server_random, sizeof(ssl->s3->server_random)) ||
!CBB_add_bytes(&body, ssl->s3->server_random, SSL3_RANDOM_SIZE) ||
(ssl->version == TLS1_3_EXPERIMENT_VERSION &&
@@ -528,6 +546,8 @@
!CBB_add_u16_length_prefixed(&body, &extensions) ||
!ssl_ext_pre_shared_key_add_serverhello(hs, &extensions) ||
!ssl_ext_key_share_add_serverhello(hs, &extensions) ||
+ (ssl->version == TLS1_3_EXPERIMENT_VERSION &&
+ !ssl_ext_supported_versions_add_serverhello(hs, &extensions)) ||
!ssl_add_message_cbb(ssl, &cbb)) {
goto err;
}