Coverage Report

Created: 2026-10-28 06:24

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/MigTD/deps/td-shim/cc-measurement/src/log.rs
Line
Count
Source
1
// Copyright (c) 2022 Intel Corporation
2
//
3
// SPDX-License-Identifier: BSD-2-Clause-Patent
4
5
use super::*;
6
use alloc::boxed::Box;
7
use core::mem::size_of;
8
9
type Result<T> = core::result::Result<T, CcEventLogError>;
10
11
#[derive(Debug)]
12
pub enum CcEventLogError {
13
    InvalidParameter,
14
    OutOfResource,
15
    InvalidMrIndex(u32),
16
    ExtendMr,
17
}
18
19
#[allow(unused)]
20
pub struct CcEventLogWriter<'a> {
21
    area: &'a mut [u8],
22
    offset: usize,
23
    last: usize,
24
    extender: Box<dyn Fn(&[u8; SHA384_DIGEST_SIZE], u32) -> Result<()>>,
25
}
26
27
impl CcEventLogWriter<'_> {
28
0
    pub fn new(
29
0
        area: &mut [u8],
30
0
        extender: Box<dyn Fn(&[u8; SHA384_DIGEST_SIZE], u32) -> Result<()>>,
31
0
    ) -> Result<CcEventLogWriter> {
32
0
        let mut cc_event_log = CcEventLogWriter {
33
0
            area,
34
0
            offset: 0,
35
0
            last: 0,
36
0
            extender,
37
0
        };
38
39
        // Create the TCG_EfiSpecIDEvent as the first event
40
0
        let first = TcgEfiSpecIdevent::default();
41
0
        cc_event_log.log_pcr_event(0, EV_NO_ACTION, first.as_bytes())?;
42
43
0
        Ok(cc_event_log)
44
0
    }
45
46
0
    pub fn create_event_log(
47
0
        &mut self,
48
0
        mr_index: u32,
49
0
        event_type: u32,
50
0
        event_data: &[&[u8]],
51
0
        hash_data: &[u8],
52
0
    ) -> Result<()> {
53
0
        let sha384 = self.calculate_digest_and_extend(hash_data, mr_index)?;
54
55
0
        self.log_cc_event(mr_index, event_type, event_data, &sha384)
56
0
    }
57
58
0
    pub fn create_seperator(&mut self) -> Result<()> {
59
0
        let separator = u32::to_le_bytes(0);
60
61
        // Measure 0x0000_0000 into RTMR[0] and RTMR[1]
62
0
        let _ = self.calculate_digest_and_extend(&separator, 1)?;
63
0
        let sha384 = self.calculate_digest_and_extend(&separator, 2)?;
64
65
0
        self.log_cc_event(1, EV_SEPARATOR, &[&separator], &sha384)?;
66
0
        self.log_cc_event(2, EV_SEPARATOR, &[&separator], &sha384)
67
0
    }
68
69
0
    pub fn as_slice(&self) -> &[u8] {
70
0
        &self.area[..self.offset]
71
0
    }
72
73
0
    fn log_pcr_event(
74
0
        &mut self,
75
0
        mr_index: u32,
76
0
        event_type: u32,
77
0
        event_data: &[u8],
78
0
    ) -> Result<usize> {
79
0
        let event_size = size_of::<TcgPcrEventHeader>()
80
0
            .checked_add(event_data.len())
81
0
            .ok_or(CcEventLogError::InvalidParameter)?;
82
83
0
        if self
84
0
            .offset
85
0
            .checked_add(event_size)
86
0
            .ok_or(CcEventLogError::InvalidParameter)?
87
0
            > self.area.len()
88
        {
89
0
            return Err(CcEventLogError::OutOfResource);
90
0
        }
91
92
0
        let pcr_header = TcgPcrEventHeader {
93
0
            mr_index,
94
0
            event_type,
95
0
            digest: [0u8; 20],
96
0
            event_size: event_data.len() as u32,
97
0
        };
98
99
0
        let data_offset = self.offset + size_of::<TcgPcrEventHeader>();
100
0
        self.area[self.offset..data_offset].copy_from_slice(pcr_header.as_bytes());
101
0
        self.write_data(event_data, data_offset);
102
0
        self.update_offset(size_of::<TcgPcrEventHeader>() + event_data.len());
103
104
0
        Ok(self.offset)
105
0
    }
106
107
0
    fn log_cc_event(
108
0
        &mut self,
109
0
        mr_index: u32,
110
0
        event_type: u32,
111
0
        event_data: &[&[u8]],
112
0
        sha384: &[u8; 48],
113
0
    ) -> Result<()> {
114
0
        let event_data_size: usize = event_data.iter().map(|&data| data.len()).sum();
115
0
        let event_size = size_of::<CcEventHeader>()
116
0
            .checked_add(event_data_size)
117
0
            .ok_or(CcEventLogError::InvalidParameter)?;
118
119
0
        if self
120
0
            .offset
121
0
            .checked_add(event_size)
122
0
            .ok_or(CcEventLogError::InvalidParameter)?
123
0
            > self.area.len()
124
        {
125
0
            return Err(CcEventLogError::OutOfResource);
126
0
        }
127
128
        // Write the event header into event log memory and update the 'size' and 'last'
129
0
        let event_offset = self
130
0
            .log_cc_event_header(mr_index, event_type, sha384, event_data_size as u32)
131
0
            .ok_or(CcEventLogError::OutOfResource)?;
132
133
0
        let mut data_offset = size_of::<CcEventHeader>();
134
        // Fill the event data into event log
135
0
        for &data in event_data {
136
0
            self.write_data(
137
0
                data,
138
0
                event_offset
139
0
                    .checked_add(data_offset)
140
0
                    .ok_or(CcEventLogError::OutOfResource)?,
141
            );
142
0
            data_offset += data.len()
143
        }
144
145
0
        self.update_offset(event_size);
146
147
0
        Ok(())
148
0
    }
149
150
0
    fn log_cc_event_header(
151
0
        &mut self,
152
0
        mr_index: u32,
153
0
        event_type: u32,
154
0
        digest: &[u8; SHA384_DIGEST_SIZE],
155
0
        event_size: u32,
156
0
    ) -> Option<usize> {
157
0
        let event_header = CcEventHeader {
158
0
            mr_index,
159
0
            event_type,
160
0
            digest: TpmlDigestValues {
161
0
                count: 1,
162
0
                digests: [TpmtHa {
163
0
                    hash_alg: TPML_ALG_SHA384,
164
0
                    digest: TpmuHa { sha384: *digest },
165
0
                }],
166
0
            },
167
0
            event_size,
168
0
        };
169
170
0
        self.area[self.offset..self.offset + size_of::<CcEventHeader>()]
171
0
            .copy_from_slice(event_header.as_bytes());
172
173
0
        Some(self.offset)
174
0
    }
175
176
0
    fn write_data(&mut self, data: &[u8], offset: usize) {
177
0
        self.area[offset..offset + data.len()].copy_from_slice(data);
178
0
    }
179
180
0
    fn update_offset(&mut self, new_log_size: usize) {
181
0
        self.last = self.offset;
182
0
        self.offset += new_log_size;
183
0
    }
184
185
0
    fn calculate_digest_and_extend(
186
0
        &self,
187
0
        hash_data: &[u8],
188
0
        mr_index: u32,
189
0
    ) -> Result<[u8; SHA384_DIGEST_SIZE]> {
190
0
        let mut digest_sha384 = [0u8; SHA384_DIGEST_SIZE];
191
192
0
        Self::hash_sha384(hash_data, &mut digest_sha384);
193
194
        // Extend the digest to the RTMR
195
0
        (self.extender)(&digest_sha384, mr_index)?;
196
197
0
        Ok(digest_sha384)
198
0
    }
199
200
    #[cfg(feature = "ring")]
201
    fn hash_sha384(hash_data: &[u8], digest_sha384: &mut [u8; SHA384_DIGEST_SIZE]) {
202
        let digest = ring::digest::digest(&ring::digest::SHA384, hash_data);
203
        let digest = digest.as_ref();
204
        assert_eq!(digest.len(), SHA384_DIGEST_SIZE);
205
206
        digest_sha384.clone_from_slice(digest);
207
    }
208
209
    #[cfg(all(not(feature = "ring"), feature = "sha2"))]
210
0
    fn hash_sha384(hash_data: &[u8], digest_sha384: &mut [u8; SHA384_DIGEST_SIZE]) {
211
        use sha2::{Digest, Sha384};
212
213
0
        let mut digest = Sha384::new();
214
0
        digest.update(hash_data);
215
0
        let digest = digest.finalize();
216
0
        assert_eq!(digest.as_slice().len(), SHA384_DIGEST_SIZE);
217
218
0
        digest_sha384.clone_from_slice(digest.as_slice());
219
0
    }
220
}
221
222
#[derive(Clone, Copy)]
223
pub struct CcEvents<'a> {
224
    pub bytes: &'a [u8],
225
}
226
227
type EventData<'a> = &'a [u8];
228
229
impl<'a> Iterator for CcEvents<'a> {
230
    type Item = (CcEventHeader, EventData<'a>);
231
0
    fn next(&mut self) -> Option<Self::Item> {
232
0
        if self.bytes.len() < size_of::<CcEventHeader>() {
233
0
            return None;
234
0
        }
235
236
0
        let event_header =
237
0
            CcEventHeader::read_from_bytes(&self.bytes[..size_of::<CcEventHeader>()]).ok()?;
238
0
        if event_header.event_size == 0 {
239
0
            return None;
240
0
        }
241
242
0
        let end_of_event = size_of::<CcEventHeader>() + event_header.event_size as usize;
243
0
        if end_of_event < self.bytes.len() {
244
0
            let event_data = &self.bytes[size_of::<CcEventHeader>()..end_of_event];
245
0
            self.bytes = &self.bytes[end_of_event..];
246
0
            Some((event_header, event_data))
247
        } else {
248
0
            None
249
        }
250
0
    }
251
}
252
253
pub struct CcEventLogReader<'a> {
254
    pub pcr_event_header: TcgPcrEventHeader,
255
    pub specific_id_event: TcgEfiSpecIdevent,
256
    pub cc_events: CcEvents<'a>,
257
}
258
259
impl CcEventLogReader<'_> {
260
0
    pub fn new(bytes: &[u8]) -> Option<CcEventLogReader> {
261
0
        let specific_id_event_size =
262
0
            size_of::<TcgPcrEventHeader>() + size_of::<TcgEfiSpecIdevent>();
263
0
        if bytes.len() < specific_id_event_size {
264
0
            return None;
265
0
        }
266
267
        // TCG_EfiSpecIDEvent should be the first event
268
0
        let pcr_event_header =
269
0
            TcgPcrEventHeader::read_from_bytes(&bytes[..size_of::<TcgPcrEventHeader>()]).ok()?;
270
0
        let specific_id_event = TcgEfiSpecIdevent::read_from_bytes(
271
0
            &bytes[size_of::<TcgPcrEventHeader>()..specific_id_event_size],
272
        )
273
0
        .ok()?;
274
0
        let cc_event_log = CcEventLogReader {
275
0
            cc_events: CcEvents {
276
0
                bytes: &bytes[specific_id_event_size..],
277
0
            },
278
0
            pcr_event_header,
279
0
            specific_id_event,
280
0
        };
281
282
0
        Some(cc_event_log)
283
0
    }
284
285
0
    pub fn query(&self, key: &[u8]) -> Option<CcEventHeader> {
286
0
        for (header, data) in self.cc_events {
287
0
            if data.len() < key.len() {
288
0
                return None;
289
0
            }
290
0
            if &data[..key.len()] == key {
291
0
                return Some(header);
292
0
            }
293
        }
294
0
        None
295
0
    }
296
}
297
298
#[cfg(test)]
299
mod tests {
300
    use core::mem::size_of;
301
302
    use alloc::{boxed::Box, vec};
303
304
    use crate::{
305
        log::CcEventLogReader, CcEventHeader, TcgEfiSpecIdevent, TcgPcrEventHeader, EV_SEPARATOR,
306
        SHA384_DIGEST_SIZE,
307
    };
308
309
    use super::{CcEventLogWriter, Result};
310
311
    fn extender(_digest: &[u8; SHA384_DIGEST_SIZE], _mr_index: u32) -> Result<()> {
312
        // Do nothing
313
        Ok(())
314
    }
315
316
    #[test]
317
    fn test_cc_eventlog_writter_new() {
318
        let mut event_log =
319
            vec![0u8; size_of::<TcgPcrEventHeader>() + size_of::<TcgEfiSpecIdevent>()];
320
        let _ = CcEventLogWriter::new(&mut event_log, Box::new(extender)).unwrap();
321
    }
322
323
    #[test]
324
    #[should_panic]
325
    fn test_cc_eventlog_writter_new_with_small_buf() {
326
        let mut event_log =
327
            vec![0u8; size_of::<TcgPcrEventHeader>() + size_of::<TcgEfiSpecIdevent>() - 1];
328
        let _ = CcEventLogWriter::new(&mut event_log, Box::new(extender)).unwrap();
329
    }
330
331
    #[test]
332
    fn test_cc_eventlog_writter() {
333
        let mut event_log = vec![0u8; 0x1000];
334
335
        let mut writter = CcEventLogWriter::new(&mut event_log, Box::new(extender)).unwrap();
336
        let first_event_size = size_of::<TcgPcrEventHeader>() + size_of::<TcgEfiSpecIdevent>();
337
        assert_eq!(writter.as_slice().len(), first_event_size);
338
339
        writter
340
            .create_event_log(2, 3, &[b"event1:", b"012"], &[0, 1, 2])
341
            .unwrap();
342
        let second_event_size = size_of::<CcEventHeader>() + 10;
343
        assert_eq!(
344
            writter.as_slice().len(),
345
            first_event_size + second_event_size
346
        );
347
348
        writter.create_seperator().unwrap();
349
        let seperator_size = (size_of::<CcEventHeader>() + size_of::<u32>()) * 2;
350
        assert_eq!(
351
            writter.as_slice().len(),
352
            first_event_size + second_event_size + seperator_size
353
        );
354
355
        assert_eq!(
356
            &event_log[first_event_size..first_event_size + second_event_size],
357
            &[
358
                0x2, 0x0, 0x0, 0x0, 0x3, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0xc, 0x0, 0x4f, 0x89,
359
                0x58, 0x54, 0xc1, 0xa4, 0xfc, 0x5a, 0xa2, 0xe0, 0x45, 0x6e, 0xaf, 0x8d, 0xe, 0xca,
360
                0xa7, 0xc, 0x19, 0x6b, 0xd9, 0x1, 0x15, 0x38, 0x61, 0xd7, 0x6b, 0x8f, 0xa3, 0xcd,
361
                0x95, 0xce, 0xea, 0x29, 0xea, 0xb6, 0xa2, 0x79, 0xf8, 0xb0, 0x84, 0x37, 0x70, 0x3c,
362
                0xe0, 0xb4, 0xb9, 0x1a, 0xa, 0x0, 0x0, 0x0, 0x65, 0x76, 0x65, 0x6e, 0x74, 0x31,
363
                0x3a, 0x30, 0x31, 0x32
364
            ]
365
        );
366
    }
367
368
    #[test]
369
    fn test_eventlog_reader_new() {
370
        let mut event_log =
371
            vec![0u8; size_of::<TcgPcrEventHeader>() + size_of::<TcgEfiSpecIdevent>()];
372
        let reader = CcEventLogReader::new(&mut event_log).unwrap();
373
        assert_eq!(reader.cc_events.bytes.len(), 0)
374
    }
375
376
    #[test]
377
    #[should_panic]
378
    fn test_eventlog_reader_new_with_small_buf() {
379
        let mut event_log =
380
            vec![0u8; size_of::<TcgPcrEventHeader>() + size_of::<TcgEfiSpecIdevent>() - 1];
381
        let _ = CcEventLogReader::new(&mut event_log).unwrap();
382
    }
383
384
    #[test]
385
    fn test_cc_events_iterator() {
386
        let mut event_log = vec![0u8; 0x1000];
387
388
        let mut writter = CcEventLogWriter::new(&mut event_log, Box::new(extender)).unwrap();
389
390
        writter
391
            .create_event_log(2, 3, &[b"event1:", b"012"], &[0, 1, 2])
392
            .unwrap();
393
394
        writter.create_seperator().unwrap();
395
396
        let reader = CcEventLogReader::new(&mut event_log).unwrap();
397
398
        for (idx, (event_header, event_data)) in reader.cc_events.enumerate() {
399
            let event_type = event_header.event_type;
400
            if idx == 0 {
401
                assert_eq!(event_type, 3);
402
                assert_eq!(event_data, b"event1:012");
403
            } else if idx == 1 {
404
                assert_eq!(event_type, EV_SEPARATOR);
405
                assert_eq!(event_data, &[0u8; 4]);
406
            }
407
        }
408
    }
409
410
    #[test]
411
    fn test_cc_event_log_reader_query() {
412
        let mut event_log = vec![0u8; 0x1000];
413
414
        let mut writter = CcEventLogWriter::new(&mut event_log, Box::new(extender)).unwrap();
415
416
        writter
417
            .create_event_log(2, 3, &[b"event1:", b"012"], &[0, 1, 2])
418
            .unwrap();
419
420
        writter.create_seperator().unwrap();
421
422
        let reader = CcEventLogReader::new(&mut event_log).unwrap();
423
424
        assert!(reader.query(b"event1:012").is_some());
425
    }
426
}