Fix TLSInnerPlaintext limit.
See https://github.com/tlswg/tls13-spec/pull/1083. We misread the
original text spec, but it turns out the original spec text required
senders have version-specific maximum send fragments. The PR fixes this
off-by-one issue. Align with the new spec text uniformly.
This is a wire format change for our existing drafts *only if* records
have padding. We don't currently send padding, so this is fine. Unpadded
records continue to be capped at 2^14 bytes of plaintext (or 2^14+1
bytes of TLSInnerPlaintext structure).
Change-Id: I01017cfd13162504bb163dd59afd74aff0896cc4
Reviewed-on: https://boringssl-review.googlesource.com/23004
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>
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 57bc20c..0cd1e81 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -2442,9 +2442,10 @@
SendLargeRecords: true,
},
},
- messageLen: maxPlaintext + 1,
- shouldFail: true,
- expectedError: ":DATA_LENGTH_TOO_LONG:",
+ messageLen: maxPlaintext + 1,
+ shouldFail: true,
+ expectedError: ":DATA_LENGTH_TOO_LONG:",
+ expectedLocalError: "remote error: record overflow",
},
{
protocol: dtls,
@@ -2454,9 +2455,64 @@
SendLargeRecords: true,
},
},
- messageLen: maxPlaintext + 1,
- shouldFail: true,
- expectedError: ":DATA_LENGTH_TOO_LONG:",
+ messageLen: maxPlaintext + 1,
+ shouldFail: true,
+ expectedError: ":DATA_LENGTH_TOO_LONG:",
+ expectedLocalError: "remote error: record overflow",
+ },
+ {
+ name: "LargePlaintext-TLS13-Padded-8192-8192",
+ config: Config{
+ MinVersion: VersionTLS13,
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ RecordPadding: 8192,
+ SendLargeRecords: true,
+ },
+ },
+ messageLen: 8192,
+ },
+ {
+ name: "LargePlaintext-TLS13-Padded-8193-8192",
+ config: Config{
+ MinVersion: VersionTLS13,
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ RecordPadding: 8193,
+ SendLargeRecords: true,
+ },
+ },
+ messageLen: 8192,
+ shouldFail: true,
+ expectedError: ":DATA_LENGTH_TOO_LONG:",
+ expectedLocalError: "remote error: record overflow",
+ },
+ {
+ name: "LargePlaintext-TLS13-Padded-16383-1",
+ config: Config{
+ MinVersion: VersionTLS13,
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ RecordPadding: 1,
+ SendLargeRecords: true,
+ },
+ },
+ messageLen: 16383,
+ },
+ {
+ name: "LargePlaintext-TLS13-Padded-16384-1",
+ config: Config{
+ MinVersion: VersionTLS13,
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ RecordPadding: 1,
+ SendLargeRecords: true,
+ },
+ },
+ messageLen: 16384,
+ shouldFail: true,
+ expectedError: ":DATA_LENGTH_TOO_LONG:",
+ expectedLocalError: "remote error: record overflow",
},
{
name: "LargeCiphertext",
@@ -11774,7 +11830,7 @@
testCases = append(testCases, testCase{
testType: clientTest,
- name: "TLS13Draft22-SkipChangeCipherSpec-Client",
+ name: "TLS13Draft22-SkipChangeCipherSpec-Client",
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
@@ -11786,7 +11842,7 @@
testCases = append(testCases, testCase{
testType: serverTest,
- name: "TLS13Draft22-SkipChangeCipherSpec-Server",
+ name: "TLS13Draft22-SkipChangeCipherSpec-Server",
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
@@ -11798,30 +11854,30 @@
testCases = append(testCases, testCase{
testType: clientTest,
- name: "TLS13Draft22-TooManyChangeCipherSpec-Client",
+ name: "TLS13Draft22-TooManyChangeCipherSpec-Client",
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
SendExtraChangeCipherSpec: 33,
},
},
- tls13Variant: TLS13Draft22,
- shouldFail: true,
- expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:",
+ tls13Variant: TLS13Draft22,
+ shouldFail: true,
+ expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:",
})
testCases = append(testCases, testCase{
testType: serverTest,
- name: "TLS13Draft22-TooManyChangeCipherSpec-Server",
+ name: "TLS13Draft22-TooManyChangeCipherSpec-Server",
config: Config{
MaxVersion: VersionTLS13,
Bugs: ProtocolBugs{
SendExtraChangeCipherSpec: 33,
},
},
- tls13Variant: TLS13Draft22,
- shouldFail: true,
- expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:",
+ tls13Variant: TLS13Draft22,
+ shouldFail: true,
+ expectedError: ":TOO_MANY_EMPTY_FRAGMENTS:",
})
fooString := "foo"
diff --git a/ssl/tls_record.cc b/ssl/tls_record.cc
index 7e8e968..a1363fa 100644
--- a/ssl/tls_record.cc
+++ b/ssl/tls_record.cc
@@ -187,9 +187,25 @@
return ret;
}
-enum ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type,
- Span<uint8_t> *out, size_t *out_consumed,
- uint8_t *out_alert, Span<uint8_t> in) {
+static ssl_open_record_t skip_early_data(SSL *ssl, uint8_t *out_alert,
+ size_t consumed) {
+ ssl->s3->early_data_skipped += consumed;
+ if (ssl->s3->early_data_skipped < consumed) {
+ ssl->s3->early_data_skipped = kMaxEarlyDataSkipped + 1;
+ }
+
+ if (ssl->s3->early_data_skipped > kMaxEarlyDataSkipped) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA);
+ *out_alert = SSL_AD_UNEXPECTED_MESSAGE;
+ return ssl_open_record_error;
+ }
+
+ return ssl_open_record_discard;
+}
+
+ssl_open_record_t tls_open_record(SSL *ssl, uint8_t *out_type,
+ Span<uint8_t> *out, size_t *out_consumed,
+ uint8_t *out_alert, Span<uint8_t> in) {
*out_consumed = 0;
if (ssl->s3->read_shutdown == ssl_shutdown_close_notify) {
return ssl_open_record_close_notify;
@@ -267,7 +283,7 @@
if (ssl->s3->skip_early_data &&
ssl->s3->aead_read_ctx->is_null_cipher() &&
type == SSL3_RT_APPLICATION_DATA) {
- goto skipped_data;
+ return skip_early_data(ssl, out_alert, *out_consumed);
}
// Decrypt the body in-place.
@@ -276,7 +292,7 @@
MakeSpan(const_cast<uint8_t *>(CBS_data(&body)), CBS_len(&body)))) {
if (ssl->s3->skip_early_data && !ssl->s3->aead_read_ctx->is_null_cipher()) {
ERR_clear_error();
- goto skipped_data;
+ return skip_early_data(ssl, out_alert, *out_consumed);
}
OPENSSL_PUT_ERROR(SSL, SSL_R_DECRYPTION_FAILED_OR_BAD_RECORD_MAC);
@@ -292,8 +308,21 @@
}
// TLS 1.3 hides the record type inside the encrypted data.
- if (!ssl->s3->aead_read_ctx->is_null_cipher() &&
- ssl->s3->aead_read_ctx->ProtocolVersion() >= TLS1_3_VERSION) {
+ bool has_padding =
+ !ssl->s3->aead_read_ctx->is_null_cipher() &&
+ ssl->s3->aead_read_ctx->ProtocolVersion() >= TLS1_3_VERSION;
+
+ // If there is padding, the plaintext limit includes the padding, but includes
+ // extra room for the inner content type.
+ size_t plaintext_limit =
+ has_padding ? SSL3_RT_MAX_PLAIN_LENGTH + 1 : SSL3_RT_MAX_PLAIN_LENGTH;
+ if (out->size() > plaintext_limit) {
+ OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
+ *out_alert = SSL_AD_RECORD_OVERFLOW;
+ return ssl_open_record_error;
+ }
+
+ if (has_padding) {
// The outer record type is always application_data.
if (type != SSL3_RT_APPLICATION_DATA) {
OPENSSL_PUT_ERROR(SSL, SSL_R_INVALID_OUTER_RECORD_TYPE);
@@ -312,13 +341,6 @@
} while (type == 0);
}
- // Check the plaintext length.
- if (out->size() > SSL3_RT_MAX_PLAIN_LENGTH) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_DATA_LENGTH_TOO_LONG);
- *out_alert = SSL_AD_RECORD_OVERFLOW;
- return ssl_open_record_error;
- }
-
// Limit the number of consecutive empty records.
if (out->empty()) {
ssl->s3->empty_record_count++;
@@ -358,20 +380,6 @@
*out_type = type;
return ssl_open_record_success;
-
-skipped_data:
- ssl->s3->early_data_skipped += *out_consumed;
- if (ssl->s3->early_data_skipped < *out_consumed) {
- ssl->s3->early_data_skipped = kMaxEarlyDataSkipped + 1;
- }
-
- if (ssl->s3->early_data_skipped > kMaxEarlyDataSkipped) {
- OPENSSL_PUT_ERROR(SSL, SSL_R_TOO_MUCH_SKIPPED_EARLY_DATA);
- *out_alert = SSL_AD_UNEXPECTED_MESSAGE;
- return ssl_open_record_error;
- }
-
- return ssl_open_record_discard;
}
static int do_seal_record(SSL *ssl, uint8_t *out_prefix, uint8_t *out,