Add extract_fmc_signatures_static() to parse cryptographic signatures from FMC ELF firmware sections. This extracts the SHA-384 hash, RSA public key, and signature needed for Chain of Trust verification.
Also exposes the elf_section() helper from firmware.rs for use by FSP. Cc: Joel Fernandes <[email protected]> Cc: Gary Guo <[email protected]> Signed-off-by: John Hubbard <[email protected]> --- drivers/gpu/nova-core/firmware.rs | 4 +- drivers/gpu/nova-core/fsp.rs | 81 +++++++++++++++++++++++++++++-- 2 files changed, 80 insertions(+), 5 deletions(-) diff --git a/drivers/gpu/nova-core/firmware.rs b/drivers/gpu/nova-core/firmware.rs index 9a9b969aaf79..e9101a08511f 100644 --- a/drivers/gpu/nova-core/firmware.rs +++ b/drivers/gpu/nova-core/firmware.rs @@ -27,6 +27,8 @@ }, }; +pub(crate) use elf::elf_section; + pub(crate) mod booter; pub(crate) mod fsp; pub(crate) mod fwsec; @@ -607,7 +609,7 @@ fn elf32_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> { } /// Automatically detects ELF32 vs ELF64 based on the ELF header. - pub(super) fn elf_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> { + pub(crate) fn elf_section<'a>(elf: &'a [u8], name: &str) -> Option<&'a [u8]> { // Check ELF magic. if elf.len() < 5 || elf.get(0..4)? != b"\x7fELF" { return None; diff --git a/drivers/gpu/nova-core/fsp.rs b/drivers/gpu/nova-core/fsp.rs index c5f3267ce329..4f7d121f4240 100644 --- a/drivers/gpu/nova-core/fsp.rs +++ b/drivers/gpu/nova-core/fsp.rs @@ -124,10 +124,10 @@ unsafe impl AsBytes for GspFmcBootParams {} // SAFETY: All bit patterns are valid for the primitive fields. unsafe impl FromBytes for GspFmcBootParams {} -/// Size constraints for FSP security signatures. -const FSP_HASH_SIZE: usize = 48; // SHA-384 hash (12 x u32) -const FSP_PKEY_SIZE: usize = 97; // Public key size for GB202 (not 384!) -const FSP_SIG_SIZE: usize = 96; // Signature size for GB202 (not 384!) +/// Size constraints for FSP security signatures (in bytes). +const FSP_HASH_SIZE: usize = 48; // SHA-384 hash ([u32; 12]) +const FSP_PKEY_SIZE: usize = 384; // RSA public key ([u32; 96]) +const FSP_SIG_SIZE: usize = 384; // RSA signature ([u32; 96]) /// Structure to hold FMC signatures. #[derive(Debug, Clone, Copy)] @@ -241,4 +241,77 @@ pub(crate) fn wait_secure_boot( }) .map(|_| ()) } + + /// Extract FMC firmware signatures for Chain of Trust verification. + /// + /// Extracts real cryptographic signatures from FMC ELF32 firmware sections. + /// Returns signatures in a heap-allocated structure to prevent stack overflow. + pub(crate) fn extract_fmc_signatures_static( + dev: &device::Device<device::Bound>, + fmc_fw_data: &[u8], + ) -> Result<KBox<FmcSignatures>> { + // Extract hash section (SHA-384) + let hash_section = crate::firmware::elf_section(fmc_fw_data, "hash") + .ok_or(EINVAL) + .inspect_err(|_| dev_err!(dev, "FMC firmware missing 'hash' section\n"))?; + + // Extract public key section (RSA public key) + let pkey_section = crate::firmware::elf_section(fmc_fw_data, "publickey") + .ok_or(EINVAL) + .inspect_err(|_| dev_err!(dev, "FMC firmware missing 'publickey' section\n"))?; + + // Extract signature section (RSA signature) + let sig_section = crate::firmware::elf_section(fmc_fw_data, "signature") + .ok_or(EINVAL) + .inspect_err(|_| dev_err!(dev, "FMC firmware missing 'signature' section\n"))?; + + // Validate section sizes - hash must be exactly 48 bytes + if hash_section.len() != FSP_HASH_SIZE { + dev_err!( + dev, + "FMC hash section size {} != expected {}\n", + hash_section.len(), + FSP_HASH_SIZE + ); + return Err(EINVAL); + } + + // Public key and signature can be smaller than the fixed array sizes. + if pkey_section.len() > FSP_PKEY_SIZE { + dev_err!( + dev, + "FMC publickey section size {} > maximum {}\n", + pkey_section.len(), + FSP_PKEY_SIZE + ); + return Err(EINVAL); + } + + if sig_section.len() > FSP_SIG_SIZE { + dev_err!( + dev, + "FMC signature section size {} > maximum {}\n", + sig_section.len(), + FSP_SIG_SIZE + ); + return Err(EINVAL); + } + + // Allocate signature structure on heap to avoid stack overflow + let mut signatures = KBox::new(FmcSignatures::default(), GFP_KERNEL)?; + + // Copy hash section directly as bytes (48 bytes exactly) + signatures + .hash384 + .as_bytes_mut() + .copy_from_slice(hash_section); + + // Copy public key section (up to 384 bytes, zero-padded) + signatures.public_key.as_bytes_mut()[..pkey_section.len()].copy_from_slice(pkey_section); + + // Copy signature section (up to 384 bytes, zero-padded) + signatures.signature.as_bytes_mut()[..sig_section.len()].copy_from_slice(sig_section); + + Ok(signatures) + } } -- 2.52.0
