diff --git a/docs/src/integration-guides/spdm-lib/hubris-ipc.md b/docs/src/integration-guides/spdm-lib/hubris-ipc.md new file mode 100644 index 0000000..ed588f2 --- /dev/null +++ b/docs/src/integration-guides/spdm-lib/hubris-ipc.md @@ -0,0 +1,321 @@ +# SPDM-lib to Hubris IPC Integration Guide + +## Overview + +This guide explains how to integrate the existing `spdm-lib` SPDM protocol implementation with Hubris IPC, bridging between the comprehensive spdm-lib types and the simplified IPC-compatible types required for inter-task communication. + +## Integration Architecture + +``` +┌─────────────────┐ ┌──────────────────────────┐ ┌─────────────────────┐ +│ SPDM Client │ │ Hubris IPC Boundary │ │ SPDM Server │ +│ (Other Task) │ │ │ │ (spdm-lib context) │ +│ │ │ - Simple IPC Types │ │ │ +│ - SpdmResponder │◄──►│ - Serializable │◄──►│ - Full spdm-lib │ +│ - SpdmVersion │ │ - no_std compatible │ │ - SpdmContext │ +│ - SpdmError │ │ │ │ - Platform traits │ +└─────────────────┘ └──────────────────────────┘ └─────────────────────┘ +``` + +## Type Mapping Strategy + +### 1. IPC Types (Client-Side) +Located in `drv/spdm-responder-api/src/lib.rs`: + +```rust +// Simple, serializable IPC types +#[derive(Serialize, Deserialize, SerializedSize)] +pub enum SpdmVersion { + V1_0 = 0x10, + V1_1 = 0x11, + V1_2 = 0x12, + V1_3 = 0x13, +} + +#[derive(Serialize, Deserialize, SerializedSize)] +pub struct SpdmCapabilities { + pub ct_exponent: u8, + pub flags: u32, // Flattened from bitfield + pub data_transfer_size: u32, + pub max_spdm_msg_size: u32, +} + +#[derive(IdolError, Serialize, Deserialize, SerializedSize)] +pub enum SpdmError { + UnsupportedVersion = 1, + InvalidParam = 2, + // ... flattened error hierarchy +} +``` + +### 2. spdm-lib Types (Server-Side) +Located in `spdm-lib/src/protocol/`: + +```rust +// Rich, protocol-complete spdm-lib types +pub enum SpdmVersion { + V10, V11, V12, V13 +} + +pub struct DeviceCapabilities { + pub ct_exponent: u8, + pub flags: CapabilityFlags, // Complex bitfield + pub data_transfer_size: u32, + pub max_spdm_msg_size: u32, +} + +pub enum SpdmError { + UnsupportedVersion, + InvalidParam, + Codec(CodecError), // Nested errors + Transport(TransportError), + Command(CommandError), + // ... +} +``` + +### 3. Server-Side Conversion Layer +Located in `drv/spdm-responder-server/src/main.rs`: + +```rust +use spdm_lib::protocol::version::SpdmVersion as LibSpdmVersion; +use spdm_lib::protocol::capabilities::DeviceCapabilities as LibCapabilities; +use spdm_lib::error::SpdmError as LibSpdmError; + +impl InOrderSpdmResponderImpl for SpdmResponderServer { + fn get_version(&mut self, _msg: &RecvMessage) -> Result> { + // 1. Use spdm-lib to get actual supported versions + let lib_versions = self.spdm_context.supported_versions; + + // 2. Convert spdm-lib types to IPC types + let ipc_versions: heapless::Vec = lib_versions + .iter() + .map(|&v| convert_version(v)) + .collect(); + + // 3. Return IPC-compatible response + Ok(SpdmVersionResponse { + version_count: ipc_versions.len() as u8, + versions: ipc_versions.into_array().unwrap_or_default(), + }) + } + + fn get_capabilities(&mut self, _msg: &RecvMessage) -> Result> { + // 1. Get capabilities from spdm-lib + let lib_caps = self.spdm_context.local_capabilities; + + // 2. Convert to IPC format + Ok(SpdmCapabilities { + ct_exponent: lib_caps.ct_exponent, + flags: lib_caps.flags.0, // Extract bitfield value + data_transfer_size: lib_caps.data_transfer_size, + max_spdm_msg_size: lib_caps.max_spdm_msg_size, + }) + } +} + +// Conversion functions +fn convert_version(lib_ver: LibSpdmVersion) -> SpdmVersion { + match lib_ver { + LibSpdmVersion::V10 => SpdmVersion::V1_0, + LibSpdmVersion::V11 => SpdmVersion::V1_1, + LibSpdmVersion::V12 => SpdmVersion::V1_2, + LibSpdmVersion::V13 => SpdmVersion::V1_3, + } +} + +fn convert_error(lib_err: LibSpdmError) -> SpdmError { + match lib_err { + LibSpdmError::UnsupportedVersion => SpdmError::UnsupportedVersion, + LibSpdmError::InvalidParam => SpdmError::InvalidParam, + LibSpdmError::Codec(_) => SpdmError::CodecError, + LibSpdmError::Transport(_) => SpdmError::TransportError, + LibSpdmError::Command(_) => SpdmError::CommandError, + LibSpdmError::BufferTooSmall => SpdmError::BufferTooSmall, + LibSpdmError::UnsupportedRequest => SpdmError::UnsupportedRequest, + LibSpdmError::CertStore(_) => SpdmError::CertStoreError, + } +} +``` + +## Implementation Steps + +### Phase 1: API Crate (IPC Types Only) +**Location**: `drv/spdm-responder-api/` +**Dependencies**: No spdm-lib dependency +**Responsibility**: Define simple, serializable types for IPC + +```toml +# drv/spdm-responder-api/Cargo.toml +[dependencies] +# Standard Hubris IPC dependencies only +hubpack = { workspace = true } +serde = { workspace = true } +derive-idol-err = { path = "../../lib/derive-idol-err" } +# NO spdm-lib dependency +``` + +### Phase 2: Server Crate (Integration Layer) +**Location**: `drv/spdm-responder-server/` +**Dependencies**: Both IPC types AND spdm-lib +**Responsibility**: Convert between type systems + +```toml +# drv/spdm-responder-server/Cargo.toml +[dependencies] +drv-spdm-responder-api = { path = "../spdm-responder-api" } +spdm-lib = { path = "../../spdm-lib" } +# ... other server dependencies +``` + +### Phase 3: Platform Integration +**Location**: `drv/spdm-responder-server/src/platform/` +**Responsibility**: Implement spdm-lib platform traits for Hubris + +```rust +// Hubris-specific platform implementations +struct HubrisTransport { + // Use Hubris IPC for SPDM transport +} + +impl spdm_lib::platform::transport::SpdmTransport for HubrisTransport { + // Implement using Hubris communication primitives +} + +struct HubrisRng { + rng_client: RngClient, +} + +impl spdm_lib::platform::rng::SpdmRng for HubrisRng { + fn fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), SpdmRngError> { + self.rng_client.fill_bytes(dest) + .map_err(|_| SpdmRngError::GenerationFailed) + } +} + +struct HubrisHash { + hash_client: HashClient, +} + +impl spdm_lib::platform::hash::SpdmHash for HubrisHash { + fn hash_sha256(&mut self, data: &[u8], output: &mut [u8]) -> Result<(), SpdmHashError> { + self.hash_client.digest_sha256(data, output) + .map_err(|_| SpdmHashError::HashFailed) + } +} +``` + +## Key Benefits of This Approach + +### 1. **Separation of Concerns** +- **API Crate**: Simple IPC types, no complex dependencies +- **Server Crate**: Full protocol implementation with conversions +- **Clear Boundary**: Type conversion happens at server boundary + +### 2. **Dependency Management** +- Client tasks only depend on lightweight IPC types +- Server task handles complex spdm-lib dependencies +- No memory allocator issues in client code + +### 3. **Standards Compliance** +- Server uses proven spdm-lib implementation +- Full SPDM protocol support with proper state management +- Platform abstractions allow Hubris-specific optimizations + +### 4. **Incremental Implementation** +- Start with basic operations (get_version, get_capabilities) +- Add complex operations (certificates, measurements) progressively +- Maintain IPC interface stability while enhancing server + +## Error Handling Strategy + +### IPC Error Flattening +spdm-lib has rich, nested error types that must be flattened for IPC: + +```rust +// spdm-lib: Rich error hierarchy +pub enum SpdmError { + Command(CommandError), + Codec(CodecError), + Transport(TransportError(IoError)), +} + +// IPC: Flattened error codes +pub enum SpdmError { + CommandError = 5, + CodecError = 3, + TransportError = 4, +} +``` + +### Server-Side Error Conversion +The server performs lossy but sufficient error conversion: + +```rust +fn handle_spdm_operation(&mut self) -> Result> { + match self.spdm_context.some_operation() { + Ok(result) => Ok(convert_response(result)), + Err(lib_error) => Err(RequestError::from(convert_error(lib_error))), + } +} +``` + +## Certificate and Measurement Integration + +### Large Data Handling +SPDM certificates and measurements require special handling: + +```rust +fn get_certificate( + &mut self, + slot: u8, + offset: u16, + length: u16, + buffer: Leased, +) -> Result> { + // 1. Get certificate from spdm-lib cert store + let cert_data = self.spdm_context.cert_store.get_certificate(slot)?; + + // 2. Handle chunked transfer using IPC lease + let available = cert_data.len().saturating_sub(offset as usize); + let copy_len = core::cmp::min(length as usize, available); + + if copy_len > 0 { + buffer.write_range(0..copy_len, &cert_data[offset as usize..]) + .map_err(|_| RequestError::went_away())?; + } + + // 3. Return actual bytes copied + Ok(copy_len as u16) +} +``` + +## Testing Strategy + +### Unit Tests +- Test type conversions in isolation +- Verify error code mappings +- Test edge cases (empty responses, large data) + +### Integration Tests +- End-to-end IPC communication +- spdm-lib integration with Hubris platform traits +- Performance testing with real hardware acceleration + +### Compliance Tests +- SPDM protocol conformance using spdm-lib test suite +- Interoperability with external SPDM requesters + +## Migration from Current State + +### Current Implementation +We currently have placeholder types in the IPC interface. + +### Migration Steps +1. **Keep IPC Types**: Maintain current simplified types in API crate +2. **Add Server Integration**: Import spdm-lib only in server crate +3. **Implement Conversions**: Add type conversion functions +4. **Replace Mocks**: Replace mock implementations with real spdm-lib calls +5. **Add Platform Traits**: Implement Hubris-specific platform integration + +This approach allows us to leverage the full power of spdm-lib while maintaining clean IPC boundaries and avoiding dependency issues in client code. \ No newline at end of file diff --git a/docs/src/integration-guides/spdm-lib/spdm-idl-lang-guide.md b/docs/src/integration-guides/spdm-lib/spdm-idl-lang-guide.md new file mode 100644 index 0000000..69d2270 --- /dev/null +++ b/docs/src/integration-guides/spdm-lib/spdm-idl-lang-guide.md @@ -0,0 +1,297 @@ +# SPDM Responder IDL Language Guide + +This guide shows how to use Hubris IDL language constructs to design an `idl/spdm-responder.idol`, serving as both a reference for the SPDM interface and a practical guide to IDL language features. + +## IDL Structure Overview + +The SPDM responder interface demonstrates a complete Hubris IDL definition with all major language constructs: + +```idl +Interface( + name: "SpdmResponder", + ops: { /* operation definitions */ } +) +``` + +## Core Language Constructs + +### 1. Interface Declaration + +```idl +Interface( + name: "SpdmResponder", + ops: { ... } +) +``` + +**Purpose**: Defines a named IPC interface that generates client stubs and server traits. +**Generated Code**: +- Client: `SpdmResponder` struct with methods +- Server: `InOrderSpdmResponderImpl` trait to implement + +### 2. Operation Definitions + +Each operation in the `ops` block defines an IPC method: + +```idl +"get_version": ( + doc: "Get supported SPDM protocol versions in priority order", + reply: Result(ok: "SpdmVersionResponse", err: CLike("SpdmError")), + encoding: Hubpack, + idempotent: true, +), +``` + +**Components**: +- **name**: Method name (becomes Rust function name) +- **doc**: Documentation string for generated code +- **reply**: Return type specification +- **encoding**: Serialization format (always `Hubpack` in Hubris) +- **idempotent**: Whether operation can be safely retried + +### 3. Result Types + +```idl +reply: Result( + ok: "SpdmVersionResponse", + err: CLike("SpdmError"), +) +``` + +**Purpose**: Defines fallible operations that return `Result` +**Components**: +- **ok**: Success type (references a Rust type) +- **err**: Error type using `CLike` enum wrapper + +### 4. CLike Error Types + +```idl +err: CLike("SpdmError") +``` + +**Purpose**: Wraps a C-like enum for error handling +**Generated**: `RequestError` in server implementations +**Requirement**: Error type must implement `IdolError` trait + +### 5. Arguments Block + +```idl +args: { + "slot": "u8", + "offset": "u16", + "length": "u16", +} +``` + +**Purpose**: Defines method parameters passed by value +**Encoding**: Serialized with specified encoding (Hubpack) +**Types**: Supports primitive types, structs, enums, and arrays + +### 6. Leases Block + +```idl +leases: { + "certificate": (type: "[u8]", write: true, max_len: Some(4096)), + "nonce": (type: "[u8]", read: true, max_len: Some(64)), +} +``` + +**Purpose**: Defines zero-copy buffer passing between tasks +**Components**: +- **type**: Buffer element type (usually `[u8]` for byte arrays) +- **read/write**: Access direction from server perspective +- **max_len**: Optional size limit for safety + +**Lease Types**: +- `read: true` → Server reads from client buffer +- `write: true` → Server writes to client buffer +- Both → Bidirectional access + +### 7. Idempotency Markers + +```idl +idempotent: true // Safe to retry, no side effects +idempotent: false // May change state, avoid retries +``` + +**Purpose**: Indicates whether operations can be safely retried +**Usage**: Critical for fault tolerance and transaction semantics + +## Advanced Type Specifications + +### Optional Types + +```idl +"nonce": "Option<[u8; 32]>" +``` + +**Purpose**: Parameters that may or may not be present +**Generated**: Standard Rust `Option` type + +### Fixed Arrays + +```idl +"nonce": "[u8; 32]" +``` + +**Purpose**: Fixed-size arrays with compile-time known length +**Serialization**: Efficient direct memory copy + +### Unit Type + +```idl +reply: Result(ok: "()", err: CLike("SpdmError")) +``` + +**Purpose**: Operations that return no data on success +**Usage**: Status operations, void functions + +## SPDM-Specific Patterns + +### Certificate Operations + +```idl +"get_certificate": ( + args: { + "slot": "u8", + "offset": "u16", + "length": "u16", + }, + leases: { + "certificate": (type: "[u8]", write: true, max_len: Some(4096)), + }, + reply: Result(ok: "u16", err: CLike("SpdmError")), +) +``` + +**Pattern**: Streaming large data with offset/length parameters +**Return**: Actual bytes written (partial read support) + +### Challenge-Response Authentication + +```idl +"challenge_auth": ( + args: { + "slot": "u8", + "measurement_summary": "u8", + }, + leases: { + "nonce": (type: "[u8]", read: true, max_len: Some(64)), + "signature": (type: "[u8]", write: true, max_len: Some(512)), + }, + reply: Result(ok: "ChallengeAuthResponse", err: CLike("SpdmError")), +) +``` + +**Pattern**: Input challenge → cryptographic response +**Security**: Separates input (nonce) from output (signature) + +### Key Exchange Operations + +```idl +"key_exchange": ( + leases: { + "req_random": (type: "[u8]", read: true, max_len: Some(64)), + "rsp_random": (type: "[u8]", write: true, max_len: Some(64)), + "exchange_data": (type: "[u8]", read: true, max_len: Some(512)), + "rsp_exchange_data": (type: "[u8]", write: true, max_len: Some(512)), + }, +) +``` + +**Pattern**: Bidirectional cryptographic data exchange +**Security**: Clear separation of request/response buffers + +## Code Generation Results + +### Client Side (API Crate) + +```rust +// Generated from IDL +pub struct SpdmResponder { /* task_id */ } + +impl SpdmResponder { + pub fn get_version(&self) -> Result> { + // IPC call implementation + } + + pub fn get_certificate( + &self, + slot: u8, + offset: u16, + length: u16, + certificate: Leased + ) -> Result> { + // IPC call with lease + } +} +``` + +### Server Side (Server Crate) + +```rust +// Generated trait to implement +pub trait InOrderSpdmResponderImpl: NotificationHandler { + fn get_version( + &mut self, + msg: &RecvMessage, + ) -> Result>; + + fn get_certificate( + &mut self, + msg: &RecvMessage, + slot: u8, + offset: u16, + length: u16, + certificate: LenLimit, 4096>, + ) -> Result>; +} +``` + +## Best Practices Demonstrated + +### 1. Consistent Error Handling +- All operations return `Result` with same error type +- Enables uniform error handling across interface + +### 2. Appropriate Idempotency +- Read operations: `idempotent: true` +- State-changing operations: `idempotent: false` +- Critical for reliable distributed systems + +### 3. Zero-Copy Buffer Management +- Large data uses leases (certificates, signatures) +- Small data uses args (slot numbers, flags) +- Optimal memory usage and performance + +### 4. Security Boundaries +- Input/output buffers clearly separated +- Buffer size limits prevent overflow +- Cryptographic operations isolated + +### 5. Comprehensive Documentation +- Every operation has descriptive `doc` string +- Generated API includes full documentation +- Self-documenting interface design + +## Integration with Hubris + +### Task Slots +```toml +# In app.toml +[tasks.spdm_responder] +name = "drv-spdm-responder-server" + +[tasks.client] +task-slots = ["spdm_responder"] +``` + +### Client Usage +```rust +task_slot!(SPDM, spdm_responder); + +let spdm = SpdmResponder::from(SPDM.get_task_id()); +let version = spdm.get_version()?; +``` + +This IDL interface demonstrates modern IPC design with security, performance, and maintainability as core principles. \ No newline at end of file