Skip to main content

tss_esapi/context/tpm_commands/
attestation_commands.rs

1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use crate::{
4    Context, Result, ReturnCode,
5    handles::{KeyHandle, ObjectHandle, SessionHandle},
6    structures::{
7        Attest, AttestBuffer, CreationTicket, Data, Digest, MaxBuffer, PcrSelectionList, Signature,
8        SignatureScheme,
9    },
10    tss2_esys::{
11        Esys_Certify, Esys_CertifyCreation, Esys_CertifyX509, Esys_GetCommandAuditDigest,
12        Esys_GetSessionAuditDigest, Esys_GetTime, Esys_Quote,
13    },
14};
15use log::error;
16use std::convert::TryFrom;
17use std::ptr::null_mut;
18
19impl Context {
20    /// Prove that an object is loaded in the TPM
21    ///
22    /// # Arguments
23    /// * `object_handle` - Handle of the object to be certified
24    /// * `signing_key_handle` - Handle of the key used to sign the attestation buffer
25    /// * `qualifying_data` - Qualifying data
26    /// * `signing_scheme` - Signing scheme to use if the scheme for `signing_key_handle` is `Null`.
27    ///
28    /// The object may be any object that is loaded with [Self::load()] or [Self::create_primary()]. An object that
29    /// only has its public area loaded may not be certified.
30    ///
31    /// The `signing_key_handle` must be usable for signing.
32    ///
33    /// If `signing_key_handle` has the Restricted attribute set to `true` then `signing_scheme` must be
34    /// [SignatureScheme::Null].
35    ///
36    /// # Returns
37    /// The command returns a tuple consisting of:
38    /// * `attest_data` - TPM-generated attestation data.
39    /// * `signature` - Signature for the attestation data.
40    ///
41    /// # Errors
42    /// * if the qualifying data provided is too long, a `WrongParamSize` wrapper error will be returned
43    ///
44    /// # Examples
45    ///
46    /// ```rust
47    /// # use tss_esapi::{Context, TctiNameConf};
48    /// # use std::convert::TryFrom;
49    /// # use tss_esapi::{
50    /// #     abstraction::cipher::Cipher,
51    /// #     handles::KeyHandle,
52    /// #     interface_types::{
53    /// #         algorithm::{HashingAlgorithm, RsaSchemeAlgorithm, SignatureSchemeAlgorithm},
54    /// #         key_bits::RsaKeyBits,
55    /// #         reserved_handles::Hierarchy,
56    /// #     },
57    /// #     structures::{
58    /// #         RsaExponent, RsaScheme, SymmetricDefinition,
59    /// #     },
60    /// #     utils::{create_unrestricted_signing_rsa_public, create_restricted_decryption_rsa_public},
61    /// # };
62    /// use std::convert::TryInto;
63    /// use tss_esapi::{
64    ///     structures::{Data, SignatureScheme},
65    ///     interface_types::session_handles::AuthSession,
66    /// };
67    /// # let mut context =
68    /// #     Context::new(
69    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
70    /// #     ).expect("Failed to create Context");
71    /// let qualifying_data = vec![0xff; 16];
72    /// # let signing_key_pub = create_unrestricted_signing_rsa_public(
73    /// #         RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
74    /// #         .expect("Failed to create RSA scheme"),
75    /// #     RsaKeyBits::Rsa2048,
76    /// #     RsaExponent::default(),
77    /// # )
78    /// # .expect("Failed to create an unrestricted signing rsa public structure");
79    /// # let sign_key_handle = context
80    /// #     .execute_with_nullauth_session(|ctx| {
81    /// #         ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
82    /// #     })
83    /// #     .unwrap()
84    /// #     .key_handle;
85    /// # let decryption_key_pub = create_restricted_decryption_rsa_public(
86    /// #         Cipher::aes_256_cfb()
87    /// #         .try_into()
88    /// #         .expect("Failed to create symmetric object"),
89    /// #     RsaKeyBits::Rsa2048,
90    /// #     RsaExponent::default(),
91    /// # )
92    /// # .expect("Failed to create a restricted decryption rsa public structure");
93    /// # let obj_key_handle = context
94    /// #     .execute_with_nullauth_session(|ctx| {
95    /// #         ctx.create_primary(
96    /// #             Hierarchy::Owner,
97    /// #             decryption_key_pub,
98    /// #             None,
99    /// #             None,
100    /// #             None,
101    /// #             None,
102    /// #         )
103    /// #     })
104    /// #     .unwrap()
105    /// #     .key_handle;
106    /// let (attest, signature) = context
107    ///     .execute_with_sessions(
108    ///         (
109    ///             Some(AuthSession::Password),
110    ///             Some(AuthSession::Password),
111    ///             None,
112    ///         ),
113    ///         |ctx| {
114    ///             ctx.certify(
115    ///                 obj_key_handle.into(),
116    ///                 sign_key_handle,
117    ///                 Data::try_from(qualifying_data).unwrap(),
118    ///                 SignatureScheme::Null,
119    ///             )
120    ///         },
121    ///     )
122    ///     .expect("Failed to certify object handle");
123    /// ```
124    pub fn certify(
125        &mut self,
126        object_handle: ObjectHandle,
127        signing_key_handle: KeyHandle,
128        qualifying_data: Data,
129        signing_scheme: SignatureScheme,
130    ) -> Result<(Attest, Signature)> {
131        let mut certify_info_ptr = null_mut();
132        let mut signature_ptr = null_mut();
133        ReturnCode::ensure_success(
134            unsafe {
135                Esys_Certify(
136                    self.mut_context(),
137                    object_handle.into(),
138                    signing_key_handle.into(),
139                    self.required_session_1()?,
140                    self.required_session_2()?,
141                    self.optional_session_3(),
142                    &qualifying_data.into(),
143                    &signing_scheme.into(),
144                    &mut certify_info_ptr,
145                    &mut signature_ptr,
146                )
147            },
148            |ret| {
149                error!("Error in certifying: {:#010X}", ret);
150            },
151        )?;
152
153        let certify_info = Context::ffi_data_to_owned(certify_info_ptr)?;
154        let signature = Context::ffi_data_to_owned(signature_ptr)?;
155        Ok((
156            Attest::try_from(AttestBuffer::try_from(certify_info)?)?,
157            Signature::try_from(signature)?,
158        ))
159    }
160
161    /// Prove the association between an object and its creation data
162    ///
163    /// # Arguments
164    /// * `signing_key_handle` - Handle of the key used to sign the attestation buffer
165    /// * `object_handle` - Handle of the object to be certified
166    /// * `qualifying_data` - Qualifying data
167    /// * `creation_hash` - Digest of the creation data
168    /// * `signing_scheme` - Signing scheme to use if the scheme for `signing_key_handle` is `Null`.
169    /// * `creation_ticket` - CreationTicket returned at object creation time.
170    ///
171    /// The object may be any object that is loaded with [Self::load()] or [Self::create_primary()]. An object that
172    /// only has its public area loaded may not be certified.
173    ///
174    /// The `signing_key_handle` must be usable for signing.
175    ///
176    /// If `signing_key_handle` has the Restricted attribute set to `true` then `signing_scheme` must be
177    /// [SignatureScheme::Null].
178    ///
179    /// # Returns
180    /// The command returns a tuple consisting of:
181    /// * `attest_data` - TPM-generated attestation data.
182    /// * `signature` - Signature for the attestation data.
183    ///
184    /// # Errors
185    /// * if the qualifying data provided is too long, a `WrongParamSize` wrapper error will be returned
186    ///
187    /// # Examples
188    ///
189    /// ```rust
190    /// # use tss_esapi::{Context, TctiNameConf};
191    /// # use std::convert::TryFrom;
192    /// # use tss_esapi::{
193    /// #     abstraction::cipher::Cipher,
194    /// #     handles::KeyHandle,
195    /// #     interface_types::{
196    /// #         algorithm::{HashingAlgorithm, EccSchemeAlgorithm, SignatureSchemeAlgorithm},
197    /// #         ecc::EccCurve,
198    /// #         reserved_handles::Hierarchy,
199    /// #     },
200    /// #     structures::{
201    /// #         EccScheme
202    /// #     },
203    /// #     utils::create_unrestricted_signing_ecc_public,
204    /// # };
205    /// use std::convert::TryInto;
206    /// use tss_esapi::{
207    ///     structures::{Data, SignatureScheme},
208    ///     interface_types::session_handles::AuthSession,
209    /// };
210    /// # let mut context =
211    /// #     Context::new(
212    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
213    /// #     ).expect("Failed to create Context");
214    /// let qualifying_data = vec![0xff; 16];
215    /// # let signing_key_pub = create_unrestricted_signing_ecc_public(
216    /// #         EccScheme::create(EccSchemeAlgorithm::EcDsa, Some(HashingAlgorithm::Sha256), None)
217    /// #         .expect("Failed to create ECC scheme"),
218    /// #         EccCurve::NistP256,
219    /// # )
220    /// # .expect("Failed to create an unrestricted signing ecc public structure");
221    /// # let create_result = context
222    /// #     .execute_with_nullauth_session(|ctx| {
223    /// #         ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
224    /// #     }).unwrap();
225    /// let (attest, signature) = context
226    ///     .execute_with_sessions(
227    ///         (
228    ///             Some(AuthSession::Password),
229    ///             None,
230    ///             None,
231    ///         ),
232    ///         |ctx| {
233    ///             ctx.certify_creation(
234    ///               create_result.key_handle,
235    ///               create_result.key_handle.into(),
236    ///               qualifying_data.try_into()?,
237    ///               create_result.creation_hash,
238    ///               SignatureScheme::Null,
239    ///               create_result.creation_ticket,
240    ///             )
241    ///         },
242    ///     )
243    ///     .expect("Failed to certify creation");
244    /// ```
245    pub fn certify_creation(
246        &mut self,
247        signing_key_handle: KeyHandle,
248        created_object: ObjectHandle,
249        qualifying_data: Data,
250        creation_hash: Digest,
251        signing_scheme: SignatureScheme,
252        creation_ticket: CreationTicket,
253    ) -> Result<(Attest, Signature)> {
254        let mut certify_info_ptr = null_mut();
255        let mut signature_ptr = null_mut();
256        ReturnCode::ensure_success(
257            unsafe {
258                Esys_CertifyCreation(
259                    self.mut_context(),
260                    signing_key_handle.into(),
261                    created_object.into(),
262                    self.required_session_1()?,
263                    self.optional_session_2(),
264                    self.optional_session_3(),
265                    &qualifying_data.into(),
266                    &creation_hash.into(),
267                    &signing_scheme.into(),
268                    &creation_ticket.try_into()?,
269                    &mut certify_info_ptr,
270                    &mut signature_ptr,
271                )
272            },
273            |ret| {
274                error!("Error in certifying creation: {:#010X}", ret);
275            },
276        )?;
277
278        let certify_info = Context::ffi_data_to_owned(certify_info_ptr)?;
279        let signature = Context::ffi_data_to_owned(signature_ptr)?;
280        Ok((
281            Attest::try_from(AttestBuffer::try_from(certify_info)?)?,
282            Signature::try_from(signature)?,
283        ))
284    }
285
286    /// Generate a quote on the selected PCRs
287    ///
288    /// # Arguments
289    /// * `signing_key_handle`  - Handle of key that will perform signature.
290    /// * `qualifying_data`     - Data supplied by the caller.
291    /// * `signing_scheme`      - Signing scheme to use if the scheme for signing_key_handle is the null scheme.
292    /// * `pcr_selection_list`  - The PCR set to quote.
293    ///
294    /// # Errors
295    /// * if the qualifying data provided is too long, a `WrongParamSize` wrapper error will be returned.
296    ///
297    /// # Examples
298    ///
299    /// ```rust
300    /// # use tss_esapi::{Context, TctiNameConf};
301    /// use std::convert::TryFrom;
302    /// # use tss_esapi::{
303    /// #     handles::KeyHandle,
304    /// #     interface_types::{
305    /// #         algorithm::{RsaSchemeAlgorithm, SignatureSchemeAlgorithm},
306    /// #         key_bits::RsaKeyBits,
307    /// #         reserved_handles::Hierarchy,
308    /// #     },
309    /// #     structures::{
310    /// #         AttestInfo, RsaExponent, RsaScheme, Signature,
311    /// #     },
312    /// #     utils::{create_unrestricted_signing_rsa_public, create_restricted_decryption_rsa_public},
313    /// # };
314    /// use tss_esapi::{
315    ///     interface_types::{
316    ///         algorithm::HashingAlgorithm,
317    ///         session_handles::AuthSession,
318    ///     },
319    ///     structures::{
320    ///         Data, PcrSelectionListBuilder, PcrSlot, SignatureScheme,
321    ///     },
322    /// };
323    ///
324    /// # let mut context =
325    /// #     Context::new(
326    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
327    /// #     ).expect("Failed to create Context");
328    /// let qualifying_data = Data::try_from(vec![0xff; 16])
329    ///     .expect("It should be possible to create qualifying data from bytes.");
330    /// # let signing_key_pub = create_unrestricted_signing_rsa_public(
331    /// #         RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
332    /// #         .expect("Failed to create RSA scheme"),
333    /// #     RsaKeyBits::Rsa2048,
334    /// #     RsaExponent::default(),
335    /// # )
336    /// # .expect("Failed to create an unrestricted signing rsa public structure");
337    /// # let sign_key_handle = context
338    /// #     .execute_with_nullauth_session(|ctx| {
339    /// #         ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
340    /// #     })
341    /// #     .unwrap()
342    /// #     .key_handle;
343    ///
344    /// // Quote PCR 0, 1, 2
345    /// let pcr_selection_list = PcrSelectionListBuilder::new()
346    ///     .with_selection(HashingAlgorithm::Sha256, &[PcrSlot::Slot0, PcrSlot::Slot1, PcrSlot::Slot2])
347    ///     .build()
348    ///     .expect("It should be possible to create PCR selection list with valid values.");
349    ///
350    /// let (attest, signature) = context
351    ///     .execute_with_sessions(
352    ///         (
353    ///             Some(AuthSession::Password),
354    ///             None,
355    ///             None,
356    ///         ),
357    ///         |ctx| {
358    ///             ctx.quote(
359    ///                 sign_key_handle,
360    ///                 qualifying_data,
361    ///                 SignatureScheme::Null,
362    ///                 pcr_selection_list.clone(),
363    ///             )
364    ///         },
365    ///     )
366    ///     .expect("Failed to get quote");
367    /// # match signature {
368    /// #     Signature::RsaSsa(signature) => {
369    /// #         assert_eq!(signature.hashing_algorithm(), HashingAlgorithm::Sha256);
370    /// #     }
371    /// #     _ => {
372    /// #         panic!("Received the wrong signature from the call to `quote`.");
373    /// #     }
374    /// # }
375    /// # match attest.attested() {
376    /// #     AttestInfo::Quote { info } => {
377    /// #         assert!(
378    /// #             !info.pcr_digest().is_empty(),
379    /// #             "Digest in QuoteInfo is empty"
380    /// #         );
381    /// #         assert_eq!(
382    /// #             &pcr_selection_list,
383    /// #             info.pcr_selection(),
384    /// #             "QuoteInfo selection list did not match the input selection list"
385    /// #         );
386    /// #     }
387    /// #     _ => {
388    /// #         panic!("Attested did not contain the expected variant.")
389    /// #     }
390    /// # }
391    /// ```
392    pub fn quote(
393        &mut self,
394        signing_key_handle: KeyHandle,
395        qualifying_data: Data,
396        signing_scheme: SignatureScheme,
397        pcr_selection_list: PcrSelectionList,
398    ) -> Result<(Attest, Signature)> {
399        let mut quoted_ptr = null_mut();
400        let mut signature_ptr = null_mut();
401        ReturnCode::ensure_success(
402            unsafe {
403                Esys_Quote(
404                    self.mut_context(),
405                    signing_key_handle.into(),
406                    self.required_session_1()?,
407                    self.optional_session_2(),
408                    self.optional_session_3(),
409                    &qualifying_data.into(),
410                    &signing_scheme.into(),
411                    &pcr_selection_list.into(),
412                    &mut quoted_ptr,
413                    &mut signature_ptr,
414                )
415            },
416            |ret| {
417                error!("Error in quoting PCR: {:#010X}", ret);
418            },
419        )?;
420
421        let quoted = Context::ffi_data_to_owned(quoted_ptr)?;
422        let signature = Context::ffi_data_to_owned(signature_ptr)?;
423        Ok((
424            Attest::try_from(AttestBuffer::try_from(quoted)?)?,
425            Signature::try_from(signature)?,
426        ))
427    }
428
429    /// Get the current time and clock from the TPM
430    ///
431    /// # Arguments
432    /// * `signing_key_handle` - Handle of the key used to sign the attestation buffer
433    /// * `qualifying_data` - Qualifying data
434    /// * `signing_scheme` - Signing scheme to use if the scheme for `signing_key_handle` is `Null`.
435    ///
436    /// The `signing_key_handle` must be usable for signing.
437    ///
438    /// If `signing_key_handle` has the Restricted attribute set to `true` then `signing_scheme` must be
439    /// [SignatureScheme::Null].
440    ///
441    /// # Returns
442    /// The command returns a tuple consisting of:
443    /// * `attest_data` - TPM-generated attestation data.
444    /// * `signature` - Signature for the attestation data.
445    ///
446    /// # Errors
447    /// * if the qualifying data provided is too long, a `WrongParamSize` wrapper error will be returned
448    ///
449    /// # Examples
450    ///
451    /// ```rust
452    /// # use tss_esapi::{Context, TctiNameConf};
453    /// # use std::convert::TryFrom;
454    /// # use tss_esapi::{
455    /// #     abstraction::cipher::Cipher,
456    /// #     interface_types::{
457    /// #         algorithm::{HashingAlgorithm, RsaSchemeAlgorithm},
458    /// #         key_bits::RsaKeyBits,
459    /// #         reserved_handles::Hierarchy,
460    /// #     },
461    /// #     structures::{
462    /// #         RsaExponent, RsaScheme,
463    /// #     },
464    /// #     utils::{create_unrestricted_signing_rsa_public, create_restricted_decryption_rsa_public},
465    /// # };
466    /// use std::convert::TryInto;
467    /// use tss_esapi::{
468    ///     structures::{Data, SignatureScheme},
469    ///     interface_types::session_handles::AuthSession,
470    /// };
471    /// # let mut context =
472    /// #     Context::new(
473    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
474    /// #     ).expect("Failed to create Context");
475    /// let qualifying_data = vec![0xff; 16];
476    /// # let signing_key_pub = create_unrestricted_signing_rsa_public(
477    /// #         RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
478    /// #         .expect("Failed to create RSA scheme"),
479    /// #     RsaKeyBits::Rsa2048,
480    /// #     RsaExponent::default(),
481    /// # )
482    /// # .expect("Failed to create an unrestricted signing rsa public structure");
483    /// # let sign_key_handle = context
484    /// #     .execute_with_nullauth_session(|ctx| {
485    /// #         ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
486    /// #     })
487    /// #     .unwrap()
488    /// #     .key_handle;
489    /// let (attest, signature) = context
490    ///     .execute_with_sessions(
491    ///         (
492    ///             Some(AuthSession::Password),
493    ///             Some(AuthSession::Password),
494    ///             None,
495    ///         ),
496    ///         |ctx| {
497    ///             ctx.get_time(
498    ///                 sign_key_handle,
499    ///                 Data::try_from(qualifying_data).unwrap(),
500    ///                 SignatureScheme::Null,
501    ///             )
502    ///         },
503    ///     )
504    ///     .expect("Failed to get tpm time");
505    /// ```
506    pub fn get_time(
507        &mut self,
508        signing_key_handle: KeyHandle,
509        qualifying_data: Data,
510        signing_scheme: SignatureScheme,
511    ) -> Result<(Attest, Signature)> {
512        let mut timeinfo_ptr = null_mut();
513        let mut signature_ptr = null_mut();
514        ReturnCode::ensure_success(
515            unsafe {
516                Esys_GetTime(
517                    self.mut_context(),
518                    ObjectHandle::Endorsement.into(),
519                    signing_key_handle.into(),
520                    self.required_session_1()?,
521                    self.required_session_2()?,
522                    self.optional_session_3(),
523                    &qualifying_data.into(),
524                    &signing_scheme.into(),
525                    &mut timeinfo_ptr,
526                    &mut signature_ptr,
527                )
528            },
529            |ret| {
530                error!("Error in GetTime: {:#010X}", ret);
531            },
532        )?;
533
534        let timeinfo = Context::ffi_data_to_owned(timeinfo_ptr)?;
535        let signature = Context::ffi_data_to_owned(signature_ptr)?;
536        Ok((
537            Attest::try_from(AttestBuffer::try_from(timeinfo)?)?,
538            Signature::try_from(signature)?,
539        ))
540    }
541
542    /// Get a signed attestation of a session audit digest.
543    ///
544    /// # Arguments
545    ///
546    /// * `privacy_admin_handle` - An [ObjectHandle] for the privacy administrator (Endorsement).
547    /// * `sign_handle` - A [KeyHandle] of the key used to sign the attestation.
548    /// * `session_handle` - A [SessionHandle] of the session to be audited.
549    /// * `qualifying_data` - [Data] to qualify the signing.
550    /// * `signing_scheme` - The [SignatureScheme] to use.
551    ///
552    /// # Details
553    ///
554    /// *From the specification*
555    /// > This command returns the current value of the session audit digest.
556    ///
557    /// # Returns
558    ///
559    /// A tuple of `(Attest, Signature)`.
560    ///
561    /// # Example
562    ///
563    /// ```rust
564    /// # use tss_esapi::{
565    /// #    Context, TctiNameConf,
566    /// #    attributes::SessionAttributesBuilder,
567    /// #    constants::SessionType,
568    /// #    handles::{ObjectHandle, SessionHandle},
569    /// #    interface_types::{
570    /// #        algorithm::{HashingAlgorithm, RsaSchemeAlgorithm},
571    /// #        key_bits::RsaKeyBits,
572    /// #        reserved_handles::Hierarchy,
573    /// #        session_handles::AuthSession,
574    /// #    },
575    /// #    structures::{Data, RsaExponent, RsaScheme, SignatureScheme, SymmetricDefinition},
576    /// #    utils::create_unrestricted_signing_rsa_public,
577    /// # };
578    /// # use std::convert::TryFrom;
579    /// # let mut context =
580    /// #     Context::new(
581    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
582    /// #     ).expect("Failed to create Context");
583    /// # let signing_key_pub = create_unrestricted_signing_rsa_public(
584    /// #         RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
585    /// #             .expect("Failed to create RSA scheme"),
586    /// #     RsaKeyBits::Rsa2048,
587    /// #     RsaExponent::default(),
588    /// # )
589    /// # .expect("Failed to create an unrestricted signing rsa public structure");
590    /// # let sign_key_handle = context
591    /// #     .execute_with_nullauth_session(|ctx| {
592    /// #         ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
593    /// #     })
594    /// #     .unwrap()
595    /// #     .key_handle;
596    /// // Create an audit session
597    /// let audit_session = context
598    ///     .start_auth_session(
599    ///         None, None, None,
600    ///         SessionType::Hmac,
601    ///         SymmetricDefinition::AES_256_CFB,
602    ///         HashingAlgorithm::Sha256,
603    ///     )
604    ///     .expect("Failed to create audit session")
605    ///     .expect("Received invalid handle");
606    ///
607    /// let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new()
608    ///     .with_audit(true)
609    ///     .build();
610    /// context
611    ///     .tr_sess_set_attributes(audit_session, session_attributes, session_attributes_mask)
612    ///     .expect("Failed to set audit attribute");
613    ///
614    /// // Use the audit session in a command to populate its digest
615    /// context.set_sessions((Some(audit_session), None, None));
616    /// let _ = context.read_public(sign_key_handle).unwrap();
617    ///
618    /// // Get the session audit digest
619    /// let session_handle = SessionHandle::from(audit_session);
620    /// let (_attest, _signature) = context
621    ///     .execute_with_sessions(
622    ///         (Some(AuthSession::Password), Some(AuthSession::Password), None),
623    ///         |ctx| {
624    ///             ctx.get_session_audit_digest(
625    ///                 ObjectHandle::Endorsement,
626    ///                 sign_key_handle,
627    ///                 session_handle,
628    ///                 Data::try_from(vec![0xff; 16]).unwrap(),
629    ///                 SignatureScheme::Null,
630    ///             )
631    ///         },
632    ///     )
633    ///     .expect("Failed to get session audit digest");
634    /// ```
635    pub fn get_session_audit_digest(
636        &mut self,
637        privacy_admin_handle: ObjectHandle,
638        sign_handle: KeyHandle,
639        session_handle: SessionHandle,
640        qualifying_data: Data,
641        signing_scheme: SignatureScheme,
642    ) -> Result<(Attest, Signature)> {
643        let mut audit_info_ptr = null_mut();
644        let mut signature_ptr = null_mut();
645        ReturnCode::ensure_success(
646            unsafe {
647                Esys_GetSessionAuditDigest(
648                    self.mut_context(),
649                    privacy_admin_handle.into(),
650                    sign_handle.into(),
651                    session_handle.into(),
652                    self.required_session_1()?,
653                    self.required_session_2()?,
654                    self.optional_session_3(),
655                    &qualifying_data.into(),
656                    &signing_scheme.into(),
657                    &mut audit_info_ptr,
658                    &mut signature_ptr,
659                )
660            },
661            |ret| {
662                error!("Error getting session audit digest: {:#010X}", ret);
663            },
664        )?;
665
666        let audit_info = Context::ffi_data_to_owned(audit_info_ptr)?;
667        let signature = Context::ffi_data_to_owned(signature_ptr)?;
668        Ok((
669            Attest::try_from(AttestBuffer::try_from(audit_info)?)?,
670            Signature::try_from(signature)?,
671        ))
672    }
673
674    /// Get a signed attestation of the command audit digest.
675    ///
676    /// # Arguments
677    ///
678    /// * `privacy_handle` - An [ObjectHandle] for the privacy administrator (Endorsement).
679    /// * `sign_handle` - A [KeyHandle] of the key used to sign the attestation.
680    /// * `qualifying_data` - [Data] to qualify the signing.
681    /// * `signing_scheme` - The [SignatureScheme] to use.
682    ///
683    /// # Details
684    ///
685    /// *From the specification*
686    /// > This command returns the current value of the command audit digest,
687    /// > a digest of the commands being audited, and the audit hash algorithm.
688    ///
689    /// # Returns
690    ///
691    /// A tuple of `(Attest, Signature)`.
692    ///
693    /// # Example
694    ///
695    /// ```rust
696    /// # use tss_esapi::{
697    /// #    Context, TctiNameConf,
698    /// #    interface_types::{
699    /// #        algorithm::{HashingAlgorithm, RsaSchemeAlgorithm},
700    /// #        key_bits::RsaKeyBits,
701    /// #        reserved_handles::Hierarchy,
702    /// #        session_handles::AuthSession,
703    /// #    },
704    /// #    structures::{Data, RsaExponent, RsaScheme, SignatureScheme},
705    /// #    utils::create_unrestricted_signing_rsa_public,
706    /// # };
707    /// # use std::convert::TryFrom;
708    /// # let mut context =
709    /// #     Context::new(
710    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
711    /// #     ).expect("Failed to create Context");
712    /// # let signing_key_pub = create_unrestricted_signing_rsa_public(
713    /// #         RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
714    /// #             .expect("Failed to create RSA scheme"),
715    /// #     RsaKeyBits::Rsa2048,
716    /// #     RsaExponent::default(),
717    /// # )
718    /// # .expect("Failed to create an unrestricted signing rsa public structure");
719    /// # let sign_key_handle = context
720    /// #     .execute_with_nullauth_session(|ctx| {
721    /// #         ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
722    /// #     })
723    /// #     .unwrap()
724    /// #     .key_handle;
725    /// let (_attest, _signature) = context
726    ///     .execute_with_sessions(
727    ///         (
728    ///             Some(AuthSession::Password),
729    ///             Some(AuthSession::Password),
730    ///             None,
731    ///         ),
732    ///         |ctx| {
733    ///             ctx.get_command_audit_digest(
734    ///                 tss_esapi::handles::ObjectHandle::Endorsement,
735    ///                 sign_key_handle,
736    ///                 Data::try_from(vec![0xff; 16]).unwrap(),
737    ///                 SignatureScheme::Null,
738    ///             )
739    ///         },
740    ///     )
741    ///     .expect("Failed to get command audit digest");
742    /// ```
743    pub fn get_command_audit_digest(
744        &mut self,
745        privacy_handle: ObjectHandle,
746        sign_handle: KeyHandle,
747        qualifying_data: Data,
748        signing_scheme: SignatureScheme,
749    ) -> Result<(Attest, Signature)> {
750        let mut audit_info_ptr = null_mut();
751        let mut signature_ptr = null_mut();
752        ReturnCode::ensure_success(
753            unsafe {
754                Esys_GetCommandAuditDigest(
755                    self.mut_context(),
756                    privacy_handle.into(),
757                    sign_handle.into(),
758                    self.required_session_1()?,
759                    self.required_session_2()?,
760                    self.optional_session_3(),
761                    &qualifying_data.into(),
762                    &signing_scheme.into(),
763                    &mut audit_info_ptr,
764                    &mut signature_ptr,
765                )
766            },
767            |ret| {
768                error!("Error getting command audit digest: {:#010X}", ret);
769            },
770        )?;
771
772        let audit_info = Context::ffi_data_to_owned(audit_info_ptr)?;
773        let signature = Context::ffi_data_to_owned(signature_ptr)?;
774        Ok((
775            Attest::try_from(AttestBuffer::try_from(audit_info)?)?,
776            Signature::try_from(signature)?,
777        ))
778    }
779
780    /// Produce a signed X.509 certificate.
781    ///
782    /// # Arguments
783    ///
784    /// * `object_handle` - An [ObjectHandle] of the object to be certified.
785    /// * `sign_handle` - A [KeyHandle] of the key used to sign the certificate.
786    /// * `reserved` - Reserved for future use, should be an empty [Data].
787    /// * `signing_scheme` - The [SignatureScheme] to use.
788    /// * `partial_certificate` - A [MaxBuffer] containing the partial certificate.
789    ///
790    /// # Details
791    ///
792    /// *From the specification*
793    /// > The purpose of this command is to generate an X.509 certificate that
794    /// > proves an object with a specific public key and attributes is loaded
795    /// > in the TPM.
796    ///
797    /// # Returns
798    ///
799    /// A tuple of `(MaxBuffer, Digest, Signature)`:
800    ///
801    /// * The [MaxBuffer] is a DER encoded SEQUENCE containing the DER encoded
802    ///   fields added to `partial_certificate` to make it a complete RFC 5280
803    ///   `TBSCertificate`.
804    /// * The [Digest] is the TBS (to-be-signed) digest that was signed.
805    /// * The [Signature] is the signature over the TBS digest.
806    ///
807    /// # Example
808    ///
809    /// ```rust
810    /// # use tss_esapi::{
811    /// #    Context, TctiNameConf,
812    /// #    attributes::ObjectAttributesBuilder,
813    /// #    handles::ObjectHandle,
814    /// #    interface_types::{
815    /// #        algorithm::{HashingAlgorithm, PublicAlgorithm, RsaSchemeAlgorithm},
816    /// #        key_bits::RsaKeyBits,
817    /// #        reserved_handles::Hierarchy,
818    /// #        session_handles::AuthSession,
819    /// #    },
820    /// #    structures::{
821    /// #        Data, MaxBuffer, PublicBuilder, PublicKeyRsa, PublicRsaParametersBuilder,
822    /// #        RsaExponent, RsaScheme, SignatureScheme,
823    /// #    },
824    /// # };
825    /// # use std::convert::TryFrom;
826    /// # let mut context =
827    /// #     Context::new(
828    /// #         TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
829    /// #     ).expect("Failed to create Context");
830    /// # let object_attributes = ObjectAttributesBuilder::new()
831    /// #     .with_fixed_tpm(true)
832    /// #     .with_fixed_parent(true)
833    /// #     .with_sensitive_data_origin(true)
834    /// #     .with_user_with_auth(true)
835    /// #     .with_sign_encrypt(true)
836    /// #     .with_restricted(true)
837    /// #     .with_x509_sign(true)
838    /// #     .build()
839    /// #     .expect("Failed to build object attributes");
840    /// # let key_pub = PublicBuilder::new()
841    /// #     .with_public_algorithm(PublicAlgorithm::Rsa)
842    /// #     .with_name_hashing_algorithm(HashingAlgorithm::Sha256)
843    /// #     .with_object_attributes(object_attributes)
844    /// #     .with_rsa_parameters(
845    /// #         PublicRsaParametersBuilder::new()
846    /// #             .with_scheme(
847    /// #                 RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
848    /// #                     .expect("Failed to create RSA scheme"),
849    /// #             )
850    /// #             .with_key_bits(RsaKeyBits::Rsa2048)
851    /// #             .with_exponent(RsaExponent::default())
852    /// #             .with_is_signing_key(true)
853    /// #             .with_is_decryption_key(false)
854    /// #             .with_restricted(true)
855    /// #             .build()
856    /// #             .expect("Failed to build RSA parameters"),
857    /// #     )
858    /// #     .with_rsa_unique_identifier(PublicKeyRsa::default())
859    /// #     .build()
860    /// #     .expect("Failed to build public");
861    /// # let key_handle = context
862    /// #     .execute_with_nullauth_session(|ctx| {
863    /// #         ctx.create_primary(Hierarchy::Owner, key_pub, None, None, None, None)
864    /// #     })
865    /// #     .unwrap()
866    /// #     .key_handle;
867    /// // DER-encoded partial X.509 certificate: SEQUENCE of
868    /// //   { issuer, validity, subject, subjectPublicKeyInfo (placeholder),
869    /// //     [3] EXPLICIT extensions }
870    /// // The TPM prepends `version` and `serialNumber`, substitutes
871    /// // `subjectPublicKeyInfo` with the certified key, then hashes / signs
872    /// // the resulting TBSCertificate. This template encodes:
873    /// //   issuer/subject : CN=rust-tss-esapi test
874    /// //   validity       : 2020-01-01 .. 2040-01-01 (UTCTime)
875    /// //   SPKI           : rsaEncryption OID + empty BIT STRING placeholder
876    /// //   extensions     : keyUsage = digitalSignature | keyCertSign (critical)
877    /// let partial_certificate: Vec<u8> = vec![
878    ///     0x30, 0x81, 0x86, 0x30, 0x1e, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04,
879    ///     0x03, 0x0c, 0x13, 0x72, 0x75, 0x73, 0x74, 0x2d, 0x74, 0x73, 0x73, 0x2d, 0x65,
880    ///     0x73, 0x61, 0x70, 0x69, 0x20, 0x74, 0x65, 0x73, 0x74, 0x30, 0x1e, 0x17, 0x0d,
881    ///     0x32, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x5a,
882    ///     0x17, 0x0d, 0x34, 0x30, 0x30, 0x31, 0x30, 0x31, 0x30, 0x30, 0x30, 0x30, 0x30,
883    ///     0x30, 0x5a, 0x30, 0x1e, 0x31, 0x1c, 0x30, 0x1a, 0x06, 0x03, 0x55, 0x04, 0x03,
884    ///     0x0c, 0x13, 0x72, 0x75, 0x73, 0x74, 0x2d, 0x74, 0x73, 0x73, 0x2d, 0x65, 0x73,
885    ///     0x61, 0x70, 0x69, 0x20, 0x74, 0x65, 0x73, 0x74, 0x30, 0x10, 0x30, 0x0b, 0x06,
886    ///     0x09, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x03, 0x01, 0x00,
887    ///     0xa3, 0x12, 0x30, 0x10, 0x30, 0x0e, 0x06, 0x03, 0x55, 0x1d, 0x0f, 0x01, 0x01,
888    ///     0xff, 0x04, 0x04, 0x03, 0x02, 0x02, 0x84,
889    /// ];
890    ///
891    /// let (_added, _tbs_digest, _signature) = context
892    ///     .execute_with_sessions(
893    ///         (
894    ///             Some(AuthSession::Password),
895    ///             Some(AuthSession::Password),
896    ///             None,
897    ///         ),
898    ///         |ctx| {
899    ///             ctx.certify_x509(
900    ///                 ObjectHandle::from(key_handle),
901    ///                 key_handle,
902    ///                 Data::default(),
903    ///                 SignatureScheme::Null,
904    ///                 MaxBuffer::try_from(partial_certificate).unwrap(),
905    ///             )
906    ///         },
907    ///     )
908    ///     .expect("Failed to certify X.509");
909    /// ```
910    pub fn certify_x509(
911        &mut self,
912        object_handle: ObjectHandle,
913        sign_handle: KeyHandle,
914        reserved: Data,
915        signing_scheme: SignatureScheme,
916        partial_certificate: MaxBuffer,
917    ) -> Result<(MaxBuffer, Digest, Signature)> {
918        let mut added_to_certificate_ptr = null_mut();
919        let mut tbs_digest_ptr = null_mut();
920        let mut signature_ptr = null_mut();
921        ReturnCode::ensure_success(
922            unsafe {
923                // According to the ESAPI specification (Ver. 1, Rev. 14),
924                // Esys_CertifyX509() only requires a sign handle session.
925                // However, according to the TPM 2.0 Library spec (Ver. 185),
926                // TPM2_CertifyX509() requires both object and sign handle
927                // sessions. We suppose the latter to be correct.
928                Esys_CertifyX509(
929                    self.mut_context(),
930                    object_handle.into(),
931                    sign_handle.into(),
932                    self.required_session_1()?,
933                    self.required_session_2()?,
934                    self.optional_session_3(),
935                    &reserved.into(),
936                    &signing_scheme.into(),
937                    &partial_certificate.into(),
938                    &mut added_to_certificate_ptr,
939                    &mut tbs_digest_ptr,
940                    &mut signature_ptr,
941                )
942            },
943            |ret| {
944                error!("Error certifying X.509: {:#010X}", ret);
945            },
946        )?;
947
948        Ok((
949            MaxBuffer::try_from(Context::ffi_data_to_owned(added_to_certificate_ptr)?)?,
950            Digest::try_from(Context::ffi_data_to_owned(tbs_digest_ptr)?)?,
951            Signature::try_from(Context::ffi_data_to_owned(signature_ptr)?)?,
952        ))
953    }
954}