From: Jonathan Cameron <jic23@kernel.org>
To: alistair23@gmail.com
Cc: linux-pci@vger.kernel.org, Jonathan.Cameron@huawei.com,
djbw@kernel.org, rust-for-linux@vger.kernel.org, lukas@wunner.de,
alistair@alistair23.me, linux-cxl@vger.kernel.org,
bhelgaas@google.com, akpm@linux-foundation.org,
linux-kernel@vger.kernel.org, gary@garyguo.net, ojeda@kernel.org,
benno.lossin@proton.me, a.hindborg@kernel.org,
wilfred.mallawa@wdc.com, tmgross@umich.edu, boqun.feng@gmail.com,
bjorn3_gh@protonmail.com, alex.gaynor@gmail.com,
aliceryhl@google.com
Subject: Re: [PATCH v3 21/21] lib: rspdm: Support SPDM challenge
Date: Wed, 9 Sep 2026 02:37:22 +0100 [thread overview]
Message-ID: <20260909023722.5615672b@jic23-huawei> (raw)
In-Reply-To: <20260901010347.2614656-22-alistair.francis@wdc.com>
On Tue, 1 Sep 2026 11:03:47 +1000
alistair23@gmail.com wrote:
> From: Alistair Francis <alistair@alistair23.me>
>
> Support the CHALLENGE SPDM command.
>
> Signed-off-by: Alistair Francis <alistair@alistair23.me>
Hi Alistair
I probably need to come at this with fresh eyes as I struggled to align
the generation of what was being signed with the spec. Anyhow out of
time for today and unfortunately I'm not sure when I'll get back to this.
Jonathan
> diff --git a/lib/rspdm/state.rs b/lib/rspdm/state.rs
> index fc7df9dd7b97..1fd691037fa5 100644
> --- a/lib/rspdm/state.rs
> +++ b/lib/rspdm/state.rs
> @@ -990,4 +1051,180 @@ pub(crate) fn validate_cert_chain(&mut self, slot: u8) -> Result<(), Error> {
>
> Ok(())
> }
> +
> + pub(crate) fn challenge_rsp_len(&mut self, nonce_len: usize, opaque_len: usize) -> usize {
> + // No measurement summary hash requested (MSHLength == 0)
> + let mut length =
> + core::mem::size_of::<SpdmHeader>() + self.hash_len + nonce_len + opaque_len + 2;
> +
> + if self.version >= SPDM_VER_13 {
> + length += 8;
> + }
> +
> + length + self.sig_len
> + }
> +
> + fn verify_signature(&mut self, signature: &mut [u8]) -> Result<(), Error> {
> + let mut sig = bindings::public_key_signature::default();
> + let mut mhash: KVec<u8> = KVec::new();
Can we move this down nearer where it is used?
> +
> + sig.s = signature as *mut _ as *mut u8;
> + sig.s_size = self.sig_len as u32;
> + sig.encoding = self.base_asym_enc.as_ptr() as *const u8;
> + sig.hash_algo = self.base_hash_alg_name.as_ptr() as *const u8;
> +
> + let mut m: KVec<u8> = KVec::new();
> + m.extend_with(SPDM_COMBINED_PREFIX_SZ + self.hash_len, 0, GFP_KERNEL)?;
> +
> + if let Some(desc) = &mut self.desc {
> + desc.tfm = self.shash;
> +
> + unsafe {
> + to_result(bindings::crypto_shash_digest(
> + *desc,
> + self.transcript.as_ptr(),
> + (self.transcript.len() - self.sig_len) as u32,
> + m[SPDM_COMBINED_PREFIX_SZ..].as_mut_ptr(),
> + ))?;
> + };
> + } else {
> + return Err(EPROTO);
> + }
> +
> + if self.version <= SPDM_VER_11 {
> + sig.m = m[SPDM_COMBINED_PREFIX_SZ..].as_mut_ptr();
> + } else {
> + let major = self.version >> 4;
> + let minor = self.version & 0xF;
> +
> + let prefix = CString::try_from_fmt(fmt!("dmtf-spdm-v{major:x}.{minor:x}.*dmtf-spdm-v{major:x}.{minor:x}.*dmtf-spdm-v{major:x}.{minor:x}.*dmtf-spdm-v{major:x}.{minor:x}.*"))?;
Sometimes I think they added this bit just to make sure all implementations break
the coding style and generally look ugly.
> + let mut buf = prefix.into_vec();
> + let zero_pad_len = SPDM_COMBINED_PREFIX_SZ - SPDM_PREFIX_SZ - SPDM_CONTEXT.len() - 1;
> +
> + buf.extend_with(zero_pad_len, 0, GFP_KERNEL)?;
> + buf.extend_from_slice(SPDM_CONTEXT.as_bytes(), GFP_KERNEL)?;
> +
> + if buf.len() != SPDM_COMBINED_PREFIX_SZ {
> + pr_err!("combined_spdm_prefix calculation is incorrect");
> + return Err(EPROTO);
> + }
> +
> + m[..SPDM_COMBINED_PREFIX_SZ].copy_from_slice(&buf);
> +
> + mhash.extend_with(self.hash_len, 0, GFP_KERNEL)?;
> +
> + if let Some(desc) = &mut self.desc {
> + desc.tfm = self.shash;
> +
> + unsafe {
> + to_result(bindings::crypto_shash_digest(
> + *desc,
> + m.as_ptr(),
> + m.len() as u32,
> + mhash.as_mut_ptr(),
> + ))?;
Could do with a few comments or spec references. It's a challenge
to align the spec with the code. I've read this a couple of times and
can't figure out why we have a hash of something we already hashed.
I may well have forgotten a spec detail though.
> + };
> + } else {
> + return Err(EPROTO);
> + }
> +
> + sig.m = mhash.as_mut_ptr();
> + }
> +
> + sig.m_size = self.hash_len as u32;
> +
> + if let Some(leaf_key) = self.leaf_key {
> + unsafe { to_result(bindings::public_key_verify_signature(leaf_key, &sig)) }
> + } else {
> + return Err(EPROTO);
> + }
> + }
> +
> + pub(crate) fn challenge(&mut self, slot: u8) -> Result<(), Error> {
> + let mut request = ChallengeReq::default();
> + request.version = self.version;
> + request.param1 = slot;
> +
> + let nonce_len = request.nonce.len();
> +
> + if self.next_nonce.len() > 0 {
> + let request_nonce_len = request.nonce.len();
> +
> + if self.next_nonce.len() == request_nonce_len {
> + request
> + .nonce
> + .copy_from_slice(&self.next_nonce[..request_nonce_len]);
> + } else {
> + return Err(EINVAL);
> + }
> +
> + self.next_nonce.clear();
> + } else {
> + unsafe {
> + bindings::get_random_bytes(&mut request.nonce as *mut _ as *mut c_void, nonce_len)
> + };
> + }
> +
> + let req_sz = if self.version <= SPDM_VER_12 {
> + offset_of!(ChallengeReq, context)
> + } else {
> + core::mem::size_of::<ChallengeReq>()
> + };
> +
> + let rsp_sz = self.challenge_rsp_len(nonce_len, SPDM_MAX_OPAQUE_DATA);
> +
> + // 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::from_elem(0u8, rsp_sz, GFP_KERNEL)?;
> +
> + let rc = self.spdm_exchange(request_buf, response_vec.as_mut_slice())? as usize;
> +
> + // The transport must report a length within the buffer we provided.
> + if rc < core::mem::size_of::<ChallengeRsp>() {
> + pr_err!("Truncated challenge response\n");
> + return Err(EIO);
> + }
> + response_vec.truncate(rc);
> +
> + let _response: &ChallengeRsp = Untrusted::new(response_vec.as_slice()).validate()?;
> +
> + // MSHLength is 0 as no measurement summary hash requested
> + let opaque_len_offset = core::mem::size_of::<SpdmHeader>() + self.hash_len + nonce_len;
> +
> + if opaque_len_offset + 2 > response_vec.len() {
> + return Err(EIO);
> + }
> +
> + let opaque_len = u16::from_le_bytes(
> + response_vec[opaque_len_offset..(opaque_len_offset + 2)]
> + .try_into()
> + .unwrap_or([0, 0]),
> + );
> +
> + let rsp_sz = self.challenge_rsp_len(nonce_len, opaque_len as usize);
> +
> + if rsp_sz > response_vec.len() {
> + pr_err!("Truncated challenge response\n");
> + return Err(EIO);
> + }
> +
We should sanity check the context matches that in requester.
Probably just a zero check given we aren't setting it in request.
> + self.transcript
> + .extend_from_slice(&response_vec[..rsp_sz], GFP_KERNEL)?;
> +
> + /* Verify signature at end of transcript against leaf key */
> + let sig_start = rsp_sz - self.sig_len;
> + let signature = &mut response_vec[sig_start..rsp_sz];
> +
> + match self.verify_signature(signature) {
> + Ok(()) => {
> + pr_info!("Authenticated with certificate slot {slot}\n");
> + Ok(())
> + }
> + Err(e) => {
> + pr_err!("Cannot verify challenge_auth signature: {e:?}\n");
> + Err(EPROTO)
> + }
> + }
> + }
> }
next prev parent reply other threads:[~2026-09-09 1:37 UTC|newest]
Thread overview: 35+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-01 1:03 [PATCH v3 00/21] lib: Rust implementation of SPDM alistair23
2026-09-01 1:03 ` [PATCH v3 01/21] rust: transmute: add `cast_slice[_mut]` functions alistair23
2026-09-01 1:03 ` [PATCH v3 02/21] rust: create basic untrusted data API alistair23
2026-09-01 1:03 ` [PATCH v3 03/21] rust: validate: add `Validate` trait alistair23
2026-09-01 1:03 ` [PATCH v3 04/21] X.509: Make certificate parser public alistair23
2026-09-01 1:03 ` [PATCH v3 05/21] X.509: Parse Subject Alternative Name in certificates alistair23
2026-09-01 1:03 ` [PATCH v3 06/21] X.509: Move certificate length retrieval into new helper alistair23
2026-09-01 1:03 ` [PATCH v3 07/21] rust: add bindings for hash.h alistair23
2026-09-01 1:03 ` [PATCH v3 08/21] rust: error: impl From<FromBytesWithNulError> for Kernel Error alistair23
2026-09-01 1:03 ` [PATCH v3 09/21] lib: rspdm: Initial commit of Rust SPDM alistair23
2026-09-08 22:57 ` Jonathan Cameron
2026-09-01 1:03 ` [PATCH v3 10/21] PCI/TSM: Rename pf0 to host alistair23
2026-09-08 23:01 ` Jonathan Cameron
2026-09-11 5:00 ` Alistair
2026-09-01 1:03 ` [PATCH v3 11/21] PCI/TSM: Support connecting to PCIe CMA devices alistair23
2026-09-01 1:03 ` [PATCH v3 12/21] PCI/CMA: Add a PCI TSM CMA driver using SPDM alistair23
2026-09-08 23:21 ` Jonathan Cameron
2026-09-01 1:03 ` [PATCH v3 13/21] PCI/CMA: Validate Subject Alternative Name in certificates alistair23
2026-09-01 1:03 ` [PATCH v3 14/21] lib: rspdm: Support SPDM get_version alistair23
2026-09-08 23:40 ` Jonathan Cameron
2026-09-01 1:03 ` [PATCH v3 15/21] lib: rspdm: Support SPDM get_capabilities alistair23
2026-09-08 23:47 ` Jonathan Cameron
2026-09-01 1:03 ` [PATCH v3 16/21] lib: rspdm: Support SPDM negotiate_algorithms alistair23
2026-09-04 5:01 ` Aksh Garg
2026-09-09 0:17 ` Jonathan Cameron
2026-09-11 4:53 ` Alistair
2026-09-01 1:03 ` [PATCH v3 17/21] lib: rspdm: Support SPDM get_digests alistair23
2026-09-09 0:31 ` Jonathan Cameron
2026-09-01 1:03 ` [PATCH v3 18/21] lib: rspdm: Support SPDM get_certificate alistair23
2026-09-01 1:03 ` [PATCH v3 19/21] lib: rspdm: Support SPDM certificate validation alistair23
2026-09-09 0:46 ` Jonathan Cameron
2026-09-01 1:03 ` [PATCH v3 20/21] rust: allow extracting the buffer from a CString alistair23
2026-09-01 1:03 ` [PATCH v3 21/21] lib: rspdm: Support SPDM challenge alistair23
2026-09-09 1:37 ` Jonathan Cameron [this message]
2026-09-11 3:46 ` Alistair
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=20260909023722.5615672b@jic23-huawei \
--to=jic23@kernel.org \
--cc=Jonathan.Cameron@huawei.com \
--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=djbw@kernel.org \
--cc=gary@garyguo.net \
--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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox