Enforce that pre_shared_key must come with psk_key_exchange_modes.
Omitting the extension means we'll never issue tickets, but if the
client were to offer a ticket anyway, RFC8446 4.2.9 says we MUST reject
the ClientHello. It's not clear on what alert to use, but
missing_extension is probably appropriate.
Thanks to Ben Kaduk for pointing this out.
Change-Id: Ie5c720eac9dd2e1a27ba8a13c59b707c109eaa4e
Reviewed-on: https://boringssl-review.googlesource.com/c/boringssl/+/46464
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/common.go b/ssl/test/runner/common.go
index f209f4a..34f0fd1 100644
--- a/ssl/test/runner/common.go
+++ b/ssl/test/runner/common.go
@@ -1240,8 +1240,8 @@
// session ticket.
SendEmptySessionTicket bool
- // SendPSKKeyExchangeModes, if present, determines the PSK key exchange modes
- // to send.
+ // SendPSKKeyExchangeModes, if not nil, determines the PSK key exchange
+ // modes to send. If a non-nil empty slice, no extension will be sent.
SendPSKKeyExchangeModes []byte
// ExpectNoNewSessionTicket, if present, means that the client will fail upon
diff --git a/ssl/test/runner/handshake_client.go b/ssl/test/runner/handshake_client.go
index efb8a18..510cbce 100644
--- a/ssl/test/runner/handshake_client.go
+++ b/ssl/test/runner/handshake_client.go
@@ -186,7 +186,7 @@
hello.supportedCurves = nil
}
- if len(c.config.Bugs.SendPSKKeyExchangeModes) != 0 {
+ if c.config.Bugs.SendPSKKeyExchangeModes != nil {
hello.pskKEModes = c.config.Bugs.SendPSKKeyExchangeModes
}
diff --git a/ssl/test/runner/runner.go b/ssl/test/runner/runner.go
index 86974e9..e555f46 100644
--- a/ssl/test/runner/runner.go
+++ b/ssl/test/runner/runner.go
@@ -12169,6 +12169,26 @@
expectResumeRejected: true,
})
+ // Test that the server rejects ClientHellos with pre_shared_key but without
+ // psk_key_exchange_modes.
+ testCases = append(testCases, testCase{
+ testType: serverTest,
+ name: "TLS13-SendNoKEMModesWithPSK-Server",
+ config: Config{
+ MaxVersion: VersionTLS13,
+ },
+ resumeConfig: &Config{
+ MaxVersion: VersionTLS13,
+ Bugs: ProtocolBugs{
+ SendPSKKeyExchangeModes: []byte{},
+ },
+ },
+ resumeSession: true,
+ shouldFail: true,
+ expectedLocalError: "remote error: missing extension",
+ expectedError: ":MISSING_EXTENSION:",
+ })
+
// Test that the client ticket age is sent correctly.
testCases = append(testCases, testCase{
testType: clientTest,
diff --git a/ssl/tls13_server.cc b/ssl/tls13_server.cc
index 6e9cd07..d33afa5 100644
--- a/ssl/tls13_server.cc
+++ b/ssl/tls13_server.cc
@@ -252,6 +252,16 @@
return ssl_ticket_aead_ignore_ticket;
}
+ // Per RFC8446, section 4.2.9, servers MUST abort the handshake if the client
+ // sends pre_shared_key without psk_key_exchange_modes.
+ CBS unused;
+ if (!ssl_client_hello_get_extension(client_hello, &unused,
+ TLSEXT_TYPE_psk_key_exchange_modes)) {
+ *out_alert = SSL_AD_MISSING_EXTENSION;
+ OPENSSL_PUT_ERROR(SSL, SSL_R_MISSING_EXTENSION);
+ return ssl_ticket_aead_error;
+ }
+
CBS ticket, binders;
uint32_t client_ticket_age;
if (!ssl_ext_pre_shared_key_parse_clienthello(