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}