Skip to content
Merged
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
21 changes: 16 additions & 5 deletions src/migtd/src/spdm/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,8 +401,7 @@ impl From<SpdmStatus> for MigrationResult {
if spdm_status.severity == StatusSeverity::SUCCESS {
MigrationResult::Success
} else if let StatusCode::VDM(vdm_error) = &spdm_status.status_code {
MigrationResult::try_from(vdm_error.vdm_error_code as u8)
.unwrap_or(MigrationResult::SecureSessionError)
decode_error_path_status(vdm_error.vdm_error_code as u8)
} else {
MigrationResult::SecureSessionError
}
Expand All @@ -429,6 +428,20 @@ impl From<MigrationResult> for SpdmStatus {
}
}

/// Decode a raw application status code that arrived on a path that is only
/// ever taken for SPDM *errors* (a `StatusCode::VDM` error status, or the
/// vendor-defined Param2 of an SPDM ERROR message). The wire encoding reuses
/// `MigrationResult::Success` (discriminant 0) as an ordinary enum value, so
/// a bare `TryFrom<u8>` decode could otherwise turn a peer-reported error
/// into a false `Success`. Reject that case (and any undecodable value) so
/// an error path can never produce `Success`.
fn decode_error_path_status(value: u8) -> MigrationResult {
match MigrationResult::try_from(value) {
Ok(MigrationResult::Success) | Err(()) => MigrationResult::SecureSessionError,
Ok(result) => result,
}
}

/// Decode an SpdmStatus returned by an SPDM session body into a
/// MigrationResult, preserving application-level errors carried over the wire
/// as `SpdmErrorVendorDefined`.
Expand All @@ -448,9 +461,7 @@ pub(crate) fn decode_spdm_session_err(e: SpdmStatus) -> MigrationResult {
if ed.length >= 4
&& ed.data[2] == spdmlib::message::SpdmErrorCode::SpdmErrorVendorDefined.get_u8()
{
if let Ok(decoded) = MigrationResult::try_from(ed.data[3]) {
return decoded;
}
return decode_error_path_status(ed.data[3]);
}
}
MigrationResult::SecureSessionError
Expand Down
51 changes: 51 additions & 0 deletions src/migtd/src/spdm/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -61,3 +61,54 @@ fn responder_teardown_clears_handshaking_and_established_sessions() {
let (mut responder, _) = spdm_responder(TestTransport).unwrap();
assert_teardown_clears_sessions(&mut responder.responder_context.common);
}

#[test]
fn decode_error_path_status_never_returns_success() {
// App-code 0 collides with `MigrationResult::Success`'s discriminant.
// On an error path this must be treated as an undecodable/invalid code,
// not as a successful result.
assert_eq!(
decode_error_path_status(0),
MigrationResult::SecureSessionError
);
// A genuine, non-zero error code still decodes to its real variant.
assert_eq!(
decode_error_path_status(MigrationResult::InvalidParameter as u8),
MigrationResult::InvalidParameter
);
// An undecodable value falls back to a generic session error rather
// than panicking or silently becoming Success.
assert_eq!(
decode_error_path_status(0xAA),
MigrationResult::SecureSessionError
);
}

#[test]
fn from_spdm_status_vdm_error_never_decodes_to_success() {
let status = SpdmStatus {
severity: StatusSeverity::ERROR,
status_code: StatusCode::VDM(StatusCodeVdmError { vdm_error_code: 0 }),
error_data: None,
};
assert_eq!(
MigrationResult::from(status),
MigrationResult::SecureSessionError
);
}

#[test]
fn decode_spdm_session_err_vendor_defined_zero_app_code_never_decodes_to_success() {
let mut data = [0u8; spdmlib::error::SPDM_ERROR_MESSAGE_DATA_MAX_LENGTH];
data[2] = spdmlib::message::SpdmErrorCode::SpdmErrorVendorDefined.get_u8();
data[3] = MigrationResult::Success as u8;
let status = SpdmStatus {
severity: StatusSeverity::ERROR,
status_code: StatusCode::VDM(StatusCodeVdmError { vdm_error_code: 0 }),
error_data: Some(spdmlib::error::SpdmErrorMessageData { length: 4, data }),
};
assert_eq!(
decode_spdm_session_err(status),
MigrationResult::SecureSessionError
);
}
Loading