DTLS 1.3 doesn't use EndOfEarlyData

We're nowhere near this doing anything, but may as well.

Bug: 715
Change-Id: I790e690c67b8501fa571e804b2bd20197a2ef028
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/70928
Reviewed-by: Nick Harper <nharper@chromium.org>
Auto-Submit: David Benjamin <davidben@google.com>
Commit-Queue: Bob Beck <bbe@google.com>
Reviewed-by: Bob Beck <bbe@google.com>
diff --git a/ssl/test/runner/common.go b/ssl/test/runner/common.go
index a63b3c7..21c2991 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -759,6 +759,10 @@
 	// EndOfEarlyData.
 	NonEmptyEndOfEarlyData bool
 
+	// SendEndOfEarlyDataInQUICAndDTLS causes the implementation to send
+	// EndOfEarlyData even in QUIC and DTLS, which do not use the message.
+	SendEndOfEarlyDataInQUICAndDTLS bool
+
 	// SkipCertificateVerify, if true causes peer to skip sending a
 	// CertificateVerify message after the Certificate message.
 	SkipCertificateVerify bool
diff --git a/ssl/test/runner/conn.go b/ssl/test/runner/conn.go
index 1237305..29ac87d 100644
--- a/ssl/test/runner/conn.go
+++ b/ssl/test/runner/conn.go
@@ -2181,3 +2181,10 @@
 	_, err := c.conn.Write(payload)
 	return err
 }
+
+func (c *Conn) usesEndOfEarlyData() bool {
+	if c.isClient && c.config.Bugs.SendEndOfEarlyDataInQUICAndDTLS {
+		return true
+	}
+	return c.config.Bugs.MockQUICTransport == nil && !c.isDTLS
+}
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index e54e284..96fd335 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -1381,7 +1381,7 @@
 
 	// Send EndOfEarlyData and then switch write key to handshake
 	// traffic key.
-	if encryptedExtensions.extensions.hasEarlyData && !c.config.Bugs.SkipEndOfEarlyData && c.config.Bugs.MockQUICTransport == nil {
+	if encryptedExtensions.extensions.hasEarlyData && !c.config.Bugs.SkipEndOfEarlyData && c.usesEndOfEarlyData() {
 		if c.config.Bugs.SendStrayEarlyHandshake {
 			helloRequest := new(helloRequestMsg)
 			c.writeRecord(recordTypeHandshake, helloRequest.marshal())
diff --git a/ssl/test/runner/handshake_server.go b/ssl/test/runner/handshake_server.go
index 9265edd..177d715 100644
--- a/ssl/test/runner/handshake_server.go
+++ b/ssl/test/runner/handshake_server.go
@@ -1247,7 +1247,7 @@
 	}
 
 	// Read end_of_early_data.
-	if encryptedExtensions.extensions.hasEarlyData && config.Bugs.MockQUICTransport == nil {
+	if encryptedExtensions.extensions.hasEarlyData && c.usesEndOfEarlyData() {
 		msg, err := c.readHandshake()
 		if err != nil {
 			return err
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 481a65c..78e3aa7 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -15316,7 +15316,7 @@
 		},
 	})
 
-	// Test that the server errors on 0-RTT streams without end_of_early_data.
+	// Test that the server errors on 0-RTT streams without EndOfEarlyData.
 	// The subsequent records should fail to decrypt.
 	testCases = append(testCases, testCase{
 		testType: serverTest,
@@ -15334,6 +15334,28 @@
 		expectedError:      ":BAD_DECRYPT:",
 	})
 
+	// Test that EndOfEarlyData is rejected in QUIC. Since we leave application
+	// data to the QUIC implementation, we never accept any data at all in
+	// the 0-RTT epoch, so the error is that the encryption level is rejected
+	// outright.
+	//
+	// TODO(crbug.com/42290594): Test this for DTLS 1.3 as well.
+	testCases = append(testCases, testCase{
+		protocol: quic,
+		testType: serverTest,
+		name:     "EarlyData-UnexpectedEndOfEarlyData-QUIC",
+		config: Config{
+			MaxVersion: VersionTLS13,
+			Bugs: ProtocolBugs{
+				SendEndOfEarlyDataInQUICAndDTLS: true,
+			},
+		},
+		resumeSession: true,
+		earlyData:     true,
+		shouldFail:    true,
+		expectedError: ":WRONG_ENCRYPTION_LEVEL_RECEIVED:",
+	})
+
 	// Test that the server errors on 0-RTT streams with a stray handshake
 	// message in them.
 	testCases = append(testCases, testCase{
diff --git a/ssl/tls13_client.cc b/ssl/tls13_client.cc
index 95e2e39..78aa246 100644
--- a/ssl/tls13_client.cc
+++ b/ssl/tls13_client.cc
@@ -795,8 +795,9 @@
   SSL *const ssl = hs->ssl;
 
   if (ssl->s3->early_data_accepted) {
-    // QUIC omits the EndOfEarlyData message. See RFC 9001, section 8.3.
-    if (ssl->quic_method == nullptr) {
+    // DTLS and QUIC omit the EndOfEarlyData message. See RFC 9001, section 8.3,
+    // and RFC 9147, section 5.6.
+    if (ssl->quic_method == nullptr && !SSL_is_dtls(ssl)) {
       ScopedCBB cbb;
       CBB body;
       if (!ssl->method->init_message(ssl, cbb.get(), &body,
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc
index 932c82c..c82fdea 100644
--- a/ssl/tls13_server.cc
+++ b/ssl/tls13_server.cc
@@ -1011,6 +1011,12 @@
   return ssl_hs_flush;
 }
 
+static bool uses_end_of_early_data(const SSL *ssl) {
+  // DTLS and QUIC omit the EndOfEarlyData message. See RFC 9001, section 8.3,
+  // and RFC 9147, section 5.6.
+  return ssl->quic_method == nullptr && !SSL_is_dtls(ssl);
+}
+
 static enum ssl_hs_wait_t do_read_second_client_flight(SSL_HANDSHAKE *hs) {
   SSL *const ssl = hs->ssl;
   if (ssl->s3->early_data_accepted) {
@@ -1024,9 +1030,9 @@
     hs->in_early_data = true;
   }
 
-  // QUIC doesn't use an EndOfEarlyData message (RFC 9001, section 8.3), so we
-  // switch to client_handshake_secret before the early return.
-  if (ssl->quic_method != nullptr) {
+  // If the EndOfEarlyData message is not used, switch to
+  // client_handshake_secret before the early return.
+  if (!uses_end_of_early_data(ssl)) {
     if (!tls13_set_traffic_key(ssl, ssl_encryption_handshake, evp_aead_open,
                                hs->new_session.get(),
                                hs->client_handshake_secret())) {
@@ -1045,7 +1051,7 @@
   SSL *const ssl = hs->ssl;
   // In protocols that use EndOfEarlyData, we must consume the extra message and
   // switch to client_handshake_secret after the early return.
-  if (ssl->quic_method == nullptr) {
+  if (uses_end_of_early_data(ssl)) {
     // If early data was not accepted, the EndOfEarlyData will be in the
     // discarded early data.
     if (hs->ssl->s3->early_data_accepted) {