|
2 | 2 | // SPDX-License-Identifier: Apache-2.0 OR MIT |
3 | 3 | // Copyright (C) 2024, Western Digital Corporation or its affiliates. |
4 | 4 |
|
| 5 | +use crate::libspdm_rs; |
| 6 | +use crate::libspdm_rs::LIBSPDM_MAX_MEASUREMENT_RECORD_SIZE; |
| 7 | +use crate::spdm::{get_base_hash_algo, get_measurement}; |
| 8 | +use core::ffi::c_void; |
| 9 | +use core::slice::from_raw_parts; |
| 10 | +use minicbor::bytes::ByteSlice; |
| 11 | +use minicbor::data::Tagged; |
| 12 | +use minicbor_derive::{CborLen, Decode, Encode}; |
5 | 13 | use std::fs::File; |
6 | 14 | use std::io::Read; |
7 | 15 | use std::io::Write; |
@@ -153,3 +161,220 @@ pub fn decode_cbor_manifest(buffer: &[u8], use_pretty: bool) -> Result<Vec<u8>, |
153 | 161 | } |
154 | 162 | } |
155 | 163 | } |
| 164 | + |
| 165 | +pub type SpdmToc<'a> = Tagged<570, TaggedEvidence<'a>>; |
| 166 | + |
| 167 | +#[derive(Debug, Encode, Decode, CborLen)] |
| 168 | +#[cbor(map)] |
| 169 | +pub struct TaggedEvidence<'a> { |
| 170 | + #[b(0)] |
| 171 | + tagged_evidence: [Tagged<571, CeEvTriples<'a>>; 1], |
| 172 | + #[b(1)] |
| 173 | + rim_locators: Vec<CorimLocatorMap<'a>>, |
| 174 | +} |
| 175 | + |
| 176 | +#[derive(Debug, Encode, Decode, CborLen)] |
| 177 | +#[cbor(map)] |
| 178 | +pub struct CeEvTriples<'a> { |
| 179 | + #[b(0)] |
| 180 | + ce_ev_triples: CeMembershipTriples<'a>, |
| 181 | +} |
| 182 | + |
| 183 | +#[derive(Debug, Encode, Decode, CborLen)] |
| 184 | +#[cbor(map)] |
| 185 | +pub struct CeMembershipTriples<'a> { |
| 186 | + #[b(0)] |
| 187 | + ce_membership_triples: (EnvironmentMap<'a>, Vec<MeasurementMap<'a>>), |
| 188 | +} |
| 189 | + |
| 190 | +#[derive(Debug, Encode, Decode, CborLen)] |
| 191 | +#[cbor(map)] |
| 192 | +pub struct EnvironmentMap<'a> { |
| 193 | + #[b(0)] |
| 194 | + class: Class<'a>, |
| 195 | +} |
| 196 | + |
| 197 | +#[derive(Debug, Encode, Decode, CborLen)] |
| 198 | +#[cbor(map)] |
| 199 | +pub struct Class<'a> { |
| 200 | + #[b(0)] |
| 201 | + id: Tagged<111, &'a ByteSlice>, |
| 202 | + #[b(1)] |
| 203 | + vendor: &'a str, |
| 204 | +} |
| 205 | + |
| 206 | +#[derive(Debug, Encode, Decode, CborLen)] |
| 207 | +#[cbor(map)] |
| 208 | +pub struct MeasurementMap<'a> { |
| 209 | + // mkey |
| 210 | + #[n(1)] |
| 211 | + mval: MeasurementValuesMap<'a>, |
| 212 | + #[b(2)] |
| 213 | + authorised_by: [Tagged<554, &'a str>; 1], |
| 214 | +} |
| 215 | + |
| 216 | +#[derive(Debug, Encode, Decode, CborLen)] |
| 217 | +#[cbor(map)] |
| 218 | +/// https://github.com/ietf-rats-wg/draft-ietf-rats-corim/blob/main/cddl/measurement-values-map.cddl |
| 219 | +pub struct MeasurementValuesMap<'a> { |
| 220 | + #[b(0)] |
| 221 | + version: Option<&'a str>, |
| 222 | + #[b(1)] |
| 223 | + svn: Option<Tagged<552, i64>>, |
| 224 | + #[b(2)] |
| 225 | + digest: Option<(i64, &'a ByteSlice)>, |
| 226 | + // ? &(flags: 3) => flags-map |
| 227 | + #[b(4)] |
| 228 | + raw_value: Option<Tagged<560, &'a ByteSlice>>, |
| 229 | + // ? ( |
| 230 | + // &(raw-value: 4) => $raw-value-type-choice, |
| 231 | + // ? &(raw-value-mask: 5) => raw-value-mask-type |
| 232 | + // ) |
| 233 | + // ? &(mac-addr: 6) => mac-addr-type-choice |
| 234 | + // ? &(ip-addr: 7) => ip-addr-type-choice |
| 235 | + // ? &(serial-number: 8) => text |
| 236 | + // ? &(ueid: 9) => ueid-type |
| 237 | + // ? &(uuid: 10) => uuid-type |
| 238 | + #[b(11)] |
| 239 | + name: Option<&'a str>, |
| 240 | + #[b(12)] |
| 241 | + spdm_indirect: Option<Index>, // ? &(cryptokeys: 13) => [ + $crypto-key-type-choice ] |
| 242 | + // ? &(integrity-registers: 14) => integrity-registers |
| 243 | +} |
| 244 | + |
| 245 | +#[derive(Debug, Encode, Decode, CborLen)] |
| 246 | +#[cbor(map)] |
| 247 | +pub struct CorimLocatorMap<'a> { |
| 248 | + #[b(0)] |
| 249 | + link: Tagged<32, &'a str>, |
| 250 | +} |
| 251 | + |
| 252 | +#[derive(Debug, Encode, Decode, Clone, Copy, CborLen)] |
| 253 | +#[cbor(map)] |
| 254 | +pub struct Index { |
| 255 | + #[n(0)] |
| 256 | + index: [u8; 1], |
| 257 | +} |
| 258 | + |
| 259 | +const DEBUG_INFORMATION: u8 = |
| 260 | + (crate::libspdm_rs::SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_DEVICE_MODE |
| 261 | + | crate::libspdm_rs::SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_RAW_BIT_STREAM) as u8; |
| 262 | +const VERSION: u8 = (crate::libspdm_rs::SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_VERSION |
| 263 | + | crate::libspdm_rs::SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_RAW_BIT_STREAM) |
| 264 | + as u8; |
| 265 | +const SVN: u8 = (crate::libspdm_rs::SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_SECURE_VERSION_NUMBER |
| 266 | + | crate::libspdm_rs::SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_RAW_BIT_STREAM) |
| 267 | + as u8; |
| 268 | +const RAW_BIT_STREAM: u8 = |
| 269 | + crate::libspdm_rs::SPDM_MEASUREMENT_BLOCK_MEASUREMENT_TYPE_RAW_BIT_STREAM as u8; |
| 270 | +const DIGESTS: u8 = RAW_BIT_STREAM - 1; |
| 271 | + |
| 272 | +/// This function converts indirect tagged-concise-evidence bindings to |
| 273 | +/// direct measurements. |
| 274 | +/// |
| 275 | +/// The TCG Concise Evidence Binding for SPDM spec states that |
| 276 | +/// "If a lead Attester supports tagged-concise-evidence and an spdm-indirect |
| 277 | +/// measurement is used, the DMTFMeasurementValueType to CoMID measurement |
| 278 | +/// mapping SHOULD be applied according to Table 7." |
| 279 | +/// |
| 280 | +/// This function will parse a Concise Evidence Binding manifest and replace |
| 281 | +/// the `spdm-indirect` entries with measurements. |
| 282 | +pub fn generate_direct_manifest( |
| 283 | + context: *mut c_void, |
| 284 | + slot_id: u8, |
| 285 | + measurement_manifest: &[u8], |
| 286 | +) -> Result<SpdmToc, minicbor::decode::Error> { |
| 287 | + let mut spdm_toc: SpdmToc<'_> = minicbor::decode(&measurement_manifest)?; |
| 288 | + let ce_ev_triples = &mut spdm_toc |
| 289 | + .value_mut() |
| 290 | + .tagged_evidence |
| 291 | + .first_mut() |
| 292 | + .unwrap() |
| 293 | + .value_mut() |
| 294 | + .ce_ev_triples; |
| 295 | + let measurement_maps = &mut ce_ev_triples.ce_membership_triples.1; |
| 296 | + |
| 297 | + for measurement_map in measurement_maps { |
| 298 | + if let Some(measurement_index) = measurement_map.mval.spdm_indirect { |
| 299 | + let mut measurement_record = [0; LIBSPDM_MAX_MEASUREMENT_RECORD_SIZE as usize]; |
| 300 | + let (dmtf_spec_measure_type, _measurement_record_length) = unsafe { |
| 301 | + get_measurement( |
| 302 | + context, |
| 303 | + slot_id, |
| 304 | + measurement_index.index[0] as u32, |
| 305 | + &mut measurement_record, |
| 306 | + ) |
| 307 | + .unwrap() |
| 308 | + }; |
| 309 | + |
| 310 | + let measurement_offset = |
| 311 | + core::mem::size_of::<libspdm_rs::spdm_measurement_block_dmtf_t>(); |
| 312 | + let measurement_block = |
| 313 | + &measurement_record as *const _ as *const libspdm_rs::spdm_measurement_block_dmtf_t; |
| 314 | + let measurement_size = unsafe { |
| 315 | + (*measurement_block) |
| 316 | + .measurement_block_dmtf_header |
| 317 | + .dmtf_spec_measurement_value_size |
| 318 | + }; |
| 319 | + |
| 320 | + match dmtf_spec_measure_type { |
| 321 | + 0..=DIGESTS => { |
| 322 | + // digests |
| 323 | + let msg_buf = unsafe { |
| 324 | + from_raw_parts( |
| 325 | + measurement_block.add(1) as *const u8, |
| 326 | + measurement_size.min(LIBSPDM_MAX_MEASUREMENT_RECORD_SIZE as u16) |
| 327 | + as usize, |
| 328 | + ) |
| 329 | + }; |
| 330 | + let hash_algo = unsafe { get_base_hash_algo(context, slot_id).unwrap().0 }; |
| 331 | + measurement_map.mval.digest = Some((hash_algo as i64, msg_buf.into())); |
| 332 | + } |
| 333 | + DEBUG_INFORMATION => { |
| 334 | + let msg_buf = unsafe { |
| 335 | + from_raw_parts( |
| 336 | + measurement_block.add(1) as *const u8, |
| 337 | + measurement_size.min(LIBSPDM_MAX_MEASUREMENT_RECORD_SIZE as u16) |
| 338 | + as usize, |
| 339 | + ) |
| 340 | + }; |
| 341 | + measurement_map.mval.raw_value = Some(Tagged::new(msg_buf.into())); |
| 342 | + } |
| 343 | + VERSION => { |
| 344 | + let msg_buf = unsafe { |
| 345 | + from_raw_parts( |
| 346 | + measurement_block.add(1) as *const u8, |
| 347 | + measurement_size.min(LIBSPDM_MAX_MEASUREMENT_RECORD_SIZE as u16) |
| 348 | + as usize, |
| 349 | + ) |
| 350 | + }; |
| 351 | + measurement_map.mval.version = Some(std::str::from_utf8(msg_buf).unwrap()); |
| 352 | + } |
| 353 | + SVN => { |
| 354 | + let value = measurement_record[measurement_offset + 0] as i64 |
| 355 | + | (measurement_record[measurement_offset + 1] as i64) << 8 |
| 356 | + | (measurement_record[measurement_offset + 2] as i64) << 16 |
| 357 | + | (measurement_record[measurement_offset + 3] as i64) << 24; |
| 358 | + |
| 359 | + measurement_map.mval.svn = Some(Tagged::<552, i64>::new(value)); |
| 360 | + } |
| 361 | + RAW_BIT_STREAM | 0xFF => { |
| 362 | + // raw-value |
| 363 | + let msg_buf = unsafe { |
| 364 | + from_raw_parts( |
| 365 | + measurement_block.add(1) as *const u8, |
| 366 | + measurement_size.min(LIBSPDM_MAX_MEASUREMENT_RECORD_SIZE as u16) |
| 367 | + as usize, |
| 368 | + ) |
| 369 | + }; |
| 370 | + measurement_map.mval.raw_value = Some(Tagged::new(msg_buf.into())); |
| 371 | + } |
| 372 | + _ => {} |
| 373 | + } |
| 374 | + |
| 375 | + measurement_map.mval.spdm_indirect = None; |
| 376 | + } |
| 377 | + } |
| 378 | + |
| 379 | + Ok(spdm_toc) |
| 380 | +} |
0 commit comments