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