From 5ded0e7d4eeef2a5fcea93a128c9878882c2a4e6 Mon Sep 17 00:00:00 2001 From: Jesper Brynolf Date: Tue, 28 Nov 2023 23:33:48 +0100 Subject: [PATCH] Fixes problem with sign requiring a HashcheckTicket. - This fixes #475 by making the HashcheckTicket that was previously required in the ```sign``` context method optional instead. If it is ```None``` it is then internally converted into the HashcheckTicket version of the `Null ticket` before being converted to the corresponding TSS type. This has the benefit of removing the need to use the TSS type in order to create a `Null ticket`. Signed-off-by: Jesper Brynolf --- tss-esapi/src/abstraction/transient/mod.rs | 15 +---- .../signing_and_signature_verification.rs | 56 ++++++++++++++++++- tss-esapi/src/structures/tickets.rs | 16 +++++- ...nhanced_authorization_ea_commands_tests.rs | 17 +----- ...igning_and_signature_verification_tests.rs | 43 +++----------- 5 files changed, 81 insertions(+), 66 deletions(-) diff --git a/tss-esapi/src/abstraction/transient/mod.rs b/tss-esapi/src/abstraction/transient/mod.rs index 63b9216f..6bf34ca2 100644 --- a/tss-esapi/src/abstraction/transient/mod.rs +++ b/tss-esapi/src/abstraction/transient/mod.rs @@ -8,7 +8,7 @@ //! client. use crate::{ attributes::{ObjectAttributesBuilder, SessionAttributesBuilder}, - constants::{tss::*, SessionType, TpmFormatZeroError}, + constants::{SessionType, TpmFormatZeroError}, error::{TpmFormatZeroResponseCode, TpmResponseCode}, handles::{KeyHandle, SessionHandle}, interface_types::{ @@ -23,7 +23,6 @@ use crate::{ RsaScheme, Signature, SignatureScheme, SymmetricDefinitionObject, VerifiedTicket, }, tcti_ldr::TctiNameConf, - tss2_esys::*, utils::{create_restricted_decryption_rsa_public, PublicKey, TpmsContext}, Context, Error, Result, ReturnCode, WrapperErrorKind as ErrorKind, }; @@ -287,20 +286,10 @@ impl TransientKeyContext { ) -> Result { let key_handle = self.load_key(key_params, key_material, key_auth)?; - let validation = TPMT_TK_HASHCHECK { - tag: TPM2_ST_HASHCHECK, - hierarchy: TPM2_RH_NULL, - digest: Default::default(), - }; self.set_session_attrs()?; let signature = self .context - .sign( - key_handle, - digest, - SignatureScheme::Null, - validation.try_into()?, - ) + .sign(key_handle, digest, SignatureScheme::Null, None) .or_else(|e| { self.context.flush_context(key_handle.into())?; Err(e) diff --git a/tss-esapi/src/context/tpm_commands/signing_and_signature_verification.rs b/tss-esapi/src/context/tpm_commands/signing_and_signature_verification.rs index 6b7295ce..0f9dfe37 100644 --- a/tss-esapi/src/context/tpm_commands/signing_and_signature_verification.rs +++ b/tss-esapi/src/context/tpm_commands/signing_and_signature_verification.rs @@ -40,14 +40,66 @@ impl Context { } /// Sign a digest with a key present in the TPM and return the signature. + /// + /// # Details + /// For signatures using a restricted key, a hashcheck must be provided. For unrestricted keys, this may be None. + /// + /// # Parameters + /// `key_handle` - Handle to the key be used for signing. + /// `digest` - The digest that is going to be signed. + /// `scheme` - The scheme to use if the scheme for the key referenced by the key handle is null. + /// `validation` - An optional [HashcheckTicket] that proof that the digest was created by the TPM. + /// N.B. None will be treated as a "Null ticket". + /// # Example + /// + /// ```rust + /// # use tss_esapi::{Context, TctiNameConf, + /// # interface_types::{ + /// # algorithm::{HashingAlgorithm, RsaSchemeAlgorithm}, + /// # key_bits::RsaKeyBits, + /// # resource_handles::Hierarchy, + /// # }, + /// # structures::{RsaScheme, RsaExponent}, + /// # utils::create_unrestricted_signing_rsa_public + /// # }; + /// use tss_esapi::structures::SignatureScheme; + /// # let mut context = + /// # Context::new( + /// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"), + /// # ).expect("Failed to create Context"); + /// # let signing_key_pub = create_unrestricted_signing_rsa_public( + /// # RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256)) + /// # .expect("Failed to create RSA scheme"), + /// # RsaKeyBits::Rsa2048, + /// # RsaExponent::default(), + /// # ) + /// # .expect("Failed to create an unrestricted signing rsa public structure"); + /// # let unrestricted_signing_key_handle = context + /// # .execute_with_nullauth_session(|ctx| { + /// # ctx.create_primary(Hierarchy::Owner, signing_key_pub, None, None, None, None) + /// # }) + /// # .unwrap() + /// # .key_handle; + /// # let digest = context.get_random(32).unwrap(); + /// let signature = context.execute_with_nullauth_session(|ctx| { + /// ctx.sign( + /// unrestricted_signing_key_handle, + /// digest, + /// SignatureScheme::Null, + /// None, + /// ) + /// }) + /// .expect("Failed to sign digest"); + /// ``` pub fn sign( &mut self, key_handle: KeyHandle, digest: Digest, scheme: SignatureScheme, - validation: HashcheckTicket, + validation: impl Into>, ) -> Result { let mut signature_ptr = null_mut(); + let validation_ticket = validation.into().unwrap_or_default().try_into()?; ReturnCode::ensure_success( unsafe { Esys_Sign( @@ -58,7 +110,7 @@ impl Context { self.optional_session_3(), &digest.into(), &scheme.into(), - &validation.try_into()?, + &validation_ticket, &mut signature_ptr, ) }, diff --git a/tss-esapi/src/structures/tickets.rs b/tss-esapi/src/structures/tickets.rs index bde53e10..0cca6381 100644 --- a/tss-esapi/src/structures/tickets.rs +++ b/tss-esapi/src/structures/tickets.rs @@ -11,7 +11,10 @@ use crate::{ }; use log::error; -use std::convert::{TryFrom, TryInto}; +use std::{ + convert::{TryFrom, TryInto}, + default::Default, +}; /// Macro used for implementing try_from /// TssTicketType -> TicketType @@ -124,6 +127,17 @@ pub struct HashcheckTicket { digest: Vec, } +impl Default for HashcheckTicket { + /// The default for the Hashcheck ticket is the Null ticket. + fn default() -> Self { + Self { + tag: StructureTag::Hashcheck, + hierarchy: Hierarchy::Null, + digest: Vec::::new(), + } + } +} + impl Ticket for HashcheckTicket { /// The tag of the verified ticket. const POSSIBLE_TAGS: &'static [StructureTag] = &[StructureTag::Hashcheck]; diff --git a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/enhanced_authorization_ea_commands_tests.rs b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/enhanced_authorization_ea_commands_tests.rs index 2dcc9c97..7815ecb2 100644 --- a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/enhanced_authorization_ea_commands_tests.rs +++ b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/enhanced_authorization_ea_commands_tests.rs @@ -530,12 +530,11 @@ mod test_policy_name_hash { mod test_policy_authorize { use crate::common::{create_ctx_with_session, get_pcr_policy_digest, signing_key_pub}; - use std::convert::{TryFrom, TryInto}; + use std::convert::TryFrom; use tss_esapi::{ - constants::tss::{TPM2_RH_NULL, TPM2_ST_HASHCHECK}, interface_types::{algorithm::HashingAlgorithm, resource_handles::Hierarchy}, structures::{Auth, MaxBuffer, Nonce, SignatureScheme}, - tss2_esys::{TPM2B_NONCE, TPMT_TK_HASHCHECK}, + tss2_esys::TPM2B_NONCE, }; #[test] fn test_policy_authorize() { @@ -569,19 +568,9 @@ mod test_policy_authorize { .unwrap() .0; - let validation = TPMT_TK_HASHCHECK { - tag: TPM2_ST_HASHCHECK, - hierarchy: TPM2_RH_NULL, - digest: Default::default(), - }; // A signature over just the policy_digest, since the policy_ref is empty let signature = context - .sign( - key_handle, - ahash.clone(), - SignatureScheme::Null, - validation.try_into().unwrap(), - ) + .sign(key_handle, ahash.clone(), SignatureScheme::Null, None) .unwrap(); let tkt = context .verify_signature(key_handle, ahash, signature) diff --git a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/signing_and_signature_verification_tests.rs b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/signing_and_signature_verification_tests.rs index c8b65e50..921ef751 100644 --- a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/signing_and_signature_verification_tests.rs +++ b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/signing_and_signature_verification_tests.rs @@ -2,12 +2,10 @@ // SPDX-License-Identifier: Apache-2.0 mod test_verify_signature { use crate::common::{create_ctx_with_session, signing_key_pub, HASH}; - use std::convert::{TryFrom, TryInto}; + use std::convert::TryFrom; use tss_esapi::{ - constants::tss::{TPM2_RH_NULL, TPM2_ST_HASHCHECK}, interface_types::{algorithm::HashingAlgorithm, resource_handles::Hierarchy}, structures::{Auth, Digest, PublicKeyRsa, RsaSignature, Signature, SignatureScheme}, - tss2_esys::TPMT_TK_HASHCHECK, }; #[test] @@ -28,17 +26,12 @@ mod test_verify_signature { .unwrap() .key_handle; - let validation = TPMT_TK_HASHCHECK { - tag: TPM2_ST_HASHCHECK, - hierarchy: TPM2_RH_NULL, - digest: Default::default(), - }; let signature = context .sign( key_handle, Digest::try_from(HASH[..32].to_vec()).unwrap(), SignatureScheme::Null, - validation.try_into().unwrap(), + None, ) .unwrap(); @@ -69,17 +62,12 @@ mod test_verify_signature { .unwrap() .key_handle; - let validation = TPMT_TK_HASHCHECK { - tag: TPM2_ST_HASHCHECK, - hierarchy: TPM2_RH_NULL, - digest: Default::default(), - }; let mut signature = context .sign( key_handle, Digest::try_from(HASH[..32].to_vec()).unwrap(), SignatureScheme::Null, - validation.try_into().unwrap(), + None, ) .unwrap(); @@ -176,12 +164,10 @@ mod test_verify_signature { mod test_sign { use crate::common::{create_ctx_with_session, signing_key_pub, HASH}; - use std::convert::{TryFrom, TryInto}; + use std::convert::TryFrom; use tss_esapi::{ - constants::tss::{TPM2_RH_NULL, TPM2_ST_HASHCHECK}, interface_types::resource_handles::Hierarchy, structures::{Auth, Digest, SignatureScheme}, - tss2_esys::TPMT_TK_HASHCHECK, }; #[test] @@ -202,17 +188,12 @@ mod test_sign { .unwrap() .key_handle; - let validation = TPMT_TK_HASHCHECK { - tag: TPM2_ST_HASHCHECK, - hierarchy: TPM2_RH_NULL, - digest: Default::default(), - }; context .sign( key_handle, Digest::try_from(HASH[..32].to_vec()).unwrap(), SignatureScheme::Null, - validation.try_into().unwrap(), + None, ) .unwrap(); } @@ -235,17 +216,12 @@ mod test_sign { .unwrap() .key_handle; - let validation = TPMT_TK_HASHCHECK { - tag: TPM2_ST_HASHCHECK, - hierarchy: TPM2_RH_NULL, - digest: Default::default(), - }; context .sign( key_handle, Digest::try_from(Vec::::new()).unwrap(), SignatureScheme::Null, - validation.try_into().unwrap(), + None, ) .unwrap_err(); } @@ -268,17 +244,12 @@ mod test_sign { .unwrap() .key_handle; - let validation = TPMT_TK_HASHCHECK { - tag: TPM2_ST_HASHCHECK, - hierarchy: TPM2_RH_NULL, - digest: Default::default(), - }; context .sign( key_handle, Digest::try_from([0xbb; 40].to_vec()).unwrap(), SignatureScheme::Null, - validation.try_into().unwrap(), + None, ) .unwrap_err(); }