diff --git a/test/spdmlib-test/Cargo.toml b/test/spdmlib-test/Cargo.toml index 77f7bf1a..77e5bb65 100644 --- a/test/spdmlib-test/Cargo.toml +++ b/test/spdmlib-test/Cargo.toml @@ -7,7 +7,7 @@ edition = "2021" [dependencies] spdmlib = { path = "../../spdmlib", default-features = false, features=["spdm-ring"] } -codec = { path = "../../codec" } +codec = { path = "../../codec", features = ["alloc"] } log = "0.4.13" ring = { version = "0.16.20" } bytes = { version="1", default-features=false } diff --git a/test/spdmlib-test/src/common/crypto_callback.rs b/test/spdmlib-test/src/common/crypto_callback.rs index 53469b71..4161dbc9 100644 --- a/test/spdmlib-test/src/common/crypto_callback.rs +++ b/test/spdmlib-test/src/common/crypto_callback.rs @@ -175,5 +175,10 @@ fn fake_verify_cert_chain(_cert_chain: &[u8]) -> SpdmResult { #[test] // Make sure this is the first test case running by `cargo test` fn test_0_crypto_init() { + use super::secret_callback::FAKE_SECRET_ASYM_IMPL_INSTANCE; spdmlib::crypto::aead::register(FAKE_AEAD.clone()); + spdmlib::crypto::asym_verify::register(FAKE_ASYM_VERIFY.clone()); + spdmlib::crypto::aead::register(FAKE_AEAD.clone()); + spdmlib::crypto::rand::register(FAKE_RAND.clone()); + spdmlib::secret::asym_sign::register(FAKE_SECRET_ASYM_IMPL_INSTANCE.clone()); } diff --git a/test/spdmlib-test/src/common/device_io.rs b/test/spdmlib-test/src/common/device_io.rs index 62cbd340..5e049c68 100644 --- a/test/spdmlib-test/src/common/device_io.rs +++ b/test/spdmlib-test/src/common/device_io.rs @@ -5,9 +5,9 @@ #![allow(unused)] use async_trait::async_trait; -use spdmlib::common::{SpdmDeviceIo, ST1}; +use spdmlib::common::{SpdmDeviceIo, SpdmTransportEncap, ST1}; use spdmlib::config::RECEIVER_BUFFER_SIZE; -use spdmlib::error::{SpdmResult, SPDM_STATUS_ERROR_PEER}; +use spdmlib::error::{SpdmResult, SPDM_STATUS_DECAP_FAIL, SPDM_STATUS_ERROR_PEER}; use spdmlib::responder; use std::cell::RefCell; use std::collections::VecDeque; @@ -246,3 +246,156 @@ fn test_fake_device_io() { }; executor::block_on(future); } + +pub struct TestTransportEncap; +#[async_trait] +impl SpdmTransportEncap for TestTransportEncap { + async fn encap( + &mut self, + spdm_buffer: Arc<&[u8]>, + transport_buffer: Arc>, + secured_message: bool, + ) -> SpdmResult { + // format + // secure_message u8 + let mut transport_buffer = transport_buffer.lock(); + let len = spdm_buffer.len(); + transport_buffer[0] = secured_message as u8; + + if transport_buffer.len() < len + 1 { + return Err(SPDM_STATUS_DECAP_FAIL); + } + transport_buffer[1..(1 + len)].copy_from_slice(&spdm_buffer[..]); + Ok(1 + len) + } + + async fn decap( + &mut self, + transport_buffer: Arc<&[u8]>, + spdm_buffer: Arc>, + ) -> SpdmResult<(usize, bool)> { + let mut spdm_buffer = spdm_buffer.lock(); + let spdm_buffer_len = transport_buffer.len() - 1; + let secure_message = if transport_buffer[0] == 0 { + false + } else { + true + }; + spdm_buffer[0..spdm_buffer_len].copy_from_slice(&transport_buffer[1..]); + Ok((spdm_buffer_len, secure_message)) + } + + async fn encap_app( + &mut self, + spdm_buffer: Arc<&[u8]>, + app_buffer: Arc>, + _is_app_message: bool, + ) -> SpdmResult { + let mut app_buffer = app_buffer.lock(); + app_buffer[0..spdm_buffer.len()].copy_from_slice(&spdm_buffer); + Ok(spdm_buffer.len()) + } + + async fn decap_app( + &mut self, + app_buffer: Arc<&[u8]>, + spdm_buffer: Arc>, + ) -> SpdmResult<(usize, bool)> { + let mut spdm_buffer = spdm_buffer.lock(); + spdm_buffer[0..app_buffer.len()].copy_from_slice(&app_buffer); + Ok((app_buffer.len(), false)) + } + fn get_sequence_number_count(&mut self) -> u8 { + todo!() + } + + fn get_max_random_count(&mut self) -> u16 { + todo!() + } +} + +pub struct TestSpdmDeviceIo { + pub rx: Arc>>, + pub tx: Arc>>, +} + +impl TestSpdmDeviceIo { + pub fn new(rx: Arc>>, tx: Arc>>) -> Self { + Self { rx, tx } + } +} + +#[async_trait] +impl SpdmDeviceIo for TestSpdmDeviceIo { + async fn receive( + &mut self, + out_buffer: Arc>, + _timeout: usize, + ) -> Result { + let mut rx = self.rx.lock(); + if (rx.len() < 4) { + return Err(0); + } + // Length 4 bytes + let length_buf: Vec = rx.drain(0..4).collect(); + let length = + u32::from_le_bytes([length_buf[0], length_buf[1], length_buf[2], length_buf[3]]); + let length = length as usize; + // Data length bytes + let mut out_buffer = out_buffer.lock(); + if out_buffer.len() < length { + return Err(0); + } + for index in 0..length { + out_buffer[index] = rx.pop_front().unwrap(); + } + println!("RECV RAW - {:02x?}", &out_buffer[..length]); + Ok(length) + } + async fn send(&mut self, buffer: Arc<&[u8]>) -> SpdmResult { + { + let mut tx = self.tx.lock(); + let length = buffer.len() as u32; + tx.extend(length.to_le_bytes()); + tx.extend(buffer.iter()); + } + println!("SEND RAW - {:02x?}", &buffer); + Ok(()) + } + + async fn flush_all(&mut self) -> SpdmResult { + Ok(()) + } +} + +pub fn test_header_generater_callback(secure: u8, spdm_msg: &[u8]) -> VecDeque { + // This function is used to generate the header + // Note: The same method as device_io and transport encap should be use + // Current implementation is for TestDeviceIo and TestTransportEncap + let mut ret = VecDeque::new(); + let length = (spdm_msg.len() + 1) as u32; + ret.extend(length.to_le_bytes()); + ret.push_back(secure); + ret.extend(spdm_msg); + ret +} + +#[test] +fn test_test_device_io() { + let rx = Arc::new(Mutex::new(VecDeque::::new())); + let tx = Arc::new(Mutex::new(VecDeque::::new())); + let rx_shared = Arc::clone(&rx); + let tx_shared = Arc::clone(&tx); + let future = async { + let mut server = TestSpdmDeviceIo::new(rx, tx); + let _ = server.send(Arc::new(b"hello")).await; + }; + executor::block_on(future); + + let tx = tx_shared.lock(); + let res = tx.as_slices(); + assert_eq!( + res.0, + [0x05, 0x00, 0x00, 0x00, 0x68, 0x65, 0x6c, 0x6c, 0x6f] + ) +} diff --git a/test/spdmlib-test/src/common/secret_callback.rs b/test/spdmlib-test/src/common/secret_callback.rs index 9295f2bf..7ea828f1 100644 --- a/test/spdmlib-test/src/common/secret_callback.rs +++ b/test/spdmlib-test/src/common/secret_callback.rs @@ -26,6 +26,9 @@ pub static SECRET_PSK_IMPL_INSTANCE: SpdmSecretPsk = SpdmSecretPsk { pub static SECRET_ASYM_IMPL_INSTANCE: SpdmSecretAsymSign = SpdmSecretAsymSign { sign_cb: asym_sign }; +pub static FAKE_SECRET_ASYM_IMPL_INSTANCE: SpdmSecretAsymSign = SpdmSecretAsymSign { + sign_cb: fake_asym_sign, +}; #[allow(clippy::field_reassign_with_default)] fn measurement_collection_impl( @@ -317,3 +320,27 @@ fn sign_ecdsa_asym_algo( data: full_signature, }) } + +fn fake_asym_sign( + base_hash_algo: SpdmBaseHashAlgo, + base_asym_algo: SpdmBaseAsymAlgo, + data: &[u8], +) -> Option { + match (base_hash_algo, base_asym_algo) { + (SpdmBaseHashAlgo::TPM_ALG_SHA_256, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P256) => { + Some(SpdmSignatureStruct { + data_size: 64, + data: [0x5a; SPDM_MAX_ASYM_KEY_SIZE], + }) + } + (SpdmBaseHashAlgo::TPM_ALG_SHA_384, SpdmBaseAsymAlgo::TPM_ALG_ECDSA_ECC_NIST_P384) => { + Some(SpdmSignatureStruct { + data_size: 96, + data: [0x5a; SPDM_MAX_ASYM_KEY_SIZE], + }) + } + _ => { + panic!(); + } + } +} diff --git a/test/spdmlib-test/src/common/util.rs b/test/spdmlib-test/src/common/util.rs index 2c6c9026..be8000e4 100644 --- a/test/spdmlib-test/src/common/util.rs +++ b/test/spdmlib-test/src/common/util.rs @@ -4,24 +4,29 @@ #![allow(unused)] +use super::device_io::TestSpdmDeviceIo; use super::USE_ECDSA; -use crate::common::device_io::MySpdmDeviceIo; +use crate::common::device_io::{MySpdmDeviceIo, TestTransportEncap}; use crate::common::secret_callback::SECRET_ASYM_IMPL_INSTANCE; use crate::common::transport::PciDoeTransportEncap; -use codec::{Reader, Writer}; +use codec::{Codec, Reader, Writer}; use spdmlib::common::{ SpdmCodec, SpdmConfigInfo, SpdmContext, SpdmDeviceIo, SpdmOpaqueSupport, SpdmProvisionInfo, - SpdmTransportEncap, DMTF_SECURE_SPDM_VERSION_10, DMTF_SECURE_SPDM_VERSION_11, + SpdmTransportEncap, DMTF_SECURE_SPDM_VERSION_10, DMTF_SECURE_SPDM_VERSION_11, ST1, }; -use spdmlib::config; +use spdmlib::config::MAX_SPDM_MSG_SIZE; use spdmlib::crypto; use spdmlib::message::SpdmMessage; use spdmlib::protocol::*; +use spdmlib::{config, responder}; +use std::fs::File; +use std::io::Read; use std::path::PathBuf; use spin::Mutex; extern crate alloc; use alloc::boxed::Box; +use alloc::collections::VecDeque; use alloc::sync::Arc; use core::ops::DerefMut; @@ -395,3 +400,116 @@ pub fn get_rsp_cert_chain_buff() -> SpdmCertChainBuffer { SpdmCertChainBuffer::new(cert_chain, root_cert_hash.as_ref()) .expect("Create format certificate chain failed.") } + +#[derive(Debug, PartialEq, Eq)] +pub struct TestSpdmMessage { + pub message: crate::protocol::Message, + pub secure: u8, // secure message +} + +#[derive(Debug, PartialEq, Eq)] +pub struct TestCase { + pub input: Vec, + pub expected: Vec, +} + +impl TestCase { + pub fn config() -> (SpdmConfigInfo, SpdmProvisionInfo) { + create_info() + } + + pub fn input_to_vec(&self, cb: fn(secure: u8, bufer: &[u8]) -> VecDeque) -> VecDeque { + let mut ret = VecDeque::new(); + for data in &self.input { + let mut buffer = vec![0u8; MAX_SPDM_MSG_SIZE]; + let writer = &mut Writer::init(&mut buffer[..]); + let len = data + .message + .encode(writer) + .expect("Error to encode input message"); + ret.extend((cb)(data.secure, &buffer[..len]).iter()) + } + ret + } + pub fn expected_to_vec( + &self, + cb: fn(secure: u8, bufer: &[u8]) -> VecDeque, + ) -> VecDeque { + let mut ret = VecDeque::new(); + for data in &self.expected { + let mut buffer = vec![0u8; MAX_SPDM_MSG_SIZE]; + let writer = &mut Writer::init(&mut buffer[..]); + let len = data + .message + .encode(writer) + .expect("Error to encode input message"); + ret.extend((cb)(data.secure, &buffer[..len]).iter()) + } + ret + } + + pub fn get_certificate_chain_buffer( + hash_algo: SpdmBaseHashAlgo, + cert_chain: &[u8], + ) -> SpdmCertChainBuffer { + let (root_cert_begin, root_cert_end) = + crypto::cert_operation::get_cert_from_cert_chain(cert_chain, 0) + .expect("Get provisioned root cert failed"); + + let root_cert_hash = + crypto::hash::hash_all(hash_algo, &cert_chain[root_cert_begin..root_cert_end]) + .expect("Must provide hash algo"); + SpdmCertChainBuffer::new(cert_chain, root_cert_hash.as_ref()) + .expect("Create format certificate chain failed.") + } +} + +pub struct ResponderRunner; +impl ResponderRunner { + pub fn run(case: TestCase, cb: fn(secure: u8, bufer: &[u8]) -> VecDeque) -> bool { + use super::secret_callback::FAKE_SECRET_ASYM_IMPL_INSTANCE; + use crate::common::crypto_callback::{FAKE_AEAD, FAKE_ASYM_VERIFY, FAKE_RAND}; + spdmlib::crypto::aead::register(FAKE_AEAD.clone()); + spdmlib::crypto::rand::register(FAKE_RAND.clone()); + spdmlib::crypto::asym_verify::register(FAKE_ASYM_VERIFY.clone()); + spdmlib::secret::asym_sign::register(FAKE_SECRET_ASYM_IMPL_INSTANCE.clone()); + + let mut output = Arc::new(Mutex::new(VecDeque::::new())); + let mut rx = Arc::new(Mutex::new(case.input_to_vec(cb))); + let mut output_ref = Arc::clone(&output); + log::debug!("intput : {:02x?}", rx.lock().make_contiguous()); + let future = async { + let mut device_io = TestSpdmDeviceIo::new(rx, output_ref); + let mut transport_encap = TestTransportEncap; + let (config_info, provision_info) = TestCase::config(); + let mut context = responder::ResponderContext::new( + Arc::new(Mutex::new(device_io)), + Arc::new(Mutex::new(transport_encap)), + config_info, + provision_info, + ); + let raw_packet = &mut [0u8; spdmlib::config::RECEIVER_BUFFER_SIZE]; + loop { + let result = context.process_message(false, &[0], raw_packet).await; + match result { + Err(nread) => { + if nread == 0 { + break; + } + } + Ok(_) => continue, + } + } + }; + executor::block_on(future); + // Check Result + // output and case.expected + let mut expected = case.expected_to_vec(cb); + let mut output = output.lock(); + let output = output.make_contiguous(); + let expected = expected.make_contiguous(); + log::debug!("output : {:02x?}\n", output); + log::debug!("expected: {:02x?}\n", expected); + output == expected + } +} diff --git a/test/spdmlib-test/src/lib.rs b/test/spdmlib-test/src/lib.rs index 9f63b90d..b2ae9ffe 100644 --- a/test/spdmlib-test/src/lib.rs +++ b/test/spdmlib-test/src/lib.rs @@ -5,6 +5,7 @@ #![forbid(unsafe_code)] pub mod common; +pub mod protocol; #[cfg(test)] mod test_client_server; diff --git a/test/spdmlib-test/src/protocol/algorithm.rs b/test/spdmlib-test/src/protocol/algorithm.rs new file mode 100644 index 00000000..ed5f1d51 --- /dev/null +++ b/test/spdmlib-test/src/protocol/algorithm.rs @@ -0,0 +1,174 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use codec::Codec; + +const ALG_STRUCT_SIZE: usize = 4usize; + +#[derive(Debug, PartialEq, Eq)] +pub struct NEGOTIATE_ALGORITHMS { + pub SPDMVersion: u8, + pub RequestResponseCode: u8, + pub Param1: u8, + pub Param2: u8, + pub Length: u16, + pub MeasurementSpecification: u8, + pub OtherParamsSupport: u8, + pub BaseAsymAlgo: u32, + pub BaseHashAlgo: u32, + pub _Reserved1: [u8; 12], + pub ExtAsymCount: u8, + pub ExtHashCount: u8, + pub _Reserved2: [u8; 2], + pub ExtAsym: Vec, + pub Exthash: Vec, + pub AlgStruct: Vec<[u8; ALG_STRUCT_SIZE]>, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct ALGORITHMS { + pub SPDMVersion: u8, + pub RequestResponseCode: u8, + pub Param1: u8, // number of AlgStruct + pub Param2: u8, + pub Length: u16, + pub MeasurementSpecification: u8, + pub OtherParamsSupport: u8, + // Response have this extra(MeasurementHashAlgo) field than the requester + pub MeasurementHashAlgo: u32, + pub BaseAsymAlgo: u32, + pub BaseHashAlgo: u32, + pub _Reserved1: [u8; 12], + pub ExtAsymCount: u8, + pub ExtHashCount: u8, + pub _Reserved2: [u8; 2], + pub ExtAsym: Vec, + pub Exthash: Vec, + pub AlgStruct: Vec<[u8; ALG_STRUCT_SIZE]>, +} + +impl Codec for NEGOTIATE_ALGORITHMS { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let used = bytes.used(); + let _ = self.SPDMVersion.encode(bytes)?; + let _ = self.RequestResponseCode.encode(bytes)?; + let _ = self.Param1.encode(bytes)?; + let _ = self.Param2.encode(bytes)?; + let _ = self.Length.encode(bytes)?; + let _ = self.MeasurementSpecification.encode(bytes)?; + let _ = self.OtherParamsSupport.encode(bytes)?; + let _ = self.BaseAsymAlgo.encode(bytes)?; + let _ = self.BaseHashAlgo.encode(bytes)?; + let _ = self._Reserved1.encode(bytes)?; + let _ = self.ExtAsymCount.encode(bytes)?; + let _ = self.ExtHashCount.encode(bytes)?; + let _ = self._Reserved2.encode(bytes)?; + let _ = self.ExtAsym.encode(bytes)?; + let _ = self.Exthash.encode(bytes)?; + let _ = self.AlgStruct.encode(bytes)?; + assert_eq!(bytes.used() - used, self.Length as usize); + Ok(bytes.used() - used) + } + + fn read(reader: &mut codec::Reader) -> Option { + let SPDMVersion = u8::read(reader)?; + let RequestResponseCode = u8::read(reader)?; + let Param1 = u8::read(reader)?; + let Param2 = u8::read(reader)?; + let Length = u16::read(reader)?; + let MeasurementSpecification = u8::read(reader)?; + let OtherParamsSupport = u8::read(reader)?; + let BaseAsymAlgo = u32::read(reader)?; + let BaseHashAlgo = u32::read(reader)?; + let _Reserved1 = <[u8; 12]>::read(reader)?; + let ExtAsymCount = u8::read(reader)?; + let ExtHashCount = u8::read(reader)?; + let _Reserved2 = <[u8; 2]>::read(reader)?; + let ExtAsym: Vec = Vec::::read_vec(reader, ExtAsymCount as usize * 4)?; + let Exthash: Vec = Vec::::read_vec(reader, ExtAsymCount as usize * 4)?; + let AlgStruct = Vec::<[u8; ALG_STRUCT_SIZE]>::read_vec(reader, Param1 as usize)?; + Some(NEGOTIATE_ALGORITHMS { + SPDMVersion, + RequestResponseCode, + Param1, + Param2, + Length, + MeasurementSpecification, + OtherParamsSupport, + BaseAsymAlgo, + BaseHashAlgo, + _Reserved1, + ExtAsymCount, + ExtHashCount, + _Reserved2, + ExtAsym, + Exthash, + AlgStruct, + }) + } +} + +impl Codec for ALGORITHMS { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let used = bytes.used(); + let _ = self.SPDMVersion.encode(bytes)?; + let _ = self.RequestResponseCode.encode(bytes)?; + let _ = self.Param1.encode(bytes)?; + let _ = self.Param2.encode(bytes)?; + let _ = self.Length.encode(bytes)?; + let _ = self.MeasurementSpecification.encode(bytes)?; + let _ = self.OtherParamsSupport.encode(bytes)?; + let _ = self.MeasurementHashAlgo.encode(bytes)?; + let _ = self.BaseAsymAlgo.encode(bytes)?; + let _ = self.BaseHashAlgo.encode(bytes)?; + let _ = self._Reserved1.encode(bytes)?; + let _ = self.ExtAsymCount.encode(bytes)?; + let _ = self.ExtHashCount.encode(bytes)?; + let _ = self._Reserved2.encode(bytes)?; + let _ = self.ExtAsym.encode(bytes)?; + let _ = self.Exthash.encode(bytes)?; + let _ = self.AlgStruct.encode(bytes)?; + assert_eq!(bytes.used() - used, self.Length as usize); + Ok(bytes.used() - used) + } + + fn read(reader: &mut codec::Reader) -> Option { + let SPDMVersion = u8::read(reader)?; + let RequestResponseCode = u8::read(reader)?; + let Param1 = u8::read(reader)?; + let Param2 = u8::read(reader)?; + let Length = u16::read(reader)?; + let MeasurementSpecification = u8::read(reader)?; + let OtherParamsSupport = u8::read(reader)?; + let MeasurementHashAlgo = u32::read(reader)?; + let BaseAsymAlgo = u32::read(reader)?; + let BaseHashAlgo = u32::read(reader)?; + let _Reserved1 = <[u8; 12]>::read(reader)?; + let ExtAsymCount = u8::read(reader)?; + let ExtHashCount = u8::read(reader)?; + let _Reserved2 = <[u8; 2]>::read(reader)?; + let ExtAsym: Vec = Vec::::read_vec(reader, ExtAsymCount as usize * 4)?; + let Exthash: Vec = Vec::::read_vec(reader, ExtAsymCount as usize * 4)?; + let AlgStruct = Vec::<[u8; ALG_STRUCT_SIZE]>::read_vec(reader, Param1 as usize)?; + Some(ALGORITHMS { + SPDMVersion, + RequestResponseCode, + Param1, + Param2, + Length, + MeasurementSpecification, + OtherParamsSupport, + MeasurementHashAlgo, + BaseAsymAlgo, + BaseHashAlgo, + _Reserved1, + ExtAsymCount, + ExtHashCount, + _Reserved2, + ExtAsym, + Exthash, + AlgStruct, + }) + } +} diff --git a/test/spdmlib-test/src/protocol/capability.rs b/test/spdmlib-test/src/protocol/capability.rs new file mode 100644 index 00000000..a751a7f6 --- /dev/null +++ b/test/spdmlib-test/src/protocol/capability.rs @@ -0,0 +1,117 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use codec::Codec; + +#[derive(Debug, PartialEq, Eq)] +pub struct GET_CAPABILITIES { + pub SPDMVersion: u8, + pub RequestResponseCode: u8, + pub Param1: u8, + pub Param2: u8, + pub _Reserved: u8, + pub CTExponent: u8, + pub _Reserved2: u16, + pub Flags: u32, + pub DataTransferSize: u32, + pub MaxSPDMmsgSize: u32, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct CAPABILITIES { + pub SPDMVersion: u8, + pub RequestResponseCode: u8, + pub Param1: u8, + pub Param2: u8, + pub _Reserved: u8, + pub CTExponent: u8, + pub _Reserved2: u16, + pub Flags: u32, + pub DataTransferSize: u32, + pub MaxSPDMmsgSize: u32, +} + +impl Codec for GET_CAPABILITIES { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let used = bytes.used(); + let _ = self.SPDMVersion.encode(bytes)?; + let _ = self.RequestResponseCode.encode(bytes)?; + let _ = self.Param1.encode(bytes)?; + let _ = self.Param2.encode(bytes)?; + let _ = self._Reserved.encode(bytes)?; + let _ = self.CTExponent.encode(bytes)?; + let _ = self._Reserved2.encode(bytes)?; + let _ = self.Flags.encode(bytes)?; + let _ = self.DataTransferSize.encode(bytes)?; + let _ = self.MaxSPDMmsgSize.encode(bytes)?; + Ok(bytes.used() - used) + } + + fn read(reader: &mut codec::Reader) -> Option { + let SPDMVersion = u8::read(reader)?; + let RequestResponseCode = u8::read(reader)?; + let Param1 = u8::read(reader)?; + let Param2 = u8::read(reader)?; + let _Reserved = u8::read(reader)?; + let CTExponent = u8::read(reader)?; + let _Reserved2 = u16::read(reader)?; + let Flags = u32::read(reader)?; + let DataTransferSize = u32::read(reader)?; + let MaxSPDMmsgSize = u32::read(reader)?; + Some(GET_CAPABILITIES { + SPDMVersion, + RequestResponseCode, + Param1, + Param2, + _Reserved, + CTExponent, + _Reserved2, + Flags, + DataTransferSize, + MaxSPDMmsgSize, + }) + } +} + +impl Codec for CAPABILITIES { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let used = bytes.used(); + let _ = self.SPDMVersion.encode(bytes)?; + let _ = self.RequestResponseCode.encode(bytes)?; + let _ = self.Param1.encode(bytes)?; + let _ = self.Param2.encode(bytes)?; + let _ = self._Reserved.encode(bytes)?; + let _ = self.CTExponent.encode(bytes)?; + let _ = self._Reserved2.encode(bytes)?; + let _ = self.Flags.encode(bytes)?; + let _ = self.DataTransferSize.encode(bytes)?; + let _ = self.MaxSPDMmsgSize.encode(bytes)?; + Ok(bytes.used() - used) + } + + fn read(reader: &mut codec::Reader) -> Option { + let SPDMVersion = u8::read(reader)?; + let RequestResponseCode = u8::read(reader)?; + let Param1 = u8::read(reader)?; + let Param2 = u8::read(reader)?; + let _Reserved = u8::read(reader)?; + let CTExponent = u8::read(reader)?; + let _Reserved2 = u16::read(reader)?; + let Flags = u32::read(reader)?; + let DataTransferSize = u32::read(reader)?; + let MaxSPDMmsgSize = u32::read(reader)?; + Some(CAPABILITIES { + SPDMVersion, + RequestResponseCode, + Param1, + Param2, + _Reserved, + CTExponent, + _Reserved2, + Flags, + DataTransferSize, + MaxSPDMmsgSize, + }) + } +} diff --git a/test/spdmlib-test/src/protocol/certificate.rs b/test/spdmlib-test/src/protocol/certificate.rs new file mode 100644 index 00000000..298afc13 --- /dev/null +++ b/test/spdmlib-test/src/protocol/certificate.rs @@ -0,0 +1,90 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use codec::Codec; + +#[derive(Debug, PartialEq, Eq)] +pub struct GET_CERTIFICATE { + pub SPDMVersion: u8, + pub RequestResponseCode: u8, + pub Param1: u8, + pub Param2: u8, + pub Offset: u16, + pub Length: u16, +} + +impl Codec for GET_CERTIFICATE { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let used = bytes.used(); + let _ = self.SPDMVersion.encode(bytes)?; + let _ = self.RequestResponseCode.encode(bytes)?; + let _ = self.Param1.encode(bytes)?; + let _ = self.Param2.encode(bytes)?; + let _ = self.Offset.encode(bytes)?; + let _ = self.Length.encode(bytes)?; + Ok(bytes.used() - used) + } + + fn read(reader: &mut codec::Reader) -> Option { + let SPDMVersion = u8::read(reader)?; + let RequestResponseCode = u8::read(reader)?; + let Param1 = u8::read(reader)?; + let Param2 = u8::read(reader)?; + let Offset = u16::read(reader)?; + let Length = u16::read(reader)?; + Some(GET_CERTIFICATE { + SPDMVersion, + RequestResponseCode, + Param1, + Param2, + Offset, + Length, + }) + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct CERTIFICATE { + pub SPDMVersion: u8, + pub RequestResponseCode: u8, + pub Param1: u8, + pub Param2: u8, + pub PortionLength: u16, + pub RemainderLength: u16, + pub CertChain: Vec, +} + +impl Codec for CERTIFICATE { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let used = bytes.used(); + let _ = self.SPDMVersion.encode(bytes)?; + let _ = self.RequestResponseCode.encode(bytes)?; + let _ = self.Param1.encode(bytes)?; + let _ = self.Param2.encode(bytes)?; + let _ = self.PortionLength.encode(bytes)?; + let _ = self.RemainderLength.encode(bytes)?; + let _ = self.CertChain.encode(bytes)?; + Ok(bytes.used() - used) + } + + fn read(reader: &mut codec::Reader) -> Option { + let SPDMVersion = u8::read(reader)?; + let RequestResponseCode = u8::read(reader)?; + let Param1 = u8::read(reader)?; + let Param2 = u8::read(reader)?; + let PortionLength = u16::read(reader)?; + let RemainderLength = u16::read(reader)?; + let CertChain = Vec::::read_vec(reader, PortionLength as usize)?; + + Some(CERTIFICATE { + SPDMVersion, + RequestResponseCode, + Param1, + Param2, + PortionLength, + RemainderLength, + CertChain, + }) + } +} diff --git a/test/spdmlib-test/src/protocol/challenge.rs b/test/spdmlib-test/src/protocol/challenge.rs new file mode 100644 index 00000000..05b19342 --- /dev/null +++ b/test/spdmlib-test/src/protocol/challenge.rs @@ -0,0 +1,105 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use codec::Codec; + +#[derive(Debug, PartialEq, Eq)] +pub struct CHALLENGE { + pub SPDMVersion: u8, + pub RequestResponseCode: u8, + pub Param1: u8, + pub Param2: u8, + pub Nonce: [u8; 32], +} + +impl Codec for CHALLENGE { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let used = bytes.used(); + let _ = self.SPDMVersion.encode(bytes)?; + let _ = self.RequestResponseCode.encode(bytes)?; + let _ = self.Param1.encode(bytes)?; + let _ = self.Param2.encode(bytes)?; + let _ = self.Nonce.encode(bytes)?; + Ok(bytes.used() - used) + } + + fn read(reader: &mut codec::Reader) -> Option { + let SPDMVersion = u8::read(reader)?; + let RequestResponseCode = u8::read(reader)?; + let Param1 = u8::read(reader)?; + let Param2 = u8::read(reader)?; + let Nonce = <[u8; 32]>::read(reader)?; + Some(CHALLENGE { + SPDMVersion, + RequestResponseCode, + Param1, + Param2, + Nonce, + }) + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct CHALLENGE_AUTH { + pub SPDMVersion: u8, + pub RequestResponseCode: u8, + pub Param1: u8, + pub Param2: u8, + pub CertChainHash: Vec, // Size(bytes) H + pub Nonce: [u8; 32], + pub MeasurementSummaryHash: Vec, + pub OpaqueDataLength: u16, + pub OpaqueData: Vec, + pub Signature: Vec, // Size(bytes) SigLen +} + +impl CHALLENGE_AUTH { + pub fn new(reader: &mut codec::Reader, H: usize, SigLen: usize) -> Option { + let SPDMVersion = u8::read(reader)?; + let RequestResponseCode = u8::read(reader)?; + let Param1 = u8::read(reader)?; + let Param2 = u8::read(reader)?; + let CertChainHash: Vec = Vec::::read_vec(reader, H)?; + let Nonce = <[u8; 32]>::read(reader)?; + let MeasurementSummaryHash: Vec = Vec::::read_vec(reader, H)?; + let OpaqueDataLength = u16::read(reader)?; + let OpaqueData: Vec = Vec::::read_vec(reader, OpaqueDataLength as usize)?; + let Signature: Vec = Vec::::read_vec(reader, SigLen as usize)?; + + Some(CHALLENGE_AUTH { + SPDMVersion, + RequestResponseCode, + Param1, + Param2, + CertChainHash, + Nonce, + MeasurementSummaryHash, + OpaqueDataLength, + OpaqueData, + Signature, + }) + } +} + +impl Codec for CHALLENGE_AUTH { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let used = bytes.used(); + let _ = self.SPDMVersion.encode(bytes)?; + let _ = self.RequestResponseCode.encode(bytes)?; + let _ = self.Param1.encode(bytes)?; + let _ = self.Param2.encode(bytes)?; + let _ = self.CertChainHash.encode(bytes)?; + let _ = self.Nonce.encode(bytes)?; + let _ = self.MeasurementSummaryHash.encode(bytes)?; + let _ = self.OpaqueDataLength.encode(bytes)?; + let _ = self.OpaqueData.encode(bytes)?; + let _ = self.Signature.encode(bytes)?; + Ok(bytes.used() - used) + } + + fn read(_: &mut codec::Reader) -> Option { + // We don't know the size of H and SigLen in current context + panic!("Not support, use CHALLENGE_AUTH::new instead!") + } +} diff --git a/test/spdmlib-test/src/protocol/digest.rs b/test/spdmlib-test/src/protocol/digest.rs new file mode 100644 index 00000000..6ccdb4eb --- /dev/null +++ b/test/spdmlib-test/src/protocol/digest.rs @@ -0,0 +1,98 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +use codec::Codec; +#[derive(Debug, PartialEq, Eq)] +pub struct GET_DIGESTS { + pub SPDMVersion: u8, + pub RequestResponseCode: u8, + pub Param1: u8, + pub Param2: u8, +} + +impl Codec for GET_DIGESTS { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let used = bytes.used(); + let _ = self.SPDMVersion.encode(bytes)?; + let _ = self.RequestResponseCode.encode(bytes)?; + let _ = self.Param1.encode(bytes)?; + let _ = self.Param2.encode(bytes)?; + Ok(bytes.used() - used) + } + + fn read(reader: &mut codec::Reader) -> Option { + let SPDMVersion = u8::read(reader)?; + let RequestResponseCode = u8::read(reader)?; + let Param1 = u8::read(reader)?; + let Param2 = u8::read(reader)?; + Some(GET_DIGESTS { + SPDMVersion, + RequestResponseCode, + Param1, + Param2, + }) + } +} + +#[derive(Debug, PartialEq, Eq)] +pub struct DIGESTS { + pub SPDMVersion: u8, + pub RequestResponseCode: u8, + pub Param1: u8, + pub Param2: u8, + pub Digest: Vec>, +} + +impl DIGESTS { + pub fn new(reader: &mut codec::Reader, H: usize) -> Option { + let SPDMVersion = u8::read(reader)?; + let RequestResponseCode = u8::read(reader)?; + let Param1 = u8::read(reader)?; + let Param2 = u8::read(reader)?; + let count = Param2.count_ones(); + let mut Digest = Vec::new(); + for _ in 0..count { + let CertChainHash: Vec = Vec::::read_vec(reader, H)?; + Digest.push(CertChainHash); + } + + Some(DIGESTS { + SPDMVersion, + RequestResponseCode, + Param1, + Param2, + Digest, + }) + } +} + +impl Codec for DIGESTS { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let used = bytes.used(); + let _ = self.SPDMVersion.encode(bytes)?; + let _ = self.RequestResponseCode.encode(bytes)?; + let _ = self.Param1.encode(bytes)?; + let _ = self.Param2.encode(bytes)?; + for d in self.Digest.as_slice() { + let _ = d.encode(bytes)?; + } + Ok(bytes.used() - used) + } + + fn read(_: &mut codec::Reader) -> Option { + // We don't know the size of H and SigLen in current context + panic!("Not support, use CHALLENGE_AUTH::new instead!") + } +} + +#[test] +fn test() { + let number: u8 = 0b1010_1100; // Example u8 with 8 bits + + // Iterate over each bit from right to left + for i in (0..8).rev() { + let bit = (number >> i) & 1; + println!("Bit {} is {}", i, bit); + } +} diff --git a/test/spdmlib-test/src/protocol/mod.rs b/test/spdmlib-test/src/protocol/mod.rs new file mode 100644 index 00000000..d29b72c7 --- /dev/null +++ b/test/spdmlib-test/src/protocol/mod.rs @@ -0,0 +1,81 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +// The naming rules are ignored here to align with spdmspec +#![allow(non_snake_case)] +#![allow(non_camel_case_types)] + +use codec::Codec; + +pub mod algorithm; +pub mod capability; +pub mod certificate; +pub mod challenge; +pub mod digest; +pub mod version; + +#[derive(Debug, PartialEq, Eq)] +pub enum Message { + GET_VERSION(version::GET_VERSION), + VERSION(version::VERSION), + GET_CAPABILITIES(capability::GET_CAPABILITIES), + CAPABILITIES(capability::CAPABILITIES), + NEGOTIATE_ALGORITHMS(algorithm::NEGOTIATE_ALGORITHMS), + ALGORITHMS(algorithm::ALGORITHMS), + GET_CERTIFICATE(certificate::GET_CERTIFICATE), + CERTIFICATE(certificate::CERTIFICATE), + CHALLENGE(challenge::CHALLENGE), + CHALLENGE_AUTH(challenge::CHALLENGE_AUTH), + GET_DIGESTS(digest::GET_DIGESTS), + DIGESTS(digest::DIGESTS), +} + +impl Codec for Message { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + match self { + Message::GET_VERSION(m) => m.encode(bytes), + Message::VERSION(m) => m.encode(bytes), + Message::GET_CAPABILITIES(m) => m.encode(bytes), + Message::CAPABILITIES(m) => m.encode(bytes), + Message::NEGOTIATE_ALGORITHMS(m) => m.encode(bytes), + Message::ALGORITHMS(m) => m.encode(bytes), + Message::GET_CERTIFICATE(m) => m.encode(bytes), + Message::CERTIFICATE(m) => m.encode(bytes), + Message::CHALLENGE(m) => m.encode(bytes), + Message::CHALLENGE_AUTH(m) => m.encode(bytes), + Message::GET_DIGESTS(m) => m.encode(bytes), + Message::DIGESTS(m) => m.encode(bytes), + } + } + + fn read(reader: &mut codec::Reader) -> Option { + let header = reader.rest(); + if header.len() < 4 { + return None; + } + let reader = &mut codec::Reader::init(header); + let RequestResponseCode = header[1]; + match RequestResponseCode { + 0x84 => Some(Message::GET_VERSION(version::GET_VERSION::read(reader)?)), + 0x04 => Some(Message::VERSION(version::VERSION::read(reader)?)), + 0xE1 => Some(Message::GET_CAPABILITIES( + capability::GET_CAPABILITIES::read(reader)?, + )), + 0x61 => Some(Message::CAPABILITIES(capability::CAPABILITIES::read( + reader, + )?)), + 0xE3 => Some(Message::NEGOTIATE_ALGORITHMS( + algorithm::NEGOTIATE_ALGORITHMS::read(reader)?, + )), + 0x63 => Some(Message::ALGORITHMS(algorithm::ALGORITHMS::read(reader)?)), + 0x82 => Some(Message::GET_CERTIFICATE( + certificate::GET_CERTIFICATE::read(reader)?, + )), + 0x02 => Some(Message::CERTIFICATE(certificate::CERTIFICATE::read( + reader, + )?)), + _ => panic!("not support type"), + } + } +} diff --git a/test/spdmlib-test/src/protocol/version.rs b/test/spdmlib-test/src/protocol/version.rs new file mode 100644 index 00000000..b05565fc --- /dev/null +++ b/test/spdmlib-test/src/protocol/version.rs @@ -0,0 +1,82 @@ +// Copyright (c) 2023 Intel Corporation +// +// SPDX-License-Identifier: Apache-2.0 + +// Follow SPDM spec field name. +use codec::Codec; + +#[derive(Debug, PartialEq, Eq)] +pub struct GET_VERSION { + pub SPDMVersion: u8, + pub RequestResponseCode: u8, + pub Param1: u8, + pub Param2: u8, +} + +#[derive(Debug, PartialEq, Eq)] +pub struct VERSION { + pub SPDMVersion: u8, + pub RequestResponseCode: u8, + pub Param1: u8, + pub Param2: u8, + pub Reserved: u8, + pub VersionNumberEntryCount: u8, + pub VersionNumberEntry: Vec, +} + +impl Codec for GET_VERSION { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let used = bytes.used(); + let _ = self.SPDMVersion.encode(bytes)?; + let _ = self.RequestResponseCode.encode(bytes)?; + let _ = self.Param1.encode(bytes)?; + let _ = self.Param2.encode(bytes)?; + Ok(bytes.used() - used) + } + + fn read(reader: &mut codec::Reader) -> Option { + let SPDMVersion = u8::read(reader)?; + let RequestResponseCode = u8::read(reader)?; + let Param1 = u8::read(reader)?; + let Param2 = u8::read(reader)?; + Some(GET_VERSION { + SPDMVersion, + RequestResponseCode, + Param1, + Param2, + }) + } +} + +impl Codec for VERSION { + fn encode(&self, bytes: &mut codec::Writer) -> Result { + let used = bytes.used(); + let _ = self.SPDMVersion.encode(bytes)?; + let _ = self.RequestResponseCode.encode(bytes)?; + let _ = self.Param1.encode(bytes)?; + let _ = self.Param2.encode(bytes)?; + let _ = self.Reserved.encode(bytes)?; + let _ = self.VersionNumberEntryCount.encode(bytes)?; + let _ = self.VersionNumberEntry.encode(bytes)?; + Ok(bytes.used() - used) + } + + fn read(reader: &mut codec::Reader) -> Option { + let SPDMVersion = u8::read(reader)?; + let RequestResponseCode = u8::read(reader)?; + let Param1 = u8::read(reader)?; + let Param2 = u8::read(reader)?; + let Reserved = u8::read(reader)?; + let VersionNumberEntryCount = u8::read(reader)?; + let VersionNumberEntry = Vec::::read_vec(reader, VersionNumberEntryCount as usize)?; + Some(VERSION { + SPDMVersion, + RequestResponseCode, + Param1, + Param2, + Reserved, + VersionNumberEntryCount, + VersionNumberEntry, + }) + } +} diff --git a/test/spdmlib-test/src/responder_tests/algorithm_rsp.rs b/test/spdmlib-test/src/responder_tests/algorithm_rsp.rs index 0c104060..7d04acd3 100644 --- a/test/spdmlib-test/src/responder_tests/algorithm_rsp.rs +++ b/test/spdmlib-test/src/responder_tests/algorithm_rsp.rs @@ -5,7 +5,7 @@ use crate::common::device_io::{FakeSpdmDeviceIoReceve, SharedBuffer}; use crate::common::secret_callback::SECRET_ASYM_IMPL_INSTANCE; use crate::common::transport::PciDoeTransportEncap; -use crate::common::util::create_info; +use crate::common::util::{create_info, TestSpdmMessage}; use codec::{Codec, Reader, Writer}; use log::debug; use spdmlib::common::*; @@ -219,3 +219,65 @@ fn test_case0_handle_spdm_algorithm() { executor::block_on(future); } + +pub fn consturct_algorithm_positive() -> (TestSpdmMessage, TestSpdmMessage) { + use crate::protocol; + let (config_info, provision_info) = create_info(); + let negotiate_algorithm_msg = TestSpdmMessage { + message: protocol::Message::NEGOTIATE_ALGORITHMS( + protocol::algorithm::NEGOTIATE_ALGORITHMS { + SPDMVersion: 0x12, + RequestResponseCode: 0xE3, + Param1: 4, + Param2: 0, + Length: 48, + MeasurementSpecification: config_info.measurement_specification.bits(), + OtherParamsSupport: config_info.opaque_support.bits(), + BaseAsymAlgo: config_info.base_asym_algo.bits(), + BaseHashAlgo: config_info.base_hash_algo.bits(), + _Reserved1: [0u8; 12], + ExtAsymCount: 0, + ExtHashCount: 0, + _Reserved2: [0u8; 2], + ExtAsym: Vec::new(), + Exthash: Vec::new(), + AlgStruct: vec![ + [0x02, 0x20, 0x10, 0x00], + [0x03, 0x20, 0x02, 0x00], + [0x04, 0x20, 0x02, 0x00], + [0x05, 0x20, 0x01, 0x00], + ], + }, + ), + secure: 0, + }; + + let algorithm_msg = TestSpdmMessage { + message: protocol::Message::ALGORITHMS(protocol::algorithm::ALGORITHMS { + SPDMVersion: 0x12, + RequestResponseCode: 0x63, + Param1: 4, + Param2: 0, + Length: 52, + MeasurementSpecification: config_info.measurement_specification.bits(), + OtherParamsSupport: config_info.opaque_support.bits(), + MeasurementHashAlgo: config_info.measurement_hash_algo.bits(), + BaseAsymAlgo: config_info.base_asym_algo.bits(), + BaseHashAlgo: config_info.base_hash_algo.bits(), + _Reserved1: [0u8; 12], + ExtAsymCount: 0, + ExtHashCount: 0, + _Reserved2: [0u8; 2], + ExtAsym: Vec::new(), + Exthash: Vec::new(), + AlgStruct: vec![ + [0x02, 0x20, 0x10, 0x00], + [0x03, 0x20, 0x02, 0x00], + [0x04, 0x20, 0x02, 0x00], + [0x05, 0x20, 0x01, 0x00], + ], + }), + secure: 0, + }; + (negotiate_algorithm_msg, algorithm_msg) +} diff --git a/test/spdmlib-test/src/responder_tests/capability_rsp.rs b/test/spdmlib-test/src/responder_tests/capability_rsp.rs index 54c92948..3167a0a3 100644 --- a/test/spdmlib-test/src/responder_tests/capability_rsp.rs +++ b/test/spdmlib-test/src/responder_tests/capability_rsp.rs @@ -5,7 +5,7 @@ use crate::common::device_io::{FakeSpdmDeviceIoReceve, SharedBuffer}; use crate::common::secret_callback::SECRET_ASYM_IMPL_INSTANCE; use crate::common::transport::PciDoeTransportEncap; -use crate::common::util::create_info; +use crate::common::util::{create_info, TestSpdmMessage}; use codec::{Codec, Reader, Writer}; use spdmlib::common::*; use spdmlib::config::MAX_SPDM_MSG_SIZE; @@ -111,3 +111,40 @@ fn test_case0_handle_spdm_capability() { }; executor::block_on(future); } + +pub fn consturct_capability_positive() -> (TestSpdmMessage, TestSpdmMessage) { + use crate::protocol; + let (config_info, provision_info) = create_info(); + let get_capabilities_msg = TestSpdmMessage { + message: protocol::Message::GET_CAPABILITIES(protocol::capability::GET_CAPABILITIES { + SPDMVersion: 0x12, + RequestResponseCode: 0xE1, + Param1: 0, + Param2: 0, + _Reserved: 0, + CTExponent: config_info.req_ct_exponent, + _Reserved2: 0, + Flags: config_info.req_capabilities.bits(), + DataTransferSize: config_info.data_transfer_size, + MaxSPDMmsgSize: config_info.max_spdm_msg_size, + }), + secure: 0, + }; + + let capabilities_msg = TestSpdmMessage { + message: protocol::Message::CAPABILITIES(protocol::capability::CAPABILITIES { + SPDMVersion: 0x12, + RequestResponseCode: 0x61, + Param1: 0, + Param2: 0, + _Reserved: 0, + CTExponent: config_info.rsp_ct_exponent, + _Reserved2: 0, + Flags: config_info.rsp_capabilities.bits(), + DataTransferSize: config_info.data_transfer_size, + MaxSPDMmsgSize: config_info.max_spdm_msg_size, + }), + secure: 0, + }; + (get_capabilities_msg, capabilities_msg) +} diff --git a/test/spdmlib-test/src/responder_tests/certificate_rsp.rs b/test/spdmlib-test/src/responder_tests/certificate_rsp.rs index 49e03bf7..351d273b 100644 --- a/test/spdmlib-test/src/responder_tests/certificate_rsp.rs +++ b/test/spdmlib-test/src/responder_tests/certificate_rsp.rs @@ -2,10 +2,10 @@ // // SPDX-License-Identifier: Apache-2.0 -use crate::common::device_io::{FakeSpdmDeviceIoReceve, SharedBuffer}; +use crate::common::device_io::{self, FakeSpdmDeviceIoReceve, SharedBuffer}; use crate::common::secret_callback::SECRET_ASYM_IMPL_INSTANCE; use crate::common::transport::PciDoeTransportEncap; -use crate::common::util::create_info; +use crate::common::util::{create_info, ResponderRunner, TestCase, TestSpdmMessage}; use codec::{Codec, Writer}; use spdmlib::common::*; use spdmlib::message::*; @@ -72,7 +72,10 @@ fn test_case0_handle_spdm_certificate() { let mut response_buffer = [0u8; MAX_SPDM_MSG_SIZE]; let mut writer = Writer::init(&mut response_buffer); - context.handle_spdm_certificate(bytes, None, &mut writer); + assert!(context + .handle_spdm_certificate(bytes, None, &mut writer) + .0 + .is_ok()); #[cfg(not(feature = "hashed-transcript-data"))] { @@ -121,3 +124,79 @@ fn test_case0_handle_spdm_certificate() { }; executor::block_on(future); } + +#[test] +fn test_case1_handle_spdm_certificate() { + use crate::protocol; + + let mut input = Vec::new(); + let mut expected = Vec::new(); + + let (config_info, provision_info) = create_info(); + let (get_version_msg, version_msg) = super::version_rsp::construct_version_positive(); + let (get_capabilities_msg, capabilities_msg) = + super::capability_rsp::consturct_capability_positive(); + let (negotiate_algorithm_msg, algorithm_msg) = + super::algorithm_rsp::consturct_algorithm_positive(); + + input.push(get_version_msg); + expected.push(version_msg); + input.push(get_capabilities_msg); + expected.push(capabilities_msg); + input.push(negotiate_algorithm_msg); + expected.push(algorithm_msg); + + let cert_chain = provision_info.my_cert_chain_data[0].as_ref(); + let spdm_certificate_chain = TestCase::get_certificate_chain_buffer( + config_info.base_hash_algo, + cert_chain.unwrap().as_ref(), + ); + let spdm_certificate_chain_len = spdm_certificate_chain.as_ref().len(); + + const PORTION_LENGTH: usize = 0x200; + let count = (spdm_certificate_chain.as_ref().len() + PORTION_LENGTH - 1) / PORTION_LENGTH; + for index in 0..count { + let offset = index * PORTION_LENGTH; + let remainder_length = spdm_certificate_chain_len - offset; + let portion_length = if remainder_length > PORTION_LENGTH { + PORTION_LENGTH + } else { + spdm_certificate_chain_len - (index * PORTION_LENGTH) + }; + + let get_certificate_msg = TestSpdmMessage { + message: protocol::Message::GET_CERTIFICATE(protocol::certificate::GET_CERTIFICATE { + SPDMVersion: 0x12, + RequestResponseCode: 0x82, + Param1: 0, + Param2: 0, + Offset: offset as u16, + Length: portion_length as u16, + }), + secure: 0, + }; + + let certificate_msg = TestSpdmMessage { + message: protocol::Message::CERTIFICATE(protocol::certificate::CERTIFICATE { + SPDMVersion: 0x12, + RequestResponseCode: 0x02, + Param1: 0, + Param2: 0, + PortionLength: portion_length as u16, + RemainderLength: (remainder_length - portion_length) as u16, + CertChain: spdm_certificate_chain.as_ref()[offset..(offset + portion_length)] + .to_vec(), + }), + secure: 0, + }; + + input.push(get_certificate_msg); + expected.push(certificate_msg); + } + + let case = TestCase { input, expected }; + assert!(ResponderRunner::run( + case, + device_io::test_header_generater_callback + )); +} diff --git a/test/spdmlib-test/src/responder_tests/challenge_rsp.rs b/test/spdmlib-test/src/responder_tests/challenge_rsp.rs index ac634e05..4bce2bab 100644 --- a/test/spdmlib-test/src/responder_tests/challenge_rsp.rs +++ b/test/spdmlib-test/src/responder_tests/challenge_rsp.rs @@ -5,10 +5,10 @@ #![allow(unused)] use crate::common::crypto_callback::FAKE_RAND; -use crate::common::device_io::{FakeSpdmDeviceIoReceve, SharedBuffer}; +use crate::common::device_io::{self, FakeSpdmDeviceIoReceve, SharedBuffer}; use crate::common::secret_callback::SECRET_ASYM_IMPL_INSTANCE; use crate::common::transport::PciDoeTransportEncap; -use crate::common::util::create_info; +use crate::common::util::{create_info, ResponderRunner, TestCase, TestSpdmMessage}; use codec::{Codec, Reader, Writer}; use spdmlib::common::*; use spdmlib::message::SpdmChallengeRequestPayload; @@ -87,7 +87,7 @@ fn test_case0_handle_spdm_challenge() { let mut response_buffer = [0u8; MAX_SPDM_MSG_SIZE]; let mut writer = Writer::init(&mut response_buffer); - context.handle_spdm_challenge(bytes, &mut writer); + assert!(context.handle_spdm_challenge(bytes, &mut writer).0.is_ok()); #[cfg(not(feature = "hashed-transcript-data"))] { @@ -169,3 +169,117 @@ fn test_case0_handle_spdm_challenge() { }; executor::block_on(future); } + +#[test] +fn test_case1_handle_spdm_challenge() { + use crate::protocol; + + let mut input = Vec::new(); + let mut expected = Vec::new(); + + let (config_info, provision_info) = create_info(); + let (get_version_msg, version_msg) = super::version_rsp::construct_version_positive(); + let (get_capabilities_msg, capabilities_msg) = + super::capability_rsp::consturct_capability_positive(); + let (negotiate_algorithm_msg, algorithm_msg) = + super::algorithm_rsp::consturct_algorithm_positive(); + + input.push(get_version_msg); + expected.push(version_msg); + input.push(get_capabilities_msg); + expected.push(capabilities_msg); + input.push(negotiate_algorithm_msg); + expected.push(algorithm_msg); + + let cert_chain = provision_info.my_cert_chain_data[0].as_ref(); + let spdm_certificate_chain = TestCase::get_certificate_chain_buffer( + config_info.base_hash_algo, + cert_chain.unwrap().as_ref(), + ); + let spdm_certificate_chain_len = spdm_certificate_chain.as_ref().len(); + + const PORTION_LENGTH: usize = 0x200; + let count = (spdm_certificate_chain.as_ref().len() + PORTION_LENGTH - 1) / PORTION_LENGTH; + for index in 0..count { + let offset = index * PORTION_LENGTH; + let remainder_length = spdm_certificate_chain_len - offset; + let portion_length = if remainder_length > PORTION_LENGTH { + PORTION_LENGTH + } else { + spdm_certificate_chain_len - (index * PORTION_LENGTH) + }; + + let get_certificate_msg = TestSpdmMessage { + message: protocol::Message::GET_CERTIFICATE(protocol::certificate::GET_CERTIFICATE { + SPDMVersion: 0x12, + RequestResponseCode: 0x82, + Param1: 0, + Param2: 0, + Offset: offset as u16, + Length: portion_length as u16, + }), + secure: 0, + }; + + let certificate_msg = TestSpdmMessage { + message: protocol::Message::CERTIFICATE(protocol::certificate::CERTIFICATE { + SPDMVersion: 0x12, + RequestResponseCode: 0x02, + Param1: 0, + Param2: 0, + PortionLength: portion_length as u16, + RemainderLength: (remainder_length - portion_length) as u16, + CertChain: spdm_certificate_chain.as_ref()[offset..(offset + portion_length)] + .to_vec(), + }), + secure: 0, + }; + + input.push(get_certificate_msg); + expected.push(certificate_msg); + } + + let challenge_msg = TestSpdmMessage { + message: protocol::Message::CHALLENGE(protocol::challenge::CHALLENGE { + SPDMVersion: 0x12, + RequestResponseCode: 0x83, + Param1: 0, + Param2: 0, + Nonce: [0u8; 32], + }), + secure: 0, + }; + + let sig_len = config_info.base_asym_algo.get_size() as usize; + let challenge_auth_msg = TestSpdmMessage { + message: protocol::Message::CHALLENGE_AUTH(protocol::challenge::CHALLENGE_AUTH { + SPDMVersion: 0x12, + RequestResponseCode: 0x3, + Param1: 0, + Param2: 1, + CertChainHash: { + let cert_chain_digest = spdmlib::crypto::hash::hash_all( + config_info.base_hash_algo, + spdm_certificate_chain.as_ref(), + ) + .expect("Must provide hash algo"); + cert_chain_digest.as_ref().to_vec() + }, + Nonce: [0xFF; 32], + MeasurementSummaryHash: Vec::new(), + OpaqueDataLength: 0, + OpaqueData: Vec::new(), + Signature: vec![0x5a; sig_len], + }), + secure: 0, + }; + + input.push(challenge_msg); + expected.push(challenge_auth_msg); + + let case = TestCase { input, expected }; + assert!(ResponderRunner::run( + case, + device_io::test_header_generater_callback + )); +} diff --git a/test/spdmlib-test/src/responder_tests/digest_rsp.rs b/test/spdmlib-test/src/responder_tests/digest_rsp.rs index da5888e2..873be399 100644 --- a/test/spdmlib-test/src/responder_tests/digest_rsp.rs +++ b/test/spdmlib-test/src/responder_tests/digest_rsp.rs @@ -2,10 +2,10 @@ // // SPDX-License-Identifier: Apache-2.0 -use crate::common::device_io::{FakeSpdmDeviceIoReceve, SharedBuffer}; +use crate::common::device_io::{self, FakeSpdmDeviceIoReceve, SharedBuffer}; use crate::common::secret_callback::SECRET_ASYM_IMPL_INSTANCE; use crate::common::transport::PciDoeTransportEncap; -use crate::common::util::create_info; +use crate::common::util::{create_info, ResponderRunner, TestCase, TestSpdmMessage}; use codec::{Codec, Writer}; use spdmlib::message::*; use spdmlib::protocol::*; @@ -62,7 +62,120 @@ fn test_case0_handle_spdm_digest() { let mut response_buffer = [0u8; MAX_SPDM_MSG_SIZE]; let mut writer = Writer::init(&mut response_buffer); - context.handle_spdm_digest(bytes, None, &mut writer); + assert!(context + .handle_spdm_digest(bytes, None, &mut writer) + .0 + .is_ok()); }; executor::block_on(future); } + +#[test] +fn test_case1_handle_spdm_digest() { + env_logger::init(); + use crate::protocol; + + let mut input = Vec::new(); + let mut expected = Vec::new(); + + let (config_info, provision_info) = create_info(); + let (get_version_msg, version_msg) = super::version_rsp::construct_version_positive(); + let (get_capabilities_msg, capabilities_msg) = + super::capability_rsp::consturct_capability_positive(); + let (negotiate_algorithm_msg, algorithm_msg) = + super::algorithm_rsp::consturct_algorithm_positive(); + + input.push(get_version_msg); + expected.push(version_msg); + input.push(get_capabilities_msg); + expected.push(capabilities_msg); + input.push(negotiate_algorithm_msg); + expected.push(algorithm_msg); + + let cert_chain = provision_info.my_cert_chain_data[0].as_ref(); + let spdm_certificate_chain = TestCase::get_certificate_chain_buffer( + config_info.base_hash_algo, + cert_chain.unwrap().as_ref(), + ); + let spdm_certificate_chain_len = spdm_certificate_chain.as_ref().len(); + + const PORTION_LENGTH: usize = 0x200; + let count = (spdm_certificate_chain.as_ref().len() + PORTION_LENGTH - 1) / PORTION_LENGTH; + for index in 0..count { + let offset = index * PORTION_LENGTH; + let remainder_length = spdm_certificate_chain_len - offset; + let portion_length = if remainder_length > PORTION_LENGTH { + PORTION_LENGTH + } else { + spdm_certificate_chain_len - (index * PORTION_LENGTH) + }; + + let get_certificate_msg = TestSpdmMessage { + message: protocol::Message::GET_CERTIFICATE(protocol::certificate::GET_CERTIFICATE { + SPDMVersion: 0x12, + RequestResponseCode: 0x82, + Param1: 0, + Param2: 0, + Offset: offset as u16, + Length: portion_length as u16, + }), + secure: 0, + }; + + let certificate_msg = TestSpdmMessage { + message: protocol::Message::CERTIFICATE(protocol::certificate::CERTIFICATE { + SPDMVersion: 0x12, + RequestResponseCode: 0x02, + Param1: 0, + Param2: 0, + PortionLength: portion_length as u16, + RemainderLength: (remainder_length - portion_length) as u16, + CertChain: spdm_certificate_chain.as_ref()[offset..(offset + portion_length)] + .to_vec(), + }), + secure: 0, + }; + + input.push(get_certificate_msg); + expected.push(certificate_msg); + } + + let get_digest_msg = TestSpdmMessage { + message: protocol::Message::GET_DIGESTS(protocol::digest::GET_DIGESTS { + SPDMVersion: 0x12, + RequestResponseCode: 0x81, + Param1: 0x0, + Param2: 0x0, + }), + secure: 0, + }; + + let digest_msg = TestSpdmMessage { + message: protocol::Message::DIGESTS(protocol::digest::DIGESTS { + SPDMVersion: 0x12, + RequestResponseCode: 0x01, + Param1: 0x0, + Param2: 0x1, + Digest: { + let mut digests = Vec::new(); + let cert_chain_digest = spdmlib::crypto::hash::hash_all( + config_info.base_hash_algo, + spdm_certificate_chain.as_ref(), + ) + .expect("Must provide hash algo"); + digests.push(cert_chain_digest.as_ref().to_vec()); + digests + }, + }), + secure: 0, + }; + + input.push(get_digest_msg); + expected.push(digest_msg); + + let case = TestCase { input, expected }; + assert!(ResponderRunner::run( + case, + device_io::test_header_generater_callback + )); +} diff --git a/test/spdmlib-test/src/responder_tests/version_rsp.rs b/test/spdmlib-test/src/responder_tests/version_rsp.rs index 60e0d242..cd013a5f 100644 --- a/test/spdmlib-test/src/responder_tests/version_rsp.rs +++ b/test/spdmlib-test/src/responder_tests/version_rsp.rs @@ -5,7 +5,7 @@ use crate::common::device_io::{FakeSpdmDeviceIoReceve, SharedBuffer}; use crate::common::secret_callback::SECRET_ASYM_IMPL_INSTANCE; use crate::common::transport::PciDoeTransportEncap; -use crate::common::util::create_info; +use crate::common::util::{create_info, TestSpdmMessage}; use codec::{Codec, Reader, Writer}; use spdmlib::common::*; use spdmlib::config::MAX_SPDM_MSG_SIZE; @@ -84,3 +84,37 @@ fn test_case0_handle_spdm_version() { }; executor::block_on(future); } + +pub fn construct_version_positive() -> (TestSpdmMessage, TestSpdmMessage) { + use crate::protocol; + let get_version_msg = TestSpdmMessage { + message: protocol::Message::GET_VERSION(protocol::version::GET_VERSION { + SPDMVersion: 0x10, + RequestResponseCode: 0x84, + Param1: 0, + Param2: 0, + }), + secure: 0, + }; + let (config_info, provision_info) = create_info(); + let version_msg = TestSpdmMessage { + message: protocol::Message::VERSION(protocol::version::VERSION { + SPDMVersion: 0x10, + RequestResponseCode: 0x04, + Param1: 0, + Param2: 0, + Reserved: 0, + VersionNumberEntryCount: config_info.spdm_version.len() as u8, + VersionNumberEntry: { + let mut versions = Vec::new(); + for v in config_info.spdm_version { + let version = (v.get_u8() as u16) << 8; + versions.push(version) + } + versions + }, + }), + secure: 0, + }; + (get_version_msg, version_msg) +}