tss_esapi/context/tpm_commands/hierarchy_commands.rs
1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use crate::{
4 Context, Result, ReturnCode,
5 context::handle_manager::HandleDropAction,
6 handles::{AuthHandle, KeyHandle, ObjectHandle},
7 interface_types::{
8 YesNo,
9 algorithm::HashingAlgorithm,
10 reserved_handles::{Enables, Hierarchy, HierarchyAuth},
11 },
12 structures::{
13 Auth, CreatePrimaryKeyResult, CreationData, CreationTicket, Data, Digest, PcrSelectionList,
14 Public, SensitiveCreate, SensitiveData,
15 },
16 tss2_esys::{
17 Esys_ChangeEPS, Esys_ChangePPS, Esys_Clear, Esys_ClearControl, Esys_CreatePrimary,
18 Esys_HierarchyChangeAuth, Esys_HierarchyControl, Esys_SetPrimaryPolicy,
19 },
20};
21use log::error;
22use std::convert::{TryFrom, TryInto};
23use std::ptr::null_mut;
24
25impl Context {
26 /// Create a primary key and return the handle.
27 ///
28 /// The authentication value, initial data, outside info and creation PCRs are passed as slices
29 /// which are then converted by the method into TSS native structures.
30 ///
31 /// # Errors
32 /// * if either of the slices is larger than the maximum size of the native objects, a
33 /// `WrongParamSize` wrapper error is returned
34 // TODO: Fix when compacting the arguments into a struct
35 #[allow(clippy::too_many_arguments)]
36 pub fn create_primary(
37 &mut self,
38 primary_handle: Hierarchy,
39 public: Public,
40 auth_value: Option<Auth>,
41 initial_data: Option<SensitiveData>,
42 outside_info: Option<Data>,
43 creation_pcrs: Option<PcrSelectionList>,
44 ) -> Result<CreatePrimaryKeyResult> {
45 let sensitive_create = SensitiveCreate::new(
46 auth_value.unwrap_or_default(),
47 initial_data.unwrap_or_default(),
48 );
49 let creation_pcrs = PcrSelectionList::list_from_option(creation_pcrs);
50
51 let mut out_public_ptr = null_mut();
52 let mut creation_data_ptr = null_mut();
53 let mut creation_hash_ptr = null_mut();
54 let mut creation_ticket_ptr = null_mut();
55 let mut object_handle = ObjectHandle::None.into();
56
57 ReturnCode::ensure_success(
58 unsafe {
59 Esys_CreatePrimary(
60 self.mut_context(),
61 ObjectHandle::from(primary_handle).into(),
62 self.required_session_1()?,
63 self.optional_session_2(),
64 self.optional_session_3(),
65 &sensitive_create.try_into()?,
66 &public.try_into()?,
67 &outside_info.unwrap_or_default().into(),
68 &creation_pcrs.into(),
69 &mut object_handle,
70 &mut out_public_ptr,
71 &mut creation_data_ptr,
72 &mut creation_hash_ptr,
73 &mut creation_ticket_ptr,
74 )
75 },
76 |ret| {
77 error!("Error in creating primary key: {:#010X}", ret);
78 },
79 )?;
80 let out_public_owned = Context::ffi_data_to_owned(out_public_ptr)?;
81 let creation_data_owned = Context::ffi_data_to_owned(creation_data_ptr)?;
82 let creation_hash_owned = Context::ffi_data_to_owned(creation_hash_ptr)?;
83 let creation_ticket_owned = Context::ffi_data_to_owned(creation_ticket_ptr)?;
84 let primary_key_handle = KeyHandle::from(object_handle);
85 self.handle_manager
86 .add_handle(primary_key_handle.into(), HandleDropAction::Flush)?;
87
88 Ok(CreatePrimaryKeyResult {
89 key_handle: primary_key_handle,
90 out_public: Public::try_from(out_public_owned)?,
91 creation_data: CreationData::try_from(creation_data_owned)?,
92 creation_hash: Digest::try_from(creation_hash_owned)?,
93 creation_ticket: CreationTicket::try_from(creation_ticket_owned)?,
94 })
95 }
96
97 /// Enables or disables use of a hierarchy.
98 ///
99 /// # Arguments
100 ///
101 /// * `enable` - The hierarchy or associated NV storage whose state will be changed.
102 /// * `state` - `true` to enable use of the hierarchy, or `false` to disable it.
103 ///
104 /// # Details
105 ///
106 /// *From the specification*
107 /// > This command enables and disables use of a hierarchy and its associated NV storage. The
108 /// > command allows phEnable, phEnableNV, shEnable, and ehEnable to be changed when the proper
109 /// > authorization is provided.
110 ///
111 /// # Example
112 ///
113 /// ```rust
114 /// # use tss_esapi::{Context, TctiNameConf};
115 /// # use tss_esapi::interface_types::{
116 /// # reserved_handles::Enables, session_handles::AuthSession,
117 /// # };
118 /// # let mut context = Context::new(
119 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
120 /// # ).expect("Failed to create Context");
121 /// context
122 /// .execute_with_session(Some(AuthSession::Password), |ctx| {
123 /// ctx.hierarchy_control(Enables::Endorsement, false)?;
124 /// ctx.hierarchy_control(Enables::Endorsement, true)
125 /// })
126 /// .unwrap();
127 /// ```
128 pub fn hierarchy_control(&mut self, enable: Enables, state: bool) -> Result<()> {
129 ReturnCode::ensure_success(
130 unsafe {
131 Esys_HierarchyControl(
132 self.mut_context(),
133 ObjectHandle::Platform.into(),
134 self.required_session_1()?,
135 self.optional_session_2(),
136 self.optional_session_3(),
137 ObjectHandle::from(enable).into(),
138 YesNo::from(state).into(),
139 )
140 },
141 |ret| {
142 error!("Error controlling hierarchy: {:#010X}", ret);
143 },
144 )
145 }
146
147 /// Sets the authorization policy for a hierarchy.
148 ///
149 /// # Arguments
150 ///
151 /// * `auth_handle` - The hierarchy whose authorization policy will be changed.
152 /// * `auth_policy` - The new authorization policy digest.
153 /// * `hash_algorithm` - The hash algorithm used to compute `auth_policy`. An empty policy must
154 /// be paired with [`HashingAlgorithm::Null`].
155 ///
156 /// # Details
157 ///
158 /// *From the specification*
159 /// > This command allows setting of the authorization policy for the lockout (lockoutPolicy),
160 /// > the platform hierarchy (platformPolicy), the storage hierarchy (ownerPolicy), and the
161 /// > endorsement hierarchy (endorsementPolicy).
162 ///
163 /// # Example
164 ///
165 /// ```rust
166 /// # use tss_esapi::{Context, TctiNameConf};
167 /// # use tss_esapi::{
168 /// # interface_types::{algorithm::HashingAlgorithm, reserved_handles::HierarchyAuth,
169 /// # session_handles::AuthSession},
170 /// # structures::Digest,
171 /// # };
172 /// # let mut context = Context::new(
173 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
174 /// # ).expect("Failed to create Context");
175 /// context
176 /// .execute_with_session(Some(AuthSession::Password), |ctx| {
177 /// ctx.set_primary_policy(
178 /// HierarchyAuth::Platform,
179 /// Digest::default(),
180 /// HashingAlgorithm::Null,
181 /// )
182 /// })
183 /// .unwrap();
184 /// ```
185 pub fn set_primary_policy(
186 &mut self,
187 auth_handle: HierarchyAuth,
188 auth_policy: Digest,
189 hash_algorithm: HashingAlgorithm,
190 ) -> Result<()> {
191 ReturnCode::ensure_success(
192 unsafe {
193 Esys_SetPrimaryPolicy(
194 self.mut_context(),
195 ObjectHandle::from(auth_handle).into(),
196 self.required_session_1()?,
197 self.optional_session_2(),
198 self.optional_session_3(),
199 &auth_policy.into(),
200 hash_algorithm.into(),
201 )
202 },
203 |ret| {
204 error!("Error setting primary policy: {:#010X}", ret);
205 },
206 )
207 }
208
209 /// Replaces the platform primary seed with a new random value.
210 ///
211 /// # Arguments
212 ///
213 /// This command has no command-specific arguments. The first configured session must authorize
214 /// the platform hierarchy.
215 ///
216 /// # Details
217 ///
218 /// *From the specification*
219 /// > This replaces the current platform primary seed (PPS) with a value from the RNG and sets
220 /// > platformPolicy to the default initialization value (the Empty Buffer).
221 ///
222 /// Existing objects in the platform hierarchy can no longer be loaded after this command.
223 ///
224 /// # Example
225 ///
226 /// ```rust
227 /// # use tss_esapi::{Context, TctiNameConf};
228 /// # use tss_esapi::interface_types::session_handles::AuthSession;
229 /// # let mut context = Context::new(
230 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
231 /// # ).expect("Failed to create Context");
232 /// context
233 /// .execute_with_session(Some(AuthSession::Password), |ctx| ctx.change_pps())
234 /// .unwrap();
235 /// ```
236 pub fn change_pps(&mut self) -> Result<()> {
237 ReturnCode::ensure_success(
238 unsafe {
239 Esys_ChangePPS(
240 self.mut_context(),
241 ObjectHandle::Platform.into(),
242 self.required_session_1()?,
243 self.optional_session_2(),
244 self.optional_session_3(),
245 )
246 },
247 |ret| {
248 error!("Error changing platform primary seed: {:#010X}", ret);
249 },
250 )
251 }
252
253 /// Replaces the endorsement primary seed with a new random value.
254 ///
255 /// # Arguments
256 ///
257 /// This command has no command-specific arguments. The first configured session must authorize
258 /// the platform hierarchy.
259 ///
260 /// # Details
261 ///
262 /// *From the specification*
263 /// > This replaces the current endorsement primary seed (EPS) with a value from the RNG and
264 /// > sets the Endorsement hierarchy controls to their default initialization values: ehEnable
265 /// > is SET, endorsementAuth and endorsementPolicy are both set to the Empty Buffer. It will
266 /// > flush any resident objects (transient or persistent) in the Endorsement hierarchy and not
267 /// > allow objects in the hierarchy associated with the previous EPS to be loaded.
268 ///
269 /// Existing objects in the endorsement hierarchy can no longer be loaded after this command.
270 ///
271 /// # Example
272 ///
273 /// ```rust
274 /// # use tss_esapi::{Context, TctiNameConf};
275 /// # use tss_esapi::interface_types::session_handles::AuthSession;
276 /// # let mut context = Context::new(
277 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
278 /// # ).expect("Failed to create Context");
279 /// context
280 /// .execute_with_session(Some(AuthSession::Password), |ctx| ctx.change_eps())
281 /// .unwrap();
282 /// ```
283 pub fn change_eps(&mut self) -> Result<()> {
284 ReturnCode::ensure_success(
285 unsafe {
286 Esys_ChangeEPS(
287 self.mut_context(),
288 ObjectHandle::Platform.into(),
289 self.required_session_1()?,
290 self.optional_session_2(),
291 self.optional_session_3(),
292 )
293 },
294 |ret| {
295 error!("Error changing endorsement primary seed: {:#010X}", ret);
296 },
297 )
298 }
299
300 /// Clear all TPM context associated with a specific Owner
301 pub fn clear(&mut self, auth_handle: AuthHandle) -> Result<()> {
302 ReturnCode::ensure_success(
303 unsafe {
304 Esys_Clear(
305 self.mut_context(),
306 auth_handle.into(),
307 self.required_session_1()?,
308 self.optional_session_2(),
309 self.optional_session_3(),
310 )
311 },
312 |ret| {
313 error!("Error in clearing TPM hierarchy: {:#010X}", ret);
314 },
315 )
316 }
317
318 /// Disable or enable the TPM2_CLEAR command
319 pub fn clear_control(&mut self, auth_handle: AuthHandle, disable: bool) -> Result<()> {
320 ReturnCode::ensure_success(
321 unsafe {
322 Esys_ClearControl(
323 self.mut_context(),
324 auth_handle.into(),
325 self.required_session_1()?,
326 self.optional_session_2(),
327 self.optional_session_3(),
328 YesNo::from(disable).into(),
329 )
330 },
331 |ret| {
332 error!("Error in controlling clear command: {:#010X}", ret);
333 },
334 )
335 }
336
337 /// Change authorization for a hierarchy root
338 pub fn hierarchy_change_auth(&mut self, auth_handle: AuthHandle, new_auth: Auth) -> Result<()> {
339 ReturnCode::ensure_success(
340 unsafe {
341 Esys_HierarchyChangeAuth(
342 self.mut_context(),
343 auth_handle.into(),
344 self.required_session_1()?,
345 self.optional_session_2(),
346 self.optional_session_3(),
347 &new_auth.into(),
348 )
349 },
350 |ret| {
351 error!("Error changing hierarchy auth: {:#010X}", ret);
352 },
353 )
354 }
355}