]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
BUG/MINOR: quic-be: missing version negotiation
authorFrederic Lecaille <flecaille@haproxy.com>
Fri, 14 Nov 2025 16:21:53 +0000 (17:21 +0100)
committerFrederic Lecaille <flecaille@haproxy.com>
Fri, 14 Nov 2025 16:37:34 +0000 (17:37 +0100)
This bug impacts only the QUIC clients (or backends). The version negotiation
was not supported at all for them. This is an oversight.

Contrary to the QUIC server which choose the negotiated version after having
received the transport parameters (into ClientHello message) the client selects
the negotiated version from the first Initial packet version field. Indeed, the
server transport parameters are inside the ServerHello messages ciphered
into Handshake packets.

This non intrusive patch does not impact the QUIC server implementation.
It only selects the negotiated version from the first Initial packet
received from the server and consequently initializes the TLS cipher context.

Thank you to @InputOutputZ for having reporte this issue in GH #3178.

No need to backport because the QUIC backends support arrives with 3.3.

src/quic_rx.c

index ec4a0f4e7426f73ad76de9c1916e184e506e5abc..c1dd4d0faf4ab7e8d746b108c2514cc1032e645c 100644 (file)
@@ -2077,6 +2077,28 @@ static int quic_rx_pkt_parse(struct quic_conn *qc, struct quic_rx_packet *pkt,
                                        memcpy(qc->dcid.data, pkt->scid.data, pkt->scid.len);
                                        qc->dcid.len = pkt->scid.len;
                                }
+
+                               /* Identify the negotiated version, chosen and sent by the server */
+                               if (qc_is_back(qc) && pkt->version != qc->original_version && !qc->nictx) {
+                                       qc->nictx = pool_alloc(pool_head_quic_tls_ctx);
+                                       if (!qc->nictx) {
+                                               TRACE_PROTO("Could not alloc a new Initial secrets TLS context",
+                                                           QUIC_EV_CONN_RXPKT, qc);
+                                               goto drop;
+                                       }
+
+                                       quic_tls_ctx_reset(qc->nictx);
+                                       if (!qc_new_isecs(qc, qc->nictx, pkt->version,
+                                                         qc->odcid.data, qc->odcid.len, 0)) {
+                                               TRACE_PROTO("Could not derive Initial secrets for new version",
+                                                           QUIC_EV_CONN_RXPKT, qc);
+                                               goto drop;
+                                       }
+
+                                       TRACE_PROTO("new Initial secrets TLS context initialization done",
+                                                   QUIC_EV_CONN_RXPKT, qc);
+                                       qc->negotiated_version = pkt->version;
+                               }
                        }
                }
                else if (pkt->type == QUIC_PACKET_TYPE_0RTT) {