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 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}