From nobody Thu Apr 2 17:18:53 2026 Received: from mail-pg1-f174.google.com (mail-pg1-f174.google.com [209.85.215.174]) (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 02B8F34AAE6 for ; Wed, 11 Feb 2026 03:32:58 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=209.85.215.174 ARC-Seal: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770780782; cv=none; b=hjUxsMFingFKgmftl7HoDkaPtO8s6rlS/4gVh9JU48zp+n32pDoeWoEbb6xvL1G78MpX3f0Rh2GMFzrapejiFnEb6KV+AFvD2UYB8NI1YUGmU4bf+I9r7TVM+KCTJnsQO0939YuPGl77TyFQeQkDJAcmo+IsCbHhis45SaEy1YU= ARC-Message-Signature: i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1770780782; c=relaxed/simple; bh=LeL9rMOoVhCYJDLJkyeUhx+7gewNtABy5Yqg9bwzEIw=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version:Content-Type; b=YTU/7YLp/gbjyTZcz6CIbr3UvVciwByIIhekf1QaZcd+CRwpkRJKeQbkpStzfHT0VDqsmSZjAt8Rl7qhhOcafcgOPHSfnyOP+tqhv4gDIf6L1FlM4Y0aYwIMWZ67oxXdBz7l/wcldXb0MJXbOAm3KPx9mdxYEgln3m+frLacb+4= 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=FTShwKvq; arc=none smtp.client-ip=209.85.215.174 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="FTShwKvq" Received: by mail-pg1-f174.google.com with SMTP id 41be03b00d2f7-c6c444e89bcso583487a12.2 for ; Tue, 10 Feb 2026 19:32:58 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20230601; t=1770780778; x=1771385578; 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=94DHUwq8TzwnOUxAyFNL8ck6qlmcEGwk0NGsy0qgL20=; b=FTShwKvqwIrPKd6U3EjJxwAF008fBB6OJUISw15YoqS5H+/aMBuM6ZFnDDYptkeMdO INF9H1Fne2FqDBnbDdby+CFW6IaVJndLHMPgL8CfafNW5xM9AjuSoLi1+tFZ1FTqOxMx /cZMy4PE1hK+SHpeapjQuauBmIr6OdW6uI87F6iDbBhpolhhFrrCnwOJPd1p+DzYxjVz Rnq6kQ6FKUUF6s5co963JsugZZoPh7AKShC9L8tInB9utgr5oLbcCLpIVRPxsCwl6V8v OfzIYcqvenjpRdCijMlOXXGwJCPECTxQlZSN7gYNxYuftZejEPHWNErZ1FUfe8sjjI2G hCNw== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20230601; t=1770780778; x=1771385578; 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=94DHUwq8TzwnOUxAyFNL8ck6qlmcEGwk0NGsy0qgL20=; b=eHSiTRSdjEGQQCdQGDlAgy8Xa02/1gT0N1bpCUZfnigtFn36MMxVhiPdX2feRpbXU1 9YqTBO3p3/kO9gB0XcHBAkjVJlqquvunBQk58lPRTon/0bVZTF2iSd6fVd+15Y0PSNYQ W+5eI4sXY34YyC0w/Kh1kgvu8+zJWebrn3tV4196jvR61h1hDuGBZDoaYlIFCOjSa57l mRQNwiWTuHjPGjMFxR114RAUco9hc5JCJBEVUd+TYteBv9yCe7kv4wIhV/P8Qy/X+cM9 uG4bzI/wwl4KLcrVQFKv60+sryxgTBgTmRXH0JOGg2yL62jgv4FRU8Wi0nYYymHCohFI HD4w== X-Forwarded-Encrypted: i=1; AJvYcCVRyLYUNkqFt4iNEAv2BRqtHpynD3orJp3+xuiUGuykWvDd6CBE30gn/RZM/N0OKii1pScRw8lr843EB5s=@vger.kernel.org X-Gm-Message-State: AOJu0YzOa2zH1RO/C93/ohhpsnl8UREQTrZ9CUhOpphH2y8ZVQvj3NSh oFVZIK9IJeVrjxDWjHEOeSS6lTT1yrEoHJZC3JVYkBdUb+Ai631JHzYL X-Gm-Gg: AZuq6aL7f+U0UBMJ29jcrzxcyQc2muBd2MfJkFtO8AIylRxDMoYoDJF+1D5go6/sCG8 4Wp+k2RSSEt4OpLKPNx5ZDOjjZUtBnxDURjxPTsDfMxv826PA4OzKwy7F0KymYqR4WnUpX2I672 zO4NSj5APNq6vyieMSE+tz8CYvHpPkS/HynuJQcDAKFfXUxMiw3GP8er2/THTlW2tT8fn81S/Ry CQb+34+qBmZg2PXG7XIA6n9pdU5AiF9vF8NlV0Bp0k5/pohU1u1PH1Kz29jXQqYUBhiO4CaAmPM KDfFYyX/mLVtDhTJchjxz6jQ1K5k+204wOysCppdea/8BX2ikaZFes4wJnnHK/Aw8piBlRjr+JF XR2JUCswniArcv1s1H5UXwQJP07247d1QeyiHVKjQBOfXdags2CMDtpDdASXU4xkIg4ZhwB5eLR Ee7D+D4uiiBl2TLkX5K4LrVHBhVUbNGy2b2MSTsrya0w== X-Received: by 2002:a05:6300:2206:b0:366:14af:9bd2 with SMTP id adf61e73a8af0-393ad3a27aamr17344339637.72.1770780778321; Tue, 10 Feb 2026 19:32:58 -0800 (PST) Received: from toolbx.alistair23.me ([2403:581e:fdf9:0:6209:4521:6813:45b7]) by smtp.gmail.com with ESMTPSA id 41be03b00d2f7-c6e197d63c9sm464856a12.20.2026.02.10.19.32.50 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Tue, 10 Feb 2026 19:32:57 -0800 (PST) From: alistair23@gmail.com X-Google-Original-From: alistair.francis@wdc.com To: bhelgaas@google.com, lukas@wunner.de, rust-for-linux@vger.kernel.org, akpm@linux-foundation.org, linux-pci@vger.kernel.org, Jonathan.Cameron@huawei.com, linux-cxl@vger.kernel.org, linux-kernel@vger.kernel.org Cc: alex.gaynor@gmail.com, benno.lossin@proton.me, boqun.feng@gmail.com, a.hindborg@kernel.org, gary@garyguo.net, bjorn3_gh@protonmail.com, tmgross@umich.edu, alistair23@gmail.com, ojeda@kernel.org, wilfred.mallawa@wdc.com, aliceryhl@google.com, James Bottomley , =?UTF-8?q?J=C3=A9r=C3=B4me=20Glisse?= , Jason Gunthorpe , Alistair Francis Subject: [RFC v3 27/27] rspdm: Multicast received signatures via netlink Date: Wed, 11 Feb 2026 13:29:34 +1000 Message-ID: <20260211032935.2705841-28-alistair.francis@wdc.com> X-Mailer: git-send-email 2.52.0 In-Reply-To: <20260211032935.2705841-1-alistair.francis@wdc.com> References: <20260211032935.2705841-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-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable From: Lukas Wunner This is based on Lukas's patch from [1]. This exposes all of the SPDM information to userspace via netlink. This includes the certificate chain and communication transcript. 1: https://github.com/l1k/linux/commit/fe90b5700ee9bc595a21c030192eac4060ea= eae1 Signed-off-by: Lukas Wunner Cc: James Bottomley Cc: J=C3=A9r=C3=B4me Glisse Cc: Jason Gunthorpe [ Change by AF: - Fixup yaml spec issues - Include certificate chain - Port to support Rust SPDM ] Signed-off-by: Alistair Francis --- Documentation/netlink/specs/spdm.yaml | 136 ++++++++++++++++++ include/uapi/linux/spdm_netlink.h | 49 +++++++ lib/rspdm/Makefile | 1 + lib/rspdm/netlink-autogen.c | 33 +++++ lib/rspdm/netlink-autogen.h | 22 +++ lib/rspdm/req-netlink.c | 197 ++++++++++++++++++++++++++ lib/rspdm/spdm.h | 28 ++++ lib/rspdm/state.rs | 52 +++++++ rust/bindings/bindings_helper.h | 4 + 9 files changed, 522 insertions(+) create mode 100644 Documentation/netlink/specs/spdm.yaml create mode 100644 include/uapi/linux/spdm_netlink.h create mode 100644 lib/rspdm/netlink-autogen.c create mode 100644 lib/rspdm/netlink-autogen.h create mode 100644 lib/rspdm/req-netlink.c diff --git a/Documentation/netlink/specs/spdm.yaml b/Documentation/netlink/= specs/spdm.yaml new file mode 100644 index 000000000000..1eb349bdc0d1 --- /dev/null +++ b/Documentation/netlink/specs/spdm.yaml @@ -0,0 +1,136 @@ +# SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Cla= use) + +name: spdm + +doc: | + DMTF Security Protocol and Data Model (SPDM) + https://www.dmtf.org/dsp/DSP0274 + +protocol: genetlink + +uapi-header: linux/spdm_netlink.h + +definitions: + - + type: enum + name: spdm-reqrsp-code + doc: SPDM request or response code of a signed message (SPDM 1.0.0 tab= le 4) + entries: + - + name: challenge-auth + - + name: endpoint-info + - + name: measurements + - + name: key-exchange-rsp + - + name: finish + - + type: enum + name: hash-algo + doc: SPDM-supported hash algorithm (SPDM 1.0.0 table 13) + entries: + - + name: sha256 + - + name: sha384 + - + name: sha512 + - + name: sha3-256 + - + name: sha3-384 + - + name: sha3-512 + header: uapi/linux/hash_info.h + +attribute-sets: + - + name: sig + doc: | + Signature received from a device, together with all ancillary data + needed for re-verification. + + Meant for remote attestation services which do not trust the kernel + to have verified the signature correctly or which want to apply + policy constraints of their own. + attributes: + - + name: device + doc: | + Path under sysfs of the device generating the signature. + type: string + - + name: rsp-code + doc: | + SPDM response code of the message containing the signature, + to determine what kind of event caused signature generation. + Equivalent to the "context" string of SPDM 1.2.0 sec 15, + but represented numerically for easier parsing. + type: u8 + enum: spdm-reqrsp-code + - + name: slot + doc: | + Certificate slot used for signature generation. Note that + if the slot has since been provisioned with a different + certificate chain, re-verification of the signature will fail. + type: u8 + - + name: hash-algo + doc: | + Hash algorithm used for signature generation. + type: u16 + enum: hash-algo + - + name: sig-offset + doc: | + Offset of signature in @transcript. The signature is located + at the end of @transcript, hence its size equals @transcript + size minus this offset. + type: u32 + - + name: req-nonce-offset + doc: | + Offset of 32 byte nonce chosen by requester in @transcript. + Allows remote attestation services to verify freshness + (uniqueness) and entropy adequacy of the nonce. + type: u32 + - + name: rsp-nonce-offset + doc: | + Offset of 32 byte nonce chosen by responder in @transcript. + Allows remote attestation services to verify freshness + (uniqueness) and entropy adequacy of the nonce. + type: u32 + - + name: combined-spdm-prefix + doc: | + Only included in the message with SPDM version 1.2.0 or newer. + type: binary + checks: + exact-len: 100 + - + name: certificate-chain + type: binary + - + name: transcript + type: binary + multi-attr: true + +operations: + list: + - + name: sig + doc: Signature event + attribute-set: sig + event: + attributes: + - sig + mcgrp: sig + +mcast-groups: + list: + - + name: sig diff --git a/include/uapi/linux/spdm_netlink.h b/include/uapi/linux/spdm_ne= tlink.h new file mode 100644 index 000000000000..a7fa183757db --- /dev/null +++ b/include/uapi/linux/spdm_netlink.h @@ -0,0 +1,49 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Cl= ause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/spdm.yaml */ +/* YNL-GEN uapi header */ +/* To regenerate run: tools/net/ynl/ynl-regen.sh */ + +#ifndef _UAPI_LINUX_SPDM_NETLINK_H +#define _UAPI_LINUX_SPDM_NETLINK_H + +#define SPDM_FAMILY_NAME "spdm" +#define SPDM_FAMILY_VERSION 1 + +/* + * SPDM request or response code of a signed message (SPDM 1.0.0 table 4) + */ +enum spdm_spdm_reqrsp_code { + SPDM_SPDM_REQRSP_CODE_CHALLENGE_AUTH, + SPDM_SPDM_REQRSP_CODE_ENDPOINT_INFO, + SPDM_SPDM_REQRSP_CODE_MEASUREMENTS, + SPDM_SPDM_REQRSP_CODE_KEY_EXCHANGE_RSP, + SPDM_SPDM_REQRSP_CODE_FINISH, +}; + +enum { + SPDM_A_SIG_DEVICE =3D 1, + SPDM_A_SIG_RSP_CODE, + SPDM_A_SIG_SLOT, + SPDM_A_SIG_HASH_ALGO, + SPDM_A_SIG_SIG_OFFSET, + SPDM_A_SIG_REQ_NONCE_OFFSET, + SPDM_A_SIG_RSP_NONCE_OFFSET, + SPDM_A_SIG_COMBINED_SPDM_PREFIX, + SPDM_A_SIG_CERTIFICATE_CHAIN, + SPDM_A_SIG_TRANSCRIPT, + + __SPDM_A_SIG_MAX, + SPDM_A_SIG_MAX =3D (__SPDM_A_SIG_MAX - 1) +}; + +enum { + SPDM_CMD_SIG =3D 1, + + __SPDM_CMD_MAX, + SPDM_CMD_MAX =3D (__SPDM_CMD_MAX - 1) +}; + +#define SPDM_MCGRP_SIG "sig" + +#endif /* _UAPI_LINUX_SPDM_NETLINK_H */ diff --git a/lib/rspdm/Makefile b/lib/rspdm/Makefile index f15b1437196b..2f29d0a62c1e 100644 --- a/lib/rspdm/Makefile +++ b/lib/rspdm/Makefile @@ -8,4 +8,5 @@ obj-$(CONFIG_RSPDM) +=3D spdm.o =20 spdm-y :=3D lib.o +spdm-$(CONFIG_NET) +=3D req-netlink.o netlink-autogen.o spdm-$(CONFIG_SYSFS) +=3D req-sysfs.o diff --git a/lib/rspdm/netlink-autogen.c b/lib/rspdm/netlink-autogen.c new file mode 100644 index 000000000000..4dc950133514 --- /dev/null +++ b/lib/rspdm/netlink-autogen.c @@ -0,0 +1,33 @@ +// SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Cl= ause) +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/spdm.yaml */ +/* YNL-GEN kernel source */ +/* To regenerate run: tools/net/ynl/ynl-regen.sh */ + +#include +#include + +#include "netlink-autogen.h" + +#include +#include + +/* Ops table for spdm */ +static const struct genl_split_ops spdm_nl_ops[] =3D { +}; + +static const struct genl_multicast_group spdm_nl_mcgrps[] =3D { + [SPDM_NLGRP_SIG] =3D { "sig", }, +}; + +struct genl_family spdm_nl_family __ro_after_init =3D { + .name =3D SPDM_FAMILY_NAME, + .version =3D SPDM_FAMILY_VERSION, + .netnsok =3D true, + .parallel_ops =3D true, + .module =3D THIS_MODULE, + .split_ops =3D spdm_nl_ops, + .n_split_ops =3D ARRAY_SIZE(spdm_nl_ops), + .mcgrps =3D spdm_nl_mcgrps, + .n_mcgrps =3D ARRAY_SIZE(spdm_nl_mcgrps), +}; diff --git a/lib/rspdm/netlink-autogen.h b/lib/rspdm/netlink-autogen.h new file mode 100644 index 000000000000..2797d194604f --- /dev/null +++ b/lib/rspdm/netlink-autogen.h @@ -0,0 +1,22 @@ +/* SPDX-License-Identifier: ((GPL-2.0 WITH Linux-syscall-note) OR BSD-3-Cl= ause) */ +/* Do not edit directly, auto-generated from: */ +/* Documentation/netlink/specs/spdm.yaml */ +/* YNL-GEN kernel header */ +/* To regenerate run: tools/net/ynl/ynl-regen.sh */ + +#ifndef _LINUX_SPDM_GEN_H +#define _LINUX_SPDM_GEN_H + +#include +#include + +#include +#include + +enum { + SPDM_NLGRP_SIG, +}; + +extern struct genl_family spdm_nl_family; + +#endif /* _LINUX_SPDM_GEN_H */ diff --git a/lib/rspdm/req-netlink.c b/lib/rspdm/req-netlink.c new file mode 100644 index 000000000000..65db5ec6a16c --- /dev/null +++ b/lib/rspdm/req-netlink.c @@ -0,0 +1,197 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * DMTF Security Protocol and Data Model (SPDM) + * https://www.dmtf.org/dsp/DSP0274 + * + * Requester role: netlink interface + * + * Copyright (C) 2025 Intel Corporation + * Copyright (C) 2026 WD Corporation + */ + +#include "netlink-autogen.h" + +#include +#include +#include + +#include + +#include "spdm.h" + +#define SPDM_NONCE_SZ 32 /* SPDM 1.0.0 table 20 */ +#define SPDM_PREFIX_SZ 64 /* SPDM 1.2.0 margin no 803 */ +#define SPDM_COMBINED_PREFIX_SZ 100 /* SPDM 1.2.0 margin no 806 */ +#define SPDM_MAX_OPAQUE_DATA 1024 /* SPDM 1.0.0 table 21 */ + +static void spdm_create_combined_prefix(u8 version, const char *spdm_conte= xt, + void *buf) +{ + u8 major =3D FIELD_GET(0xf0, version); + u8 minor =3D FIELD_GET(0x0f, version); + size_t len =3D strlen(spdm_context); + int rc, zero_pad; + + rc =3D snprintf(buf, SPDM_PREFIX_SZ + 1, + "dmtf-spdm-v%hhx.%hhx.*dmtf-spdm-v%hhx.%hhx.*dmtf-spdm-v%hhx.%hhx.= *dmtf-spdm-v%hhx.%hhx.*", + major, minor, major, minor, major, minor, major, minor); + WARN_ON(rc !=3D SPDM_PREFIX_SZ); + + zero_pad =3D SPDM_COMBINED_PREFIX_SZ - SPDM_PREFIX_SZ - 1 - len; + WARN_ON(zero_pad < 0); + + memset(buf + SPDM_PREFIX_SZ + 1, 0, zero_pad); + memcpy(buf + SPDM_PREFIX_SZ + 1 + zero_pad, spdm_context, len); +} + +int spdm_netlink_sig_event(struct device *dev, + u8 version, + const void *transcript, + size_t transcript_len, + const void *cert_chain, + size_t cert_chain_len, + enum hash_algo base_hash_alg, + size_t sig_len, + int rsp_code, u8 slot, + size_t req_nonce_off, size_t rsp_nonce_off, + const char *spdm_context) +{ + unsigned int seq, msg_sz, nr_msgs, nr_pages, nr_frags; + struct sk_buff *msg; + struct nlattr *nla; + void *hdr; + const void *ptr; + int rc, i; + + if (!genl_has_listeners(&spdm_nl_family, &init_net, SPDM_NLGRP_SIG)) + return 0; + + char *devpath __free(kfree) =3D kobject_get_path(&dev->kobj, + GFP_KERNEL); + if (!devpath) + return -ENOMEM; + + nr_pages =3D transcript_len / PAGE_SIZE; + nr_msgs =3D DIV_ROUND_UP(nr_pages, MAX_SKB_FRAGS); + + /* Calculate exact size to avoid reallocation by netlink_trim() */ + msg_sz =3D nlmsg_total_size(genlmsg_msg_size( + nla_total_size(strlen(devpath)) + + nla_total_size(sizeof(u8)) + + nla_total_size(sizeof(u8)) + + nla_total_size(sizeof(u16)) + + nla_total_size(sizeof(u32)) + + nla_total_size(sizeof(u32)) + + nla_total_size(sizeof(u32)) + + nla_total_size(SPDM_COMBINED_PREFIX_SZ) + + nla_total_size(cert_chain_len) + + nla_total_size(0))); + + msg =3D genlmsg_new(msg_sz, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr =3D genlmsg_put(msg, 0, 0, &spdm_nl_family, + nr_msgs > 1 ? NLM_F_MULTI : 0, SPDM_CMD_SIG); + if (!hdr) { + rc =3D -EMSGSIZE; + goto err_free_msg; + } + + if (nla_put_string(msg, SPDM_A_SIG_DEVICE, devpath) || + nla_put_u8(msg, SPDM_A_SIG_RSP_CODE, rsp_code) || + nla_put_u8(msg, SPDM_A_SIG_SLOT, slot) || + nla_put_u16(msg, SPDM_A_SIG_HASH_ALGO, + base_hash_alg) || + nla_put_u32(msg, SPDM_A_SIG_SIG_OFFSET, + transcript_len - sig_len) || + nla_put_u32(msg, SPDM_A_SIG_REQ_NONCE_OFFSET, req_nonce_off) || + nla_put_u32(msg, SPDM_A_SIG_RSP_NONCE_OFFSET, rsp_nonce_off)) { + rc =3D -EMSGSIZE; + goto err_cancel_msg; + } + + if (version >=3D 0x12) { + nla =3D nla_reserve(msg, SPDM_A_SIG_COMBINED_SPDM_PREFIX, + SPDM_COMBINED_PREFIX_SZ); + if (!nla) { + rc =3D -EMSGSIZE; + goto err_cancel_msg; + } + + spdm_create_combined_prefix(version, spdm_context, + nla_data(nla)); + } + + if (cert_chain_len >=3D 0) + nla_put(msg, SPDM_A_SIG_CERTIFICATE_CHAIN, cert_chain_len, cert_chain); + + ptr =3D transcript; + + /* Loop over Netlink messages - break condition is in loop body */ + for (seq =3D 1; ; seq++) { + nla =3D nla_reserve(msg, SPDM_A_SIG_TRANSCRIPT, 0); + if (!nla) { + rc =3D -EMSGSIZE; + goto err_cancel_msg; + } + + nr_frags =3D min(nr_pages, MAX_SKB_FRAGS); + nla->nla_len =3D nr_frags * PAGE_SIZE; + nr_pages -=3D nr_frags; + + /* Loop over fragments of this Netlink message */ + for (i =3D 0; i < nr_frags; i++) { + struct page *page =3D vmalloc_to_page(ptr); + size_t sz =3D min(transcript_len, PAGE_SIZE); + + skb_add_rx_frag(msg, i, page, 0, sz, sz); + ptr +=3D PAGE_SIZE; + transcript_len -=3D PAGE_SIZE; + } + + genlmsg_end(msg, hdr); + rc =3D genlmsg_multicast(&spdm_nl_family, msg, 0, + SPDM_NLGRP_SIG, GFP_KERNEL); + if (rc) + return rc; + + if (nr_pages =3D=3D 0) /* End of loop - entire transcript sent */ + break; + + /* Start new message for remainder of transcript */ + msg_sz =3D nlmsg_total_size(genlmsg_msg_size(nla_total_size(0))); + + msg =3D genlmsg_new(msg_sz, GFP_KERNEL); + if (!msg) + return -ENOMEM; + + hdr =3D genlmsg_put(msg, 0, seq, &spdm_nl_family, + NLM_F_MULTI, SPDM_CMD_SIG); + if (!hdr) { + rc =3D -EMSGSIZE; + goto err_free_msg; + } + } + + return 0; + +err_cancel_msg: + nlmsg_cancel(msg, hdr); +err_free_msg: + nlmsg_free(msg); + return rc; +} + +static int __init spdm_netlink_init(void) +{ + return genl_register_family(&spdm_nl_family); +} + +static void __exit spdm_netlink_exit(void) +{ + genl_unregister_family(&spdm_nl_family); +} + +arch_initcall(spdm_netlink_init); +module_exit(spdm_netlink_exit); diff --git a/lib/rspdm/spdm.h b/lib/rspdm/spdm.h index 43ef56a073c0..36bc1b47a796 100644 --- a/lib/rspdm/spdm.h +++ b/lib/rspdm/spdm.h @@ -12,6 +12,34 @@ #ifndef _LIB_SPDM_H_ #define _LIB_SPDM_H_ =20 +#include + +#ifdef CONFIG_NET +int spdm_netlink_sig_event(struct device *dev, + u8 version, + const void *transcript, + size_t transcript_len, + const void *cert_chain, + size_t cert_chain_len, + enum hash_algo base_hash_alg, + size_t sig_len, + int rsp_code, u8 slot, + size_t req_nonce_off, size_t rsp_nonce_off, + const char *spdm_context); +#else +static inline int spdm_netlink_sig_event(struct device *dev, + u8 version, + const void *transcript, + size_t transcript_len, + const void *cert_chain, + size_t cert_chain_len, + enum hash_algo base_hash_alg, + size_t sig_len, + int rsp_code, u8 slot, + size_t req_nonce_off, size_t rsp_nonce_off, + const char *spdm_context) { return 0; } +#endif + int spdm_chall(struct spdm_state *spdm_state); =20 #endif /* _LIB_SPDM_H_ */ diff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs index a4d803af48fe..8b18e415d4d5 100644 --- a/lib/rspdm/state.rs +++ b/lib/rspdm/state.rs @@ -13,6 +13,7 @@ use kernel::{ bindings, error::{code::EINVAL, from_err_ptr, to_result, Error}, + page::PAGE_SIZE, str::CStr, str::CString, validate::Untrusted, @@ -1036,6 +1037,57 @@ pub(crate) fn challenge(&mut self, slot: u8, verify:= bool) -> Result<(), Error> }; } =20 + let spdm_context =3D b"responder-challenge_auth signing\0"; + + let hash_digest_size =3D if self.base_hash_alg < bindings::hash_al= go_HASH_ALGO__LAST { + // SAFETY: `base_hash_alg` is a valid offset into `hash_digest= _size` + (unsafe { bindings::get_hash_digest_size(self.base_hash_alg) }= ) as usize + } else { + to_result(-(bindings::EIO as i32))?; + 0 + }; + + let req_nonce_off =3D self.transcript.len() + core::mem::offset_of= !(ChallengeReq, nonce); + let rsp_nonce_off =3D + self.transcript.len() + core::mem::size_of::() += hash_digest_size; + + // This is the actual transcript length + let transcript_len =3D self.transcript.len(); + + // This is how much extra capacity we need to page align the trans= cript buffer + let extra_cap =3D PAGE_SIZE - transcript_len.rem_euclid(PAGE_SIZE); + // Ensure we have the capacity + self.transcript.reserve(extra_cap, GFP_KERNEL)?; + + // We know the buffer is this long and this value will be PAGE_SIZ= E aligned + let transcript_buf_len =3D transcript_len + extra_cap; + + let cert_chain_len =3D self.certs[slot as usize].len(); + + let cert_chain =3D if cert_chain_len > 0 { + self.certs[slot as usize].as_ptr() as *const c_void + } else { + core::ptr::null_mut() + }; + + unsafe { + bindings::spdm_netlink_sig_event( + self.dev, + self.version, + self.transcript.as_ptr() as *const c_void, + transcript_buf_len, + cert_chain, + cert_chain_len, + self.base_hash_alg, + self.sig_len, + 0x03, + slot, + req_nonce_off, + rsp_nonce_off, + spdm_context as *const _ as *const u8, + ); + } + Ok(()) } } diff --git a/rust/bindings/bindings_helper.h b/rust/bindings/bindings_helpe= r.h index 35e4378fb9dc..64326e5f2490 100644 --- a/rust/bindings/bindings_helper.h +++ b/rust/bindings/bindings_helper.h @@ -156,3 +156,7 @@ const vm_flags_t RUST_CONST_HELPER_VM_NOHUGEPAGE =3D VM= _NOHUGEPAGE; #include "../../drivers/android/binder/rust_binder_events.h" #include "../../drivers/android/binder/page_range_helper.h" #endif + +#if IS_ENABLED(CONFIG_RSPDM) +#include "../../lib/rspdm/spdm.h" +#endif --=20 2.52.0