Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
43 changes: 41 additions & 2 deletions examples/spdm_requester.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,14 @@ use std::net::TcpStream;
use clap::Parser;
use der::{Decode, Encode};
use p384::ecdsa::{Signature, VerifyingKey};
use spdm_lib::chunk_ctx::ChunkError;
use spdm_lib::codec::MessageBuf;
use spdm_lib::commands::certificate::request::generate_get_certificate;
use spdm_lib::commands::challenge::{
request::generate_challenge_request, MeasurementSummaryHashType,
};
use spdm_lib::context::SpdmContext;
use spdm_lib::error::SpdmError;
use spdm_lib::error::{CommandError, SpdmError};
use spdm_lib::protocol::algorithms::{
AeadCipherSuite, AlgorithmPriorityTable, BaseAsymAlgo, BaseHashAlgo, DeviceAlgorithms,
DheNamedGroup, KeySchedule, LocalDeviceAlgorithms, MeasurementHashAlgo,
Expand Down Expand Up @@ -228,8 +229,12 @@ fn full_flow(stream: TcpStream, config: &RequesterConfig) -> IoResult<()> {
}

// Process SPDM messages using the context
let mut buffer = [0u8; 4096];
// let mut buffer = [0u8; capabilities.data_transfer_size];
let mut buffer = [0u8; 1024];
let mut message_buffer = MessageBuf::new(&mut buffer);

let mut large_buffer = [0u8; 8192];
let mut large_response_buffer = MessageBuf::new(&mut large_buffer);
// For now, we just want to show, that the VCA (Version, Capability, Auth) flow works as expected
// For that, we need to do the following:
// 1.1 Send GET_VERSION
Expand Down Expand Up @@ -279,6 +284,24 @@ fn full_flow(stream: TcpStream, config: &RequesterConfig) -> IoResult<()> {
.requester_send_request(&mut message_buffer, EID)
.unwrap();

// CAPABILITES is the first response that might require chunking!
match spdm_context.requester_process_message(&mut message_buffer) {
// For now ig we have to live with it like this.
// An alternative would be to poll our own context to check if the chunking
// was initialized and then proceed with the chunk retrieval and assembly.
Err(SpdmError::Command(CommandError::Chunk(ChunkError::None))) => {
message_buffer.reset();
spdm_context
.requester_retrieve_large_response(
&mut message_buffer,
EID,
&mut large_response_buffer,
)
.unwrap();
}
e => e.unwrap(),
};

if config.verbose {
println!(
"Sent GET_CAPABILITIES: {:?}",
Expand Down Expand Up @@ -499,6 +522,22 @@ fn full_flow(stream: TcpStream, config: &RequesterConfig) -> IoResult<()> {
println!("CHALLENGE_AUTH signature verification successfull");
}

// Used for GET_MEASUREMENTS.
// match spdm_context.requester_process_message(&mut message_buffer) {
// // For now ig we have to live with it like this.
// // An alternative would be to poll our own context to check if the chunking
// // was initialized and then proceed with the chunk retrieval and assembly.
// SpdmError::Command(CommandError::Chunk(ChunkError::None)) => {
// message_buffer.reset();
// spdm_context.requester_retrieve_large_response(
// &mut message_buffer,
// EID,
// &mut large_response_buffer,
// )?;
// }
// SpdmError(e) => e,
// };

Ok(())
}

Expand Down
99 changes: 98 additions & 1 deletion src/chunk_ctx.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@ use crate::commands::measurements_rsp::MeasurementsResponse;

#[derive(Debug, PartialEq)]
pub enum ChunkError {
/// Super hacky way to signal back the client application via [CommandError::Chunk(ChunkError::None)]
/// that the chunking process has started and that it now has to retrieve the chunked data.
None,
LargeResponseInitError,
NoLargeResponseInProgress,
InvalidChunkHandle,
Expand All @@ -34,6 +37,11 @@ struct ChunkInfo {
}

impl ChunkInfo {
/// Reset the chunk info.
///
/// # Arguments
/// - `reset_handle`: If `reset_handle` is set, the handle of the chunk info
/// is set to `0`. If not, it is incremented to be ready for the next chunk operation.
pub fn reset(&mut self, reset_handle: bool) {
self.chunk_in_use = false;
if reset_handle {
Expand Down Expand Up @@ -64,7 +72,18 @@ pub(crate) enum LargeResponse {
Measurements(MeasurementsResponse),
}

/// Manages the context for ongoing large message responses
/// Manages the context for ongoing large message responses.
/// The naming might be confusion, but we re-use this struct for both requester and responder.
///
/// # Requester
///
/// For the requester, this [LargeResponseCtx] is used to track the state
/// of `CHUNK_SEND` commands.
///
/// # Responder
///
/// For the responder, this [LargeResponseCtx] is used to track the state
/// of `CHUNK_RESPONSE` commands.
#[derive(Default)]
pub(crate) struct LargeResponseCtx {
chunk_info: ChunkInfo,
Expand Down Expand Up @@ -127,4 +146,82 @@ impl LargeResponseCtx {
pub fn bytes_transferred(&self) -> usize {
self.chunk_info.bytes_transferred
}

pub fn seq_no(&self) -> u16 {
self.chunk_info.chunk_seq_num
}

pub fn handle(&self) -> u8 {
self.chunk_info.chunk_handle
}
}

/// Manages the context for ongoing large message retrievals on the **requester** side.
///
/// Initialized when the requester receives `ERROR(LargeResponse)` and tracks
/// progress across successive `CHUNK_GET` / `CHUNK_RESPONSE` exchanges until
/// the last chunk has been received.
#[derive(Default)]
pub(crate) struct LargeRequestCtx {
chunk_info: ChunkInfo,
}

impl LargeRequestCtx {
/// Initialize context for a new large response retrieval.
///
/// Call this when `ERROR(LargeResponse)` is received.
///
/// # Arguments
/// * `handle` - The handle value carried in `Param2` of the `ERROR` message.
pub(crate) fn init(&mut self, handle: u8) {
// Total size is unknown until the first CHUNK_RESPONSE arrives.
self.chunk_info.init(0, Some(handle));
}

/// Discard any in-progress retrieval and reset to the initial state.
pub(crate) fn reset(&mut self) {
self.chunk_info.reset(true);
}

/// Returns `true` if a large response retrieval is currently in progress.
pub(crate) fn in_progress(&self) -> bool {
self.chunk_info.chunk_in_use
}

/// Returns the handle identifying the current large response transfer.
pub(crate) fn handle(&self) -> u8 {
self.chunk_info.chunk_handle
}

/// Returns the `ChunkSeqNo` that shall appear in the next `CHUNK_GET`.
pub(crate) fn current_seq_num(&self) -> u16 {
self.chunk_info.chunk_seq_num
}

/// Returns the number of bytes successfully received so far.
pub(crate) fn bytes_received(&self) -> usize {
self.chunk_info.bytes_transferred
}

/// Returns the total size of the large response.
///
/// Only meaningful after the first `CHUNK_RESPONSE` (`ChunkSeqNo == 0`)
/// has been processed and [`set_total_size`] has been called.
pub(crate) fn total_size(&self) -> usize {
self.chunk_info.large_msg_size
}

/// Record the total response size decoded from the first `CHUNK_RESPONSE`.
pub(crate) fn set_total_size(&mut self, size: usize) {
self.chunk_info.large_msg_size = size;
}

/// Advance tracking state after a chunk has been successfully received.
///
/// Adds `chunk_size` to `bytes_received` and bumps the sequence number so
/// that the next `CHUNK_GET` requests the following chunk.
pub(crate) fn advance(&mut self, chunk_size: usize) {
self.chunk_info.bytes_transferred += chunk_size;
self.chunk_info.chunk_seq_num = self.chunk_info.chunk_seq_num.wrapping_add(1);
}
}
2 changes: 1 addition & 1 deletion src/commands/algorithms/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
use crate::{
codec::{Codec, MessageBuf},
commands::algorithms::{AlgStructure, AlgorithmsResp, ExtendedAlgo, NegotiateAlgorithmsReq},
commands::error_rsp::ErrorCode,
commands::error::ErrorCode,
context::SpdmContext,
error::{CommandError, CommandResult},
protocol::{DeviceAlgorithms, SpdmMsgHdr},
Expand Down
2 changes: 1 addition & 1 deletion src/commands/algorithms/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ use crate::{
transcript::TranscriptContext,
};

use crate::commands::error_rsp::ErrorCode;
use crate::commands::error::ErrorCode;
use crate::protocol::*;

use core::mem::size_of;
Expand Down
2 changes: 1 addition & 1 deletion src/commands/capabilities/request.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
// See the License for the specific language governing permissions and
// limitations under the License.

use crate::commands::error_rsp::ErrorCode;
use crate::commands::error::ErrorCode;
use crate::protocol::CapabilityFlags;
use crate::{codec::MessageBuf, context::SpdmContext, error::CommandResult, protocol::SpdmMsgHdr};

Expand Down
2 changes: 1 addition & 1 deletion src/commands/capabilities/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
// limitations under the License.
use super::*;
use crate::codec::{Codec, MessageBuf};
use crate::commands::error_rsp::ErrorCode;
use crate::commands::error::ErrorCode;
use crate::context::SpdmContext;
use crate::error::{CommandError, CommandResult};
use crate::protocol::*;
Expand Down
2 changes: 1 addition & 1 deletion src/commands/certificate/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ use crate::commands::certificate::{
encode_certchain_metadata, CertificateRespAttributes, CertificateRespCommon, GetCertificateReq,
SlotId,
};
use crate::commands::error_rsp::ErrorCode;
use crate::commands::error::ErrorCode;
use crate::context::SpdmContext;
use crate::error::{CommandError, CommandResult};
use crate::protocol::*;
Expand Down
2 changes: 1 addition & 1 deletion src/commands/challenge/response.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ use crate::codec::{Codec, MessageBuf};
use crate::commands::algorithms::selected_measurement_specification;
use crate::commands::challenge::{ChallengeAuthRspBase, ChallengeReq, MeasurementSummaryHashType};
use crate::commands::digests::compute_cert_chain_hash;
use crate::commands::error_rsp::ErrorCode;
use crate::commands::error::ErrorCode;
use crate::context::SpdmContext;
use crate::error::{CommandError, CommandResult, PlatformError};
use crate::platform::hash::SpdmHashAlgoType;
Expand Down
Loading
Loading