1use core::str::from_utf8;
2
3use alloc::string::{String, ToString};
4use tinyvec::ArrayVec;
5
6use super::MeasurementError;
7use crate::BootMeasurement;
8use crate::ValueHash;
9
10pub const MEASUREMENT_VALUE_MIN_SIZE: usize = 32;
12pub const MEASUREMENT_VALUE_MAX_SIZE: usize = 64;
14pub const SIGNER_ID_MIN_SIZE: usize = MEASUREMENT_VALUE_MIN_SIZE;
16pub const SIGNER_ID_MAX_SIZE: usize = MEASUREMENT_VALUE_MAX_SIZE;
18pub const VERSION_MAX_SIZE: usize = 14;
20pub const SW_TYPE_MAX_SIZE: usize = 32;
22
23const SIGNER_ID_SIZE_ERROR_MSG: &'static str = "SignerIdSize";
25const SW_VERSION_SIZE_ERROR_MSG: &'static str = "SWVersionSize";
27const SW_VERSION_VALUE_ERROR_MSG: &'static str = "SWVersionNotUtf8";
29const SW_TYPE_SIZE_ERROR_MSG: &'static str = "SWTypeSize";
31const SW_TYPE_VALUE_ERROR_MSG: &'static str = "SWTypeNotUtf8";
33const MEASUREMENT_VALUE_SIZE_ERROR_MSG: &'static str = "MeasurementValueSize";
35
36const MEASUREMENT_TYPE_ERROR_MSG: &'static str = "MeasurementType";
38
39#[derive(Debug, Copy, Clone, PartialEq)]
41pub enum MeasurementType {
42 Sha256,
43 Sha384,
44 Sha512,
45}
46
47impl Default for MeasurementType {
48 fn default() -> Self {
51 Self::Sha256
52 }
53}
54
55impl TryFrom<u16> for MeasurementType {
56 type Error = MeasurementError;
57 fn try_from(value: u16) -> Result<Self, Self::Error> {
61 match value {
62 0 => Ok(Self::Sha256),
63 1 => Ok(Self::Sha384),
64 2 => Ok(Self::Sha512),
65 _ => Err(MeasurementError::InvalidData(MEASUREMENT_TYPE_ERROR_MSG)),
66 }
67 }
68}
69
70impl MeasurementType {
71 pub fn hash_len(&self) -> usize {
72 match self {
73 MeasurementType::Sha256 => 32,
74 MeasurementType::Sha384 => 48,
75 MeasurementType::Sha512 => 64,
76 }
77 }
78}
79
80pub type SignerHash = ArrayVec<[u8; SIGNER_ID_MAX_SIZE]>;
81pub type SWVersion = String;
82pub type SWType = String;
83
84#[derive(Debug, Default, Clone, PartialEq)]
86pub struct MeasurementMetaData {
87 pub signer_id: SignerHash,
89 pub sw_version: SWVersion,
91 pub algorithm: MeasurementType,
94 pub sw_type: SWType,
96}
97
98#[derive(Debug, Default, Clone, PartialEq)]
100pub struct Measurement {
101 pub metadata: MeasurementMetaData,
103 pub value: ValueHash,
105}
106
107impl TryFrom<BootMeasurement> for Measurement {
108 type Error = MeasurementError;
109 fn try_from(value: BootMeasurement) -> Result<Self, Self::Error> {
112 if value.metadata.signer_id.len() < SIGNER_ID_MIN_SIZE
113 || value.metadata.signer_id.len() > SIGNER_ID_MAX_SIZE
114 {
115 return Err(MeasurementError::InvalidData(SIGNER_ID_SIZE_ERROR_MSG));
116 }
117
118 if value.metadata.sw_version.len() > VERSION_MAX_SIZE {
119 return Err(MeasurementError::InvalidData(SW_VERSION_SIZE_ERROR_MSG));
120 }
121
122 if value.metadata.sw_type.len() > SW_TYPE_MAX_SIZE {
123 return Err(MeasurementError::InvalidData(SW_TYPE_SIZE_ERROR_MSG));
124 }
125
126 if value.measurement_value.len() < MEASUREMENT_VALUE_MIN_SIZE
127 || value.measurement_value.len() > MEASUREMENT_VALUE_MAX_SIZE
128 {
129 return Err(MeasurementError::InvalidData(
130 MEASUREMENT_VALUE_SIZE_ERROR_MSG,
131 ));
132 }
133
134 let sw_version = match from_utf8(&value.metadata.sw_version) {
135 Ok(version_str) => version_str,
136 Err(_) => return Err(MeasurementError::InvalidData(SW_VERSION_VALUE_ERROR_MSG)),
137 }
138 .to_string();
139
140 let sw_type = match from_utf8(&value.metadata.sw_type) {
141 Ok(type_str) => type_str,
142 Err(_) => return Err(MeasurementError::InvalidData(SW_TYPE_VALUE_ERROR_MSG)),
143 }
144 .to_string();
145
146 Ok(Self {
147 metadata: MeasurementMetaData {
148 signer_id: value.metadata.signer_id.iter().cloned().collect(),
149 sw_version,
150 algorithm: value.metadata.measurement_type.try_into()?,
151 sw_type,
152 },
153 value: value.measurement_value,
154 })
155 }
156}
157
158#[cfg(test)]
159mod tests {
160 use super::*;
161 use crate::{
162 hw::{
163 BootMeasurementMetadata, HWHash, HWSWType, HWSWVersion, MAX_HW_HASH_VALUE_SIZE,
164 MAX_HW_SW_TYPE_SIZE, MAX_HW_SW_VERSION_SIZE,
165 },
166 BootMeasurement,
167 };
168 use alloc::{vec, vec::Vec};
169
170 fn boot_measurement_value(len: usize) -> HWHash {
171 let mut value: HWHash = HWHash::from([
172 0x8a, 0x66, 0x01, 0xf6, 0x70, 0x74, 0x8b, 0xe2, 0x33, 0xff, 0x5d, 0x75, 0xd7, 0xea,
173 0x89, 0xa8, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x01, 0x05, 0x01, 0xEF,
174 0x68, 0x07, 0x88, 0xCC, 0x83, 0x09, 0x22, 0xCD, 0x09, 0x61, 0xB6, 0xFF, 0xbb, 0xbb,
175 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0xbb, 0x56, 0x46, 0x58, 0x49, 0x99, 0x31, 0xcf, 0x59,
176 0x7d, 0xbc, 0x3a, 0x4e, 0x68, 0x79, 0x8a, 0x1c,
177 ]);
178 value.truncate(len);
179 value
180 }
181
182 fn boot_signer_id(len: usize) -> HWHash {
183 let mut signer_id: HWHash = HWHash::from([
184 0x01, 0x05, 0x01, 0xEF, 0x68, 0x07, 0x88, 0xCC, 0x33, 0x06, 0x54, 0xAB, 0x09, 0x01,
185 0x74, 0x77, 0x49, 0x08, 0x93, 0xA8, 0x01, 0x07, 0xEF, 0x01, 0x83, 0x09, 0x22, 0xCD,
186 0x09, 0x61, 0xB6, 0xFF, 0x01, 0x05, 0x01, 0xEF, 0x68, 0x07, 0x88, 0xCC, 0x33, 0x06,
187 0x54, 0xAB, 0x09, 0x01, 0x74, 0x77, 0x49, 0x08, 0x93, 0xA8, 0x01, 0x07, 0xEF, 0x01,
188 0x83, 0x09, 0x22, 0xCD, 0x09, 0x61, 0xB6, 0xFF,
189 ]);
190 signer_id.truncate(len);
191 signer_id
192 }
193
194 fn boot_sw_type(len: usize) -> HWSWType {
195 let mut sw_type: HWSWType =
196 HWSWType::from([0x4D, 0x45, 0x41, 0x53, 0x55, 0x52, 0x45, 0x44, 0x5F, 0x42]);
197 sw_type.truncate(len);
198 sw_type
199 }
200
201 fn boot_sw_version(len: usize) -> HWSWVersion {
202 let mut sw_version: HWSWVersion = HWSWVersion::from([
203 0x32, 0x35, 0x35, 0x2E, 0x32, 0x35, 0x35, 0x2E, 0x36, 0x35, 0x35, 0x33, 0x35, 0x0,
204 ]);
205 sw_version.truncate(len);
206 sw_version
207 }
208
209 #[test]
210 fn measurement_type_conversion_ok() {
211 let measurement_types_u16: Vec<u16> = vec![0, 1, 2];
212 let measurement_types: Vec<MeasurementType> = vec![
213 MeasurementType::Sha256,
214 MeasurementType::Sha384,
215 MeasurementType::Sha512,
216 ];
217
218 for (measurement_type_u16, measurement_type) in measurement_types_u16
219 .into_iter()
220 .zip(measurement_types.into_iter())
221 {
222 assert_eq!(
223 <u16 as TryInto<MeasurementType>>::try_into(measurement_type_u16).unwrap(),
224 measurement_type
225 );
226 }
227 }
228
229 #[test]
230 fn measurement_conversion_ok() {
231 let boot_measurement = BootMeasurement {
232 measurement_value: boot_measurement_value(MEASUREMENT_VALUE_MIN_SIZE),
233 metadata: BootMeasurementMetadata {
234 measurement_type: 0,
235 signer_id: boot_signer_id(MAX_HW_HASH_VALUE_SIZE),
236 sw_type: boot_sw_type(MAX_HW_SW_TYPE_SIZE),
237 sw_version: boot_sw_version(MAX_HW_SW_VERSION_SIZE),
238 },
239 };
240
241 let measurement: Measurement = boot_measurement.clone().try_into().unwrap();
242 assert_eq!(boot_measurement.measurement_value, measurement.value);
243
244 let boot_metadata = &boot_measurement.metadata;
245 let metadata = &measurement.metadata;
246
247 assert_eq!(boot_metadata.signer_id, metadata.signer_id);
248 assert_eq!(
249 <u16 as TryInto<MeasurementType>>::try_into(boot_metadata.measurement_type).unwrap(),
250 metadata.algorithm
251 );
252 assert_eq!(
253 &boot_metadata.sw_type[..],
254 &metadata.sw_type[..MAX_HW_SW_TYPE_SIZE].as_bytes()[..]
255 );
256 assert_eq!(boot_metadata.sw_version, metadata.sw_version.as_bytes());
257 }
258
259 #[test]
260 fn measurement_conversion_too_short_value() {
261 let boot_measurement = BootMeasurement {
262 measurement_value: boot_measurement_value(MEASUREMENT_VALUE_MIN_SIZE - 1),
264 metadata: BootMeasurementMetadata {
265 measurement_type: 0,
266 signer_id: boot_signer_id(MAX_HW_HASH_VALUE_SIZE),
267 sw_type: boot_sw_type(MAX_HW_SW_TYPE_SIZE),
268 sw_version: boot_sw_version(MAX_HW_SW_VERSION_SIZE),
269 },
270 };
271
272 assert_eq!(
273 <BootMeasurement as TryInto<Measurement>>::try_into(boot_measurement).unwrap_err(),
274 MeasurementError::InvalidData(MEASUREMENT_VALUE_SIZE_ERROR_MSG)
275 );
276 }
277
278 #[test]
279 fn measurement_conversion_too_short_signer_id() {
280 let boot_measurement = BootMeasurement {
281 measurement_value: boot_measurement_value(MAX_HW_HASH_VALUE_SIZE),
282 metadata: BootMeasurementMetadata {
283 measurement_type: 0,
284 signer_id: boot_signer_id(SIGNER_ID_MIN_SIZE - 1),
286 sw_type: boot_sw_type(MAX_HW_SW_TYPE_SIZE),
287 sw_version: boot_sw_version(MAX_HW_SW_VERSION_SIZE),
288 },
289 };
290
291 assert_eq!(
292 <BootMeasurement as TryInto<Measurement>>::try_into(boot_measurement).unwrap_err(),
293 MeasurementError::InvalidData(SIGNER_ID_SIZE_ERROR_MSG)
294 );
295 }
296
297 #[test]
298 fn measurement_conversion_bad_measurement_type() {
299 let boot_measurement = BootMeasurement {
300 measurement_value: boot_measurement_value(MAX_HW_HASH_VALUE_SIZE),
301 metadata: BootMeasurementMetadata {
302 measurement_type: 10,
304 signer_id: boot_signer_id(MAX_HW_HASH_VALUE_SIZE),
305 sw_type: boot_sw_type(MAX_HW_SW_TYPE_SIZE),
306 sw_version: boot_sw_version(MAX_HW_SW_VERSION_SIZE),
307 },
308 };
309
310 assert_eq!(
311 <BootMeasurement as TryInto<Measurement>>::try_into(boot_measurement).unwrap_err(),
312 MeasurementError::InvalidData(MEASUREMENT_TYPE_ERROR_MSG)
313 );
314 }
315}