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;