1#![no_std]
2extern crate alloc;
5
6mod attestation;
8mod hw;
10mod measured_boot;
12pub(crate) mod utils;
14
15use core::{fmt::Debug, str::from_utf8};
16
17use alloc::{string::ToString, vec::Vec};
18use ciborium::into_writer;
19use coset::CoseSign1;
20use key_derivation::generate_seed;
21use tinyvec::ArrayVec;
22
23pub use measured_boot::{
24 Measurement, MeasurementError, MeasurementMetaData, MeasurementMgr, MeasurementType, SWType,
25 SWVersion, SignerHash, MEASUREMENT_VALUE_MAX_SIZE, MEASUREMENT_VALUE_MIN_SIZE,
26 NUM_OF_MEASUREMENT_SLOTS, SIGNER_ID_MAX_SIZE, SIGNER_ID_MIN_SIZE, SW_TYPE_MAX_SIZE,
27 VERSION_MAX_SIZE,
28};
29
30pub use hw::{
31 BootMeasurement, BootMeasurementMetadata, HWAsymmetricKey, HWData, HWHash, HWSWType,
32 HWSWVersion, HWSymmetricKey,
33};
34
35pub use attestation::{
36 calculate_public_key_hash, AttestationError, AttestationMgr, ECCFamily, HWClaims, HashAlgo,
37 KeyBits, KeyMaterialData,
38};
39
40pub const MAX_HASH_VALUE_SIZE: usize = 64;
41pub type ValueHash = ArrayVec<[u8; MAX_HASH_VALUE_SIZE]>;
42
43pub mod security_lifecycle {
45 pub const UNKNOWN: u32 = 0x1000;
46 pub const PSA_ROT_PROVISIONNING: u32 = 0x2000;
47 pub const SECURED: u32 = 0x3000;
48 pub const NON_PSA_ROT_DEBUG: u32 = 0x4000;
49 pub const RECOVERABLE_PSA_ROT_DEBUG: u32 = 0x5000;
50 pub const DECOMISSIONED: u32 = 0x6000;
51}
52
53pub struct IsletHES {
54 measured_boot_mgr: MeasurementMgr,
55 attestation_mgr: AttestationMgr,
56 lcs: u32,
57 huk: Vec<u8>,
58}
59
60#[derive(Debug)]
61pub enum IsletHESError {
62 GenericError,
64 InvalidArgument,
66 NotPermitted,
68 DoesNotExist,
70 BadState,
72 NotSupported,
74}
75
76impl From<MeasurementError> for IsletHESError {
77 fn from(value: MeasurementError) -> Self {
78 match value {
79 MeasurementError::BadState => Self::BadState,
80 MeasurementError::DoesNotExist => Self::DoesNotExist,
81 MeasurementError::InvalidArgument => Self::InvalidArgument,
82 MeasurementError::InvalidData(_) => Self::InvalidArgument,
83 MeasurementError::NotPermitted => Self::NotPermitted,
84 }
85 }
86}
87
88impl From<AttestationError> for IsletHESError {
89 fn from(value: AttestationError) -> Self {
90 match value {
91 AttestationError::InvalidArgument => Self::InvalidArgument,
92 AttestationError::GenericError => Self::GenericError,
93 AttestationError::NotSupported => Self::NotSupported,
94 }
95 }
96}
97
98impl IsletHES {
99 pub fn init<H: HWData>(hw_data: H) -> Result<Self, IsletHESError>
101 where
102 <H as HWData>::Error: Debug,
103 {
104 let measured_boot_mgr = MeasurementMgr::init(
105 hw_data
106 .boot_measurements()
107 .map_err(|_| IsletHESError::InvalidArgument)?,
108 )?;
109
110 let profile_definition = match hw_data
111 .profile_definition()
112 .map_err(|_| IsletHESError::InvalidArgument)?
113 {
114 Some(p) => Some(
115 from_utf8(&p)
116 .map_err(|_| IsletHESError::InvalidArgument)?
117 .to_string(),
118 ),
119 None => None,
120 };
121
122 let verification_service_url = match hw_data
123 .verification_service_url()
124 .map_err(|_| IsletHESError::InvalidArgument)?
125 {
126 Some(p) => Some(
127 from_utf8(&p)
128 .map_err(|_| IsletHESError::InvalidArgument)?
129 .to_string(),
130 ),
131 None => None,
132 };
133
134 let security_lifecycle = hw_data
135 .security_lifecycle()
136 .map_err(|_| IsletHESError::InvalidArgument)?;
137
138 let attestation_mgr = AttestationMgr::init(
139 KeyMaterialData {
140 hash: hw_data
141 .bl_hash()
142 .map_err(|_| IsletHESError::InvalidArgument)?,
143 guk: hw_data.guk().map_err(|_| IsletHESError::InvalidArgument)?,
144 },
145 HWClaims {
146 implementation_id: hw_data
147 .implementation_id()
148 .map_err(|_| IsletHESError::InvalidArgument)?,
149 security_lifecycle,
150 profile_definition,
151 verification_service_url,
152 platform_config: hw_data
153 .platform_config()
154 .map_err(|_| IsletHESError::InvalidArgument)?,
155 },
156 );
157
158 Ok(IsletHES {
159 measured_boot_mgr,
160 attestation_mgr,
161 lcs: security_lifecycle,
162 huk: hw_data
163 .huk()
164 .map_err(|_| IsletHESError::InvalidArgument)?
165 .to_vec(),
166 })
167 }
168
169 pub fn reset<H: HWData>(&mut self, hw_data: H) -> Result<(), IsletHESError> {
171 self.measured_boot_mgr = MeasurementMgr::init(
172 hw_data
173 .boot_measurements()
174 .map_err(|_| IsletHESError::InvalidArgument)?,
175 )?;
176
177 self.attestation_mgr.reset();
178 Ok(())
179 }
180
181 pub fn read_measurement(&self, slot_id: usize) -> Result<(&Measurement, bool), IsletHESError> {
185 Ok(self.measured_boot_mgr.read_measurement(slot_id)?)
186 }
187
188 pub fn extend_measurement(
194 &mut self,
195 slot_id: usize,
196 measurement: Measurement,
197 lock: bool,
198 ) -> Result<(), IsletHESError> {
199 Ok(self
200 .measured_boot_mgr
201 .extend_measurement(slot_id, measurement, lock)?)
202 }
203
204 fn fetch_current_measurements(&self) -> Result<Vec<Measurement>, IsletHESError> {
205 let mut measurements = Vec::new();
206 for i in 0..measured_boot::NUM_OF_MEASUREMENT_SLOTS {
207 match self.measured_boot_mgr.read_measurement(i) {
208 Ok((measurement, _)) => measurements.push(measurement.clone()),
209 Err(MeasurementError::DoesNotExist) => continue,
210 Err(e) => return Err(e.into()),
211 }
212 }
213 Ok(measurements)
214 }
215
216 pub fn get_delegated_key(
222 &mut self,
223 ecc_family: ECCFamily,
224 key_bits: KeyBits,
225 hash_algo: HashAlgo,
226 ) -> Result<Vec<u8>, IsletHESError> {
227 let measurements = self.fetch_current_measurements()?;
228
229 Ok(self.attestation_mgr.get_delegated_key(
230 ecc_family,
231 key_bits,
232 hash_algo,
233 &measurements,
234 )?)
235 }
236
237 pub fn get_platform_token(&mut self, dak_pub_hash: &[u8]) -> Result<CoseSign1, IsletHESError> {
244 let measurements = self.fetch_current_measurements()?;
245
246 Ok(self
247 .attestation_mgr
248 .get_platform_token(dak_pub_hash, &measurements)?)
249 }
250
251 pub fn get_authority_vhuk(&mut self) -> Result<Vec<u8>, IsletHESError> {
256 let measurements = self.fetch_current_measurements()?;
257
258 let mut authority_info = Vec::new();
259 for Measurement { metadata, .. } in measurements {
260 let MeasurementMetaData {
261 signer_id, sw_type, ..
262 } = metadata;
263 authority_info.extend_from_slice(signer_id.as_slice());
264 authority_info.extend_from_slice(sw_type.as_bytes());
265 }
266
267 let mut context = Vec::new();
268 context.extend(&authority_info);
269 context.extend(self.lcs.to_ne_bytes());
270
271 Ok(generate_seed(&context, &self.huk, b"VHUK_A"))
272 }
273
274 pub fn get_measurement_vhuk(&mut self) -> Result<Vec<u8>, IsletHESError> {
278 let measurements = self.fetch_current_measurements()?;
279 let encoded_measurements = utils::encode_measurements(&measurements);
280
281 let mut context = Vec::new();
282 into_writer(&encoded_measurements, &mut context)
283 .map_err(|_| IsletHESError::GenericError)?;
284 context.extend(self.lcs.to_ne_bytes());
285
286 Ok(generate_seed(&context, &self.huk, b"VHUK_M"))
287 }
288}