tss_esapi/context/tpm_commands/non_volatile_storage.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, NvIndexHandle, ObjectHandle},
7 interface_types::reserved_handles::{NvAuth, Provision},
8 structures::{
9 Attest, AttestBuffer, Auth, Data, MaxNvBuffer, Name, NvPublic, Signature, SignatureScheme,
10 },
11 tss2_esys::{
12 Esys_NV_Certify, Esys_NV_ChangeAuth, Esys_NV_DefineSpace, Esys_NV_Extend,
13 Esys_NV_GlobalWriteLock, Esys_NV_Increment, Esys_NV_Read, Esys_NV_ReadLock,
14 Esys_NV_ReadPublic, Esys_NV_SetBits, Esys_NV_UndefineSpace, Esys_NV_UndefineSpaceSpecial,
15 Esys_NV_Write, Esys_NV_WriteLock,
16 },
17};
18use log::error;
19use std::convert::{TryFrom, TryInto};
20use std::ptr::null_mut;
21
22impl Context {
23 /// Allocates an index in the non volatile storage.
24 ///
25 /// # Details
26 /// This method will instruct the TPM to reserve space for an NV index
27 /// with the attributes defined in the provided parameters.
28 ///
29 /// Please beware
30 /// that this method requires an authorization session handle to be present.
31 ///
32 /// # Arguments
33 /// * `nv_auth` - The [Provision] used for authorization.
34 /// * `auth` - The authorization value.
35 /// * `public_info` - The public parameters of the NV area.
36 ///
37 /// # Returns
38 /// A [NvIndexHandle] associated with the NV memory that
39 /// was defined.
40 ///
41 /// # Example
42 /// ```rust
43 /// # use tss_esapi::{
44 /// # Context, TctiNameConf, attributes::SessionAttributes, constants::SessionType,
45 /// # structures::SymmetricDefinition,
46 /// # };
47 /// use tss_esapi::{
48 /// handles::NvIndexTpmHandle, attributes::NvIndexAttributes, structures::NvPublic,
49 /// interface_types::{algorithm::HashingAlgorithm, reserved_handles::Provision},
50 /// };
51 /// # // Create context
52 /// # let mut context =
53 /// # Context::new(
54 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
55 /// # ).expect("Failed to create Context");
56 /// #
57 /// # let session = context
58 /// # .start_auth_session(
59 /// # None,
60 /// # None,
61 /// # None,
62 /// # SessionType::Hmac,
63 /// # SymmetricDefinition::AES_256_CFB,
64 /// # HashingAlgorithm::Sha256,
65 /// # )
66 /// # .expect("Failed to create session")
67 /// # .expect("Received invalid handle");
68 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
69 /// # .with_decrypt(true)
70 /// # .with_encrypt(true)
71 /// # .build();
72 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
73 /// # .expect("Failed to set attributes on session");
74 /// # context.set_sessions((Some(session), None, None));
75 /// #
76 /// let nv_index = NvIndexTpmHandle::new(0x01500022)
77 /// .expect("Failed to create NV index tpm handle");
78 ///
79 /// // Create NV index attributes
80 /// let owner_nv_index_attributes = NvIndexAttributes::builder()
81 /// .with_owner_write(true)
82 /// .with_owner_read(true)
83 /// .build()
84 /// .expect("Failed to create owner nv index attributes");
85 ///
86 /// // Create owner nv public.
87 /// let owner_nv_public = NvPublic::builder()
88 /// .with_nv_index(nv_index)
89 /// .with_index_name_algorithm(HashingAlgorithm::Sha256)
90 /// .with_index_attributes(owner_nv_index_attributes)
91 /// .with_data_area_size(32)
92 /// .build()
93 /// .expect("Failed to build NvPublic for owner");
94 ///
95 /// // Define the NV space.
96 /// let owner_nv_index_handle = context
97 /// .nv_define_space(Provision::Owner, None, owner_nv_public)
98 /// .expect("Call to nv_define_space failed");
99 ///
100 /// # context
101 /// # .nv_undefine_space(Provision::Owner, owner_nv_index_handle)
102 /// # .expect("Call to nv_undefine_space failed");
103 /// ```
104 pub fn nv_define_space(
105 &mut self,
106 nv_auth: Provision,
107 auth: Option<Auth>,
108 public_info: NvPublic,
109 ) -> Result<NvIndexHandle> {
110 let mut nv_handle = ObjectHandle::None.into();
111 ReturnCode::ensure_success(
112 unsafe {
113 Esys_NV_DefineSpace(
114 self.mut_context(),
115 AuthHandle::from(nv_auth).into(),
116 self.required_session_1()?,
117 self.optional_session_2(),
118 self.optional_session_3(),
119 &auth.unwrap_or_default().into(),
120 &public_info.try_into()?,
121 &mut nv_handle,
122 )
123 },
124 |ret| {
125 error!("Error when defining NV space: {:#010X}", ret);
126 },
127 )?;
128
129 self.handle_manager
130 .add_handle(nv_handle.into(), HandleDropAction::Close)?;
131 Ok(NvIndexHandle::from(nv_handle))
132 }
133
134 /// Deletes an index in the non volatile storage.
135 ///
136 /// # Details
137 /// The method will instruct the TPM to remove a
138 /// nv index.
139 ///
140 /// Please beware that this method requires an authorization
141 /// session handle to be present.
142 ///
143 /// # Arguments
144 /// * `nv_auth` - The [Provision] used for authorization.
145 /// * `nv_index_handle`- The [NvIndexHandle] associated with
146 /// the nv area that is to be removed.
147 ///
148 /// # Example
149 /// ```rust
150 /// # use tss_esapi::{
151 /// # Context, TctiNameConf, attributes::SessionAttributes, constants::SessionType,
152 /// # structures::SymmetricDefinition,
153 /// # handles::NvIndexTpmHandle, attributes::NvIndexAttributes, structures::NvPublic,
154 /// # interface_types::algorithm::HashingAlgorithm,
155 /// # };
156 /// use tss_esapi::interface_types::reserved_handles::Provision;
157 /// # // Create context
158 /// # let mut context =
159 /// # Context::new(
160 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
161 /// # ).expect("Failed to create Context");
162 /// #
163 /// # let session = context
164 /// # .start_auth_session(
165 /// # None,
166 /// # None,
167 /// # None,
168 /// # SessionType::Hmac,
169 /// # SymmetricDefinition::AES_256_CFB,
170 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
171 /// # )
172 /// # .expect("Failed to create session")
173 /// # .expect("Received invalid handle");
174 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
175 /// # .with_decrypt(true)
176 /// # .with_encrypt(true)
177 /// # .build();
178 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
179 /// # .expect("Failed to set attributes on session");
180 /// # context.set_sessions((Some(session), None, None));
181 /// # let nv_index = NvIndexTpmHandle::new(0x01500023)
182 /// # .expect("Failed to create NV index tpm handle");
183 /// #
184 /// # // Create NV index attributes
185 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
186 /// # .with_owner_write(true)
187 /// # .with_owner_read(true)
188 /// # .build()
189 /// # .expect("Failed to create owner nv index attributes");
190 /// #
191 /// # // Create owner nv public.
192 /// # let owner_nv_public = NvPublic::builder()
193 /// # .with_nv_index(nv_index)
194 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
195 /// # .with_index_attributes(owner_nv_index_attributes)
196 /// # .with_data_area_size(32)
197 /// # .build()
198 /// # .expect("Failed to build NvPublic for owner");
199 /// #
200 /// // Define the NV space.
201 /// let owner_nv_index_handle = context
202 /// .nv_define_space(Provision::Owner, None, owner_nv_public)
203 /// .expect("Call to nv_define_space failed");
204 ///
205 /// context
206 /// .nv_undefine_space(Provision::Owner, owner_nv_index_handle)
207 /// .expect("Call to nv_undefine_space failed");
208 /// ```
209 pub fn nv_undefine_space(
210 &mut self,
211 nv_auth: Provision,
212 nv_index_handle: NvIndexHandle,
213 ) -> Result<()> {
214 ReturnCode::ensure_success(
215 unsafe {
216 Esys_NV_UndefineSpace(
217 self.mut_context(),
218 AuthHandle::from(nv_auth).into(),
219 nv_index_handle.into(),
220 self.required_session_1()?,
221 self.optional_session_2(),
222 self.optional_session_3(),
223 )
224 },
225 |ret| {
226 error!("Error when undefining NV space: {:#010X}", ret);
227 },
228 )?;
229
230 self.handle_manager.set_as_closed(nv_index_handle.into())
231 }
232
233 /// Deletes an index in the non volatile storage.
234 ///
235 /// # Details
236 /// The method will instruct the TPM to remove a
237 /// nv index that was defined with TPMA_NV_POLICY_DELETE.
238 ///
239 /// Please beware that this method requires both a policy and
240 /// authorization session handle to be present.
241 ///
242 /// # Arguments
243 /// * `nv_auth` - The [Provision] used for authorization.
244 /// * `nv_index_handle`- The [NvIndexHandle] associated with
245 /// the nv area that is to be removed.
246 ///
247 /// # Example
248 /// ```rust
249 /// # use tss_esapi::{
250 /// # Context, TctiNameConf, attributes::SessionAttributes, constants::SessionType,
251 /// # structures::SymmetricDefinition, constants::CommandCode,
252 /// # handles::NvIndexTpmHandle, attributes::NvIndexAttributes, structures::NvPublic,
253 /// # interface_types::algorithm::HashingAlgorithm, structures::Digest,
254 /// # interface_types::session_handles::PolicySession,
255 /// # };
256 /// # use std::convert::TryFrom;
257 /// use tss_esapi::interface_types::reserved_handles::Provision;
258 /// use tss_esapi::interface_types::session_handles::AuthSession;
259 /// # // Create context
260 /// # let mut context =
261 /// # Context::new(
262 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
263 /// # ).expect("Failed to create Context");
264 /// #
265 /// # // Create a trial session to generate policy digest
266 /// # let session = context
267 /// # .start_auth_session(
268 /// # None,
269 /// # None,
270 /// # None,
271 /// # SessionType::Trial,
272 /// # SymmetricDefinition::AES_256_CFB,
273 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
274 /// # )
275 /// # .expect("Failed to create session")
276 /// # .expect("Received invalid handle");
277 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
278 /// # .with_decrypt(true)
279 /// # .with_encrypt(true)
280 /// # .build();
281 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
282 /// # .expect("Failed to set attributes on session");
283 /// #
284 /// # // Create a trial policy session that allows undefine with NvUndefineSpaceSpecial
285 /// # let policy_session = PolicySession::try_from(session).expect("Failed to get policy session");
286 /// # context.policy_command_code(policy_session, CommandCode::NvUndefineSpaceSpecial).expect("Failed to create trial policy");
287 /// # let digest = context.policy_get_digest(policy_session).expect("Failed to get policy digest");
288 /// #
289 /// # let nv_index = NvIndexTpmHandle::new(0x01500023)
290 /// # .expect("Failed to create NV index tpm handle");
291 /// #
292 /// # // Create NV index attributes
293 /// # let nv_index_attributes = NvIndexAttributes::builder()
294 /// # .with_pp_read(true)
295 /// # .with_platform_create(true)
296 /// # .with_policy_delete(true)
297 /// # .with_policy_write(true)
298 /// # .build()
299 /// # .expect("Failed to create nv index attributes");
300 /// #
301 /// # // Create nv public.
302 /// # let nv_public = NvPublic::builder()
303 /// # .with_nv_index(nv_index)
304 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
305 /// # .with_index_attributes(nv_index_attributes)
306 /// # .with_index_auth_policy(digest)
307 /// # .with_data_area_size(32)
308 /// # .build()
309 /// # .expect("Failed to build NvPublic");
310 /// #
311 /// // Define the NV space.
312 /// let index_handle = context.execute_with_session(Some(AuthSession::Password), |context| {
313 /// context
314 /// .nv_define_space(Provision::Platform, None, nv_public)
315 /// .expect("Call to nv_define_space failed")
316 /// });
317 ///
318 /// # // Setup auth policy session
319 /// # let session = context
320 /// # .start_auth_session(
321 /// # None,
322 /// # None,
323 /// # None,
324 /// # SessionType::Policy,
325 /// # SymmetricDefinition::AES_256_CFB,
326 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
327 /// # )
328 /// # .expect("Failed to create policy session")
329 /// # .expect("Received invalid handle");
330 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
331 /// # .with_decrypt(true)
332 /// # .with_encrypt(true)
333 /// # .build();
334 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
335 /// # .expect("Failed to set attributes on session");
336 /// #
337 /// # // Define a policy command code that allows undefine with NvUndefineSpaceSpecial
338 /// # let policy_session = PolicySession::try_from(session).expect("Failed to get policy session");
339 /// # context.policy_command_code(policy_session, CommandCode::NvUndefineSpaceSpecial).expect("Failed to create policy");
340 /// #
341 /// // Undefine the NV space with a policy session and default auth session
342 /// context.execute_with_sessions((
343 /// Some(session),
344 /// Some(AuthSession::Password),
345 /// None,
346 /// ), |context| {
347 /// context
348 /// .nv_undefine_space_special(Provision::Platform, index_handle)
349 /// .expect("Call to nv_undefine_space_special failed");
350 /// }
351 /// );
352 /// ```
353 pub fn nv_undefine_space_special(
354 &mut self,
355 nv_auth: Provision,
356 nv_index_handle: NvIndexHandle,
357 ) -> Result<()> {
358 ReturnCode::ensure_success(
359 unsafe {
360 Esys_NV_UndefineSpaceSpecial(
361 self.mut_context(),
362 nv_index_handle.into(),
363 AuthHandle::from(nv_auth).into(),
364 self.required_session_1()?,
365 self.optional_session_2(),
366 self.optional_session_3(),
367 )
368 },
369 |ret| {
370 error!("Error when undefining NV space: {:#010X}", ret);
371 },
372 )?;
373
374 self.handle_manager.set_as_closed(nv_index_handle.into())
375 }
376
377 /// Reads the public part of an nv index.
378 ///
379 /// # Details
380 /// This method is used to read the public
381 /// area and name of a nv index.
382 ///
383 /// # Arguments
384 /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
385 /// for which the public part is to be read.
386 /// # Returns
387 /// A tuple containing the public area and the name of an nv index.
388 ///
389 /// # Example
390 /// ```rust
391 /// # use tss_esapi::{
392 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
393 /// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
394 /// # structures::{SymmetricDefinition, NvPublic}, constants::SessionType,
395 /// # };
396 /// use tss_esapi::{
397 /// interface_types::reserved_handles::Provision,
398 /// };
399 ///
400 /// # // Create context
401 /// # let mut context =
402 /// # Context::new(
403 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
404 /// # ).expect("Failed to create Context");
405 /// #
406 /// # let session = context
407 /// # .start_auth_session(
408 /// # None,
409 /// # None,
410 /// # None,
411 /// # SessionType::Hmac,
412 /// # SymmetricDefinition::AES_256_CFB,
413 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
414 /// # )
415 /// # .expect("Failed to create session")
416 /// # .expect("Received invalid handle");
417 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
418 /// # .with_decrypt(true)
419 /// # .with_encrypt(true)
420 /// # .build();
421 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
422 /// # .expect("Failed to set attributes on session");
423 /// # context.set_sessions((Some(session), None, None));
424 /// #
425 /// # let nv_index = NvIndexTpmHandle::new(0x01500024)
426 /// # .expect("Failed to create NV index tpm handle");
427 /// #
428 /// # // Create NV index attributes
429 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
430 /// # .with_owner_write(true)
431 /// # .with_owner_read(true)
432 /// # .build()
433 /// # .expect("Failed to create owner nv index attributes");
434 /// #
435 /// // Create owner nv public.
436 /// let owner_nv_public = NvPublic::builder()
437 /// .with_nv_index(nv_index)
438 /// .with_index_name_algorithm(HashingAlgorithm::Sha256)
439 /// .with_index_attributes(owner_nv_index_attributes)
440 /// .with_data_area_size(32)
441 /// .build()
442 /// .expect("Failed to build NvPublic for owner");
443 ///
444 /// let nv_index_handle = context
445 /// .nv_define_space(Provision::Owner, None, owner_nv_public.clone())
446 /// .expect("Call to nv_define_space failed");
447 ///
448 /// // Holds the result in order to ensure that the
449 /// // NV space gets undefined.
450 /// let nv_read_public_result = context.nv_read_public(nv_index_handle);
451 ///
452 /// context
453 /// .nv_undefine_space(Provision::Owner, nv_index_handle)
454 /// .expect("Call to nv_undefine_space failed");
455 ///
456 /// // Process result
457 /// let (read_nv_public, _name) = nv_read_public_result
458 /// .expect("Call to nv_read_public failed");
459 ///
460 /// assert_eq!(owner_nv_public, read_nv_public);
461 /// ```
462 pub fn nv_read_public(&mut self, nv_index_handle: NvIndexHandle) -> Result<(NvPublic, Name)> {
463 let mut nv_public_ptr = null_mut();
464 let mut nv_name_ptr = null_mut();
465 ReturnCode::ensure_success(
466 unsafe {
467 Esys_NV_ReadPublic(
468 self.mut_context(),
469 nv_index_handle.into(),
470 self.optional_session_1(),
471 self.optional_session_2(),
472 self.optional_session_3(),
473 &mut nv_public_ptr,
474 &mut nv_name_ptr,
475 )
476 },
477 |ret| {
478 error!("Error when reading NV public: {:#010X}", ret);
479 },
480 )?;
481
482 Ok((
483 NvPublic::try_from(Context::ffi_data_to_owned(nv_public_ptr)?)?,
484 Name::try_from(Context::ffi_data_to_owned(nv_name_ptr)?)?,
485 ))
486 }
487
488 /// Writes data to the NV memory associated with a nv index.
489 ///
490 /// # Details
491 /// This method is used to write a value to
492 /// the nv memory in the TPM.
493 ///
494 /// Please beware that this method requires an authorization
495 /// session handle to be present.
496 ///
497 /// # Arguments
498 /// * `auth_handle` - Handle indicating the source of authorization value.
499 /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
500 /// where data is to be written.
501 /// * `data` - The data, in the form of a [MaxNvBuffer], that is to be written.
502 /// * `offset` - The octet offset into the NV area.
503 ///
504 /// # Example
505 /// ```rust
506 /// # use tss_esapi::{
507 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
508 /// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
509 /// # structures::{SymmetricDefinition, NvPublic}, constants::SessionType,
510 /// # };
511 /// use tss_esapi::{
512 /// interface_types::reserved_handles::{Provision, NvAuth}, structures::MaxNvBuffer,
513 /// };
514 /// use std::convert::TryFrom;
515 ///
516 /// # // Create context
517 /// # let mut context =
518 /// # Context::new(
519 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
520 /// # ).expect("Failed to create Context");
521 /// #
522 /// # let session = context
523 /// # .start_auth_session(
524 /// # None,
525 /// # None,
526 /// # None,
527 /// # SessionType::Hmac,
528 /// # SymmetricDefinition::AES_256_CFB,
529 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
530 /// # )
531 /// # .expect("Failed to create session")
532 /// # .expect("Received invalid handle");
533 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
534 /// # .with_decrypt(true)
535 /// # .with_encrypt(true)
536 /// # .build();
537 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
538 /// # .expect("Failed to set attributes on session");
539 /// # context.set_sessions((Some(session), None, None));
540 /// #
541 /// # let nv_index = NvIndexTpmHandle::new(0x01500025)
542 /// # .expect("Failed to create NV index tpm handle");
543 /// #
544 /// # // Create NV index attributes
545 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
546 /// # .with_owner_write(true)
547 /// # .with_owner_read(true)
548 /// # .build()
549 /// # .expect("Failed to create owner nv index attributes");
550 /// #
551 /// # // Create owner nv public.
552 /// # let owner_nv_public = NvPublic::builder()
553 /// # .with_nv_index(nv_index)
554 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
555 /// # .with_index_attributes(owner_nv_index_attributes)
556 /// # .with_data_area_size(32)
557 /// # .build()
558 /// # .expect("Failed to build NvPublic for owner");
559 ///
560 /// let data = MaxNvBuffer::try_from(vec![1, 2, 3, 4, 5, 6, 7])
561 /// .expect("Failed to create MaxNvBuffer from vec");
562 ///
563 /// let nv_index_handle = context
564 /// .nv_define_space(Provision::Owner, None, owner_nv_public.clone())
565 /// .expect("Call to nv_define_space failed");
566 ///
567 /// // Use owner authorization
568 /// let nv_write_result = context.nv_write(NvAuth::Owner, nv_index_handle, data, 0);
569 ///
570 /// context
571 /// .nv_undefine_space(Provision::Owner, nv_index_handle)
572 /// .expect("Call to nv_undefine_space failed");
573 ///
574 /// // Process result
575 /// nv_write_result.expect("Call to nv_write failed");
576 /// ```
577 pub fn nv_write(
578 &mut self,
579 auth_handle: NvAuth,
580 nv_index_handle: NvIndexHandle,
581 data: MaxNvBuffer,
582 offset: u16,
583 ) -> Result<()> {
584 ReturnCode::ensure_success(
585 unsafe {
586 Esys_NV_Write(
587 self.mut_context(),
588 AuthHandle::from(auth_handle).into(),
589 nv_index_handle.into(),
590 self.required_session_1()?,
591 self.optional_session_2(),
592 self.optional_session_3(),
593 &data.into(),
594 offset,
595 )
596 },
597 |ret| {
598 error!("Error when writing NV: {:#010X}", ret);
599 },
600 )
601 }
602
603 /// Increment monotonic counter index
604 ///
605 /// # Details
606 /// This method is used to increment monotonic counter
607 /// in the TPM.
608 ///
609 /// Please beware that this method requires an authorization
610 /// session handle to be present.
611 ///
612 /// # Arguments
613 /// * `auth_handle` - Handle indicating the source of authorization value.
614 /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
615 /// where data is to be written.
616 /// ```rust
617 /// # use tss_esapi::{
618 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
619 /// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
620 /// # structures::{SymmetricDefinition, NvPublic}, constants::SessionType,
621 /// # constants::nv_index_type::NvIndexType,
622 /// # };
623 /// use tss_esapi::{
624 /// interface_types::reserved_handles::{Provision, NvAuth}
625 /// };
626 ///
627 /// # // Create context
628 /// # let mut context =
629 /// # Context::new(
630 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
631 /// # ).expect("Failed to create Context");
632 /// #
633 /// # let session = context
634 /// # .start_auth_session(
635 /// # None,
636 /// # None,
637 /// # None,
638 /// # SessionType::Hmac,
639 /// # SymmetricDefinition::AES_256_CFB,
640 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
641 /// # )
642 /// # .expect("Failed to create session")
643 /// # .expect("Received invalid handle");
644 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
645 /// # .with_decrypt(true)
646 /// # .with_encrypt(true)
647 /// # .build();
648 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
649 /// # .expect("Failed to set attributes on session");
650 /// # context.set_sessions((Some(session), None, None));
651 /// #
652 /// # let nv_index = NvIndexTpmHandle::new(0x01500026)
653 /// # .expect("Failed to create NV index tpm handle");
654 /// #
655 /// # // Create NV index attributes
656 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
657 /// # .with_owner_write(true)
658 /// # .with_owner_read(true)
659 /// # .with_nv_index_type(NvIndexType::Counter)
660 /// # .build()
661 /// # .expect("Failed to create owner nv index attributes");
662 /// #
663 /// # // Create owner nv public.
664 /// # let owner_nv_public = NvPublic::builder()
665 /// # .with_nv_index(nv_index)
666 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
667 /// # .with_index_attributes(owner_nv_index_attributes)
668 /// # .with_data_area_size(8)
669 /// # .build()
670 /// # .expect("Failed to build NvPublic for owner");
671 /// #
672 /// let nv_index_handle = context
673 /// .nv_define_space(Provision::Owner, None, owner_nv_public.clone())
674 /// .expect("Call to nv_define_space failed");
675 ///
676 /// let nv_increment_result = context.nv_increment(NvAuth::Owner, nv_index_handle);
677 ///
678 /// context
679 /// .nv_undefine_space(Provision::Owner, nv_index_handle)
680 /// .expect("Call to nv_undefine_space failed");
681 ///
682 /// // Process result
683 /// nv_increment_result.expect("Call to nv_increment failed");
684 /// ```
685 pub fn nv_increment(
686 &mut self,
687 auth_handle: NvAuth,
688 nv_index_handle: NvIndexHandle,
689 ) -> Result<()> {
690 ReturnCode::ensure_success(
691 unsafe {
692 Esys_NV_Increment(
693 self.mut_context(),
694 AuthHandle::from(auth_handle).into(),
695 nv_index_handle.into(),
696 self.required_session_1()?,
697 self.optional_session_2(),
698 self.optional_session_3(),
699 )
700 },
701 |ret| error!("Error when incrementing NV: {:#010X}", ret),
702 )
703 }
704
705 /// Extends data to the NV memory associated with a nv index.
706 ///
707 /// # Details
708 /// This method is used to extend a value to the nv memory in the TPM.
709 ///
710 /// Please beware that this method requires an authorization session handle to be present.
711 ///
712 /// Any NV index (that is not already used) can be defined as an extend type. However various specifications define
713 /// indexes that have specific purposes or are reserved, for example the TCG PC Client Platform Firmware Profile
714 /// Specification Section 3.3.6 defines indexes within the 0x01c40200-0x01c402ff range for instance measurements.
715 /// Section 2.2 of TCG Registry of Reserved TPM 2.0 Handles and Localities provides additional context for specific
716 /// NV index ranges.
717 ///
718 /// # Arguments
719 /// * `auth_handle` - Handle indicating the source of authorization value.
720 /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
721 /// which will be extended by data hashed with the previous data.
722 /// * `data` - The data, in the form of a [MaxNvBuffer], that is to be written.
723 ///
724 /// # Example
725 /// ```rust
726 /// # use tss_esapi::{
727 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
728 /// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
729 /// # structures::{SymmetricDefinition, NvPublic},
730 /// # constants::SessionType, constants::nv_index_type::NvIndexType,
731 /// # };
732 /// use tss_esapi::{
733 /// interface_types::reserved_handles::{Provision, NvAuth}, structures::MaxNvBuffer,
734 /// };
735 ///
736 /// # // Create context
737 /// # let mut context =
738 /// # Context::new(
739 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
740 /// # ).expect("Failed to create Context");
741 /// #
742 /// # let session = context
743 /// # .start_auth_session(
744 /// # None,
745 /// # None,
746 /// # None,
747 /// # SessionType::Hmac,
748 /// # SymmetricDefinition::AES_256_CFB,
749 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
750 /// # )
751 /// # .expect("Failed to create session")
752 /// # .expect("Received invalid handle");
753 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
754 /// # .with_decrypt(true)
755 /// # .with_encrypt(true)
756 /// # .build();
757 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
758 /// # .expect("Failed to set attributes on session");
759 /// # context.set_sessions((Some(session), None, None));
760 /// #
761 /// # let nv_index = NvIndexTpmHandle::new(0x01500028)
762 /// # .expect("Failed to create NV index tpm handle");
763 /// #
764 /// // Create NV index attributes
765 /// let owner_nv_index_attributes = NvIndexAttributes::builder()
766 /// .with_owner_write(true)
767 /// .with_owner_read(true)
768 /// .with_orderly(true)
769 /// .with_nv_index_type(NvIndexType::Extend)
770 /// .build()
771 /// .expect("Failed to create owner nv index attributes");
772 ///
773 /// // Create owner nv public.
774 /// let owner_nv_public = NvPublic::builder()
775 /// .with_nv_index(nv_index)
776 /// .with_index_name_algorithm(HashingAlgorithm::Sha256)
777 /// .with_index_attributes(owner_nv_index_attributes)
778 /// .with_data_area_size(32)
779 /// .build()
780 /// .expect("Failed to build NvPublic for owner");
781 ///
782 /// let nv_index_handle = context
783 /// .nv_define_space(Provision::Owner, None, owner_nv_public.clone())
784 /// .expect("Call to nv_define_space failed");
785 ///
786 /// let data = MaxNvBuffer::try_from(vec![0x0]).unwrap();
787 /// let result = context.nv_extend(NvAuth::Owner, nv_index_handle, data);
788 ///
789 /// # context
790 /// # .nv_undefine_space(Provision::Owner, nv_index_handle)
791 /// # .expect("Call to nv_undefine_space failed");
792 /// ```
793 pub fn nv_extend(
794 &mut self,
795 auth_handle: NvAuth,
796 nv_index_handle: NvIndexHandle,
797 data: MaxNvBuffer,
798 ) -> Result<()> {
799 ReturnCode::ensure_success(
800 unsafe {
801 Esys_NV_Extend(
802 self.mut_context(),
803 AuthHandle::from(auth_handle).into(),
804 nv_index_handle.into(),
805 self.required_session_1()?,
806 self.optional_session_2(),
807 self.optional_session_3(),
808 &data.into(),
809 )
810 },
811 |ret| error!("Error when extending NV: {:#010X}", ret),
812 )
813 }
814
815 /// Set bits in an NV index.
816 ///
817 /// # Arguments
818 ///
819 /// * `auth_handle` - The handle indicating the source of authorization value.
820 /// * `nv_index_handle` - The [NvIndexHandle] of the NV index.
821 /// * `bits` - The data to OR with the current contents.
822 ///
823 /// # Details
824 ///
825 /// *From the specification*
826 /// > This command is used to SET bits in an NV Index that was
827 /// > created as a bit field. Any number of bits from 0 to 64 may
828 /// > be SET. The contents of bits are ORed with the current contents
829 /// > of the NV Index.
830 ///
831 /// # Example
832 /// ```rust
833 /// # use tss_esapi::{
834 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
835 /// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
836 /// # structures::{SymmetricDefinition, NvPublic}, constants::SessionType,
837 /// # constants::nv_index_type::NvIndexType,
838 /// # };
839 /// use tss_esapi::interface_types::reserved_handles::{Provision, NvAuth};
840 ///
841 /// # // Create context
842 /// # let mut context =
843 /// # Context::new(
844 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
845 /// # ).expect("Failed to create Context");
846 /// #
847 /// # let session = context
848 /// # .start_auth_session(
849 /// # None,
850 /// # None,
851 /// # None,
852 /// # SessionType::Hmac,
853 /// # SymmetricDefinition::AES_256_CFB,
854 /// # HashingAlgorithm::Sha256,
855 /// # )
856 /// # .expect("Failed to create session")
857 /// # .expect("Received invalid handle");
858 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
859 /// # .with_decrypt(true)
860 /// # .with_encrypt(true)
861 /// # .build();
862 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
863 /// # .expect("Failed to set attributes on session");
864 /// # context.set_sessions((Some(session), None, None));
865 /// #
866 /// # let nv_index = NvIndexTpmHandle::new(0x01500030)
867 /// # .expect("Failed to create NV index tpm handle");
868 /// #
869 /// # // Create NV index attributes for a bit field.
870 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
871 /// # .with_owner_write(true)
872 /// # .with_owner_read(true)
873 /// # .with_nv_index_type(NvIndexType::Bits)
874 /// # .build()
875 /// # .expect("Failed to create owner nv index attributes");
876 /// #
877 /// # // Create owner nv public.
878 /// # let owner_nv_public = NvPublic::builder()
879 /// # .with_nv_index(nv_index)
880 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
881 /// # .with_index_attributes(owner_nv_index_attributes)
882 /// # .with_data_area_size(8)
883 /// # .build()
884 /// # .expect("Failed to build NvPublic for owner");
885 /// #
886 /// let nv_index_handle = context
887 /// .nv_define_space(Provision::Owner, None, owner_nv_public)
888 /// .expect("Call to nv_define_space failed");
889 ///
890 /// let nv_set_bits_result = context.nv_set_bits(NvAuth::Owner, nv_index_handle, 0x01);
891 ///
892 /// context
893 /// .nv_undefine_space(Provision::Owner, nv_index_handle)
894 /// .expect("Call to nv_undefine_space failed");
895 ///
896 /// // Process result
897 /// nv_set_bits_result.expect("Call to nv_set_bits failed");
898 /// ```
899 pub fn nv_set_bits(
900 &mut self,
901 auth_handle: NvAuth,
902 nv_index_handle: NvIndexHandle,
903 bits: u64,
904 ) -> Result<()> {
905 ReturnCode::ensure_success(
906 unsafe {
907 Esys_NV_SetBits(
908 self.mut_context(),
909 AuthHandle::from(auth_handle).into(),
910 nv_index_handle.into(),
911 self.required_session_1()?,
912 self.optional_session_2(),
913 self.optional_session_3(),
914 bits,
915 )
916 },
917 |ret| {
918 error!("Error when setting NV bits: {:#010X}", ret);
919 },
920 )
921 }
922
923 /// Write-lock an NV index.
924 ///
925 /// # Arguments
926 ///
927 /// * `auth_handle` - The handle indicating the source of authorization value.
928 /// * `nv_index_handle` - The [NvIndexHandle] of the NV index.
929 ///
930 /// # Details
931 ///
932 /// *From the specification*
933 /// > If the TPMA_NV_WRITEDEFINE or TPMA_NV_WRITE_STCLEAR attribute of
934 /// > the NV Index is SET, then this command may be used to inhibit
935 /// > further writes of the NV Index.
936 ///
937 /// # Example
938 /// ```rust
939 /// # use tss_esapi::{
940 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
941 /// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
942 /// # structures::{SymmetricDefinition, NvPublic}, constants::SessionType,
943 /// # };
944 /// use tss_esapi::interface_types::reserved_handles::{Provision, NvAuth};
945 ///
946 /// # // Create context
947 /// # let mut context =
948 /// # Context::new(
949 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
950 /// # ).expect("Failed to create Context");
951 /// #
952 /// # let session = context
953 /// # .start_auth_session(
954 /// # None,
955 /// # None,
956 /// # None,
957 /// # SessionType::Hmac,
958 /// # SymmetricDefinition::AES_256_CFB,
959 /// # HashingAlgorithm::Sha256,
960 /// # )
961 /// # .expect("Failed to create session")
962 /// # .expect("Received invalid handle");
963 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
964 /// # .with_decrypt(true)
965 /// # .with_encrypt(true)
966 /// # .build();
967 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
968 /// # .expect("Failed to set attributes on session");
969 /// # context.set_sessions((Some(session), None, None));
970 /// #
971 /// # let nv_index = NvIndexTpmHandle::new(0x01500031)
972 /// # .expect("Failed to create NV index tpm handle");
973 /// #
974 /// # // Create NV index attributes that allow the write lock to be set.
975 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
976 /// # .with_owner_write(true)
977 /// # .with_owner_read(true)
978 /// # .with_write_stclear(true)
979 /// # .build()
980 /// # .expect("Failed to create owner nv index attributes");
981 /// #
982 /// # // Create owner nv public.
983 /// # let owner_nv_public = NvPublic::builder()
984 /// # .with_nv_index(nv_index)
985 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
986 /// # .with_index_attributes(owner_nv_index_attributes)
987 /// # .with_data_area_size(32)
988 /// # .build()
989 /// # .expect("Failed to build NvPublic for owner");
990 /// #
991 /// let nv_index_handle = context
992 /// .nv_define_space(Provision::Owner, None, owner_nv_public)
993 /// .expect("Call to nv_define_space failed");
994 ///
995 /// let nv_write_lock_result = context.nv_write_lock(NvAuth::Owner, nv_index_handle);
996 ///
997 /// context
998 /// .nv_undefine_space(Provision::Owner, nv_index_handle)
999 /// .expect("Call to nv_undefine_space failed");
1000 ///
1001 /// // Process result
1002 /// nv_write_lock_result.expect("Call to nv_write_lock failed");
1003 /// ```
1004 pub fn nv_write_lock(
1005 &mut self,
1006 auth_handle: NvAuth,
1007 nv_index_handle: NvIndexHandle,
1008 ) -> Result<()> {
1009 ReturnCode::ensure_success(
1010 unsafe {
1011 Esys_NV_WriteLock(
1012 self.mut_context(),
1013 AuthHandle::from(auth_handle).into(),
1014 nv_index_handle.into(),
1015 self.required_session_1()?,
1016 self.optional_session_2(),
1017 self.optional_session_3(),
1018 )
1019 },
1020 |ret| {
1021 error!("Error when write-locking NV index: {:#010X}", ret);
1022 },
1023 )
1024 }
1025
1026 /// Apply a global lock on NV write.
1027 ///
1028 /// # Arguments
1029 ///
1030 /// * `auth_handle` - An [AuthHandle] used for authorization. This command
1031 /// requires either [AuthHandle::Owner] (ownerAuth/ownerPolicy) or
1032 /// [AuthHandle::Platform] (platformAuth/platformPolicy).
1033 ///
1034 /// # Details
1035 ///
1036 /// *From the specification*
1037 /// > This command will SET TPMA_NV_WRITELOCKED for all indexes that have
1038 /// > their TPMA_NV_GLOBALLOCK attribute SET.
1039 ///
1040 /// # Example
1041 /// ```rust
1042 /// # use tss_esapi::{
1043 /// # Context, TctiNameConf, attributes::SessionAttributes,
1044 /// # interface_types::algorithm::HashingAlgorithm,
1045 /// # structures::SymmetricDefinition, constants::SessionType,
1046 /// # };
1047 /// use tss_esapi::handles::AuthHandle;
1048 ///
1049 /// # // Create context
1050 /// # let mut context =
1051 /// # Context::new(
1052 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
1053 /// # ).expect("Failed to create Context");
1054 /// #
1055 /// # let session = context
1056 /// # .start_auth_session(
1057 /// # None,
1058 /// # None,
1059 /// # None,
1060 /// # SessionType::Hmac,
1061 /// # SymmetricDefinition::AES_256_CFB,
1062 /// # HashingAlgorithm::Sha256,
1063 /// # )
1064 /// # .expect("Failed to create session")
1065 /// # .expect("Received invalid handle");
1066 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
1067 /// # .with_decrypt(true)
1068 /// # .with_encrypt(true)
1069 /// # .build();
1070 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
1071 /// # .expect("Failed to set attributes on session");
1072 /// # context.set_sessions((Some(session), None, None));
1073 /// #
1074 /// context.nv_global_write_lock(AuthHandle::Owner)
1075 /// .expect("Call to nv_global_write_lock failed");
1076 /// ```
1077 pub fn nv_global_write_lock(&mut self, auth_handle: AuthHandle) -> Result<()> {
1078 ReturnCode::ensure_success(
1079 unsafe {
1080 Esys_NV_GlobalWriteLock(
1081 self.mut_context(),
1082 auth_handle.into(),
1083 self.required_session_1()?,
1084 self.optional_session_2(),
1085 self.optional_session_3(),
1086 )
1087 },
1088 |ret| {
1089 error!("Error when globally write-locking NV: {:#010X}", ret);
1090 },
1091 )
1092 }
1093
1094 /// Reads data from the nv index.
1095 ///
1096 /// # Details
1097 /// This method is used to read a value from an area in
1098 /// NV memory of the TPM.
1099 ///
1100 /// Please beware that this method requires an authorization
1101 /// session handle to be present.
1102 ///
1103 /// # Arguments
1104 /// * `auth_handle` - Handle indicating the source of authorization value.
1105 /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
1106 /// where data is to be written.
1107 /// * `size` - The number of octets to read.
1108 /// * `offset`- Octet offset into the NV area.
1109 ///
1110 /// # Example
1111 /// ```rust
1112 /// # use tss_esapi::{
1113 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
1114 /// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
1115 /// # structures::{SymmetricDefinition, NvPublic}, constants::SessionType,
1116 /// # };
1117 /// use tss_esapi::{
1118 /// interface_types::reserved_handles::{Provision, NvAuth}, structures::MaxNvBuffer,
1119 /// };
1120 /// use std::convert::TryFrom;
1121 ///
1122 /// # // Create context
1123 /// # let mut context =
1124 /// # Context::new(
1125 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
1126 /// # ).expect("Failed to create Context");
1127 /// #
1128 /// # let session = context
1129 /// # .start_auth_session(
1130 /// # None,
1131 /// # None,
1132 /// # None,
1133 /// # SessionType::Hmac,
1134 /// # SymmetricDefinition::AES_256_CFB,
1135 /// # tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
1136 /// # )
1137 /// # .expect("Failed to create session")
1138 /// # .expect("Received invalid handle");
1139 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
1140 /// # .with_decrypt(true)
1141 /// # .with_encrypt(true)
1142 /// # .build();
1143 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
1144 /// # .expect("Failed to set attributes on session");
1145 /// # context.set_sessions((Some(session), None, None));
1146 /// #
1147 /// # let nv_index = NvIndexTpmHandle::new(0x01500027)
1148 /// # .expect("Failed to create NV index tpm handle");
1149 /// #
1150 /// # // Create NV index attributes
1151 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
1152 /// # .with_owner_write(true)
1153 /// # .with_owner_read(true)
1154 /// # .build()
1155 /// # .expect("Failed to create owner nv index attributes");
1156 /// #
1157 /// # // Create owner nv public.
1158 /// # let owner_nv_public = NvPublic::builder()
1159 /// # .with_nv_index(nv_index)
1160 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
1161 /// # .with_index_attributes(owner_nv_index_attributes)
1162 /// # .with_data_area_size(32)
1163 /// # .build()
1164 /// # .expect("Failed to build NvPublic for owner");
1165 /// #
1166 /// let data = MaxNvBuffer::try_from(vec![1, 2, 3, 4, 5, 6, 7])
1167 /// .expect("Failed to create MaxNvBuffer from vec");
1168 ///
1169 /// let nv_index_handle = context
1170 /// .nv_define_space(Provision::Owner, None, owner_nv_public)
1171 /// .expect("Call to nv_define_space failed");
1172 ///
1173 /// // Write data using owner authorization
1174 /// let nv_write_result = context.nv_write(NvAuth::Owner, nv_index_handle, data.clone(), 0);
1175 ///
1176 /// // Read data using owner authorization
1177 /// let data_len = u16::try_from(data.len()).expect("Failed to retrieve length of data");
1178 /// let nv_read_result = context
1179 /// .nv_read(NvAuth::Owner, nv_index_handle, data_len, 0);
1180 ///
1181 /// context
1182 /// .nv_undefine_space(Provision::Owner, nv_index_handle)
1183 /// .expect("Call to nv_undefine_space failed");
1184 ///
1185 /// // Process result
1186 /// nv_write_result.expect("Call to nv_write failed");
1187 /// let read_data = nv_read_result.expect("Call to nv_read failed");
1188 /// assert_eq!(data, read_data);
1189 /// ```
1190 pub fn nv_read(
1191 &mut self,
1192 auth_handle: NvAuth,
1193 nv_index_handle: NvIndexHandle,
1194 size: u16,
1195 offset: u16,
1196 ) -> Result<MaxNvBuffer> {
1197 let mut data_ptr = null_mut();
1198 ReturnCode::ensure_success(
1199 unsafe {
1200 Esys_NV_Read(
1201 self.mut_context(),
1202 AuthHandle::from(auth_handle).into(),
1203 nv_index_handle.into(),
1204 self.required_session_1()?,
1205 self.optional_session_2(),
1206 self.optional_session_3(),
1207 size,
1208 offset,
1209 &mut data_ptr,
1210 )
1211 },
1212 |ret| {
1213 error!("Error when reading NV: {:#010X}", ret);
1214 },
1215 )?;
1216 MaxNvBuffer::try_from(Context::ffi_data_to_owned(data_ptr)?)
1217 }
1218
1219 /// Read-lock an NV index.
1220 ///
1221 /// # Arguments
1222 ///
1223 /// * `auth_handle` - The handle indicating the source of authorization value.
1224 /// * `nv_index_handle` - The [NvIndexHandle] of the NV index.
1225 ///
1226 /// # Details
1227 ///
1228 /// *From the specification*
1229 /// > If TPMA_NV_READ_STCLEAR is SET in an Index, then this command
1230 /// > may be used to prevent further reads of the NV Index until
1231 /// > the next TPM2_Startup (TPM_SU_CLEAR).
1232 ///
1233 /// # Example
1234 /// ```rust
1235 /// # use tss_esapi::{
1236 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
1237 /// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
1238 /// # structures::{SymmetricDefinition, NvPublic}, constants::SessionType,
1239 /// # };
1240 /// use tss_esapi::interface_types::reserved_handles::{Provision, NvAuth};
1241 ///
1242 /// # // Create context
1243 /// # let mut context =
1244 /// # Context::new(
1245 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
1246 /// # ).expect("Failed to create Context");
1247 /// #
1248 /// # let session = context
1249 /// # .start_auth_session(
1250 /// # None,
1251 /// # None,
1252 /// # None,
1253 /// # SessionType::Hmac,
1254 /// # SymmetricDefinition::AES_256_CFB,
1255 /// # HashingAlgorithm::Sha256,
1256 /// # )
1257 /// # .expect("Failed to create session")
1258 /// # .expect("Received invalid handle");
1259 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
1260 /// # .with_decrypt(true)
1261 /// # .with_encrypt(true)
1262 /// # .build();
1263 /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
1264 /// # .expect("Failed to set attributes on session");
1265 /// # context.set_sessions((Some(session), None, None));
1266 /// #
1267 /// # let nv_index = NvIndexTpmHandle::new(0x01500032)
1268 /// # .expect("Failed to create NV index tpm handle");
1269 /// #
1270 /// # // Create NV index attributes that allow the read lock to be set.
1271 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
1272 /// # .with_owner_write(true)
1273 /// # .with_owner_read(true)
1274 /// # .with_read_stclear(true)
1275 /// # .build()
1276 /// # .expect("Failed to create owner nv index attributes");
1277 /// #
1278 /// # // Create owner nv public.
1279 /// # let owner_nv_public = NvPublic::builder()
1280 /// # .with_nv_index(nv_index)
1281 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
1282 /// # .with_index_attributes(owner_nv_index_attributes)
1283 /// # .with_data_area_size(32)
1284 /// # .build()
1285 /// # .expect("Failed to build NvPublic for owner");
1286 /// #
1287 /// let nv_index_handle = context
1288 /// .nv_define_space(Provision::Owner, None, owner_nv_public)
1289 /// .expect("Call to nv_define_space failed");
1290 ///
1291 /// let nv_read_lock_result = context.nv_read_lock(NvAuth::Owner, nv_index_handle);
1292 ///
1293 /// context
1294 /// .nv_undefine_space(Provision::Owner, nv_index_handle)
1295 /// .expect("Call to nv_undefine_space failed");
1296 ///
1297 /// // Process result
1298 /// nv_read_lock_result.expect("Call to nv_read_lock failed");
1299 /// ```
1300 pub fn nv_read_lock(
1301 &mut self,
1302 auth_handle: NvAuth,
1303 nv_index_handle: NvIndexHandle,
1304 ) -> Result<()> {
1305 ReturnCode::ensure_success(
1306 unsafe {
1307 Esys_NV_ReadLock(
1308 self.mut_context(),
1309 AuthHandle::from(auth_handle).into(),
1310 nv_index_handle.into(),
1311 self.required_session_1()?,
1312 self.optional_session_2(),
1313 self.optional_session_3(),
1314 )
1315 },
1316 |ret| {
1317 error!("Error when read-locking NV index: {:#010X}", ret);
1318 },
1319 )
1320 }
1321
1322 /// Change the authorization value for an NV index.
1323 ///
1324 /// # Arguments
1325 ///
1326 /// * `nv_index_handle` - The [NvIndexHandle] of the NV index.
1327 /// * `new_auth` - The new authorization [Auth] value.
1328 ///
1329 /// # Details
1330 ///
1331 /// *From the specification*
1332 /// > This command allows the authorization secret for an NV Index
1333 /// > to be changed.
1334 ///
1335 /// # Details
1336 ///
1337 /// NV_ChangeAuth uses the ADMIN role of the NV index. This is satisfied by a
1338 /// policy session whose policy includes
1339 /// [`CommandCode::NvChangeAuth`](crate::constants::CommandCode::NvChangeAuth),
1340 /// so the index must be defined with a matching `authPolicy`.
1341 ///
1342 /// # Example
1343 /// ```rust
1344 /// # use tss_esapi::{
1345 /// # Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
1346 /// # handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
1347 /// # structures::{SymmetricDefinition, NvPublic, Auth}, constants::SessionType,
1348 /// # interface_types::session_handles::PolicySession,
1349 /// # };
1350 /// # use std::convert::TryFrom;
1351 /// use tss_esapi::{
1352 /// constants::CommandCode,
1353 /// interface_types::{reserved_handles::Provision, session_handles::AuthSession},
1354 /// };
1355 ///
1356 /// # // Create context
1357 /// # let mut context =
1358 /// # Context::new(
1359 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
1360 /// # ).expect("Failed to create Context");
1361 /// #
1362 /// # // Trial session to compute the policy digest for NV_ChangeAuth.
1363 /// # let trial_session = context
1364 /// # .start_auth_session(
1365 /// # None,
1366 /// # None,
1367 /// # None,
1368 /// # SessionType::Trial,
1369 /// # SymmetricDefinition::AES_256_CFB,
1370 /// # HashingAlgorithm::Sha256,
1371 /// # )
1372 /// # .expect("Failed to create session")
1373 /// # .expect("Received invalid handle");
1374 /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
1375 /// # .with_decrypt(true)
1376 /// # .with_encrypt(true)
1377 /// # .build();
1378 /// # context.tr_sess_set_attributes(trial_session, session_attributes, session_attributes_mask)
1379 /// # .expect("Failed to set attributes on session");
1380 /// # let trial_policy_session = PolicySession::try_from(trial_session)
1381 /// # .expect("Failed to get policy session");
1382 /// # context.policy_command_code(trial_policy_session, CommandCode::NvChangeAuth)
1383 /// # .expect("Failed to create trial policy");
1384 /// # let digest = context.policy_get_digest(trial_policy_session)
1385 /// # .expect("Failed to get policy digest");
1386 /// #
1387 /// # let nv_index = NvIndexTpmHandle::new(0x01500033)
1388 /// # .expect("Failed to create NV index tpm handle");
1389 /// #
1390 /// # // Define the index with the NV_ChangeAuth policy as its authPolicy.
1391 /// # let nv_index_attributes = NvIndexAttributes::builder()
1392 /// # .with_owner_write(true)
1393 /// # .with_owner_read(true)
1394 /// # .with_policy_write(true)
1395 /// # .with_policy_read(true)
1396 /// # .build()
1397 /// # .expect("Failed to create nv index attributes");
1398 /// #
1399 /// let nv_public = NvPublic::builder()
1400 /// .with_nv_index(nv_index)
1401 /// .with_index_name_algorithm(HashingAlgorithm::Sha256)
1402 /// .with_index_attributes(nv_index_attributes)
1403 /// .with_index_auth_policy(digest)
1404 /// .with_data_area_size(32)
1405 /// .build()
1406 /// .expect("Failed to build NvPublic");
1407 ///
1408 /// let nv_index_handle = context
1409 /// .execute_with_session(Some(AuthSession::Password), |context| {
1410 /// context.nv_define_space(Provision::Owner, None, nv_public)
1411 /// })
1412 /// .expect("Call to nv_define_space failed");
1413 ///
1414 /// // Start a policy session satisfying the index's NV_ChangeAuth policy.
1415 /// let policy_session = context
1416 /// .start_auth_session(
1417 /// None,
1418 /// None,
1419 /// None,
1420 /// SessionType::Policy,
1421 /// SymmetricDefinition::AES_256_CFB,
1422 /// HashingAlgorithm::Sha256,
1423 /// )
1424 /// .expect("Failed to create policy session")
1425 /// .expect("Received invalid handle");
1426 /// # context.tr_sess_set_attributes(policy_session, session_attributes, session_attributes_mask)
1427 /// # .expect("Failed to set attributes on session");
1428 /// context
1429 /// .policy_command_code(
1430 /// PolicySession::try_from(policy_session).expect("Failed to get policy session"),
1431 /// CommandCode::NvChangeAuth,
1432 /// )
1433 /// .expect("Failed to create policy");
1434 ///
1435 /// let new_auth = Auth::from_bytes(&[1, 2, 3, 4]).expect("Failed to create new auth");
1436 /// let nv_change_auth_result = context.execute_with_session(Some(policy_session), |context| {
1437 /// context.nv_change_auth(nv_index_handle, new_auth)
1438 /// });
1439 ///
1440 /// context
1441 /// .execute_with_session(Some(AuthSession::Password), |context| {
1442 /// context.nv_undefine_space(Provision::Owner, nv_index_handle)
1443 /// })
1444 /// .expect("Call to nv_undefine_space failed");
1445 ///
1446 /// // Process result
1447 /// nv_change_auth_result.expect("Call to nv_change_auth failed");
1448 /// ```
1449 pub fn nv_change_auth(&mut self, nv_index_handle: NvIndexHandle, new_auth: Auth) -> Result<()> {
1450 ReturnCode::ensure_success(
1451 unsafe {
1452 Esys_NV_ChangeAuth(
1453 self.mut_context(),
1454 nv_index_handle.into(),
1455 self.required_session_1()?,
1456 self.optional_session_2(),
1457 self.optional_session_3(),
1458 &new_auth.into(),
1459 )
1460 },
1461 |ret| {
1462 error!("Error when changing NV auth: {:#010X}", ret);
1463 },
1464 )
1465 }
1466
1467 /// Certify the contents of an NV index.
1468 ///
1469 /// # Arguments
1470 ///
1471 /// * `sign_handle` - A [KeyHandle] of the key used to sign the attestation structure.
1472 /// * `auth_handle` - The handle indicating the source of authorization value for the NV index.
1473 /// * `nv_index_handle` - The [NvIndexHandle] of the NV index to be certified.
1474 /// * `qualifying_data` - [Data] to qualify the signing.
1475 /// * `signing_scheme` - The [SignatureScheme] to use for signing.
1476 /// * `size` - Number of octets to certify.
1477 /// * `offset` - Octet offset into the NV area.
1478 ///
1479 /// # Details
1480 ///
1481 /// *From the specification*
1482 /// > The purpose of this command is to certify the contents of an
1483 /// > NV Index or portion of an NV Index.
1484 ///
1485 /// # Returns
1486 ///
1487 /// A tuple of `(Attest, Signature)`.
1488 ///
1489 /// # Example
1490 /// ```rust
1491 /// # use std::convert::TryFrom;
1492 /// # use tss_esapi::{
1493 /// # Context, TctiNameConf, attributes::NvIndexAttributes,
1494 /// # handles::NvIndexTpmHandle, constants::SessionType,
1495 /// # structures::{NvPublic, MaxNvBuffer, RsaExponent, RsaScheme},
1496 /// # utils::create_unrestricted_signing_rsa_public,
1497 /// # };
1498 /// use tss_esapi::{
1499 /// interface_types::{
1500 /// algorithm::{HashingAlgorithm, RsaSchemeAlgorithm},
1501 /// key_bits::RsaKeyBits,
1502 /// reserved_handles::{Hierarchy, NvAuth, Provision},
1503 /// session_handles::AuthSession,
1504 /// },
1505 /// structures::{Data, SignatureScheme},
1506 /// };
1507 ///
1508 /// # // Create context
1509 /// # let mut context =
1510 /// # Context::new(
1511 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
1512 /// # ).expect("Failed to create Context");
1513 /// #
1514 /// // Create a signing key.
1515 /// let signing_key_pub = create_unrestricted_signing_rsa_public(
1516 /// RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
1517 /// .expect("Failed to create RSA scheme"),
1518 /// RsaKeyBits::Rsa2048,
1519 /// RsaExponent::default(),
1520 /// )
1521 /// .expect("Failed to create signing rsa public structure");
1522 /// let sign_key_handle = context
1523 /// .execute_with_nullauth_session(|ctx| {
1524 /// ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
1525 /// })
1526 /// .expect("Call to create_primary failed")
1527 /// .key_handle;
1528 ///
1529 /// # let nv_index = NvIndexTpmHandle::new(0x01500050)
1530 /// # .expect("Failed to create NV index tpm handle");
1531 /// #
1532 /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
1533 /// # .with_owner_write(true)
1534 /// # .with_owner_read(true)
1535 /// # .build()
1536 /// # .expect("Failed to create owner nv index attributes");
1537 /// #
1538 /// # let owner_nv_public = NvPublic::builder()
1539 /// # .with_nv_index(nv_index)
1540 /// # .with_index_name_algorithm(HashingAlgorithm::Sha256)
1541 /// # .with_index_attributes(owner_nv_index_attributes)
1542 /// # .with_data_area_size(32)
1543 /// # .build()
1544 /// # .expect("Failed to build NvPublic for owner");
1545 /// #
1546 /// // Define an NV index and write some data to it.
1547 /// let nv_index_handle = context
1548 /// .execute_with_session(Some(AuthSession::Password), |ctx| {
1549 /// ctx.nv_define_space(Provision::Owner, None, owner_nv_public)
1550 /// })
1551 /// .expect("Call to nv_define_space failed");
1552 ///
1553 /// let data = MaxNvBuffer::try_from(vec![1, 2, 3, 4, 5, 6, 7, 8])
1554 /// .expect("Failed to create MaxNvBuffer from vec");
1555 /// context
1556 /// .execute_with_session(Some(AuthSession::Password), |ctx| {
1557 /// ctx.nv_write(NvAuth::Owner, nv_index_handle, data, 0)
1558 /// })
1559 /// .expect("Call to nv_write failed");
1560 ///
1561 /// // Certify the NV index contents.
1562 /// let nv_certify_result = context.execute_with_sessions(
1563 /// (
1564 /// Some(AuthSession::Password),
1565 /// Some(AuthSession::Password),
1566 /// None,
1567 /// ),
1568 /// |ctx| {
1569 /// ctx.nv_certify(
1570 /// sign_key_handle,
1571 /// NvAuth::Owner,
1572 /// nv_index_handle,
1573 /// Data::try_from(vec![0xff; 16]).unwrap(),
1574 /// SignatureScheme::Null,
1575 /// 8,
1576 /// 0,
1577 /// )
1578 /// },
1579 /// );
1580 ///
1581 /// // Clean up the NV index.
1582 /// context
1583 /// .execute_with_session(Some(AuthSession::Password), |ctx| {
1584 /// ctx.nv_undefine_space(Provision::Owner, nv_index_handle)
1585 /// })
1586 /// .expect("Call to nv_undefine_space failed");
1587 ///
1588 /// // Process result
1589 /// let (_attest, _signature) = nv_certify_result.expect("Call to nv_certify failed");
1590 /// ```
1591 #[allow(clippy::too_many_arguments)]
1592 pub fn nv_certify(
1593 &mut self,
1594 sign_handle: KeyHandle,
1595 auth_handle: NvAuth,
1596 nv_index_handle: NvIndexHandle,
1597 qualifying_data: Data,
1598 signing_scheme: SignatureScheme,
1599 size: u16,
1600 offset: u16,
1601 ) -> Result<(Attest, Signature)> {
1602 let mut certify_info_ptr = null_mut();
1603 let mut signature_ptr = null_mut();
1604 ReturnCode::ensure_success(
1605 unsafe {
1606 Esys_NV_Certify(
1607 self.mut_context(),
1608 sign_handle.into(),
1609 AuthHandle::from(auth_handle).into(),
1610 nv_index_handle.into(),
1611 self.required_session_1()?,
1612 self.required_session_2()?,
1613 self.optional_session_3(),
1614 &qualifying_data.into(),
1615 &signing_scheme.into(),
1616 size,
1617 offset,
1618 &mut certify_info_ptr,
1619 &mut signature_ptr,
1620 )
1621 },
1622 |ret| {
1623 error!("Error when certifying NV: {:#010X}", ret);
1624 },
1625 )?;
1626
1627 let certify_info = AttestBuffer::try_from(Context::ffi_data_to_owned(certify_info_ptr)?)?;
1628 let signature = Signature::try_from(Context::ffi_data_to_owned(signature_ptr)?)?;
1629 Ok((certify_info.try_into()?, signature))
1630 }
1631}