Discard user_canceled alerts in TLS 1.3.
Warning alerts do not exist in TLS 1.3, but RFC 8446 section 6.1
continues to define user_canceled as a signal to cancel the handshake,
without specifying how to handle it. JDK11 misuses it to signal
full-duplex connection close after the handshake. As a workaround, skip
user_canceled as in TLS 1.2. This matches NSS and OpenSSL.
Bug: b/135941563
Change-Id: I7ef546f1f166741b9f112686c75e6757331948f0
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/38605
Commit-Queue: David Benjamin <davidben@google.com>
Commit-Queue: Adam Langley <agl@google.com>
Reviewed-by: Adam Langley <agl@google.com>
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 660be0a..fc68ce9 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -601,6 +601,9 @@
// sendWarningAlerts is the number of consecutive warning alerts to send
// before each test message.
sendWarningAlerts int
+ // sendUserCanceledAlerts is the number of consecutive user_canceled alerts to
+ // send before each test message.
+ sendUserCanceledAlerts int
// sendBogusAlertType, if true, causes a bogus alert of invalid type to
// be sent before each test message.
sendBogusAlertType bool
@@ -1005,6 +1008,10 @@
tlsConn.SendAlert(alertLevelWarning, alertUnexpectedMessage)
}
+ for i := 0; i < test.sendUserCanceledAlerts; i++ {
+ tlsConn.SendAlert(alertLevelWarning, alertUserCanceled)
+ }
+
if test.sendBogusAlertType {
tlsConn.SendAlert(0x42, alertUnexpectedMessage)
}
@@ -2590,8 +2597,28 @@
expectedError: ":BAD_ALERT:",
expectedLocalError: "remote error: error decoding message",
},
+ // Although TLS 1.3 intended to remove warning alerts, it left in
+ // user_canceled. JDK11 misuses this alert as a post-handshake
+ // full-duplex signal. As a workaround, skip user_canceled as in
+ // TLS 1.2, which is consistent with NSS and OpenSSL.
{
- name: "SendWarningAlerts",
+ name: "SendUserCanceledAlerts-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ sendUserCanceledAlerts: 4,
+ },
+ {
+ name: "SendUserCanceledAlerts-TooMany-TLS13",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ sendUserCanceledAlerts: 5,
+ shouldFail: true,
+ expectedError: ":TOO_MANY_WARNING_ALERTS:",
+ },
+ {
+ name: "SendWarningAlerts-TooMany",
config: Config{
MaxVersion: VersionTLS12,
},
@@ -2600,7 +2627,7 @@
expectedError: ":TOO_MANY_WARNING_ALERTS:",
},
{
- name: "SendWarningAlerts-Async",
+ name: "SendWarningAlerts-TooMany-Async",
config: Config{
MaxVersion: VersionTLS12,
},
diff --git a/ssl/tls_record.cc b/ssl/tls_record.cc
index c1f9e7f..464c5c5 100644
--- a/ssl/tls_record.cc
+++ b/ssl/tls_record.cc
@@ -566,9 +566,14 @@
return ssl_open_record_close_notify;
}
- // Warning alerts do not exist in TLS 1.3.
+ // Warning alerts do not exist in TLS 1.3, but RFC 8446 section 6.1
+ // continues to define user_canceled as a signal to cancel the handshake,
+ // without specifying how to handle it. JDK11 misuses it to signal
+ // full-duplex connection close after the handshake. As a workaround, skip
+ // user_canceled as in TLS 1.2. This matches NSS and OpenSSL.
if (ssl->s3->have_version &&
- ssl_protocol_version(ssl) >= TLS1_3_VERSION) {
+ ssl_protocol_version(ssl) >= TLS1_3_VERSION &&
+ alert_descr != SSL_AD_USER_CANCELLED) {
*out_alert = SSL_AD_DECODE_ERROR;
OPENSSL_PUT_ERROR(SSL, SSL_R_BAD_ALERT);
return ssl_open_record_error;