Skip to content

Commit 58f633e

Browse files
alistair23twilfredo
authored andcommitted
libspdm: Support generating direct manifest
This supports generating a direct manifest from an indirect manifest. This is based on the original discussion at [1]. 1: https://gitlab.com/twittner/minicbor/-/merge_requests/39 Signed-off-by: Alistair Francis <[email protected]>
1 parent f820c27 commit 58f633e

File tree

5 files changed

+350
-29
lines changed

5 files changed

+350
-29
lines changed

Cargo.lock

Lines changed: 45 additions & 8 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ readme = "README.md"
1111
default = ["std"]
1212

1313
no_std = []
14-
std = ["clap", "memmap2", "once_cell", "sha2", "env_logger", "serialport", "lazy_static", "colored", "which", "asn1-rs", "x509-parser"]
14+
std = ["clap", "memmap2", "once_cell", "sha2", "env_logger", "serialport", "lazy_static", "colored", "which", "asn1-rs", "x509-parser", "minicbor", "minicbor-derive"]
1515

1616
[lib]
1717
name = "libspdm"
@@ -39,5 +39,7 @@ colored = { version = "2.1", optional = true }
3939
which = { version = "6.0", optional = true }
4040
asn1-rs = { version = "0.6", optional = true }
4141
x509-parser = { version = "0.15", optional = true }
42+
minicbor = { git = "https://gitlab.com/twittner/minicbor.git", features = ["half", "alloc", "std"], optional = true }
43+
minicbor-derive = { git = "https://gitlab.com/twittner/minicbor.git", features = ["alloc", "std"], optional = true }
4244

4345
libmctp = { git = "https://github.com/westerndigitalcorporation/libmctp.git" }

src/libspdm/manifest.rs

Lines changed: 225 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,14 @@
22
// SPDX-License-Identifier: Apache-2.0 OR MIT
33
// Copyright (C) 2024, Western Digital Corporation or its affiliates.
44

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};
513
use std::fs::File;
614
use std::io::Read;
715
use std::io::Write;
@@ -153,3 +161,220 @@ pub fn decode_cbor_manifest(buffer: &[u8], use_pretty: bool) -> Result<Vec<u8>,
153161
}
154162
}
155163
}
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

Comments
 (0)