underhill_attestation/igvm_attest/
ak_cert.rs1use crate::igvm_attest::Error as CommonError;
7use crate::igvm_attest::parse_response_header;
8
9use thiserror::Error;
10
11#[derive(Debug, Error)]
13pub enum AkCertError {
14 #[error(
15 "AK cert response is too small to parse. Found {size} bytes but expected at least {minimum_size}"
16 )]
17 SizeTooSmall { size: usize, minimum_size: usize },
18 #[error(
19 "AK cert response size {specified_size} specified in the header is larger then the actual size {size}"
20 )]
21 SizeMismatch { size: usize, specified_size: usize },
22 #[error(
23 "AK cert response header version {version} does match the expected version {expected_version}"
24 )]
25 HeaderVersionMismatch { version: u32, expected_version: u32 },
26 #[error("error in parsing response header")]
27 ParseHeader(#[source] CommonError),
28 #[error("invalid response header version: {0}")]
29 InvalidResponseVersion(u32),
30}
31
32pub fn parse_response(response: &[u8]) -> Result<Vec<u8>, AkCertError> {
36 use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestAkCertResponseHeader;
37 use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestCommonResponseHeader;
38 use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestResponseVersion;
39
40 let header = parse_response_header(response).map_err(AkCertError::ParseHeader)?;
41
42 let header_size = match header.version {
44 IgvmAttestResponseVersion::VERSION_1 => size_of::<IgvmAttestCommonResponseHeader>(),
45 IgvmAttestResponseVersion::VERSION_2 => size_of::<IgvmAttestAkCertResponseHeader>(),
46 invalid_version => return Err(AkCertError::InvalidResponseVersion(invalid_version.0)),
47 };
48
49 Ok(response[header_size..header.data_size as usize].to_vec())
50}
51
52#[cfg(test)]
53mod tests {
54 use super::*;
55 use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestAkCertResponseHeader;
56 use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestCommonResponseHeader;
57 use zerocopy::FromBytes;
58
59 #[test]
60 fn test_undersized_response() {
61 const HEADER_SIZE: usize = size_of::<IgvmAttestAkCertResponseHeader>();
62 let properly_sized_response: [u8; HEADER_SIZE] = [1; HEADER_SIZE];
63 let undersized_response = &properly_sized_response[..HEADER_SIZE - 1];
64
65 let result = parse_response(&[]);
67 assert!(result.is_err());
68 assert_eq!(
69 result.unwrap_err().to_string(),
70 AkCertError::ParseHeader(CommonError::ResponseSizeTooSmall { response_size: 0 })
71 .to_string()
72 );
73
74 let undersized_parse_ = parse_response(undersized_response);
76 assert!(undersized_parse_.is_err());
77 assert_eq!(
78 undersized_parse_.unwrap_err().to_string(),
79 AkCertError::ParseHeader(CommonError::ResponseSizeTooSmall {
80 response_size: HEADER_SIZE - 1
81 })
82 .to_string()
83 );
84
85 let properly_sized_parse = parse_response(&properly_sized_response);
88 assert!(
89 !properly_sized_parse
90 .unwrap_err()
91 .to_string()
92 .starts_with("AK cert response is too small to parse"),
93 );
94 }
95
96 #[test]
97 fn test_valid_response_size_match() {
98 const VALID_RESPONSE: [u8; 56] = [
99 0x38, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x82, 0x03, 0xeb, 0x30, 0x82,
100 0x02, 0xd3, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x3b, 0xa3, 0x33, 0x97, 0xef,
101 0x2f, 0x9e, 0xef, 0xbd, 0x35, 0x5e, 0xda, 0xdd, 0x27, 0x38, 0x42, 0x30, 0x0d, 0x06,
102 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x25,
103 ];
104
105 const HEADER_SIZE: usize = size_of::<IgvmAttestCommonResponseHeader>();
106 let result = IgvmAttestAkCertResponseHeader::read_from_prefix(&VALID_RESPONSE);
107 assert!(result.is_ok());
108
109 let result = parse_response(&VALID_RESPONSE);
110 assert!(result.is_ok());
111
112 let payload = result.unwrap();
113 let data_size = parse_response_header(&VALID_RESPONSE).unwrap().data_size as usize;
114 assert_eq!(payload.len(), data_size - HEADER_SIZE);
115 assert_eq!(payload, &VALID_RESPONSE[HEADER_SIZE..data_size]);
116 }
117
118 #[test]
119 fn test_valid_response_size_smaller_than_specified() {
120 const VALID_RESPONSE: [u8; 56] = [
121 0x37, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x82, 0x03, 0xeb, 0x30, 0x82,
122 0x02, 0xd3, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x3b, 0xa3, 0x33, 0x97, 0xef,
123 0x2f, 0x9e, 0xef, 0xbd, 0x35, 0x5e, 0xda, 0xdd, 0x27, 0x38, 0x42, 0x30, 0x0d, 0x06,
124 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x25,
125 ];
126
127 const HEADER_SIZE: usize = size_of::<IgvmAttestCommonResponseHeader>();
128
129 let result = IgvmAttestAkCertResponseHeader::read_from_prefix(&VALID_RESPONSE);
130 assert!(result.is_ok());
131
132 let result = parse_response(&VALID_RESPONSE);
133 assert!(result.is_ok());
134
135 let payload = result.unwrap();
136 let data_size = parse_response_header(&VALID_RESPONSE).unwrap().data_size as usize;
137 assert_eq!(payload.len(), data_size - HEADER_SIZE);
138 assert_eq!(payload, &VALID_RESPONSE[HEADER_SIZE..data_size]);
139 }
140}