From: "Gary Guo" <gary@garyguo.net>
To: "Alistair Francis" <alistair23@gmail.com>,
"Jonathan Cameron" <jonathan.cameron@huawei.com>
Cc: <bhelgaas@google.com>, <lukas@wunner.de>,
<rust-for-linux@vger.kernel.org>, <akpm@linux-foundation.org>,
<linux-pci@vger.kernel.org>, <linux-cxl@vger.kernel.org>,
<linux-kernel@vger.kernel.org>, <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>,
<ojeda@kernel.org>, <wilfred.mallawa@wdc.com>,
<aliceryhl@google.com>,
"Alistair Francis" <alistair@alistair23.me>
Subject: Re: [RFC v3 16/27] lib: rspdm: Support SPDM get_certificate
Date: Tue, 31 Mar 2026 14:19:17 +0100 [thread overview]
Message-ID: <DHGZXDPKEDAU.1DX1Z6U87O8XS@garyguo.net> (raw)
In-Reply-To: <CAKmqyKNrP6Ap-0Jy-uaYKM=7W3Fiz8WtdG=JWV4ACv=2weS5EQ@mail.gmail.com>
On Tue Mar 31, 2026 at 3:37 AM BST, Alistair Francis wrote:
> On Wed, Mar 4, 2026 at 12:51 AM Jonathan Cameron
> <jonathan.cameron@huawei.com> wrote:
>>
>> On Wed, 11 Feb 2026 13:29:23 +1000
>> alistair23@gmail.com wrote:
>>
>> > From: Alistair Francis <alistair@alistair23.me>
>> >
>> > Support the GET_CERTIFICATE SPDM command.
>> >
>> > Signed-off-by: Alistair Francis <alistair@alistair23.me>
>>
>> Minor things inline. The endian handling in general needs
>> some care + possibly some tests.
>>
>> > diff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs
>> > index 2606b825c494..1e5656144611 100644
>> > --- a/lib/rspdm/state.rs
>> > +++ b/lib/rspdm/state.rs
>> > @@ -26,8 +26,9 @@
>> > SPDM_REQ, SPDM_RSP_MIN_CAPS, SPDM_SLOTS, SPDM_VER_10, SPDM_VER_11, SPDM_VER_12,
>> > };
>>
>> > impl SpdmState {
>> > pub(crate) fn new(
>> > dev: *mut bindings::device,
>> > @@ -620,4 +629,118 @@ pub(crate) fn get_digests(&mut self) -> Result<(), Error> {
>> >
>> > Ok(())
>> > }
>> > +
>> > + fn get_cert_exchange(
>> > + &mut self,
>> > + request_buf: &mut [u8],
>> > + response_vec: &mut KVec<u8>,
>> > + rsp_sz: usize,
>> > + ) -> Result<&mut GetCertificateRsp, Error> {
>> > + // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice
>> > + let response_buf = unsafe { from_raw_parts_mut(response_vec.as_mut_ptr(), rsp_sz) };
>> > +
>> > + let rc = self.spdm_exchange(request_buf, response_buf)?;
>> > +
>> > + if rc < (core::mem::size_of::<GetCertificateReq>() as i32) {
>> > + pr_err!("Truncated certificate response\n");
>> > + to_result(-(bindings::EIO as i32))?;
>> > + }
>> > +
>> > + // SAFETY: `rc` is the length of data read, which will be smaller
>> > + // then the capacity of the vector
>> > + unsafe { response_vec.inc_len(rc as usize) };
>> > +
>> > + let response: &mut GetCertificateRsp = Untrusted::new_mut(response_vec).validate_mut()?;
>> > +
>> > + if rc
>> > + < (core::mem::size_of::<GetCertificateRsp>() + response.portion_length as usize) as i32
>>
>> As below, I'd keep the type matching the spec and have the little endian to cpu conversion out here.
>>
>>
>> > + {
>> > + pr_err!("Truncated certificate response\n");
>> > + to_result(-(bindings::EIO as i32))?;
>> > + }
>> > +
>> > + Ok(response)
>> > + }
>> > +
>> > + pub(crate) fn get_certificate(&mut self, slot: u8) -> Result<(), Error> {
>> > + let mut request = GetCertificateReq::default();
>> > + request.version = self.version;
>> > + request.param1 = slot;
>> > +
>> > + let req_sz = core::mem::size_of::<GetCertificateReq>();
>> > + let rsp_sz = ((core::mem::size_of::<GetCertificateRsp>() + 0xffff) as u32)
>>
>> Similar to earlier comment, do we have U16_MAX or similar available?
>>
>> > + .min(self.transport_sz) as usize;
>> > +
>> > + request.offset = 0;
>>
>> That's the default, so worth setting here?
>
> I like being explicit :)
>
>>
>> > + request.length = (rsp_sz - core::mem::size_of::<GetCertificateRsp>()).to_le() as u16;
>>
>> Why store it in a u16 if it is le16?
>
> core::mem::size_of gives us a usize. So this ensures it's little
> endian then casts it to a u16.
This is broken code then.
In BE architectures, `.to_le()` flips the bytes around, and you do the truncation
*after* the byteswap, which would give you 0.
You'd need ((...) as u16).to_le()
Best,
Gary
>
> We could cast it to a __le16. u16 is a standard Rust type (compared to
> __le16 which is a internal kernel type), so I prefer u16 as it matches
> other Rust implementations.
>
>>
>> > +
>> > + // SAFETY: `request` is repr(C) and packed, so we can convert it to a slice
>> > + let request_buf = unsafe { from_raw_parts_mut(&mut request as *mut _ as *mut u8, req_sz) };
>> > +
>> > + let mut response_vec: KVec<u8> = KVec::with_capacity(rsp_sz, GFP_KERNEL)?;
>> > +
>> > + let response = self.get_cert_exchange(request_buf, &mut response_vec, rsp_sz)?;
>> > +
>> > + let total_cert_len =
>> > + ((response.portion_length + response.remainder_length) & 0xFFFF) as usize;
>> > +
>> > + let mut certs_buf: KVec<u8> = KVec::new();
>> > +
>> > + certs_buf.extend_from_slice(
>> > + &response_vec[8..(8 + response.portion_length as usize)],
>> > + GFP_KERNEL,
>> > + )?;
>> > +
>> > + let mut offset: usize = response.portion_length as usize;
>> > + let mut remainder_length = response.remainder_length as usize;
>> > +
>> > + while remainder_length > 0 {
>> > + request.offset = offset.to_le() as u16;
>>
>> Similar to other places, why not just make the type __le16
>> and avoid need to cast.
>
> Same as above
>
>>
>> > + request.length = (remainder_length
>> > + .min(rsp_sz - core::mem::size_of::<GetCertificateRsp>()))
>> > + .to_le() as u16;
>>
>> Likewise.
>
> and above
>
>>
>> > +
>> > + let request_buf =
>> > + unsafe { from_raw_parts_mut(&mut request as *mut _ as *mut u8, req_sz) };
>> > +
>> > + let response = self.get_cert_exchange(request_buf, &mut response_vec, rsp_sz)?;
>> > +
>> > + if response.portion_length == 0
>> > + || (response.param1 & 0xF) != slot
>> > + || offset as u16 + response.portion_length + response.remainder_length
>> > + != total_cert_len as u16
>> > + {
>> > + pr_err!("Malformed certificate response\n");
>> > + to_result(-(bindings::EPROTO as i32))?;
>> > + }
>> > +
>> > + certs_buf.extend_from_slice(
>> > + &response_vec[8..(8 + response.portion_length as usize)],
>> > + GFP_KERNEL,
>> > + )?;
>> > + offset += response.portion_length as usize;
>> > + remainder_length = response.remainder_length as usize;
>> > + }
>> > +
>> > + let header_length = core::mem::size_of::<SpdmCertChain>() + self.hash_len;
>> > +
>> > + let ptr = certs_buf.as_mut_ptr();
>> > + // SAFETY: `SpdmCertChain` is repr(C) and packed, so we can convert it from a slice
>> > + let ptr = ptr.cast::<SpdmCertChain>();
>> > + // SAFETY: `ptr` came from a reference and the cast above is valid.
>> > + let certs: &mut SpdmCertChain = unsafe { &mut *ptr };
>> > +
>> > + if total_cert_len < header_length
>> > + || total_cert_len != usize::from_le(certs.length as usize)
>>
>> That's a confusing bit of casting as you are interpretting an __le16 as a usize
>> before doing the endian conversion? Seems unlikely to get what you want
>> on a big endian machine.
>
> Yeah, I think this is wrong
>
>>
>> > + || total_cert_len != certs_buf.len()
>> > + {
>> > + pr_err!("Malformed certificate chain in slot {slot}\n");
>> > + to_result(-(bindings::EPROTO as i32))?;
>> > + }
>> > +
>> > + self.certs[slot as usize].clear();
>> > + self.certs[slot as usize].extend_from_slice(&certs_buf, GFP_KERNEL)?;
>> > +
>> > + Ok(())
>> > + }
>> > }
>> > diff --git a/lib/rspdm/validator.rs b/lib/rspdm/validator.rs
>> > index 2150a23997db..a8bc3378676f 100644
>> > --- a/lib/rspdm/validator.rs
>> > +++ b/lib/rspdm/validator.rs
>> > @@ -17,8 +17,9 @@
>> > };
>>
>> > #[repr(C, packed)]
>> > @@ -364,3 +365,62 @@ fn validate(unvalidated: &mut Unvalidated<KVec<u8>>) -> Result<Self, Self::Err>
>> > Ok(rsp)
>> > }
>> > }
>>
>> > +#[repr(C, packed)]
>> > +pub(crate) struct GetCertificateRsp {
>> > + pub(crate) version: u8,
>> > + pub(crate) code: u8,
>> > + pub(crate) param1: u8,
>> > + pub(crate) param2: u8,
>> > +
>> > + pub(crate) portion_length: u16,
>> > + pub(crate) remainder_length: u16,
>> > +
>> > + pub(crate) cert_chain: __IncompleteArrayField<u8>,
>> > +}
>> > +
>> > +impl Validate<&mut Unvalidated<KVec<u8>>> for &mut GetCertificateRsp {
>> > + type Err = Error;
>> > +
>> > + fn validate(unvalidated: &mut Unvalidated<KVec<u8>>) -> Result<Self, Self::Err> {
>> > + let raw = unvalidated.raw_mut();
>> > + if raw.len() < mem::size_of::<GetCertificateRsp>() {
>> > + return Err(EINVAL);
>> > + }
>> > +
>> > + let ptr = raw.as_mut_ptr();
>> > + // CAST: `GetCertificateRsp` only contains integers and has `repr(C)`.
>> > + let ptr = ptr.cast::<GetCertificateRsp>();
>> > + // SAFETY: `ptr` came from a reference and the cast above is valid.
>> > + let rsp: &mut GetCertificateRsp = unsafe { &mut *ptr };
>> > +
>> > + rsp.portion_length = rsp.portion_length.to_le();
>> > + rsp.remainder_length = rsp.remainder_length.to_le();
>>
>> Why to_le()? I can understand from_le() but then I'm a bit dubious about the
>> types. My gut feeling is that the validate code should leave these in little
>> endian and we should convert them only at time of use.
>
> Fixed
>
> Alistair
>
>>
>> > +
>> > + Ok(rsp)
>> > + }
>> > +}
>>
next prev parent reply other threads:[~2026-03-31 13:19 UTC|newest]
Thread overview: 112+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-02-11 3:29 [RFC v3 00/27] lib: Rust implementation of SPDM alistair23
2026-02-11 3:29 ` [RFC v3 01/27] rust: add untrusted data abstraction alistair23
2026-02-11 3:29 ` [RFC v3 02/27] X.509: Make certificate parser public alistair23
2026-02-11 3:29 ` [RFC v3 03/27] X.509: Parse Subject Alternative Name in certificates alistair23
2026-02-11 3:29 ` [RFC v3 04/27] X.509: Move certificate length retrieval into new helper alistair23
2026-02-11 3:29 ` [RFC v3 05/27] certs: Create blacklist keyring earlier alistair23
2026-02-11 3:29 ` [RFC v3 06/27] rust: add bindings for hash.h alistair23
2026-02-19 14:48 ` Gary Guo
2026-03-02 16:18 ` Jonathan Cameron
2026-02-11 3:29 ` [RFC v3 07/27] rust: error: impl From<FromBytesWithNulError> for Kernel Error alistair23
2026-02-19 14:49 ` Gary Guo
2026-03-13 2:20 ` Alistair Francis
2026-03-13 10:35 ` Alice Ryhl
2026-02-11 3:29 ` [RFC v3 08/27] lib: rspdm: Initial commit of Rust SPDM alistair23
2026-03-02 17:09 ` Jonathan Cameron
2026-03-13 3:44 ` Alistair Francis
2026-02-11 3:29 ` [RFC v3 09/27] PCI/CMA: Authenticate devices on enumeration alistair23
2026-02-16 4:25 ` Aksh Garg
2026-02-11 3:29 ` [RFC v3 10/27] PCI/CMA: Validate Subject Alternative Name in certificates alistair23
2026-02-11 3:29 ` [RFC v3 11/27] PCI/CMA: Reauthenticate devices on reset and resume alistair23
2026-02-11 3:29 ` [RFC v3 12/27] lib: rspdm: Support SPDM get_version alistair23
2026-02-11 4:00 ` Wilfred Mallawa
2026-03-03 11:36 ` Jonathan Cameron
2026-03-13 5:35 ` Alistair Francis
2026-03-13 5:53 ` Miguel Ojeda
2026-03-13 5:55 ` Miguel Ojeda
2026-03-16 17:16 ` Jonathan Cameron
2026-02-11 3:29 ` [RFC v3 13/27] lib: rspdm: Support SPDM get_capabilities alistair23
2026-02-11 4:08 ` Wilfred Mallawa
2026-03-03 12:09 ` Jonathan Cameron
2026-03-03 18:07 ` Miguel Ojeda
2026-03-20 4:32 ` Alistair Francis
2026-02-11 3:29 ` [RFC v3 14/27] lib: rspdm: Support SPDM negotiate_algorithms alistair23
2026-03-03 13:46 ` Jonathan Cameron
2026-02-11 3:29 ` [RFC v3 15/27] lib: rspdm: Support SPDM get_digests alistair23
2026-03-03 14:29 ` Jonathan Cameron
2026-02-11 3:29 ` [RFC v3 16/27] lib: rspdm: Support SPDM get_certificate alistair23
2026-03-03 14:51 ` Jonathan Cameron
2026-03-31 2:37 ` Alistair Francis
2026-03-31 13:19 ` Gary Guo [this message]
2026-02-11 3:29 ` [RFC v3 17/27] crypto: asymmetric_keys - Load certificate parsing early in boot alistair23
2026-02-11 3:29 ` [RFC v3 18/27] KEYS: Load keyring and certificates " alistair23
2026-02-11 3:29 ` [RFC v3 19/27] PCI/CMA: Support built in X.509 certificates alistair23
2026-02-11 3:29 ` [RFC v3 20/27] crypto: sha: Load early in boot alistair23
2026-03-03 14:52 ` Jonathan Cameron
2026-02-11 3:29 ` [RFC v3 21/27] crypto: ecdsa: " alistair23
2026-03-03 14:54 ` Jonathan Cameron
2026-02-11 3:29 ` [RFC v3 22/27] lib: rspdm: Support SPDM certificate validation alistair23
2026-03-03 15:00 ` Jonathan Cameron
2026-03-31 3:29 ` Alistair Francis
2026-03-31 10:11 ` Miguel Ojeda
2026-04-01 1:48 ` Alistair Francis
2026-04-01 10:37 ` Miguel Ojeda
2026-02-11 3:29 ` [RFC v3 23/27] rust: allow extracting the buffer from a CString alistair23
2026-02-19 14:50 ` Gary Guo
2026-02-11 3:29 ` [RFC v3 24/27] lib: rspdm: Support SPDM challenge alistair23
2026-03-03 16:54 ` Jonathan Cameron
2026-02-11 3:29 ` [RFC v3 25/27] PCI/CMA: Expose in sysfs whether devices are authenticated alistair23
2026-02-11 3:29 ` [RFC v3 26/27] rust: add bindings for hash_info alistair23
2026-02-11 3:29 ` [RFC v3 27/27] rspdm: Multicast received signatures via netlink alistair23
2026-02-19 10:19 ` Lukas Wunner
2026-02-12 5:56 ` [RFC v3 00/27] lib: Rust implementation of SPDM dan.j.williams
2026-02-18 2:12 ` Alistair Francis
2026-04-09 3:39 ` Alistair Francis
2026-04-13 5:42 ` Alistair Francis
2026-04-17 2:35 ` Dan Williams
2026-04-17 4:34 ` Lukas Wunner
2026-04-17 5:20 ` Alistair Francis
2026-05-02 1:34 ` Dan Williams (nvidia)
2026-05-05 8:56 ` Alistair Francis
2026-02-17 23:56 ` Jason Gunthorpe
2026-02-18 2:17 ` Alistair Francis
2026-02-18 23:40 ` dan.j.williams
2026-02-19 0:56 ` Jason Gunthorpe
2026-02-19 5:05 ` dan.j.williams
2026-02-19 12:41 ` Jason Gunthorpe
2026-02-19 14:15 ` Lukas Wunner
2026-02-19 14:31 ` Jason Gunthorpe
2026-02-19 15:07 ` Lukas Wunner
2026-02-19 17:39 ` Jason Gunthorpe
2026-02-19 20:07 ` dan.j.williams
2026-02-20 8:30 ` Lukas Wunner
2026-02-20 14:10 ` Jason Gunthorpe
2026-02-21 18:46 ` Lukas Wunner
2026-02-21 23:29 ` dan.j.williams
2026-02-23 17:15 ` Jonathan Cameron
2026-02-23 19:11 ` dan.j.williams
2026-02-24 14:33 ` Jason Gunthorpe
2026-03-05 4:17 ` dan.j.williams
2026-03-05 12:48 ` Jason Gunthorpe
2026-03-05 19:49 ` dan.j.williams
2026-03-09 11:39 ` Jonathan Cameron
2026-03-09 12:31 ` Jason Gunthorpe
2026-03-09 15:33 ` Jonathan Cameron
2026-03-09 15:59 ` Jason Gunthorpe
2026-03-09 18:00 ` Jonathan Cameron
2026-03-09 20:40 ` Jason Gunthorpe
2026-03-09 23:11 ` DanX Williams
2026-02-24 14:16 ` Jason Gunthorpe
2026-02-24 15:54 ` Lukas Wunner
2026-02-25 14:50 ` Jason Gunthorpe
2026-02-19 14:40 ` Greg KH
2026-02-20 7:46 ` Lukas Wunner
2026-02-20 9:14 ` Greg KH
2026-02-20 11:45 ` Lukas Wunner
2026-02-20 11:57 ` Greg KH
2026-02-19 9:34 ` Lukas Wunner
2026-02-19 12:43 ` Jason Gunthorpe
2026-02-19 18:48 ` dan.j.williams
2026-02-19 9:13 ` Lukas Wunner
2026-02-19 18:42 ` dan.j.williams
2026-02-19 11:24 ` Jonathan Cameron
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=DHGZXDPKEDAU.1DX1Z6U87O8XS@garyguo.net \
--to=gary@garyguo.net \
--cc=a.hindborg@kernel.org \
--cc=akpm@linux-foundation.org \
--cc=alex.gaynor@gmail.com \
--cc=aliceryhl@google.com \
--cc=alistair23@gmail.com \
--cc=alistair@alistair23.me \
--cc=benno.lossin@proton.me \
--cc=bhelgaas@google.com \
--cc=bjorn3_gh@protonmail.com \
--cc=boqun.feng@gmail.com \
--cc=jonathan.cameron@huawei.com \
--cc=linux-cxl@vger.kernel.org \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-pci@vger.kernel.org \
--cc=lukas@wunner.de \
--cc=ojeda@kernel.org \
--cc=rust-for-linux@vger.kernel.org \
--cc=tmgross@umich.edu \
--cc=wilfred.mallawa@wdc.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.