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 let data_size = header.data_size as usize;
49
50 if data_size < header_size {
51 return Err(AkCertError::SizeTooSmall {
52 size: data_size,
53 minimum_size: header_size,
54 });
55 }
56
57 Ok(response[header_size..data_size].to_vec())
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestAkCertResponseHeader;
64 use openhcl_attestation_protocol::igvm_attest::get::IgvmAttestCommonResponseHeader;
65 use zerocopy::FromBytes;
66
67 #[test]
68 fn test_undersized_response() {
69 const HEADER_SIZE: usize = size_of::<IgvmAttestAkCertResponseHeader>();
70 let properly_sized_response: [u8; HEADER_SIZE] = [1; HEADER_SIZE];
71 let undersized_response = &properly_sized_response[..HEADER_SIZE - 1];
72
73 let result = parse_response(&[]);
75 assert!(result.is_err());
76 assert_eq!(
77 result.unwrap_err().to_string(),
78 AkCertError::ParseHeader(CommonError::ResponseSizeTooSmall { response_size: 0 })
79 .to_string()
80 );
81
82 let undersized_parse_ = parse_response(undersized_response);
84 assert!(undersized_parse_.is_err());
85 assert_eq!(
86 undersized_parse_.unwrap_err().to_string(),
87 AkCertError::ParseHeader(CommonError::ResponseSizeTooSmall {
88 response_size: HEADER_SIZE - 1
89 })
90 .to_string()
91 );
92
93 let properly_sized_parse = parse_response(&properly_sized_response);
96 assert!(
97 !properly_sized_parse
98 .unwrap_err()
99 .to_string()
100 .starts_with("AK cert response is too small to parse"),
101 );
102 }
103
104 #[test]
105 fn test_valid_response_size_match() {
106 const VALID_RESPONSE: [u8; 56] = [
107 0x38, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x82, 0x03, 0xeb, 0x30, 0x82,
108 0x02, 0xd3, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x3b, 0xa3, 0x33, 0x97, 0xef,
109 0x2f, 0x9e, 0xef, 0xbd, 0x35, 0x5e, 0xda, 0xdd, 0x27, 0x38, 0x42, 0x30, 0x0d, 0x06,
110 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x25,
111 ];
112
113 const HEADER_SIZE: usize = size_of::<IgvmAttestCommonResponseHeader>();
114 let result = IgvmAttestAkCertResponseHeader::read_from_prefix(&VALID_RESPONSE);
115 assert!(result.is_ok());
116
117 let result = parse_response(&VALID_RESPONSE);
118 assert!(result.is_ok());
119
120 let payload = result.unwrap();
121 let data_size = parse_response_header(&VALID_RESPONSE).unwrap().data_size as usize;
122 assert_eq!(payload.len(), data_size - HEADER_SIZE);
123 assert_eq!(payload, &VALID_RESPONSE[HEADER_SIZE..data_size]);
124 }
125
126 #[test]
127 fn test_parse_response_small_size() {
128 let mut response = [0u8; 8];
129 response[0..4].copy_from_slice(&4u32.to_le_bytes());
131 response[4..8].copy_from_slice(&1u32.to_le_bytes());
133
134 assert!(parse_response(&response).is_err());
135 }
136
137 #[test]
138 fn test_valid_response_size_smaller_than_specified() {
139 const VALID_RESPONSE: [u8; 56] = [
140 0x37, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x30, 0x82, 0x03, 0xeb, 0x30, 0x82,
141 0x02, 0xd3, 0xa0, 0x03, 0x02, 0x01, 0x02, 0x02, 0x10, 0x3b, 0xa3, 0x33, 0x97, 0xef,
142 0x2f, 0x9e, 0xef, 0xbd, 0x35, 0x5e, 0xda, 0xdd, 0x27, 0x38, 0x42, 0x30, 0x0d, 0x06,
143 0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x0b, 0x05, 0x00, 0x30, 0x25,
144 ];
145
146 const HEADER_SIZE: usize = size_of::<IgvmAttestCommonResponseHeader>();
147
148 let result = IgvmAttestAkCertResponseHeader::read_from_prefix(&VALID_RESPONSE);
149 assert!(result.is_ok());
150
151 let result = parse_response(&VALID_RESPONSE);
152 assert!(result.is_ok());
153
154 let payload = result.unwrap();
155 let data_size = parse_response_header(&VALID_RESPONSE).unwrap().data_size as usize;
156 assert_eq!(payload.len(), data_size - HEADER_SIZE);
157 assert_eq!(payload, &VALID_RESPONSE[HEADER_SIZE..data_size]);
158 }
159}