blob: 6b1be610c45a7b0412856db4b1cadeca10f56761 [file] [view]
# SPDM Peer Certificate Store - AST1060-EVB Software Implementation
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.
## Overview
The peer certificate store is used by SPDM **requester** (client) applications to store certificates received from **responder** (server) devices during attestation and authentication flows.
### Key Differences from SpdmCertStore
| 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) |
## Architecture
```text
┌─────────────────────────┐
│ SPDM Requester │
│ (Client) │
└───────────┬─────────────┘
│ GET_DIGESTS
│ GET_CERTIFICATE
│ CHALLENGE
┌─────────────────────────┐
│ Ast1060PeerCertStore │◄── This crate
│ - Store peer certs │
│ - Assemble fragments │
│ - Provide for verify │
└─────────────────────────┘
```
## Features
- **Runtime storage**: Stores certificates received during protocol execution
- **Fragment assembly**: Handles multi-message certificate transfer
- **Two certificate slots**: Support for up to 2 peer certificates
- **Fixed-size buffers**: 4KB per slot, no dynamic allocation
- **Metadata storage**: Digest, KeyPairID, CertificateInfo, KeyUsageMask
- **No_std compatible**: Fully embedded-friendly
## Usage
### Basic Storage
```rust
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)?;
```
### Certificate Fragment Assembly
```rust
// 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)?;
```
### Verification
```rust
// 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)?;
```
## Implementation Details
### Storage Layout
Each slot stores:
- **Certificate chain**: Up to 4KB (includes SPDM header, root hash, DER certificates)
- **Digest**: 48 bytes (SHA-384 from GET_DIGESTS)
- **KeyPairID**: Optional u8
- **CertificateInfo**: Optional metadata
- **KeyUsageMask**: Optional usage flags
- **MeasurementSummaryHashType**: From CHALLENGE request
### Memory Usage
- 2 slots × 4KB = **8KB** for certificate storage
- 2 slots × ~100 bytes = **~200 bytes** for metadata
- **Total: ~8.2KB** static RAM
### Certificate Chain Format
```
┌─────────────────────────────────────────────┐
│ 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 Handling
| 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 |
## Testing
The implementation includes comprehensive unit tests:
```bash
# Tests are included in the library
bazel test --platforms=//target/ast1060-evb:ast1060-evb \
//target/ast1060-evb/peer-cert-store:peer_cert_store
```
### Test Coverage
- Slot count verification
- Supported/provisioned slot masks
- Certificate chain storage and retrieval
- Buffer overflow protection
- Fragment assembly
- Digest storage
- Metadata storage (KeyPairID, CertInfo, KeyUsage)
- Slot reset functionality
- Invalid slot ID handling
- MeasurementSummaryHashType storage
## Limitations
1. **Fixed slot count**: 2 slots maximum (can be increased by changing `MAX_PEER_SLOTS`)
2. **Fixed certificate size**: 4KB per slot (typical X.509 chains are 1-4KB)
3. **No persistence**: Stored certificates lost on reset/power cycle
4. **No validation**: Does not validate certificate structure or signatures
5. **Simple assembly**: Caller must determine when reassembly is complete
## Future Hardware-Backed Implementations
When implementing hardware-backed versions:
### Secure Storage
```rust
// 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(())
}
}
```
### Certificate Validation
```rust
// 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(())
}
```
### Certificate Revocation
```rust
// 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(())
}
```
## Integration with SPDM Requester
```rust
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
```
## License
Licensed under the Apache-2.0 license.