Skip to main content

tss_esapi/context/tpm_commands/
enhanced_authorization_ea_commands.rs

1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use crate::{
4    attributes::LocalityAttributes,
5    constants::CommandCode,
6    handles::{AuthHandle, NvIndexHandle, ObjectHandle, SessionHandle},
7    interface_types::{reserved_handles::NvAuth, session_handles::PolicySession, YesNo},
8    structures::{
9        AuthTicket, Digest, DigestList, Name, Nonce, PcrSelectionList, Signature, Timeout,
10        VerifiedTicket,
11    },
12    tss2_esys::{
13        Esys_PolicyAuthValue, Esys_PolicyAuthorize, Esys_PolicyAuthorizeNV, Esys_PolicyCommandCode,
14        Esys_PolicyCpHash, Esys_PolicyDuplicationSelect, Esys_PolicyGetDigest, Esys_PolicyLocality,
15        Esys_PolicyNameHash, Esys_PolicyNvWritten, Esys_PolicyOR, Esys_PolicyPCR,
16        Esys_PolicyPassword, Esys_PolicyPhysicalPresence, Esys_PolicySecret, Esys_PolicySigned,
17        Esys_PolicyTemplate,
18    },
19    Context, Error, Result, ReturnCode, WrapperErrorKind as ErrorKind,
20};
21use log::error;
22use std::convert::{TryFrom, TryInto};
23use std::ptr::null_mut;
24use std::time::Duration;
25
26impl Context {
27    /// Cause the policy to include a signed authorization
28    #[allow(clippy::too_many_arguments)]
29    pub fn policy_signed(
30        &mut self,
31        policy_session: PolicySession,
32        auth_object: ObjectHandle,
33        nonce_tpm: Nonce,
34        cp_hash_a: Digest,
35        policy_ref: Nonce,
36        expiration: Option<Duration>,
37        signature: Signature,
38    ) -> Result<(Timeout, AuthTicket)> {
39        let mut out_timeout_ptr = null_mut();
40        let mut out_policy_ticket_ptr = null_mut();
41        ReturnCode::ensure_success(
42            unsafe {
43                Esys_PolicySigned(
44                    self.mut_context(),
45                    auth_object.into(),
46                    SessionHandle::from(policy_session).into(),
47                    self.required_session_1()?,
48                    self.optional_session_2(),
49                    self.optional_session_3(),
50                    &nonce_tpm.into(),
51                    &cp_hash_a.into(),
52                    &policy_ref.into(),
53                    i32::try_from(expiration.map_or(0, |v| v.as_secs())).map_err(|e| {
54                        error!("Unable to convert duration to i32: {}", e);
55                        Error::local_error(ErrorKind::InvalidParam)
56                    })?,
57                    &signature.try_into()?,
58                    &mut out_timeout_ptr,
59                    &mut out_policy_ticket_ptr,
60                )
61            },
62            |ret| {
63                error!("Error when sending policy signed: {:#010X}", ret);
64            },
65        )?;
66        Ok((
67            Timeout::try_from(Context::ffi_data_to_owned(out_timeout_ptr)?)?,
68            AuthTicket::try_from(Context::ffi_data_to_owned(out_policy_ticket_ptr)?)?,
69        ))
70    }
71
72    /// Cause the policy to require a secret in authValue
73    pub fn policy_secret(
74        &mut self,
75        policy_session: PolicySession,
76        auth_handle: AuthHandle,
77        nonce_tpm: Nonce,
78        cp_hash_a: Digest,
79        policy_ref: Nonce,
80        expiration: Option<Duration>,
81    ) -> Result<(Timeout, AuthTicket)> {
82        let mut out_timeout_ptr = null_mut();
83        let mut out_policy_ticket_ptr = null_mut();
84        ReturnCode::ensure_success(
85            unsafe {
86                Esys_PolicySecret(
87                    self.mut_context(),
88                    auth_handle.into(),
89                    SessionHandle::from(policy_session).into(),
90                    self.required_session_1()?,
91                    self.optional_session_2(),
92                    self.optional_session_3(),
93                    &nonce_tpm.into(),
94                    &cp_hash_a.into(),
95                    &policy_ref.into(),
96                    i32::try_from(expiration.map_or(0, |v| v.as_secs())).map_err(|e| {
97                        error!("Unable to convert duration to i32: {}", e);
98                        Error::local_error(ErrorKind::InvalidParam)
99                    })?,
100                    &mut out_timeout_ptr,
101                    &mut out_policy_ticket_ptr,
102                )
103            },
104            |ret| {
105                error!("Error when sending policy secret: {:#010X}", ret);
106            },
107        )?;
108        Ok((
109            Timeout::try_from(Context::ffi_data_to_owned(out_timeout_ptr)?)?,
110            AuthTicket::try_from(Context::ffi_data_to_owned(out_policy_ticket_ptr)?)?,
111        ))
112    }
113
114    // Missing function: PolicyTicket
115
116    /// Cause conditional gating of a policy based on an OR'd condition.
117    ///
118    /// The TPM will ensure that the current policy digest equals at least
119    /// one of the digests.
120    /// If this is the case, the policyDigest of the policy session is replaced
121    /// by the value of the different hashes.
122    ///
123    /// # Constraints
124    /// * `digest_list` must be at least 2 and at most 8 elements long
125    ///
126    /// # Errors
127    /// * if the hash list provided is too short or too long, a `WrongParamSize` wrapper error will be returned
128    pub fn policy_or(
129        &mut self,
130        policy_session: PolicySession,
131        digest_list: DigestList,
132    ) -> Result<()> {
133        if digest_list.len() < 2 {
134            error!(
135                "The digest list only contains {} digests, it must contain at least 2",
136                digest_list.len()
137            );
138            return Err(Error::local_error(ErrorKind::WrongParamSize));
139        }
140
141        ReturnCode::ensure_success(
142            unsafe {
143                Esys_PolicyOR(
144                    self.mut_context(),
145                    SessionHandle::from(policy_session).into(),
146                    self.optional_session_1(),
147                    self.optional_session_2(),
148                    self.optional_session_3(),
149                    &digest_list.try_into()?,
150                )
151            },
152            |ret| {
153                error!("Error when computing policy OR: {:#010X}", ret);
154            },
155        )
156    }
157
158    /// Cause conditional gating of a policy based on PCR.
159    ///
160    /// # Details
161    /// The TPM will use the hash algorithm of the policy_session
162    /// to calculate a digest from the values of the pcr slots
163    /// specified in the pcr_selections.
164    /// This is then compared to pcr_policy_digest if they match then
165    /// the policyDigest of the policy session is extended.
166    ///
167    /// # Errors
168    /// * if the pcr policy digest provided is too long, a `WrongParamSize` wrapper error will be returned
169    pub fn policy_pcr(
170        &mut self,
171        policy_session: PolicySession,
172        pcr_policy_digest: Digest,
173        pcr_selection_list: PcrSelectionList,
174    ) -> Result<()> {
175        ReturnCode::ensure_success(
176            unsafe {
177                Esys_PolicyPCR(
178                    self.mut_context(),
179                    SessionHandle::from(policy_session).into(),
180                    self.optional_session_1(),
181                    self.optional_session_2(),
182                    self.optional_session_3(),
183                    &pcr_policy_digest.into(),
184                    &pcr_selection_list.into(),
185                )
186            },
187            |ret| {
188                error!("Error when computing policy PCR: {:#010X}", ret);
189            },
190        )
191    }
192
193    /// Cause conditional gating of a policy based on locality.
194    ///
195    /// The TPM will ensure that the current policy can only complete in the specified
196    /// locality (extended) or any of the specified localities (non-extended).
197    pub fn policy_locality(
198        &mut self,
199        policy_session: PolicySession,
200        locality: LocalityAttributes,
201    ) -> Result<()> {
202        ReturnCode::ensure_success(
203            unsafe {
204                Esys_PolicyLocality(
205                    self.mut_context(),
206                    SessionHandle::from(policy_session).into(),
207                    self.optional_session_1(),
208                    self.optional_session_2(),
209                    self.optional_session_3(),
210                    locality.into(),
211                )
212            },
213            |ret| {
214                error!("Error when computing policy locality: {:#010X}", ret);
215            },
216        )
217    }
218
219    // Missing function: PolicyNV
220    // Missing function: PolicyCounterTimer
221
222    /// Cause conditional gating of a policy based on command code of authorized command.
223    ///
224    /// The TPM will ensure that the current policy can only be used to complete the command
225    /// indicated by code.
226    pub fn policy_command_code(
227        &mut self,
228        policy_session: PolicySession,
229        code: CommandCode,
230    ) -> Result<()> {
231        ReturnCode::ensure_success(
232            unsafe {
233                Esys_PolicyCommandCode(
234                    self.mut_context(),
235                    SessionHandle::from(policy_session).into(),
236                    self.optional_session_1(),
237                    self.optional_session_2(),
238                    self.optional_session_3(),
239                    code.into(),
240                )
241            },
242            |ret| {
243                error!("Error when computing policy command code: {:#010X}", ret);
244            },
245        )
246    }
247
248    /// Cause conditional gating of a policy based on physical presence.
249    ///
250    /// The TPM will ensure that the current policy can only complete when physical
251    /// presence is asserted. The way this is done is implementation-specific.
252    pub fn policy_physical_presence(&mut self, policy_session: PolicySession) -> Result<()> {
253        ReturnCode::ensure_success(
254            unsafe {
255                Esys_PolicyPhysicalPresence(
256                    self.mut_context(),
257                    SessionHandle::from(policy_session).into(),
258                    self.optional_session_1(),
259                    self.optional_session_2(),
260                    self.optional_session_3(),
261                )
262            },
263            |ret| {
264                error!(
265                    "Error when computing policy physical presence: {:#010X}",
266                    ret
267                );
268            },
269        )
270    }
271
272    /// Cause conditional gating of a policy based on command parameters.
273    ///
274    /// The TPM will ensure that the current policy can only be used to authorize
275    /// a command where the parameters are hashed into cp_hash_a.
276    pub fn policy_cp_hash(
277        &mut self,
278        policy_session: PolicySession,
279        cp_hash_a: Digest,
280    ) -> Result<()> {
281        ReturnCode::ensure_success(
282            unsafe {
283                Esys_PolicyCpHash(
284                    self.mut_context(),
285                    SessionHandle::from(policy_session).into(),
286                    self.optional_session_1(),
287                    self.optional_session_2(),
288                    self.optional_session_3(),
289                    &cp_hash_a.into(),
290                )
291            },
292            |ret| {
293                error!(
294                    "Error when computing policy command parameters: {:#010X}",
295                    ret
296                );
297            },
298        )
299    }
300
301    /// Cause conditional gating of a policy based on name hash.
302    ///
303    /// The TPM will ensure that the current policy can only be used to authorize
304    /// a command acting on an object whose name hashes to name_hash.
305    pub fn policy_name_hash(
306        &mut self,
307        policy_session: PolicySession,
308        name_hash: Digest,
309    ) -> Result<()> {
310        ReturnCode::ensure_success(
311            unsafe {
312                Esys_PolicyNameHash(
313                    self.mut_context(),
314                    SessionHandle::from(policy_session).into(),
315                    self.optional_session_1(),
316                    self.optional_session_2(),
317                    self.optional_session_3(),
318                    &name_hash.into(),
319                )
320            },
321            |ret| {
322                error!("Error when computing policy name hash: {:#010X}", ret);
323            },
324        )
325    }
326
327    /// Cause conditional gating of a policy based on duplication parent's name.
328    ///
329    /// # Arguments
330    /// * `policy_session` - The [policy session][PolicySession] being extended.
331    /// * `object_name` - The [name][Name] of the object being duplicated.
332    /// * `new_parent_name` - The [name][Name] of the new parent.
333    /// * `include_object` - Flag indicating if `object_name` will be included in policy
334    ///   calculation.
335    ///
336    /// # Details
337    /// Set `include_object` only when this command is used in conjunction with
338    /// [`policy_authorize`][Context::policy_authorize].
339    ///
340    /// # Example
341    ///
342    /// ```rust
343    /// # use std::convert::{TryFrom, TryInto};
344    /// # use tss_esapi::attributes::{ObjectAttributesBuilder, SessionAttributesBuilder};
345    /// # use tss_esapi::constants::{CommandCode, SessionType};
346    /// # use tss_esapi::handles::ObjectHandle;
347    /// # use tss_esapi::interface_types::{
348    /// #     algorithm::{HashingAlgorithm, PublicAlgorithm},
349    /// #     key_bits::RsaKeyBits,
350    /// #     reserved_handles::Hierarchy,
351    /// #     session_handles::PolicySession,
352    /// # };
353    /// # use tss_esapi::structures::SymmetricDefinition;
354    /// # use tss_esapi::structures::{
355    /// #     PublicBuilder, PublicKeyRsa, PublicRsaParametersBuilder, RsaScheme,
356    /// #     RsaExponent, Name,
357    /// # };
358    /// # use tss_esapi::structures::SymmetricDefinitionObject;
359    /// # use tss_esapi::abstraction::cipher::Cipher;
360    /// # use tss_esapi::{Context, TctiNameConf};
361    /// #
362    /// # let mut context = // ...
363    /// #     Context::new(
364    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
365    /// #     ).expect("Failed to create Context");
366    /// #
367    /// # let trial_session = context
368    /// #     .start_auth_session(
369    /// #         None,
370    /// #         None,
371    /// #         None,
372    /// #         SessionType::Trial,
373    /// #         SymmetricDefinition::AES_256_CFB,
374    /// #         HashingAlgorithm::Sha256,
375    /// #     )
376    /// #     .expect("Start auth session failed")
377    /// #     .expect("Start auth session returned a NONE handle");
378    /// #
379    /// # let (policy_auth_session_attributes, policy_auth_session_attributes_mask) =
380    /// #     SessionAttributesBuilder::new()
381    /// #         .with_decrypt(true)
382    /// #         .with_encrypt(true)
383    /// #         .build();
384    /// # context
385    /// #     .tr_sess_set_attributes(
386    /// #         trial_session,
387    /// #         policy_auth_session_attributes,
388    /// #         policy_auth_session_attributes_mask,
389    /// #     )
390    /// #     .expect("tr_sess_set_attributes call failed");
391    /// #
392    /// # let policy_session = PolicySession::try_from(trial_session)
393    /// #     .expect("Failed to convert auth session into policy session");
394    /// #
395    /// # let object_name: Name = Vec::<u8>::new().try_into().unwrap();
396    /// # let parent_name = object_name.clone();
397    /// #
398    /// context
399    ///     .policy_duplication_select(policy_session, object_name, parent_name, false)
400    ///     .expect("Policy command code");
401    /// #
402    /// # /// Digest of the policy that allows duplication
403    /// # let digest = context
404    /// #     .policy_get_digest(policy_session)
405    /// #     .expect("Could retrieve digest");
406    /// ```
407    pub fn policy_duplication_select(
408        &mut self,
409        policy_session: PolicySession,
410        object_name: Name,
411        new_parent_name: Name,
412        include_object: bool,
413    ) -> Result<()> {
414        ReturnCode::ensure_success(
415            unsafe {
416                Esys_PolicyDuplicationSelect(
417                    self.mut_context(),
418                    SessionHandle::from(policy_session).into(),
419                    self.optional_session_1(),
420                    self.optional_session_2(),
421                    self.optional_session_3(),
422                    &object_name.into(),
423                    &new_parent_name.into(),
424                    YesNo::from(include_object).into(),
425                )
426            },
427            |ret| {
428                error!(
429                    "Error when computing policy duplication select: {:#010X}",
430                    ret
431                );
432            },
433        )
434    }
435
436    /// Cause conditional gating of a policy based on an authorized policy
437    ///
438    /// The TPM will ensure that the current policy digest is correctly signed
439    /// by the ticket in check_ticket and that check_ticket is signed by the key
440    /// named in key_sign.
441    /// If this is the case, the policyDigest of the policy session is replaced
442    /// by the value of the key_sign and policy_ref values.
443    pub fn policy_authorize(
444        &mut self,
445        policy_session: PolicySession,
446        approved_policy: Digest,
447        policy_ref: Nonce,
448        key_sign: &Name,
449        check_ticket: VerifiedTicket,
450    ) -> Result<()> {
451        ReturnCode::ensure_success(
452            unsafe {
453                Esys_PolicyAuthorize(
454                    self.mut_context(),
455                    SessionHandle::from(policy_session).into(),
456                    self.optional_session_1(),
457                    self.optional_session_2(),
458                    self.optional_session_3(),
459                    &approved_policy.into(),
460                    &policy_ref.into(),
461                    key_sign.as_ref(),
462                    &check_ticket.try_into()?,
463                )
464            },
465            |ret| {
466                error!("Error when computing policy authorize: {:#010X}", ret);
467            },
468        )
469    }
470
471    /// Cause conditional gating of a policy based on authValue.
472    ///
473    /// The TPM will ensure that the current policy requires the user to know the authValue
474    /// used when creating the object.
475    pub fn policy_auth_value(&mut self, policy_session: PolicySession) -> Result<()> {
476        ReturnCode::ensure_success(
477            unsafe {
478                Esys_PolicyAuthValue(
479                    self.mut_context(),
480                    SessionHandle::from(policy_session).into(),
481                    self.optional_session_1(),
482                    self.optional_session_2(),
483                    self.optional_session_3(),
484                )
485            },
486            |ret| {
487                error!("Error when computing policy auth value: {:#010X}", ret);
488            },
489        )
490    }
491
492    /// Cause conditional gating of a policy based on password.
493    ///
494    /// The TPM will ensure that the current policy requires the user to know the password
495    /// used when creating the object.
496    pub fn policy_password(&mut self, policy_session: PolicySession) -> Result<()> {
497        ReturnCode::ensure_success(
498            unsafe {
499                Esys_PolicyPassword(
500                    self.mut_context(),
501                    SessionHandle::from(policy_session).into(),
502                    self.optional_session_1(),
503                    self.optional_session_2(),
504                    self.optional_session_3(),
505                )
506            },
507            |ret| {
508                error!("Error when computing policy password: {:#010X}", ret);
509            },
510        )
511    }
512
513    /// Function for retrieving the current policy digest for
514    /// the session.
515    pub fn policy_get_digest(&mut self, policy_session: PolicySession) -> Result<Digest> {
516        let mut policy_digest_ptr = null_mut();
517        ReturnCode::ensure_success(
518            unsafe {
519                Esys_PolicyGetDigest(
520                    self.mut_context(),
521                    SessionHandle::from(policy_session).into(),
522                    self.optional_session_1(),
523                    self.optional_session_2(),
524                    self.optional_session_3(),
525                    &mut policy_digest_ptr,
526                )
527            },
528            |ret| {
529                error!(
530                    "Error failed to perform policy get digest operation: {:#010X}.",
531                    ret
532                );
533            },
534        )?;
535
536        Digest::try_from(Context::ffi_data_to_owned(policy_digest_ptr)?)
537    }
538
539    /// Cause conditional gating of a policy based on NV written state.
540    ///
541    /// The TPM will ensure that the NV index that is used has a specific written state.
542    pub fn policy_nv_written(
543        &mut self,
544        policy_session: PolicySession,
545        written_set: bool,
546    ) -> Result<()> {
547        ReturnCode::ensure_success(
548            unsafe {
549                Esys_PolicyNvWritten(
550                    self.mut_context(),
551                    SessionHandle::from(policy_session).into(),
552                    self.optional_session_1(),
553                    self.optional_session_2(),
554                    self.optional_session_3(),
555                    written_set.into(),
556                )
557            },
558            |ret| {
559                error!(
560                    "Error when computing policy NV written state: {:#010X}",
561                    ret
562                );
563            },
564        )
565    }
566
567    /// Bind policy to a specific creation template.
568    ///
569    /// # Arguments
570    /// * `policy_session` - The [policy session][PolicySession] being extended.
571    /// * `template_hash` - The [digest][Digest] to be added to the policy.
572    pub fn policy_template(
573        &mut self,
574        policy_session: PolicySession,
575        template_hash: Digest,
576    ) -> Result<()> {
577        ReturnCode::ensure_success(
578            unsafe {
579                Esys_PolicyTemplate(
580                    self.mut_context(),
581                    SessionHandle::from(policy_session).into(),
582                    self.optional_session_1(),
583                    self.optional_session_2(),
584                    self.optional_session_3(),
585                    &template_hash.into(),
586                )
587            },
588            |ret| {
589                error!(
590                    "Failed to bind template to a specific creation template: {:#010X}",
591                    ret
592                );
593            },
594        )
595    }
596
597    /// Cause conditional gating of a policy based on an authorized policy
598    /// stored in non-volatile memory.
599    ///
600    /// # Arguments
601    /// * `policy_session` - The [policy session][PolicySession] being extended.
602    /// * `auth_handle` - Handle indicating the source of authorization value.
603    /// * `nv_index_handle` - The [NvIndexHandle] associated with NV memory
604    ///   where the policy is stored.
605    ///
606    /// # Example
607    /// ```rust
608    /// # use std::convert::TryFrom;
609    /// # use tss_esapi::attributes::{NvIndexAttributes, SessionAttributes};
610    /// # use tss_esapi::constants::SessionType;
611    /// # use tss_esapi::handles::NvIndexTpmHandle;
612    /// # use tss_esapi::interface_types::{
613    /// #     algorithm::HashingAlgorithm,
614    /// #     reserved_handles::{NvAuth, Provision},
615    /// #     session_handles::PolicySession,
616    /// # };
617    /// # use tss_esapi::structures::{NvPublic, SymmetricDefinition};
618    /// # use tss_esapi::{Context, TctiNameConf};
619    /// #
620    /// # let mut context = // ...
621    /// #     Context::new(
622    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
623    /// #     ).expect("Failed to create Context");
624    /// #
625    /// # // Set owner session for NV space definition
626    /// # let owner_auth_session = context
627    /// #     .start_auth_session(
628    /// #         None,
629    /// #         None,
630    /// #         None,
631    /// #         SessionType::Hmac,
632    /// #         SymmetricDefinition::AES_256_CFB,
633    /// #         tss_esapi::interface_types::algorithm::HashingAlgorithm::Sha256,
634    /// #     )
635    /// #     .expect("Failed to create session")
636    /// #     .expect("Received invalid handle");
637    /// # let (session_attributes, session_attributes_mask) = SessionAttributes::builder()
638    /// #     .with_decrypt(true)
639    /// #     .with_encrypt(true)
640    /// #     .build();
641    /// # context.tr_sess_set_attributes(owner_auth_session, session_attributes, session_attributes_mask)
642    /// #     .expect("Failed to set attributes on session");
643    /// # context.set_sessions((Some(owner_auth_session), None, None));
644    /// #
645    /// # let trial_session = context
646    /// #     .start_auth_session(
647    /// #         None,
648    /// #         None,
649    /// #         None,
650    /// #         SessionType::Trial,
651    /// #         SymmetricDefinition::AES_256_CFB,
652    /// #         HashingAlgorithm::Sha256,
653    /// #     )
654    /// #     .expect("Start auth session failed")
655    /// #     .expect("Start auth session returned a NONE handle");
656    /// #
657    /// # let (policy_auth_session_attributes, policy_auth_session_attributes_mask) =
658    /// #     SessionAttributes::builder()
659    /// #         .with_decrypt(true)
660    /// #         .with_encrypt(true)
661    /// #         .build();
662    /// # context
663    /// #     .tr_sess_set_attributes(
664    /// #         trial_session,
665    /// #         policy_auth_session_attributes,
666    /// #         policy_auth_session_attributes_mask,
667    /// #     )
668    /// #     .expect("tr_sess_set_attributes call failed");
669    /// #
670    /// # let policy_session = PolicySession::try_from(trial_session)
671    /// #     .expect("Failed to convert auth session into policy session");
672    /// #
673    /// # let nv_index = NvIndexTpmHandle::new(0x01500600)
674    /// #     .expect("Failed to create NV index tpm handle");
675    /// #
676    /// # // Create NV index attributes
677    /// # let owner_nv_index_attributes = NvIndexAttributes::builder()
678    /// #     .with_owner_write(true)
679    /// #     .with_owner_read(true)
680    /// #     .build()
681    /// #     .expect("Failed to create owner nv index attributes");
682    /// #
683    /// # // Create owner nv public.
684    /// # let owner_nv_public = NvPublic::builder()
685    /// #     .with_nv_index(nv_index)
686    /// #     .with_index_name_algorithm(HashingAlgorithm::Sha256)
687    /// #     .with_index_attributes(owner_nv_index_attributes)
688    /// #     .with_data_area_size(32)
689    /// #     .build()
690    /// #     .expect("Failed to build NvPublic for owner");
691    /// #
692    /// let nv_index_handle = context
693    ///    .nv_define_space(Provision::Owner, None, owner_nv_public)
694    ///    .expect("Call to nv_define_space failed");
695    ///
696    /// context.policy_authorize_nv(
697    ///     policy_session,
698    ///     NvAuth::Owner,
699    ///     nv_index_handle,
700    /// ).expect("failed to extend policy with policy_authorize_nv");;
701    /// #
702    /// # context
703    /// #     .nv_undefine_space(Provision::Owner, nv_index_handle)
704    /// #     .expect("Call to nv_undefine_space failed");
705    /// ```
706    pub fn policy_authorize_nv(
707        &mut self,
708        policy_session: PolicySession,
709        auth_handle: NvAuth,
710        nv_index_handle: NvIndexHandle,
711    ) -> Result<()> {
712        ReturnCode::ensure_success(
713            unsafe {
714                Esys_PolicyAuthorizeNV(
715                    self.mut_context(),
716                    AuthHandle::from(auth_handle).into(),
717                    nv_index_handle.into(),
718                    SessionHandle::from(policy_session).into(),
719                    self.optional_session_1(),
720                    self.optional_session_2(),
721                    self.optional_session_3(),
722                )
723            },
724            |ret| {
725                error!("Error when computing policy authorize NV: {:#010X}", ret);
726            },
727        )
728    }
729}