1use super::{PolicyError, PolicySession};
7use crate::{
8 crypto::{crypto_digest, crypto_hash_size},
9 device::Device,
10 write_object,
11};
12use tpm2_protocol::data::{
13 Tpm2bDigest, Tpm2bName, Tpm2bNonce, TpmAlgId, TpmCc, TpmlDigest, TpmlPcrSelection,
14};
15
16pub fn update_policy_digest(
23 current_digest: &mut Tpm2bDigest,
24 hash_alg: TpmAlgId,
25 cc: TpmCc,
26 params: &[&[u8]],
27) -> Result<(), PolicyError> {
28 let cc_bytes = (cc as u32).to_be_bytes();
29 let mut chunks: Vec<&[u8]> = Vec::with_capacity(2 + params.len());
30 chunks.push(current_digest.as_ref());
31 chunks.push(&cc_bytes);
32 chunks.extend(params.iter());
33
34 let new_digest_bytes = crypto_digest(hash_alg, &chunks)?;
35 *current_digest = Tpm2bDigest::try_from(new_digest_bytes.as_slice())?;
36 Ok(())
37}
38
39pub struct SoftwarePolicySession<'a> {
41 digest: Tpm2bDigest,
42 hash_alg: TpmAlgId,
43 digest_size: usize,
44 device: &'a mut Device,
45}
46
47impl<'a> SoftwarePolicySession<'a> {
48 pub fn new(hash_alg: TpmAlgId, device: &'a mut Device) -> Result<Self, PolicyError> {
54 let digest_size =
55 crypto_hash_size(hash_alg).ok_or(PolicyError::InvalidAlgorithm(hash_alg))?;
56 let digest = Tpm2bDigest::try_from(vec![0; digest_size].as_slice())?;
57 Ok(Self {
58 digest,
59 hash_alg,
60 digest_size,
61 device,
62 })
63 }
64}
65
66impl PolicySession for SoftwarePolicySession<'_> {
67 fn device(&mut self) -> &mut Device {
68 self.device
69 }
70
71 fn policy_pcr(
72 &mut self,
73 pcr_digest: &Tpm2bDigest,
74 pcrs: TpmlPcrSelection,
75 ) -> Result<(), PolicyError> {
76 let pcrs_bytes = write_object(&pcrs)?;
77 update_policy_digest(
78 &mut self.digest,
79 self.hash_alg,
80 TpmCc::PolicyPcr,
81 &[&pcrs_bytes, pcr_digest.as_ref()],
82 )
83 }
84
85 fn policy_or(&mut self, p_hash_list: &TpmlDigest) -> Result<(), PolicyError> {
86 let digests_as_bytes: Vec<u8> = p_hash_list
87 .iter()
88 .flat_map(std::convert::AsRef::as_ref)
89 .copied()
90 .collect();
91
92 self.digest = Tpm2bDigest::try_from(vec![0; self.digest_size].as_slice())?;
93
94 update_policy_digest(
95 &mut self.digest,
96 self.hash_alg,
97 TpmCc::PolicyOR,
98 &[&digests_as_bytes],
99 )
100 }
101
102 fn policy_secret(
103 &mut self,
104 _auth_handle: u32,
105 auth_handle_name: &Tpm2bName,
106 _password: Option<&[u8]>,
107 _cp_hash: Option<Tpm2bDigest>,
108 ) -> Result<(), PolicyError> {
109 let command_code = TpmCc::PolicySecret;
110 let policy_ref = Tpm2bNonce::default();
111 let cc_bytes = (command_code as u32).to_be_bytes();
112
113 let intermediate_digest_bytes = crypto_digest(
114 self.hash_alg,
115 &[self.digest.as_ref(), &cc_bytes, auth_handle_name.as_ref()],
116 )?;
117
118 let final_digest_bytes = crypto_digest(
119 self.hash_alg,
120 &[&intermediate_digest_bytes, policy_ref.as_ref()],
121 )?;
122
123 self.digest = Tpm2bDigest::try_from(final_digest_bytes.as_slice())?;
124 Ok(())
125 }
126
127 fn policy_restart(&mut self) -> Result<(), PolicyError> {
128 self.digest = Tpm2bDigest::try_from(vec![0; self.digest_size].as_slice())?;
129 Ok(())
130 }
131
132 fn get_digest(&mut self) -> Result<Tpm2bDigest, PolicyError> {
133 Ok(self.digest)
134 }
135
136 fn hash_alg(&self) -> TpmAlgId {
137 self.hash_alg
138 }
139}