get:
Show a patch.

patch:
Update a patch.

put:
Update a patch.

GET /api/1.2/patches/2234750/?format=api
HTTP 200 OK
Allow: GET, PUT, PATCH, HEAD, OPTIONS
Content-Type: application/json
Vary: Accept

{
    "id": 2234750,
    "url": "http://patchwork.ozlabs.org/api/1.2/patches/2234750/?format=api",
    "web_url": "http://patchwork.ozlabs.org/project/linux-pci/patch/20260508031710.514574-15-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-15-alistair.francis@wdc.com>",
    "list_archive_url": null,
    "date": "2026-05-08T03:17:06",
    "name": "[14/18] lib: rspdm: Support SPDM get_digests",
    "commit_ref": null,
    "pull_url": null,
    "state": "new",
    "archived": false,
    "hash": "987198d4c1c93468e80ec758c8018775575551d1",
    "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-15-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/2234750/comments/",
    "check": "pending",
    "checks": "http://patchwork.ozlabs.org/api/patches/2234750/checks/",
    "tags": {},
    "related": [],
    "headers": {
        "Return-Path": "\n <linux-pci+bounces-54169-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=aCXaTQ7o;\n\tdkim-atps=neutral",
            "legolas.ozlabs.org;\n spf=pass (sender SPF authorized) smtp.mailfrom=vger.kernel.org\n (client-ip=2600:3c04:e001:36c::12fc:5321; helo=tor.lore.kernel.org;\n envelope-from=linux-pci+bounces-54169-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=\"aCXaTQ7o\"",
            "smtp.subspace.kernel.org;\n arc=none smtp.client-ip=209.85.216.50",
            "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\n [IPv6:2600:3c04:e001:36c::12fc:5321])\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 4gBZG11PLYz1yK7\n\tfor <incoming@patchwork.ozlabs.org>; Fri, 08 May 2026 13:23:37 +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 21AF430A1D66\n\tfor <incoming@patchwork.ozlabs.org>; Fri,  8 May 2026 03:19:45 +0000 (UTC)",
            "from localhost.localdomain (localhost.localdomain [127.0.0.1])\n\tby smtp.subspace.kernel.org (Postfix) with ESMTP id 8A8702FE056;\n\tFri,  8 May 2026 03:19:17 +0000 (UTC)",
            "from mail-pj1-f50.google.com (mail-pj1-f50.google.com\n [209.85.216.50])\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 28A36313E07\n\tfor <linux-pci@vger.kernel.org>; Fri,  8 May 2026 03:19:10 +0000 (UTC)",
            "by mail-pj1-f50.google.com with SMTP id\n 98e67ed59e1d1-364c5317d67so1618237a91.2\n        for <linux-pci@vger.kernel.org>; Thu, 07 May 2026 20:19:10 -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.19.02\n        (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256);\n        Thu, 07 May 2026 20:19:08 -0700 (PDT)"
        ],
        "ARC-Seal": "i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116;\n\tt=1778210355; cv=none;\n b=PtVD0tStr+A5CdsHt2dtkQLDAJjs28UqKCY1khyQbHW8hEjmyL5Hr8vCXFNE0qpjFpGramWwxlw9rGJMZ9H8vFDOcbeWHFLwkWhOzUCF5x/MPw0hiISu9NkeRv+edKNPaXVaevfYTdREqKgItpGAVXjKKP3k2uWbvwC7LB4vWkY=",
        "ARC-Message-Signature": "i=1; a=rsa-sha256; d=subspace.kernel.org;\n\ts=arc-20240116; t=1778210355; c=relaxed/simple;\n\tbh=T0+ZvWaKl6aU1RnDTQJKVo5xqdWjeysfv86NbgJZTQk=;\n\th=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References:\n\t MIME-Version;\n b=BmJKOyDWtTQzq7Yq7tDvaurFfgN4yXFRIKzptHnKL7sBv6VJLMmKBX3owsG7S07yoJD427K89cj+Og64r2Sv/37n0qwmc7+HwXcsQemWQiXHesKJKNibHmEvFqTyp2Mtio6mnAhDdHgnMUGCYokxUPTengYCqR5bfG92W8m3dE0=",
        "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=aCXaTQ7o; arc=none smtp.client-ip=209.85.216.50",
        "DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=gmail.com; s=20251104; t=1778210349; x=1778815149;\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=/ZVy9zCp2FVtT/BdK26xWCodS3E+jo75mkR1y+4KXx8=;\n        b=aCXaTQ7o+PznnzUrtURa26K5jIefT04nUXVWmmxICywIpG2qkIVTyRAfu7HYSFyb4/\n         5fWzfBy6YInOD4XOy/d4OsPZrlz772mSpEi0vDQdsr6vC+aMRBjhjr72/GcQoOh54cOo\n         4Cg5TbjUix6JUC7zMmtgdz6mq2SRqV5kGNaZYcw+FDdeGvHaRVsv5EkDbF6e7bYHxDK6\n         fm0BIiEWAHxiDCJVnKsJdYAogSVGc2O4dj6sj3K4H3+d205a9i7nDmDgRUxTkj11Wy0B\n         IyA1JR5hty/EKgQJlBzR7IDRKzsOzIbDqp2cMe6M1Dz3IqXqIRE1e/8WpWAm2lSdKf9f\n         A5Yg==",
        "X-Google-DKIM-Signature": "v=1; a=rsa-sha256; c=relaxed/relaxed;\n        d=1e100.net; s=20251104; t=1778210349; x=1778815149;\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=/ZVy9zCp2FVtT/BdK26xWCodS3E+jo75mkR1y+4KXx8=;\n        b=aHnPIGYCAz4VRaRaRjoiKu65C6n0nDeYPtz9lkhNP1+W6XRhYlZ56h1QwQ57mQbkBD\n         +VIn5Nu0plCoYandapbQUJtv/YHJSq8p+HvaP7kJ07DU4Xjswy9uS65wxO0j3gGU5etb\n         cFe2dhIzI6ck0Uo3cn8dg4SgZjrSxY0k6uhPJxkzrQ9bmd6ZBf9T06gw6OocA4rwNG9l\n         D8p7pAL1WYuSdnp5IiYX90j5d0t6O5iRyPFgokAL8dNGgy0UligCqpUv1BxgzIldueTU\n         WDdX4jhCDvg/Ec4RwScWj255fqu2pO45BFZD/l/vT4BWn/mAUJEXdQfx1Q22Dw1YvO5S\n         32kA==",
        "X-Forwarded-Encrypted": "i=1;\n AFNElJ83cI5QX9st0niZWObzQKCeRdeR9sra8A3R+IIUB7ooLppdCUa/G03OWS0JA+OaYOaOslm91luBgnw=@vger.kernel.org",
        "X-Gm-Message-State": "AOJu0YxvLpUXJ7jN0fNcydnvaewO9k3z+a1xm/egWr2kRFb9cEr3dZ9W\n\tXc8D1hT72NelIX9sfMrFzqi4FtLp0eKQPfUcn/urceam3x5utOYX6Shnh7neug==",
        "X-Gm-Gg": "Acq92OEH83w7DuS/k5S5Xe+pMdkEEy6810bKcuygvsIEfcgZ77fRfjOAv4xcOhIqbiL\n\tfp1D+xeDlyufuSP+C6mLKD7VUnI2Lr4f0bS8mI8A1M3Zcugt4eink50SjFva56+NZj1gK33bQ5C\n\tYMLTPYIuSY4sWrMencmSSoaqs77bvqll37NefEvzGQ0lliFd2vlMTXtmmROlnESZ4WEICxRS7sR\n\tICki2zWGnMT7mHIMBg5D2ohomQU8LOIA8N6xpCwy+jvAWDIoMlkus4hH7eJClPO0KYA6fB6bxcu\n\tWeNERlUHjK5KwsgUvSanoKVeeNZvSwP51sy5PvuvlG7t7WoqiaZz376omPb2+XZIUGMuUPs40F0\n\tlzt+nA88h9lz5dpDyUvvcE07BILNE6rSUwOaHADr2Ghw8mnjrbVRVKTap/9Hp8KM21BiaG3dkbr\n\tNjeMiMTUKV5GhSsLh7hnPIL213nRfzFUBHSpMPwmwP",
        "X-Received": "by 2002:a17:903:1450:b0:2b4:5cd0:b6c3 with SMTP id\n d9443c01a7336-2ba79be16c0mr123514345ad.29.1778210349207;\n        Thu, 07 May 2026 20:19:09 -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 14/18] lib: rspdm: Support SPDM get_digests",
        "Date": "Fri,  8 May 2026 13:17:06 +1000",
        "Message-ID": "<20260508031710.514574-15-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 GET_DIGESTS SPDM command.\n\nSigned-off-by: Alistair Francis <alistair@alistair23.me>\n---\n lib/rspdm/consts.rs    |  7 +++-\n lib/rspdm/lib.rs       |  4 ++\n lib/rspdm/state.rs     | 85 +++++++++++++++++++++++++++++++++++++++++-\n lib/rspdm/validator.rs | 54 +++++++++++++++++++++++++++\n 4 files changed, 147 insertions(+), 3 deletions(-)",
    "diff": "diff --git a/lib/rspdm/consts.rs b/lib/rspdm/consts.rs\nindex e4652b18eb2a..092205dab74d 100644\n--- a/lib/rspdm/consts.rs\n+++ b/lib/rspdm/consts.rs\n@@ -19,10 +19,11 @@\n pub(crate) const SPDM_VER_10: u8 = 0x10;\n pub(crate) const SPDM_VER_11: u8 = 0x11;\n pub(crate) const SPDM_VER_12: u8 = 0x12;\n-#[allow(dead_code)]\n pub(crate) const SPDM_VER_13: u8 = 0x13;\n pub(crate) const SPDM_VER_14: u8 = 0x14;\n \n+pub(crate) const SPDM_SLOTS: usize = 8;\n+\n pub(crate) const SPDM_MIN_VER: u8 = SPDM_VER_10;\n pub(crate) const SPDM_MAX_VER: u8 = SPDM_VER_14;\n \n@@ -73,7 +74,7 @@ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\n pub(crate) const SPDM_GET_VERSION_LEN: usize = mem::size_of::<SpdmHeader>() + u8::MAX as usize;\n \n pub(crate) const SPDM_GET_CAPABILITIES: u8 = 0xe1;\n-pub(crate) const SPDM_MIN_DATA_TRANSFER_SIZE: u32 = 42;\n+pub(crate) const SPDM_MIN_DATA_TRANSFER_SIZE: u32 = 42; // SPDM 1.2.0 margin no 226\n \n // SPDM cryptographic timeout of this implementation:\n // Assume calculations may take up to 1 sec on a busy machine, which equals\n@@ -111,6 +112,8 @@ fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {\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+pub(crate) const SPDM_GET_DIGESTS: u8 = 0x81;\n+\n // If the crypto support isn't enabled don't offer the algorithms\n // to the responder\n #[cfg(CONFIG_CRYPTO_RSA)]\ndiff --git a/lib/rspdm/lib.rs b/lib/rspdm/lib.rs\nindex 72886a5dfd69..e42cfdd35524 100644\n--- a/lib/rspdm/lib.rs\n+++ b/lib/rspdm/lib.rs\n@@ -120,6 +120,10 @@\n         return e.to_errno() as c_int;\n     }\n \n+    if let Err(e) = state.get_digests() {\n+        return e.to_errno() as c_int;\n+    }\n+\n     0\n }\n \ndiff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs\nindex 34676744e509..bcb1cc955c4c 100644\n--- a/lib/rspdm/state.rs\n+++ b/lib/rspdm/state.rs\n@@ -46,13 +46,17 @@\n     SPDM_OPAQUE_DATA_FMT_GENERAL,\n     SPDM_REQ,\n     SPDM_RSP_MIN_CAPS,\n+    SPDM_SLOTS,\n     SPDM_VER_10,\n     SPDM_VER_11,\n-    SPDM_VER_12, //\n+    SPDM_VER_12,\n+    SPDM_VER_13, //\n };\n use crate::validator::{\n     GetCapabilitiesReq,\n     GetCapabilitiesRsp,\n+    GetDigestsReq,\n+    GetDigestsRsp,\n     GetVersionReq,\n     GetVersionRsp,\n     NegotiateAlgsReq,\n@@ -83,6 +87,10 @@\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+/// @supported_slots: Bitmask of responder's supported certificate slots.\n+///  Received during GET_DIGESTS exchange (from SPDM 1.3).\n+/// @provisioned_slots: Bitmask of responder's provisioned certificate slots.\n+///  Received during GET_DIGESTS 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@@ -94,6 +102,8 @@\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+/// @certs: Certificate chain in each of the 8 slots. Empty KVec if a slot is\n+///  not populated. Prefixed by the 4 + H header per SPDM 1.0.0 table 15.\n #[expect(dead_code)]\n pub struct SpdmState {\n     pub(crate) dev: *mut bindings::device,\n@@ -108,6 +118,8 @@ pub struct SpdmState {\n     pub(crate) base_asym_alg: u32,\n     pub(crate) base_hash_alg: u32,\n     pub(crate) meas_hash_alg: u32,\n+    pub(crate) supported_slots: u8,\n+    pub(crate) provisioned_slots: u8,\n \n     /* Signature algorithm */\n     base_asym_enc: &'static CStr,\n@@ -118,6 +130,9 @@ pub struct SpdmState {\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+    // Certificates\n+    pub(crate) certs: [KVec<u8>; SPDM_SLOTS],\n }\n \n impl SpdmState {\n@@ -139,12 +154,15 @@ pub(crate) fn new(\n             base_asym_alg: 0,\n             base_hash_alg: 0,\n             meas_hash_alg: 0,\n+            supported_slots: 0,\n+            provisioned_slots: 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+            certs: [const { KVec::new() }; SPDM_SLOTS],\n         }\n     }\n \n@@ -578,4 +596,69 @@ pub(crate) fn negotiate_algs(&mut self) -> Result<(), Error> {\n \n         Ok(())\n     }\n+\n+    pub(crate) fn get_digests(&mut self) -> Result<(), Error> {\n+        let mut request = GetDigestsReq::default();\n+        request.version = self.version;\n+\n+        let req_sz = core::mem::size_of::<GetDigestsReq>();\n+        let rsp_sz = core::mem::size_of::<GetDigestsRsp>() + SPDM_SLOTS * self.hash_len;\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 len = self.spdm_exchange(request_buf, response_buf)?;\n+\n+        if len < (core::mem::size_of::<GetDigestsRsp>() as i32) {\n+            pr_err!(\"Truncated digests response\\n\");\n+            to_result(-(bindings::EIO as i32))?;\n+        }\n+\n+        // SAFETY: `len` is the length of data read, which will be smaller\n+        // then the capacity of the vector\n+        unsafe { response_vec.inc_len(len as usize) };\n+\n+        let response: &mut GetDigestsRsp = Untrusted::new_mut(&mut response_vec).validate_mut()?;\n+\n+        if len\n+            < (core::mem::size_of::<GetDigestsReq>()\n+                + response.param2.count_ones() as usize * self.hash_len) as i32\n+        {\n+            pr_err!(\"Truncated digests response\\n\");\n+            to_result(-(bindings::EIO as i32))?;\n+        }\n+\n+        let mut deprovisioned_slots = self.provisioned_slots & !response.param2;\n+        while (deprovisioned_slots.trailing_zeros() as usize) < SPDM_SLOTS {\n+            let slot = deprovisioned_slots.trailing_zeros() as usize;\n+            self.certs[slot].clear();\n+            deprovisioned_slots &= !(1 << slot);\n+        }\n+\n+        self.provisioned_slots = response.param2;\n+        if self.provisioned_slots == 0 {\n+            pr_err!(\"No certificates provisioned\\n\");\n+            to_result(-(bindings::EPROTO as i32))?;\n+        }\n+\n+        if self.version >= SPDM_VER_13 && (response.param2 & !response.param1 != 0) {\n+            pr_err!(\"Malformed digests response\\n\");\n+            to_result(-(bindings::EPROTO as i32))?;\n+        }\n+\n+        let supported_slots = if self.version >= SPDM_VER_13 {\n+            response.param1\n+        } else {\n+            0xFF\n+        };\n+\n+        self.supported_slots = supported_slots;\n+\n+        Ok(())\n+    }\n }\ndiff --git a/lib/rspdm/validator.rs b/lib/rspdm/validator.rs\nindex 9d738133399d..1e5ee8a7582b 100644\n--- a/lib/rspdm/validator.rs\n+++ b/lib/rspdm/validator.rs\n@@ -30,6 +30,7 @@\n     SPDM_ASYM_ALGOS,\n     SPDM_CTEXPONENT,\n     SPDM_GET_CAPABILITIES,\n+    SPDM_GET_DIGESTS,\n     SPDM_GET_VERSION,\n     SPDM_HASH_ALGOS,\n     SPDM_MEAS_SPEC_DMTF,\n@@ -349,3 +350,56 @@ 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 GetDigestsReq {\n+    pub(crate) version: u8,\n+    pub(crate) code: u8,\n+    pub(crate) param1: u8,\n+    pub(crate) param2: u8,\n+}\n+\n+impl Default for GetDigestsReq {\n+    fn default() -> Self {\n+        GetDigestsReq {\n+            version: 0,\n+            code: SPDM_GET_DIGESTS,\n+            param1: 0,\n+            param2: 0,\n+        }\n+    }\n+}\n+\n+#[repr(C, packed)]\n+pub(crate) struct GetDigestsRsp {\n+    pub(crate) version: u8,\n+    pub(crate) code: u8,\n+    pub(crate) param1: u8,\n+    pub(crate) param2: u8,\n+\n+    pub(crate) digests: __IncompleteArrayField<u8>,\n+    // KeyPairIDs, added in 1.3\n+\n+    // CertificatInfo, added in 1.3\n+\n+    // KeyUsageMask, added in 1.3\n+}\n+\n+impl Validate<&mut Unvalidated<KVec<u8>>> for &mut GetDigestsRsp {\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::<GetDigestsRsp>() {\n+            return Err(EINVAL);\n+        }\n+\n+        let ptr = raw.as_mut_ptr();\n+        // CAST: `GetDigestsRsp` only contains integers and has `repr(C)`.\n+        let ptr = ptr.cast::<GetDigestsRsp>();\n+        // SAFETY: `ptr` came from a reference and the cast above is valid.\n+        let rsp: &mut GetDigestsRsp = unsafe { &mut *ptr };\n+\n+        Ok(rsp)\n+    }\n+}\n",
    "prefixes": [
        "14/18"
    ]
}