From nobody Fri Apr 3 06:25:00 2026 Received: from mail-pj1-f51.google.com (mail-pj1-f51.google.com [209.85.216.51]) (using TLSv1.2 with cipher ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 8DC4E34CFDD for ; Wed, 4 Mar 2026 05:36:33 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.216.51 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772602594; cv=none; b=DZW0Ng6TmHw1O4Stc442/a5TQ0+FdtGRtITbZgC9M0NIUm0XvFwwMkttOOuaoIkHWOrlr1y4EEmXyDA4BoSdr9jfhmPdKsySYku6Sgl6Otzs1GqUsiw4W9EVKhoZDOX4HmgTErTTy3c+vlTKUMboC5ZtFcQsAdXjnjHZUvf3y8Y= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1772602594; c=relaxed/simple; bh=7qA9Q6Pz/ZThLLziRlzsP+Ns3IK5HTYVcg1/SCKOubM=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=YWdO7MLIhuRtxAUr00aL3G7OVTQLLOTWP4oXMt0OPc7pdC9433zUMQ8SxmmUwTsgMc8NZN/OX/HYLn/3FbT5VnubN1W3RwErFKj6dKHBUnmhfZ/D31Brc+d1/99ax944Ux55h64PIMxQVfz5b8S8buxNT0hftWnVoZbUZc/e5YI= ARC-Authentication-Results: i=1; smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com; spf=pass smtp.mailfrom=gmail.com; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b=cH76yQK+; arc=none smtp.client-ip=209.85.216.51 Authentication-Results: smtp.subspace.kernel.org; dmarc=pass (p=none dis=none) header.from=gmail.com Authentication-Results: smtp.subspace.kernel.org; spf=pass smtp.mailfrom=gmail.com Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=gmail.com header.i=@gmail.com header.b="cH76yQK+" Received: by mail-pj1-f51.google.com with SMTP id 98e67ed59e1d1-35691a231a7so3973046a91.3 for ; Tue, 03 Mar 2026 21:36:33 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1772602593; x=1773207393; darn=vger.kernel.org; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:from:to:cc:subject:date :message-id:reply-to; bh=xNCDZkyqVlGeQwFgjROGPRwx2fLC/OmgR/7kGK793I8=; b=cH76yQK+A9h6nZkjDPrZmT9qn339hzoy2A+8gT1IdpuEcAk7yttMr+cK+u23yi9O11 LEfL/xVFnSgW6GGSbrX6/RXIWZdMsD3y37IIYAFMEcivx0qhfHHXqquF3oV4i4rnLOkf VrZ3y6GMLGNgbsvQHWAzrtubog4DdjqR3JjzsATMvOoaN03YNLJ0nNW4nA1U6hvEGaBn O5HKblyXVw7pRxktaqyAmtE61E2+8fVVf75TY2zcweCbkGpCoKp8jS+LdsrNbIULL/lT muEoSXuvIG4unAjC5uawSzvyttRPlVMFnj5ou1LZ4D97MrvnFe9QDWA5xYfUoSrxYocQ 6J1g== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1772602593; x=1773207393; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-gg:x-gm-message-state:from :to:cc:subject:date:message-id:reply-to; bh=xNCDZkyqVlGeQwFgjROGPRwx2fLC/OmgR/7kGK793I8=; b=QuUttEmJaVRC9jauvSJpsTw5vbIYaqZTxMUpIaVUMSPOPJNJjIRtmqClROOS5DcDV9 GS27ZymfLLEwjC+FZR25AOlBnRRB09qqr+uY2+RiJuTzynpJwVi5t7G0zrb2PISoeeOr SM29lIL4Pq5TBT2yB1b5/zl8Se1pJVxjBUai06kbAkvqLo1WPNPW+JUmeD0+Z97m9Dlq vTR8r/32tAMkgBpbxHRfghIefMfzcKfaCtuYYqoz6h58wpQVW3BcnzFXKQgMH/4zrt53 nqDweUklfg/9VW3F75xdY+I+GhH9OrN8aWTurCO3sdsQDoCUP5moDpCj6FRIYlbCJ6na I9YQ== X-Forwarded-Encrypted: i=1; AJvYcCURU568S9dsAGq8Lpcltm4BKsm+so27M/xsEWh0s8qzdU24OVSLy3qdDDbm0LhMHBOSdORo0kJVmsdWY50=@vger.kernel.org X-Gm-Message-State: AOJu0YwdVewRkcDtTvA9K20xAPTncI57j7G0a3vwhLqvDoHbJ+lvEf6U en1QoLW/mv6YQp0ZlkTukMDNMgaVcWrzWuhME6NY4PDi75SIWJbUaD3a X-Gm-Gg: ATEYQzwT/8eCvCV3dkrpAEy4H8UkhvIDRRFoQ8vukolpbolbGwFQfabPP4E+kXVAM7s Q24tqIcQ15kDXyfEbXz7XdGsav7lq5/npRHuPkdeS2lpovulNvCVPB7b0Klqqznl2bK85lyipNk 3rxpE4kRKkosepTQJv4er+rJsDtZwL3HMfyyuc92cEeuY+bxJ/AQdkdQ7o9pTznh/jVr40K9qyu iNUnWq8wnKR2bFrwrYcZVbMDuJzT2F5CbXr+gCd8gvURZrwLgr6aPtQZGakv5yvLt1jBMMKeo4Y 1TOgOZbDYRpsAm/Kw0ZfDyHRaqJ6+++eT8gmBSKPYYEILaHUD8aLMIaP+S+uGKZoqN1ws24t9SC ip+fKNeYe7cdqMPJc2KUrQ+msa0S5PLo10jMIT3N4tKkIw6Q1tUBPgrgmBQ6CCtzZ7fq6KCGi9M wQL8fHZpeZQFkHK/JrH1emGCFtrMM7ELRLGt1OPT+adQ== X-Received: by 2002:a17:90b:538c:b0:356:2db3:1206 with SMTP id 98e67ed59e1d1-359a69dae4emr997051a91.13.1772602592975; Tue, 03 Mar 2026 21:36:32 -0800 (PST) Received: from toolbx.alistair23.me ([2403:581e:fdf9:0:6209:4521:6813:45b7]) by smtp.gmail.com with ESMTPSA id 98e67ed59e1d1-3599c090bfdsm4020057a91.8.2026.03.03.21.36.27 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 03 Mar 2026 21:36:32 -0800 (PST) From: alistair23@gmail.com X-Google-Original-From: alistair.francis@wdc.com To: chuck.lever@oracle.com, hare@kernel.org, kernel-tls-handshake@lists.linux.dev, netdev@vger.kernel.org, linux-kernel@vger.kernel.org, linux-doc@vger.kernel.org, linux-nvme@lists.infradead.org, linux-nfs@vger.kernel.org Cc: kbusch@kernel.org, axboe@kernel.dk, hch@lst.de, sagi@grimberg.me, kch@nvidia.com, hare@suse.de, alistair23@gmail.com, Alistair Francis Subject: [PATCH v7 1/5] net/handshake: Store the key serial number on completion Date: Wed, 4 Mar 2026 15:34:56 +1000 Message-ID: <20260304053500.590630-2-alistair.francis@wdc.com> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260304053500.590630-1-alistair.francis@wdc.com> References: <20260304053500.590630-1-alistair.francis@wdc.com> Precedence: bulk X-Mailing-List: linux-kernel@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable Content-Type: text/plain; charset="utf-8" From: Alistair Francis Allow userspace to include a key serial number when completing a handshake with the HANDSHAKE_CMD_DONE command. We then store this serial number and will provide it back to userspace in the future. This allows userspace to save data to the keyring and then restore that data later. This will be used to support the TLS KeyUpdate operation, as now userspace can resume information about a established session. Signed-off-by: Alistair Francis Reviewed-by: Hannes Reincke Reviewed-by: Chuck Lever Reviewed-by: Sagi Grimberg --- v7: - No change v6: - Add the "ta_" and "th_" prefixs v5: - Change name to "handshake session ID" v4: - No change v3: - No change v2: - Change "key-serial" to "session-id" Documentation/netlink/specs/handshake.yaml | 4 ++++ Documentation/networking/tls-handshake.rst | 1 + drivers/nvme/host/tcp.c | 3 ++- drivers/nvme/target/tcp.c | 3 ++- include/net/handshake.h | 5 ++++- include/uapi/linux/handshake.h | 1 + net/handshake/genl.c | 5 +++-- net/handshake/tlshd.c | 15 +++++++++++++-- net/sunrpc/svcsock.c | 4 +++- net/sunrpc/xprtsock.c | 4 +++- 10 files changed, 36 insertions(+), 9 deletions(-) diff --git a/Documentation/netlink/specs/handshake.yaml b/Documentation/net= link/specs/handshake.yaml index 95c3fade7a8d..a273bc74d26f 100644 --- a/Documentation/netlink/specs/handshake.yaml +++ b/Documentation/netlink/specs/handshake.yaml @@ -87,6 +87,9 @@ attribute-sets: name: remote-auth type: u32 multi-attr: true + - + name: session-id + type: u32 =20 operations: list: @@ -123,6 +126,7 @@ operations: - status - sockfd - remote-auth + - session-id =20 mcast-groups: list: diff --git a/Documentation/networking/tls-handshake.rst b/Documentation/net= working/tls-handshake.rst index 6f5ea1646a47..c58b3c8b16c1 100644 --- a/Documentation/networking/tls-handshake.rst +++ b/Documentation/networking/tls-handshake.rst @@ -60,6 +60,7 @@ fills in a structure that contains the parameters of the = request: key_serial_t ta_my_privkey; unsigned int ta_num_peerids; key_serial_t ta_my_peerids[5]; + key_serial_t ta_handshake_session_id; }; =20 The @ta_sock field references an open and connected socket. The consumer diff --git a/drivers/nvme/host/tcp.c b/drivers/nvme/host/tcp.c index 9ab3f61196a3..204f45f791a3 100644 --- a/drivers/nvme/host/tcp.c +++ b/drivers/nvme/host/tcp.c @@ -1676,7 +1676,8 @@ static void nvme_tcp_set_queue_io_cpu(struct nvme_tcp= _queue *queue) qid, queue->io_cpu); } =20 -static void nvme_tcp_tls_done(void *data, int status, key_serial_t pskid) +static void nvme_tcp_tls_done(void *data, int status, key_serial_t pskid, + key_serial_t handshake_session_id) { struct nvme_tcp_queue *queue =3D data; struct nvme_tcp_ctrl *ctrl =3D queue->ctrl; diff --git a/drivers/nvme/target/tcp.c b/drivers/nvme/target/tcp.c index acc71a26733f..63613e60f566 100644 --- a/drivers/nvme/target/tcp.c +++ b/drivers/nvme/target/tcp.c @@ -1808,7 +1808,8 @@ static int nvmet_tcp_tls_key_lookup(struct nvmet_tcp_= queue *queue, } =20 static void nvmet_tcp_tls_handshake_done(void *data, int status, - key_serial_t peerid) + key_serial_t peerid, + key_serial_t handshake_session_id) { struct nvmet_tcp_queue *queue =3D data; =20 diff --git a/include/net/handshake.h b/include/net/handshake.h index 8ebd4f9ed26e..d9b2411d5523 100644 --- a/include/net/handshake.h +++ b/include/net/handshake.h @@ -15,10 +15,12 @@ enum { TLS_NO_PEERID =3D 0, TLS_NO_CERT =3D 0, TLS_NO_PRIVKEY =3D 0, + TLS_NO_SESSION_ID =3D 0, }; =20 typedef void (*tls_done_func_t)(void *data, int status, - key_serial_t peerid); + key_serial_t peerid, + key_serial_t handshake_session_id); =20 struct tls_handshake_args { struct socket *ta_sock; @@ -31,6 +33,7 @@ struct tls_handshake_args { key_serial_t ta_my_privkey; unsigned int ta_num_peerids; key_serial_t ta_my_peerids[5]; + key_serial_t ta_handshake_session_id; }; =20 int tls_client_hello_anon(const struct tls_handshake_args *args, gfp_t fla= gs); diff --git a/include/uapi/linux/handshake.h b/include/uapi/linux/handshake.h index d7e40f594888..7fb3ef7f64df 100644 --- a/include/uapi/linux/handshake.h +++ b/include/uapi/linux/handshake.h @@ -56,6 +56,7 @@ enum { HANDSHAKE_A_DONE_STATUS =3D 1, HANDSHAKE_A_DONE_SOCKFD, HANDSHAKE_A_DONE_REMOTE_AUTH, + HANDSHAKE_A_DONE_SESSION_ID, =20 __HANDSHAKE_A_DONE_MAX, HANDSHAKE_A_DONE_MAX =3D (__HANDSHAKE_A_DONE_MAX - 1) diff --git a/net/handshake/genl.c b/net/handshake/genl.c index 870612609491..2542c13bb562 100644 --- a/net/handshake/genl.c +++ b/net/handshake/genl.c @@ -17,10 +17,11 @@ static const struct nla_policy handshake_accept_nl_poli= cy[HANDSHAKE_A_ACCEPT_HAN }; =20 /* HANDSHAKE_CMD_DONE - do */ -static const struct nla_policy handshake_done_nl_policy[HANDSHAKE_A_DONE_R= EMOTE_AUTH + 1] =3D { +static const struct nla_policy handshake_done_nl_policy[HANDSHAKE_A_DONE_S= ESSION_ID + 1] =3D { [HANDSHAKE_A_DONE_STATUS] =3D { .type =3D NLA_U32, }, [HANDSHAKE_A_DONE_SOCKFD] =3D { .type =3D NLA_S32, }, [HANDSHAKE_A_DONE_REMOTE_AUTH] =3D { .type =3D NLA_U32, }, + [HANDSHAKE_A_DONE_SESSION_ID] =3D { .type =3D NLA_U32, }, }; =20 /* Ops table for handshake */ @@ -36,7 +37,7 @@ static const struct genl_split_ops handshake_nl_ops[] =3D= { .cmd =3D HANDSHAKE_CMD_DONE, .doit =3D handshake_nl_done_doit, .policy =3D handshake_done_nl_policy, - .maxattr =3D HANDSHAKE_A_DONE_REMOTE_AUTH, + .maxattr =3D HANDSHAKE_A_DONE_SESSION_ID, .flags =3D GENL_CMD_CAP_DO, }, }; diff --git a/net/handshake/tlshd.c b/net/handshake/tlshd.c index 8f9532a15f43..e72f45bdc226 100644 --- a/net/handshake/tlshd.c +++ b/net/handshake/tlshd.c @@ -26,7 +26,8 @@ =20 struct tls_handshake_req { void (*th_consumer_done)(void *data, int status, - key_serial_t peerid); + key_serial_t peerid, + key_serial_t handshake_session_id); void *th_consumer_data; =20 int th_type; @@ -39,6 +40,8 @@ struct tls_handshake_req { =20 unsigned int th_num_peerids; key_serial_t th_peerid[5]; + + key_serial_t th_handshake_session_id; }; =20 static struct tls_handshake_req * @@ -55,6 +58,7 @@ tls_handshake_req_init(struct handshake_req *req, treq->th_num_peerids =3D 0; treq->th_certificate =3D TLS_NO_CERT; treq->th_privkey =3D TLS_NO_PRIVKEY; + treq->th_handshake_session_id =3D TLS_NO_SESSION_ID; return treq; } =20 @@ -83,6 +87,13 @@ static void tls_handshake_remote_peerids(struct tls_hand= shake_req *treq, if (i >=3D treq->th_num_peerids) break; } + + nla_for_each_attr(nla, head, len, rem) { + if (nla_type(nla) =3D=3D HANDSHAKE_A_DONE_SESSION_ID) { + treq->th_handshake_session_id =3D nla_get_u32(nla); + break; + } + } } =20 /** @@ -105,7 +116,7 @@ static void tls_handshake_done(struct handshake_req *re= q, set_bit(HANDSHAKE_F_REQ_SESSION, &req->hr_flags); =20 treq->th_consumer_done(treq->th_consumer_data, -status, - treq->th_peerid[0]); + treq->th_peerid[0], treq->th_handshake_session_id); } =20 #if IS_ENABLED(CONFIG_KEYS) diff --git a/net/sunrpc/svcsock.c b/net/sunrpc/svcsock.c index f28c6076f7e8..5b003ac66a54 100644 --- a/net/sunrpc/svcsock.c +++ b/net/sunrpc/svcsock.c @@ -455,13 +455,15 @@ static void svc_tcp_kill_temp_xprt(struct svc_xprt *x= prt) * @data: address of xprt to wake * @status: status of handshake * @peerid: serial number of key containing the remote peer's identity + * @handshake_session_id: serial number of the userspace session ID * * If a security policy is specified as an export option, we don't * have a specific export here to check. So we set a "TLS session * is present" flag on the xprt and let an upper layer enforce local * security policy. */ -static void svc_tcp_handshake_done(void *data, int status, key_serial_t pe= erid) +static void svc_tcp_handshake_done(void *data, int status, key_serial_t pe= erid, + key_serial_t handshake_session_id) { struct svc_xprt *xprt =3D data; struct svc_sock *svsk =3D container_of(xprt, struct svc_sock, sk_xprt); diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 2e1fe6013361..86eb51a9b224 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -2590,9 +2590,11 @@ static int xs_tcp_tls_finish_connecting(struct rpc_x= prt *lower_xprt, * @data: address of xprt to wake * @status: status of handshake * @peerid: serial number of key containing the remote's identity + * @handshake_session_id: serial number of the userspace session ID * */ -static void xs_tls_handshake_done(void *data, int status, key_serial_t pee= rid) +static void xs_tls_handshake_done(void *data, int status, key_serial_t pee= rid, + key_serial_t handshake_session_id) { struct rpc_xprt *lower_xprt =3D data; struct sock_xprt *lower_transport =3D --=20 2.53.0