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 handles::{KeyHandle, ObjectHandle},
5 structures::{
6 Attest, AttestBuffer, CreationTicket, Data, Digest, PcrSelectionList, Signature,
7 SignatureScheme,
8 },
9 tss2_esys::{Esys_Certify, Esys_CertifyCreation, Esys_GetTime, Esys_Quote},
10 Context, Result, ReturnCode,
11};
12use log::error;
13use std::convert::TryFrom;
14use std::ptr::null_mut;
15
16impl Context {
17 /// Prove that an object is loaded in the TPM
18 ///
19 /// # Arguments
20 /// * `object_handle` - Handle of the object to be certified
21 /// * `signing_key_handle` - Handle of the key used to sign the attestation buffer
22 /// * `qualifying_data` - Qualifying data
23 /// * `signing_scheme` - Signing scheme to use if the scheme for `signing_key_handle` is `Null`.
24 ///
25 /// The object may be any object that is loaded with [Self::load()] or [Self::create_primary()]. An object that
26 /// only has its public area loaded may not be certified.
27 ///
28 /// The `signing_key_handle` must be usable for signing.
29 ///
30 /// If `signing_key_handle` has the Restricted attribute set to `true` then `signing_scheme` must be
31 /// [SignatureScheme::Null].
32 ///
33 /// # Returns
34 /// The command returns a tuple consisting of:
35 /// * `attest_data` - TPM-generated attestation data.
36 /// * `signature` - Signature for the attestation data.
37 ///
38 /// # Errors
39 /// * if the qualifying data provided is too long, a `WrongParamSize` wrapper error will be returned
40 ///
41 /// # Examples
42 ///
43 /// ```rust
44 /// # use tss_esapi::{Context, TctiNameConf};
45 /// # use std::convert::TryFrom;
46 /// # use tss_esapi::{
47 /// # abstraction::cipher::Cipher,
48 /// # handles::KeyHandle,
49 /// # interface_types::{
50 /// # algorithm::{HashingAlgorithm, RsaSchemeAlgorithm, SignatureSchemeAlgorithm},
51 /// # key_bits::RsaKeyBits,
52 /// # reserved_handles::Hierarchy,
53 /// # },
54 /// # structures::{
55 /// # RsaExponent, RsaScheme, SymmetricDefinition,
56 /// # },
57 /// # utils::{create_unrestricted_signing_rsa_public, create_restricted_decryption_rsa_public},
58 /// # };
59 /// use std::convert::TryInto;
60 /// use tss_esapi::{
61 /// structures::{Data, SignatureScheme},
62 /// interface_types::session_handles::AuthSession,
63 /// };
64 /// # let mut context =
65 /// # Context::new(
66 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
67 /// # ).expect("Failed to create Context");
68 /// let qualifying_data = vec![0xff; 16];
69 /// # let signing_key_pub = create_unrestricted_signing_rsa_public(
70 /// # RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
71 /// # .expect("Failed to create RSA scheme"),
72 /// # RsaKeyBits::Rsa2048,
73 /// # RsaExponent::default(),
74 /// # )
75 /// # .expect("Failed to create an unrestricted signing rsa public structure");
76 /// # let sign_key_handle = context
77 /// # .execute_with_nullauth_session(|ctx| {
78 /// # ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
79 /// # })
80 /// # .unwrap()
81 /// # .key_handle;
82 /// # let decryption_key_pub = create_restricted_decryption_rsa_public(
83 /// # Cipher::aes_256_cfb()
84 /// # .try_into()
85 /// # .expect("Failed to create symmetric object"),
86 /// # RsaKeyBits::Rsa2048,
87 /// # RsaExponent::default(),
88 /// # )
89 /// # .expect("Failed to create a restricted decryption rsa public structure");
90 /// # let obj_key_handle = context
91 /// # .execute_with_nullauth_session(|ctx| {
92 /// # ctx.create_primary(
93 /// # Hierarchy::Owner,
94 /// # decryption_key_pub,
95 /// # None,
96 /// # None,
97 /// # None,
98 /// # None,
99 /// # )
100 /// # })
101 /// # .unwrap()
102 /// # .key_handle;
103 /// let (attest, signature) = context
104 /// .execute_with_sessions(
105 /// (
106 /// Some(AuthSession::Password),
107 /// Some(AuthSession::Password),
108 /// None,
109 /// ),
110 /// |ctx| {
111 /// ctx.certify(
112 /// obj_key_handle.into(),
113 /// sign_key_handle,
114 /// Data::try_from(qualifying_data).unwrap(),
115 /// SignatureScheme::Null,
116 /// )
117 /// },
118 /// )
119 /// .expect("Failed to certify object handle");
120 /// ```
121 pub fn certify(
122 &mut self,
123 object_handle: ObjectHandle,
124 signing_key_handle: KeyHandle,
125 qualifying_data: Data,
126 signing_scheme: SignatureScheme,
127 ) -> Result<(Attest, Signature)> {
128 let mut certify_info_ptr = null_mut();
129 let mut signature_ptr = null_mut();
130 ReturnCode::ensure_success(
131 unsafe {
132 Esys_Certify(
133 self.mut_context(),
134 object_handle.into(),
135 signing_key_handle.into(),
136 self.required_session_1()?,
137 self.required_session_2()?,
138 self.optional_session_3(),
139 &qualifying_data.into(),
140 &signing_scheme.into(),
141 &mut certify_info_ptr,
142 &mut signature_ptr,
143 )
144 },
145 |ret| {
146 error!("Error in certifying: {:#010X}", ret);
147 },
148 )?;
149
150 let certify_info = Context::ffi_data_to_owned(certify_info_ptr)?;
151 let signature = Context::ffi_data_to_owned(signature_ptr)?;
152 Ok((
153 Attest::try_from(AttestBuffer::try_from(certify_info)?)?,
154 Signature::try_from(signature)?,
155 ))
156 }
157
158 /// Prove the association between an object and its creation data
159 ///
160 /// # Arguments
161 /// * `signing_key_handle` - Handle of the key used to sign the attestation buffer
162 /// * `object_handle` - Handle of the object to be certified
163 /// * `qualifying_data` - Qualifying data
164 /// * `creation_hash` - Digest of the creation data
165 /// * `signing_scheme` - Signing scheme to use if the scheme for `signing_key_handle` is `Null`.
166 /// * `creation_ticket` - CreationTicket returned at object creation time.
167 ///
168 /// The object may be any object that is loaded with [Self::load()] or [Self::create_primary()]. An object that
169 /// only has its public area loaded may not be certified.
170 ///
171 /// The `signing_key_handle` must be usable for signing.
172 ///
173 /// If `signing_key_handle` has the Restricted attribute set to `true` then `signing_scheme` must be
174 /// [SignatureScheme::Null].
175 ///
176 /// # Returns
177 /// The command returns a tuple consisting of:
178 /// * `attest_data` - TPM-generated attestation data.
179 /// * `signature` - Signature for the attestation data.
180 ///
181 /// # Errors
182 /// * if the qualifying data provided is too long, a `WrongParamSize` wrapper error will be returned
183 ///
184 /// # Examples
185 ///
186 /// ```rust
187 /// # use tss_esapi::{Context, TctiNameConf};
188 /// # use std::convert::TryFrom;
189 /// # use tss_esapi::{
190 /// # abstraction::cipher::Cipher,
191 /// # handles::KeyHandle,
192 /// # interface_types::{
193 /// # algorithm::{HashingAlgorithm, EccSchemeAlgorithm, SignatureSchemeAlgorithm},
194 /// # ecc::EccCurve,
195 /// # reserved_handles::Hierarchy,
196 /// # },
197 /// # structures::{
198 /// # EccScheme
199 /// # },
200 /// # utils::create_unrestricted_signing_ecc_public,
201 /// # };
202 /// use std::convert::TryInto;
203 /// use tss_esapi::{
204 /// structures::{Data, SignatureScheme},
205 /// interface_types::session_handles::AuthSession,
206 /// };
207 /// # let mut context =
208 /// # Context::new(
209 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
210 /// # ).expect("Failed to create Context");
211 /// let qualifying_data = vec![0xff; 16];
212 /// # let signing_key_pub = create_unrestricted_signing_ecc_public(
213 /// # EccScheme::create(EccSchemeAlgorithm::EcDsa, Some(HashingAlgorithm::Sha256), None)
214 /// # .expect("Failed to create ECC scheme"),
215 /// # EccCurve::NistP256,
216 /// # )
217 /// # .expect("Failed to create an unrestricted signing ecc public structure");
218 /// # let create_result = context
219 /// # .execute_with_nullauth_session(|ctx| {
220 /// # ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
221 /// # }).unwrap();
222 /// let (attest, signature) = context
223 /// .execute_with_sessions(
224 /// (
225 /// Some(AuthSession::Password),
226 /// None,
227 /// None,
228 /// ),
229 /// |ctx| {
230 /// ctx.certify_creation(
231 /// create_result.key_handle,
232 /// create_result.key_handle.into(),
233 /// qualifying_data.try_into()?,
234 /// create_result.creation_hash,
235 /// SignatureScheme::Null,
236 /// create_result.creation_ticket,
237 /// )
238 /// },
239 /// )
240 /// .expect("Failed to certify creation");
241 /// ```
242 pub fn certify_creation(
243 &mut self,
244 signing_key_handle: KeyHandle,
245 created_object: ObjectHandle,
246 qualifying_data: Data,
247 creation_hash: Digest,
248 signing_scheme: SignatureScheme,
249 creation_ticket: CreationTicket,
250 ) -> Result<(Attest, Signature)> {
251 let mut certify_info_ptr = null_mut();
252 let mut signature_ptr = null_mut();
253 ReturnCode::ensure_success(
254 unsafe {
255 Esys_CertifyCreation(
256 self.mut_context(),
257 signing_key_handle.into(),
258 created_object.into(),
259 self.required_session_1()?,
260 self.optional_session_2(),
261 self.optional_session_3(),
262 &qualifying_data.into(),
263 &creation_hash.into(),
264 &signing_scheme.into(),
265 &creation_ticket.try_into()?,
266 &mut certify_info_ptr,
267 &mut signature_ptr,
268 )
269 },
270 |ret| {
271 error!("Error in certifying creation: {:#010X}", ret);
272 },
273 )?;
274
275 let certify_info = Context::ffi_data_to_owned(certify_info_ptr)?;
276 let signature = Context::ffi_data_to_owned(signature_ptr)?;
277 Ok((
278 Attest::try_from(AttestBuffer::try_from(certify_info)?)?,
279 Signature::try_from(signature)?,
280 ))
281 }
282
283 /// Generate a quote on the selected PCRs
284 ///
285 /// # Arguments
286 /// * `signing_key_handle` - Handle of key that will perform signature.
287 /// * `qualifying_data` - Data supplied by the caller.
288 /// * `signing_scheme` - Signing scheme to use if the scheme for signing_key_handle is the null scheme.
289 /// * `pcr_selection_list` - The PCR set to quote.
290 ///
291 /// # Errors
292 /// * if the qualifying data provided is too long, a `WrongParamSize` wrapper error will be returned.
293 ///
294 /// # Examples
295 ///
296 /// ```rust
297 /// # use tss_esapi::{Context, TctiNameConf};
298 /// use std::convert::TryFrom;
299 /// # use tss_esapi::{
300 /// # handles::KeyHandle,
301 /// # interface_types::{
302 /// # algorithm::{RsaSchemeAlgorithm, SignatureSchemeAlgorithm},
303 /// # key_bits::RsaKeyBits,
304 /// # reserved_handles::Hierarchy,
305 /// # },
306 /// # structures::{
307 /// # AttestInfo, RsaExponent, RsaScheme, Signature,
308 /// # },
309 /// # utils::{create_unrestricted_signing_rsa_public, create_restricted_decryption_rsa_public},
310 /// # };
311 /// use tss_esapi::{
312 /// interface_types::{
313 /// algorithm::HashingAlgorithm,
314 /// session_handles::AuthSession,
315 /// },
316 /// structures::{
317 /// Data, PcrSelectionListBuilder, PcrSlot, SignatureScheme,
318 /// },
319 /// };
320 ///
321 /// # let mut context =
322 /// # Context::new(
323 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
324 /// # ).expect("Failed to create Context");
325 /// let qualifying_data = Data::try_from(vec![0xff; 16])
326 /// .expect("It should be possible to create qualifying data from bytes.");
327 /// # let signing_key_pub = create_unrestricted_signing_rsa_public(
328 /// # RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
329 /// # .expect("Failed to create RSA scheme"),
330 /// # RsaKeyBits::Rsa2048,
331 /// # RsaExponent::default(),
332 /// # )
333 /// # .expect("Failed to create an unrestricted signing rsa public structure");
334 /// # let sign_key_handle = context
335 /// # .execute_with_nullauth_session(|ctx| {
336 /// # ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
337 /// # })
338 /// # .unwrap()
339 /// # .key_handle;
340 ///
341 /// // Quote PCR 0, 1, 2
342 /// let pcr_selection_list = PcrSelectionListBuilder::new()
343 /// .with_selection(HashingAlgorithm::Sha256, &[PcrSlot::Slot0, PcrSlot::Slot1, PcrSlot::Slot2])
344 /// .build()
345 /// .expect("It should be possible to create PCR selection list with valid values.");
346 ///
347 /// let (attest, signature) = context
348 /// .execute_with_sessions(
349 /// (
350 /// Some(AuthSession::Password),
351 /// None,
352 /// None,
353 /// ),
354 /// |ctx| {
355 /// ctx.quote(
356 /// sign_key_handle,
357 /// qualifying_data,
358 /// SignatureScheme::Null,
359 /// pcr_selection_list.clone(),
360 /// )
361 /// },
362 /// )
363 /// .expect("Failed to get quote");
364 /// # match signature {
365 /// # Signature::RsaSsa(signature) => {
366 /// # assert_eq!(signature.hashing_algorithm(), HashingAlgorithm::Sha256);
367 /// # }
368 /// # _ => {
369 /// # panic!("Received the wrong signature from the call to `quote`.");
370 /// # }
371 /// # }
372 /// # match attest.attested() {
373 /// # AttestInfo::Quote { info } => {
374 /// # assert!(
375 /// # !info.pcr_digest().is_empty(),
376 /// # "Digest in QuoteInfo is empty"
377 /// # );
378 /// # assert_eq!(
379 /// # &pcr_selection_list,
380 /// # info.pcr_selection(),
381 /// # "QuoteInfo selection list did not match the input selection list"
382 /// # );
383 /// # }
384 /// # _ => {
385 /// # panic!("Attested did not contain the expected variant.")
386 /// # }
387 /// # }
388 /// ```
389 pub fn quote(
390 &mut self,
391 signing_key_handle: KeyHandle,
392 qualifying_data: Data,
393 signing_scheme: SignatureScheme,
394 pcr_selection_list: PcrSelectionList,
395 ) -> Result<(Attest, Signature)> {
396 let mut quoted_ptr = null_mut();
397 let mut signature_ptr = null_mut();
398 ReturnCode::ensure_success(
399 unsafe {
400 Esys_Quote(
401 self.mut_context(),
402 signing_key_handle.into(),
403 self.optional_session_1(),
404 self.optional_session_2(),
405 self.optional_session_3(),
406 &qualifying_data.into(),
407 &signing_scheme.into(),
408 &pcr_selection_list.into(),
409 &mut quoted_ptr,
410 &mut signature_ptr,
411 )
412 },
413 |ret| {
414 error!("Error in quoting PCR: {:#010X}", ret);
415 },
416 )?;
417
418 let quoted = Context::ffi_data_to_owned(quoted_ptr)?;
419 let signature = Context::ffi_data_to_owned(signature_ptr)?;
420 Ok((
421 Attest::try_from(AttestBuffer::try_from(quoted)?)?,
422 Signature::try_from(signature)?,
423 ))
424 }
425
426 /// Get the current time and clock from the TPM
427 ///
428 /// # Arguments
429 /// * `signing_key_handle` - Handle of the key used to sign the attestation buffer
430 /// * `qualifying_data` - Qualifying data
431 /// * `signing_scheme` - Signing scheme to use if the scheme for `signing_key_handle` is `Null`.
432 ///
433 /// The `signing_key_handle` must be usable for signing.
434 ///
435 /// If `signing_key_handle` has the Restricted attribute set to `true` then `signing_scheme` must be
436 /// [SignatureScheme::Null].
437 ///
438 /// # Returns
439 /// The command returns a tuple consisting of:
440 /// * `attest_data` - TPM-generated attestation data.
441 /// * `signature` - Signature for the attestation data.
442 ///
443 /// # Errors
444 /// * if the qualifying data provided is too long, a `WrongParamSize` wrapper error will be returned
445 ///
446 /// # Examples
447 ///
448 /// ```rust
449 /// # use tss_esapi::{Context, TctiNameConf};
450 /// # use std::convert::TryFrom;
451 /// # use tss_esapi::{
452 /// # abstraction::cipher::Cipher,
453 /// # interface_types::{
454 /// # algorithm::{HashingAlgorithm, RsaSchemeAlgorithm},
455 /// # key_bits::RsaKeyBits,
456 /// # reserved_handles::Hierarchy,
457 /// # },
458 /// # structures::{
459 /// # RsaExponent, RsaScheme,
460 /// # },
461 /// # utils::{create_unrestricted_signing_rsa_public, create_restricted_decryption_rsa_public},
462 /// # };
463 /// use std::convert::TryInto;
464 /// use tss_esapi::{
465 /// structures::{Data, SignatureScheme},
466 /// interface_types::session_handles::AuthSession,
467 /// };
468 /// # let mut context =
469 /// # Context::new(
470 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
471 /// # ).expect("Failed to create Context");
472 /// let qualifying_data = vec![0xff; 16];
473 /// # let signing_key_pub = create_unrestricted_signing_rsa_public(
474 /// # RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
475 /// # .expect("Failed to create RSA scheme"),
476 /// # RsaKeyBits::Rsa2048,
477 /// # RsaExponent::default(),
478 /// # )
479 /// # .expect("Failed to create an unrestricted signing rsa public structure");
480 /// # let sign_key_handle = context
481 /// # .execute_with_nullauth_session(|ctx| {
482 /// # ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
483 /// # })
484 /// # .unwrap()
485 /// # .key_handle;
486 /// let (attest, signature) = context
487 /// .execute_with_sessions(
488 /// (
489 /// Some(AuthSession::Password),
490 /// Some(AuthSession::Password),
491 /// None,
492 /// ),
493 /// |ctx| {
494 /// ctx.get_time(
495 /// sign_key_handle,
496 /// Data::try_from(qualifying_data).unwrap(),
497 /// SignatureScheme::Null,
498 /// )
499 /// },
500 /// )
501 /// .expect("Failed to get tpm time");
502 /// ```
503 pub fn get_time(
504 &mut self,
505 signing_key_handle: KeyHandle,
506 qualifying_data: Data,
507 signing_scheme: SignatureScheme,
508 ) -> Result<(Attest, Signature)> {
509 let mut timeinfo_ptr = null_mut();
510 let mut signature_ptr = null_mut();
511 ReturnCode::ensure_success(
512 unsafe {
513 Esys_GetTime(
514 self.mut_context(),
515 ObjectHandle::Endorsement.into(),
516 signing_key_handle.into(),
517 self.required_session_1()?,
518 self.required_session_2()?,
519 self.optional_session_3(),
520 &qualifying_data.into(),
521 &signing_scheme.into(),
522 &mut timeinfo_ptr,
523 &mut signature_ptr,
524 )
525 },
526 |ret| {
527 error!("Error in GetTime: {:#010X}", ret);
528 },
529 )?;
530
531 let timeinfo = Context::ffi_data_to_owned(timeinfo_ptr)?;
532 let signature = Context::ffi_data_to_owned(signature_ptr)?;
533 Ok((
534 Attest::try_from(AttestBuffer::try_from(timeinfo)?)?,
535 Signature::try_from(signature)?,
536 ))
537 }
538
539 // Missing function: GetSessionAuditDigest
540 // Missing function: GestCommandAuditDigest
541 // Missing function: CertifyX509
542}