cli/policy/
tpm.rs

1// SPDX-License-Identifier: GPL-3-0-or-later
2// Copyright (c) 2025 Opinsys Oy
3
4//! A policy session that interacts directly with a TPM device.
5
6use super::{PolicyError, PolicySession};
7use crate::device::Device;
8use crate::session;
9use tpm2_protocol::{
10    data::{Tpm2bDigest, Tpm2bName, Tpm2bNonce, TpmAlgId, TpmCc, TpmlDigest, TpmlPcrSelection},
11    message::{
12        TpmPolicyGetDigestCommand, TpmPolicyOrCommand, TpmPolicyPcrCommand, TpmPolicySecretCommand,
13    },
14    TpmHandle,
15};
16
17/// A session that sends policy commands to a real TPM device.
18pub struct TpmPolicySession<'a> {
19    device: &'a mut Device,
20    handle: TpmHandle,
21    hash_alg: TpmAlgId,
22}
23
24impl<'a> TpmPolicySession<'a> {
25    /// Creates a new TPM policy session.
26    #[must_use]
27    pub fn new(device: &'a mut Device, handle: TpmHandle, hash_alg: TpmAlgId) -> Self {
28        Self {
29            device,
30            handle,
31            hash_alg,
32        }
33    }
34}
35
36impl PolicySession for TpmPolicySession<'_> {
37    fn device(&mut self) -> &mut Device {
38        self.device
39    }
40
41    fn policy_pcr(
42        &mut self,
43        pcr_digest: &Tpm2bDigest,
44        pcrs: TpmlPcrSelection,
45    ) -> Result<(), PolicyError> {
46        let cmd = TpmPolicyPcrCommand {
47            policy_session: self.handle.0.into(),
48            pcr_digest: *pcr_digest,
49            pcrs,
50        };
51        self.device.execute(&cmd, &[])?;
52        Ok(())
53    }
54
55    fn policy_or(&mut self, p_hash_list: &TpmlDigest) -> Result<(), PolicyError> {
56        let cmd = TpmPolicyOrCommand {
57            policy_session: self.handle.0.into(),
58            p_hash_list: *p_hash_list,
59        };
60        self.device.execute(&cmd, &[])?;
61        Ok(())
62    }
63
64    fn policy_secret(
65        &mut self,
66        auth_handle: u32,
67        _auth_handle_name: &Tpm2bName,
68        password: Option<&[u8]>,
69        cp_hash: Option<Tpm2bDigest>,
70    ) -> Result<(), PolicyError> {
71        let cmd = TpmPolicySecretCommand {
72            auth_handle: auth_handle.into(),
73            policy_session: self.handle.0.into(),
74            nonce_tpm: Tpm2bNonce::default(),
75            cp_hash_a: cp_hash.unwrap_or_default(),
76            policy_ref: Tpm2bNonce::default(),
77            expiration: 0,
78        };
79
80        let password_auth = session::build_password_session(password.unwrap_or_default())?;
81        let sessions = vec![password_auth];
82
83        self.device.execute(&cmd, &sessions)?;
84        Ok(())
85    }
86
87    fn get_digest(&mut self) -> Result<Tpm2bDigest, PolicyError> {
88        let cmd = TpmPolicyGetDigestCommand {
89            policy_session: self.handle.0.into(),
90        };
91        let (resp, _) = self.device.execute(&cmd, &[])?;
92        let digest_resp = resp
93            .PolicyGetDigest()
94            .map_err(|_| crate::device::DeviceError::ResponseMismatch(TpmCc::PolicyGetDigest))?;
95        Ok(digest_resp.policy_digest)
96    }
97
98    fn hash_alg(&self) -> TpmAlgId {
99        self.hash_alg
100    }
101}