This crate provides a software-based reference implementation of the SPDM peer certificate store for the AST1060-EVB target. It stores and manages certificates received from peer SPDM responders during protocol operations.
Note: This is a platform-specific implementation using static buffers. Future hardware-backed implementations could use secure flash, implement certificate caching across reboots, or provide hardware-accelerated certificate validation.
The peer certificate store is used by SPDM requester (client) applications to store certificates received from responder (server) devices during attestation and authentication flows.
| Aspect | SpdmCertStore | PeerCertStore |
|---|---|---|
| Used by | SPDM Responder | SPDM Requester |
| Stores | Local device certificates | Remote peer certificates |
| Purpose | Sign challenge responses | Verify peer signatures |
| Provisioning | Build-time (embedded) | Runtime (received via protocol) |
| Signing | Yes (with private key) | No (verification only) |
┌─────────────────────────┐ │ SPDM Requester │ │ (Client) │ └───────────┬─────────────┘ │ GET_DIGESTS │ GET_CERTIFICATE │ CHALLENGE ▼ ┌─────────────────────────┐ │ Ast1060PeerCertStore │◄── This crate │ - Store peer certs │ │ - Assemble fragments │ │ - Provide for verify │ └─────────────────────────┘
use ast1060_peer_cert_store::Ast1060PeerCertStore; use spdm_lib::cert_store::PeerCertStore; // Create peer certificate store let mut peer_store = Ast1060PeerCertStore::new(); // Configure slots (from GET_DIGESTS response) peer_store.set_supported_slots(0b11)?; // Slots 0 and 1 supported peer_store.set_provisioned_slots(0b01)?; // Only slot 0 provisioned // Store digest peer_store.set_digest(0, &digest_from_response)?; // Store metadata peer_store.set_cert_info(0, cert_info)?; peer_store.set_key_usage_mask(0, key_usage)?;
// GET_CERTIFICATE responses may be fragmented across multiple messages loop { let portion = receive_certificate_portion()?; let status = peer_store.assemble(0, &portion)?; match status { ReassemblyStatus::InProgress => continue, ReassemblyStatus::Done => break, _ => {} } } // Retrieve complete certificate chain let cert_chain = peer_store.get_cert_chain(0, hash_algo)?; let root_hash = peer_store.get_root_hash(0, hash_algo)?;
// Get certificate for signature verification let cert_chain = peer_store.get_cert_chain(0, BaseHashAlgoType::Sha384)?; // Verify signature using crypto service crypto_client.verify_signature(cert_chain, message, signature)?;
Each slot stores:
┌─────────────────────────────────────────────┐ │ SpdmCertChainHeader (4 bytes) │ ├─────────────────────────────────────────────┤ │ Root Certificate Hash (48 bytes, SHA-384) │ ├─────────────────────────────────────────────┤ │ Root Certificate (DER) │ ├─────────────────────────────────────────────┤ │ Intermediate Certificate(s) (DER) │ ├─────────────────────────────────────────────┤ │ End Entity Certificate (DER) │ └─────────────────────────────────────────────┘
The get_cert_chain() method returns only the DER certificates (without header and root hash).
The get_raw_chain() method returns the complete chain (with header).
| Error | Cause |
|---|---|
InvalidSlotId | Slot ID >= 2 |
BufferTooSmall | Certificate chain > 4KB |
CertReadError | Slot empty or data not available |
Undefined | Optional field not set |
PlatformError | Invalid bitmask or internal error |
The implementation includes comprehensive unit tests:
# Tests are included in the library bazel test --platforms=//target/ast1060-evb:ast1060-evb \ //target/ast1060-evb/peer-cert-store:peer_cert_store
MAX_PEER_SLOTS)When implementing hardware-backed versions:
// Store peer certificates in secure flash impl Ast1060PeerCertStore { fn persist_to_flash(&self, slot_id: u8) -> Result<()> { platform::secure_flash::write(slot_id, &self.slots[slot_id])?; Ok(()) } fn load_from_flash(&mut self, slot_id: u8) -> Result<()> { platform::secure_flash::read(slot_id, &mut self.slots[slot_id])?; Ok(()) } }
// Add X.509 parsing and validation fn validate_cert_chain(&self, slot_id: u8) -> Result<()> { let chain = self.get_raw_chain(slot_id)?; // Parse X.509 certificates let certs = x509_parser::parse_chain(chain)?; // Verify chain validity certs.verify_chain()?; // Check expiration certs.check_validity(current_time())?; Ok(()) }
// Check certificate revocation status fn check_revocation(&self, slot_id: u8) -> Result<()> { let cert = self.get_cert_chain(slot_id, hash_algo)?; // Query OCSP or CRL platform::check_cert_revocation(cert)?; Ok(()) }
use ast1060_peer_cert_store::Ast1060PeerCertStore; use spdm_lib::requester::SpdmRequester; // Create peer store let peer_store = Ast1060PeerCertStore::new(); // Create SPDM requester with peer store let requester = SpdmRequester::new( transport, hash_impl, rng_impl, peer_store, // ← Our implementation ); // Run SPDM protocol requester.get_version()?; requester.get_capabilities()?; requester.negotiate_algorithms()?; requester.get_digests()?; // Populates peer_store requester.get_certificate(0)?; // Fragments assembled in peer_store requester.challenge(0)?; // Uses peer_store for verification
Licensed under the Apache-2.0 license.