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::handle_manager::HandleDropAction,
5    handles::{AuthHandle, NvIndexHandle, ObjectHandle},
6    interface_types::reserved_handles::{NvAuth, Provision},
7    structures::{Auth, MaxNvBuffer, Name, NvPublic},
8    tss2_esys::{
9        Esys_NV_DefineSpace, Esys_NV_Extend, Esys_NV_Increment, Esys_NV_Read, Esys_NV_ReadPublic,
10        Esys_NV_UndefineSpace, Esys_NV_UndefineSpaceSpecial, Esys_NV_Write,
11    },
12    Context, Result, ReturnCode,
13};
14use log::error;
15use std::convert::{TryFrom, TryInto};
16use std::ptr::null_mut;
17
18impl Context {
19    /// Allocates an index in the non volatile storage.
20    ///
21    /// # Details
22    /// This method will instruct the TPM to reserve space for an NV index
23    /// with the attributes defined in the provided parameters.
24    ///
25    /// Please beware
26    /// that this method requires an authorization session handle to be present.
27    ///
28    /// # Arguments
29    /// * `nv_auth` - The [Provision] used for authorization.
30    /// * `auth` - The authorization value.
31    /// * `public_info` - The public parameters of the NV area.
32    ///
33    /// # Returns
34    /// A [NvIndexHandle] associated with the NV memory that
35    /// was defined.
36    ///
37    /// # Example
38    /// ```rust
39    /// # use tss_esapi::{
40    /// #     Context, TctiNameConf, attributes::SessionAttributes, constants::SessionType,
41    /// #     structures::SymmetricDefinition,
42    /// # };
43    /// use tss_esapi::{
44    ///      handles::NvIndexTpmHandle, attributes::NvIndexAttributes, structures::NvPublic,
45    ///      interface_types::{algorithm::HashingAlgorithm, reserved_handles::Provision},
46    /// };
47    /// # // Create context
48    /// # let mut context =
49    /// #     Context::new(
50    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
51    /// #     ).expect("Failed to create Context");
52    /// #
53    /// # let session = context
54    /// #     .start_auth_session(
55    /// #         None,
56    /// #         None,
57    /// #         None,
58    /// #         SessionType::Hmac,
59    /// #         SymmetricDefinition::AES_256_CFB,
60    /// #         HashingAlgorithm::Sha256,
61    /// #     )
62    /// #     .expect("Failed to create session")
63    /// #     .expect("Received invalid handle");
64    /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
65    /// #     .with_decrypt(true)
66    /// #     .with_encrypt(true)
67    /// #     .build();
68    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
69    /// #     .expect("Failed to set attributes on session");
70    /// # context.set_sessions((Some(session), None, None));
71    /// #
72    /// let nv_index = NvIndexTpmHandle::new(0x01500022)
73    ///     .expect("Failed to create NV index tpm handle");
74    ///
75    /// // Create NV index attributes
76    /// let owner_nv_index_attributes = NvIndexAttributes::builder()
77    ///     .with_owner_write(true)
78    ///     .with_owner_read(true)
79    ///     .build()
80    ///     .expect("Failed to create owner nv index attributes");
81    ///
82    /// // Create owner nv public.
83    /// let owner_nv_public = NvPublic::builder()
84    ///     .with_nv_index(nv_index)
85    ///     .with_index_name_algorithm(HashingAlgorithm::Sha256)
86    ///     .with_index_attributes(owner_nv_index_attributes)
87    ///     .with_data_area_size(32)
88    ///     .build()
89    ///     .expect("Failed to build NvPublic for owner");
90    ///
91    /// // Define the NV space.
92    /// let owner_nv_index_handle = context
93    ///     .nv_define_space(Provision::Owner, None, owner_nv_public)
94    ///     .expect("Call to nv_define_space failed");
95    ///
96    /// # context
97    /// #    .nv_undefine_space(Provision::Owner, owner_nv_index_handle)
98    /// #    .expect("Call to nv_undefine_space failed");
99    /// ```
100    pub fn nv_define_space(
101        &mut self,
102        nv_auth: Provision,
103        auth: Option<Auth>,
104        public_info: NvPublic,
105    ) -> Result<NvIndexHandle> {
106        let mut nv_handle = ObjectHandle::None.into();
107        ReturnCode::ensure_success(
108            unsafe {
109                Esys_NV_DefineSpace(
110                    self.mut_context(),
111                    AuthHandle::from(nv_auth).into(),
112                    self.required_session_1()?,
113                    self.optional_session_2(),
114                    self.optional_session_3(),
115                    &auth.unwrap_or_default().into(),
116                    &public_info.try_into()?,
117                    &mut nv_handle,
118                )
119            },
120            |ret| {
121                error!("Error when defining NV space: {:#010X}", ret);
122            },
123        )?;
124
125        self.handle_manager
126            .add_handle(nv_handle.into(), HandleDropAction::Close)?;
127        Ok(NvIndexHandle::from(nv_handle))
128    }
129
130    /// Deletes an index in the non volatile storage.
131    ///
132    /// # Details
133    /// The method will instruct the TPM to remove a
134    /// nv index.
135    ///
136    /// Please beware that this method requires an authorization
137    /// session handle to be present.
138    ///
139    /// # Arguments
140    /// * `nv_auth` - The [Provision] used for authorization.
141    /// * `nv_index_handle`- The [NvIndexHandle] associated with
142    ///   the nv area that is to be removed.
143    ///
144    /// # Example
145    /// ```rust
146    /// # use tss_esapi::{
147    /// #     Context, TctiNameConf, attributes::SessionAttributes, constants::SessionType,
148    /// #     structures::SymmetricDefinition,
149    /// #      handles::NvIndexTpmHandle, attributes::NvIndexAttributes, structures::NvPublic,
150    /// #      interface_types::algorithm::HashingAlgorithm,
151    /// # };
152    /// use tss_esapi::interface_types::reserved_handles::Provision;
153    /// # // Create context
154    /// # let mut context =
155    /// #     Context::new(
156    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
157    /// #     ).expect("Failed to create Context");
158    /// #
159    /// # let session = context
160    /// #     .start_auth_session(
161    /// #         None,
162    /// #         None,
163    /// #         None,
164    /// #         SessionType::Hmac,
165    /// #         SymmetricDefinition::AES_256_CFB,
166    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
167    /// #     )
168    /// #     .expect("Failed to create session")
169    /// #     .expect("Received invalid handle");
170    /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
171    /// #     .with_decrypt(true)
172    /// #     .with_encrypt(true)
173    /// #     .build();
174    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
175    /// #     .expect("Failed to set attributes on session");
176    /// # context.set_sessions((Some(session), None, None));
177    /// # let nv_index = NvIndexTpmHandle::new(0x01500023)
178    /// #     .expect("Failed to create NV index tpm handle");
179    /// #
180    /// # // Create NV index attributes
181    /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
182    /// #     .with_owner_write(true)
183    /// #     .with_owner_read(true)
184    /// #     .build()
185    /// #     .expect("Failed to create owner nv index attributes");
186    /// #
187    /// # // Create owner nv public.
188    /// # let owner_nv_public = NvPublic::builder()
189    /// #     .with_nv_index(nv_index)
190    /// #     .with_index_name_algorithm(HashingAlgorithm::Sha256)
191    /// #     .with_index_attributes(owner_nv_index_attributes)
192    /// #     .with_data_area_size(32)
193    /// #     .build()
194    /// #     .expect("Failed to build NvPublic for owner");
195    /// #
196    /// // Define the NV space.
197    /// let owner_nv_index_handle = context
198    ///     .nv_define_space(Provision::Owner, None, owner_nv_public)
199    ///     .expect("Call to nv_define_space failed");
200    ///
201    /// context
202    ///    .nv_undefine_space(Provision::Owner, owner_nv_index_handle)
203    ///    .expect("Call to nv_undefine_space failed");
204    /// ```
205    pub fn nv_undefine_space(
206        &mut self,
207        nv_auth: Provision,
208        nv_index_handle: NvIndexHandle,
209    ) -> Result<()> {
210        ReturnCode::ensure_success(
211            unsafe {
212                Esys_NV_UndefineSpace(
213                    self.mut_context(),
214                    AuthHandle::from(nv_auth).into(),
215                    nv_index_handle.into(),
216                    self.required_session_1()?,
217                    self.optional_session_2(),
218                    self.optional_session_3(),
219                )
220            },
221            |ret| {
222                error!("Error when undefining NV space: {:#010X}", ret);
223            },
224        )?;
225
226        self.handle_manager.set_as_closed(nv_index_handle.into())
227    }
228
229    /// Deletes an index in the non volatile storage.
230    ///
231    /// # Details
232    /// The method will instruct the TPM to remove a
233    /// nv index that was defined with TPMA_NV_POLICY_DELETE.
234    ///
235    /// Please beware that this method requires both a policy and
236    /// authorization session handle to be present.
237    ///
238    /// # Arguments
239    /// * `nv_auth` - The [Provision] used for authorization.
240    /// * `nv_index_handle`- The [NvIndexHandle] associated with
241    ///   the nv area that is to be removed.
242    ///
243    /// # Example
244    /// ```rust
245    /// # use tss_esapi::{
246    /// #     Context, TctiNameConf, attributes::SessionAttributes, constants::SessionType,
247    /// #     structures::SymmetricDefinition, constants::CommandCode,
248    /// #     handles::NvIndexTpmHandle, attributes::NvIndexAttributes, structures::NvPublic,
249    /// #     interface_types::algorithm::HashingAlgorithm, structures::Digest,
250    /// #     interface_types::session_handles::PolicySession,
251    /// # };
252    /// # use std::convert::TryFrom;
253    /// use tss_esapi::interface_types::reserved_handles::Provision;
254    /// use tss_esapi::interface_types::session_handles::AuthSession;
255    /// # // Create context
256    /// # let mut context =
257    /// #     Context::new(
258    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
259    /// #     ).expect("Failed to create Context");
260    /// #
261    /// # // Create a trial session to generate policy digest
262    /// # let session = context
263    /// #     .start_auth_session(
264    /// #         None,
265    /// #         None,
266    /// #         None,
267    /// #         SessionType::Trial,
268    /// #         SymmetricDefinition::AES_256_CFB,
269    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
270    /// #     )
271    /// #     .expect("Failed to create session")
272    /// #     .expect("Received invalid handle");
273    /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
274    /// #     .with_decrypt(true)
275    /// #     .with_encrypt(true)
276    /// #     .build();
277    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
278    /// #     .expect("Failed to set attributes on session");
279    /// #
280    /// # // Create a trial policy session that allows undefine with NvUndefineSpaceSpecial
281    /// # let policy_session = PolicySession::try_from(session).expect("Failed to get policy session");
282    /// # context.policy_command_code(policy_session, CommandCode::NvUndefineSpaceSpecial).expect("Failed to create trial policy");
283    /// # let digest = context.policy_get_digest(policy_session).expect("Failed to get policy digest");
284    /// #
285    /// # let nv_index = NvIndexTpmHandle::new(0x01500023)
286    /// #     .expect("Failed to create NV index tpm handle");
287    /// #
288    /// # // Create NV index attributes
289    /// # let nv_index_attributes = NvIndexAttributes::builder()
290    /// #     .with_pp_read(true)
291    /// #     .with_platform_create(true)
292    /// #     .with_policy_delete(true)
293    /// #     .with_policy_write(true)
294    /// #     .build()
295    /// #     .expect("Failed to create nv index attributes");
296    /// #
297    /// # // Create nv public.
298    /// # let nv_public = NvPublic::builder()
299    /// #     .with_nv_index(nv_index)
300    /// #     .with_index_name_algorithm(HashingAlgorithm::Sha256)
301    /// #     .with_index_attributes(nv_index_attributes)
302    /// #     .with_index_auth_policy(digest)
303    /// #     .with_data_area_size(32)
304    /// #     .build()
305    /// #     .expect("Failed to build NvPublic");
306    /// #
307    /// // Define the NV space.
308    /// let index_handle = context.execute_with_session(Some(AuthSession::Password), |context| {
309    ///         context
310    ///             .nv_define_space(Provision::Platform, None, nv_public)
311    ///             .expect("Call to nv_define_space failed")
312    ///     });
313    ///
314    /// # // Setup auth policy session
315    /// # let session = context
316    /// #     .start_auth_session(
317    /// #         None,
318    /// #         None,
319    /// #         None,
320    /// #         SessionType::Policy,
321    /// #         SymmetricDefinition::AES_256_CFB,
322    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
323    /// #     )
324    /// #     .expect("Failed to create policy session")
325    /// #     .expect("Received invalid handle");
326    /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
327    /// #     .with_decrypt(true)
328    /// #     .with_encrypt(true)
329    /// #     .build();
330    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
331    /// #     .expect("Failed to set attributes on session");
332    /// #
333    /// # // Define a policy command code that allows undefine with NvUndefineSpaceSpecial
334    /// # let policy_session = PolicySession::try_from(session).expect("Failed to get policy session");
335    /// # context.policy_command_code(policy_session, CommandCode::NvUndefineSpaceSpecial).expect("Failed to create policy");
336    /// #
337    /// // Undefine the NV space with a policy session and default auth session
338    /// context.execute_with_sessions((
339    ///         Some(session),
340    ///         Some(AuthSession::Password),
341    ///         None,
342    ///     ), |context| {
343    ///         context
344    ///             .nv_undefine_space_special(Provision::Platform, index_handle)
345    ///             .expect("Call to nv_undefine_space_special failed");
346    ///         }
347    ///     );
348    /// ```
349    pub fn nv_undefine_space_special(
350        &mut self,
351        nv_auth: Provision,
352        nv_index_handle: NvIndexHandle,
353    ) -> Result<()> {
354        ReturnCode::ensure_success(
355            unsafe {
356                Esys_NV_UndefineSpaceSpecial(
357                    self.mut_context(),
358                    nv_index_handle.into(),
359                    AuthHandle::from(nv_auth).into(),
360                    self.required_session_1()?,
361                    self.optional_session_2(),
362                    self.optional_session_3(),
363                )
364            },
365            |ret| {
366                error!("Error when undefining NV space: {:#010X}", ret);
367            },
368        )?;
369
370        self.handle_manager.set_as_closed(nv_index_handle.into())
371    }
372
373    /// Reads the public part of an nv index.
374    ///
375    /// # Details
376    /// This method is used to read the public
377    /// area and name of a nv index.
378    ///
379    /// # Arguments
380    /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
381    ///   for which the public part is to be read.
382    /// # Returns
383    /// A tuple containing the public area and the name of an nv index.
384    ///
385    /// # Example
386    /// ```rust
387    /// # use tss_esapi::{
388    /// #     Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
389    /// #     handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
390    /// #     structures::{SymmetricDefinition, NvPublic}, constants::SessionType,
391    /// # };
392    /// use tss_esapi::{
393    ///       interface_types::reserved_handles::Provision,
394    /// };
395    ///
396    /// # // Create context
397    /// # let mut context =
398    /// #     Context::new(
399    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
400    /// #     ).expect("Failed to create Context");
401    /// #
402    /// # let session = context
403    /// #     .start_auth_session(
404    /// #         None,
405    /// #         None,
406    /// #         None,
407    /// #         SessionType::Hmac,
408    /// #         SymmetricDefinition::AES_256_CFB,
409    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
410    /// #     )
411    /// #     .expect("Failed to create session")
412    /// #     .expect("Received invalid handle");
413    /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
414    /// #     .with_decrypt(true)
415    /// #     .with_encrypt(true)
416    /// #     .build();
417    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
418    /// #     .expect("Failed to set attributes on session");
419    /// # context.set_sessions((Some(session), None, None));
420    /// #
421    /// # let nv_index = NvIndexTpmHandle::new(0x01500024)
422    /// #     .expect("Failed to create NV index tpm handle");
423    /// #
424    /// # // Create NV index attributes
425    /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
426    /// #     .with_owner_write(true)
427    /// #     .with_owner_read(true)
428    /// #     .build()
429    /// #     .expect("Failed to create owner nv index attributes");
430    /// #
431    /// // Create owner nv public.
432    /// let owner_nv_public = NvPublic::builder()
433    ///     .with_nv_index(nv_index)
434    ///     .with_index_name_algorithm(HashingAlgorithm::Sha256)
435    ///     .with_index_attributes(owner_nv_index_attributes)
436    ///     .with_data_area_size(32)
437    ///     .build()
438    ///     .expect("Failed to build NvPublic for owner");
439    ///
440    /// let nv_index_handle = context
441    ///    .nv_define_space(Provision::Owner, None, owner_nv_public.clone())
442    ///    .expect("Call to nv_define_space failed");
443    ///
444    /// // Holds the result in order to ensure that the
445    /// // NV space gets undefined.
446    /// let nv_read_public_result = context.nv_read_public(nv_index_handle);
447    ///
448    /// context
449    ///     .nv_undefine_space(Provision::Owner, nv_index_handle)
450    ///     .expect("Call to nv_undefine_space failed");
451    ///
452    /// // Process result
453    /// let (read_nv_public, _name) = nv_read_public_result
454    ///     .expect("Call to nv_read_public failed");
455    ///
456    /// assert_eq!(owner_nv_public, read_nv_public);
457    /// ```
458    pub fn nv_read_public(&mut self, nv_index_handle: NvIndexHandle) -> Result<(NvPublic, Name)> {
459        let mut nv_public_ptr = null_mut();
460        let mut nv_name_ptr = null_mut();
461        ReturnCode::ensure_success(
462            unsafe {
463                Esys_NV_ReadPublic(
464                    self.mut_context(),
465                    nv_index_handle.into(),
466                    self.optional_session_1(),
467                    self.optional_session_2(),
468                    self.optional_session_3(),
469                    &mut nv_public_ptr,
470                    &mut nv_name_ptr,
471                )
472            },
473            |ret| {
474                error!("Error when reading NV public: {:#010X}", ret);
475            },
476        )?;
477
478        Ok((
479            NvPublic::try_from(Context::ffi_data_to_owned(nv_public_ptr)?)?,
480            Name::try_from(Context::ffi_data_to_owned(nv_name_ptr)?)?,
481        ))
482    }
483
484    /// Writes data to the NV memory associated with a nv index.
485    ///
486    /// # Details
487    /// This method is used to write a value to
488    /// the nv memory in the TPM.
489    ///
490    /// Please beware that this method requires an authorization
491    /// session handle to be present.
492    ///
493    /// # Arguments
494    /// * `auth_handle` - Handle indicating the source of authorization value.
495    /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
496    ///   where data is to be written.
497    /// * `data` - The data, in the form of a [MaxNvBuffer], that is to be written.
498    /// * `offset` - The octet offset into the NV area.
499    ///
500    /// # Example
501    /// ```rust
502    /// # use tss_esapi::{
503    /// #     Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
504    /// #     handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
505    /// #     structures::{SymmetricDefinition, NvPublic}, constants::SessionType,
506    /// # };
507    /// use tss_esapi::{
508    ///       interface_types::reserved_handles::{Provision, NvAuth}, structures::MaxNvBuffer,
509    /// };
510    /// use std::convert::TryFrom;
511    ///
512    /// # // Create context
513    /// # let mut context =
514    /// #     Context::new(
515    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
516    /// #     ).expect("Failed to create Context");
517    /// #
518    /// # let session = context
519    /// #     .start_auth_session(
520    /// #         None,
521    /// #         None,
522    /// #         None,
523    /// #         SessionType::Hmac,
524    /// #         SymmetricDefinition::AES_256_CFB,
525    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
526    /// #     )
527    /// #     .expect("Failed to create session")
528    /// #     .expect("Received invalid handle");
529    /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
530    /// #     .with_decrypt(true)
531    /// #     .with_encrypt(true)
532    /// #     .build();
533    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
534    /// #     .expect("Failed to set attributes on session");
535    /// # context.set_sessions((Some(session), None, None));
536    /// #
537    /// # let nv_index = NvIndexTpmHandle::new(0x01500025)
538    /// #     .expect("Failed to create NV index tpm handle");
539    /// #
540    /// # // Create NV index attributes
541    /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
542    /// #     .with_owner_write(true)
543    /// #     .with_owner_read(true)
544    /// #     .build()
545    /// #     .expect("Failed to create owner nv index attributes");
546    /// #
547    /// # // Create owner nv public.
548    /// # let owner_nv_public = NvPublic::builder()
549    /// #     .with_nv_index(nv_index)
550    /// #     .with_index_name_algorithm(HashingAlgorithm::Sha256)
551    /// #     .with_index_attributes(owner_nv_index_attributes)
552    /// #     .with_data_area_size(32)
553    /// #     .build()
554    /// #     .expect("Failed to build NvPublic for owner");
555    ///
556    /// let data = MaxNvBuffer::try_from(vec![1, 2, 3, 4, 5, 6, 7])
557    ///    .expect("Failed to create MaxNvBuffer from vec");
558    ///
559    /// let nv_index_handle = context
560    ///    .nv_define_space(Provision::Owner, None, owner_nv_public.clone())
561    ///    .expect("Call to nv_define_space failed");
562    ///
563    /// // Use owner authorization
564    /// let nv_write_result = context.nv_write(NvAuth::Owner, nv_index_handle, data, 0);
565    ///
566    /// context
567    ///     .nv_undefine_space(Provision::Owner, nv_index_handle)
568    ///     .expect("Call to nv_undefine_space failed");
569    ///
570    /// // Process result
571    /// nv_write_result.expect("Call to nv_write failed");
572    /// ```
573    pub fn nv_write(
574        &mut self,
575        auth_handle: NvAuth,
576        nv_index_handle: NvIndexHandle,
577        data: MaxNvBuffer,
578        offset: u16,
579    ) -> Result<()> {
580        ReturnCode::ensure_success(
581            unsafe {
582                Esys_NV_Write(
583                    self.mut_context(),
584                    AuthHandle::from(auth_handle).into(),
585                    nv_index_handle.into(),
586                    self.required_session_1()?,
587                    self.optional_session_2(),
588                    self.optional_session_3(),
589                    &data.into(),
590                    offset,
591                )
592            },
593            |ret| {
594                error!("Error when writing NV: {:#010X}", ret);
595            },
596        )
597    }
598
599    /// Increment monotonic counter index
600    ///
601    /// # Details
602    /// This method is used to increment monotonic counter
603    /// in the TPM.
604    ///
605    /// Please beware that this method requires an authorization
606    /// session handle to be present.
607    ///
608    /// # Arguments
609    /// * `auth_handle` - Handle indicating the source of authorization value.
610    /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
611    ///   where data is to be written.
612    /// ```rust
613    /// # use tss_esapi::{
614    /// #     Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
615    /// #     handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
616    /// #     structures::{SymmetricDefinition, NvPublic}, constants::SessionType,
617    /// #     constants::nv_index_type::NvIndexType,
618    /// # };
619    /// use tss_esapi::{
620    ///       interface_types::reserved_handles::{Provision, NvAuth}
621    /// };
622    ///
623    /// # // Create context
624    /// # let mut context =
625    /// #     Context::new(
626    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
627    /// #     ).expect("Failed to create Context");
628    /// #
629    /// # let session = context
630    /// #     .start_auth_session(
631    /// #         None,
632    /// #         None,
633    /// #         None,
634    /// #         SessionType::Hmac,
635    /// #         SymmetricDefinition::AES_256_CFB,
636    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
637    /// #     )
638    /// #     .expect("Failed to create session")
639    /// #     .expect("Received invalid handle");
640    /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
641    /// #     .with_decrypt(true)
642    /// #     .with_encrypt(true)
643    /// #     .build();
644    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
645    /// #     .expect("Failed to set attributes on session");
646    /// # context.set_sessions((Some(session), None, None));
647    /// #
648    /// # let nv_index = NvIndexTpmHandle::new(0x01500026)
649    /// #     .expect("Failed to create NV index tpm handle");
650    /// #
651    /// # // Create NV index attributes
652    /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
653    /// #     .with_owner_write(true)
654    /// #     .with_owner_read(true)
655    /// #     .with_nv_index_type(NvIndexType::Counter)
656    /// #     .build()
657    /// #     .expect("Failed to create owner nv index attributes");
658    /// #
659    /// # // Create owner nv public.
660    /// # let owner_nv_public = NvPublic::builder()
661    /// #     .with_nv_index(nv_index)
662    /// #     .with_index_name_algorithm(HashingAlgorithm::Sha256)
663    /// #     .with_index_attributes(owner_nv_index_attributes)
664    /// #     .with_data_area_size(8)
665    /// #     .build()
666    /// #     .expect("Failed to build NvPublic for owner");
667    /// #
668    /// let nv_index_handle = context
669    ///     .nv_define_space(Provision::Owner, None, owner_nv_public.clone())
670    ///     .expect("Call to nv_define_space failed");
671    ///
672    /// let nv_increment_result = context.nv_increment(NvAuth::Owner, nv_index_handle);
673    ///
674    /// context
675    ///     .nv_undefine_space(Provision::Owner, nv_index_handle)
676    ///     .expect("Call to nv_undefine_space failed");
677    ///
678    /// // Process result
679    /// nv_increment_result.expect("Call to nv_increment failed");
680    /// ```
681    pub fn nv_increment(
682        &mut self,
683        auth_handle: NvAuth,
684        nv_index_handle: NvIndexHandle,
685    ) -> Result<()> {
686        ReturnCode::ensure_success(
687            unsafe {
688                Esys_NV_Increment(
689                    self.mut_context(),
690                    AuthHandle::from(auth_handle).into(),
691                    nv_index_handle.into(),
692                    self.required_session_1()?,
693                    self.optional_session_2(),
694                    self.optional_session_3(),
695                )
696            },
697            |ret| error!("Error when incrementing NV: {:#010X}", ret),
698        )
699    }
700
701    /// Extends data to the NV memory associated with a nv index.
702    ///
703    /// # Details
704    /// This method is used to extend a value to the nv memory in the TPM.
705    ///
706    /// Please beware that this method requires an authorization session handle to be present.
707    ///
708    /// Any NV index (that is not already used) can be defined as an extend type. However various specifications define
709    /// indexes that have specific purposes or are reserved, for example the TCG PC Client Platform Firmware Profile
710    /// Specification Section 3.3.6 defines indexes within the 0x01c40200-0x01c402ff range for instance measurements.
711    /// Section 2.2 of TCG Registry of Reserved TPM 2.0 Handles and Localities provides additional context for specific
712    /// NV index ranges.
713    ///
714    /// # Arguments
715    /// * `auth_handle` - Handle indicating the source of authorization value.
716    /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
717    ///   which will be extended by data hashed with the previous data.
718    /// * `data` - The data, in the form of a [MaxNvBuffer], that is to be written.
719    ///
720    /// # Example
721    /// ```rust
722    /// # use tss_esapi::{
723    /// #     Context, TctiNameConf, attributes::{SessionAttributes, NvIndexAttributes},
724    /// #     handles::NvIndexTpmHandle, interface_types::algorithm::HashingAlgorithm,
725    /// #     structures::{SymmetricDefinition, NvPublic},
726    /// #     constants::SessionType, constants::nv_index_type::NvIndexType,
727    /// # };
728    /// use tss_esapi::{
729    ///       interface_types::reserved_handles::{Provision, NvAuth}, structures::MaxNvBuffer,
730    /// };
731    ///
732    /// # // Create context
733    /// # let mut context =
734    /// #     Context::new(
735    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
736    /// #     ).expect("Failed to create Context");
737    /// #
738    /// # let session = context
739    /// #     .start_auth_session(
740    /// #         None,
741    /// #         None,
742    /// #         None,
743    /// #         SessionType::Hmac,
744    /// #         SymmetricDefinition::AES_256_CFB,
745    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
746    /// #     )
747    /// #     .expect("Failed to create session")
748    /// #     .expect("Received invalid handle");
749    /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
750    /// #     .with_decrypt(true)
751    /// #     .with_encrypt(true)
752    /// #     .build();
753    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
754    /// #     .expect("Failed to set attributes on session");
755    /// # context.set_sessions((Some(session), None, None));
756    /// #
757    /// # let nv_index = NvIndexTpmHandle::new(0x01500028)
758    /// #     .expect("Failed to create NV index tpm handle");
759    /// #
760    /// // Create NV index attributes
761    /// let owner_nv_index_attributes = NvIndexAttributes::builder()
762    ///     .with_owner_write(true)
763    ///     .with_owner_read(true)
764    ///     .with_orderly(true)
765    ///     .with_nv_index_type(NvIndexType::Extend)
766    ///     .build()
767    ///     .expect("Failed to create owner nv index attributes");
768    ///
769    /// // Create owner nv public.
770    /// let owner_nv_public = NvPublic::builder()
771    ///     .with_nv_index(nv_index)
772    ///     .with_index_name_algorithm(HashingAlgorithm::Sha256)
773    ///     .with_index_attributes(owner_nv_index_attributes)
774    ///     .with_data_area_size(32)
775    ///     .build()
776    ///     .expect("Failed to build NvPublic for owner");
777    ///
778    /// let nv_index_handle = context
779    ///     .nv_define_space(Provision::Owner, None, owner_nv_public.clone())
780    ///     .expect("Call to nv_define_space failed");
781    ///
782    /// let data = MaxNvBuffer::try_from(vec![0x0]).unwrap();
783    /// let result = context.nv_extend(NvAuth::Owner, nv_index_handle, data);
784    ///
785    /// # context
786    /// #    .nv_undefine_space(Provision::Owner, nv_index_handle)
787    /// #    .expect("Call to nv_undefine_space failed");
788    /// ```
789    pub fn nv_extend(
790        &mut self,
791        auth_handle: NvAuth,
792        nv_index_handle: NvIndexHandle,
793        data: MaxNvBuffer,
794    ) -> Result<()> {
795        ReturnCode::ensure_success(
796            unsafe {
797                Esys_NV_Extend(
798                    self.mut_context(),
799                    AuthHandle::from(auth_handle).into(),
800                    nv_index_handle.into(),
801                    self.required_session_1()?,
802                    self.optional_session_2(),
803                    self.optional_session_3(),
804                    &data.into(),
805                )
806            },
807            |ret| error!("Error when extending NV: {:#010X}", ret),
808        )
809    }
810
811    // Missing function: NV_SetBits
812    // Missing function: NV_WriteLock
813    // Missing function: NV_GlobalWriteLock
814
815    /// Reads data from the nv index.
816    ///
817    /// # Details
818    /// This method is used to read a value from an area in
819    /// NV memory of the TPM.
820    ///
821    /// Please beware that this method requires an authorization
822    /// session handle to be present.
823    ///
824    /// # Arguments
825    /// * `auth_handle` - Handle indicating the source of authorization value.
826    /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
827    ///   where data is to be written.
828    /// * `size` -  The number of octets to read.
829    /// * `offset`- Octet offset into the NV area.
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    /// # };
838    /// use tss_esapi::{
839    ///       interface_types::reserved_handles::{Provision, NvAuth}, structures::MaxNvBuffer,
840    /// };
841    /// use std::convert::TryFrom;
842    ///
843    /// # // Create context
844    /// # let mut context =
845    /// #     Context::new(
846    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
847    /// #     ).expect("Failed to create Context");
848    /// #
849    /// # let session = context
850    /// #     .start_auth_session(
851    /// #         None,
852    /// #         None,
853    /// #         None,
854    /// #         SessionType::Hmac,
855    /// #         SymmetricDefinition::AES_256_CFB,
856    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
857    /// #     )
858    /// #     .expect("Failed to create session")
859    /// #     .expect("Received invalid handle");
860    /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
861    /// #     .with_decrypt(true)
862    /// #     .with_encrypt(true)
863    /// #     .build();
864    /// # context.tr_sess_set_attributes(session, session_attributes, session_attributes_mask)
865    /// #     .expect("Failed to set attributes on session");
866    /// # context.set_sessions((Some(session), None, None));
867    /// #
868    /// # let nv_index = NvIndexTpmHandle::new(0x01500027)
869    /// #     .expect("Failed to create NV index tpm handle");
870    /// #
871    /// # // Create NV index attributes
872    /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
873    /// #     .with_owner_write(true)
874    /// #     .with_owner_read(true)
875    /// #     .build()
876    /// #     .expect("Failed to create owner nv index attributes");
877    /// #
878    /// # // Create owner nv public.
879    /// # let owner_nv_public = NvPublic::builder()
880    /// #     .with_nv_index(nv_index)
881    /// #     .with_index_name_algorithm(HashingAlgorithm::Sha256)
882    /// #     .with_index_attributes(owner_nv_index_attributes)
883    /// #     .with_data_area_size(32)
884    /// #     .build()
885    /// #     .expect("Failed to build NvPublic for owner");
886    /// #
887    /// let data = MaxNvBuffer::try_from(vec![1, 2, 3, 4, 5, 6, 7])
888    ///    .expect("Failed to create MaxNvBuffer from vec");
889    ///
890    /// let nv_index_handle = context
891    ///    .nv_define_space(Provision::Owner, None, owner_nv_public)
892    ///    .expect("Call to nv_define_space failed");
893    ///
894    /// // Write data using owner authorization
895    /// let nv_write_result = context.nv_write(NvAuth::Owner, nv_index_handle, data.clone(), 0);
896    ///
897    /// // Read data using owner authorization
898    /// let data_len = u16::try_from(data.len()).expect("Failed to retrieve length of data");
899    /// let nv_read_result = context
900    ///     .nv_read(NvAuth::Owner, nv_index_handle, data_len, 0);
901    ///
902    /// context
903    ///     .nv_undefine_space(Provision::Owner, nv_index_handle)
904    ///     .expect("Call to nv_undefine_space failed");
905    ///
906    /// // Process result
907    /// nv_write_result.expect("Call to nv_write failed");
908    /// let read_data = nv_read_result.expect("Call to nv_read failed");
909    /// assert_eq!(data, read_data);
910    /// ```
911    pub fn nv_read(
912        &mut self,
913        auth_handle: NvAuth,
914        nv_index_handle: NvIndexHandle,
915        size: u16,
916        offset: u16,
917    ) -> Result<MaxNvBuffer> {
918        let mut data_ptr = null_mut();
919        ReturnCode::ensure_success(
920            unsafe {
921                Esys_NV_Read(
922                    self.mut_context(),
923                    AuthHandle::from(auth_handle).into(),
924                    nv_index_handle.into(),
925                    self.required_session_1()?,
926                    self.optional_session_2(),
927                    self.optional_session_3(),
928                    size,
929                    offset,
930                    &mut data_ptr,
931                )
932            },
933            |ret| {
934                error!("Error when reading NV: {:#010X}", ret);
935            },
936        )?;
937        MaxNvBuffer::try_from(Context::ffi_data_to_owned(data_ptr)?)
938    }
939
940    // Missing function: NV_ReadLock
941    // Missing function: NV_ChangeAuth
942    // Missing function: NV_Certify
943}