From ad2c641a151324c2b17213e618fb60484038525c Mon Sep 17 00:00:00 2001 From: "Yang, Longlong" Date: Mon, 9 Oct 2023 20:22:35 -0400 Subject: [PATCH] introduce IDE_KM. fix #19 Signed-off-by: Yang, Longlong --- Cargo.lock | 12 + Cargo.toml | 1 + idekm/Cargo.toml | 23 + idekm/src/lib.rs | 10 + idekm/src/pci_ide_km_requester/mod.rs | 18 + .../pci_ide_km_req_key_prog.rs | 86 +++ .../pci_ide_km_req_key_set_go.rs | 80 ++ .../pci_ide_km_req_key_set_stop.rs | 80 ++ .../pci_ide_km_req_query.rs | 76 ++ idekm/src/pci_ide_km_responder/mod.rs | 17 + .../pci_ide_km_rsp_dispatcher.rs | 43 ++ .../pci_ide_km_rsp_key_prog.rs | 123 ++++ .../pci_ide_km_rsp_key_set_go.rs | 109 +++ .../pci_ide_km_rsp_key_set_stop.rs | 110 +++ .../pci_ide_km_rsp_query.rs | 129 ++++ idekm/src/pci_idekm.rs | 567 ++++++++++++++ test/spdm-requester-emu/Cargo.toml | 1 + test/spdm-requester-emu/src/main.rs | 695 +++++++++++++++++- test/spdm-responder-emu/Cargo.toml | 1 + test/spdm-responder-emu/src/main.rs | 6 + .../src/spdm_device_example.rs | 89 +++ 21 files changed, 2275 insertions(+), 1 deletion(-) create mode 100644 idekm/Cargo.toml create mode 100644 idekm/src/lib.rs create mode 100644 idekm/src/pci_ide_km_requester/mod.rs create mode 100644 idekm/src/pci_ide_km_requester/pci_ide_km_req_key_prog.rs create mode 100644 idekm/src/pci_ide_km_requester/pci_ide_km_req_key_set_go.rs create mode 100644 idekm/src/pci_ide_km_requester/pci_ide_km_req_key_set_stop.rs create mode 100644 idekm/src/pci_ide_km_requester/pci_ide_km_req_query.rs create mode 100644 idekm/src/pci_ide_km_responder/mod.rs create mode 100644 idekm/src/pci_ide_km_responder/pci_ide_km_rsp_dispatcher.rs create mode 100644 idekm/src/pci_ide_km_responder/pci_ide_km_rsp_key_prog.rs create mode 100644 idekm/src/pci_ide_km_responder/pci_ide_km_rsp_key_set_go.rs create mode 100644 idekm/src/pci_ide_km_responder/pci_ide_km_rsp_key_set_stop.rs create mode 100644 idekm/src/pci_ide_km_responder/pci_ide_km_rsp_query.rs create mode 100644 idekm/src/pci_idekm.rs create mode 100644 test/spdm-responder-emu/src/spdm_device_example.rs diff --git a/Cargo.lock b/Cargo.lock index b2049a7a..fb11a2f0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -905,6 +905,16 @@ dependencies = [ "cc", ] +[[package]] +name = "idekm" +version = "0.1.0" +dependencies = [ + "codec", + "conquer-once", + "spdmlib", + "zeroize", +] + [[package]] name = "is-terminal" version = "0.4.9" @@ -1626,6 +1636,7 @@ version = "0.1.0" dependencies = [ "codec", "futures", + "idekm", "log", "mctp_transport", "pcidoe_transport", @@ -1642,6 +1653,7 @@ version = "0.1.0" dependencies = [ "codec", "futures", + "idekm", "log", "mctp_transport", "pcidoe_transport", diff --git a/Cargo.toml b/Cargo.toml index 93a2160c..c6a670a3 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -14,6 +14,7 @@ members = [ "codec", "executor", "sys_time", + "idekm", "test/spdm-requester-emu", "test/spdm-responder-emu", "test/spdmlib-test", diff --git a/idekm/Cargo.toml b/idekm/Cargo.toml new file mode 100644 index 00000000..463e2cd4 --- /dev/null +++ b/idekm/Cargo.toml @@ -0,0 +1,23 @@ +[package] +name = "idekm" +license = "BSD-2-Clause-Patent" +version = "0.1.0" +authors = [ + "Jiewen Yao ", + "Xiaoyu Lu ", + "Longlong Yang " + ] +edition = "2018" + +[dev-dependencies] + +[build-dependencies] + +[dependencies] +codec = { path = "../codec" } +zeroize = { version = "1.5.0", features = ["zeroize_derive"]} +spdmlib = { path = "../spdmlib", default-features = false, features = ["spdm-ring"]} +conquer-once = { version = "0.3.2", default-features = false } + + +[features] diff --git a/idekm/src/lib.rs b/idekm/src/lib.rs new file mode 100644 index 00000000..a338d760 --- /dev/null +++ b/idekm/src/lib.rs @@ -0,0 +1,10 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +#![forbid(unsafe_code)] +#![cfg_attr(not(feature = "std"), no_std)] + +pub mod pci_ide_km_requester; +pub mod pci_ide_km_responder; +pub mod pci_idekm; diff --git a/idekm/src/pci_ide_km_requester/mod.rs b/idekm/src/pci_ide_km_requester/mod.rs new file mode 100644 index 00000000..9b86bf8c --- /dev/null +++ b/idekm/src/pci_ide_km_requester/mod.rs @@ -0,0 +1,18 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +#[derive(Debug, Default, Copy, Clone)] +pub struct IdekmReqContext; + +pub mod pci_ide_km_req_query; +pub use pci_ide_km_req_query::*; + +pub mod pci_ide_km_req_key_prog; +pub use pci_ide_km_req_key_prog::*; + +pub mod pci_ide_km_req_key_set_go; +pub use pci_ide_km_req_key_set_go::*; + +pub mod pci_ide_km_req_key_set_stop; +pub use pci_ide_km_req_key_set_stop::*; diff --git a/idekm/src/pci_ide_km_requester/pci_ide_km_req_key_prog.rs b/idekm/src/pci_ide_km_requester/pci_ide_km_req_key_prog.rs new file mode 100644 index 00000000..03ede616 --- /dev/null +++ b/idekm/src/pci_ide_km_requester/pci_ide_km_req_key_prog.rs @@ -0,0 +1,86 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use codec::Codec; +use codec::Writer; +use spdmlib::error::SpdmResult; +use spdmlib::error::SPDM_STATUS_BUFFER_FULL; +use spdmlib::error::SPDM_STATUS_INVALID_MSG_FIELD; +use spdmlib::{ + message::{VendorDefinedReqPayloadStruct, MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE}, + requester::RequesterContext, +}; + +use crate::pci_idekm::vendor_id; +use crate::pci_idekm::KpAckDataObject; +use crate::pci_idekm::STANDARD_ID; +use crate::pci_idekm::{Aes256GcmKeyBuffer, KeyProgDataObject, KpAckStatus}; + +use super::IdekmReqContext; + +impl IdekmReqContext { + #[allow(clippy::too_many_arguments)] + pub async fn pci_ide_km_key_prog( + &mut self, + // IN + spdm_requester: &mut RequesterContext, + session_id: u32, + stream_id: u8, + key_set: u8, + key_direction: u8, + key_sub_stream: u8, + port_index: u8, + key_iv: Aes256GcmKeyBuffer, + // OUT + kp_ack_status: &mut KpAckStatus, + ) -> SpdmResult { + let mut vendor_defined_req_payload_struct = VendorDefinedReqPayloadStruct { + req_length: 0, + vendor_defined_req_payload: [0u8; MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE], + }; + + let mut writer = + Writer::init(&mut vendor_defined_req_payload_struct.vendor_defined_req_payload); + + vendor_defined_req_payload_struct.req_length = KeyProgDataObject { + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + key_iv, + } + .encode(&mut writer) + .map_err(|_| SPDM_STATUS_BUFFER_FULL)? + as u16; + + let vendor_defined_rsp_payload_struct = spdm_requester + .send_spdm_vendor_defined_request( + Some(session_id), + STANDARD_ID, + vendor_id(), + vendor_defined_req_payload_struct, + ) + .await?; + + let kp_ack_data_object = KpAckDataObject::read_bytes( + &vendor_defined_rsp_payload_struct.vendor_defined_rsp_payload + [..vendor_defined_rsp_payload_struct.rsp_length as usize], + ) + .ok_or(SPDM_STATUS_INVALID_MSG_FIELD)?; + + if kp_ack_data_object.stream_id != stream_id + || kp_ack_data_object.key_set != key_set + || kp_ack_data_object.key_direction != key_direction + || kp_ack_data_object.key_sub_stream != key_sub_stream + || kp_ack_data_object.port_index != port_index + { + return Err(SPDM_STATUS_INVALID_MSG_FIELD); + } else { + *kp_ack_status = kp_ack_data_object.status; + } + + Ok(()) + } +} diff --git a/idekm/src/pci_ide_km_requester/pci_ide_km_req_key_set_go.rs b/idekm/src/pci_ide_km_requester/pci_ide_km_req_key_set_go.rs new file mode 100644 index 00000000..579d6f40 --- /dev/null +++ b/idekm/src/pci_ide_km_requester/pci_ide_km_req_key_set_go.rs @@ -0,0 +1,80 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use codec::Codec; +use codec::Writer; +use spdmlib::error::SPDM_STATUS_BUFFER_FULL; +use spdmlib::error::SPDM_STATUS_INVALID_MSG_FIELD; +use spdmlib::{ + error::SpdmResult, + message::{VendorDefinedReqPayloadStruct, MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE}, + requester::RequesterContext, +}; + +use crate::pci_idekm::vendor_id; +use crate::pci_idekm::KGoStopAckDataObject; +use crate::pci_idekm::KSetGoDataObject; +use crate::pci_idekm::STANDARD_ID; + +use super::IdekmReqContext; + +impl IdekmReqContext { + #[allow(clippy::too_many_arguments)] + pub async fn pci_ide_km_key_set_go( + &mut self, + // IN + spdm_requester: &mut RequesterContext, + session_id: u32, + stream_id: u8, + key_set: u8, + key_direction: u8, + key_sub_stream: u8, + port_index: u8, + ) -> SpdmResult { + let mut vendor_defined_req_payload_struct = VendorDefinedReqPayloadStruct { + req_length: 0, + vendor_defined_req_payload: [0u8; MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE], + }; + + let mut writer = + Writer::init(&mut vendor_defined_req_payload_struct.vendor_defined_req_payload); + + vendor_defined_req_payload_struct.req_length = KSetGoDataObject { + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + } + .encode(&mut writer) + .map_err(|_| SPDM_STATUS_BUFFER_FULL)? + as u16; + + let vendor_defined_rsp_payload_struct = spdm_requester + .send_spdm_vendor_defined_request( + Some(session_id), + STANDARD_ID, + vendor_id(), + vendor_defined_req_payload_struct, + ) + .await?; + + let kgo_stop_ack_data_object = KGoStopAckDataObject::read_bytes( + &vendor_defined_rsp_payload_struct.vendor_defined_rsp_payload + [..vendor_defined_rsp_payload_struct.rsp_length as usize], + ) + .ok_or(SPDM_STATUS_INVALID_MSG_FIELD)?; + + if kgo_stop_ack_data_object.stream_id != stream_id + || kgo_stop_ack_data_object.key_set != key_set + || kgo_stop_ack_data_object.key_direction != key_direction + || kgo_stop_ack_data_object.key_sub_stream != key_sub_stream + || kgo_stop_ack_data_object.port_index != port_index + { + Err(SPDM_STATUS_INVALID_MSG_FIELD) + } else { + Ok(()) + } + } +} diff --git a/idekm/src/pci_ide_km_requester/pci_ide_km_req_key_set_stop.rs b/idekm/src/pci_ide_km_requester/pci_ide_km_req_key_set_stop.rs new file mode 100644 index 00000000..23a92ce8 --- /dev/null +++ b/idekm/src/pci_ide_km_requester/pci_ide_km_req_key_set_stop.rs @@ -0,0 +1,80 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use codec::Codec; +use codec::Writer; +use spdmlib::error::SPDM_STATUS_BUFFER_FULL; +use spdmlib::error::SPDM_STATUS_INVALID_MSG_FIELD; +use spdmlib::{ + error::SpdmResult, + message::{VendorDefinedReqPayloadStruct, MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE}, + requester::RequesterContext, +}; + +use crate::pci_idekm::vendor_id; +use crate::pci_idekm::KGoStopAckDataObject; +use crate::pci_idekm::KSetStopDataObject; +use crate::pci_idekm::STANDARD_ID; + +use super::IdekmReqContext; + +impl IdekmReqContext { + #[allow(clippy::too_many_arguments)] + pub async fn pci_ide_km_key_set_stop( + &mut self, + // IN + spdm_requester: &mut RequesterContext, + session_id: u32, + stream_id: u8, + key_set: u8, + key_direction: u8, + key_sub_stream: u8, + port_index: u8, + ) -> SpdmResult { + let mut vendor_defined_req_payload_struct = VendorDefinedReqPayloadStruct { + req_length: 0, + vendor_defined_req_payload: [0u8; MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE], + }; + + let mut writer = + Writer::init(&mut vendor_defined_req_payload_struct.vendor_defined_req_payload); + + vendor_defined_req_payload_struct.req_length = KSetStopDataObject { + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + } + .encode(&mut writer) + .map_err(|_| SPDM_STATUS_BUFFER_FULL)? + as u16; + + let vendor_defined_rsp_payload_struct = spdm_requester + .send_spdm_vendor_defined_request( + Some(session_id), + STANDARD_ID, + vendor_id(), + vendor_defined_req_payload_struct, + ) + .await?; + + let kgo_stop_ack_data_object = KGoStopAckDataObject::read_bytes( + &vendor_defined_rsp_payload_struct.vendor_defined_rsp_payload + [..vendor_defined_rsp_payload_struct.rsp_length as usize], + ) + .ok_or(SPDM_STATUS_INVALID_MSG_FIELD)?; + + if kgo_stop_ack_data_object.stream_id != stream_id + || kgo_stop_ack_data_object.key_set != key_set + || kgo_stop_ack_data_object.key_direction != key_direction + || kgo_stop_ack_data_object.key_sub_stream != key_sub_stream + || kgo_stop_ack_data_object.port_index != port_index + { + Err(SPDM_STATUS_INVALID_MSG_FIELD) + } else { + Ok(()) + } + } +} diff --git a/idekm/src/pci_ide_km_requester/pci_ide_km_req_query.rs b/idekm/src/pci_ide_km_requester/pci_ide_km_req_query.rs new file mode 100644 index 00000000..94c440cd --- /dev/null +++ b/idekm/src/pci_ide_km_requester/pci_ide_km_req_query.rs @@ -0,0 +1,76 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use codec::{Codec, Writer}; +use spdmlib::{ + error::{SpdmResult, SPDM_STATUS_BUFFER_FULL, SPDM_STATUS_INVALID_MSG_FIELD}, + message::{VendorDefinedReqPayloadStruct, MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE}, + requester::RequesterContext, +}; + +use crate::pci_idekm::{ + vendor_id, QueryDataObject, QueryRespDataObject, PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT, + STANDARD_ID, +}; + +use super::IdekmReqContext; + +impl IdekmReqContext { + #[allow(clippy::too_many_arguments)] + pub async fn pci_ide_km_query( + &mut self, + // IN + spdm_requester: &mut RequesterContext, + session_id: u32, + port_index: u8, + // OUT + dev_func_num: &mut u8, + bus_num: &mut u8, + segment: &mut u8, + max_port_index: &mut u8, + ide_reg_block: &mut [u32; PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT], + ide_reg_block_cnt: &mut usize, + ) -> SpdmResult { + let mut vendor_defined_req_payload_struct = VendorDefinedReqPayloadStruct { + req_length: 0, + vendor_defined_req_payload: [0u8; MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE], + }; + + let mut writer = + Writer::init(&mut vendor_defined_req_payload_struct.vendor_defined_req_payload); + + vendor_defined_req_payload_struct.req_length = QueryDataObject { port_index } + .encode(&mut writer) + .map_err(|_| SPDM_STATUS_BUFFER_FULL)? + as u16; + + let vendor_defined_rsp_payload_struct = spdm_requester + .send_spdm_vendor_defined_request( + Some(session_id), + STANDARD_ID, + vendor_id(), + vendor_defined_req_payload_struct, + ) + .await?; + + let query_resp_data_object = QueryRespDataObject::read_bytes( + &vendor_defined_rsp_payload_struct.vendor_defined_rsp_payload + [..vendor_defined_rsp_payload_struct.rsp_length as usize], + ) + .ok_or(SPDM_STATUS_INVALID_MSG_FIELD)?; + + if port_index != query_resp_data_object.port_index { + return Err(SPDM_STATUS_INVALID_MSG_FIELD); + } + + *dev_func_num = query_resp_data_object.dev_func_num; + *bus_num = query_resp_data_object.bus_num; + *segment = query_resp_data_object.segment; + *max_port_index = query_resp_data_object.max_port_index; + *ide_reg_block = query_resp_data_object.ide_reg_block; + *ide_reg_block_cnt = query_resp_data_object.ide_reg_block_cnt; + + Ok(()) + } +} diff --git a/idekm/src/pci_ide_km_responder/mod.rs b/idekm/src/pci_ide_km_responder/mod.rs new file mode 100644 index 00000000..e7283029 --- /dev/null +++ b/idekm/src/pci_ide_km_responder/mod.rs @@ -0,0 +1,17 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +#[derive(Debug, Default, Copy, Clone)] +pub struct IdekmRspContext; + +pub mod pci_ide_km_rsp_dispatcher; +pub use pci_ide_km_rsp_dispatcher::*; + +pub mod pci_ide_km_rsp_query; + +pub mod pci_ide_km_rsp_key_prog; + +pub mod pci_ide_km_rsp_key_set_go; + +pub mod pci_ide_km_rsp_key_set_stop; diff --git a/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_dispatcher.rs b/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_dispatcher.rs new file mode 100644 index 00000000..cd8aed11 --- /dev/null +++ b/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_dispatcher.rs @@ -0,0 +1,43 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use super::{ + pci_ide_km_rsp_key_prog, pci_ide_km_rsp_key_set_go, pci_ide_km_rsp_key_set_stop, + pci_ide_km_rsp_query, +}; +use crate::pci_idekm::{ + KEY_PROG_OBJECT_ID, K_SET_GO_OBJECT_ID, K_SET_STOP_OBJECT_ID, QUERY_OBJECT_ID, +}; +use spdmlib::{ + error::{SpdmResult, SPDM_STATUS_INVALID_MSG_FIELD}, + message::{VendorDefinedReqPayloadStruct, VendorDefinedRspPayloadStruct, VendorDefinedStruct}, +}; + +pub const PCI_IDE_KM_INSTANCE: VendorDefinedStruct = VendorDefinedStruct { + vendor_defined_request_handler: pci_ide_km_rsp_dispatcher, +}; + +fn pci_ide_km_rsp_dispatcher( + vendor_defined_req_payload_struct: &VendorDefinedReqPayloadStruct, +) -> SpdmResult { + if vendor_defined_req_payload_struct.req_length < 2 { + return Err(SPDM_STATUS_INVALID_MSG_FIELD); + } + + match vendor_defined_req_payload_struct.vendor_defined_req_payload[1] { + QUERY_OBJECT_ID => { + pci_ide_km_rsp_query::pci_ide_km_rsp_query(vendor_defined_req_payload_struct) + } + KEY_PROG_OBJECT_ID => { + pci_ide_km_rsp_key_prog::pci_ide_km_rsp_key_prog(vendor_defined_req_payload_struct) + } + K_SET_GO_OBJECT_ID => { + pci_ide_km_rsp_key_set_go::pci_ide_km_rsp_key_set_go(vendor_defined_req_payload_struct) + } + K_SET_STOP_OBJECT_ID => pci_ide_km_rsp_key_set_stop::pci_ide_km_rsp_key_set_stop( + vendor_defined_req_payload_struct, + ), + _ => Err(SPDM_STATUS_INVALID_MSG_FIELD), + } +} diff --git a/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_key_prog.rs b/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_key_prog.rs new file mode 100644 index 00000000..2362296c --- /dev/null +++ b/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_key_prog.rs @@ -0,0 +1,123 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use codec::{Codec, Writer}; +use spdmlib::{ + error::{ + SpdmResult, SPDM_STATUS_BUFFER_FULL, SPDM_STATUS_INVALID_MSG_FIELD, + SPDM_STATUS_INVALID_STATE_LOCAL, + }, + message::{ + VendorDefinedReqPayloadStruct, VendorDefinedRspPayloadStruct, + MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE, + }, +}; + +use conquer_once::spin::OnceCell; + +use crate::pci_idekm::{Aes256GcmKeyBuffer, KeyProgDataObject, KpAckDataObject, KpAckStatus}; +static PCI_IDE_KM_DEVICE_KEY_PROG_INSTANCE: OnceCell = OnceCell::uninit(); + +#[derive(Clone)] +pub struct PciIdeKmDeviceKeyProg { + pub pci_ide_km_device_key_prog_cb: fn( + // IN + stream_id: u8, + key_set: u8, + key_direction: u8, + key_sub_stream: u8, + port_index: u8, + key_iv: Aes256GcmKeyBuffer, + // OUT + status: &mut KpAckStatus, + ) -> SpdmResult, +} + +pub fn register(context: PciIdeKmDeviceKeyProg) -> bool { + PCI_IDE_KM_DEVICE_KEY_PROG_INSTANCE + .try_init_once(|| context) + .is_ok() +} + +static UNIMPLETEMTED: PciIdeKmDeviceKeyProg = PciIdeKmDeviceKeyProg { + pci_ide_km_device_key_prog_cb: |_stream_id: u8, + _key_set: u8, + _key_direction: u8, + _key_sub_stream: u8, + _port_index: u8, + _key_iv: Aes256GcmKeyBuffer, + _status: &mut KpAckStatus| + -> SpdmResult { unimplemented!() }, +}; + +fn pci_ide_km_device_key_prog( + stream_id: u8, + key_set: u8, + key_direction: u8, + key_sub_stream: u8, + port_index: u8, + key_iv: Aes256GcmKeyBuffer, + status: &mut KpAckStatus, +) -> SpdmResult { + (PCI_IDE_KM_DEVICE_KEY_PROG_INSTANCE + .try_get_or_init(|| UNIMPLETEMTED.clone()) + .ok() + .ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)? + .pci_ide_km_device_key_prog_cb)( + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + key_iv, + status, + ) +} + +pub(crate) fn pci_ide_km_rsp_key_prog( + vendor_defined_req_payload_struct: &VendorDefinedReqPayloadStruct, +) -> SpdmResult { + let key_prog_data_object = KeyProgDataObject::read_bytes( + &vendor_defined_req_payload_struct.vendor_defined_req_payload + [..vendor_defined_req_payload_struct.req_length as usize], + ) + .ok_or(SPDM_STATUS_INVALID_MSG_FIELD)?; + + let mut vendor_defined_rsp_payload_struct = VendorDefinedRspPayloadStruct { + rsp_length: 0, + vendor_defined_rsp_payload: [0u8; MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE], + }; + + let mut status = KpAckStatus::default(); + let key_iv = key_prog_data_object.key_iv.clone(); + pci_ide_km_device_key_prog( + key_prog_data_object.stream_id, + key_prog_data_object.key_set, + key_prog_data_object.key_direction, + key_prog_data_object.key_sub_stream, + key_prog_data_object.port_index, + key_iv, + &mut status, + )?; + + let mut writer = + Writer::init(&mut vendor_defined_rsp_payload_struct.vendor_defined_rsp_payload); + let cnt = KpAckDataObject { + stream_id: key_prog_data_object.stream_id, + status, + key_set: key_prog_data_object.key_set, + key_direction: key_prog_data_object.key_direction, + key_sub_stream: key_prog_data_object.key_sub_stream, + port_index: key_prog_data_object.port_index, + } + .encode(&mut writer) + .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + + if cnt > u16::MAX as usize { + Err(SPDM_STATUS_INVALID_STATE_LOCAL) + } else { + vendor_defined_rsp_payload_struct.rsp_length = cnt as u16; + Ok(vendor_defined_rsp_payload_struct) + } +} diff --git a/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_key_set_go.rs b/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_key_set_go.rs new file mode 100644 index 00000000..46222d02 --- /dev/null +++ b/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_key_set_go.rs @@ -0,0 +1,109 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use codec::{Codec, Writer}; +use conquer_once::spin::OnceCell; +use spdmlib::{ + error::{ + SpdmResult, SPDM_STATUS_BUFFER_FULL, SPDM_STATUS_INVALID_MSG_FIELD, + SPDM_STATUS_INVALID_STATE_LOCAL, + }, + message::{ + VendorDefinedReqPayloadStruct, VendorDefinedRspPayloadStruct, + MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE, + }, +}; + +use crate::pci_idekm::{KGoStopAckDataObject, KSetGoDataObject}; + +static PCI_IDE_KM_DEVICE_KEY_SET_GO_INSTANCE: OnceCell = OnceCell::uninit(); + +#[derive(Clone)] +pub struct PciIdeKmDeviceKeySetGo { + pub pci_ide_km_device_key_set_go_cb: fn( + // IN + stream_id: u8, + key_set: u8, + key_direction: u8, + key_sub_stream: u8, + port_index: u8, + ) -> SpdmResult, +} + +pub fn register(context: PciIdeKmDeviceKeySetGo) -> bool { + PCI_IDE_KM_DEVICE_KEY_SET_GO_INSTANCE + .try_init_once(|| context) + .is_ok() +} + +static UNIMPLETEMTED: PciIdeKmDeviceKeySetGo = PciIdeKmDeviceKeySetGo { + pci_ide_km_device_key_set_go_cb: |_stream_id: u8, + _key_set: u8, + _key_direction: u8, + _key_sub_stream: u8, + _port_index: u8| + -> SpdmResult { unimplemented!() }, +}; + +fn pci_ide_km_device_key_set_go( + stream_id: u8, + key_set: u8, + key_direction: u8, + key_sub_stream: u8, + port_index: u8, +) -> SpdmResult { + (PCI_IDE_KM_DEVICE_KEY_SET_GO_INSTANCE + .try_get_or_init(|| UNIMPLETEMTED.clone()) + .ok() + .ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)? + .pci_ide_km_device_key_set_go_cb)( + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + ) +} + +pub(crate) fn pci_ide_km_rsp_key_set_go( + vendor_defined_req_payload_struct: &VendorDefinedReqPayloadStruct, +) -> SpdmResult { + let kset_go_data_object = KSetGoDataObject::read_bytes( + &vendor_defined_req_payload_struct.vendor_defined_req_payload + [..vendor_defined_req_payload_struct.req_length as usize], + ) + .ok_or(SPDM_STATUS_INVALID_MSG_FIELD)?; + + let mut vendor_defined_rsp_payload_struct = VendorDefinedRspPayloadStruct { + rsp_length: 0, + vendor_defined_rsp_payload: [0u8; MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE], + }; + + pci_ide_km_device_key_set_go( + kset_go_data_object.stream_id, + kset_go_data_object.key_set, + kset_go_data_object.key_direction, + kset_go_data_object.key_sub_stream, + kset_go_data_object.port_index, + )?; + + let mut writer = + Writer::init(&mut vendor_defined_rsp_payload_struct.vendor_defined_rsp_payload); + let cnt = KGoStopAckDataObject { + stream_id: kset_go_data_object.stream_id, + key_set: kset_go_data_object.key_set, + key_direction: kset_go_data_object.key_direction, + key_sub_stream: kset_go_data_object.key_sub_stream, + port_index: kset_go_data_object.port_index, + } + .encode(&mut writer) + .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + + if cnt > u16::MAX as usize { + Err(SPDM_STATUS_INVALID_STATE_LOCAL) + } else { + vendor_defined_rsp_payload_struct.rsp_length = cnt as u16; + Ok(vendor_defined_rsp_payload_struct) + } +} diff --git a/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_key_set_stop.rs b/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_key_set_stop.rs new file mode 100644 index 00000000..6ca889af --- /dev/null +++ b/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_key_set_stop.rs @@ -0,0 +1,110 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use codec::{Codec, Writer}; +use conquer_once::spin::OnceCell; +use spdmlib::{ + error::{ + SpdmResult, SPDM_STATUS_BUFFER_FULL, SPDM_STATUS_INVALID_MSG_FIELD, + SPDM_STATUS_INVALID_STATE_LOCAL, + }, + message::{ + VendorDefinedReqPayloadStruct, VendorDefinedRspPayloadStruct, + MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE, + }, +}; + +use crate::pci_idekm::{KGoStopAckDataObject, KSetStopDataObject}; + +static PCI_IDE_KM_DEVICE_KEY_SET_STOP_INSTANCE: OnceCell = + OnceCell::uninit(); + +#[derive(Clone)] +pub struct PciIdeKmDeviceKeySetStop { + pub pci_ide_km_device_key_set_stop_cb: fn( + // IN + stream_id: u8, + key_set: u8, + key_direction: u8, + key_sub_stream: u8, + port_index: u8, + ) -> SpdmResult, +} + +pub fn register(context: PciIdeKmDeviceKeySetStop) -> bool { + PCI_IDE_KM_DEVICE_KEY_SET_STOP_INSTANCE + .try_init_once(|| context) + .is_ok() +} + +static UNIMPLETEMTED: PciIdeKmDeviceKeySetStop = PciIdeKmDeviceKeySetStop { + pci_ide_km_device_key_set_stop_cb: |_stream_id: u8, + _key_set: u8, + _key_direction: u8, + _key_sub_stream: u8, + _port_index: u8| + -> SpdmResult { unimplemented!() }, +}; + +fn pci_ide_km_device_key_set_stop( + stream_id: u8, + key_set: u8, + key_direction: u8, + key_sub_stream: u8, + port_index: u8, +) -> SpdmResult { + (PCI_IDE_KM_DEVICE_KEY_SET_STOP_INSTANCE + .try_get_or_init(|| UNIMPLETEMTED.clone()) + .ok() + .ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)? + .pci_ide_km_device_key_set_stop_cb)( + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + ) +} + +pub(crate) fn pci_ide_km_rsp_key_set_stop( + vendor_defined_req_payload_struct: &VendorDefinedReqPayloadStruct, +) -> SpdmResult { + let kset_stop_data_object = KSetStopDataObject::read_bytes( + &vendor_defined_req_payload_struct.vendor_defined_req_payload + [..vendor_defined_req_payload_struct.req_length as usize], + ) + .ok_or(SPDM_STATUS_INVALID_MSG_FIELD)?; + + let mut vendor_defined_rsp_payload_struct = VendorDefinedRspPayloadStruct { + rsp_length: 0, + vendor_defined_rsp_payload: [0u8; MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE], + }; + + pci_ide_km_device_key_set_stop( + kset_stop_data_object.stream_id, + kset_stop_data_object.key_set, + kset_stop_data_object.key_direction, + kset_stop_data_object.key_sub_stream, + kset_stop_data_object.port_index, + )?; + + let mut writer = + Writer::init(&mut vendor_defined_rsp_payload_struct.vendor_defined_rsp_payload); + let cnt = KGoStopAckDataObject { + stream_id: kset_stop_data_object.stream_id, + key_set: kset_stop_data_object.key_set, + key_direction: kset_stop_data_object.key_direction, + key_sub_stream: kset_stop_data_object.key_sub_stream, + port_index: kset_stop_data_object.port_index, + } + .encode(&mut writer) + .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + + if cnt > u16::MAX as usize { + Err(SPDM_STATUS_INVALID_STATE_LOCAL) + } else { + vendor_defined_rsp_payload_struct.rsp_length = cnt as u16; + Ok(vendor_defined_rsp_payload_struct) + } +} diff --git a/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_query.rs b/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_query.rs new file mode 100644 index 00000000..e840192e --- /dev/null +++ b/idekm/src/pci_ide_km_responder/pci_ide_km_rsp_query.rs @@ -0,0 +1,129 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use codec::{Codec, Writer}; +use spdmlib::{ + error::{ + SpdmResult, SPDM_STATUS_BUFFER_FULL, SPDM_STATUS_INVALID_MSG_FIELD, + SPDM_STATUS_INVALID_STATE_LOCAL, + }, + message::{ + VendorDefinedReqPayloadStruct, VendorDefinedRspPayloadStruct, + MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE, + }, +}; + +use crate::pci_idekm::{QueryDataObject, QueryRespDataObject, PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT}; + +use conquer_once::spin::OnceCell; +static PCI_IDE_KM_DEVICE_QUERY_INSTANCE: OnceCell = OnceCell::uninit(); + +#[derive(Clone)] +pub struct PciIdeKmDeviceQuery { + pub pci_ide_km_device_query_cb: fn( + port_index: u8, + dev_func_num: &mut u8, + bus_num: &mut u8, + segment: &mut u8, + max_port_index: &mut u8, + ide_reg_block: &mut [u32; PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT], + ide_reg_block_cnt: &mut usize, + ) -> SpdmResult, +} + +pub fn register(context: PciIdeKmDeviceQuery) -> bool { + PCI_IDE_KM_DEVICE_QUERY_INSTANCE + .try_init_once(|| context) + .is_ok() +} + +static UNIMPLETEMTED: PciIdeKmDeviceQuery = PciIdeKmDeviceQuery { + pci_ide_km_device_query_cb: |_port_index: u8, + _dev_func_num: &mut u8, + _bus_num: &mut u8, + _segment: &mut u8, + _max_port_index: &mut u8, + _ide_reg_block: &mut [u32; PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT], + _ide_reg_block_cnt: &mut usize| + -> SpdmResult { unimplemented!() }, +}; + +fn pci_ide_km_device_query( + port_index: u8, + dev_func_num: &mut u8, + bus_num: &mut u8, + segment: &mut u8, + max_port_index: &mut u8, + ide_reg_block: &mut [u32; PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT], + ide_reg_block_cnt: &mut usize, +) -> SpdmResult { + (PCI_IDE_KM_DEVICE_QUERY_INSTANCE + .try_get_or_init(|| UNIMPLETEMTED.clone()) + .ok() + .ok_or(SPDM_STATUS_INVALID_STATE_LOCAL)? + .pci_ide_km_device_query_cb)( + port_index, + dev_func_num, + bus_num, + segment, + max_port_index, + ide_reg_block, + ide_reg_block_cnt, + ) +} + +pub(crate) fn pci_ide_km_rsp_query( + vendor_defined_req_payload_struct: &VendorDefinedReqPayloadStruct, +) -> SpdmResult { + let query_data_object = QueryDataObject::read_bytes( + &vendor_defined_req_payload_struct.vendor_defined_req_payload + [..vendor_defined_req_payload_struct.req_length as usize], + ) + .ok_or(SPDM_STATUS_INVALID_MSG_FIELD)?; + + let mut vendor_defined_rsp_payload_struct = VendorDefinedRspPayloadStruct { + rsp_length: 0, + vendor_defined_rsp_payload: [0u8; MAX_SPDM_VENDOR_DEFINED_PAYLOAD_SIZE], + }; + + let port_index = query_data_object.port_index; + let mut dev_func_num = 0u8; + let mut bus_num = 0u8; + let mut segment = 0u8; + let mut max_port_index = 0u8; + let mut ide_reg_block = [0u32; PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT]; + let mut ide_reg_block_cnt = 0usize; + + pci_ide_km_device_query( + port_index, + &mut dev_func_num, + &mut bus_num, + &mut segment, + &mut max_port_index, + &mut ide_reg_block, + &mut ide_reg_block_cnt, + )?; + + let mut writer = + Writer::init(&mut vendor_defined_rsp_payload_struct.vendor_defined_rsp_payload); + + let cnt = QueryRespDataObject { + port_index, + dev_func_num, + bus_num, + segment, + max_port_index, + ide_reg_block_cnt, + ide_reg_block, + } + .encode(&mut writer) + .map_err(|_| SPDM_STATUS_BUFFER_FULL)?; + + if cnt > u16::MAX as usize { + Err(SPDM_STATUS_INVALID_STATE_LOCAL) + } else { + vendor_defined_rsp_payload_struct.rsp_length = cnt as u16; + Ok(vendor_defined_rsp_payload_struct) + } +} diff --git a/idekm/src/pci_idekm.rs b/idekm/src/pci_idekm.rs new file mode 100644 index 00000000..bfd59b0a --- /dev/null +++ b/idekm/src/pci_idekm.rs @@ -0,0 +1,567 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use codec::Codec; +use core::convert::TryFrom; +use spdmlib::message::{ + RegistryOrStandardsBodyID, VendorIDStruct, MAX_SPDM_VENDOR_DEFINED_VENDOR_ID_LEN, +}; +use zeroize::ZeroizeOnDrop; +extern crate alloc; +use alloc::boxed::Box; + +pub const PCI_IDE_KM_LINK_IDE_REG_BLOCK_MAX_COUNT: usize = 8; +pub const PCI_IDE_KM_SELECTIVE_IDE_REG_BLOCK_MAX_COUNT: usize = 255; +pub const PCI_IDE_KM_SELECTIVE_IDE_ADDRESS_ASSOCIATION_REG_BLOCK_MAX_COUNT: usize = 15; + +pub const PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT: usize = 2 + + 2 * PCI_IDE_KM_LINK_IDE_REG_BLOCK_MAX_COUNT + + (3 + 2 + 3 * PCI_IDE_KM_SELECTIVE_IDE_ADDRESS_ASSOCIATION_REG_BLOCK_MAX_COUNT) + * PCI_IDE_KM_SELECTIVE_IDE_REG_BLOCK_MAX_COUNT; +pub const PCI_IDE_KM_IDE_REG_BLOCK_MIN_COUNT: usize = 2; + +pub const IDE_PROTOCOL_ID: u8 = 0; + +pub const QUERY_OBJECT_ID: u8 = 0; +pub const QUERY_RESP_OBJECT_ID: u8 = 1; +pub const KEY_PROG_OBJECT_ID: u8 = 2; +pub const KP_ACK_OBJECT_ID: u8 = 3; +pub const K_SET_GO_OBJECT_ID: u8 = 4; +pub const K_SET_STOP_OBJECT_ID: u8 = 5; +pub const K_GOSTOP_ACK_OBJECT_ID: u8 = 6; + +pub const KEY_SET_MASK: u8 = 0x1; +pub const KEY_SET_0: u8 = 0x0; +pub const KEY_SET_1: u8 = 0x1; + +pub const KEY_DIRECTION_MASK: u8 = 0x2; +pub const KEY_DIRECTION_RX: u8 = 0x0; +pub const KEY_DIRECTION_TX: u8 = 0x2; + +pub const KEY_SUB_STREAM_MASK: u8 = 0xF0; +pub const KEY_SUB_STREAM_PR: u8 = 0x0; +pub const KEY_SUB_STREAM_NPR: u8 = 0x10; +pub const KEY_SUB_STREAM_CPL: u8 = 0x20; + +#[derive(Debug)] +pub struct QueryDataObject { + pub port_index: u8, +} + +impl Codec for QueryDataObject { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let mut cnt = 0; + + cnt += IDE_PROTOCOL_ID.encode(bytes)?; + cnt += QUERY_OBJECT_ID.encode(bytes)?; + cnt += 0u8.encode(bytes)?; + cnt += self.port_index.encode(bytes)?; + + Ok(cnt) + } + + fn read(r: &mut codec::Reader) -> Option { + let protocol_id = u8::read(r)?; + if protocol_id != IDE_PROTOCOL_ID { + return None; + } + + let object_id = u8::read(r)?; + if object_id != QUERY_OBJECT_ID { + return None; + } + + u8::read(r)?; + + let port_index = u8::read(r)?; + + Some(Self { port_index }) + } +} + +#[derive(Debug)] +pub struct QueryRespDataObject { + pub port_index: u8, + pub dev_func_num: u8, + pub bus_num: u8, + pub segment: u8, + pub max_port_index: u8, + pub ide_reg_block_cnt: usize, + pub ide_reg_block: [u32; PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT], +} + +impl Codec for QueryRespDataObject { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let mut cnt = 0; + + cnt += IDE_PROTOCOL_ID.encode(bytes)?; + cnt += QUERY_RESP_OBJECT_ID.encode(bytes)?; + cnt += 0u8.encode(bytes)?; + cnt += self.port_index.encode(bytes)?; + cnt += self.dev_func_num.encode(bytes)?; + cnt += self.bus_num.encode(bytes)?; + cnt += self.segment.encode(bytes)?; + cnt += self.max_port_index.encode(bytes)?; + for ide_reg in self.ide_reg_block.iter().take(self.ide_reg_block_cnt) { + cnt += ide_reg.encode(bytes)?; + } + + Ok(cnt) + } + + fn read(r: &mut codec::Reader) -> Option { + let protocol_id = u8::read(r)?; + if protocol_id != IDE_PROTOCOL_ID { + return None; + } + let object_id = u8::read(r)?; + if object_id != QUERY_RESP_OBJECT_ID { + return None; + } + u8::read(r)?; + let port_index = u8::read(r)?; + let dev_func_num = u8::read(r)?; + let bus_num = u8::read(r)?; + let segment = u8::read(r)?; + let max_port_index = u8::read(r)?; + + let left = r.left(); + if left % 4 != 0 { + return None; + } + + let ide_reg_block_cnt = left / 4; + if !(PCI_IDE_KM_IDE_REG_BLOCK_MIN_COUNT..=PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT) + .contains(&ide_reg_block_cnt) + { + return None; + } + + let mut ide_reg_block = [0u32; PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT]; + for ide_reg in ide_reg_block.iter_mut().take(ide_reg_block_cnt) { + *ide_reg = u32::read(r)?; + } + + Some(Self { + port_index, + dev_func_num, + bus_num, + segment, + max_port_index, + ide_reg_block_cnt, + ide_reg_block, + }) + } +} + +#[derive(Debug, Default, Clone, ZeroizeOnDrop)] +pub struct Aes256GcmKeyBuffer { + pub key: Box<[u32; 8]>, + pub iv: Box<[u32; 2]>, +} + +impl Codec for Aes256GcmKeyBuffer { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let mut cnt = 0; + + cnt += self.key[7].encode(bytes)?; + cnt += self.key[6].encode(bytes)?; + cnt += self.key[5].encode(bytes)?; + cnt += self.key[4].encode(bytes)?; + cnt += self.key[3].encode(bytes)?; + cnt += self.key[2].encode(bytes)?; + cnt += self.key[1].encode(bytes)?; + cnt += self.key[0].encode(bytes)?; + cnt += self.iv[1].encode(bytes)?; + cnt += self.iv[0].encode(bytes)?; + + Ok(cnt) + } + + fn read(r: &mut codec::Reader) -> Option { + let mut key = Box::new([0u32; 8]); + let mut iv = Box::new([0u32; 2]); + + for k in key.iter_mut().take(8) { + *k = u32::read(r)?; + } + + key.reverse(); + + for i in iv.iter_mut().take(2) { + *i = u32::read(r)?; + } + + iv.reverse(); + + Some(Self { key, iv }) + } +} + +#[derive(Debug, Default, ZeroizeOnDrop)] +pub struct KeyProgDataObject { + pub stream_id: u8, + pub key_set: u8, + pub key_direction: u8, + pub key_sub_stream: u8, + pub port_index: u8, + pub key_iv: Aes256GcmKeyBuffer, +} + +impl Codec for KeyProgDataObject { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let mut cnt = 0; + + cnt += IDE_PROTOCOL_ID.encode(bytes)?; + cnt += KEY_PROG_OBJECT_ID.encode(bytes)?; + cnt += 0u16.encode(bytes)?; + cnt += self.stream_id.encode(bytes)?; + cnt += 0u8.encode(bytes)?; + cnt += (self.key_set | self.key_direction | self.key_sub_stream).encode(bytes)?; + cnt += self.port_index.encode(bytes)?; + cnt += self.key_iv.encode(bytes)?; + + Ok(cnt) + } + + fn read(r: &mut codec::Reader) -> Option { + let protocol_id = u8::read(r)?; + if protocol_id != IDE_PROTOCOL_ID { + return None; + } + let object_id = u8::read(r)?; + if object_id != KEY_PROG_OBJECT_ID { + return None; + } + u16::read(r)?; + let stream_id = u8::read(r)?; + u8::read(r)?; + let key_set_direction_sub_stream = u8::read(r)?; + let key_set = key_set_direction_sub_stream & KEY_SET_MASK; + let key_direction = key_set_direction_sub_stream & KEY_DIRECTION_MASK; + let key_sub_stream = key_set_direction_sub_stream & KEY_SUB_STREAM_MASK; + if key_sub_stream != KEY_SUB_STREAM_PR + && key_sub_stream != KEY_SUB_STREAM_NPR + && key_sub_stream != KEY_SUB_STREAM_CPL + { + return None; + } + let port_index = u8::read(r)?; + let key_iv = Aes256GcmKeyBuffer::read(r)?; + + Some(Self { + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + key_iv, + }) + } +} + +#[allow(non_camel_case_types)] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub enum KpAckStatus { + SUCCESS, + INCORRECT_LENGTH, + UNSUPPORTED_PORT_INDEX, + UNSUPPORTED_VALUE, + UNSPECIFIED_FAILURE, +} + +impl Default for KpAckStatus { + fn default() -> Self { + Self::UNSPECIFIED_FAILURE + } +} + +impl From for u8 { + fn from(status: KpAckStatus) -> Self { + match status { + KpAckStatus::SUCCESS => 0, + KpAckStatus::INCORRECT_LENGTH => 1, + KpAckStatus::UNSUPPORTED_PORT_INDEX => 2, + KpAckStatus::UNSUPPORTED_VALUE => 3, + KpAckStatus::UNSPECIFIED_FAILURE => 4, + } + } +} + +impl TryFrom for KpAckStatus { + type Error = (); + fn try_from(untrusted_status: u8) -> Result>::Error> { + match untrusted_status { + 0 => Ok(KpAckStatus::SUCCESS), + 1 => Ok(KpAckStatus::INCORRECT_LENGTH), + 2 => Ok(KpAckStatus::UNSUPPORTED_PORT_INDEX), + 3 => Ok(KpAckStatus::UNSUPPORTED_VALUE), + 4 => Ok(KpAckStatus::UNSPECIFIED_FAILURE), + _ => Err(()), + } + } +} + +impl Codec for KpAckStatus { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let mut cnt = 0; + + cnt += u8::from(*self).encode(bytes)?; + + Ok(cnt) + } + + fn read(r: &mut codec::Reader) -> Option { + let status = u8::read(r)?; + KpAckStatus::try_from(status).ok() + } +} + +#[derive(Debug, Default)] +pub struct KpAckDataObject { + pub stream_id: u8, + pub status: KpAckStatus, + pub key_set: u8, + pub key_direction: u8, + pub key_sub_stream: u8, + pub port_index: u8, +} + +impl Codec for KpAckDataObject { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let mut cnt = 0; + + cnt += IDE_PROTOCOL_ID.encode(bytes)?; + cnt += KP_ACK_OBJECT_ID.encode(bytes)?; + cnt += 0u16.encode(bytes)?; + cnt += self.stream_id.encode(bytes)?; + cnt += self.status.encode(bytes)?; + cnt += (self.key_set | self.key_direction | self.key_sub_stream).encode(bytes)?; + cnt += self.port_index.encode(bytes)?; + + Ok(cnt) + } + + fn read(r: &mut codec::Reader) -> Option { + let protocol_id = u8::read(r)?; + if protocol_id != IDE_PROTOCOL_ID { + return None; + } + let object_id = u8::read(r)?; + if object_id != KP_ACK_OBJECT_ID { + return None; + } + u16::read(r)?; + let stream_id = u8::read(r)?; + let status = KpAckStatus::read(r)?; + let key_set_direction_sub_stream = u8::read(r)?; + let key_set = key_set_direction_sub_stream & KEY_SET_MASK; + let key_direction = key_set_direction_sub_stream & KEY_DIRECTION_MASK; + let key_sub_stream = key_set_direction_sub_stream & KEY_SUB_STREAM_MASK; + if key_sub_stream != KEY_SUB_STREAM_PR + && key_sub_stream != KEY_SUB_STREAM_NPR + && key_sub_stream != KEY_SUB_STREAM_CPL + { + return None; + } + let port_index = u8::read(r)?; + + Some(Self { + stream_id, + status, + key_set, + key_direction, + key_sub_stream, + port_index, + }) + } +} + +#[derive(Debug, Default)] +pub struct KSetGoDataObject { + pub stream_id: u8, + pub key_set: u8, + pub key_direction: u8, + pub key_sub_stream: u8, + pub port_index: u8, +} + +impl Codec for KSetGoDataObject { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let mut cnt = 0; + + cnt += IDE_PROTOCOL_ID.encode(bytes)?; + cnt += K_SET_GO_OBJECT_ID.encode(bytes)?; + cnt += 0u16.encode(bytes)?; + cnt += self.stream_id.encode(bytes)?; + cnt += 0u8.encode(bytes)?; + cnt += (self.key_set | self.key_direction | self.key_sub_stream).encode(bytes)?; + cnt += self.port_index.encode(bytes)?; + + Ok(cnt) + } + + fn read(r: &mut codec::Reader) -> Option { + let protocol_id = u8::read(r)?; + if protocol_id != IDE_PROTOCOL_ID { + return None; + } + let object_id = u8::read(r)?; + if object_id != K_SET_GO_OBJECT_ID { + return None; + } + u16::read(r)?; + let stream_id = u8::read(r)?; + u8::read(r)?; + let key_set_direction_sub_stream = u8::read(r)?; + let key_set = key_set_direction_sub_stream & KEY_SET_MASK; + let key_direction = key_set_direction_sub_stream & KEY_DIRECTION_MASK; + let key_sub_stream = key_set_direction_sub_stream & KEY_SUB_STREAM_MASK; + if key_sub_stream != KEY_SUB_STREAM_PR + && key_sub_stream != KEY_SUB_STREAM_NPR + && key_sub_stream != KEY_SUB_STREAM_CPL + { + return None; + } + let port_index = u8::read(r)?; + + Some(Self { + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + }) + } +} + +#[derive(Debug, Default)] +pub struct KSetStopDataObject { + pub stream_id: u8, + pub key_set: u8, + pub key_direction: u8, + pub key_sub_stream: u8, + pub port_index: u8, +} + +impl Codec for KSetStopDataObject { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let mut cnt = 0; + + cnt += IDE_PROTOCOL_ID.encode(bytes)?; + cnt += K_SET_STOP_OBJECT_ID.encode(bytes)?; + cnt += 0u16.encode(bytes)?; + cnt += self.stream_id.encode(bytes)?; + cnt += 0u8.encode(bytes)?; + cnt += (self.key_set | self.key_direction | self.key_sub_stream).encode(bytes)?; + cnt += self.port_index.encode(bytes)?; + + Ok(cnt) + } + + fn read(r: &mut codec::Reader) -> Option { + let protocol_id = u8::read(r)?; + if protocol_id != IDE_PROTOCOL_ID { + return None; + } + let object_id = u8::read(r)?; + if object_id != K_SET_STOP_OBJECT_ID { + return None; + } + u16::read(r)?; + let stream_id = u8::read(r)?; + u8::read(r)?; + let key_set_direction_sub_stream = u8::read(r)?; + let key_set = key_set_direction_sub_stream & KEY_SET_MASK; + let key_direction = key_set_direction_sub_stream & KEY_DIRECTION_MASK; + let key_sub_stream = key_set_direction_sub_stream & KEY_SUB_STREAM_MASK; + if key_sub_stream != KEY_SUB_STREAM_PR + && key_sub_stream != KEY_SUB_STREAM_NPR + && key_sub_stream != KEY_SUB_STREAM_CPL + { + return None; + } + let port_index = u8::read(r)?; + + Some(Self { + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + }) + } +} + +#[derive(Debug, Default)] +pub struct KGoStopAckDataObject { + pub stream_id: u8, + pub key_set: u8, + pub key_direction: u8, + pub key_sub_stream: u8, + pub port_index: u8, +} + +impl Codec for KGoStopAckDataObject { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let mut cnt = 0; + + cnt += IDE_PROTOCOL_ID.encode(bytes)?; + cnt += K_GOSTOP_ACK_OBJECT_ID.encode(bytes)?; + cnt += 0u16.encode(bytes)?; + cnt += self.stream_id.encode(bytes)?; + cnt += 0u8.encode(bytes)?; + cnt += (self.key_set | self.key_direction | self.key_sub_stream).encode(bytes)?; + cnt += self.port_index.encode(bytes)?; + + Ok(cnt) + } + + fn read(r: &mut codec::Reader) -> Option { + let protocol_id = u8::read(r)?; + if protocol_id != IDE_PROTOCOL_ID { + return None; + } + let object_id = u8::read(r)?; + if object_id != K_GOSTOP_ACK_OBJECT_ID { + return None; + } + u16::read(r)?; + let stream_id = u8::read(r)?; + u8::read(r)?; + let key_set_direction_sub_stream = u8::read(r)?; + let key_set = key_set_direction_sub_stream & KEY_SET_MASK; + let key_direction = key_set_direction_sub_stream & KEY_DIRECTION_MASK; + let key_sub_stream = key_set_direction_sub_stream & KEY_SUB_STREAM_MASK; + if key_sub_stream != KEY_SUB_STREAM_PR + && key_sub_stream != KEY_SUB_STREAM_NPR + && key_sub_stream != KEY_SUB_STREAM_CPL + { + return None; + } + let port_index = u8::read(r)?; + + Some(Self { + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + }) + } +} + +pub const STANDARD_ID: RegistryOrStandardsBodyID = RegistryOrStandardsBodyID::PCISIG; + +#[inline] +pub const fn vendor_id() -> VendorIDStruct { + let mut vendor_idstruct = VendorIDStruct { + len: 2, + vendor_id: [0u8; MAX_SPDM_VENDOR_DEFINED_VENDOR_ID_LEN], + }; + + vendor_idstruct.vendor_id[0] = 0x01; + + vendor_idstruct +} diff --git a/test/spdm-requester-emu/Cargo.toml b/test/spdm-requester-emu/Cargo.toml index 63524055..615f5de9 100644 --- a/test/spdm-requester-emu/Cargo.toml +++ b/test/spdm-requester-emu/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] spdm-emu = { path = "../spdm-emu", default-features = false } spdmlib = { path = "../../spdmlib", default-features = false } +idekm = { path = "../../idekm", default-features = false } codec = { path = "../../codec" } mctp_transport = { path = "../../mctp_transport" } pcidoe_transport = { path = "../../pcidoe_transport" } diff --git a/test/spdm-requester-emu/src/main.rs b/test/spdm-requester-emu/src/main.rs index ce4ddb9e..86fcf8ba 100644 --- a/test/spdm-requester-emu/src/main.rs +++ b/test/spdm-requester-emu/src/main.rs @@ -7,6 +7,16 @@ use common::SpdmDeviceIo; use common::SpdmTransportEncap; +use idekm::pci_ide_km_requester::IdekmReqContext; +use idekm::pci_idekm::Aes256GcmKeyBuffer; +use idekm::pci_idekm::KpAckStatus; +use idekm::pci_idekm::KEY_DIRECTION_RX; +use idekm::pci_idekm::KEY_DIRECTION_TX; +use idekm::pci_idekm::KEY_SET_0; +use idekm::pci_idekm::KEY_SUB_STREAM_CPL; +use idekm::pci_idekm::KEY_SUB_STREAM_NPR; +use idekm::pci_idekm::KEY_SUB_STREAM_PR; +use idekm::pci_idekm::PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT; use log::LevelFilter; use log::*; use simple_logger::SimpleLogger; @@ -19,6 +29,7 @@ use spdmlib::common::SpdmOpaqueSupport; use spdmlib::common::ST1; use spdmlib::config; use spdmlib::config::MAX_ROOT_CERT_SUPPORT; +use spdmlib::crypto::rand::get_random; use spdmlib::message::*; use spdmlib::protocol::*; use spdmlib::requester; @@ -372,6 +383,682 @@ async fn test_spdm( } } +async fn test_idekm( + socket_io_transport: Arc>, + transport_encap: Arc>, +) { + let req_capabilities = SpdmRequestCapabilityFlags::CERT_CAP + | SpdmRequestCapabilityFlags::CHAL_CAP + | SpdmRequestCapabilityFlags::ENCRYPT_CAP + | SpdmRequestCapabilityFlags::MAC_CAP + | SpdmRequestCapabilityFlags::KEY_EX_CAP + | SpdmRequestCapabilityFlags::PSK_CAP + | SpdmRequestCapabilityFlags::ENCAP_CAP + | SpdmRequestCapabilityFlags::HBEAT_CAP + | SpdmRequestCapabilityFlags::KEY_UPD_CAP; + // | SpdmRequestCapabilityFlags::HANDSHAKE_IN_THE_CLEAR_CAP + // | SpdmRequestCapabilityFlags::PUB_KEY_ID_CAP + let req_capabilities = if cfg!(feature = "mut-auth") { + req_capabilities | SpdmRequestCapabilityFlags::MUT_AUTH_CAP + } else { + req_capabilities + }; + + let config_info = common::SpdmConfigInfo { + spdm_version: [ + SpdmVersion::SpdmVersion10, + SpdmVersion::SpdmVersion11, + SpdmVersion::SpdmVersion12, + ], + req_capabilities, + req_ct_exponent: 0, + measurement_specification: SpdmMeasurementSpecification::DMTF, + base_asym_algo: if USE_ECDSA { + SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384 + } else { + SpdmBaseAsymAlgo::TPM_ALG_RSASSA_3072 + }, + base_hash_algo: SpdmBaseHashAlgo::TPM_ALG_SHA_384, + dhe_algo: SpdmDheAlgo::SECP_384_R1, + aead_algo: SpdmAeadAlgo::AES_256_GCM, + req_asym_algo: if USE_ECDSA { + SpdmReqAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384 + } else { + SpdmReqAsymAlgo::TPM_ALG_RSASSA_3072 + }, + key_schedule_algo: SpdmKeyScheduleAlgo::SPDM_KEY_SCHEDULE, + opaque_support: SpdmOpaqueSupport::OPAQUE_DATA_FMT1, + data_transfer_size: config::MAX_SPDM_MSG_SIZE as u32, + max_spdm_msg_size: config::MAX_SPDM_MSG_SIZE as u32, + ..Default::default() + }; + + let mut peer_root_cert_data = SpdmCertChainData { + ..Default::default() + }; + + let ca_file_path = if USE_ECDSA { + "test_key/ecp384/ca.cert.der" + } else { + "test_key/rsa3072/ca.cert.der" + }; + let ca_cert = std::fs::read(ca_file_path).expect("unable to read ca cert!"); + let inter_file_path = if USE_ECDSA { + "test_key/ecp384/inter.cert.der" + } else { + "test_key/rsa3072/inter.cert.der" + }; + let inter_cert = std::fs::read(inter_file_path).expect("unable to read inter cert!"); + let leaf_file_path = if USE_ECDSA { + "test_key/ecp384/end_responder.cert.der" + } else { + "test_key/rsa3072/end_responder.cert.der" + }; + let leaf_cert = std::fs::read(leaf_file_path).expect("unable to read leaf cert!"); + + let ca_len = ca_cert.len(); + let inter_len = inter_cert.len(); + let leaf_len = leaf_cert.len(); + println!( + "total cert size - {:?} = {:?} + {:?} + {:?}", + ca_len + inter_len + leaf_len, + ca_len, + inter_len, + leaf_len + ); + peer_root_cert_data.data_size = (ca_len) as u16; + peer_root_cert_data.data[0..ca_len].copy_from_slice(ca_cert.as_ref()); + + let mut peer_root_cert_data_list = gen_array_clone(None, MAX_ROOT_CERT_SUPPORT); + peer_root_cert_data_list[0] = Some(peer_root_cert_data); + + let provision_info = if cfg!(feature = "mut-auth") { + spdmlib::secret::asym_sign::register(SECRET_ASYM_IMPL_INSTANCE.clone()); + let mut my_cert_chain_data = SpdmCertChainData { + ..Default::default() + }; + + my_cert_chain_data.data_size = (ca_len + inter_len + leaf_len) as u16; + my_cert_chain_data.data[0..ca_len].copy_from_slice(ca_cert.as_ref()); + my_cert_chain_data.data[ca_len..(ca_len + inter_len)].copy_from_slice(inter_cert.as_ref()); + my_cert_chain_data.data[(ca_len + inter_len)..(ca_len + inter_len + leaf_len)] + .copy_from_slice(leaf_cert.as_ref()); + + common::SpdmProvisionInfo { + my_cert_chain_data: [ + Some(my_cert_chain_data), + None, + None, + None, + None, + None, + None, + None, + ], + my_cert_chain: [None, None, None, None, None, None, None, None], + peer_root_cert_data: peer_root_cert_data_list, + } + } else { + common::SpdmProvisionInfo { + my_cert_chain_data: [None, None, None, None, None, None, None, None], + my_cert_chain: [None, None, None, None, None, None, None, None], + peer_root_cert_data: peer_root_cert_data_list, + } + }; + + let mut context = requester::RequesterContext::new( + socket_io_transport, + transport_encap, + config_info, + provision_info, + ); + + if context.init_connection().await.is_err() { + panic!("init_connection failed!"); + } + + if context.send_receive_spdm_digest(None).await.is_err() { + panic!("send_receive_spdm_digest failed!"); + } + + if context + .send_receive_spdm_certificate(None, 0) + .await + .is_err() + { + panic!("send_receive_spdm_certificate failed!"); + } + + if context + .send_receive_spdm_challenge( + 0, + SpdmMeasurementSummaryHashType::SpdmMeasurementSummaryHashTypeNone, + ) + .await + .is_err() + { + panic!("send_receive_spdm_challenge failed!"); + } + + let mut total_number: u8 = 0; + let mut spdm_measurement_record_structure = SpdmMeasurementRecordStructure::default(); + if context + .send_receive_spdm_measurement( + None, + 0, + SpdmMeasurementAttributes::SIGNATURE_REQUESTED, + SpdmMeasurementOperation::SpdmMeasurementRequestAll, + &mut total_number, + &mut spdm_measurement_record_structure, + ) + .await + .is_err() + { + panic!("send_receive_spdm_measurement failed!"); + } + + let session_id = context + .start_session( + false, + 0, + SpdmMeasurementSummaryHashType::SpdmMeasurementSummaryHashTypeNone, + ) + .await + .unwrap(); + + // ide_km test + let mut idekm_req_context = IdekmReqContext; + // ide_km query + let port_index = 0u8; + let mut dev_func_num = 0u8; + let mut bus_num = 0u8; + let mut segment = 0u8; + let mut max_port_index = 0u8; + let mut ide_reg_block = [0u32; PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT]; + let mut ide_reg_block_cnt = 0usize; + idekm_req_context + .pci_ide_km_query( + &mut context, + session_id, + port_index, + &mut dev_func_num, + &mut bus_num, + &mut segment, + &mut max_port_index, + &mut ide_reg_block, + &mut ide_reg_block_cnt, + ) + .await + .unwrap(); + + // ide_km key_prog key set 0 | RX | PR + let stream_id = 0u8; + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_RX; + let key_sub_stream = KEY_SUB_STREAM_PR; + let mut key_iv: Aes256GcmKeyBuffer; + key_iv = Default::default(); + get_random(&mut key_iv.key[0].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[1].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[2].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[3].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[4].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[5].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[6].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[7].to_le_bytes()).unwrap(); + key_iv.iv[0] = 0; + key_iv.iv[1] = 1; + let mut kp_ack_status = KpAckStatus::default(); + idekm_req_context + .pci_ide_km_key_prog( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + key_iv, + &mut kp_ack_status, + ) + .await + .unwrap(); + if kp_ack_status != KpAckStatus::SUCCESS { + panic!( + "KEY_PROG at Key Set 0 | RX | PR failed with {:X?}", + kp_ack_status + ); + } else { + println!("Successful KEY_PROG at Key Set 0 | RX | PR!"); + } + + // ide_km key_prog key set 0 | RX | NPR + let stream_id = 0u8; + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_RX; + let key_sub_stream = KEY_SUB_STREAM_NPR; + let mut key_iv: Aes256GcmKeyBuffer; + key_iv = Default::default(); + get_random(&mut key_iv.key[0].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[1].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[2].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[3].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[4].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[5].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[6].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[7].to_le_bytes()).unwrap(); + key_iv.iv[0] = 0; + key_iv.iv[1] = 1; + let mut kp_ack_status = KpAckStatus::default(); + idekm_req_context + .pci_ide_km_key_prog( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + key_iv, + &mut kp_ack_status, + ) + .await + .unwrap(); + if kp_ack_status != KpAckStatus::SUCCESS { + panic!( + "KEY_PROG at Key Set 0 | RX | NPR failed with {:X?}", + kp_ack_status + ); + } else { + println!("Successful KEY_PROG at Key Set 0 | RX | NPR!"); + } + + // ide_km key_prog key set 0 | RX | CPL + let stream_id = 0u8; + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_RX; + let key_sub_stream = KEY_SUB_STREAM_CPL; + let mut key_iv: Aes256GcmKeyBuffer; + key_iv = Default::default(); + get_random(&mut key_iv.key[0].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[1].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[2].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[3].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[4].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[5].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[6].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[7].to_le_bytes()).unwrap(); + key_iv.iv[0] = 0; + key_iv.iv[1] = 1; + let mut kp_ack_status = KpAckStatus::default(); + idekm_req_context + .pci_ide_km_key_prog( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + key_iv, + &mut kp_ack_status, + ) + .await + .unwrap(); + if kp_ack_status != KpAckStatus::SUCCESS { + panic!( + "KEY_PROG at Key Set 0 | RX | CPL failed with {:X?}", + kp_ack_status + ); + } else { + println!("Successful KEY_PROG at Key Set 0 | RX | CPL!"); + } + + // ide_km key_prog key set 0 | TX | PR + let stream_id = 0u8; + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_TX; + let key_sub_stream = KEY_SUB_STREAM_PR; + let mut key_iv: Aes256GcmKeyBuffer; + key_iv = Default::default(); + get_random(&mut key_iv.key[0].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[1].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[2].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[3].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[4].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[5].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[6].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[7].to_le_bytes()).unwrap(); + key_iv.iv[0] = 0; + key_iv.iv[1] = 1; + let mut kp_ack_status = KpAckStatus::default(); + idekm_req_context + .pci_ide_km_key_prog( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + key_iv, + &mut kp_ack_status, + ) + .await + .unwrap(); + if kp_ack_status != KpAckStatus::SUCCESS { + panic!( + "KEY_PROG at Key Set 0 | TX | PR failed with {:X?}", + kp_ack_status + ); + } else { + println!("Successful KEY_PROG at Key Set 0 | TX | PR!"); + } + + // ide_km key_prog key set 0 | TX | NPR + let stream_id = 0u8; + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_TX; + let key_sub_stream = KEY_SUB_STREAM_NPR; + let mut key_iv: Aes256GcmKeyBuffer; + key_iv = Default::default(); + get_random(&mut key_iv.key[0].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[1].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[2].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[3].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[4].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[5].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[6].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[7].to_le_bytes()).unwrap(); + key_iv.iv[0] = 0; + key_iv.iv[1] = 1; + let mut kp_ack_status = KpAckStatus::default(); + idekm_req_context + .pci_ide_km_key_prog( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + key_iv, + &mut kp_ack_status, + ) + .await + .unwrap(); + if kp_ack_status != KpAckStatus::SUCCESS { + panic!( + "KEY_PROG at Key Set 0 | TX | NPR failed with {:X?}", + kp_ack_status + ); + } else { + println!("Successful KEY_PROG at Key Set 0 | TX | NPR!"); + } + + // ide_km key_prog key set 0 | TX | CPL + let stream_id = 0u8; + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_TX; + let key_sub_stream = KEY_SUB_STREAM_CPL; + let mut key_iv: Aes256GcmKeyBuffer; + key_iv = Default::default(); + get_random(&mut key_iv.key[0].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[1].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[2].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[3].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[4].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[5].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[6].to_le_bytes()).unwrap(); + get_random(&mut key_iv.key[7].to_le_bytes()).unwrap(); + key_iv.iv[0] = 0; + key_iv.iv[1] = 1; + let mut kp_ack_status = KpAckStatus::default(); + idekm_req_context + .pci_ide_km_key_prog( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + key_iv, + &mut kp_ack_status, + ) + .await + .unwrap(); + if kp_ack_status != KpAckStatus::SUCCESS { + panic!( + "KEY_PROG at Key Set 0 | TX | CPL failed with {:X?}", + kp_ack_status + ); + } else { + println!("Successful KEY_PROG at Key Set 0 | TX | CPL!"); + } + + // ide_km key_set_go key set 0 | RX | PR + let stream_id = 0u8; + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_RX; + let key_sub_stream = KEY_SUB_STREAM_PR; + let port_index = 0u8; + idekm_req_context + .pci_ide_km_key_set_go( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + ) + .await + .unwrap(); + println!("Successful KEY_SET_GO at Key Set 0 | RX | PR!"); + + // ide_km key_set_go key set 0 | RX | NPR + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_RX; + let key_sub_stream = KEY_SUB_STREAM_NPR; + idekm_req_context + .pci_ide_km_key_set_go( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + ) + .await + .unwrap(); + println!("Successful KEY_SET_GO at Key Set 0 | RX | NPR!"); + + // ide_km key_set_go key set 0 | RX | CPL + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_RX; + let key_sub_stream = KEY_SUB_STREAM_CPL; + idekm_req_context + .pci_ide_km_key_set_go( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + ) + .await + .unwrap(); + println!("Successful KEY_SET_GO at Key Set 0 | RX | CPL!"); + + // ide_km key_set_go key set 0 | TX | PR + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_TX; + let key_sub_stream = KEY_SUB_STREAM_PR; + idekm_req_context + .pci_ide_km_key_set_go( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + ) + .await + .unwrap(); + println!("Successful KEY_SET_GO at Key Set 0 | TX | PR!"); + + // ide_km key_set_go key set 0 | TX | NPR + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_TX; + let key_sub_stream = KEY_SUB_STREAM_NPR; + idekm_req_context + .pci_ide_km_key_set_go( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + ) + .await + .unwrap(); + println!("Successful KEY_SET_GO at Key Set 0 | TX | NPR!"); + + // ide_km key_set_go key set 0 | TX | CPL + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_TX; + let key_sub_stream = KEY_SUB_STREAM_CPL; + idekm_req_context + .pci_ide_km_key_set_go( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + ) + .await + .unwrap(); + println!("Successful KEY_SET_GO at Key Set 0 | TX | CPL!"); + + // ide_km key_set_stop key set 0 | RX | PR + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_RX; + let key_sub_stream = KEY_SUB_STREAM_PR; + idekm_req_context + .pci_ide_km_key_set_stop( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + ) + .await + .unwrap(); + println!("Successful KEY_SET_STOP at Key Set 0 | RX | PR!"); + + // ide_km key_set_stop key set 0 | RX | NPR + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_RX; + let key_sub_stream = KEY_SUB_STREAM_NPR; + idekm_req_context + .pci_ide_km_key_set_stop( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + ) + .await + .unwrap(); + println!("Successful KEY_SET_STOP at Key Set 0 | RX | NPR!"); + + // ide_km key_set_stop key set 0 | RX | CPL + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_RX; + let key_sub_stream = KEY_SUB_STREAM_CPL; + idekm_req_context + .pci_ide_km_key_set_stop( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + ) + .await + .unwrap(); + println!("Successful KEY_SET_STOP at Key Set 0 | RX | CPL!"); + + // ide_km key_set_stop key set 0 | TX | PR + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_TX; + let key_sub_stream = KEY_SUB_STREAM_PR; + idekm_req_context + .pci_ide_km_key_set_stop( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + ) + .await + .unwrap(); + println!("Successful KEY_SET_STOP at Key Set 0 | TX | PR!"); + + // ide_km key_set_stop key set 0 | TX | NPR + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_TX; + let key_sub_stream = KEY_SUB_STREAM_NPR; + idekm_req_context + .pci_ide_km_key_set_stop( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + ) + .await + .unwrap(); + println!("Successful KEY_SET_STOP at Key Set 0 | TX | NPR!"); + + // ide_km key_set_stop key set 0 | TX | CPL + let key_set = KEY_SET_0; + let key_direction = KEY_DIRECTION_TX; + let key_sub_stream = KEY_SUB_STREAM_CPL; + idekm_req_context + .pci_ide_km_key_set_stop( + &mut context, + session_id, + stream_id, + key_set, + key_direction, + key_sub_stream, + port_index, + ) + .await + .unwrap(); + println!("Successful KEY_SET_STOP at Key Set 0 | TX | CPL!"); + + // end spdm session + context.end_session(session_id).await.unwrap(); +} + // A new logger enables the user to choose log level by setting a `SPDM_LOG` environment variable. // Use the `Trace` level by default. fn new_logger_from_env() -> SimpleLogger { @@ -435,11 +1122,17 @@ fn emu_main() { let socket_io_transport = SocketIoTransport::new(socket.clone()); let socket_io_transport: Arc> = Arc::new(Mutex::new(socket_io_transport)); + rt.block_on(test_spdm( socket_io_transport.clone(), transport_encap.clone(), )); + rt.block_on(test_idekm( + socket_io_transport.clone(), + transport_encap.clone(), + )); + rt.block_on(send_receive_stop(socket, transport_encap, transport_type)); } @@ -447,7 +1140,7 @@ fn main() { use std::thread; thread::Builder::new() - .stack_size(EMU_STACK_SIZE) + .stack_size(EMU_STACK_SIZE * 2) .spawn(emu_main) .unwrap() .join() diff --git a/test/spdm-responder-emu/Cargo.toml b/test/spdm-responder-emu/Cargo.toml index a99cc3f9..dce2a28a 100644 --- a/test/spdm-responder-emu/Cargo.toml +++ b/test/spdm-responder-emu/Cargo.toml @@ -9,6 +9,7 @@ edition = "2018" [dependencies] spdm-emu = { path = "../spdm-emu", default-features = false } spdmlib = { path = "../../spdmlib", default-features = false } +idekm = { path = "../../idekm", default-features = false } codec = { path = "../../codec" } mctp_transport = { path = "../../mctp_transport" } pcidoe_transport = { path = "../../pcidoe_transport" } diff --git a/test/spdm-responder-emu/src/main.rs b/test/spdm-responder-emu/src/main.rs index 6c3efb0a..8bd0d8bd 100644 --- a/test/spdm-responder-emu/src/main.rs +++ b/test/spdm-responder-emu/src/main.rs @@ -4,6 +4,10 @@ #![forbid(unsafe_code)] +mod spdm_device_example; +use spdm_device_example::init_device_instance; + +use idekm::pci_ide_km_responder::PCI_IDE_KM_INSTANCE; use log::LevelFilter; use simple_logger::SimpleLogger; use spdmlib::common::{SecuredMessageVersion, SpdmOpaqueSupport}; @@ -258,6 +262,7 @@ async fn handle_message( }; spdmlib::secret::asym_sign::register(SECRET_ASYM_IMPL_INSTANCE.clone()); + spdmlib::message::vendor::register_vendor_defined_struct(PCI_IDE_KM_INSTANCE); let mut context = responder::ResponderContext::new( socket_io_transport, transport_encap, @@ -416,6 +421,7 @@ pub async fn send_pci_discovery( fn main() { use std::thread; + init_device_instance(); thread::Builder::new() .stack_size(EMU_STACK_SIZE) diff --git a/test/spdm-responder-emu/src/spdm_device_example.rs b/test/spdm-responder-emu/src/spdm_device_example.rs new file mode 100644 index 00000000..461e4239 --- /dev/null +++ b/test/spdm-responder-emu/src/spdm_device_example.rs @@ -0,0 +1,89 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use idekm::{ + pci_ide_km_responder::{ + pci_ide_km_rsp_key_prog::{self, PciIdeKmDeviceKeyProg}, + pci_ide_km_rsp_key_set_go::{self, PciIdeKmDeviceKeySetGo}, + pci_ide_km_rsp_key_set_stop::{self, PciIdeKmDeviceKeySetStop}, + pci_ide_km_rsp_query::{self, PciIdeKmDeviceQuery}, + }, + pci_idekm::{Aes256GcmKeyBuffer, KpAckStatus, PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT}, +}; +use spdmlib::error::SpdmResult; + +fn pci_ide_km_device_key_prog( + // IN + stream_id: u8, + key_set: u8, + key_direction: u8, + key_sub_stream: u8, + port_index: u8, + key_iv: Aes256GcmKeyBuffer, + // OUT + status: &mut KpAckStatus, +) -> SpdmResult { + *status = KpAckStatus::SUCCESS; + log::info!("{stream_id:X?}, {key_set:X?}, {key_direction:X?}, {key_sub_stream:X?}, {port_index:X?}, {key_iv:X?}, {status:X?}!"); + Ok(()) +} + +fn pci_ide_km_device_key_set_go( + stream_id: u8, + key_set: u8, + key_direction: u8, + key_sub_stream: u8, + port_index: u8, +) -> SpdmResult { + log::info!( + "{stream_id:X?}, {key_set:X?}, {key_direction:X?}, {key_sub_stream:X?}, {port_index:X?}!" + ); + Ok(()) +} + +fn pci_ide_km_device_key_set_stop( + stream_id: u8, + key_set: u8, + key_direction: u8, + key_sub_stream: u8, + port_index: u8, +) -> SpdmResult { + log::info!( + "{stream_id:X?}, {key_set:X?}, {key_direction:X?}, {key_sub_stream:X?}, {port_index:X?}!" + ); + Ok(()) +} + +fn pci_ide_km_device_query( + port_index: u8, + dev_func_num: &mut u8, + bus_num: &mut u8, + segment: &mut u8, + max_port_index: &mut u8, + ide_reg_block: &mut [u32; PCI_IDE_KM_IDE_REG_BLOCK_MAX_COUNT], + ide_reg_block_cnt: &mut usize, +) -> SpdmResult { + *dev_func_num = 0; + *bus_num = 0x6a; + *segment = 1; + *max_port_index = 1; + *ide_reg_block_cnt = 2; + log::info!("{port_index:X?}, {dev_func_num:X?}, {bus_num:X?}, {segment:X?}, {max_port_index:X?}, {ide_reg_block:X?}, {ide_reg_block_cnt:X?}!"); + Ok(()) +} + +pub fn init_device_instance() { + pci_ide_km_rsp_key_prog::register(PciIdeKmDeviceKeyProg { + pci_ide_km_device_key_prog_cb: pci_ide_km_device_key_prog, + }); + pci_ide_km_rsp_key_set_go::register(PciIdeKmDeviceKeySetGo { + pci_ide_km_device_key_set_go_cb: pci_ide_km_device_key_set_go, + }); + pci_ide_km_rsp_key_set_stop::register(PciIdeKmDeviceKeySetStop { + pci_ide_km_device_key_set_stop_cb: pci_ide_km_device_key_set_stop, + }); + pci_ide_km_rsp_query::register(PciIdeKmDeviceQuery { + pci_ide_km_device_query_cb: pci_ide_km_device_query, + }); +}