Implement ContentType TLS 1.3 variant.
This implements PR #1051
(https://github.com/tlswg/tls13-spec/pull/1051).
Local experiments were not able to replicate the claims in the PR, but
implement this anyway for comparison purposes.
Change-Id: Ic9baf5e671f9a44565020466a553dd08f5ec0f1b
Reviewed-on: https://boringssl-review.googlesource.com/17844
Reviewed-by: Steven Valdez <svaldez@google.com>
Commit-Queue: Steven Valdez <svaldez@google.com>
CQ-Verified: CQ bot account: commit-bot@chromium.org <commit-bot@chromium.org>
diff --git a/ssl/handshake_client.cc b/ssl/handshake_client.cc
index 2c37ec0..48fe052 100644
--- a/ssl/handshake_client.cc
+++ b/ssl/handshake_client.cc
@@ -674,7 +674,7 @@
/* In TLS 1.3 experimental encodings, send a fake placeholder session ID
* when we do not otherwise have one to send. */
if (hs->max_version >= TLS1_3_VERSION &&
- ssl->tls13_variant != tls13_default &&
+ ssl->tls13_variant == tls13_experiment &&
!CBB_add_bytes(&child, hs->session_id, hs->session_id_len)) {
return 0;
}
@@ -759,7 +759,7 @@
}
/* Initialize a random session ID for the experimental TLS 1.3 variant. */
- if (ssl->tls13_variant != tls13_default) {
+ if (ssl->tls13_variant == tls13_experiment) {
hs->session_id_len = sizeof(hs->session_id);
if (!RAND_bytes(hs->session_id, hs->session_id_len)) {
return -1;
diff --git a/ssl/s3_both.cc b/ssl/s3_both.cc
index 5eb364d..79f71fa 100644
--- a/ssl/s3_both.cc
+++ b/ssl/s3_both.cc
@@ -266,7 +266,15 @@
todo = ssl->max_send_fragment;
}
- if (!add_record_to_flight(ssl, SSL3_RT_HANDSHAKE, msg + added, todo)) {
+ uint8_t type = SSL3_RT_HANDSHAKE;
+ if (ssl->server &&
+ ssl->s3->have_version &&
+ ssl->version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION &&
+ ssl->s3->aead_write_ctx == NULL) {
+ type = SSL3_RT_PLAINTEXT_HANDSHAKE;
+ }
+
+ if (!add_record_to_flight(ssl, type, msg + added, todo)) {
goto err;
}
added += todo;
diff --git a/ssl/s3_pkt.cc b/ssl/s3_pkt.cc
index beaa08e..4ae2e34 100644
--- a/ssl/s3_pkt.cc
+++ b/ssl/s3_pkt.cc
@@ -523,7 +523,13 @@
return -1;
}
- if (rr->type != SSL3_RT_HANDSHAKE) {
+ /* Accept server_plaintext_handshake records when the content type TLS 1.3
+ * variant is enabled. */
+ if (rr->type != SSL3_RT_HANDSHAKE &&
+ !(!ssl->server &&
+ ssl->tls13_variant == tls13_record_type_experiment &&
+ ssl->s3->aead_read_ctx == NULL &&
+ rr->type == SSL3_RT_PLAINTEXT_HANDSHAKE)) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNEXPECTED_RECORD);
ssl3_send_alert(ssl, SSL3_AL_FATAL, SSL_AD_UNEXPECTED_MESSAGE);
return -1;
diff --git a/ssl/ssl_versions.cc b/ssl/ssl_versions.cc
index 387eee7..8b54bd2 100644
--- a/ssl/ssl_versions.cc
+++ b/ssl/ssl_versions.cc
@@ -34,6 +34,7 @@
case TLS1_3_DRAFT_VERSION:
case TLS1_3_EXPERIMENT_VERSION:
+ case TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION:
*out = TLS1_3_VERSION;
return 1;
@@ -55,8 +56,9 @@
* decreasing preference. */
static const uint16_t kTLSVersions[] = {
- TLS1_3_DRAFT_VERSION,
TLS1_3_EXPERIMENT_VERSION,
+ TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION,
+ TLS1_3_DRAFT_VERSION,
TLS1_2_VERSION,
TLS1_1_VERSION,
TLS1_VERSION,
@@ -98,7 +100,8 @@
* everywhere to refer to any draft TLS 1.3 versions. In this direction, we
* map it to some representative TLS 1.3 draft version. */
if (version == TLS1_3_DRAFT_VERSION ||
- version == TLS1_3_EXPERIMENT_VERSION) {
+ version == TLS1_3_EXPERIMENT_VERSION ||
+ version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) {
OPENSSL_PUT_ERROR(SSL, SSL_R_UNKNOWN_SSL_VERSION);
return 0;
}
@@ -238,7 +241,8 @@
int SSL_version(const SSL *ssl) {
uint16_t ret = ssl_version(ssl);
/* Report TLS 1.3 draft version as TLS 1.3 in the public API. */
- if (ret == TLS1_3_DRAFT_VERSION || ret == TLS1_3_EXPERIMENT_VERSION) {
+ if (ret == TLS1_3_DRAFT_VERSION || ret == TLS1_3_EXPERIMENT_VERSION ||
+ ret == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) {
return TLS1_3_VERSION;
}
return ret;
@@ -249,6 +253,7 @@
/* Report TLS 1.3 draft version as TLS 1.3 in the public API. */
case TLS1_3_DRAFT_VERSION:
case TLS1_3_EXPERIMENT_VERSION:
+ case TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION:
return "TLSv1.3";
case TLS1_2_VERSION:
@@ -301,12 +306,15 @@
* non-default value. */
if (ssl->server) {
if (ssl->tls13_variant == tls13_default &&
- version == TLS1_3_EXPERIMENT_VERSION) {
+ (version == TLS1_3_EXPERIMENT_VERSION ||
+ version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION)) {
return 0;
}
} else {
if ((ssl->tls13_variant != tls13_experiment &&
version == TLS1_3_EXPERIMENT_VERSION) ||
+ (ssl->tls13_variant != tls13_record_type_experiment &&
+ version == TLS1_3_RECORD_TYPE_EXPERIMENT_VERSION) ||
(ssl->tls13_variant != tls13_default &&
version == TLS1_3_DRAFT_VERSION)) {
return 0;
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index b40f222..a3c744c 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -33,18 +33,21 @@
// A draft version of TLS 1.3 that is sent over the wire for the current draft.
const (
- tls13DraftVersion = 0x7f12
- tls13ExperimentVersion = 0x7e01
+ tls13DraftVersion = 0x7f12
+ tls13ExperimentVersion = 0x7e01
+ tls13RecordTypeExperimentVersion = 0x7a12
)
const (
- TLS13Default = 0
- TLS13Experiment = 1
+ TLS13Default = 0
+ TLS13Experiment = 1
+ TLS13RecordTypeExperiment = 2
)
var allTLSWireVersions = []uint16{
tls13DraftVersion,
tls13ExperimentVersion,
+ tls13RecordTypeExperimentVersion,
VersionTLS12,
VersionTLS11,
VersionTLS10,
@@ -71,10 +74,11 @@
type recordType uint8
const (
- recordTypeChangeCipherSpec recordType = 20
- recordTypeAlert recordType = 21
- recordTypeHandshake recordType = 22
- recordTypeApplicationData recordType = 23
+ recordTypeChangeCipherSpec recordType = 20
+ recordTypeAlert recordType = 21
+ recordTypeHandshake recordType = 22
+ recordTypeApplicationData recordType = 23
+ recordTypePlaintextHandshake recordType = 24
)
// TLS handshake message types.
@@ -1485,6 +1489,7 @@
// false.
func (c *Config) isSupportedVersion(wireVers uint16, isDTLS bool) (uint16, bool) {
if (c.TLS13Variant != TLS13Experiment && wireVers == tls13ExperimentVersion) ||
+ (c.TLS13Variant != TLS13RecordTypeExperiment && wireVers == tls13RecordTypeExperimentVersion) ||
(c.TLS13Variant != TLS13Default && wireVers == tls13DraftVersion) {
return 0, false
}
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index a50029f..c974bd4 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -762,6 +762,11 @@
return 0, nil, c.in.setErrorLocked(errors.New("tls: unsupported SSLv2 handshake received"))
}
+ // Accept server_plaintext_handshake records when the content type TLS 1.3 variant is enabled.
+ if c.isClient && c.in.cipher == nil && c.config.TLS13Variant == TLS13RecordTypeExperiment && want == recordTypeHandshake && typ == recordTypePlaintextHandshake {
+ typ = recordTypeHandshake
+ }
+
vers := uint16(b.data[1])<<8 | uint16(b.data[2])
n := int(b.data[3])<<8 | int(b.data[4])
diff --git a/ssl/test/runner/dtls.go b/ssl/test/runner/dtls.go
index b0b6c18..72369d6 100644
--- a/ssl/test/runner/dtls.go
+++ b/ssl/test/runner/dtls.go
@@ -35,7 +35,7 @@
switch vers {
case VersionSSL30, VersionTLS10, VersionTLS11, VersionTLS12:
return vers, true
- case tls13DraftVersion, tls13ExperimentVersion:
+ case tls13DraftVersion, tls13ExperimentVersion, tls13RecordTypeExperimentVersion:
return VersionTLS13, true
}
}
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 25230a4..35d005e 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -573,7 +573,11 @@
if sendHelloRetryRequest {
oldClientHelloBytes := hs.clientHello.marshal()
hs.writeServerHash(helloRetryRequest.marshal())
- c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal())
+ if c.vers == tls13RecordTypeExperimentVersion {
+ c.writeRecord(recordTypePlaintextHandshake, helloRetryRequest.marshal())
+ } else {
+ c.writeRecord(recordTypeHandshake, helloRetryRequest.marshal())
+ }
c.flushHandshake()
if hs.clientHello.hasEarlyData {
@@ -751,7 +755,11 @@
toWrite = append(toWrite, typeEncryptedExtensions)
c.writeRecord(recordTypeHandshake, toWrite)
} else {
- c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+ if c.vers == tls13RecordTypeExperimentVersion {
+ c.writeRecord(recordTypePlaintextHandshake, hs.hello.marshal())
+ } else {
+ c.writeRecord(recordTypeHandshake, hs.hello.marshal())
+ }
}
c.flushHandshake()
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 0005725..86f5f71 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -1280,6 +1280,13 @@
versionWire: tls13ExperimentVersion,
tls13Variant: TLS13Experiment,
},
+ {
+ name: "TLS13RecordTypeExperiment",
+ version: VersionTLS13,
+ excludeFlag: "-no-tls13",
+ versionWire: tls13RecordTypeExperimentVersion,
+ tls13Variant: TLS13RecordTypeExperiment,
+ },
}
func allVersions(protocol protocol) []tlsVersion {
@@ -4018,6 +4025,34 @@
tests = append(tests, testCase{
testType: clientTest,
+ name: "TLS13RecordTypeExperiment-EarlyData-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MinVersion: VersionTLS13,
+ TLS13Variant: TLS13RecordTypeExperiment,
+ MaxEarlyDataSize: 16384,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ MinVersion: VersionTLS13,
+ TLS13Variant: TLS13RecordTypeExperiment,
+ MaxEarlyDataSize: 16384,
+ Bugs: ProtocolBugs{
+ ExpectEarlyData: [][]byte{{'h', 'e', 'l', 'l', 'o'}},
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-enable-early-data",
+ "-expect-early-data-info",
+ "-expect-accept-early-data",
+ "-on-resume-shim-writes-first",
+ "-tls13-variant", "2",
+ },
+ })
+
+ tests = append(tests, testCase{
+ testType: clientTest,
name: "TLS13-EarlyData-TooMuchData-Client",
config: Config{
MaxVersion: VersionTLS13,
@@ -4146,6 +4181,28 @@
tests = append(tests, testCase{
testType: serverTest,
+ name: "TLS13RecordTypeExperiment-EarlyData-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MinVersion: VersionTLS13,
+ TLS13Variant: TLS13RecordTypeExperiment,
+ Bugs: ProtocolBugs{
+ SendEarlyData: [][]byte{{1, 2, 3, 4}},
+ ExpectEarlyDataAccepted: true,
+ ExpectHalfRTTData: [][]byte{{254, 253, 252, 251}},
+ },
+ },
+ messageCount: 2,
+ resumeSession: true,
+ flags: []string{
+ "-enable-early-data",
+ "-expect-accept-early-data",
+ "-tls13-variant", "2",
+ },
+ })
+
+ tests = append(tests, testCase{
+ testType: serverTest,
name: "TLS13-MaxEarlyData-Server",
config: Config{
MaxVersion: VersionTLS13,
@@ -10477,6 +10534,19 @@
testCases = append(testCases, testCase{
testType: serverTest,
+ name: "SkipEarlyData-TLS13RecordTypeExperiment",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ TLS13Variant: TLS13RecordTypeExperiment,
+ Bugs: ProtocolBugs{
+ SendFakeEarlyDataLength: 4,
+ },
+ },
+ flags: []string{"-tls13-variant", "2"},
+ })
+
+ testCases = append(testCases, testCase{
+ testType: serverTest,
name: "SkipEarlyData-OmitEarlyDataExtension",
config: Config{
MaxVersion: VersionTLS13,
@@ -11003,6 +11073,32 @@
testCases = append(testCases, testCase{
testType: clientTest,
+ name: "TLS13RecordTypeExperiment-EarlyData-Reject-Client",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ MaxEarlyDataSize: 16384,
+ TLS13Variant: TLS13RecordTypeExperiment,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ TLS13Variant: TLS13RecordTypeExperiment,
+ MaxEarlyDataSize: 16384,
+ Bugs: ProtocolBugs{
+ AlwaysRejectEarlyData: true,
+ },
+ },
+ resumeSession: true,
+ flags: []string{
+ "-enable-early-data",
+ "-expect-early-data-info",
+ "-expect-reject-early-data",
+ "-on-resume-shim-writes-first",
+ "-tls13-variant", "2",
+ },
+ })
+
+ testCases = append(testCases, testCase{
+ testType: clientTest,
name: "TLS13-EarlyData-RejectTicket-Client",
config: Config{
MaxVersion: VersionTLS13,