tss_esapi/context/tpm_commands/signing_and_signature_verification.rs
1// Copyright 2021 Contributors to the Parsec project.
2// SPDX-License-Identifier: Apache-2.0
3use crate::{
4 handles::KeyHandle,
5 structures::{Digest, HashcheckTicket, Signature, SignatureScheme, VerifiedTicket},
6 tss2_esys::{Esys_Sign, Esys_VerifySignature},
7 Context, Result, ReturnCode,
8};
9use log::error;
10use std::convert::{TryFrom, TryInto};
11use std::ptr::null_mut;
12
13impl Context {
14 /// Verify if a signature was generated by signing a given digest with a key in the TPM.
15 pub fn verify_signature(
16 &mut self,
17 key_handle: KeyHandle,
18 digest: Digest,
19 signature: Signature,
20 ) -> Result<VerifiedTicket> {
21 let mut validation_ptr = null_mut();
22 ReturnCode::ensure_success(
23 unsafe {
24 Esys_VerifySignature(
25 self.mut_context(),
26 key_handle.into(),
27 self.optional_session_1(),
28 self.optional_session_2(),
29 self.optional_session_3(),
30 &digest.into(),
31 &signature.try_into()?,
32 &mut validation_ptr,
33 )
34 },
35 |ret| {
36 error!("Error when verifying signature: {:#010X}", ret);
37 },
38 )?;
39 VerifiedTicket::try_from(Context::ffi_data_to_owned(validation_ptr)?)
40 }
41
42 /// Sign a digest with a key present in the TPM and return the signature.
43 ///
44 /// # Details
45 /// For signatures using a restricted key, a hashcheck must be provided. For unrestricted keys, this may be None.
46 ///
47 /// # Parameters
48 /// `key_handle` - Handle to the key be used for signing.
49 /// `digest` - The digest that is going to be signed.
50 /// `scheme` - The scheme to use if the scheme for the key referenced by the key handle is null.
51 /// `validation` - An optional [HashcheckTicket] that proof that the digest was created by the TPM.
52 /// N.B. None will be treated as a "Null ticket".
53 /// # Example
54 ///
55 /// ```rust
56 /// # use tss_esapi::{Context, TctiNameConf,
57 /// # interface_types::{
58 /// # algorithm::{HashingAlgorithm, RsaSchemeAlgorithm},
59 /// # key_bits::RsaKeyBits,
60 /// # reserved_handles::Hierarchy,
61 /// # },
62 /// # structures::{RsaScheme, RsaExponent},
63 /// # utils::create_unrestricted_signing_rsa_public
64 /// # };
65 /// use tss_esapi::structures::SignatureScheme;
66 /// # let mut context =
67 /// # Context::new(
68 /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
69 /// # ).expect("Failed to create Context");
70 /// # let signing_key_pub = create_unrestricted_signing_rsa_public(
71 /// # RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
72 /// # .expect("Failed to create RSA scheme"),
73 /// # RsaKeyBits::Rsa2048,
74 /// # RsaExponent::default(),
75 /// # )
76 /// # .expect("Failed to create an unrestricted signing rsa public structure");
77 /// # let unrestricted_signing_key_handle = context
78 /// # .execute_with_nullauth_session(|ctx| {
79 /// # ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None)
80 /// # })
81 /// # .unwrap()
82 /// # .key_handle;
83 /// # let digest = context.get_random(32).unwrap();
84 /// let signature = context.execute_with_nullauth_session(|ctx| {
85 /// ctx.sign(
86 /// unrestricted_signing_key_handle,
87 /// digest,
88 /// SignatureScheme::Null,
89 /// None,
90 /// )
91 /// })
92 /// .expect("Failed to sign digest");
93 /// ```
94 pub fn sign(
95 &mut self,
96 key_handle: KeyHandle,
97 digest: Digest,
98 scheme: SignatureScheme,
99 validation: impl Into<Option<HashcheckTicket>>,
100 ) -> Result<Signature> {
101 let mut signature_ptr = null_mut();
102 let validation_ticket = validation.into().unwrap_or_default().try_into()?;
103 ReturnCode::ensure_success(
104 unsafe {
105 Esys_Sign(
106 self.mut_context(),
107 key_handle.into(),
108 self.required_session_1()?,
109 self.optional_session_2(),
110 self.optional_session_3(),
111 &digest.into(),
112 &scheme.into(),
113 &validation_ticket,
114 &mut signature_ptr,
115 )
116 },
117 |ret| {
118 error!("Error when signing: {:#010X}", ret);
119 },
120 )?;
121 Signature::try_from(Context::ffi_data_to_owned(signature_ptr)?)
122 }
123}