Skip to main content

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}