]> git.ipfire.org Git - thirdparty/haproxy.git/commitdiff
MINOR: quic: extend Retry token check function
authorAmaury Denoyelle <adenoyelle@haproxy.com>
Mon, 17 Oct 2022 09:13:07 +0000 (11:13 +0200)
committerAmaury Denoyelle <adenoyelle@haproxy.com>
Wed, 19 Oct 2022 16:45:58 +0000 (18:45 +0200)
On Initial packet reception, token is checked for validity through
quic_retry_token_check() function. However, some related parts were left
in the parent function quic_rx_pkt_retrieve_conn(). Move this code
directly into quic_retry_token_check() to facilitate its call in various
context.

The API of quic_retry_token_check() has also been refactored. Instead of
working on a plain char* buffer, it now uses a quic_rx_packet instance.
This helps to reduce the number of parameters.

This change will allow to check Retry token even if data were received
with a FD-owned quic-conn socket. Indeed, in this case,
quic_rx_pkt_retrieve_conn() call will probably be skipped.

This should be backported up to 2.6.

src/quic_conn.c
src/quic_tp.c

index 7c77bfae0095e3014b88e2b0ece18b66a15e90a9..8b046952498fb6a0c5e0e64014d03fc750d7da85 100644 (file)
@@ -5549,20 +5549,28 @@ static int quic_generate_retry_token(unsigned char *buf, size_t len,
 }
 
 /* QUIC server only function.
- * Check the validity of the Retry token from <token> buffer with <tokenlen>
- * as length. If valid, the ODCID of <qc> QUIC connection will be put
- * into <odcid> connection ID. <dcid> is our side destination connection ID
- * of client source connection ID.
+ *
+ * Check the validity of the Retry token from Initial packet <pkt>. <dgram> is
+ * the UDP datagram containing <pkt> and <l> is the listener instance on which
+ * it was received. If the token is valid, the ODCID of <qc> QUIC connection
+ * will be put into <odcid>. <qc> is used to retrieve the QUIC version needed
+ * to validate the token but it can be NULL : in this case the version will be
+ * retrieved from the packet.
+ *
  * Return 1 if succeeded, 0 if not.
  */
-static int quic_retry_token_check(unsigned char *token, size_t tokenlen,
-                                  const struct quic_version *qv,
-                                  struct quic_cid *odcid,
-                                  const struct quic_cid *dcid,
+
+static int quic_retry_token_check(struct quic_rx_packet *pkt,
+                                  struct quic_dgram *dgram,
+                                  struct listener *l,
                                   struct quic_conn *qc,
-                                  struct sockaddr_storage *addr)
+                                  struct quic_cid *odcid)
 {
+       struct proxy *prx;
+       struct quic_counters *prx_counters;
        int ret = 0;
+       unsigned char *token = pkt->token;
+       const uint64_t tokenlen = pkt->token_len;
        unsigned char buf[128];
        unsigned char aad[sizeof(uint32_t) + sizeof(in_port_t) +
                          sizeof(struct in6_addr) + QUIC_CID_MAXLEN];
@@ -5574,15 +5582,29 @@ static int quic_retry_token_check(unsigned char *token, size_t tokenlen,
        size_t seclen = strlen(global.cluster_secret);
        EVP_CIPHER_CTX *ctx = NULL;
        const EVP_CIPHER *aead = EVP_aes_128_gcm();
+       const struct quic_version *qv = qc ? qc->original_version :
+                                            pkt->version;
 
        TRACE_ENTER(QUIC_EV_CONN_LPKT, qc);
 
+       /* The caller must ensure this. */
+       BUG_ON(!global.cluster_secret || !pkt->token_len);
+
+       prx = l->bind_conf->frontend;
+       prx_counters = EXTRA_COUNTERS_GET(prx->extra_counters_fe, &quic_stats_module);
+
+       if (*pkt->token != QUIC_TOKEN_FMT_RETRY) {
+               /* TODO: New token check */
+               TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT, qc, NULL, NULL, pkt->version);
+               goto leave;
+       }
+
        if (sizeof buf < tokenlen) {
                TRACE_ERROR("too short buffer", QUIC_EV_CONN_LPKT, qc);
                goto err;
        }
 
-       aadlen = quic_generate_retry_token_aad(aad, qv->num, dcid, addr);
+       aadlen = quic_generate_retry_token_aad(aad, qv->num, &pkt->scid, &dgram->saddr);
        salt = token + tokenlen - QUIC_RETRY_TOKEN_SALTLEN;
        if (!quic_tls_derive_retry_token_secret(EVP_sha256(), key, sizeof key, iv, sizeof iv,
                                                salt, QUIC_RETRY_TOKEN_SALTLEN, sec, seclen)) {
@@ -5610,11 +5632,14 @@ static int quic_retry_token_check(unsigned char *token, size_t tokenlen,
        EVP_CIPHER_CTX_free(ctx);
 
        ret = 1;
+       HA_ATOMIC_INC(&prx_counters->retry_validated);
+
  leave:
        TRACE_LEAVE(QUIC_EV_CONN_LPKT, qc);
        return ret;
 
  err:
+       HA_ATOMIC_INC(&prx_counters->retry_error);
        if (ctx)
                EVP_CIPHER_CTX_free(ctx);
        goto leave;
@@ -5936,8 +5961,7 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
                                                    struct quic_dgram *dgram,
                                                    struct listener *l)
 {
-       struct quic_cid odcid;
-       const struct quic_cid *token_odcid = NULL; // ODCID received from client token
+       struct quic_cid token_odcid = { .len = 0 };
        struct quic_conn *qc = NULL;
        struct proxy *prx;
        struct quic_counters *prx_counters;
@@ -5953,27 +5977,8 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
                BUG_ON(!pkt->version); /* This must not happen. */
 
                if (global.cluster_secret && pkt->token_len) {
-                       if (*pkt->token == QUIC_TOKEN_FMT_RETRY) {
-                               const struct quic_version *ver = qc ? qc->original_version : pkt->version;
-                               if (!quic_retry_token_check(pkt->token, pkt->token_len, ver, &odcid,
-                                                           &pkt->scid, qc, &dgram->saddr)) {
-                                       HA_ATOMIC_INC(&prx_counters->retry_error);
-                                       TRACE_PROTO("Wrong retry token",
-                                                   QUIC_EV_CONN_LPKT, qc, NULL, NULL, pkt->version);
-                                       /* TODO: RFC 9000 8.1.2 A server SHOULD immediately close the connection
-                                        * with an INVALID_TOKEN error.
-                                        */
-                                       goto out;
-                               }
-
-                               token_odcid = &odcid;
-                               HA_ATOMIC_INC(&prx_counters->retry_validated);
-                       }
-                       else {
-                               /* TODO: New token check */
-                               TRACE_PROTO("Packet dropped", QUIC_EV_CONN_LPKT, qc, NULL, NULL, pkt->version);
-                               goto out;
-                       }
+                       if (!quic_retry_token_check(pkt, dgram, l, qc, &token_odcid))
+                               goto err;
                }
 
                if (!qc) {
@@ -6008,7 +6013,7 @@ static struct quic_conn *quic_rx_pkt_retrieve_conn(struct quic_rx_packet *pkt,
                        pkt->saddr = dgram->saddr;
                        ipv4 = dgram->saddr.ss_family == AF_INET;
 
-                       qc = qc_new_conn(pkt->version, ipv4, &pkt->dcid, &pkt->scid, token_odcid,
+                       qc = qc_new_conn(pkt->version, ipv4, &pkt->dcid, &pkt->scid, &token_odcid,
                                         &dgram->daddr, &pkt->saddr, 1,
                                         !!pkt->token_len, l);
                        if (qc == NULL)
index bd8a99e8169108515698ba8c850701bdf3e41951..2be6d5150224ebadc478863f4ff8f50314cfd54f 100644 (file)
@@ -657,7 +657,7 @@ int qc_lstnr_params_init(struct quic_conn *qc,
        memcpy(rx_params->stateless_reset_token, stateless_reset_token,
               sizeof rx_params->stateless_reset_token);
        /* Copy original_destination_connection_id transport parameter. */
-       if (token_odcid) {
+       if (token_odcid->len) {
                memcpy(odcid_param->data, token_odcid->data, token_odcid->len);
                odcid_param->len = token_odcid->len;
                /* Copy retry_source_connection_id transport parameter. */