Skip to content

Commit

Permalink
SPDM 1.3 Add Capability Support
Browse files Browse the repository at this point in the history
This Patch Adds:
1. Definitions of get_capacity_req and capacity_rep added in spdm
  1.3.
2. Capability Violation checks for newly added flags.
3. Unit test cases for capability 1.3 fields.
4. Error Response if responder does not support Large SPDM message
  transfer mechanism while Requester set bit0 of param1 in capability
  request message. (Spec requested).

Remains:
1. Config info of capability as 1.2 since relative 1.3 features not
  implemented.
2. Supported Algorithms extend capability bit (Param 1 Bit 0) as
  unimplemented. Will track this feature in another issue.
  • Loading branch information
IntelCaisui authored and jyao1 committed Dec 26, 2024
1 parent a4bbc69 commit 857fe55
Show file tree
Hide file tree
Showing 5 changed files with 314 additions and 32 deletions.
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 {
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;
}
}
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
&& flags.contains(SpdmRequestCapabilityFlags::EP_INFO_CAP_SIG)
{
return None;
}
}

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]
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! {
#[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

0 comments on commit 857fe55

Please sign in to comment.