{"id":2215695,"url":"http://patchwork.ozlabs.org/api/patches/2215695/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-cifs-client/patch/d86910330339da257534ad93db71949176961522.1774410440.git.lucien.xin@gmail.com/","project":{"id":12,"url":"http://patchwork.ozlabs.org/api/projects/12/?format=json","name":"Linux CIFS Client","link_name":"linux-cifs-client","list_id":"linux-cifs.vger.kernel.org","list_email":"linux-cifs@vger.kernel.org","web_url":"","scm_url":"","webscm_url":"","list_archive_url":"","list_archive_url_format":"","commit_url_format":""},"msgid":"<d86910330339da257534ad93db71949176961522.1774410440.git.lucien.xin@gmail.com>","list_archive_url":null,"date":"2026-03-25T03:47:17","name":"[net-next,v11,12/15] quic: add crypto packet encryption and decryption","commit_ref":null,"pull_url":null,"state":"new","archived":false,"hash":"9cf1b78793589431dabff68023667de3276d18ee","submitter":{"id":61073,"url":"http://patchwork.ozlabs.org/api/people/61073/?format=json","name":"Xin Long","email":"lucien.xin@gmail.com"},"delegate":null,"mbox":"http://patchwork.ozlabs.org/project/linux-cifs-client/patch/d86910330339da257534ad93db71949176961522.1774410440.git.lucien.xin@gmail.com/mbox/","series":[{"id":497380,"url":"http://patchwork.ozlabs.org/api/series/497380/?format=json","web_url":"http://patchwork.ozlabs.org/project/linux-cifs-client/list/?series=497380","date":"2026-03-25T03:47:06","name":"net: introduce QUIC infrastructure and core subcomponents","version":11,"mbox":"http://patchwork.ozlabs.org/series/497380/mbox/"}],"comments":"http://patchwork.ozlabs.org/api/patches/2215695/comments/","check":"pending","checks":"http://patchwork.ozlabs.org/api/patches/2215695/checks/","tags":{},"related":[],"headers":{"Return-Path":"\n <linux-cifs+bounces-10514-incoming=patchwork.ozlabs.org@vger.kernel.org>","X-Original-To":["incoming@patchwork.ozlabs.org","linux-cifs@vger.kernel.org"],"Delivered-To":"patchwork-incoming@legolas.ozlabs.org","Authentication-Results":["legolas.ozlabs.org;\n\tdkim=pass (2048-bit key;\n unprotected) header.d=gmail.com header.i=@gmail.com header.a=rsa-sha256\n header.s=20251104 header.b=SBRxoucZ;\n\tdkim-atps=neutral","legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=104.64.211.4; helo=sin.lore.kernel.org;\n envelope-from=linux-cifs+bounces-10514-incoming=patchwork.ozlabs.org@vger.kernel.org;\n receiver=patchwork.ozlabs.org)","smtp.subspace.kernel.org;\n\tdkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=\"SBRxoucZ\"","smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.160.180","smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com","smtp.subspace.kernel.org;\n spf=pass smtp.mailfrom=gmail.com"],"Received":["from sin.lore.kernel.org (sin.lore.kernel.org [104.64.211.4])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4fgY116l5Pz1y1G\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 25 Mar 2026 14:53:41 +1100 (AEDT)","from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby sin.lore.kernel.org (Postfix) with ESMTP id 429ED3042A1F\n\tfor <incoming@patchwork.ozlabs.org>; Wed, 25 Mar 2026 03:50:01 +0000 (UTC)","from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 2826E2DECCB;\n\tWed, 25 Mar 2026 03:49:57 +0000 (UTC)","from mail-qt1-f180.google.com (mail-qt1-f180.google.com\n [209.85.160.180])\n\t(using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits))\n\t(No client certificate requested)\n\tby smtp.subspace.kernel.org (Postfix) with ESMTPS id EDC912D780E\n\tfor <linux-cifs@vger.kernel.org>; Wed, 25 Mar 2026 03:49:54 +0000 (UTC)","by mail-qt1-f180.google.com with SMTP id\n d75a77b69052e-50b392f1846so74139001cf.3\n        for <linux-cifs@vger.kernel.org>;\n Tue, 24 Mar 2026 20:49:54 -0700 (PDT)","from wsfd-netdev58.anl.eng.rdu2.dc.redhat.com ([66.187.232.140])\n        by smtp.gmail.com with ESMTPSA id\n d75a77b69052e-50b36cb2e29sm150093001cf.1.2026.03.24.20.49.51\n        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n        Tue, 24 Mar 2026 20:49:52 -0700 (PDT)"],"ARC-Seal":"i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1774410597; cv=none;\n b=P52vpo/MM8Wuk9RnYClgO8PK/rvn67XED/2fbeFf6eiTTNajDrWI1G2i4/yIJP6WfgP58+AFYdrjVF/nEy7MFkdtSz8tvgSAt2chxN67ZPJ41MbroNTcEH5wYlj8LLNMzI2RAMhJYxxlG1Exl7zQEvS+vHD2W44eeOPEr+ExUZI=","ARC-Message-Signature":"i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1774410597; c=relaxed/simple;\n\tbh=U6CmJkkOb65dP+2WZX0yooM/zJ4KvM1zrcnOI2YDLF4=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=jSk2Q2jm8k4aIpt0Ocuco7ROAwd/2S12E0TC2Gb5zv4MqIligvCRZIAVa8H1yKkRv06jrkE1GlKphA32b+PjKBlUNu6me7C6UdOoOovWvMHHOVa6dirjVqIHPjn8aQ05lIHGtIAevH+mRwIrMgxZ9h6oQhuVKo8UXvnz1wDxFL4=","ARC-Authentication-Results":"i=1; smtp.subspace.kernel.org;\n dmarc=pass (p=none dis=none) header.from=gmail.com;\n spf=pass smtp.mailfrom=gmail.com;\n dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com\n header.b=SBRxoucZ; arc=none smtp.client-ip=209.85.160.180","DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=gmail.com; s=20251104; t=1774410594; x=1775015394;\n darn=vger.kernel.org;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:from:to:cc:subject:date\n         :message-id:reply-to;\n        bh=hJ3NZXRQOFtAvpeL/rsa7vkoA2TLpksMEO6d4RIQ5FQ=;\n        b=SBRxoucZEDl9iUuqWNNUu8ufz1iU2/7bVhXPRh9mtC0PAcUuWBTpzC1ZCPYeZ5QISt\n         ODPEy0Wyqi8GIykVLhf7DR+3iSCMcYrZSXaOfulCvZajY2hGE+cQ7wisovxC58z3wWuV\n         GPntlZSGKe77uHIg9uaU5Nf4zx02Blroo/NRBsbnPlK/AQ1YzXtEnV/ek5IUYNAfSe07\n         DUrqTuuMRBjgwyZoXI23OgBzGmI1M/DbfI3KAG3aE6cmCQrXiGg1Rq6sxj2qEHX0MrL7\n         LF3a//yxw+AfmbUcv5ZnsdPSSLnCbat0dl98yWdUo10KjtGZ8kyJCzUKTk3SsvEUiM/4\n         Vm2g==","X-Google-DKIM-Signature":"v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=1e100.net; s=20251104; t=1774410594; x=1775015394;\n        h=content-transfer-encoding:mime-version:references:in-reply-to\n         :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from\n         :to:cc:subject:date:message-id:reply-to;\n        bh=hJ3NZXRQOFtAvpeL/rsa7vkoA2TLpksMEO6d4RIQ5FQ=;\n        b=tCxBxAFUxGjm/FPYu7o80GAavikphpRRsg4QJD0gsJhGPPDbaBKBx/y9dgvvrjmVbO\n         BJW7amnF1W8uu/ojbDIiUWfXY9PRvm6yuCeedvs6zac4xRHxALyaqIUd6CzKKBLGe+yh\n         p4gth1dkRqTB9UA8uFlhUvjEVzIcBg2F+GX/HyNmqwKV0oNDdfhZpNJNSHkqsKyJL2/y\n         AL1qR5MeoFRDuBKdV6pmVNv+jGZSPuS9kd+FvDT4VJVyb7ucevlkIeoD+s+pL66cX8Sl\n         bGw0l+7+yF1+q+fdGN3EVh9hiIzCPc3KTSnfPy8/5Vt6DtCokDOmqEKS7QsaAWg2Cn9b\n         F7Ow==","X-Forwarded-Encrypted":"i=1;\n AJvYcCUnXcBrou8pFRdMDe0y8zatTyt7zLBv16GjA1r4BhOrBFRNYsvsjKzkwg+ffvymK/4HEkhxzcr8WJkk@vger.kernel.org","X-Gm-Message-State":"AOJu0YxQxjNfyQTR3WFzCxxAV+mkY7Zk831G7bfZYtX/jvlq2S9Jss7+\n\tyex5p7K8UXj7F2GCb7HX7JIpRf1mZEmm2TOCpPpFiGYi0nKgOf6/zSGk","X-Gm-Gg":"ATEYQzx88JtIujvFRVnVfxZqBx/YlMxjJngCXGQri0cLtQ9/R16TsqZSeUs2eXXVC7Q\n\txzoF8OJIferpehP1tpZHIycLWQCanYs89XgvqhUxoAH0pGDAdpp74TDZ8u1oNt89lG1GlzEEW2W\n\t/MgdqAb4BvsCuHW92mncF0/tsCYPQSxm6xMz20Lcvqybjl3ygsCSqhu+4iKQH9PijTa1GGUPvgr\n\tnjE+o7QAhe5jRq9Q2vLZrCliUjZtAEABbgoye4kEK03je6KQc6IyDBniBdMUQG+Z6qUP5+TA0Ym\n\tXwBSN/M8qD2XZiIkVB4Drqz1d3KuqHkyow+u0omMT2y7y8h4K5RsDPGtOxXzga4m2gJXLXaMOZY\n\tn2EfQu6gi2xfeY4bKIgaHGikwRLYs2oM13oMQ1UZyRrj+a2Ebw+duFBG4NmlSDXad3OfOOghXBO\n\t6A43TeYegmfd3SZjdHj+YuOQLCKhtCONlpKM2ZbSBFNnUr+FcK0x1fV7OK7DsXYM5YKS1dPYfse\n\tI+bE6TGwqLnz3bgBgZyqDn+/492rZA0ezNvphaTTEb8pMB/5lpCOFujIFQiSWTTlDH0VMJUT7qK","X-Received":"by 2002:a05:622a:8355:b0:50b:47ae:8abd with SMTP id\n d75a77b69052e-50b80c8797fmr25344741cf.2.1774410593672;\n        Tue, 24 Mar 2026 20:49:53 -0700 (PDT)","From":"Xin Long <lucien.xin@gmail.com>","To":"network dev <netdev@vger.kernel.org>,\n\tquic@lists.linux.dev","Cc":"davem@davemloft.net,\n\tkuba@kernel.org,\n\tEric Dumazet <edumazet@google.com>,\n\tPaolo Abeni <pabeni@redhat.com>,\n\tSimon Horman <horms@kernel.org>,\n\tStefan Metzmacher <metze@samba.org>,\n\tMoritz Buhl <mbuhl@openbsd.org>,\n\tTyler Fanelli <tfanelli@redhat.com>,\n\tPengtao He <hepengtao@xiaomi.com>,\n\tThomas Dreibholz <dreibh@simula.no>,\n\tlinux-cifs@vger.kernel.org,\n\tSteve French <smfrench@gmail.com>,\n\tNamjae Jeon <linkinjeon@kernel.org>,\n\tPaulo Alcantara <pc@manguebit.com>,\n\tTom Talpey <tom@talpey.com>,\n\tkernel-tls-handshake@lists.linux.dev,\n\tChuck Lever <chuck.lever@oracle.com>,\n\tJeff Layton <jlayton@kernel.org>,\n\tSteve Dickson <steved@redhat.com>,\n\tHannes Reinecke <hare@suse.de>,\n\tAlexander Aring <aahringo@redhat.com>,\n\tDavid Howells <dhowells@redhat.com>,\n\tMatthieu Baerts <matttbe@kernel.org>,\n\tJohn Ericson <mail@johnericson.me>,\n\tCong Wang <xiyou.wangcong@gmail.com>,\n\t\"D . Wythe\" <alibuda@linux.alibaba.com>,\n\tJason Baron <jbaron@akamai.com>,\n\tilliliti <illiliti@protonmail.com>,\n\tSabrina Dubroca <sd@queasysnail.net>,\n\tMarcelo Ricardo Leitner <marcelo.leitner@gmail.com>,\n\tDaniel Stenberg <daniel@haxx.se>,\n\tAndy Gospodarek <andrew.gospodarek@broadcom.com>,\n\t\"Marc E . Fiuczynski\" <marc@fiuczynski.com>","Subject":"[PATCH net-next v11 12/15] quic: add crypto packet encryption and\n decryption","Date":"Tue, 24 Mar 2026 23:47:17 -0400","Message-ID":"\n <d86910330339da257534ad93db71949176961522.1774410440.git.lucien.xin@gmail.com>","X-Mailer":"git-send-email 2.47.1","In-Reply-To":"<cover.1774410440.git.lucien.xin@gmail.com>","References":"<cover.1774410440.git.lucien.xin@gmail.com>","Precedence":"bulk","X-Mailing-List":"linux-cifs@vger.kernel.org","List-Id":"<linux-cifs.vger.kernel.org>","List-Subscribe":"<mailto:linux-cifs+subscribe@vger.kernel.org>","List-Unsubscribe":"<mailto:linux-cifs+unsubscribe@vger.kernel.org>","MIME-Version":"1.0","Content-Transfer-Encoding":"8bit"},"content":"This patch adds core support for packet-level encryption and decryption\nusing AEAD, including both payload protection and QUIC header protection.\nIt introduces helpers to encrypt packets before transmission and to\nremove header protection and decrypt payloads upon reception, in line\nwith QUIC's cryptographic requirements.\n\n- quic_crypto_encrypt(): Perform header protection and payload\n  encryption (TX).\n\n- quic_crypto_decrypt(): Perform header protection removal and\n  payload decryption (RX).\n\nThe patch also includes support for Retry token handling. It provides\nhelpers to compute the Retry integrity tag, generate tokens for address\nvalidation, and verify tokens received from clients during the\nhandshake phase.\n\n- quic_crypto_get_retry_tag(): Compute tag for Retry packets.\n\n- quic_crypto_generate_token(): Generate retry token.\n\n- quic_crypto_verify_token(): Verify retry token.\n\nThese additions establish the cryptographic primitives necessary for\nsecure QUIC packet exchange and address validation.\n\nSigned-off-by: Xin Long <lucien.xin@gmail.com>\n---\nv3:\n  - quic_crypto_decrypt(): return -EKEYREVOKED to defer key updates to\n    the workqueue when the packet is not marked backlog, since\n    quic_crypto_key_update()/crypto_aead_setkey() must run in process\n    context.\n  - Only perform header decryption if !cb->number_len to avoid double\n    decryption when a key-update packet (with flipped key_phase)\n    re-enters quic_crypto_decrypt() from the workqueue.\nv4:\n  - skb_dst_force() is already called in in quic_udp_rcv() on recv path,\n    so remove its call from quic_crypto_payload_decrypt(), which may be\n    called without RCU protection.\n  - Remove the incorrect (void *) cast to quic_crypto_done.\nv5:\n  - Use skb_cb->crypto_ctx for async crypto context freeing, which is\n    safer than using skb_shinfo(skb)->destructor_arg.\n  - skb_cb->number_max is removed and number is reused as the largest\n    previously seen and update quic_crypto_get_header() accordingly.\n  - Change timestamp variables from u32 to u64 and use quic_ktime_get_us()\n    for current timestamps, as jiffies_to_usecs() is not accurate enough.\nv6:\n  - Rename quic_crypto_get_header() to quic_crypto_get_number(), move\n    key_phase parsing out of it, check cb->length when parsing packet\n    number, and update all callers.\n  - Use hdr->pnl + 1 instead of (*p & QUIC_PN_LEN_BITS_MASK) + 1 to get\n    packet number length, and remove the unnecessary the len variable\n    and QUIC_PN_LEN_BITS_MASK macro from quic_crypto_header_decrypt().\nv8:\n  - Move skb_cow_data() from quic_crypto_payload_decrypt() to\n    quic_crypto_header_decrypt(), as header decryption also writes to\n    the skb and is invoked earlier than payload decryption on RX path.\nv10:\n  - Fix double period at end of the comment for quic_crypto_encrypt().\nv11:\n  - Note for AI review: call quic_crypto_aead_mem_alloc() after\n    skb_cow_data() as it uses the return value for nsg. If the allocation\n    fails, skb is dropped, so no rollback of prior skb modifications is\n    needed.\n  - Set maximum line length to 80 characters.\n  - Add a check for skb->len in quic_crypto_get_retry_tag().\n  - Also reset key_update_send_time when key_pending is cleared in\n    quic_crypto_decrypt().\n  - Handle -EBUSY returned from crypto_aead_en/decrypt() and return when\n    err == -EINPROGRESS in quic_crypto_done().\n  - Extract quic_crypto_token_init() from quic_crypto_generate_token() and\n    quic_crypto_verify_token().\n  - Merge quic_crypto_header_en/decrypt() to quic_crypto_header_protect()\n    with an extra parameter to reduce code duplication.\n  - Merge quic_crypto_payload_en/decrypt() to quic_crypto_payload_protect()\n    with an extra parameter to reduce code duplication (noted by AI\n    review).\n---\n net/quic/crypto.c | 638 ++++++++++++++++++++++++++++++++++++++++++++++\n net/quic/crypto.h |  12 +\n 2 files changed, 650 insertions(+)","diff":"diff --git a/net/quic/crypto.c b/net/quic/crypto.c\nindex 218d3fe49dff..5b0a74e9d8ac 100644\n--- a/net/quic/crypto.c\n+++ b/net/quic/crypto.c\n@@ -194,6 +194,275 @@ static int quic_crypto_keys_derive_and_install(struct quic_crypto *crypto,\n \treturn err;\n }\n \n+static void *quic_crypto_skcipher_mem_alloc(struct crypto_skcipher *tfm,\n+\t\t\t\t\t    u32 mask_size, u8 **iv,\n+\t\t\t\t\t    struct skcipher_request **req)\n+{\n+\tunsigned int iv_size, req_size;\n+\tunsigned int len;\n+\tu8 *mem;\n+\n+\tiv_size = crypto_skcipher_ivsize(tfm);\n+\treq_size = sizeof(**req) + crypto_skcipher_reqsize(tfm);\n+\n+\tlen = mask_size;\n+\tlen += iv_size;\n+\tlen += crypto_skcipher_alignmask(tfm) &\n+\t       ~(crypto_tfm_ctx_alignment() - 1);\n+\tlen = ALIGN(len, crypto_tfm_ctx_alignment());\n+\tlen += req_size;\n+\n+\tmem = kzalloc(len, GFP_ATOMIC);\n+\tif (!mem)\n+\t\treturn NULL;\n+\n+\t*iv = (u8 *)PTR_ALIGN(mem + mask_size,\n+\t\t\t      crypto_skcipher_alignmask(tfm) + 1);\n+\t*req = (struct skcipher_request *)PTR_ALIGN(*iv + iv_size,\n+\t\t\tcrypto_tfm_ctx_alignment());\n+\n+\treturn (void *)mem;\n+}\n+\n+/* Extracts and reconstructs the packet number from an incoming QUIC packet. */\n+static int quic_crypto_get_number(struct sk_buff *skb)\n+{\n+\tstruct quic_skb_cb *cb = QUIC_SKB_CB(skb);\n+\ts64 number_max = cb->number;\n+\tu32 len = cb->length;\n+\tu8 *p;\n+\n+\t/* rfc9000#section-17.1:\n+\t *\n+\t * Once header protection is removed, the packet number is decoded by\n+\t * finding the packet number value that is closest to the next expected\n+\t * packet. The next expected packet is the highest received packet\n+\t * number plus one.\n+\t */\n+\tp = (u8 *)quic_hdr(skb) + cb->number_offset;\n+\tif (!quic_get_int(&p, &len, &cb->number, cb->number_len))\n+\t\treturn -EINVAL;\n+\tcb->number = quic_get_num(number_max, cb->number, cb->number_len);\n+\treturn 0;\n+}\n+\n+#define QUIC_SAMPLE_LEN\t\t16\n+\n+#define QUIC_HEADER_FORM_BIT\t0x80\n+#define QUIC_LONG_HEADER_MASK\t0x0f\n+#define QUIC_SHORT_HEADER_MASK\t0x1f\n+\n+/* Header Protection. */\n+static int quic_crypto_header_protect(struct crypto_skcipher *tfm,\n+\t\t\t\t      struct sk_buff *skb, bool chacha,\n+\t\t\t\t      bool enc)\n+{\n+\tstruct quic_skb_cb *cb = QUIC_SKB_CB(skb);\n+\tstruct skcipher_request *req;\n+\tu8 *mask, *iv, *p, h_mask;\n+\tstruct sk_buff *trailer;\n+\tstruct scatterlist sg;\n+\tint err, i;\n+\n+\tif (!enc) {\n+\t\tif (cb->length < QUIC_PN_MAX_LEN + QUIC_SAMPLE_LEN)\n+\t\t\treturn -EINVAL;\n+\n+\t\terr = skb_cow_data(skb, 0, &trailer);\n+\t\tif (err < 0)\n+\t\t\treturn err;\n+\t}\n+\n+\tmask = quic_crypto_skcipher_mem_alloc(tfm, QUIC_SAMPLE_LEN, &iv, &req);\n+\tif (!mask)\n+\t\treturn -ENOMEM;\n+\n+\t/* rfc9001#section-5.4.2: Header Protection Sample:\n+\t *\n+\t *   # pn_offset is the start of the Packet Number field.\n+\t *   sample_offset = pn_offset + 4\n+\t *\n+\t *   sample = packet[sample_offset..sample_offset+sample_length]\n+\t *\n+\t * rfc9001#section-5.4.3: AES-Based Header Protection:\n+\t *\n+\t *   header_protection(hp_key, sample):\n+\t *     mask = AES-ECB(hp_key, sample)\n+\t *\n+\t * rfc9001#section-5.4.4: ChaCha20-Based Header Protection:\n+\t *\n+\t *   header_protection(hp_key, sample):\n+\t *     counter = sample[0..3]\n+\t *     nonce = sample[4..15]\n+\t *     mask = ChaCha20(hp_key, counter, nonce, {0,0,0,0,0})\n+\t */\n+\tp = skb->data + cb->number_offset + QUIC_PN_MAX_LEN;\n+\tmemcpy((chacha ? iv : mask), p, QUIC_SAMPLE_LEN);\n+\tsg_init_one(&sg, mask, QUIC_SAMPLE_LEN);\n+\tskcipher_request_set_tfm(req, tfm);\n+\tskcipher_request_set_crypt(req, &sg, &sg, QUIC_SAMPLE_LEN, iv);\n+\terr = crypto_skcipher_encrypt(req);\n+\tif (err)\n+\t\tgoto err;\n+\n+\t/* rfc9001#section-5.4.1:\n+\t *\n+\t * mask = header_protection(hp_key, sample)\n+\t *\n+\t * pn_length = (packet[0] & 0x03) + 1\n+\t * if (packet[0] & 0x80) == 0x80:\n+\t *    # Long header: 4 bits masked\n+\t *    packet[0] ^= mask[0] & 0x0f\n+\t * else:\n+\t *    # Short header: 5 bits masked\n+\t *    packet[0] ^= mask[0] & 0x1f\n+\t *\n+\t * # pn_offset is the start of the Packet Number field.\n+\t * packet[pn_offset:pn_offset+pn_length] ^= mask[1:1+pn_length]\n+\t */\n+\tp = skb->data;\n+\th_mask = ((*p & QUIC_HEADER_FORM_BIT) == QUIC_HEADER_FORM_BIT) ?\n+\t\t QUIC_LONG_HEADER_MASK : QUIC_SHORT_HEADER_MASK;\n+\t*p = (u8)(*p ^ (mask[0] & h_mask));\n+\tif (!enc) {\n+\t\tcb->key_phase = quic_hdr(skb)->key;\n+\t\tcb->number_len = quic_hdr(skb)->pnl + 1;\n+\t}\n+\tp += cb->number_offset;\n+\tfor (i = 1; i <= cb->number_len; i++)\n+\t\t*p++ ^= mask[i];\n+\n+\tif (!enc)\n+\t\terr = quic_crypto_get_number(skb);\n+err:\n+\tkfree_sensitive(mask);\n+\treturn err;\n+}\n+\n+static void *quic_crypto_aead_mem_alloc(struct crypto_aead *tfm, u32 ctx_size,\n+\t\t\t\t\tu8 **iv, struct aead_request **req,\n+\t\t\t\t\tstruct scatterlist **sg, u32 nsg)\n+{\n+\tunsigned int iv_size, req_size;\n+\tunsigned int len;\n+\tu8 *mem;\n+\n+\tiv_size = crypto_aead_ivsize(tfm);\n+\treq_size = sizeof(**req) + crypto_aead_reqsize(tfm);\n+\n+\tlen = ctx_size;\n+\tlen += iv_size;\n+\tlen += crypto_aead_alignmask(tfm) & ~(crypto_tfm_ctx_alignment() - 1);\n+\tlen = ALIGN(len, crypto_tfm_ctx_alignment());\n+\tlen += req_size;\n+\tlen = ALIGN(len, __alignof__(struct scatterlist));\n+\tlen += nsg * sizeof(**sg);\n+\n+\tmem = kzalloc(len, GFP_ATOMIC);\n+\tif (!mem)\n+\t\treturn NULL;\n+\n+\t*iv = (u8 *)PTR_ALIGN(mem + ctx_size, crypto_aead_alignmask(tfm) + 1);\n+\t*req = (struct aead_request *)PTR_ALIGN(*iv + iv_size,\n+\t\t\tcrypto_tfm_ctx_alignment());\n+\t*sg = (struct scatterlist *)PTR_ALIGN((u8 *)*req + req_size,\n+\t\t\t__alignof__(struct scatterlist));\n+\n+\treturn (void *)mem;\n+}\n+\n+static void quic_crypto_done(void *data, int err)\n+{\n+\tstruct sk_buff *skb = data;\n+\n+\tif (err == -EINPROGRESS)\n+\t\treturn;\n+\n+\tkfree_sensitive(QUIC_SKB_CB(skb)->crypto_ctx);\n+\tQUIC_SKB_CB(skb)->crypto_done(skb, err);\n+}\n+\n+/* AEAD Usage. */\n+static int quic_crypto_payload_protect(struct crypto_aead *tfm,\n+\t\t\t\t       struct sk_buff *skb, u8 *base_iv,\n+\t\t\t\t       bool ccm, bool enc)\n+{\n+\tstruct quic_skb_cb *cb = QUIC_SKB_CB(skb);\n+\tu8 *iv, i, nonce[QUIC_IV_LEN];\n+\tu32 len, hlen, sglen, nsg;\n+\tstruct aead_request *req;\n+\tstruct sk_buff *trailer;\n+\tstruct scatterlist *sg;\n+\tvoid *ctx;\n+\t__be64 n;\n+\tint err;\n+\n+\thlen = cb->number_offset + cb->number_len;\n+\tif (enc) {\n+\t\tlen = skb->len;\n+\t\terr = skb_cow_data(skb, QUIC_TAG_LEN, &trailer);\n+\t\tif (err < 0)\n+\t\t\treturn err;\n+\t\tpskb_put(skb, trailer, QUIC_TAG_LEN);\n+\t\tquic_hdr(skb)->key = cb->key_phase;\n+\t\tsglen = skb->len;\n+\t\tnsg = (u32)err;\n+\t} else {\n+\t\tlen = cb->length + cb->number_offset;\n+\t\tif (len - hlen < QUIC_TAG_LEN)\n+\t\t\treturn -EINVAL;\n+\t\tsglen = len;\n+\t\tnsg = 1;\n+\t}\n+\n+\tctx = quic_crypto_aead_mem_alloc(tfm, 0, &iv, &req, &sg, nsg);\n+\tif (!ctx)\n+\t\treturn -ENOMEM;\n+\n+\tsg_init_table(sg, nsg);\n+\terr = skb_to_sgvec(skb, sg, 0, sglen);\n+\tif (err < 0)\n+\t\tgoto err;\n+\n+\t/* rfc9001#section-5.3:\n+\t *\n+\t * The associated data, A, for the AEAD is the contents of the QUIC\n+\t * header, starting from the first byte of either the short or long\n+\t * header, up to and including the unprotected packet number.\n+\t *\n+\t * The nonce, N, is formed by combining the packet protection IV with\n+\t * the packet number.  The 62 bits of the reconstructed QUIC packet\n+\t * number in network byte order are left-padded with zeros to the size\n+\t * of the IV. The exclusive OR of the padded packet number and the IV\n+\t * forms the AEAD nonce.\n+\t */\n+\tmemcpy(nonce, base_iv, QUIC_IV_LEN);\n+\tn = cpu_to_be64(cb->number);\n+\tfor (i = 0; i < sizeof(n); i++)\n+\t\tnonce[QUIC_IV_LEN - sizeof(n) + i] ^= ((u8 *)&n)[i];\n+\n+\t/* For CCM based ciphers, first byte of IV is a constant. */\n+\tiv[0] = TLS_AES_CCM_IV_B0_BYTE;\n+\tmemcpy(&iv[ccm], nonce, QUIC_IV_LEN);\n+\taead_request_set_tfm(req, tfm);\n+\taead_request_set_ad(req, hlen);\n+\taead_request_set_crypt(req, sg, sg, len - hlen, iv);\n+\taead_request_set_callback(req, CRYPTO_TFM_REQ_MAY_BACKLOG,\n+\t\t\t\t  quic_crypto_done, skb);\n+\n+\tcb->crypto_ctx = ctx; /* Async free context for quic_crypto_done() */\n+\terr = enc ? crypto_aead_encrypt(req) : crypto_aead_decrypt(req);\n+\tif (err == -EINPROGRESS || err == -EBUSY) {\n+\t\tmemzero_explicit(nonce, sizeof(nonce));\n+\t\treturn -EINPROGRESS;\n+\t}\n+\n+err:\n+\tkfree_sensitive(ctx);\n+\tmemzero_explicit(nonce, sizeof(nonce));\n+\treturn err;\n+}\n+\n #define QUIC_CIPHER_MIN TLS_CIPHER_AES_GCM_128\n #define QUIC_CIPHER_MAX TLS_CIPHER_CHACHA20_POLY1305\n \n@@ -221,6 +490,146 @@ static struct quic_cipher ciphers[QUIC_CIPHER_MAX + 1 - QUIC_CIPHER_MIN] = {\n \t\t    \"rfc7539(chacha20,poly1305)\", \"chacha20\", \"hmac(sha256)\"),\n };\n \n+static bool quic_crypto_is_cipher_ccm(struct quic_crypto *crypto)\n+{\n+\treturn crypto->cipher_type == TLS_CIPHER_AES_CCM_128;\n+}\n+\n+static bool quic_crypto_is_cipher_chacha(struct quic_crypto *crypto)\n+{\n+\treturn crypto->cipher_type == TLS_CIPHER_CHACHA20_POLY1305;\n+}\n+\n+/* Encrypts a QUIC packet before transmission.  This function performs AEAD\n+ * encryption of the packet payload and applies header protection. It handles\n+ * key phase tracking and key update timing.\n+ *\n+ * Return: 0 on success, or a negative error code.\n+ */\n+int quic_crypto_encrypt(struct quic_crypto *crypto, struct sk_buff *skb)\n+{\n+\tu8 *iv, cha, ccm, phase = crypto->key_phase;\n+\tstruct quic_skb_cb *cb = QUIC_SKB_CB(skb);\n+\tint err;\n+\n+\tcb->key_phase = phase;\n+\tiv = crypto->tx_iv[phase];\n+\t/* Packet payload is already encrypted (e.g., resumed from async),\n+\t * proceed to header protection only.\n+\t */\n+\tif (cb->resume)\n+\t\tgoto out;\n+\n+\t/* If a key update is pending and this is the first packet using the\n+\t * new key, save the current time. Later used to clear old keys after\n+\t * some time has passed (see quic_crypto_decrypt()).\n+\t */\n+\tif (crypto->key_pending && !crypto->key_update_send_time)\n+\t\tcrypto->key_update_send_time = quic_ktime_get_us();\n+\n+\tccm = quic_crypto_is_cipher_ccm(crypto);\n+\terr = quic_crypto_payload_protect(crypto->tx_tfm[phase], skb, iv, ccm,\n+\t\t\t\t\t  true);\n+\tif (err)\n+\t\treturn err;\n+out:\n+\tcha = quic_crypto_is_cipher_chacha(crypto);\n+\treturn quic_crypto_header_protect(crypto->tx_hp_tfm, skb, cha, true);\n+}\n+\n+/* Decrypts a QUIC packet after reception.  This function removes header\n+ * protection, decrypts the payload, and processes any key updates if the key\n+ * phase bit changes.\n+ *\n+ * Return: 0 on success, or a negative error code.\n+ */\n+int quic_crypto_decrypt(struct quic_crypto *crypto, struct sk_buff *skb)\n+{\n+\tstruct quic_skb_cb *cb = QUIC_SKB_CB(skb);\n+\tu8 *iv, cha, ccm, phase;\n+\tint err = 0;\n+\tu64 time;\n+\n+\t/* Payload was decrypted asynchronously.  Proceed with parsing packet\n+\t * number and key phase.\n+\t */\n+\tif (cb->resume) {\n+\t\terr = quic_crypto_get_number(skb);\n+\t\tif (err)\n+\t\t\treturn err;\n+\t\tgoto out;\n+\t}\n+\tif (!cb->number_len) { /* Packet header not yet decrypted. */\n+\t\tcha = quic_crypto_is_cipher_chacha(crypto);\n+\t\terr = quic_crypto_header_protect(crypto->rx_hp_tfm, skb, cha,\n+\t\t\t\t\t\t false);\n+\t\tif (err) {\n+\t\t\tpr_debug(\"%s: hd decrypt err %d\\n\", __func__, err);\n+\t\t\treturn err;\n+\t\t}\n+\t}\n+\n+\t/* rfc9001#section-6:\n+\t *\n+\t * The Key Phase bit allows a recipient to detect a change in keying\n+\t * material without needing to receive the first packet that triggered\n+\t * the change. An endpoint that notices a changed Key Phase bit updates\n+\t * keys and decrypts the packet that contains the changed value.\n+\t */\n+\tif (cb->key_phase != crypto->key_phase && !crypto->key_pending) {\n+\t\tif (!crypto->send_ready) /* Not ready for key update. */\n+\t\t\treturn -EINVAL;\n+\t\tif (!cb->backlog) /* Key update requires process context */\n+\t\t\treturn -EKEYREVOKED;\n+\t\terr = quic_crypto_key_update(crypto); /* Perform key update. */\n+\t\tif (err) {\n+\t\t\tcb->errcode = QUIC_TRANSPORT_ERROR_KEY_UPDATE;\n+\t\t\treturn err;\n+\t\t}\n+\t\tcb->key_update = 1; /* Mark packet as triggering key update. */\n+\t}\n+\n+\tphase = cb->key_phase;\n+\tiv = crypto->rx_iv[phase];\n+\tccm = quic_crypto_is_cipher_ccm(crypto);\n+\terr = quic_crypto_payload_protect(crypto->rx_tfm[phase], skb, iv, ccm,\n+\t\t\t\t\t  false);\n+\tif (err) {\n+\t\tif (err == -EINPROGRESS)\n+\t\t\treturn err;\n+\t\t/* When using the old keys can not decrypt the packets, the\n+\t\t * peer might start another key_update. Thus, clear the last\n+\t\t * key_pending so that next packets will trigger the new\n+\t\t * key-update.\n+\t\t */\n+\t\tif (crypto->key_pending && cb->key_phase != crypto->key_phase) {\n+\t\t\tcrypto->key_pending = 0;\n+\t\t\tcrypto->key_update_time = 0;\n+\t\t\tcrypto->key_update_send_time = 0;\n+\t\t}\n+\t\treturn err;\n+\t}\n+\n+out:\n+\t/* rfc9001#section-6.1:\n+\t *\n+\t * An endpoint MUST retain old keys until it has successfully\n+\t * unprotected a packet sent using the new keys. An endpoint SHOULD\n+\t * retain old keys for some time after unprotecting a packet sent using\n+\t * the new keys.\n+\t */\n+\tif (crypto->key_pending && cb->key_phase == crypto->key_phase) {\n+\t\ttime = crypto->key_update_send_time;\n+\t\tif (time &&\n+\t\t    quic_ktime_get_us() - time >= crypto->key_update_time) {\n+\t\t\tcrypto->key_pending = 0;\n+\t\t\tcrypto->key_update_time = 0;\n+\t\t\tcrypto->key_update_send_time = 0;\n+\t\t}\n+\t}\n+\treturn err;\n+}\n+\n int quic_crypto_set_cipher(struct quic_crypto *crypto, u32 type, u32 flag)\n {\n \tstruct quic_cipher *cipher;\n@@ -515,6 +924,235 @@ int quic_crypto_initial_keys_install(struct quic_crypto *crypto,\n \treturn err;\n }\n \n+#define QUIC_RETRY_KEY_V1 \\\n+\t\"\\xbe\\x0c\\x69\\x0b\\x9f\\x66\\x57\\x5a\\x1d\\x76\\x6b\\x54\\xe3\\x68\\xc8\\x4e\"\n+#define QUIC_RETRY_KEY_V2 \\\n+\t\"\\x8f\\xb4\\xb0\\x1b\\x56\\xac\\x48\\xe2\\x60\\xfb\\xcb\\xce\\xad\\x7c\\xcc\\x92\"\n+\n+#define QUIC_RETRY_NONCE_V1 \"\\x46\\x15\\x99\\xd3\\x5d\\x63\\x2b\\xf2\\x23\\x98\\x25\\xbb\"\n+#define QUIC_RETRY_NONCE_V2 \"\\xd8\\x69\\x69\\xbc\\x2d\\x7c\\x6d\\x99\\x90\\xef\\xb0\\x4a\"\n+\n+/* Retry Packet Integrity. */\n+int quic_crypto_get_retry_tag(struct quic_crypto *crypto, struct sk_buff *skb,\n+\t\t\t      struct quic_conn_id *odcid, u32 version, u8 *tag)\n+{\n+\tstruct crypto_aead *tfm = crypto->tag_tfm;\n+\tu8 *pseudo_retry, *p, *iv, *key;\n+\tstruct aead_request *req;\n+\tstruct scatterlist *sg;\n+\tu32 plen;\n+\tint err;\n+\n+\tif (skb->len < QUIC_TAG_LEN)\n+\t\treturn -EINVAL;\n+\n+\t/* rfc9001#section-5.8:\n+\t *\n+\t * The Retry Integrity Tag is a 128-bit field that is computed as the\n+\t * output of AEAD_AES_128_GCM used with the following inputs:\n+\t *\n+\t * - The secret key, K, is 128 bits equal to\n+\t *   0xbe0c690b9f66575a1d766b54e368c84e.\n+\t * - The nonce, N, is 96 bits equal to 0x461599d35d632bf2239825bb.\n+\t * - The plaintext, P, is empty.\n+\t * - The associated data, A, is the contents of the Retry\n+\t *   Pseudo-Packet,\n+\t *\n+\t * The Retry Pseudo-Packet is not sent over the wire. It is computed by\n+\t * taking the transmitted Retry packet, removing the Retry Integrity\n+\t * Tag, and prepending the two following fields: ODCID Length +\n+\t * Original Destination Connection ID (ODCID).\n+\t */\n+\terr = crypto_aead_setauthsize(tfm, QUIC_TAG_LEN);\n+\tif (err)\n+\t\treturn err;\n+\tkey = QUIC_RETRY_KEY_V1;\n+\tif (version == QUIC_VERSION_V2)\n+\t\tkey = QUIC_RETRY_KEY_V2;\n+\terr = crypto_aead_setkey(tfm, key, TLS_CIPHER_AES_GCM_128_KEY_SIZE);\n+\tif (err)\n+\t\treturn err;\n+\n+\t/* The caller must ensure skb->len > QUIC_TAG_LEN. */\n+\tplen = 1 + odcid->len + skb->len - QUIC_TAG_LEN;\n+\tpseudo_retry = quic_crypto_aead_mem_alloc(tfm, plen + QUIC_TAG_LEN, &iv,\n+\t\t\t\t\t\t  &req, &sg, 1);\n+\tif (!pseudo_retry)\n+\t\treturn -ENOMEM;\n+\n+\tp = pseudo_retry;\n+\tp = quic_put_int(p, odcid->len, 1);\n+\tp = quic_put_data(p, odcid->data, odcid->len);\n+\tp = quic_put_data(p, skb->data, skb->len - QUIC_TAG_LEN);\n+\tsg_init_one(sg, pseudo_retry, plen + QUIC_TAG_LEN);\n+\n+\tmemcpy(iv, QUIC_RETRY_NONCE_V1, QUIC_IV_LEN);\n+\tif (version == QUIC_VERSION_V2)\n+\t\tmemcpy(iv, QUIC_RETRY_NONCE_V2, QUIC_IV_LEN);\n+\taead_request_set_tfm(req, tfm);\n+\taead_request_set_ad(req, plen);\n+\taead_request_set_crypt(req, sg, sg, 0, iv);\n+\terr = crypto_aead_encrypt(req);\n+\tif (!err)\n+\t\tmemcpy(tag, p, QUIC_TAG_LEN);\n+\tkfree_sensitive(pseudo_retry);\n+\treturn err;\n+}\n+\n+/* Initialize crypto for token operations.\n+ *\n+ * Derives a key and IV using HKDF, configures the AEAD transform, and\n+ * allocates memory for the token request. Used by both generation and\n+ * verification paths.\n+ *\n+ * Returns the token buffer on success or an ERR_PTR() on failure.\n+ */\n+static void *quic_crypto_token_init(struct quic_crypto *crypto, u32 len,\n+\t\t\t\t    u8 **token_iv, struct aead_request **req,\n+\t\t\t\t    struct scatterlist **sg)\n+{\n+\tu8 key[TLS_CIPHER_AES_GCM_128_KEY_SIZE], iv[QUIC_IV_LEN];\n+\tstruct crypto_aead *tfm = crypto->tag_tfm;\n+\tstruct quic_data srt = {}, k, i;\n+\tvoid *token = NULL;\n+\tint err;\n+\n+\tquic_data(&srt, quic_random_data, QUIC_RANDOM_DATA_LEN);\n+\tquic_data(&k, key, TLS_CIPHER_AES_GCM_128_KEY_SIZE);\n+\tquic_data(&i, iv, QUIC_IV_LEN);\n+\terr = quic_crypto_keys_derive(crypto->secret_tfm, &srt, &k, &i, NULL,\n+\t\t\t\t      QUIC_VERSION_V1);\n+\tif (err)\n+\t\tgoto out;\n+\terr = crypto_aead_setauthsize(tfm, QUIC_TAG_LEN);\n+\tif (err)\n+\t\tgoto out;\n+\terr = crypto_aead_setkey(tfm, key, TLS_CIPHER_AES_GCM_128_KEY_SIZE);\n+\tif (err)\n+\t\tgoto out;\n+\ttoken = quic_crypto_aead_mem_alloc(tfm, len, token_iv, req, sg, 1);\n+\tif (!token) {\n+\t\terr = -ENOMEM;\n+\t\tgoto out;\n+\t}\n+\tmemcpy(*token_iv, iv, QUIC_IV_LEN);\n+out:\n+\tmemzero_explicit(key, sizeof(key));\n+\tmemzero_explicit(iv, sizeof(iv));\n+\treturn token ?: ERR_PTR(err);\n+}\n+\n+/* Generate a token for Retry or address validation.\n+ *\n+ * Builds a token with the format: [client address][timestamp][original\n+ * DCID][auth tag]\n+ *\n+ * Encrypts the token (excluding the first flag byte) using AES-GCM with a key\n+ * and IV derived via HKDF. The original DCID is stored to be recovered later\n+ * from a Client Initial packet.  Ensures the token is bound to the client\n+ * address and time, preventing reuse or tampering.\n+ *\n+ * Returns 0 on success or a negative error code on failure.\n+ */\n+int quic_crypto_generate_token(struct quic_crypto *crypto, void *addr,\n+\t\t\t       u32 addrlen, struct quic_conn_id *conn_id,\n+\t\t\t       u8 *token, u32 *tlen)\n+{\n+\tu64 ts = quic_ktime_get_us();\n+\tstruct aead_request *req;\n+\tstruct scatterlist *sg;\n+\tu8 *token_buf, *iv, *p;\n+\tint err, len;\n+\n+\tlen = addrlen + sizeof(ts) + conn_id->len + QUIC_TAG_LEN;\n+\ttoken_buf = quic_crypto_token_init(crypto, len, &iv, &req, &sg);\n+\tif (IS_ERR(token_buf))\n+\t\treturn PTR_ERR(token_buf);\n+\n+\tp = token_buf;\n+\tp = quic_put_data(p, addr, addrlen);\n+\tp = quic_put_int(p, ts, sizeof(ts));\n+\tquic_put_data(p, conn_id->data, conn_id->len);\n+\n+\tsg_init_one(sg, token_buf, len);\n+\taead_request_set_tfm(req, crypto->tag_tfm);\n+\taead_request_set_ad(req, addrlen);\n+\taead_request_set_crypt(req, sg, sg, len - addrlen - QUIC_TAG_LEN, iv);\n+\terr = crypto_aead_encrypt(req);\n+\tif (err)\n+\t\tgoto out;\n+\n+\tmemcpy(token + 1, token_buf, len);\n+\t*tlen = len + 1;\n+out:\n+\tkfree_sensitive(token_buf);\n+\treturn err;\n+}\n+\n+/* Validate a Retry or address validation token.\n+ *\n+ * Decrypts the token using derived key and IV. Checks that the decrypted\n+ * address matches the provided address, validates the embedded timestamp\n+ * against current time with a version-specific timeout. If applicable, it\n+ * extracts and returns the original destination connection ID (ODCID) for\n+ * Retry packets.\n+ *\n+ * Returns 0 if the token is valid, -EINVAL if invalid, or another negative\n+ * error code.\n+ */\n+int quic_crypto_verify_token(struct quic_crypto *crypto, void *addr,\n+\t\t\t     u32 addrlen, struct quic_conn_id *conn_id,\n+\t\t\t     u8 *token, u32 len)\n+{\n+\tu64 t, ts = quic_ktime_get_us(), timeout = QUIC_TOKEN_TIMEOUT_RETRY;\n+\tu8 *token_buf, *iv, *p, flag = *token;\n+\tstruct aead_request *req;\n+\tstruct scatterlist *sg;\n+\tint err;\n+\n+\tif (len < sizeof(flag) + addrlen + sizeof(ts) + QUIC_TAG_LEN)\n+\t\treturn -EINVAL;\n+\tlen--;\n+\ttoken++;\n+\n+\ttoken_buf = quic_crypto_token_init(crypto, len, &iv, &req, &sg);\n+\tif (IS_ERR(token_buf))\n+\t\treturn PTR_ERR(token_buf);\n+\n+\tmemcpy(token_buf, token, len);\n+\n+\tsg_init_one(sg, token_buf, len);\n+\taead_request_set_tfm(req, crypto->tag_tfm);\n+\taead_request_set_ad(req, addrlen);\n+\taead_request_set_crypt(req, sg, sg, len - addrlen, iv);\n+\terr = crypto_aead_decrypt(req);\n+\tif (err)\n+\t\tgoto out;\n+\n+\terr = -EINVAL;\n+\tp = token_buf;\n+\tif (memcmp(p, addr, addrlen))\n+\t\tgoto out;\n+\n+\tp += addrlen;\n+\tlen -= addrlen;\n+\tif (flag == QUIC_TOKEN_FLAG_REGULAR)\n+\t\ttimeout = QUIC_TOKEN_TIMEOUT_REGULAR;\n+\tif (!quic_get_int(&p, &len, &t, sizeof(ts)) || t + timeout < ts)\n+\t\tgoto out;\n+\n+\tlen -= QUIC_TAG_LEN;\n+\tif (len > QUIC_CONN_ID_MAX_LEN)\n+\t\tgoto out;\n+\n+\tif (flag == QUIC_TOKEN_FLAG_RETRY)\n+\t\tquic_conn_id_update(conn_id, p, len);\n+\terr = 0;\n+out:\n+\tkfree_sensitive(token_buf);\n+\treturn err;\n+}\n+\n /* Generate a derived key using HKDF-Extract and HKDF-Expand with a given\n  * label.\n  */\ndiff --git a/net/quic/crypto.h b/net/quic/crypto.h\nindex f9450e55d6dd..b84275783880 100644\n--- a/net/quic/crypto.h\n+++ b/net/quic/crypto.h\n@@ -66,6 +66,9 @@ int quic_crypto_set_cipher(struct quic_crypto *crypto,\n \t\t\t   u32 type, u32 flag);\n int quic_crypto_key_update(struct quic_crypto *crypto);\n \n+int quic_crypto_encrypt(struct quic_crypto *crypto, struct sk_buff *skb);\n+int quic_crypto_decrypt(struct quic_crypto *crypto, struct sk_buff *skb);\n+\n int quic_crypto_initial_keys_install(struct quic_crypto *crypto,\n \t\t\t\t     struct quic_conn_id *conn_id,\n \t\t\t\t     u32 version, bool is_serv);\n@@ -76,5 +79,14 @@ int quic_crypto_generate_stateless_reset_token(struct quic_crypto *crypto,\n \t\t\t\t\t       void *data, u32 len, u8 *key,\n \t\t\t\t\t       u32 key_len);\n \n+int quic_crypto_generate_token(struct quic_crypto *crypto, void *addr,\n+\t\t\t       u32 addrlen, struct quic_conn_id *conn_id,\n+\t\t\t       u8 *token, u32 *tlen);\n+int quic_crypto_get_retry_tag(struct quic_crypto *crypto, struct sk_buff *skb,\n+\t\t\t      struct quic_conn_id *odcid, u32 version, u8 *tag);\n+int quic_crypto_verify_token(struct quic_crypto *crypto, void *addr,\n+\t\t\t     u32 addrlen, struct quic_conn_id *conn_id,\n+\t\t\t     u8 *token, u32 len);\n+\n void quic_crypto_free(struct quic_crypto *crypto);\n void quic_crypto_init(void);\n","prefixes":["net-next","v11","12/15"]}