Skip to main content

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}