eventlog_rs/
lib.rs

1use anyhow::{anyhow, Result};
2use byteorder::{LittleEndian, ReadBytesExt};
3use core::fmt;
4use enums::{EVENTLOG_TYPES, TCG_ALGORITHMS};
5use sha2::{Digest, Sha384};
6use std::collections::HashMap;
7use std::convert::TryFrom;
8
9const RTMR_LENGTH_BY_BYTES: usize = 48;
10
11mod bios_eventlog;
12mod enums;
13
14pub use bios_eventlog::BiosEventlog;
15pub mod read;
16
17#[derive(Clone)]
18pub struct Eventlog {
19    pub log: Vec<EventlogEntry>,
20}
21
22impl fmt::Display for Eventlog {
23    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
24        let mut parsed_el = String::default();
25        for event_entry in self.log.clone() {
26            parsed_el = format!(
27                "{}\nEvent Entry:\nPCR(CC Event Log MR): {}\n\tEvent Type id: {}\n\tEvent Type: {}\n\tDigest Algorithm: {}\n\tDigest: {}\n\tEvent Desc: {}\n",
28                parsed_el,
29                event_entry.target_measurement_registry,
30                format!("0x{:08X}", event_entry.event_type_id),
31                event_entry.event_type,
32                event_entry.digests[0].algorithm,
33                hex::encode(event_entry.digests[0].digest.clone()),
34                String::from_utf8(event_entry.event_desc.clone())
35                    .unwrap_or_else(|_| hex::encode(event_entry.event_desc.clone())),
36            );
37        }
38
39        write!(f, "{parsed_el}")
40    }
41}
42
43#[derive(Clone)]
44pub struct EventlogEntry {
45    pub target_measurement_registry: u32,
46    pub event_type_id: u32,
47    pub event_type: String,
48    pub digests: Vec<ElDigest>,
49    pub event_desc: Vec<u8>,
50}
51
52#[derive(Debug, Clone)]
53pub struct ElDigest {
54    pub algorithm: String,
55    pub digest: Vec<u8>,
56}
57
58impl Eventlog {
59    pub fn replay_measurement_registry(&self) -> HashMap<u32, Vec<u8>> {
60        // result dictionary for classifying event logs by rtmr index
61        // the key is a integer, which represents rtmr index
62        // the value is a list of event log entries whose rtmr index is equal to its related key
63        let mut event_logs_by_mr_index: HashMap<u32, Vec<EventlogEntry>> = HashMap::new();
64
65        let mut result: HashMap<u32, Vec<u8>> = HashMap::new();
66
67        for log_entry in self.log.iter() {
68            match event_logs_by_mr_index.get_mut(&log_entry.target_measurement_registry) {
69                Some(logs) => logs.push(log_entry.clone()),
70                None => {
71                    event_logs_by_mr_index.insert(
72                        log_entry.target_measurement_registry,
73                        vec![log_entry.clone()],
74                    );
75                }
76            }
77        }
78
79        for (mr_index, log_set) in event_logs_by_mr_index.iter() {
80            let mut mr_value = [0; RTMR_LENGTH_BY_BYTES];
81
82            for log in log_set.iter() {
83                let digest = &log.digests[0].digest;
84                let mut sha384_algo = Sha384::new();
85                sha384_algo.update(&mr_value);
86                sha384_algo.update(digest.as_slice());
87                mr_value.copy_from_slice(sha384_algo.finalize().as_slice());
88            }
89            result.insert(mr_index.clone(), mr_value.to_vec());
90        }
91
92        result
93    }
94}
95
96impl TryFrom<Vec<u8>> for Eventlog {
97    type Error = anyhow::Error;
98
99    fn try_from(data: Vec<u8>) -> Result<Self, Self::Error> {
100        let mut index = 0;
101        let mut event_log: Vec<EventlogEntry> = Vec::new();
102        let mut digest_size_map: HashMap<u16, u16> = HashMap::new();
103
104        while index < data.len() as usize {
105            let stop_flag = (&data[index..(index + 8)]).read_u64::<LittleEndian>()?;
106            let target_measurement_registry =
107                (&data[index..(index + 4)]).read_u32::<LittleEndian>()?;
108            index += 4;
109
110            let event_type_num = (&data[index..(index + 4)]).read_u32::<LittleEndian>()?;
111            index += 4;
112            let event_type = match EVENTLOG_TYPES.get(&event_type_num) {
113                Some(type_name) => type_name.to_string(),
114                None => format!("UNKNOWN_TYPE: {:x}", &event_type_num),
115            };
116
117            let event_type_id = event_type_num;
118            if event_type == "EV_NO_ACTION".to_string() {
119                index += 48;
120                let algo_number = (&data[index..(index + 4)]).read_u32::<LittleEndian>()?;
121                index += 4;
122                for _ in 0..algo_number {
123                    digest_size_map.insert(
124                        (&data[index..(index + 2)]).read_u16::<LittleEndian>()?,
125                        (&data[(index + 2)..(index + 4)]).read_u16::<LittleEndian>()?,
126                    );
127                    index += 4;
128                }
129                let vendor_size = data[index];
130                index += vendor_size as usize + 1;
131                continue;
132            }
133
134            if stop_flag == 0xFFFFFFFFFFFFFFFF || stop_flag == 0x0000000000000000 {
135                break;
136            }
137
138            let digest_count = (&data[index..(index + 4)]).read_u32::<LittleEndian>()?;
139            index += 4;
140            let mut digests: Vec<ElDigest> = Vec::new();
141            for _ in 0..digest_count {
142                let digest_algo_num = (&data[index..(index + 2)]).read_u16::<LittleEndian>()?;
143                index += 2;
144                let algorithm = match TCG_ALGORITHMS.get(&digest_algo_num) {
145                    Some(digest_algo_name) => digest_algo_name.to_string(),
146                    None => format!("UNKNOWN_ALGORITHM: {:x}", &digest_algo_num),
147                };
148                let digest_size = digest_size_map
149                    .get(&digest_algo_num)
150                    .ok_or(anyhow!(
151                        "Internal Error: get digest size failed when parse eventlog entry, digest_algo_num: {:?}", &digest_algo_num
152                    ))?
153                    .to_owned() as usize;
154                let digest = data[index..(index + digest_size)].to_vec();
155                index += digest_size;
156                digests.push(ElDigest { algorithm, digest });
157            }
158
159            let event_desc_size = (&data[index..(index + 4)]).read_u32::<LittleEndian>()? as usize;
160            index += 4;
161            let event_desc = data[index..(index + event_desc_size)].to_vec();
162            index += event_desc_size;
163
164            let eventlog_entry = EventlogEntry {
165                target_measurement_registry,
166                event_type_id,
167                event_type,
168                digests,
169                event_desc,
170            };
171
172            event_log.push(eventlog_entry)
173        }
174
175        Ok(Eventlog { log: event_log })
176    }
177}