Repository: rustls/rustls (language: rust)

Issue:
`session_ticket` extension is sent by TLS 1.3 client
I am looking at
https://github.com/rustls/rustls/blob/d1c33f8641c1c69edc27d98047c38f7f852f55eb/rustls/src/client/hs.rs#L587-L592

This code pushes extension 35 (`session_ticket`) defined in https://datatracker.ietf.org/doc/html/rfc5077
This extension has nothing to do with TLS 1.3 session resumption mechanism.
https://www.rfc-editor.org/rfc/rfc8446 never mentions this extension and explicitly deprecated RFC 5077:

> This document supersedes and obsoletes previous versions of TLS,
> including version 1.2 [[RFC5246](https://www.rfc-editor.org/rfc/rfc5246)].  It also obsoletes the TLS ticket
> mechanism defined in [[RFC5077](https://www.rfc-editor.org/rfc/rfc5077)] and replaces it with the mechanism
> defined in [Section 2.2](https://www.rfc-editor.org/rfc/rfc8446#section-2.2).

So it seems this code should be changed like this:
```diff
diff --git a/rustls/src/client/hs.rs b/rustls/src/client/hs.rs
index 9ddad98a..24f9124a 100644
--- a/rustls/src/client/hs.rs
+++ b/rustls/src/client/hs.rs
@@ -584,8 +584,8 @@ fn prepare_resumption<'a>(
     let resuming = match resuming {
         Some(resuming) if !resuming.ticket().is_empty() => resuming,
         _ => {
-            if config.supports_version(ProtocolVersion::TLSv1_3)
-                || config.resumption.tls12_resumption == Tls12Resumption::SessionIdOrTickets
+            if config.supports_version(ProtocolVersion::TLSv1_2)
+                && config.resumption.tls12_resumption == Tls12Resumption::SessionIdOrTickets
             {
                 // If we don't have a ticket, request one.
                 exts.push(ClientExtension::SessionTicket(ClientSessionTicket::Request));
```

Only if TLS 1.2 is enabled and its RFC 5077 is used we should request RFC 5077 ticket.
TLS 1.3 servers should send `new_session_ticket` extension (4) if they support TLS session resumption using new PSK mechanism regardless of whether `session_ticket` extension is sent.


Discussion / hints:

Fix patch:
diff --git a/rustls/src/client/hs.rs b/rustls/src/client/hs.rs
index 9ddad98a701..24f9124a2ea 100644
--- a/rustls/src/client/hs.rs
+++ b/rustls/src/client/hs.rs
@@ -584,8 +584,8 @@ fn prepare_resumption<'a>(
     let resuming = match resuming {
         Some(resuming) if !resuming.ticket().is_empty() => resuming,
         _ => {
-            if config.supports_version(ProtocolVersion::TLSv1_3)
-                || config.resumption.tls12_resumption == Tls12Resumption::SessionIdOrTickets
+            if config.supports_version(ProtocolVersion::TLSv1_2)
+                && config.resumption.tls12_resumption == Tls12Resumption::SessionIdOrTickets
             {
                 // If we don't have a ticket, request one.
                 exts.push(ClientExtension::SessionTicket(ClientSessionTicket::Request));


Test patch:
diff --git a/rustls/tests/api.rs b/rustls/tests/api.rs
index 796ef661f1b..7bace14b549 100644
--- a/rustls/tests/api.rs
+++ b/rustls/tests/api.rs
@@ -6199,6 +6199,35 @@ fn test_server_rejects_clients_without_any_kx_groups() {
     );
 }
 
+/// Tests that session_ticket(35) extension
+/// is not sent if the client does not support TLS 1.2.
+#[test]
+fn test_no_session_ticket_request_on_tls_1_3() {
+    /// Panics if TLS 1.2 session_ticket(35) extension is detected.
+    ///
+    /// Does not actually alter the payload.
+    fn panic_on_session_ticket(msg: &mut Message) -> Altered {
+        if let MessagePayload::Handshake { parsed, encoded: _ } = &msg.payload {
+            if let HandshakePayload::ClientHello(ch) = &parsed.payload {
+                for ext in &ch.extensions {
+                    if matches!(ext, ClientExtension::SessionTicket(_)) {
+                        panic!("TLS 1.2 session_ticket extension in TLS 1.3 handshake detected.");
+                    }
+                }
+            }
+        }
+        Altered::InPlace
+    }
+
+    let client_config =
+        make_client_config_with_versions(KeyType::Rsa2048, &[&rustls::version::TLS13]);
+    let server_config = make_server_config(KeyType::Rsa2048);
+
+    let (client, server) = make_pair_for_configs(client_config, server_config);
+    let (mut client, mut server) = (client.into(), server.into());
+    transfer_altered(&mut client, panic_on_session_ticket, &mut server);
+}
+
 #[test]
 fn test_server_rejects_clients_without_any_kx_group_overlap() {
     for version in rustls::ALL_VERSIONS {