From 2d974ddc9b2e4542868410dadc8da03be53b783b Mon Sep 17 00:00:00 2001 From: "Lu, Xiaoyu1" Date: Wed, 30 Aug 2023 07:53:27 -0400 Subject: [PATCH] Test: check test results and response message Signed-off-by: xiaoyuxlu --- test/spdmlib-test/Cargo.toml | 2 + .../src/common/crypto_callback.rs | 1 + .../src/common/secret_callback.rs | 3 +- test/spdmlib-test/src/common/util.rs | 614 +++++++++++++++++- .../src/responder_tests/algorithm_rsp.rs | 179 ++++- .../src/responder_tests/capability_rsp.rs | 93 ++- .../src/responder_tests/certificate_rsp.rs | 223 ++++++- .../src/responder_tests/challenge_rsp.rs | 127 +++- .../src/responder_tests/digest_rsp.rs | 137 +++- .../src/responder_tests/version_rsp.rs | 105 ++- 10 files changed, 1470 insertions(+), 14 deletions(-) diff --git a/test/spdmlib-test/Cargo.toml b/test/spdmlib-test/Cargo.toml index 77f7bf1a..e2873adb 100644 --- a/test/spdmlib-test/Cargo.toml +++ b/test/spdmlib-test/Cargo.toml @@ -17,6 +17,8 @@ async-recursion = "1.0.4" spin = { version = "0.9.8" } executor = { path = "../../executor" } pcidoe_transport = { path = "../../pcidoe_transport" } +byteorder = { version = "1.4" } +bit_field = "0.10.1" [dev-dependencies] env_logger = "*" diff --git a/test/spdmlib-test/src/common/crypto_callback.rs b/test/spdmlib-test/src/common/crypto_callback.rs index 53469b71..00045ece 100644 --- a/test/spdmlib-test/src/common/crypto_callback.rs +++ b/test/spdmlib-test/src/common/crypto_callback.rs @@ -176,4 +176,5 @@ fn fake_verify_cert_chain(_cert_chain: &[u8]) -> SpdmResult { // Make sure this is the first test case running by `cargo test` fn test_0_crypto_init() { spdmlib::crypto::aead::register(FAKE_AEAD.clone()); + spdmlib::crypto::rand::register(FAKE_RAND.clone()); } diff --git a/test/spdmlib-test/src/common/secret_callback.rs b/test/spdmlib-test/src/common/secret_callback.rs index 1451807b..52758cba 100644 --- a/test/spdmlib-test/src/common/secret_callback.rs +++ b/test/spdmlib-test/src/common/secret_callback.rs @@ -6,6 +6,7 @@ #![allow(unused_variables)] use crate::common::util::get_test_key_directory; use codec::{u24, Codec, Writer}; +use ring::rand::SecureRandom; use spdmlib::common::key_schedule::SpdmKeySchedule; use spdmlib::config; use spdmlib::crypto; @@ -310,7 +311,7 @@ fn sign_ecdsa_asym_algo( let signature = signature.as_ref(); let mut full_signature: [u8; SPDM_MAX_ASYM_KEY_SIZE] = [0u8; SPDM_MAX_ASYM_KEY_SIZE]; - full_signature[..signature.len()].copy_from_slice(signature); + full_signature[..signature.len()].copy_from_slice(vec![0x5au8; signature.len()].as_slice()); Some(SpdmSignatureStruct { data_size: signature.len() as u16, diff --git a/test/spdmlib-test/src/common/util.rs b/test/spdmlib-test/src/common/util.rs index 2c6c9026..fe3f4057 100644 --- a/test/spdmlib-test/src/common/util.rs +++ b/test/spdmlib-test/src/common/util.rs @@ -8,7 +8,8 @@ use super::USE_ECDSA; use crate::common::device_io::MySpdmDeviceIo; use crate::common::secret_callback::SECRET_ASYM_IMPL_INSTANCE; use crate::common::transport::PciDoeTransportEncap; -use codec::{Reader, Writer}; +use byteorder::{ByteOrder, LittleEndian}; +use spdmlib::common::ST1; use spdmlib::common::{ SpdmCodec, SpdmConfigInfo, SpdmContext, SpdmDeviceIo, SpdmOpaqueSupport, SpdmProvisionInfo, SpdmTransportEncap, DMTF_SECURE_SPDM_VERSION_10, DMTF_SECURE_SPDM_VERSION_11, @@ -17,8 +18,12 @@ use spdmlib::config; use spdmlib::crypto; use spdmlib::message::SpdmMessage; use spdmlib::protocol::*; +use spdmlib::{requester, responder}; use std::path::PathBuf; +use alloc::collections::VecDeque; +use async_trait::async_trait; +use spdmlib::error::{SpdmResult, SPDM_STATUS_DECAP_FAIL}; use spin::Mutex; extern crate alloc; use alloc::boxed::Box; @@ -133,6 +138,7 @@ pub fn new_context( } pub fn new_spdm_message(value: SpdmMessage, mut context: SpdmContext) -> SpdmMessage { + use codec::{Reader, Writer}; let u8_slice = &mut [0u8; 1000]; let mut writer = Writer::init(u8_slice); value.spdm_encode(&mut context, &mut writer); @@ -395,3 +401,609 @@ pub fn get_rsp_cert_chain_buff() -> SpdmCertChainBuffer { SpdmCertChainBuffer::new(cert_chain, root_cert_hash.as_ref()) .expect("Create format certificate chain failed.") } + +pub const TESE_TRANSPORT_ENCAP_HEADER_LEN: usize = 5; +pub const TEST_SPDM_DEVICE_IO_HEADER_LEN: usize = 4; +pub const TEST_HEADER_LEN: usize = TESE_TRANSPORT_ENCAP_HEADER_LEN + TEST_SPDM_DEVICE_IO_HEADER_LEN; + +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 + // length u32 + // value slice + let mut transport_buffer = transport_buffer.lock(); + let mut writer = Writer::new_unchecked(&mut transport_buffer[..]); + writer + .put_u8(secured_message as u8) + .ok_or(SPDM_STATUS_DECAP_FAIL)?; + if spdm_buffer.len() > u32::MAX as usize { + return Err(SPDM_STATUS_DECAP_FAIL); + } + writer + .put_u32(spdm_buffer.len() as u32) + .ok_or(SPDM_STATUS_DECAP_FAIL)?; + writer + .put_buffer(&spdm_buffer[..]) + .ok_or(SPDM_STATUS_DECAP_FAIL)?; + return Ok(writer.used()); + } + + async fn decap( + &mut self, + transport_buffer: Arc<&[u8]>, + spdm_buffer: Arc>, + ) -> SpdmResult<(usize, bool)> { + let mut reader = Reader::new_unchecked(&transport_buffer[..]); + let secured_message = reader.get_u8().ok_or(SPDM_STATUS_DECAP_FAIL)? != 0; + let spdm_buffer_len = reader.get_u32().ok_or(SPDM_STATUS_DECAP_FAIL)? as usize; + let buffer = reader + .get_buffer(spdm_buffer_len) + .ok_or(SPDM_STATUS_DECAP_FAIL)?; + let mut spdm_buffer = spdm_buffer.lock(); + spdm_buffer[0..spdm_buffer_len].copy_from_slice(buffer); + return Ok((spdm_buffer_len, secured_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>>, + pub expected: VecDeque, + test_requester: bool, +} + +impl TestSpdmDeviceIo { + pub const HEADER_LEN: usize = 4; + + pub fn new() -> Self { + Self { + rx: Arc::new(Mutex::new(VecDeque::::new())), + tx: Arc::new(Mutex::new(VecDeque::::new())), + expected: VecDeque::::new(), + test_requester: false, + } + } + + pub fn load_rx(&mut self, rx: &[u8]) { + self.test_requester = false; + let mut buf = self.rx.lock(); + buf.extend(rx.iter()) + } + + pub fn load_tx(&mut self, tx: &[u8]) { + let mut buf = self.tx.lock(); + buf.extend(tx.iter()) + } + + pub fn load_expected(&mut self, expected: &[u8]) { + self.expected.extend(expected.iter()) + } + + pub fn test_tx(&mut self) { + let mut tx = self.tx.lock(); + let buffer = tx.make_contiguous(); + let mut reader = Reader::new_unchecked(buffer); + let value_len = reader.get_u32().expect("unable to get length") as usize; + let packet = reader.get_buffer(value_len).expect("unable to get packet"); + + let expected_buffer = self.expected.make_contiguous(); + let mut expected_reader = Reader::new_unchecked(expected_buffer); + let expected_buffer_len = expected_reader + .get_u32() + .expect("unable to get expected length") as usize; + assert_eq!( + expected_buffer_len, value_len, + "\nexpected buffer_len {}\nactual buffer_len {}", + expected_buffer_len, value_len + ); + let expected = expected_reader + .get_buffer(value_len) + .expect("unable to get expected value"); + assert_eq!( + expected, packet, + "\n\nexpected response:\n{:02x?}\nactual response:\n{:02x?}", + expected, packet + ); + + tx.drain(0..(value_len + 4)); + self.expected.drain(0..(value_len + 4)); + } + + pub fn test_rx(&mut self) { + let mut rx = self.rx.lock(); + let buffer = rx.make_contiguous(); + let mut reader = Reader::new_unchecked(buffer); + let value_len = reader.get_u32().expect("unable to get length") as usize; + let packet = reader.get_buffer(value_len).expect("unable to get packet"); + + let expected_buffer = self.expected.make_contiguous(); + let mut expected_reader = Reader::new_unchecked(expected_buffer); + assert_eq!( + expected_reader + .get_u32() + .expect("unable to get expected length") as usize, + value_len + ); + assert_eq!( + expected_reader + .get_buffer(value_len) + .expect("unable to get expected value"), + packet + ); + + rx.drain(0..(value_len + 4)); + self.expected.drain(0..(value_len + 4)); + } +} + +#[async_trait] +impl SpdmDeviceIo for TestSpdmDeviceIo { + async fn receive( + &mut self, + read_buffer: Arc>, + _timeout: usize, + ) -> Result { + let buffer_len = { + let mut rx = self.rx.lock(); + let mut read_buffer = read_buffer.lock(); + if rx.is_empty() { + return Err(0); + } + let mut reader = Reader::new_unchecked(rx.make_contiguous()); + let buffer_len = reader.get_u32().ok_or(0usize)? as usize; + if buffer_len > read_buffer.len() { + return Err(buffer_len); + } + let buffer = reader.get_buffer(buffer_len).ok_or(0usize)?; + read_buffer[0..buffer_len].copy_from_slice(buffer); + let drain_len = reader.used(); + rx.drain(0..drain_len); + println!( + "responder receive RAW - {:02x?}", + &read_buffer[0..buffer_len] + ); + buffer_len + }; + if self.test_requester { + self.test_rx() + } + Ok(buffer_len) + } + + 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_ne_bytes().iter()); + tx.extend(buffer.iter()); + } + + if !self.test_requester { + self.test_tx(); + } + + println!("responder send RAW - {:02x?}", &buffer); + Ok(()) + } + + async fn flush_all(&mut self) -> SpdmResult { + Ok(()) + } +} + +pub fn wrapper_test_encap( + secure_message: bool, + out_buffer: &mut [u8], + input: fn(buffer: &mut [u8]) -> usize, +) -> usize { + let nwrite = (input)(&mut out_buffer[TESE_TRANSPORT_ENCAP_HEADER_LEN..]); + let mut writer = Writer::new_unchecked(out_buffer); + writer.put_u8(secure_message as u8); + writer.put_u32(nwrite as u32); + nwrite + writer.used() +} +pub fn wrapper_test_device_io( + secure_message: bool, + out_buffer: &mut [u8], + input: fn(buffer: &mut [u8]) -> usize, +) -> usize { + let nwrite = wrapper_test_encap( + secure_message, + &mut out_buffer[TEST_SPDM_DEVICE_IO_HEADER_LEN..], + input, + ); + let mut writer = Writer::new_unchecked(out_buffer); + writer.put_u32(nwrite as u32); + nwrite + writer.used() +} + +pub struct Reader> { + data: T, + pos: usize, +} + +impl> Reader { + pub fn new_unchecked(buffer: T) -> Self { + Self { + data: buffer, + pos: 0usize, + } + } + + pub fn get_u8(&mut self) -> Option { + let data = self.data.as_ref(); + let pos = self.pos; + let data_len = data.len(); + let value_len = 1; + if pos + value_len - 1 > data_len { + return None; + } + let ret = data[pos]; + self.pos += value_len; + Some(ret) + } + + pub fn get_u16(&mut self) -> Option { + let data = self.data.as_ref(); + let pos = self.pos; + let data_len = data.len(); + let value_len = core::mem::size_of::(); + if pos + value_len - 1 > data_len { + return None; + } + let ret = LittleEndian::read_u16(&data[pos..pos + (value_len)]); + self.pos += value_len; + Some(ret) + } + pub fn get_u24(&mut self) -> Option { + let data = self.data.as_ref(); + let pos = self.pos; + let data_len = data.len(); + let value_len = 3; + if pos + value_len - 1 > data_len { + return None; + } + let ret = LittleEndian::read_u24(&data[pos..pos + (value_len)]); + self.pos += value_len; + Some(ret) + } + + pub fn get_u32(&mut self) -> Option { + let data = self.data.as_ref(); + let pos = self.pos; + let data_len = data.len(); + let value_len = core::mem::size_of::(); + if pos + value_len - 1 > data_len { + return None; + } + let ret = LittleEndian::read_u32(&data[pos..pos + (value_len)]); + self.pos += value_len; + Some(ret) + } + + pub fn get_u64(&mut self) -> Option { + let data = self.data.as_ref(); + let pos = self.pos; + let data_len = data.len(); + let value_len = core::mem::size_of::(); + if pos + value_len - 1 > data_len { + return None; + } + let ret = LittleEndian::read_u64(&data[pos..pos + (value_len)]); + self.pos += value_len; + Some(ret) + } + + pub fn get_buffer(&mut self, value_len: usize) -> Option<&[u8]> { + let data = self.data.as_ref(); + let pos = self.pos; + let data_len = data.len(); + if pos + value_len - 1 > data_len { + return None; + } + self.pos += value_len; + Some(&data[pos..(pos + value_len)]) + } + + pub fn used(&self) -> usize { + self.pos + } + + pub fn seek(&mut self, pos: usize) -> bool { + if pos > self.data.as_ref().len() { + return false; + } + self.pos = pos; + return true; + } +} + +pub struct Writer + AsMut<[u8]>> { + data: T, + pos: usize, +} + +impl + AsMut<[u8]>> Writer { + pub fn new_unchecked(buffer: T) -> Self { + Self { + data: buffer, + pos: 0usize, + } + } + + pub fn put_u8(&mut self, value: u8) -> Option { + let data = self.data.as_mut(); + let pos = self.pos; + let data_len = data.len(); + let value_len = 1; + if pos + value_len - 1 > data_len { + return None; + } + data[pos] = value; + self.pos += value_len; + Some(1) + } + + pub fn put_u16(&mut self, value: u16) -> Option { + let data = self.data.as_mut(); + let pos = self.pos; + let data_len = data.len(); + let value_len = core::mem::size_of::(); + if pos + value_len - 1 > data_len { + return None; + } + LittleEndian::write_u16(&mut data[pos..(pos + value_len)], value); + self.pos += value_len; + Some(value_len) + } + + pub fn put_u24(&mut self, value: u32) -> Option { + if value > 0xFF_FFFF { + return None; + } + let data = self.data.as_mut(); + let pos = self.pos; + let data_len = data.len(); + let value_len = 3; + if pos + value_len - 1 > data_len { + return None; + } + LittleEndian::write_u24(&mut data[pos..(pos + value_len)], value); + self.pos += value_len; + Some(value_len) + } + + pub fn put_u32(&mut self, value: u32) -> Option { + let data = self.data.as_mut(); + let pos = self.pos; + let data_len = data.len(); + let value_len = core::mem::size_of::(); + if pos + value_len - 1 > data_len { + return None; + } + LittleEndian::write_u32(&mut data[pos..(pos + value_len)], value); + self.pos += value_len; + Some(value_len) + } + + pub fn put_u64(&mut self, value: u64) -> Option { + let data = self.data.as_mut(); + let pos = self.pos; + let data_len = data.len(); + let value_len = core::mem::size_of::(); + if pos + value_len - 1 > data_len { + return None; + } + LittleEndian::write_u64(&mut data[pos..(pos + value_len)], value); + self.pos += value_len; + Some(value_len) + } + + pub fn put_buffer(&mut self, value: &[u8]) -> Option { + let data = self.data.as_mut(); + let pos = self.pos; + let data_len = data.len(); + let value_len = value.len(); + if pos + value_len - 1 > data_len { + return None; + } + data[pos..(pos + value_len)].copy_from_slice(value); + self.pos += value_len; + Some(value_len) + } + + pub fn used(&self) -> usize { + self.pos + } + + pub fn seek(&mut self, pos: usize) -> bool { + if pos > self.data.as_ref().len() { + return false; + } + self.pos = pos; + return true; + } +} + +// Vec<(fn(buffer: &mut [u8]) -> usize, secure_message: bool)> +pub fn run_responder_test_multi_fn( + config_info: SpdmConfigInfo, + provision_info: SpdmProvisionInfo, + input_fn: VecDeque<(fn(buffer: &mut [u8]) -> usize, bool)>, + expected_fn: VecDeque<(fn(buffer: &mut [u8]) -> usize, bool)>, + max_size: usize, +) { + let mut input = vec![0u8; max_size]; + let mut expected = vec![0u8; max_size]; + + let mut input_nwrite = 0usize; + let mut expected_nwrite = 0usize; + + for (f, secure_message) in input_fn { + let nwrite = wrapper_test_device_io(secure_message, &mut input[input_nwrite..], f); + input_nwrite += nwrite; + } + + for (f, secure_message) in expected_fn { + let nwrite = wrapper_test_device_io(secure_message, &mut expected[expected_nwrite..], f); + expected_nwrite += nwrite; + } + run_responder_test( + config_info, + provision_info, + &input[..input_nwrite], + &expected[..expected_nwrite], + ); +} + +pub fn run_responder_test_fn( + config_info: SpdmConfigInfo, + provision_info: SpdmProvisionInfo, + input_fn: fn(buffer: &mut [u8]) -> usize, + expected_fn: fn(buffer: &mut [u8]) -> usize, + max_size: usize, +) { + let mut input = vec![0u8; max_size]; + let mut expected = vec![0u8; max_size]; + + let nwrite = wrapper_test_device_io(false, &mut expected[..], expected_fn); + let expected_buffer = &expected[..nwrite]; + let nwrite = wrapper_test_device_io(false, &mut input[..], input_fn); + let input_buffer = &input[..nwrite]; + run_responder_test(config_info, provision_info, input_buffer, expected_buffer); +} + +pub fn run_responder_test, F: AsRef<[u8]>>( + config_info: SpdmConfigInfo, + provision_info: SpdmProvisionInfo, + input: T, + expected: F, +) { + let mut test_spdm_device_io = TestSpdmDeviceIo::new(); + let expected = expected.as_ref(); + let input = input.as_ref(); + test_spdm_device_io.load_expected(expected); + test_spdm_device_io.load_rx(input); + + let future = async { + let pcidoe_transport_encap = Arc::new(Mutex::new(TestTransportEncap {})); + let socket_io_transport = Arc::new(Mutex::new(test_spdm_device_io)); + + let mut context = responder::ResponderContext::new( + socket_io_transport, + pcidoe_transport_encap, + config_info, + provision_info, + ); + + assert!(context.process_message(ST1, &[0]).await.expect("error")); + loop { + let result = context.process_message(ST1, &[0]).await; + match result { + Err(nread) => { + if nread.0 == 0 { + break; + } else { + assert!(false, "won't run to here") + } + } + Ok(_) => continue, + } + } + }; + executor::block_on(future); +} + +pub fn hex_to_bin(hex: &str) -> Option> { + if hex.len() % 2 != 0 { + return None; + } + + let mut bytes = Vec::new(); + + for i in (0..hex.len()).step_by(2) { + if let Ok(byte) = u8::from_str_radix(&hex[i..i + 2], 16) { + bytes.push(byte); + } else { + return None; // Invalid hex characters + } + } + Some(bytes) +} + +#[test] +fn test_reader_writer() { + let mut buffer = [0u8; 1024]; + { + let mut writer = Writer::new_unchecked(&mut buffer[..]); + writer.put_u8(u8::MIN).unwrap(); + writer.put_u8(u8::MAX).unwrap(); + writer.put_u16(u16::MIN).unwrap(); + writer.put_u16(u16::MAX).unwrap(); + writer.put_u24(0).unwrap(); + writer.put_u24(0xFFFFFF).unwrap(); + assert!(writer.put_u24(0x1000000).is_none()); + writer.put_u32(u32::MIN).unwrap(); + writer.put_u32(u32::MAX).unwrap(); + writer.put_u64(u64::MIN).unwrap(); + writer.put_u64(u64::MAX).unwrap(); + writer.put_buffer(b"hello"); + assert_eq!(writer.used(), 41); + assert!(writer.seek(1000)); + writer.put_u24(0x5A_5A5A); + } + { + let mut reader = Reader::new_unchecked(&buffer[..]); + assert_eq!(reader.get_u8().unwrap(), u8::MIN); + assert_eq!(reader.get_u8().unwrap(), u8::MAX); + assert_eq!(reader.get_u16().unwrap(), u16::MIN); + assert_eq!(reader.get_u16().unwrap(), u16::MAX); + assert_eq!(reader.get_u24().unwrap(), 0); + assert_eq!(reader.get_u24().unwrap(), 0xFF_FFFF); + assert_eq!(reader.get_u32().unwrap(), u32::MIN); + assert_eq!(reader.get_u32().unwrap(), u32::MAX); + assert_eq!(reader.get_u64().unwrap(), u64::MIN); + assert_eq!(reader.get_u64().unwrap(), u64::MAX); + assert_eq!(reader.get_buffer(5).unwrap(), b"hello"); + assert_eq!(reader.used(), 41); + assert!(reader.seek(1000)); + assert_eq!(reader.get_u24().unwrap(), 0x5A_5A5A) + } +} diff --git a/test/spdmlib-test/src/responder_tests/algorithm_rsp.rs b/test/spdmlib-test/src/responder_tests/algorithm_rsp.rs index a91f009e..d60d949c 100644 --- a/test/spdmlib-test/src/responder_tests/algorithm_rsp.rs +++ b/test/spdmlib-test/src/responder_tests/algorithm_rsp.rs @@ -5,7 +5,8 @@ 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::{self, create_info, run_responder_test_multi_fn}; +use bit_field::BitField; use codec::{Codec, Reader, Writer}; use log::debug; use spdmlib::common::*; @@ -14,6 +15,7 @@ use spdmlib::protocol::*; use spdmlib::{responder, secret}; use spin::Mutex; extern crate alloc; +use alloc::collections::VecDeque; use alloc::sync::Arc; #[test] @@ -87,7 +89,7 @@ fn test_case0_handle_spdm_algorithm() { bytes.copy_from_slice(&spdm_message_header[0..]); bytes[2..].copy_from_slice(&negotiate_algorithms[0..1022]); - context.handle_spdm_algorithm(bytes).await; + assert!(context.handle_spdm_algorithm(bytes).await.is_ok()); let data = context.common.runtime_info.message_a.as_ref(); let u8_slice = &mut [0u8; 2048]; @@ -216,3 +218,176 @@ fn test_case0_handle_spdm_algorithm() { executor::block_on(future); } + +pub fn construct_algorithm_request_positive(buffer: &mut [u8]) -> usize { + let (config_info, _) = create_info(); + let mut writer = util::Writer::new_unchecked(buffer); + // SPDM Version 0x12 + writer.put_u8(0x12); + // RequestResponseCode 0xE3 + writer.put_u8(0xE3); + // Param1: number of algorithm structure tables in RespAlgStruct + writer.put_u8(4); + // Param2 + writer.put_u8(0x0); + // Length + writer.put_u16(48); // 32 (ExtAsym offset) + 4 * 16 (ReqAlgStruct * 4) + // MeasurementSpecification + writer.put_u8(config_info.measurement_specification.bits()); + // OtherParamSupport + writer.put_u8(config_info.opaque_support.bits()); + // BaseAsymAlgo + writer.put_u32(config_info.base_asym_algo.bits()); + // BaseHashAlgo + writer.put_u32(config_info.base_hash_algo.bits()); + // Reserved + writer.put_buffer(&[0u8; 12]); + // ExtAsymCount + writer.put_u8(0); + // ExtHashCount + writer.put_u8(0); + // Reserved + writer.put_u16(0); + // ExtAsym 0 + // ExtHash 0 + // ReqAlgStruct #1: AlgType DHE + writer.put_u8(2); + let mut alg_count = 0u8; + alg_count.set_bits(0..=3, 0); + alg_count.set_bits(4..=7, 2); + writer.put_u8(alg_count); + writer.put_u16(config_info.dhe_algo.bits()); + // ReqAlgStruct #2: AlgType AEAD + writer.put_u8(3); + let mut alg_count = 0u8; + alg_count.set_bits(0..=3, 0); + alg_count.set_bits(4..=7, 2); + writer.put_u8(alg_count); + writer.put_u16(config_info.aead_algo.bits()); + // ReqAlgStruct #3 + writer.put_u8(4); + let mut alg_count = 0u8; + alg_count.set_bits(0..=3, 0); + alg_count.set_bits(4..=7, 2); + writer.put_u8(alg_count); + writer.put_u16(config_info.req_asym_algo.bits()); + // ReqAlgStruct #4 + writer.put_u8(5); + let mut alg_count = 0u8; + alg_count.set_bits(0..=3, 0); + alg_count.set_bits(4..=7, 2); + writer.put_u8(alg_count); + writer.put_u16(config_info.key_schedule_algo.bits()); + + assert_eq!(writer.used(), 48); + writer.used() +} + +pub fn expected_algorithm_request_positive(buffer: &mut [u8]) -> usize { + let (config_info, _) = create_info(); + + let mut writer = util::Writer::new_unchecked(buffer); + writer.put_u8(0x12); + writer.put_u8(0x63); + // Param1: number of algorithm structure tables in RespAlgStruct + writer.put_u8(4); + // Param2 + writer.put_u8(0); + // Length + writer.put_u16(52); + // MeasurementSpecificationSel + writer.put_u8(config_info.measurement_specification.bits()); + // OtherParamSelection + writer.put_u8(config_info.opaque_support.bits()); + // MeasurementHashAlgo + writer.put_u32(config_info.measurement_hash_algo.bits()); + // BaseAsymSel + writer.put_u32(config_info.base_asym_algo.bits()); + // BaseHashSel + writer.put_u32(config_info.base_hash_algo.bits()); + // Reserved + writer.put_buffer(&[0u8; 12]); + // ExtAsymSelCount + writer.put_u8(0); + // ExtHashSelCount + writer.put_u8(0); + // Reserved + writer.put_buffer(&[0u8; 2]); + // ExtAsymSel + // ExtHashSel + // RespAlgoStruct + // ReqAlgStruct #1: AlgType DHE + writer.put_u8(2); + let mut alg_count = 0u8; + alg_count.set_bits(0..=3, 0); + alg_count.set_bits(4..=7, 2); + writer.put_u8(alg_count); + writer.put_u16(config_info.dhe_algo.bits()); + // ReqAlgStruct #2: AlgType AEAD + writer.put_u8(3); + let mut alg_count = 0u8; + alg_count.set_bits(0..=3, 0); + alg_count.set_bits(4..=7, 2); + writer.put_u8(alg_count); + writer.put_u16(config_info.aead_algo.bits()); + // ReqAlgStruct #3 + writer.put_u8(4); + let mut alg_count = 0u8; + alg_count.set_bits(0..=3, 0); + alg_count.set_bits(4..=7, 2); + writer.put_u8(alg_count); + writer.put_u16(config_info.req_asym_algo.bits()); + // ReqAlgStruct #4 + writer.put_u8(5); + let mut alg_count = 0u8; + alg_count.set_bits(0..=3, 0); + alg_count.set_bits(4..=7, 2); + writer.put_u8(alg_count); + writer.put_u16(config_info.key_schedule_algo.bits()); + + assert_eq!(writer.used(), 52); + writer.used() +} + +// checkpoint: +#[test] +fn test_case1_handle_spdm_algorithm() { + let mut input_fns: VecDeque<(fn(&mut [u8]) -> usize, bool)> = VecDeque::new(); + input_fns.push_back(( + crate::responder_tests::version_rsp::construct_version_request_positive, + false, + )); + input_fns.push_back(( + crate::responder_tests::capability_rsp::construct_capability_request_positive, + false, + )); + input_fns.push_back(( + crate::responder_tests::algorithm_rsp::construct_algorithm_request_positive, + false, + )); + + let mut expected_fns: VecDeque<(fn(&mut [u8]) -> usize, bool)> = VecDeque::new(); + expected_fns.push_back(( + crate::responder_tests::version_rsp::expected_version_response_positive, + false, + )); + expected_fns.push_back(( + crate::responder_tests::capability_rsp::expected_capability_request_positive, + false, + )); + expected_fns.push_back(( + crate::responder_tests::algorithm_rsp::expected_algorithm_request_positive, + false, + )); + + let (config_info, provision_info) = create_info(); + + secret::asym_sign::register(SECRET_ASYM_IMPL_INSTANCE.clone()); + run_responder_test_multi_fn( + config_info, + provision_info, + input_fns, + expected_fns, + 4096 * 3, + ); +} diff --git a/test/spdmlib-test/src/responder_tests/capability_rsp.rs b/test/spdmlib-test/src/responder_tests/capability_rsp.rs index fe0470ed..1df397dd 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::{self, create_info, run_responder_test_multi_fn}; use codec::{Codec, Reader, Writer}; use spdmlib::common::*; use spdmlib::message::*; @@ -13,8 +13,11 @@ use spdmlib::protocol::*; use spdmlib::{responder, secret}; use spin::Mutex; extern crate alloc; +use alloc::collections::VecDeque; use alloc::sync::Arc; +use bit_field::BitField; + #[test] fn test_case0_handle_spdm_capability() { let future = async { @@ -107,3 +110,91 @@ fn test_case0_handle_spdm_capability() { }; executor::block_on(future); } + +pub fn construct_capability_request_positive(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // SPDM Version 0x12 + writer.put_u8(0x12); + writer.put_u8(0xE1); + writer.put_u8(0x0); + writer.put_u8(0x0); + writer.put_u8(0x0); + writer.put_u8(7); // CTExponent + writer.put_u16(0); + + let mut flags = 0u32; + // ENCRYPT_CAP=1 MAC_CAP=1 KEY_EX_CAP=1 HBEAT_CAP=1 KEY_UPD_CAP=1 + flags.set_bit(6, true); + flags.set_bit(7, true); + flags.set_bit(9, true); + flags.set_bit(13, true); + flags.set_bit(14, true); + + let mut capabilities = SpdmRequestCapabilityFlags::empty(); + capabilities |= SpdmRequestCapabilityFlags::ENCRYPT_CAP; + capabilities |= SpdmRequestCapabilityFlags::MAC_CAP; + capabilities |= SpdmRequestCapabilityFlags::KEY_EX_CAP; + capabilities |= SpdmRequestCapabilityFlags::HBEAT_CAP; + capabilities |= SpdmRequestCapabilityFlags::KEY_UPD_CAP; + assert_eq!(capabilities.bits(), flags); + writer.put_u32(flags); + + // DataTransferSize + writer.put_u32(0x1000); + writer.put_u32(0x1000); + + assert_eq!(20, writer.used()); + + writer.used() +} + +pub fn expected_capability_request_positive(buffer: &mut [u8]) -> usize { + let (config_info, _) = create_info(); + + let mut writer = util::Writer::new_unchecked(buffer); + writer.put_u8(0x12); + writer.put_u8(0x61); + writer.put_u8(0); + writer.put_u8(0); + writer.put_u8(0); + // CTExponent 0 + writer.put_u8(config_info.rsp_ct_exponent); + + writer.put_u16(0); + + writer.put_u32(config_info.rsp_capabilities.bits()); + writer.put_u32(config_info.data_transfer_size); + writer.put_u32(config_info.max_spdm_msg_size); + assert_eq!(writer.used(), 20); + + writer.used() +} + +// checkpoint: +#[test] +fn test_case1_handle_spdm_capability() { + let mut input_fns: VecDeque<(fn(&mut [u8]) -> usize, bool)> = VecDeque::new(); + input_fns.push_back(( + crate::responder_tests::version_rsp::construct_version_request_positive, + false, + )); + input_fns.push_back((construct_capability_request_positive, false)); + + let mut expected_fns: VecDeque<(fn(&mut [u8]) -> usize, bool)> = VecDeque::new(); + expected_fns.push_back(( + crate::responder_tests::version_rsp::expected_version_response_positive, + false, + )); + expected_fns.push_back((expected_capability_request_positive, false)); + + let (config_info, provision_info) = create_info(); + + secret::asym_sign::register(SECRET_ASYM_IMPL_INSTANCE.clone()); + run_responder_test_multi_fn( + config_info, + provision_info, + input_fns, + expected_fns, + 4096 * 2, + ); +} diff --git a/test/spdmlib-test/src/responder_tests/certificate_rsp.rs b/test/spdmlib-test/src/responder_tests/certificate_rsp.rs index f9d5a0ba..d0cac05b 100644 --- a/test/spdmlib-test/src/responder_tests/certificate_rsp.rs +++ b/test/spdmlib-test/src/responder_tests/certificate_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::{self, create_info, run_responder_test_multi_fn}; use codec::{Codec, Writer}; use spdmlib::common::*; use spdmlib::message::*; @@ -13,6 +13,7 @@ use spdmlib::protocol::*; use spdmlib::{config, responder, secret}; use spin::Mutex; extern crate alloc; +use alloc::collections::VecDeque; use alloc::sync::Arc; #[test] @@ -67,7 +68,7 @@ fn test_case0_handle_spdm_certificate() { let bytes = &mut [0u8; 1024]; bytes.copy_from_slice(&spdm_message_header[0..]); bytes[2..].copy_from_slice(&capabilities[0..1022]); - context.handle_spdm_certificate(bytes, None).await; + assert!(context.handle_spdm_certificate(bytes, None).await.is_ok()); #[cfg(not(feature = "hashed-transcript-data"))] { @@ -116,3 +117,221 @@ fn test_case0_handle_spdm_certificate() { }; executor::block_on(future); } + +pub fn construct_certificate_request_part1_positive(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // SPDMVersion + writer.put_u8(0x12); + // RequestResponseCode + writer.put_u8(0x82); + // Param1: slot id. + writer.put_u8(0x0); + // Param2: reserved + writer.put_u8(0x0); + // Offset + writer.put_u16(0); + // Length + writer.put_u16(0x200); + writer.used() +} + +pub fn construct_certificate_request_part2_positive(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // SPDMVersion + writer.put_u8(0x12); + // RequestResponseCode + writer.put_u8(0x82); + // Param1: slot id. + writer.put_u8(0x0); + // Param2: reserved + writer.put_u8(0x0); + // Offset + writer.put_u16(0x200); + // Length + writer.put_u16(0x200); + writer.used() +} + +pub fn construct_certificate_request_part3_positive(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // SPDMVersion + writer.put_u8(0x12); + // RequestResponseCode + writer.put_u8(0x82); + // Param1: slot id. + writer.put_u8(0x0); + // Param2: reserved + writer.put_u8(0x0); + // Offset + writer.put_u16(0x400); + // Length + writer.put_u16(0x200); + writer.used() +} + +pub fn construct_certificate_request_part4_positive(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // SPDMVersion + writer.put_u8(0x12); + // RequestResponseCode + writer.put_u8(0x82); + // Param1: slot id. + writer.put_u8(0x0); + // Param2: reserved + writer.put_u8(0x0); + // Offset + writer.put_u16(0x600); + // Length + writer.put_u16(1535 + 4 + 48 - 0x600); + writer.used() +} + +pub fn expected_certificate_request_part1_positive(buffer: &mut [u8]) -> usize { + let spdm_cert = &mut [0u8; 4096]; + let len = crate::responder_tests::digest_rsp::generate_spdm_cert_chain( + include_bytes!("../../../../test_key/ecp384/bundle_responder.certchain.der"), + include_bytes!("../../../../test_key/ecp384/ca.cert.der"), + spdm_cert, + ); + let mut writer = util::Writer::new_unchecked(buffer); + // SPDMVersion + writer.put_u8(0x12); + // RequestResponseCode + writer.put_u8(0x2); + // Param1: slot id. + writer.put_u8(0x0); + // Param2: reserved + writer.put_u8(0x0); + // PortionLength + writer.put_u16(0x200); + // RemainderLength + writer.put_u16(len as u16 - 0x200); + // CertChainPart + writer.put_buffer(&spdm_cert[0..0x200]); + writer.used() +} + +pub fn expected_certificate_request_part2_positive(buffer: &mut [u8]) -> usize { + let spdm_cert = &mut [0u8; 4096]; + let len = crate::responder_tests::digest_rsp::generate_spdm_cert_chain( + include_bytes!("../../../../test_key/ecp384/bundle_responder.certchain.der"), + include_bytes!("../../../../test_key/ecp384/ca.cert.der"), + spdm_cert, + ); + let mut writer = util::Writer::new_unchecked(buffer); + // SPDMVersion + writer.put_u8(0x12); + // RequestResponseCode + writer.put_u8(0x2); + // Param1: slot id. + writer.put_u8(0x0); + // Param2: reserved + writer.put_u8(0x0); + // PortionLength + writer.put_u16(0x200); + // RemainderLength + writer.put_u16(len as u16 - 0x400); + // CertChainPart + let buffer = &mut [0u8; 0x1000]; + writer.put_buffer(&spdm_cert[0x200..0x400]); + writer.used() +} + +pub fn expected_certificate_request_part3_positive(buffer: &mut [u8]) -> usize { + let spdm_cert = &mut [0u8; 4096]; + let len = crate::responder_tests::digest_rsp::generate_spdm_cert_chain( + include_bytes!("../../../../test_key/ecp384/bundle_responder.certchain.der"), + include_bytes!("../../../../test_key/ecp384/ca.cert.der"), + spdm_cert, + ); + let mut writer = util::Writer::new_unchecked(buffer); + // SPDMVersion + writer.put_u8(0x12); + // RequestResponseCode + writer.put_u8(0x2); + // Param1: slot id. + writer.put_u8(0x0); + // Param2: reserved + writer.put_u8(0x0); + // PortionLength + writer.put_u16(0x200); + // RemainderLength + writer.put_u16(len as u16 - 0x600); + // CertChainPart + writer.put_buffer(&spdm_cert[0x400..0x600]); + writer.used() +} + +pub fn expected_certificate_request_part4_positive(buffer: &mut [u8]) -> usize { + let spdm_cert = &mut [0u8; 4096]; + let len = crate::responder_tests::digest_rsp::generate_spdm_cert_chain( + include_bytes!("../../../../test_key/ecp384/bundle_responder.certchain.der"), + include_bytes!("../../../../test_key/ecp384/ca.cert.der"), + spdm_cert, + ); + let mut writer = util::Writer::new_unchecked(buffer); + // SPDMVersion + writer.put_u8(0x12); + // RequestResponseCode + writer.put_u8(0x2); + // Param1: slot id. + writer.put_u8(0x0); + // Param2: reserved + writer.put_u8(0x0); + // PortionLength + writer.put_u16(len as u16 - 0x600); + // RemainderLength + writer.put_u16(0); + // CertChainPart + writer.put_buffer(&spdm_cert[0x600..len]); + writer.used() +} + +#[test] +fn test_case1_handle_spdm_certificate() { + let mut input_fns: VecDeque<(fn(&mut [u8]) -> usize, bool)> = VecDeque::new(); + input_fns.push_back(( + crate::responder_tests::version_rsp::construct_version_request_positive, + false, + )); + input_fns.push_back(( + crate::responder_tests::capability_rsp::construct_capability_request_positive, + false, + )); + input_fns.push_back(( + crate::responder_tests::algorithm_rsp::construct_algorithm_request_positive, + false, + )); + input_fns.push_back((construct_certificate_request_part1_positive, false)); + input_fns.push_back((construct_certificate_request_part2_positive, false)); + input_fns.push_back((construct_certificate_request_part3_positive, false)); + input_fns.push_back((construct_certificate_request_part4_positive, false)); + + let mut expected_fns: VecDeque<(fn(&mut [u8]) -> usize, bool)> = VecDeque::new(); + expected_fns.push_back(( + crate::responder_tests::version_rsp::expected_version_response_positive, + false, + )); + expected_fns.push_back(( + crate::responder_tests::capability_rsp::expected_capability_request_positive, + false, + )); + expected_fns.push_back(( + crate::responder_tests::algorithm_rsp::expected_algorithm_request_positive, + false, + )); + expected_fns.push_back((expected_certificate_request_part1_positive, false)); + expected_fns.push_back((expected_certificate_request_part2_positive, false)); + expected_fns.push_back((expected_certificate_request_part3_positive, false)); + expected_fns.push_back((expected_certificate_request_part4_positive, false)); + + let (config_info, provision_info) = create_info(); + secret::asym_sign::register(SECRET_ASYM_IMPL_INSTANCE.clone()); + run_responder_test_multi_fn( + config_info, + provision_info, + input_fns, + expected_fns, + 4096 * 4, + ); +} diff --git a/test/spdmlib-test/src/responder_tests/challenge_rsp.rs b/test/spdmlib-test/src/responder_tests/challenge_rsp.rs index 20449c8d..255f8096 100644 --- a/test/spdmlib-test/src/responder_tests/challenge_rsp.rs +++ b/test/spdmlib-test/src/responder_tests/challenge_rsp.rs @@ -8,7 +8,7 @@ use crate::common::crypto_callback::FAKE_RAND; 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::{self, create_info, run_responder_test_multi_fn}; use codec::{Codec, Reader, Writer}; use spdmlib::common::*; use spdmlib::message::SpdmChallengeRequestPayload; @@ -17,6 +17,7 @@ use spdmlib::protocol::*; use spdmlib::{config, crypto, responder, secret}; use spin::Mutex; extern crate alloc; +use alloc::collections::VecDeque; use alloc::sync::Arc; #[test] @@ -82,7 +83,7 @@ fn test_case0_handle_spdm_challenge() { let bytes = &mut [0u8; 4 + SPDM_NONCE_SIZE]; bytes[0..2].copy_from_slice(&spdm_message_header[0..]); bytes[2..4 + SPDM_NONCE_SIZE].copy_from_slice(&challenge[0..2 + SPDM_NONCE_SIZE]); - context.handle_spdm_challenge(bytes).await; + assert!(context.handle_spdm_challenge(bytes).await.is_ok()); #[cfg(not(feature = "hashed-transcript-data"))] { @@ -164,3 +165,125 @@ fn test_case0_handle_spdm_challenge() { }; executor::block_on(future); } + +pub fn construct_challenge_request_positive(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // SPDMVersion + writer.put_u8(0x12); + // RequestResponseCode + writer.put_u8(0x83); + // Param1: slot id. + writer.put_u8(0x0); + // Param2: reserved + writer.put_u8(0x0); + // Nonce 32 + writer.put_buffer(&mut [0u8; 32]); + writer.used() +} + +pub fn expected_challenge_request_positive(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // SPDMVersion + writer.put_u8(0x12); + // RequestResponseCode + writer.put_u8(0x3); + // Param1: Slot attibute. + writer.put_u8(0x0); + // Param2: Slot mask Why 1 + writer.put_u8(0x1); + // CertChain Hash + let certchain_hash = crate::responder_tests::digest_rsp::generate_spdm_cert_chain_digest( + include_bytes!("../../../../test_key/ecp384/bundle_responder.certchain.der"), + include_bytes!("../../../../test_key/ecp384/ca.cert.der"), + ); + writer.put_buffer(certchain_hash.as_ref()); + // Responder Nonce + writer.put_buffer(&mut [0xFFu8; 32]); + // MeasurementSummaryHash nil + // OpaqueDatalength + writer.put_u16(0x0); + // OpaqueData nil + assert_eq!(writer.used(), 86); + // Signature + writer.put_buffer(&mut [0x5au8; 96]); + writer.used() +} + +#[test] +fn test_case1_handle_challenge_positive() { + env_logger::Builder::from_default_env().init(); + + spdmlib::crypto::rand::register(FAKE_RAND.clone()); + + let mut input_fns: VecDeque<(fn(&mut [u8]) -> usize, bool)> = VecDeque::new(); + input_fns.push_back(( + crate::responder_tests::version_rsp::construct_version_request_positive, + false, + )); + input_fns.push_back(( + crate::responder_tests::capability_rsp::construct_capability_request_positive, + false, + )); + input_fns.push_back(( + crate::responder_tests::algorithm_rsp::construct_algorithm_request_positive, + false, + )); + input_fns.push_back(( + crate::responder_tests::certificate_rsp::construct_certificate_request_part1_positive, + false, + )); + input_fns.push_back(( + crate::responder_tests::certificate_rsp::construct_certificate_request_part2_positive, + false, + )); + input_fns.push_back(( + crate::responder_tests::certificate_rsp::construct_certificate_request_part3_positive, + false, + )); + input_fns.push_back(( + crate::responder_tests::certificate_rsp::construct_certificate_request_part4_positive, + false, + )); + input_fns.push_back((construct_challenge_request_positive, false)); + + let mut expected_fns: VecDeque<(fn(&mut [u8]) -> usize, bool)> = VecDeque::new(); + expected_fns.push_back(( + crate::responder_tests::version_rsp::expected_version_response_positive, + false, + )); + expected_fns.push_back(( + crate::responder_tests::capability_rsp::expected_capability_request_positive, + false, + )); + expected_fns.push_back(( + crate::responder_tests::algorithm_rsp::expected_algorithm_request_positive, + false, + )); + expected_fns.push_back(( + crate::responder_tests::certificate_rsp::expected_certificate_request_part1_positive, + false, + )); + expected_fns.push_back(( + crate::responder_tests::certificate_rsp::expected_certificate_request_part2_positive, + false, + )); + expected_fns.push_back(( + crate::responder_tests::certificate_rsp::expected_certificate_request_part3_positive, + false, + )); + expected_fns.push_back(( + crate::responder_tests::certificate_rsp::expected_certificate_request_part4_positive, + false, + )); + expected_fns.push_back((expected_challenge_request_positive, false)); + + let (config_info, provision_info) = create_info(); + secret::asym_sign::register(SECRET_ASYM_IMPL_INSTANCE.clone()); + run_responder_test_multi_fn( + config_info, + provision_info, + input_fns, + expected_fns, + 4096 * 4, + ); +} diff --git a/test/spdmlib-test/src/responder_tests/digest_rsp.rs b/test/spdmlib-test/src/responder_tests/digest_rsp.rs index e83529a2..6ec79618 100644 --- a/test/spdmlib-test/src/responder_tests/digest_rsp.rs +++ b/test/spdmlib-test/src/responder_tests/digest_rsp.rs @@ -5,13 +5,14 @@ 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::{self, create_info, run_responder_test_multi_fn}; use codec::{Codec, Writer}; use spdmlib::message::*; use spdmlib::protocol::*; use spdmlib::{config, responder, secret}; use spin::Mutex; extern crate alloc; +use alloc::collections::VecDeque; use alloc::sync::Arc; #[test] @@ -52,12 +53,142 @@ fn test_case0_handle_spdm_digest() { let mut writer = Writer::init(spdm_message_header); let value = SpdmMessageHeader { version: SpdmVersion::SpdmVersion10, - request_response_code: SpdmRequestResponseCode::SpdmRequestChallenge, + request_response_code: SpdmRequestResponseCode::SpdmRequestGetDigests, }; assert!(value.encode(&mut writer).is_ok()); let bytes = &mut [0u8; 1024]; - context.handle_spdm_digest(bytes, None).await; + assert!(context.handle_spdm_digest(bytes, None).await.is_ok()); }; executor::block_on(future); } + +// Note: spdm version 0x12 +// +pub fn construct_digest_request_positive(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // SPDM Version + writer.put_u8(0x12); + writer.put_u8(0x81); + writer.put_u8(0x0); + writer.put_u8(0x0); + writer.used() +} + +pub fn expected_digest_requeset_negative(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // should send VAC first return ERROR + writer.put_u8(0x12); + writer.put_u8(0x7f); + writer.put_u8(0x04); + writer.put_u8(0); + writer.used() +} + +// Checkpoint: for test_case0_handle_spdm_digest +#[test] +fn test_case1_handle_spdm_digest() { + let mut input_fns: VecDeque<(fn(&mut [u8]) -> usize, bool)> = VecDeque::new(); + input_fns.push_back((construct_digest_request_positive, false)); + + let mut expected_fns: VecDeque<(fn(&mut [u8]) -> usize, bool)> = VecDeque::new(); + expected_fns.push_back((expected_digest_requeset_negative, false)); + + let (config_info, provision_info) = create_info(); + secret::asym_sign::register(SECRET_ASYM_IMPL_INSTANCE.clone()); + run_responder_test_multi_fn(config_info, provision_info, input_fns, expected_fns, 4096); +} + +pub fn expected_digest_request_positive(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // Version + writer.put_u8(0x12); + // RequestResponseCode + writer.put_u8(0x01); + // Param1 + writer.put_u8(0x0); + // Param2 slot fields + writer.put_u8(1); + // Hash hash385 sha384sum test_key/ecp384/bundle_responder.certchain.der + // cert_chain: test_key/ecp384/bundle_responder.certchain.der + // root_cert: test_key/ecp384/ca.cert.der + // Length: 0..2 1535 + 48 + 4 + // Reserved: 2..4 + // RootHash: 4..(48+4) + // Certificates: 52.. + writer.put_buffer( + generate_spdm_cert_chain_digest( + include_bytes!("../../../../test_key/ecp384/bundle_responder.certchain.der"), + include_bytes!("../../../../test_key/ecp384/ca.cert.der"), + ) + .as_ref(), + ); + writer.used() +} + +pub fn generate_spdm_cert_chain(cert_chain: &[u8], root_cert: &[u8], buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // Length + writer.put_u16((cert_chain.len() + 48 + 4) as u16); + // Reserved + writer.put_u16(0); + // RootHash + let root_cert_hash = + spdmlib::crypto::hash::hash_all(SpdmBaseHashAlgo::TPM_ALG_SHA_384, root_cert).unwrap(); + writer.put_buffer(root_cert_hash.as_ref()); + // Certificates + writer.put_buffer(cert_chain); + writer.used() +} +pub fn generate_spdm_cert_chain_digest(cert_chain: &[u8], root_cert: &[u8]) -> SpdmDigestStruct { + let mut buffer = [0u8; 4096]; + let nwrite = generate_spdm_cert_chain(cert_chain, root_cert, &mut buffer[..]); + let buffer = &buffer[0..nwrite]; + let digest = + spdmlib::crypto::hash::hash_all(SpdmBaseHashAlgo::TPM_ALG_SHA_384, buffer).unwrap(); + return digest; +} + +// Checkpoint: Positive flow +#[test] +fn test_case2_handle_spdm_digest() { + let mut input_fns: VecDeque<(fn(&mut [u8]) -> usize, bool)> = VecDeque::new(); + input_fns.push_back(( + crate::responder_tests::version_rsp::construct_version_request_positive, + false, + )); + input_fns.push_back(( + crate::responder_tests::capability_rsp::construct_capability_request_positive, + false, + )); + input_fns.push_back(( + crate::responder_tests::algorithm_rsp::construct_algorithm_request_positive, + false, + )); + input_fns.push_back((construct_digest_request_positive, false)); + + let mut expected_fns: VecDeque<(fn(&mut [u8]) -> usize, bool)> = VecDeque::new(); + expected_fns.push_back(( + crate::responder_tests::version_rsp::expected_version_response_positive, + false, + )); + expected_fns.push_back(( + crate::responder_tests::capability_rsp::expected_capability_request_positive, + false, + )); + expected_fns.push_back(( + crate::responder_tests::algorithm_rsp::expected_algorithm_request_positive, + false, + )); + expected_fns.push_back((expected_digest_request_positive, false)); + + let (config_info, provision_info) = create_info(); + secret::asym_sign::register(SECRET_ASYM_IMPL_INSTANCE.clone()); + run_responder_test_multi_fn( + config_info, + provision_info, + input_fns, + expected_fns, + 4096 * 4, + ); +} diff --git a/test/spdmlib-test/src/responder_tests/version_rsp.rs b/test/spdmlib-test/src/responder_tests/version_rsp.rs index 5f77fbed..89e99f3b 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::{self, create_info, run_responder_test_fn}; use codec::{Codec, Reader, Writer}; use spdmlib::common::*; use spdmlib::message::*; @@ -43,7 +43,7 @@ fn test_case0_handle_spdm_version() { }; assert!(value.encode(&mut writer).is_ok()); - context.handle_spdm_version(bytes).await; + assert!(!context.handle_spdm_version(bytes).await.is_ok()); let data = context.common.runtime_info.message_a.as_ref(); let u8_slice = &mut [0u8; 1024]; @@ -81,3 +81,104 @@ fn test_case0_handle_spdm_version() { }; executor::block_on(future); } + +// checkpoint: +// GetVersion Positive +pub fn construct_version_request_positive(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // SPDM Version + writer.put_u8(0x10); + writer.put_u8(0x84); + writer.put_u8(0x0); + writer.put_u8(0x0); + writer.used() +} +pub fn expected_version_response_positive(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // SPDM Version + writer.put_u8(0x10); + writer.put_u8(0x04); + writer.put_u8(0x0); + writer.put_u8(0x0); + writer.put_u8(0x0); + writer.put_u8(0x3); + writer.put_u16(0x1000); + writer.put_u16(0x1100); + writer.put_u16(0x1200); + writer.used() +} +#[test] +fn test_case1_handle_spdm_version() { + let expected_fn = expected_version_response_positive; + let input_fn = construct_version_request_positive; + let (config_info, provision_info) = create_info(); + secret::asym_sign::register(SECRET_ASYM_IMPL_INSTANCE.clone()); + run_responder_test_fn(config_info, provision_info, input_fn, expected_fn, 4096); +} + +// checkpoint: +// GetVersion Negative Case1 SPDM Version shall be 0x10 +// Expected Result return SPDM Error response Error(0x7F) InvalidRequest(0x1) +pub fn construct_version_request_negative(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // SPDM Version + // SPDM Version shall be 0x10 + // SPDM is 0x11 shall return SPDM ERROR response + writer.put_u8(0x11); + writer.put_u8(0x84); + writer.put_u8(0x0); + writer.put_u8(0x0); + writer.used() +} +pub fn expected_version_request_negative(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + writer.put_u8(0x10); + // SPDM RequestResponse Code is ERROR + writer.put_u8(0x7F); + // Requested SPDM version is not supported or is a different version from the selected version.(0x41) + writer.put_u8(0x41); + writer.put_u8(0x0); + writer.used() +} + +#[test] +fn test_case2_handle_spdm_version() { + let expected_fn = expected_version_request_negative; + let input_fn = construct_version_request_negative; + let (config_info, provision_info) = create_info(); + secret::asym_sign::register(SECRET_ASYM_IMPL_INSTANCE.clone()); + run_responder_test_fn(config_info, provision_info, input_fn, expected_fn, 4096); +} + +// checkpoint: +// GetVersion Negative Case2 If there is no get version. +// GetCapabilities should be failed. +pub fn construct_version_request_negative_2(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // SPDM Version + writer.put_u8(0x10); + writer.put_u8(0xE1); + writer.put_u8(0x0); + writer.put_u8(0x0); + writer.used() +} + +pub fn expected_version_request_negative_2(buffer: &mut [u8]) -> usize { + let mut writer = util::Writer::new_unchecked(buffer); + // SPDM Version + writer.put_u8(0x10); + // Return Error Message + writer.put_u8(0x7F); + // return ErrorCode is UnexpectedRequest(0x04) + writer.put_u8(0x4); + writer.put_u8(0x0); + writer.used() +} +#[test] +fn test_case3_handle_spdm_version() { + let expected_fn = expected_version_request_negative_2; + let input_fn = construct_version_request_negative_2; + let (config_info, provision_info) = create_info(); + secret::asym_sign::register(SECRET_ASYM_IMPL_INSTANCE.clone()); + run_responder_test_fn(config_info, provision_info, input_fn, expected_fn, 4096); +}