blob: 94f371b4f7c00be195cd2eac862c9c9c5708a540 [file]
// Licensed under the Apache-2.0 license
//! SPDM Responder Application
//!
//! Runs the SPDM responder using spdm-lib's responder API. Communicates with
//! the SPDM requester via the MCTP loopback server using IPC channels.
//!
//! The responder:
//! 1. Connects to the MCTP loopback server via an IPC channel
//! 2. Creates an `MctpSpdmTransport` in responder mode (listener for SPDM messages)
//! 3. Creates an `SpdmContext` with mock platform implementations
//! 4. Loops processing incoming SPDM requests via `responder_process_message`
#![no_std]
#![no_main]
use openprot_mctp_client::IpcMctpClient;
use openprot_spdm_transport_mctp::MctpSpdmTransport;
use pw_log::{error, info};
use spdm_lib::codec::MessageBuf;
use spdm_lib::context::SpdmContext;
use spdm_lib::platform::transport::SpdmTransport;
use spdm_lib::protocol::{
AeadCipherSuite, AlgorithmPriorityTable, BaseAsymAlgo, BaseHashAlgo, CapabilityFlags,
DeviceAlgorithms, DeviceCapabilities, DheNamedGroup, KeySchedule, LocalDeviceAlgorithms,
MeasurementHashAlgo, MeasurementSpecification, MelSpecification, OtherParamSupport,
ReqBaseAsymAlg, SpdmVersion,
};
use userspace::entry;
use userspace::syscall;
use app_spdm_responder::handle;
use mock_platform::{MockCertStore, MockEvidence, MockHash, MockRng};
/// Create local device algorithms configuration for SPDM responder
fn create_local_algorithms<'a>() -> LocalDeviceAlgorithms<'a> {
// Measurement specification (DMTF)
let mut measurement_spec = MeasurementSpecification::default();
measurement_spec.set_dmtf_measurement_spec(1);
// Measurement hash algorithm (SHA-384)
let mut measurement_hash_algo = MeasurementHashAlgo::default();
measurement_hash_algo.set_tpm_alg_sha_384(1);
// Base asymmetric algorithm (ECDSA P-384)
let mut base_asym_algo = BaseAsymAlgo::default();
base_asym_algo.set_tpm_alg_ecdsa_ecc_nist_p384(1);
// Base hash algorithm (SHA-384)
let mut base_hash_algo = BaseHashAlgo::default();
base_hash_algo.set_tpm_alg_sha_384(1);
let device_algorithms = DeviceAlgorithms {
measurement_spec,
other_param_support: OtherParamSupport::default(),
measurement_hash_algo,
base_asym_algo,
base_hash_algo,
mel_specification: MelSpecification::default(),
dhe_group: DheNamedGroup::default(),
aead_cipher_suite: AeadCipherSuite::default(),
req_base_asym_algo: ReqBaseAsymAlg::default(),
key_schedule: KeySchedule::default(),
};
let algorithm_priority_table = AlgorithmPriorityTable {
measurement_specification: None,
opaque_data_format: None,
base_asym_algo: None,
base_hash_algo: None,
mel_specification: None,
dhe_group: None,
aead_cipher_suite: None,
req_base_asym_algo: None,
key_schedule: None,
};
LocalDeviceAlgorithms {
device_algorithms,
algorithm_priority_table,
}
}
fn spdm_responder_loop() -> Result<(), &'static str> {
info!("SPDM responder starting");
// Create MCTP client via IPC to loopback server
let mctp_client = IpcMctpClient::new(handle::MCTP);
// Create SPDM transport in responder mode
let mut transport = MctpSpdmTransport::new_responder(mctp_client);
// Initialize transport (registers MCTP listener for SPDM message type 0x05)
if let Err(_) = transport.init_sequence() {
error!("Failed to initialize responder transport");
return Err("Transport init failed");
}
info!("SPDM transport initialized (responder mode)");
// Create mock platform implementations
let mut cert_store = MockCertStore::new();
let mut hash = MockHash::new();
let mut m1_hash = MockHash::new();
let mut l1_hash = MockHash::new();
let mut rng = MockRng::new();
let evidence = MockEvidence::new();
// Configure device capabilities
let mut flags = CapabilityFlags::default();
flags.set_cert_cap(1); // Certificate capability
flags.set_chal_cap(1); // Challenge capability
flags.set_meas_cap(2); // Measurements with signature
flags.set_meas_fresh_cap(1); // Measurements freshness
flags.set_chunk_cap(1); // Chunk capability
let capabilities = DeviceCapabilities {
ct_exponent: 0,
flags,
data_transfer_size: 1024,
max_spdm_msg_size: 4096,
include_supported_algorithms: true,
};
// Configure supported algorithms
let algorithms = create_local_algorithms();
// Supported SPDM versions
static SUPPORTED_VERSIONS: [SpdmVersion; 2] = [SpdmVersion::V12, SpdmVersion::V13];
// Create SPDM responder context
let mut ctx = match SpdmContext::new(
&SUPPORTED_VERSIONS,
&mut transport,
capabilities,
algorithms,
&mut cert_store,
None, // No peer cert store for responder
&mut hash,
&mut m1_hash,
&mut l1_hash,
&mut rng,
&evidence,
) {
Ok(ctx) => ctx,
Err(_) => {
error!("Failed to create SPDM responder context");
return Err("SPDM context creation failed");
}
};
info!("SPDM responder context created, entering message loop");
// Responder loop: process incoming SPDM requests
let mut response_buf = [0u8; 4096];
let mut msg_buf = MessageBuf::new(&mut response_buf);
loop {
msg_buf.reset();
match ctx.responder_process_message(&mut msg_buf) {
Ok(_) => {
info!("Processed SPDM request successfully");
}
Err(_) => {
error!("Error processing SPDM request");
// Continue processing — don't exit on individual message errors
}
}
}
}
#[entry]
fn entry() -> ! {
info!("SPDM Responder Application");
match spdm_responder_loop() {
Ok(_) => {
// Responder loop should not return Ok — it loops forever
info!("SPDM responder exited unexpectedly");
let _ = syscall::debug_shutdown(Ok(()));
}
Err(e) => {
error!("SPDM responder FAILURE: {}", e as &str);
let _ = syscall::debug_shutdown(Err(pw_status::Error::Unknown));
}
}
loop {}
}
#[panic_handler]
fn panic(_info: &core::panic::PanicInfo) -> ! {
error!("PANIC in SPDM responder");
loop {}
}