Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SPDM 1.3 Add Capability Support #159

Merged
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
132 changes: 107 additions & 25 deletions spdmlib/src/message/capability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,19 @@ impl SpdmCodec for SpdmGetCapabilitiesRequestPayload {
context: &mut common::SpdmContext,
r: &mut Reader,
) -> Option<SpdmGetCapabilitiesRequestPayload> {
u8::read(r)?; // param1
if context.negotiate_info.spdm_version_sel >= SpdmVersion::SpdmVersion13 {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If the GET_CAPABILITIES request sets Bit 0 of Param1 to a value of 1 and the Responder
does not support the Large SPDM message transfer mechanism ( CHUNK_CAP=0 ), the Responder shall send an
ERROR message of ErrorCode=InvalidRequest .

let param1 = SpdmCapabilityParam1::read(r)?; // param1
if param1.contains(SpdmCapabilityParam1::SUPPORTED_ALGOS_EXT_CAP)
&& !context
.config_info
.rsp_capabilities
.contains(SpdmResponseCapabilityFlags::CHUNK_CAP)
{
return None;
}
} else {
u8::read(r)?; // param1
}
u8::read(r)?; // param2

let mut ct_exponent = 0;
Expand All @@ -75,13 +87,20 @@ impl SpdmCodec for SpdmGetCapabilitiesRequestPayload {
if !flags.contains(SpdmRequestCapabilityFlags::MAC_CAP) {
return None;
}
} else if flags.contains(SpdmRequestCapabilityFlags::MAC_CAP)
|| flags.contains(SpdmRequestCapabilityFlags::ENCRYPT_CAP)
|| flags.contains(SpdmRequestCapabilityFlags::HANDSHAKE_IN_THE_CLEAR_CAP)
|| flags.contains(SpdmRequestCapabilityFlags::HBEAT_CAP)
|| flags.contains(SpdmRequestCapabilityFlags::KEY_UPD_CAP)
{
return None;
} else {
if flags.contains(SpdmRequestCapabilityFlags::MAC_CAP)
|| flags.contains(SpdmRequestCapabilityFlags::ENCRYPT_CAP)
|| flags.contains(SpdmRequestCapabilityFlags::HANDSHAKE_IN_THE_CLEAR_CAP)
|| flags.contains(SpdmRequestCapabilityFlags::HBEAT_CAP)
|| flags.contains(SpdmRequestCapabilityFlags::KEY_UPD_CAP)
{
return None;
}
if context.negotiate_info.spdm_version_sel >= SpdmVersion::SpdmVersion13
&& flags.contains(SpdmRequestCapabilityFlags::EVENT_CAP)
{
return None;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Align with libspdm implementation.
Cannot support event without key exchange capabilities.

}
}
if !flags.contains(SpdmRequestCapabilityFlags::KEY_EX_CAP)
&& flags.contains(SpdmRequestCapabilityFlags::PSK_CAP)
Expand All @@ -102,10 +121,17 @@ impl SpdmCodec for SpdmGetCapabilitiesRequestPayload {
{
return None;
}
} else if flags.contains(SpdmRequestCapabilityFlags::CHAL_CAP)
|| flags.contains(SpdmRequestCapabilityFlags::MUT_AUTH_CAP)
{
return None;
} else {
if flags.contains(SpdmRequestCapabilityFlags::CHAL_CAP)
|| flags.contains(SpdmRequestCapabilityFlags::MUT_AUTH_CAP)
{
return None;
}
if context.negotiate_info.spdm_version_sel >= SpdmVersion::SpdmVersion13
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Capabilities Flags checks are aligned with spdm spec 1.3 and libspdm implementation.

&& flags.contains(SpdmRequestCapabilityFlags::EP_INFO_CAP_SIG)
{
return None;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Align with libspdm implementation.
Cannot support ep info signature without certificate or public key capabilities.

}
}

if context.negotiate_info.spdm_version_sel == SpdmVersion::SpdmVersion11
Expand All @@ -114,6 +140,25 @@ impl SpdmCodec for SpdmGetCapabilitiesRequestPayload {
{
return None;
}

if context.negotiate_info.spdm_version_sel >= SpdmVersion::SpdmVersion13 {
if flags.contains(SpdmRequestCapabilityFlags::EP_INFO_CAP_NO_SIG)
&& flags.contains(SpdmRequestCapabilityFlags::EP_INFO_CAP_SIG)
{
return None;
}
if flags.contains(SpdmRequestCapabilityFlags::MULTI_KEY_CAP_ONLY)
&& flags.contains(SpdmRequestCapabilityFlags::MULTI_KEY_CAP_CONN_SEL)
{
return None;
}
if flags.contains(SpdmRequestCapabilityFlags::PUB_KEY_ID_CAP)
&& (flags.contains(SpdmRequestCapabilityFlags::MULTI_KEY_CAP_ONLY)
|| flags.contains(SpdmRequestCapabilityFlags::MULTI_KEY_CAP_CONN_SEL))
{
return None;
}
}
}

let mut data_transfer_size = 0;
Expand Down Expand Up @@ -228,13 +273,20 @@ impl SpdmCodec for SpdmCapabilitiesResponsePayload {
if !flags.contains(SpdmResponseCapabilityFlags::MAC_CAP) {
return None;
}
} else if flags.contains(SpdmResponseCapabilityFlags::MAC_CAP)
|| flags.contains(SpdmResponseCapabilityFlags::ENCRYPT_CAP)
|| flags.contains(SpdmResponseCapabilityFlags::HANDSHAKE_IN_THE_CLEAR_CAP)
|| flags.contains(SpdmResponseCapabilityFlags::HBEAT_CAP)
|| flags.contains(SpdmResponseCapabilityFlags::KEY_UPD_CAP)
{
return None;
} else {
if flags.contains(SpdmResponseCapabilityFlags::MAC_CAP)
|| flags.contains(SpdmResponseCapabilityFlags::ENCRYPT_CAP)
|| flags.contains(SpdmResponseCapabilityFlags::HANDSHAKE_IN_THE_CLEAR_CAP)
|| flags.contains(SpdmResponseCapabilityFlags::HBEAT_CAP)
|| flags.contains(SpdmResponseCapabilityFlags::KEY_UPD_CAP)
{
return None;
}
if context.negotiate_info.spdm_version_sel >= SpdmVersion::SpdmVersion13
&& flags.contains(SpdmResponseCapabilityFlags::EVENT_CAP)
{
return None;
}
}
if !flags.contains(SpdmResponseCapabilityFlags::KEY_EX_CAP)
&& (flags.contains(SpdmResponseCapabilityFlags::PSK_CAP_WITHOUT_CONTEXT)
Expand All @@ -257,12 +309,19 @@ impl SpdmCodec for SpdmCapabilitiesResponsePayload {
{
return None;
}
} else if flags.contains(SpdmResponseCapabilityFlags::CHAL_CAP)
|| flags.contains(SpdmResponseCapabilityFlags::KEY_EX_CAP)
|| flags.contains(SpdmResponseCapabilityFlags::MEAS_CAP_SIG)
|| flags.contains(SpdmResponseCapabilityFlags::MUT_AUTH_CAP)
{
return None;
} else {
if flags.contains(SpdmResponseCapabilityFlags::CHAL_CAP)
|| flags.contains(SpdmResponseCapabilityFlags::KEY_EX_CAP)
|| flags.contains(SpdmResponseCapabilityFlags::MEAS_CAP_SIG)
|| flags.contains(SpdmResponseCapabilityFlags::MUT_AUTH_CAP)
{
return None;
}
if context.negotiate_info.spdm_version_sel >= SpdmVersion::SpdmVersion13
&& flags.contains(SpdmResponseCapabilityFlags::EP_INFO_CAP_SIG)
{
return None;
}
}
}
if context.negotiate_info.spdm_version_sel == SpdmVersion::SpdmVersion11
Expand Down Expand Up @@ -291,6 +350,29 @@ impl SpdmCodec for SpdmCapabilitiesResponsePayload {
}
}

if context.negotiate_info.spdm_version_sel >= SpdmVersion::SpdmVersion13 {
if flags.contains(SpdmResponseCapabilityFlags::EP_INFO_CAP_NO_SIG)
&& flags.contains(SpdmResponseCapabilityFlags::EP_INFO_CAP_SIG)
{
return None;
}
if flags.contains(SpdmResponseCapabilityFlags::MULTI_KEY_CAP_ONLY)
&& flags.contains(SpdmResponseCapabilityFlags::MULTI_KEY_CAP_CONN_SEL)
{
return None;
}
if flags.contains(SpdmResponseCapabilityFlags::MULTI_KEY_CAP_ONLY)
|| flags.contains(SpdmResponseCapabilityFlags::MULTI_KEY_CAP_CONN_SEL)
{
if flags.contains(SpdmResponseCapabilityFlags::PUB_KEY_ID_CAP) {
return None;
}
if !flags.contains(SpdmResponseCapabilityFlags::GET_KEY_PAIR_INFO_CAP) {
return None;
}
}
}

if context.negotiate_info.spdm_version_sel >= SpdmVersion::SpdmVersion12 {
let data_transfer_size = u32::read(r)?;
let max_spdm_msg_size = u32::read(r)?;
Expand Down
132 changes: 132 additions & 0 deletions spdmlib/src/message/capability_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,3 +43,135 @@ fn test_capability_struct() {
let res = SpdmCapabilitiesResponsePayload::spdm_read(&mut context, &mut reader);
assert!(res.is_none());
}

#[test]
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

spdm 1.3 capacity test cases.

fn test_capability_request_struct() {
// 0. Version 1.3 Successful Setting.
let u8_slice = &mut [0u8; 100];
create_spdm_context!(context);
context.negotiate_info.spdm_version_sel = SpdmVersion::SpdmVersion13;

let flags = SpdmRequestCapabilityFlags::CERT_CAP
| SpdmRequestCapabilityFlags::ENCRYPT_CAP
| SpdmRequestCapabilityFlags::MAC_CAP
| SpdmRequestCapabilityFlags::KEY_EX_CAP
| SpdmRequestCapabilityFlags::ENCAP_CAP
| SpdmRequestCapabilityFlags::HBEAT_CAP
| SpdmRequestCapabilityFlags::KEY_UPD_CAP
| SpdmRequestCapabilityFlags::MUT_AUTH_CAP
| SpdmRequestCapabilityFlags::EP_INFO_CAP_NO_SIG
| SpdmRequestCapabilityFlags::EVENT_CAP
| SpdmRequestCapabilityFlags::MULTI_KEY_CAP_ONLY;
LittleEndian::write_u32(&mut u8_slice[8..12], flags.bits());
LittleEndian::write_u32(&mut u8_slice[12..16], 4096);
LittleEndian::write_u32(&mut u8_slice[16..20], 4096);

let mut reader = Reader::init(&u8_slice[2..]);
let res = SpdmGetCapabilitiesRequestPayload::spdm_read(&mut context, &mut reader);
assert!(res.is_some());
let res = res.unwrap();
assert!(res.ct_exponent == 0);
assert!(res.flags.bits() == flags.bits());
assert!(res.data_transfer_size == 4096);
assert!(res.max_spdm_msg_size == 4096);

// 1. Validate SUPPORTED_ALGOS_EXT_CAP bit is set and CHUNK_CAP not supported. Expectation failed.
let u8_slice = &mut [0u8; 100];
create_spdm_context!(context);
context.negotiate_info.spdm_version_sel = SpdmVersion::SpdmVersion13;

u8_slice[2] = 1; // Set SUPPORTED_ALGOS_EXT_CAP bit in param1.
let flags = SpdmRequestCapabilityFlags::CERT_CAP | SpdmRequestCapabilityFlags::CHAL_CAP;
LittleEndian::write_u32(&mut u8_slice[8..12], flags.bits());
LittleEndian::write_u32(&mut u8_slice[12..16], 4096);
LittleEndian::write_u32(&mut u8_slice[16..20], 4096);

let mut reader = Reader::init(&u8_slice[2..]);
let res = SpdmGetCapabilitiesRequestPayload::spdm_read(&mut context, &mut reader);
assert!(res.is_none());

// 2. Validate sample illegal capability flags settings. Expectation failed.
let u8_slice = &mut [0u8; 100];
create_spdm_context!(context);
context.negotiate_info.spdm_version_sel = SpdmVersion::SpdmVersion13;

let flags = SpdmRequestCapabilityFlags::EP_INFO_CAP_SIG
| SpdmRequestCapabilityFlags::EP_INFO_CAP_NO_SIG;
LittleEndian::write_u32(&mut u8_slice[8..12], flags.bits());
LittleEndian::write_u32(&mut u8_slice[12..16], 4096);
LittleEndian::write_u32(&mut u8_slice[16..20], 4096);

let mut reader = Reader::init(&u8_slice[2..]);
let res = SpdmGetCapabilitiesRequestPayload::spdm_read(&mut context, &mut reader);
assert!(res.is_none());

let flags =
SpdmRequestCapabilityFlags::MULTI_KEY_CAP_ONLY | SpdmRequestCapabilityFlags::PUB_KEY_ID_CAP;
LittleEndian::write_u32(&mut u8_slice[8..12], flags.bits());

let mut reader = Reader::init(&u8_slice[2..]);
let res = SpdmGetCapabilitiesRequestPayload::spdm_read(&mut context, &mut reader);
assert!(res.is_none());
}

#[test]
fn test_capability_response_struct() {
// 0. Version 1.3 Successful Setting.
let u8_slice = &mut [0u8; 100];
create_spdm_context!(context);
context.negotiate_info.spdm_version_sel = SpdmVersion::SpdmVersion13;

let flags = SpdmResponseCapabilityFlags::CERT_CAP
| SpdmResponseCapabilityFlags::CHAL_CAP
| SpdmResponseCapabilityFlags::MEAS_CAP_SIG
| SpdmResponseCapabilityFlags::MEAS_FRESH_CAP
| SpdmResponseCapabilityFlags::ENCRYPT_CAP
| SpdmResponseCapabilityFlags::MAC_CAP
| SpdmResponseCapabilityFlags::KEY_EX_CAP
| SpdmResponseCapabilityFlags::PSK_CAP_WITH_CONTEXT
| SpdmResponseCapabilityFlags::ENCAP_CAP
| SpdmResponseCapabilityFlags::HBEAT_CAP
| SpdmResponseCapabilityFlags::KEY_UPD_CAP
| SpdmResponseCapabilityFlags::MUT_AUTH_CAP
| SpdmResponseCapabilityFlags::EP_INFO_CAP_NO_SIG
| SpdmResponseCapabilityFlags::MEL_CAP
| SpdmResponseCapabilityFlags::EVENT_CAP
| SpdmResponseCapabilityFlags::MULTI_KEY_CAP_ONLY
| SpdmResponseCapabilityFlags::GET_KEY_PAIR_INFO_CAP
| SpdmResponseCapabilityFlags::SET_KEY_PAIR_INFO_CAP;
LittleEndian::write_u32(&mut u8_slice[8..12], flags.bits());
LittleEndian::write_u32(&mut u8_slice[12..16], 4096);
LittleEndian::write_u32(&mut u8_slice[16..20], 4096);

let mut reader = Reader::init(&u8_slice[2..]);
let res = SpdmCapabilitiesResponsePayload::spdm_read(&mut context, &mut reader);
assert!(res.is_some());
let res = res.unwrap();
assert!(res.ct_exponent == 0);
assert!(res.flags.bits() == flags.bits());
assert!(res.data_transfer_size == 4096);
assert!(res.max_spdm_msg_size == 4096);

// 1. Validate sample illegal capability flags settings. Expectation failed.
let u8_slice = &mut [0u8; 100];
create_spdm_context!(context);
context.negotiate_info.spdm_version_sel = SpdmVersion::SpdmVersion13;

let flags = SpdmResponseCapabilityFlags::MULTI_KEY_CAP_ONLY
| SpdmResponseCapabilityFlags::MULTI_KEY_CAP_CONN_SEL
| SpdmResponseCapabilityFlags::GET_KEY_PAIR_INFO_CAP;
LittleEndian::write_u32(&mut u8_slice[8..12], flags.bits());
LittleEndian::write_u32(&mut u8_slice[12..16], 4096);
LittleEndian::write_u32(&mut u8_slice[16..20], 4096);

let mut reader = Reader::init(&u8_slice[2..]);
let res = SpdmCapabilitiesResponsePayload::spdm_read(&mut context, &mut reader);
assert!(res.is_none());

let flags = SpdmResponseCapabilityFlags::MULTI_KEY_CAP_ONLY;
LittleEndian::write_u32(&mut u8_slice[8..12], flags.bits());

let mut reader = Reader::init(&u8_slice[2..]);
let res = SpdmCapabilitiesResponsePayload::spdm_read(&mut context, &mut reader);
assert!(res.is_none());
}
50 changes: 48 additions & 2 deletions spdmlib/src/protocol/capability.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ bitflags! {
const HANDSHAKE_IN_THE_CLEAR_CAP = 0b1000_0000_0000_0000;
const PUB_KEY_ID_CAP = 0b0000_0001_0000_0000_0000_0000;
const CHUNK_CAP = 0b0000_0010_0000_0000_0000_0000;
const EP_INFO_CAP_NO_SIG = 0b0100_0000_0000_0000_0000_0000;
const EP_INFO_CAP_SIG = 0b1000_0000_0000_0000_0000_0000;
const EVENT_CAP = 0b0000_0010_0000_0000_0000_0000_0000_0000;
const MULTI_KEY_CAP_ONLY = 0b0000_0100_0000_0000_0000_0000_0000_0000;
const MULTI_KEY_CAP_CONN_SEL = 0b0000_1000_0000_0000_0000_0000_0000_0000;
const VALID_MASK = Self::CERT_CAP.bits
| Self::CHAL_CAP.bits
| Self::ENCRYPT_CAP.bits
Expand All @@ -34,7 +39,12 @@ bitflags! {
| Self::KEY_UPD_CAP.bits
| Self::HANDSHAKE_IN_THE_CLEAR_CAP.bits
| Self::PUB_KEY_ID_CAP.bits
| Self::CHUNK_CAP.bits;
| Self::CHUNK_CAP.bits
| Self::EP_INFO_CAP_NO_SIG.bits
| Self::EP_INFO_CAP_SIG.bits
| Self::EVENT_CAP.bits
| Self::MULTI_KEY_CAP_ONLY.bits
| Self::MULTI_KEY_CAP_CONN_SEL.bits;
}
}

Expand Down Expand Up @@ -75,6 +85,14 @@ bitflags! {
const SET_CERT_CAP = 0b0000_1000_0000_0000_0000_0000;
const CSR_CAP = 0b0001_0000_0000_0000_0000_0000;
const CERT_INSTALL_RESET_CAP = 0b0010_0000_0000_0000_0000_0000;
const EP_INFO_CAP_NO_SIG = 0b0100_0000_0000_0000_0000_0000;
const EP_INFO_CAP_SIG = 0b1000_0000_0000_0000_0000_0000;
const MEL_CAP = 0b0000_0001_0000_0000_0000_0000_0000_0000;
const EVENT_CAP = 0b0000_0010_0000_0000_0000_0000_0000_0000;
const MULTI_KEY_CAP_ONLY = 0b0000_0100_0000_0000_0000_0000_0000_0000;
const MULTI_KEY_CAP_CONN_SEL = 0b0000_1000_0000_0000_0000_0000_0000_0000;
const GET_KEY_PAIR_INFO_CAP = 0b0001_0000_0000_0000_0000_0000_0000_0000;
const SET_KEY_PAIR_INFO_CAP = 0b0010_0000_0000_0000_0000_0000_0000_0000;
const VALID_MASK = Self::CACHE_CAP.bits
| Self::CERT_CAP.bits
| Self::CHAL_CAP.bits
Expand All @@ -96,7 +114,15 @@ bitflags! {
| Self::ALIAS_CERT_CAP.bits
| Self::SET_CERT_CAP.bits
| Self::CSR_CAP.bits
| Self::CERT_INSTALL_RESET_CAP.bits;
| Self::CERT_INSTALL_RESET_CAP.bits
| Self::EP_INFO_CAP_NO_SIG.bits
| Self::EP_INFO_CAP_SIG.bits
| Self::MEL_CAP.bits
| Self::EVENT_CAP.bits
| Self::MULTI_KEY_CAP_ONLY.bits
| Self::MULTI_KEY_CAP_CONN_SEL.bits
| Self::GET_KEY_PAIR_INFO_CAP.bits
| Self::SET_KEY_PAIR_INFO_CAP.bits;
}
}

Expand All @@ -111,3 +137,23 @@ impl Codec for SpdmResponseCapabilityFlags {
SpdmResponseCapabilityFlags::from_bits(bits & SpdmResponseCapabilityFlags::VALID_MASK.bits)
}
}

bitflags! {
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Get_capacity_req/ capacity_rsp param1 definition structure.

#[derive(Default)]
pub struct SpdmCapabilityParam1: u8 {
const SUPPORTED_ALGOS_EXT_CAP = 0b0000_0001;
const VALID_MASK = Self::SUPPORTED_ALGOS_EXT_CAP.bits;
}
}

impl Codec for SpdmCapabilityParam1 {
fn encode(&self, bytes: &mut Writer) -> Result<usize, codec::EncodeErr> {
self.bits().encode(bytes)
}

fn read(r: &mut Reader) -> Option<SpdmCapabilityParam1> {
let bits = u8::read(r)?;

SpdmCapabilityParam1::from_bits(bits & SpdmCapabilityParam1::VALID_MASK.bits)
}
}
Loading
Loading