]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: Make xprt support 0-RTT.
authorFrédéric Lécaille <flecaille@haproxy.com>
Tue, 14 Dec 2021 18:44:14 +0000 (19:44 +0100)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Fri, 17 Dec 2021 07:38:43 +0000 (08:38 +0100)
A client sends a 0-RTT data packet after an Initial one in the same datagram.
We must be able to parse such packets just after having parsed the Initial packets.

include/haproxy/quic_tls.h
src/xprt_quic.c

index 47946cc22d5b5fdad6cbeca8f7ed83339e73d851..209576a4e14f8eb8486010f68cd48bdd13068021 100644 (file)
@@ -423,13 +423,16 @@ static inline int quic_tls_level_pkt_type(enum quic_tls_enc_level level)
 /* Set <*level> and <*next_level> depending on <state> QUIC handshake state. */
 static inline int quic_get_tls_enc_levels(enum quic_tls_enc_level *level,
                                           enum quic_tls_enc_level *next_level,
-                                          enum quic_handshake_state state)
+                                          enum quic_handshake_state state, int zero_rtt)
 {
        switch (state) {
        case QUIC_HS_ST_SERVER_INITIAL:
        case QUIC_HS_ST_CLIENT_INITIAL:
                *level = QUIC_TLS_ENC_LEVEL_INITIAL;
-               *next_level = QUIC_TLS_ENC_LEVEL_HANDSHAKE;
+               if (zero_rtt)
+                       *next_level = QUIC_TLS_ENC_LEVEL_EARLY_DATA;
+               else
+                       *next_level = QUIC_TLS_ENC_LEVEL_HANDSHAKE;
                break;
        case QUIC_HS_ST_SERVER_HANDSHAKE:
        case QUIC_HS_ST_CLIENT_HANDSHAKE:
index b4669dba757c8db4c81b87a67a2e1f3a89df74ab..0dfd1082bd3a5d0b23a61bfa9e38c3f9886ae348 100644 (file)
@@ -2415,7 +2415,7 @@ static int qc_prep_pkts(struct qring *qr, struct ssl_sock_ctx *ctx)
 
        TRACE_ENTER(QUIC_EV_CONN_PHPKTS, ctx->conn);
        qc = ctx->conn->qc;
-       if (!quic_get_tls_enc_levels(&tel, &next_tel, HA_ATOMIC_LOAD(&qc->state))) {
+       if (!quic_get_tls_enc_levels(&tel, &next_tel, HA_ATOMIC_LOAD(&qc->state), 0)) {
                TRACE_DEVEL("unknown enc. levels", QUIC_EV_CONN_PHPKTS, ctx->conn);
                goto err;
        }
@@ -3082,7 +3082,7 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
        struct quic_enc_level *qel, *next_qel;
        struct quic_tls_ctx *tls_ctx;
        struct qring *qr; // Tx ring
-       int prev_st, st, force_ack;
+       int prev_st, st, force_ack, zero_rtt;
 
        ctx = context;
        qc = ctx->conn->qc;
@@ -3090,8 +3090,9 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
        st = HA_ATOMIC_LOAD(&qc->state);
        TRACE_ENTER(QUIC_EV_CONN_HDSHK, ctx->conn, &st);
        ssl_err = SSL_ERROR_NONE;
+       zero_rtt = !MT_LIST_ISEMPTY(&qc->els[QUIC_TLS_ENC_LEVEL_EARLY_DATA].rx.pqpkts);
  start:
-       if (!quic_get_tls_enc_levels(&tel, &next_tel, st))
+       if (!quic_get_tls_enc_levels(&tel, &next_tel, st, zero_rtt))
                goto err;
 
        qel = &qc->els[tel];
@@ -3113,6 +3114,13 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
        if (!qc_treat_rx_pkts(qel, next_qel, ctx, force_ack))
                goto err;
 
+       if (zero_rtt && next_qel && !MT_LIST_ISEMPTY(&next_qel->rx.pqpkts) &&
+           (next_qel->tls_ctx.rx.flags & QUIC_FL_TLS_SECRETS_SET)) {
+               qel = next_qel;
+               next_qel = NULL;
+               goto next_level;
+       }
+
        st = HA_ATOMIC_LOAD(&qc->state);
        if (st >= QUIC_HS_ST_COMPLETE &&
            (prev_st == QUIC_HS_ST_SERVER_INITIAL || prev_st == QUIC_HS_ST_SERVER_HANDSHAKE)) {
@@ -3466,7 +3474,9 @@ static inline int quic_packet_read_long_header(unsigned char **buf, const unsign
                /* Check that the length of this received DCID matches the CID lengths
                 * of our implementation for non Initials packets only.
                 */
-               if (pkt->type != QUIC_PACKET_TYPE_INITIAL && dcid_len != QUIC_CID_LEN)
+               if (pkt->type != QUIC_PACKET_TYPE_INITIAL &&
+                   pkt->type != QUIC_PACKET_TYPE_0RTT &&
+                   dcid_len != QUIC_CID_LEN)
                        return 0;
 
                memcpy(pkt->dcid.data, *buf, dcid_len);
@@ -3929,7 +3939,8 @@ static ssize_t qc_lstnr_pkt_rcv(unsigned char **buf, const unsigned char *end,
                /* For Initial packets, and for servers (QUIC clients connections),
                 * there is no Initial connection IDs storage.
                 */
-               if (pkt->type == QUIC_PACKET_TYPE_INITIAL) {
+               if (pkt->type == QUIC_PACKET_TYPE_INITIAL ||
+                   pkt->type == QUIC_PACKET_TYPE_0RTT) {
                        uint64_t token_len;
                        /* DCIDs of first packets coming from clients may have the same values.
                         * Let's distinguish them concatenating the socket addresses to the DCIDs.
@@ -3937,20 +3948,22 @@ static ssize_t qc_lstnr_pkt_rcv(unsigned char **buf, const unsigned char *end,
                        quic_cid_saddr_cat(&pkt->dcid, saddr);
                        cids = &l->rx.odcids;
 
-                       if (!quic_dec_int(&token_len, (const unsigned char **)buf, end) ||
-                           end - *buf < token_len) {
-                               TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT);
-                               goto err;
-                       }
+                       if (pkt->type == QUIC_PACKET_TYPE_INITIAL) {
+                               if (!quic_dec_int(&token_len, (const unsigned char **)buf, end) ||
+                                       end - *buf < token_len) {
+                                       TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT);
+                                       goto err;
+                               }
 
-                       /* XXX TO DO XXX 0 value means "the token is not present".
-                        * A server which sends an Initial packet must not set the token.
-                        * So, a client which receives an Initial packet with a token
-                        * MUST discard the packet or generate a connection error with
-                        * PROTOCOL_VIOLATION as type.
-                        * The token must be provided in a Retry packet or NEW_TOKEN frame.
-                        */
-                       pkt->token_len = token_len;
+                               /* XXX TO DO XXX 0 value means "the token is not present".
+                                * A server which sends an Initial packet must not set the token.
+                                * So, a client which receives an Initial packet with a token
+                                * MUST discard the packet or generate a connection error with
+                                * PROTOCOL_VIOLATION as type.
+                                * The token must be provided in a Retry packet or NEW_TOKEN frame.
+                                */
+                               pkt->token_len = token_len;
+                       }
                }
                else {
                        if (pkt->dcid.len != QUIC_CID_LEN) {
@@ -4069,7 +4082,8 @@ static ssize_t qc_lstnr_pkt_rcv(unsigned char **buf, const unsigned char *end,
                        node = &qc->odcid_node;
                }
                else {
-                       if (pkt->type == QUIC_PACKET_TYPE_INITIAL && cids == &l->rx.odcids) {
+                       if ((pkt->type == QUIC_PACKET_TYPE_INITIAL ||
+                            pkt->type == QUIC_PACKET_TYPE_0RTT) && cids == &l->rx.odcids) {
                                qc = ebmb_entry(node, struct quic_conn, odcid_node);
                        }
                        else {