Patch Detail
get:
Show a patch.
patch:
Update a patch.
put:
Update a patch.
GET /api/1.2/patches/2234748/?format=api
{ "id": 2234748, "url": "http://patchwork.ozlabs.org/api/1.2/patches/2234748/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-pci/patch/20260508031710.514574-14-alistair.francis@wdc.com/", "project": { "id": 28, "url": "http://patchwork.ozlabs.org/api/1.2/projects/28/?format=api", "name": "Linux PCI development", "link_name": "linux-pci", "list_id": "linux-pci.vger.kernel.org", "list_email": "linux-pci@vger.kernel.org", "web_url": null, "scm_url": null, "webscm_url": null, "list_archive_url": "", "list_archive_url_format": "", "commit_url_format": "" }, "msgid": "<20260508031710.514574-14-alistair.francis@wdc.com>", "list_archive_url": null, "date": "2026-05-08T03:17:05", "name": "[13/18] lib: rspdm: Support SPDM negotiate_algorithms", "commit_ref": null, "pull_url": null, "state": "new", "archived": false, "hash": "baecb3c31b2ee4957bb5fff0e9db56361e89864a", "submitter": { "id": 64571, "url": "http://patchwork.ozlabs.org/api/1.2/people/64571/?format=api", "name": "Alistair Francis", "email": "alistair23@gmail.com" }, "delegate": null, "mbox": "http://patchwork.ozlabs.org/project/linux-pci/patch/20260508031710.514574-14-alistair.francis@wdc.com/mbox/", "series": [ { "id": 503312, "url": "http://patchwork.ozlabs.org/api/1.2/series/503312/?format=api", "web_url": "http://patchwork.ozlabs.org/project/linux-pci/list/?series=503312", "date": "2026-05-08T03:16:52", "name": "lib: Rust implementation of SPDM", "version": 1, "mbox": "http://patchwork.ozlabs.org/series/503312/mbox/" } ], "comments": "http://patchwork.ozlabs.org/api/patches/2234748/comments/", "check": "pending", "checks": "http://patchwork.ozlabs.org/api/patches/2234748/checks/", "tags": {}, "related": [], "headers": { "Return-Path": "\n <linux-pci+bounces-54168-incoming=patchwork.ozlabs.org@vger.kernel.org>", "X-Original-To": [ "incoming@patchwork.ozlabs.org", "linux-pci@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=iA/eIkm7;\n\tdkim-atps=neutral", "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=172.105.105.114; helo=tor.lore.kernel.org;\n envelope-from=linux-pci+bounces-54168-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=\"iA/eIkm7\"", "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.214.178", "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 tor.lore.kernel.org (tor.lore.kernel.org [172.105.105.114])\n\t(using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits)\n\t key-exchange x25519 server-signature ECDSA (secp384r1) server-digest SHA384)\n\t(No client certificate requested)\n\tby legolas.ozlabs.org (Postfix) with ESMTPS id 4gBZFR5kLQz1yK7\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 08 May 2026 13:23:07 +1000 (AEST)", "from smtp.subspace.kernel.org (conduit.subspace.kernel.org\n [100.90.174.1])\n\tby tor.lore.kernel.org (Postfix) with ESMTP id 108FA309DA2E\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 8 May 2026 03:19:37 +0000 (UTC)", "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 43CB631326B;\n\tFri, 8 May 2026 03:19:09 +0000 (UTC)", "from mail-pl1-f178.google.com (mail-pl1-f178.google.com\n [209.85.214.178])\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 EABEF2FA0C6\n\tfor <linux-pci@vger.kernel.org>; Fri, 8 May 2026 03:19:03 +0000 (UTC)", "by mail-pl1-f178.google.com with SMTP id\n d9443c01a7336-2b4650d5f5cso5724635ad.0\n for <linux-pci@vger.kernel.org>; Thu, 07 May 2026 20:19:03 -0700 (PDT)", "from toolbx.alistair23.me ([2403:581e:fdf9:0:6209:4521:6813:45b7])\n by smtp.gmail.com with ESMTPSA id\n d9443c01a7336-2baf1eafa62sm3220685ad.74.2026.05.07.20.18.54\n (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n Thu, 07 May 2026 20:19:01 -0700 (PDT)" ], "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1778210348; cv=none;\n b=PAWyvNAFi9a1IHXohj71wzfr4Xq/EoF+KwNspSVmpU0Cg3/ztyVCfbYHr3Su34+wZsUqnkJkw3wBFglZ9JvGCtBoREjZIAUYnS8hgce1W2tFRzbqL5rlMYg/lGLPjC6JdeSTZOQIczb/WVQH0tGcbiKCjXse1RpMEY0U99WNgKI=", "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1778210348; c=relaxed/simple;\n\tbh=AEIRQMFJ78obs/Fig6dF1+21hQUwsD8gqjiemnD2yGk=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=fOQGQhbMPXkHD19u4NcWnL30KbuH0hd9LBJ68KZAGgU/MANkAeiI+SduUVU/O9kGiA3vpOzER7l1ZfBc/CfiZTsbqDSB1dg0UnTzUMYOqlKMBkSY4OWvHtTS/DCjdjlD8wJrfeiEekbzO9fgndCAc8ZoSwIFL6vCZqA7pqq7MGw=", "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=iA/eIkm7; arc=none smtp.client-ip=209.85.214.178", "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=gmail.com; s=20251104; t=1778210342; x=1778815142;\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=67SIRNlN4DFhJcQDNjNjH5wMdIlffhQXlWGApt2+Y0k=;\n b=iA/eIkm7wnGuzAdFikXNwpvsyoNZ7NMjztzH8sDawquOmCqwzIAaqzbvQCr8qDpArq\n BMWyvsuXXxBve/Xzgdagevj2iULFZoD37rZQLgLnTNQe//bhaIjfUhnD/OgWrowTiFIz\n gzIIiJBsQf3nD2bPT2E3T+eHwhUPkEpNzSp5iG+o9EYhafostVMyTptHfeXwpjyWSVcA\n luucz3v9qZvyNAVBFp/m/2WRNpq/afWkJ9fjG6YP+Y7uHIK6Y2LlCNE7tEeo8aSb0urJ\n 4cQrNlvioUA/+hMMJvkUXfZ4nhsYnYt1FTHe2roEbjXCl1ROthApvT1U4yoIWsoVucco\n nxEw==", "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n d=1e100.net; s=20251104; t=1778210342; x=1778815142;\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=67SIRNlN4DFhJcQDNjNjH5wMdIlffhQXlWGApt2+Y0k=;\n b=YAIznyR+a4CwkrcRFGSNllhr9qLRsS5EkixMzbBxdxRacWLnHJYil2RmMnWkOkxacp\n j+8yP2BTkPFH+2f545jkz2T8f3sn493G9DDZp5HVkykF+z6cUepj+Es+Nxm/f5QThBT1\n dx4T1bnkCUr4zf10VzPr3vC45DDnRB+9ZXXoROIpQf8VkCfk0GmXfU1hUXfgf1q7w2MQ\n qC5TPiMzA7X1ESPdJrE0wK1nLxDKs1D8noThhWyAWNU4uk8+oOasDofKu9pKC4NKKDqv\n HkpqYmb4uszHhaT5+EGysz8uNmMlVUFWHXBURtA267BZS7DYBgAb1tUzNw60h4opqQ/q\n L38g==", "X-Forwarded-Encrypted": "i=1;\n AFNElJ/3CCNa05gFT8Yf0ZuHZl5yLmjD3xOg8ssbnTWFZ3sb1ayqB2Qthx2iyXu0MDEiwIQ/A234AXqHg8c=@vger.kernel.org", "X-Gm-Message-State": "AOJu0YxtN9EzdifQ/hUmQqovFSLVoEw2cFuDrXtb5JvMipPz42hk2gzU\n\tm8cVyvgsRs3/o2o1F/M5/3hY3G+q/Zo+8XVYiM6QLGulrIseqgx9V0+M", "X-Gm-Gg": "Acq92OEOfqascKWV7/YRebWcn/DZhjq8QsDZqkTBoS2kUFFHrgHGrBJQF4mmaLaerOI\n\t7uSMph/4LPnlNb9kR1xokBwKf2OS4P3wfF9SFe8drBur/i/HpkyrlB30E1Rd+tBW+wBJ/2cmqoh\n\tP2pJziQNJxKlVZp24aIpeYI3alWN5fGJ1rPM1e6rRT1SLTOjNikBA6t5pHLreGhX2RLt6nbRyY4\n\t7B1AyhPyqHOdvfdURvhiEnmYGsVMrR+/NVLYNvGBxuMjo53VegS8sr7ZTUZ5TmKWcY0g9GvId/A\n\tA33zS6g0mG2cy3d/7jJTWIFmIMA/frpu0w9NaB5Bqw0wiQSevQHD33amc8bs3HZY7L3sFQDEwq/\n\tp9ZoNik41eVa5sBQ/jIGp4LcSbgAew/NrcBL70wGsJx6J10lqRS1/P5QiqC3OmlTqAIWJShfh4A\n\t+UYR4EP95kMw6jzeEbVNO75j6aCVhIUc2pbely4RvW", "X-Received": "by 2002:a17:903:1c8:b0:2b4:65d8:6a20 with SMTP id\n d9443c01a7336-2ba78f50177mr116458145ad.2.1778210341840;\n Thu, 07 May 2026 20:19:01 -0700 (PDT)", "From": "alistair23@gmail.com", "X-Google-Original-From": "alistair.francis@wdc.com", "To": "alistair@alistair23.me,\n\tlinux-kernel@vger.kernel.org,\n\tlukas@wunner.de,\n\tJonathan.Cameron@huawei.com,\n\tbhelgaas@google.com,\n\trust-for-linux@vger.kernel.org,\n\takpm@linux-foundation.org,\n\tlinux-cxl@vger.kernel.org,\n\tdjbw@kernel.org,\n\tlinux-pci@vger.kernel.org", "Cc": "alex.gaynor@gmail.com,\n\twilfred.mallawa@wdc.com,\n\tgary@garyguo.net,\n\tbjorn3_gh@protonmail.com,\n\tbenno.lossin@proton.me,\n\taliceryhl@google.com,\n\tboqun.feng@gmail.com,\n\ta.hindborg@kernel.org,\n\ttmgross@umich.edu,\n\tojeda@kernel.org,\n\talistair23@gmail.com", "Subject": "[PATCH 13/18] lib: rspdm: Support SPDM negotiate_algorithms", "Date": "Fri, 8 May 2026 13:17:05 +1000", "Message-ID": "<20260508031710.514574-14-alistair.francis@wdc.com>", "X-Mailer": "git-send-email 2.52.0", "In-Reply-To": "<20260508031710.514574-1-alistair.francis@wdc.com>", "References": "<20260508031710.514574-1-alistair.francis@wdc.com>", "Precedence": "bulk", "X-Mailing-List": "linux-pci@vger.kernel.org", "List-Id": "<linux-pci.vger.kernel.org>", "List-Subscribe": "<mailto:linux-pci+subscribe@vger.kernel.org>", "List-Unsubscribe": "<mailto:linux-pci+unsubscribe@vger.kernel.org>", "MIME-Version": "1.0", "Content-Transfer-Encoding": "8bit" }, "content": "From: Alistair Francis <alistair@alistair23.me>\n\nSupport the NEGOTIATE_ALGORITHMS SPDM command.\n\nSigned-off-by: Alistair Francis <alistair@alistair23.me>\n---\n lib/rspdm/consts.rs | 65 ++++++++++++-\n lib/rspdm/lib.rs | 18 +++-\n lib/rspdm/state.rs | 211 +++++++++++++++++++++++++++++++++++++++++\n lib/rspdm/validator.rs | 115 +++++++++++++++++++++-\n 4 files changed, 404 insertions(+), 5 deletions(-)", "diff": "diff --git a/lib/rspdm/consts.rs b/lib/rspdm/consts.rs\nindex ef7d2d1d8e6e..e4652b18eb2a 100644\n--- a/lib/rspdm/consts.rs\n+++ b/lib/rspdm/consts.rs\n@@ -9,7 +9,11 @@\n \n use crate::validator::SpdmHeader;\n use core::mem;\n-use kernel::bits::bit_u32;\n+use kernel::bits::{\n+ bit_u32,\n+ bit_u8,\n+ genmask_u32, //\n+};\n \n /* SPDM versions supported by this implementation */\n pub(crate) const SPDM_VER_10: u8 = 0x10;\n@@ -73,13 +77,68 @@ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n \n // SPDM cryptographic timeout of this implementation:\n // Assume calculations may take up to 1 sec on a busy machine, which equals\n-// roughly 1 << 20. That's within the limits mandated for responders by CMA\n-// (1 << 23 usec, PCIe r6.2 sec 6.31.3) and DOE (1 sec, PCIe r6.2 sec 6.30.2).\n+// roughly bit_u32(20. That's within the limits mandated for responders by CMA\n+// (bit_u32(23 usec, PCIe r6.2 sec 6.31.3) and DOE (1 sec, PCIe r6.2 sec 6.30.2).\n // Used in GET_CAPABILITIES exchange.\n pub(crate) const SPDM_CTEXPONENT: u8 = 20;\n \n pub(crate) const SPDM_CERT_CAP: u32 = bit_u32(1);\n pub(crate) const SPDM_CHAL_CAP: u32 = bit_u32(2);\n+pub(crate) const SPDM_MEAS_CAP_MASK: u32 = genmask_u32(3..=4);\n+pub(crate) const SPDM_KEY_EX_CAP: u32 = bit_u32(9);\n \n pub(crate) const SPDM_REQ_CAPS: u32 = SPDM_CERT_CAP | SPDM_CHAL_CAP;\n pub(crate) const SPDM_RSP_MIN_CAPS: u32 = SPDM_CERT_CAP | SPDM_CHAL_CAP;\n+\n+pub(crate) const SPDM_NEGOTIATE_ALGS: u8 = 0xe3;\n+\n+pub(crate) const SPDM_MEAS_SPEC_DMTF: u8 = bit_u8(0);\n+\n+pub(crate) const SPDM_ASYM_RSASSA_2048: u32 = bit_u32(0);\n+pub(crate) const _SPDM_ASYM_RSAPSS_2048: u32 = bit_u32(1);\n+pub(crate) const SPDM_ASYM_RSASSA_3072: u32 = bit_u32(2);\n+pub(crate) const _SPDM_ASYM_RSAPSS_3072: u32 = bit_u32(3);\n+pub(crate) const SPDM_ASYM_ECDSA_ECC_NIST_P256: u32 = bit_u32(4);\n+pub(crate) const SPDM_ASYM_RSASSA_4096: u32 = bit_u32(5);\n+pub(crate) const _SPDM_ASYM_RSAPSS_4096: u32 = bit_u32(6);\n+pub(crate) const SPDM_ASYM_ECDSA_ECC_NIST_P384: u32 = bit_u32(7);\n+pub(crate) const SPDM_ASYM_ECDSA_ECC_NIST_P521: u32 = bit_u32(8);\n+pub(crate) const _SPDM_ASYM_SM2_ECC_SM2_P256: u32 = bit_u32(9);\n+pub(crate) const _SPDM_ASYM_EDDSA_ED25519: u32 = bit_u32(10);\n+pub(crate) const _SPDM_ASYM_EDDSA_ED448: u32 = bit_u32(11);\n+\n+pub(crate) const SPDM_HASH_SHA_256: u32 = bit_u32(0);\n+pub(crate) const SPDM_HASH_SHA_384: u32 = bit_u32(1);\n+pub(crate) const SPDM_HASH_SHA_512: u32 = bit_u32(2);\n+\n+// If the crypto support isn't enabled don't offer the algorithms\n+// to the responder\n+#[cfg(CONFIG_CRYPTO_RSA)]\n+pub(crate) const SPDM_ASYM_RSA: u32 =\n+ SPDM_ASYM_RSASSA_2048 | SPDM_ASYM_RSASSA_3072 | SPDM_ASYM_RSASSA_4096;\n+#[cfg(not(CONFIG_CRYPTO_RSA))]\n+pub(crate) const SPDM_ASYM_RSA: u32 = 0;\n+\n+#[cfg(CONFIG_CRYPTO_ECDSA)]\n+pub(crate) const SPDM_ASYM_ECDSA: u32 =\n+ SPDM_ASYM_ECDSA_ECC_NIST_P256 | SPDM_ASYM_ECDSA_ECC_NIST_P384 | SPDM_ASYM_ECDSA_ECC_NIST_P521;\n+#[cfg(not(CONFIG_CRYPTO_ECDSA))]\n+pub(crate) const SPDM_ASYM_ECDSA: u32 = 0;\n+\n+#[cfg(CONFIG_CRYPTO_SHA256)]\n+pub(crate) const SPDM_HASH_SHA2_256: u32 = SPDM_HASH_SHA_256;\n+#[cfg(not(CONFIG_CRYPTO_SHA256))]\n+pub(crate) const SPDM_HASH_SHA2_256: u32 = 0;\n+\n+#[cfg(CONFIG_CRYPTO_SHA512)]\n+pub(crate) const SPDM_HASH_SHA2_384_512: u32 = SPDM_HASH_SHA_384 | SPDM_HASH_SHA_512;\n+#[cfg(not(CONFIG_CRYPTO_SHA512))]\n+pub(crate) const SPDM_HASH_SHA2_384_512: u32 = 0;\n+\n+pub(crate) const SPDM_ASYM_ALGOS: u32 = SPDM_ASYM_RSA | SPDM_ASYM_ECDSA;\n+pub(crate) const SPDM_HASH_ALGOS: u32 = SPDM_HASH_SHA2_256 | SPDM_HASH_SHA2_384_512;\n+\n+/* Maximum number of ReqAlgStructs sent by this implementation */\n+// pub(crate) const SPDM_MAX_REQ_ALG_STRUCT: usize = 4;\n+\n+pub(crate) const SPDM_OPAQUE_DATA_FMT_GENERAL: u8 = bit_u8(1);\ndiff --git a/lib/rspdm/lib.rs b/lib/rspdm/lib.rs\nindex 9628f258854c..72886a5dfd69 100644\n--- a/lib/rspdm/lib.rs\n+++ b/lib/rspdm/lib.rs\n@@ -116,6 +116,10 @@\n return e.to_errno() as c_int;\n }\n \n+ if let Err(e) = state.negotiate_algs() {\n+ return e.to_errno() as c_int;\n+ }\n+\n 0\n }\n \n@@ -123,4 +127,16 @@\n ///\n /// @spdm_state: SPDM session state\n #[export]\n-pub unsafe extern \"C\" fn spdm_destroy(_state_ptr: *mut spdm_state) {}\n+pub unsafe extern \"C\" fn spdm_destroy(state_ptr: *mut spdm_state) {\n+ let state: &mut SpdmState = unsafe { &mut (*(state_ptr as *mut SpdmState)) };\n+\n+ if let Some(desc) = &mut state.desc {\n+ unsafe {\n+ bindings::kfree(*desc as *mut _ as *mut c_void);\n+ }\n+ }\n+\n+ unsafe {\n+ bindings::crypto_free_shash(state.shash);\n+ }\n+}\ndiff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs\nindex e7119ffa9a69..34676744e509 100644\n--- a/lib/rspdm/state.rs\n+++ b/lib/rspdm/state.rs\n@@ -14,19 +14,36 @@\n bindings,\n error::{\n code::EINVAL,\n+ from_err_ptr,\n to_result,\n Error, //\n },\n+ str::CStr,\n validate::Untrusted,\n };\n \n use crate::consts::{\n SpdmErrorCode,\n+ SPDM_ASYM_ALGOS,\n+ SPDM_ASYM_ECDSA_ECC_NIST_P256,\n+ SPDM_ASYM_ECDSA_ECC_NIST_P384,\n+ SPDM_ASYM_ECDSA_ECC_NIST_P521,\n+ SPDM_ASYM_RSASSA_2048,\n+ SPDM_ASYM_RSASSA_3072,\n+ SPDM_ASYM_RSASSA_4096,\n SPDM_ERROR,\n SPDM_GET_VERSION_LEN,\n+ SPDM_HASH_ALGOS,\n+ SPDM_HASH_SHA_256,\n+ SPDM_HASH_SHA_384,\n+ SPDM_HASH_SHA_512,\n+ SPDM_KEY_EX_CAP,\n SPDM_MAX_VER,\n+ SPDM_MEAS_CAP_MASK,\n+ SPDM_MEAS_SPEC_DMTF,\n SPDM_MIN_DATA_TRANSFER_SIZE,\n SPDM_MIN_VER,\n+ SPDM_OPAQUE_DATA_FMT_GENERAL,\n SPDM_REQ,\n SPDM_RSP_MIN_CAPS,\n SPDM_VER_10,\n@@ -38,6 +55,8 @@\n GetCapabilitiesRsp,\n GetVersionReq,\n GetVersionRsp,\n+ NegotiateAlgsReq,\n+ NegotiateAlgsRsp,\n SpdmErrorRsp,\n SpdmHeader, //\n };\n@@ -56,6 +75,25 @@\n /// Negotiated during GET_VERSION exchange.\n /// @rsp_caps: Cached capabilities of responder.\n /// Received during GET_CAPABILITIES exchange.\n+/// @base_asym_alg: Asymmetric key algorithm for signature verification of\n+/// CHALLENGE_AUTH and MEASUREMENTS messages.\n+/// Selected by responder during NEGOTIATE_ALGORITHMS exchange.\n+/// @base_hash_alg: Hash algorithm for signature verification of\n+/// CHALLENGE_AUTH and MEASUREMENTS messages.\n+/// Selected by responder during NEGOTIATE_ALGORITHMS exchange.\n+/// @meas_hash_alg: Hash algorithm for measurement blocks.\n+/// Selected by responder during NEGOTIATE_ALGORITHMS exchange.\n+/// @base_asym_enc: Human-readable name of @base_asym_alg's signature encoding.\n+/// Passed to crypto subsystem when calling verify_signature().\n+/// @sig_len: Signature length of @base_asym_alg (in bytes).\n+/// S or SigLen in SPDM specification.\n+/// @base_hash_alg_name: Human-readable name of @base_hash_alg.\n+/// Passed to crypto subsystem when calling crypto_alloc_shash() and\n+/// verify_signature().\n+/// @shash: Synchronous hash handle for @base_hash_alg computation.\n+/// @desc: Synchronous hash context for @base_hash_alg computation.\n+/// @hash_len: Hash length of @base_hash_alg (in bytes).\n+/// H in SPDM specification.\n #[expect(dead_code)]\n pub struct SpdmState {\n pub(crate) dev: *mut bindings::device,\n@@ -67,6 +105,19 @@ pub struct SpdmState {\n // Negotiated state\n pub(crate) version: u8,\n pub(crate) rsp_caps: u32,\n+ pub(crate) base_asym_alg: u32,\n+ pub(crate) base_hash_alg: u32,\n+ pub(crate) meas_hash_alg: u32,\n+\n+ /* Signature algorithm */\n+ base_asym_enc: &'static CStr,\n+ sig_len: usize,\n+\n+ /* Hash algorithm */\n+ base_hash_alg_name: &'static CStr,\n+ pub(crate) shash: *mut bindings::crypto_shash,\n+ pub(crate) desc: Option<&'static mut bindings::shash_desc>,\n+ pub(crate) hash_len: usize,\n }\n \n impl SpdmState {\n@@ -85,6 +136,15 @@ pub(crate) fn new(\n validate,\n version: SPDM_MIN_VER,\n rsp_caps: 0,\n+ base_asym_alg: 0,\n+ base_hash_alg: 0,\n+ meas_hash_alg: 0,\n+ base_asym_enc: unsafe { CStr::from_bytes_with_nul_unchecked(b\"\\0\") },\n+ sig_len: 0,\n+ base_hash_alg_name: unsafe { CStr::from_bytes_with_nul_unchecked(b\"\\0\") },\n+ shash: core::ptr::null_mut(),\n+ desc: None,\n+ hash_len: 0,\n }\n }\n \n@@ -367,4 +427,155 @@ pub(crate) fn get_capabilities(&mut self) -> Result<(), Error> {\n \n Ok(())\n }\n+\n+ fn update_response_algs(&mut self) -> Result<(), Error> {\n+ match self.base_asym_alg {\n+ SPDM_ASYM_RSASSA_2048 => {\n+ self.sig_len = 256;\n+ self.base_asym_enc = CStr::from_bytes_with_nul(b\"pkcs1\\0\")?;\n+ }\n+ SPDM_ASYM_RSASSA_3072 => {\n+ self.sig_len = 384;\n+ self.base_asym_enc = CStr::from_bytes_with_nul(b\"pkcs1\\0\")?;\n+ }\n+ SPDM_ASYM_RSASSA_4096 => {\n+ self.sig_len = 512;\n+ self.base_asym_enc = CStr::from_bytes_with_nul(b\"pkcs1\\0\")?;\n+ }\n+ SPDM_ASYM_ECDSA_ECC_NIST_P256 => {\n+ self.sig_len = 64;\n+ self.base_asym_enc = CStr::from_bytes_with_nul(b\"p1363\\0\")?;\n+ }\n+ SPDM_ASYM_ECDSA_ECC_NIST_P384 => {\n+ self.sig_len = 96;\n+ self.base_asym_enc = CStr::from_bytes_with_nul(b\"p1363\\0\")?;\n+ }\n+ SPDM_ASYM_ECDSA_ECC_NIST_P521 => {\n+ self.sig_len = 132;\n+ self.base_asym_enc = CStr::from_bytes_with_nul(b\"p1363\\0\")?;\n+ }\n+ _ => {\n+ pr_err!(\"Unknown asym algorithm\\n\");\n+ return Err(EINVAL);\n+ }\n+ }\n+\n+ match self.base_hash_alg {\n+ SPDM_HASH_SHA_256 => {\n+ self.base_hash_alg_name = CStr::from_bytes_with_nul(b\"sha256\\0\")?;\n+ }\n+ SPDM_HASH_SHA_384 => {\n+ self.base_hash_alg_name = CStr::from_bytes_with_nul(b\"sha384\\0\")?;\n+ }\n+ SPDM_HASH_SHA_512 => {\n+ self.base_hash_alg_name = CStr::from_bytes_with_nul(b\"sha512\\0\")?;\n+ }\n+ _ => {\n+ pr_err!(\"Unknown hash algorithm\\n\");\n+ return Err(EINVAL);\n+ }\n+ }\n+\n+ /*\n+ * shash and desc allocations are reused for subsequent measurement\n+ * retrieval, hence are not freed until spdm_reset().\n+ */\n+ self.shash =\n+ unsafe { bindings::crypto_alloc_shash(self.base_hash_alg_name.as_char_ptr(), 0, 0) };\n+ from_err_ptr(self.shash)?;\n+\n+ let desc_len = core::mem::size_of::<bindings::shash_desc>()\n+ + unsafe { bindings::crypto_shash_descsize(self.shash) } as usize;\n+\n+ let mut desc_vec: KVec<u8> = KVec::with_capacity(desc_len, GFP_KERNEL)?;\n+ // SAFETY: `desc_vec` is `desc_len` long\n+ let desc_buf = unsafe { from_raw_parts_mut(desc_vec.as_mut_ptr(), desc_len) };\n+\n+ let desc = unsafe {\n+ core::mem::transmute::<*mut c_void, &mut bindings::shash_desc>(\n+ desc_buf.as_mut_ptr() as *mut c_void\n+ )\n+ };\n+ desc.tfm = self.shash;\n+\n+ self.desc = Some(desc);\n+\n+ /* Used frequently to compute offsets, so cache H */\n+ self.hash_len = unsafe { bindings::crypto_shash_digestsize(self.shash) as usize };\n+\n+ if let Some(desc) = &mut self.desc {\n+ unsafe { to_result(bindings::crypto_shash_init(*desc)) }\n+ } else {\n+ Err(ENOMEM)\n+ }\n+ }\n+\n+ pub(crate) fn negotiate_algs(&mut self) -> Result<(), Error> {\n+ let mut request = NegotiateAlgsReq::default();\n+ request.version = self.version;\n+\n+ if self.version >= SPDM_VER_12 && (self.rsp_caps & SPDM_KEY_EX_CAP) == SPDM_KEY_EX_CAP {\n+ request.other_params_support = SPDM_OPAQUE_DATA_FMT_GENERAL;\n+ }\n+\n+ let req_sz = core::mem::size_of::<NegotiateAlgsReq>();\n+ let rsp_sz = core::mem::size_of::<NegotiateAlgsRsp>();\n+\n+ request.length = req_sz as u16;\n+\n+ // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice\n+ let request_buf = unsafe { from_raw_parts_mut(&mut request as *mut _ as *mut u8, req_sz) };\n+\n+ let mut response_vec: KVec<u8> = KVec::with_capacity(rsp_sz, GFP_KERNEL)?;\n+ // SAFETY: `response_vec` is rsp_sz length, initialised, aligned\n+ // and won't be mutated\n+ let response_buf = unsafe { from_raw_parts_mut(response_vec.as_mut_ptr(), rsp_sz) };\n+\n+ let rc = self.spdm_exchange(request_buf, response_buf)?;\n+\n+ if rc < (rsp_sz as i32) {\n+ pr_err!(\"Truncated capabilities response\\n\");\n+ to_result(-(bindings::EIO as i32))?;\n+ }\n+\n+ // SAFETY: `rc` is the length of data read, which will be smaller\n+ // then the capacity of the vector\n+ unsafe { response_vec.inc_len(rc as usize) };\n+\n+ let response: &mut NegotiateAlgsRsp =\n+ Untrusted::new_mut(&mut response_vec).validate_mut()?;\n+\n+ self.base_asym_alg = response.base_asym_sel;\n+ self.base_hash_alg = response.base_hash_sel;\n+ self.meas_hash_alg = response.measurement_hash_algo;\n+\n+ if self.base_asym_alg & SPDM_ASYM_ALGOS == 0 || self.base_hash_alg & SPDM_HASH_ALGOS == 0 {\n+ pr_err!(\"No common supported algorithms\\n\");\n+ to_result(-(bindings::EPROTO as i32))?;\n+ }\n+\n+ // /* Responder shall select exactly 1 alg (SPDM 1.0.0 table 14) */\n+ if self.base_asym_alg.count_ones() != 1\n+ || self.base_hash_alg.count_ones() != 1\n+ || response.ext_asym_sel_count != 0\n+ || response.ext_hash_sel_count != 0\n+ || response.param1 > request.param1\n+ || response.other_params_sel != request.other_params_support\n+ {\n+ pr_err!(\"Malformed algorithms response\\n\");\n+ to_result(-(bindings::EPROTO as i32))?;\n+ }\n+\n+ if self.rsp_caps & SPDM_MEAS_CAP_MASK == SPDM_MEAS_CAP_MASK\n+ && (self.meas_hash_alg.count_ones() != 1\n+ || response.measurement_specification_sel != SPDM_MEAS_SPEC_DMTF)\n+ {\n+ pr_err!(\"Malformed algorithms response\\n\");\n+ to_result(-(bindings::EPROTO as i32))?;\n+ }\n+\n+ self.update_response_algs()?;\n+\n+ Ok(())\n+ }\n }\ndiff --git a/lib/rspdm/validator.rs b/lib/rspdm/validator.rs\nindex 7dc55882c880..9d738133399d 100644\n--- a/lib/rspdm/validator.rs\n+++ b/lib/rspdm/validator.rs\n@@ -9,7 +9,8 @@\n \n use crate::bindings::{\n __IncompleteArrayField,\n- __le16, //\n+ __le16,\n+ __le32, //\n };\n use crate::consts::SpdmErrorCode;\n use core::mem;\n@@ -26,10 +27,14 @@\n };\n \n use crate::consts::{\n+ SPDM_ASYM_ALGOS,\n SPDM_CTEXPONENT,\n SPDM_GET_CAPABILITIES,\n SPDM_GET_VERSION,\n+ SPDM_HASH_ALGOS,\n+ SPDM_MEAS_SPEC_DMTF,\n SPDM_MIN_VER,\n+ SPDM_NEGOTIATE_ALGS,\n SPDM_REQ_CAPS, //\n SPDM_VER_11,\n };\n@@ -236,3 +241,111 @@ fn validate(unvalidated: &mut Unvalidated<KVec<u8>>) -> Result<Self, Self::Err>\n Ok(rsp)\n }\n }\n+\n+#[repr(C, packed)]\n+pub(crate) struct RegAlg {\n+ pub(crate) alg_type: u8,\n+ pub(crate) alg_count: u8,\n+ pub(crate) alg_supported: u16,\n+ pub(crate) alg_external: __IncompleteArrayField<__le32>,\n+}\n+\n+#[repr(C, packed)]\n+pub(crate) struct NegotiateAlgsReq {\n+ pub(crate) version: u8,\n+ pub(crate) code: u8,\n+ pub(crate) param1: u8, // size of resp_alg_struct\n+ param2: u8,\n+\n+ pub(crate) length: u16,\n+ pub(crate) measurement_specification: u8,\n+ pub(crate) other_params_support: u8,\n+\n+ pub(crate) base_asym_algo: u32,\n+ pub(crate) base_hash_algo: u32,\n+\n+ reserved1: [u8; 12],\n+\n+ pub(crate) ext_asym_count: u8,\n+ pub(crate) ext_hash_count: u8,\n+ reserved2: u8,\n+ pub(crate) mel_specification: u8,\n+\n+ pub(crate) ext_asym: __IncompleteArrayField<__le32>,\n+ pub(crate) ext_hash: __IncompleteArrayField<__le32>,\n+ pub(crate) resp_alg_struct: __IncompleteArrayField<RegAlg>,\n+}\n+\n+impl Default for NegotiateAlgsReq {\n+ fn default() -> Self {\n+ NegotiateAlgsReq {\n+ version: 0,\n+ code: SPDM_NEGOTIATE_ALGS,\n+ param1: 0, // Size of resp_alg_struct\n+ param2: 0,\n+ length: 32,\n+ measurement_specification: SPDM_MEAS_SPEC_DMTF,\n+ other_params_support: 0,\n+ base_asym_algo: SPDM_ASYM_ALGOS.to_le(),\n+ base_hash_algo: SPDM_HASH_ALGOS.to_le(),\n+ reserved1: [0u8; 12],\n+ ext_asym_count: 0,\n+ ext_hash_count: 0,\n+ reserved2: 0,\n+ mel_specification: 0,\n+ ext_asym: __IncompleteArrayField::new(),\n+ ext_hash: __IncompleteArrayField::new(),\n+ resp_alg_struct: __IncompleteArrayField::new(),\n+ }\n+ }\n+}\n+\n+#[repr(C, packed)]\n+pub(crate) struct NegotiateAlgsRsp {\n+ pub(crate) version: u8,\n+ pub(crate) code: u8,\n+ pub(crate) param1: u8,\n+ pub(crate) param2: u8,\n+\n+ pub(crate) length: u16,\n+ pub(crate) measurement_specification_sel: u8,\n+ pub(crate) other_params_sel: u8,\n+\n+ pub(crate) measurement_hash_algo: u32,\n+ pub(crate) base_asym_sel: u32,\n+ pub(crate) base_hash_sel: u32,\n+\n+ reserved1: [u8; 11],\n+\n+ pub(crate) mel_specification_sel: u8,\n+ pub(crate) ext_asym_sel_count: u8,\n+ pub(crate) ext_hash_sel_count: u8,\n+ reserved2: [u8; 2],\n+\n+ pub(crate) ext_asym: __IncompleteArrayField<__le32>,\n+ pub(crate) ext_hash: __IncompleteArrayField<__le32>,\n+ pub(crate) resp_alg_struct: __IncompleteArrayField<RegAlg>,\n+}\n+\n+impl Validate<&mut Unvalidated<KVec<u8>>> for &mut NegotiateAlgsRsp {\n+ type Err = Error;\n+\n+ fn validate(unvalidated: &mut Unvalidated<KVec<u8>>) -> Result<Self, Self::Err> {\n+ let raw = unvalidated.raw_mut();\n+ if raw.len() < mem::size_of::<NegotiateAlgsRsp>() {\n+ return Err(EINVAL);\n+ }\n+\n+ let ptr = raw.as_mut_ptr();\n+ // CAST: `NegotiateAlgsRsp` only contains integers and has `repr(C)`.\n+ let ptr = ptr.cast::<NegotiateAlgsRsp>();\n+ // SAFETY: `ptr` came from a reference and the cast above is valid.\n+ let rsp: &mut NegotiateAlgsRsp = unsafe { &mut *ptr };\n+\n+ rsp.base_asym_sel = rsp.base_asym_sel.to_le();\n+ rsp.base_hash_sel = rsp.base_hash_sel.to_le();\n+ rsp.measurement_hash_algo = rsp.measurement_hash_algo.to_le();\n+\n+ Ok(rsp)\n+ }\n+}\n", "prefixes": [ "13/18" ] }