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