cli/command/
pcr_event.rs

1// SPDX-License-Identifier: GPL-3-0-or-later
2// Copyright (c) 2025 Opinsys Oy
3
4use crate::{
5    cli::SubCommand, command::CommandError, device::with_device, io::read_file_input, job::Job,
6    key::Tpm2shAlgId, parse_hex_u32, pcr::pcr_get_bank_list,
7};
8use clap::Args;
9use tpm2_protocol::{
10    data::{Tpm2bEvent, TpmCc, TpmuHa},
11    message::TpmPcrEventCommand,
12    TpmHandle,
13};
14
15fn parse_pcr_index(handle_str: &str) -> Result<TpmHandle, String> {
16    parse_hex_u32(handle_str)
17        .map(TpmHandle)
18        .map_err(|_| "malformed value".to_string())
19}
20
21/// Extends a PCR with an event.
22#[derive(Args, Debug)]
23#[command(name = "pcr-event")]
24pub struct PcrEvent {
25    /// PCR index
26    #[arg(value_name = "pcr-index", value_parser = parse_pcr_index)]
27    pub pcr_index: TpmHandle,
28}
29
30impl SubCommand for PcrEvent {
31    fn run(&self, job: &mut Job) -> Result<(), CommandError> {
32        with_device(job.device.clone(), |device| {
33            let banks = pcr_get_bank_list(device)?;
34            let handles = [self.pcr_index.0];
35
36            let auths = vec![job.auth_list.first().cloned().unwrap_or_default()];
37
38            let data_bytes = read_file_input(None)?;
39
40            let event_data = Tpm2bEvent::try_from(data_bytes.as_slice())?;
41            let command = TpmPcrEventCommand {
42                pcr_handle: handles[0].into(),
43                event_data,
44            };
45
46            let (resp, _) = job.execute(device, &command, &handles, &auths)?;
47
48            let pcr_resp = resp
49                .PcrEvent()
50                .map_err(|_| CommandError::ResponseMismatch(TpmCc::PcrEvent))?;
51
52            let clauses: Vec<String> = banks
53                .iter()
54                .zip(pcr_resp.digests.iter())
55                .filter_map(|(bank, digest_struct)| {
56                    if let TpmuHa::Digest(bytes) = digest_struct.digest {
57                        Some(format!(
58                            "{}:{}:{}",
59                            Tpm2shAlgId(bank.alg),
60                            self.pcr_index.0,
61                            hex::encode(bytes)
62                        ))
63                    } else {
64                        None
65                    }
66                })
67                .collect();
68
69            writeln!(job.writer, "{}", clauses.join("+"))?;
70
71            Ok(())
72        })
73    }
74}