diff --git a/Cargo.toml b/Cargo.toml index fdc9a74..326434d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,8 @@ authors = ["William Brown "] # default = ["tpm"] tpm = ["dep:tss-esapi"] +# tss-esapi = { path = "../rust-tss-esapi/tss-esapi" } + [dependencies] argon2 = { version = "0.5.2", features = ["alloc"] } hex = "0.4.3" @@ -23,3 +25,5 @@ zeroize = "1.6.0" [dev-dependencies] tracing-subscriber = "^0.3.17" + + diff --git a/src/lib.rs b/src/lib.rs index c32215b..62f4786 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,11 +19,13 @@ use argon2::MIN_SALT_LEN; use openssl::pkey::{PKey, Private}; use openssl::x509::X509; -use serde::{Deserialize, Serialize}; use std::str::FromStr; use tracing::error; use zeroize::Zeroizing; +#[cfg(not(feature = "tpm"))] +use serde::{Deserialize, Serialize}; + pub mod soft; #[cfg(feature = "tpm")] @@ -187,9 +189,28 @@ pub enum TpmError { TpmHmacKeyCreate, TpmHmacKeyLoad, TpmHmacSign, - TpmHmacInputTooLarge, + TpmIdentityKeyObjectAttributesInvalid, + TpmIdentityKeyAlgorithmInvalid, + TpmIdentityKeyBuilderInvalid, + TpmIdentityKeyCreate, + TpmIdentityKeySign, + TpmIdentityKeySignatureInvalid, + TpmIdentityKeyEcdsaSigRInvalid, + TpmIdentityKeyEcdsaSigSInvalid, + TpmIdentityKeyEcdsaSigFromParams, + TpmIdentityKeyEcdsaSigToDer, + + TpmIdentityKeyParamInvalid, + TpmIdentityKeyParamsToRsaSig, + + TpmIdentityKeyDerToEcdsaSig, + TpmIdentityKeyParamRInvalid, + TpmIdentityKeyParamSInvalid, + TpmIdentityKeyParamsToEcdsaSig, + TpmIdentityKeyVerify, + TpmOperationUnsupported, Entropy, @@ -254,11 +275,12 @@ pub enum HmacKey { }, #[cfg(not(feature = "tpm"))] TpmSha256 { - key_handle: (), + key_context: (), }, } -#[derive(Debug, Clone, Serialize, Deserialize)] +#[derive(Debug, Clone)] +#[cfg_attr(not(feature = "tpm"), derive(Serialize, Deserialize))] pub enum LoadableIdentityKey { SoftEcdsa256V1 { key: Vec, @@ -272,6 +294,22 @@ pub enum LoadableIdentityKey { iv: [u8; 16], x509: Option>, }, + #[cfg(feature = "tpm")] + TpmEcdsa256V1 { + private: tpm::Private, + public: tpm::Public, + x509: Option>, + }, + #[cfg(not(feature = "tpm"))] + TpmEcdsa256V1 { private: (), public: (), x509: () }, + #[cfg(feature = "tpm")] + TpmRsa2048V1 { + private: tpm::Private, + public: tpm::Public, + x509: Option>, + }, + #[cfg(not(feature = "tpm"))] + TpmRsa2048V1 { private: (), public: (), x509: () }, } pub enum IdentityKey { @@ -283,13 +321,31 @@ pub enum IdentityKey { pkey: PKey, x509: Option, }, + #[cfg(feature = "tpm")] + TpmEcdsa256 { + key_context: tpm::TpmsContext, + x509: Option, + }, + #[cfg(not(feature = "tpm"))] + TpmEcdsa256 { key_context: (), x509: () }, + #[cfg(feature = "tpm")] + TpmRsa2048 { + key_context: tpm::TpmsContext, + x509: Option, + }, + #[cfg(not(feature = "tpm"))] + TpmRsa2048 { key_context: (), x509: () }, } impl IdentityKey { pub fn alg(&self) -> KeyAlgorithm { match self { - IdentityKey::SoftEcdsa256 { .. } => KeyAlgorithm::Ecdsa256, - IdentityKey::SoftRsa2048 { .. } => KeyAlgorithm::Rsa2048, + IdentityKey::SoftEcdsa256 { .. } | IdentityKey::TpmEcdsa256 { .. } => { + KeyAlgorithm::Ecdsa256 + } + IdentityKey::SoftRsa2048 { .. } | IdentityKey::TpmRsa2048 { .. } => { + KeyAlgorithm::Rsa2048 + } } } } @@ -555,6 +611,58 @@ mod tests { }; } + #[macro_export] + macro_rules! test_tpm_identity_no_export { + ( $tpm:expr, $alg:expr ) => { + use crate::{AuthValue, Tpm}; + use std::str::FromStr; + use tracing::trace; + + let _ = tracing_subscriber::fmt::try_init(); + + let auth_str = AuthValue::generate().expect("Failed to create hex pin"); + + let auth_value = AuthValue::from_str(&auth_str).expect("Unable to create auth value"); + + // Request a new machine-key-context. This key "owns" anything + // created underneath it. + let loadable_machine_key = $tpm + .machine_key_create(&auth_value) + .expect("Unable to create new machine key"); + + trace!(?loadable_machine_key); + + let machine_key = $tpm + .machine_key_load(&auth_value, &loadable_machine_key) + .expect("Unable to load machine key"); + + // from that ctx, create an identity key + let loadable_id_key = $tpm + .identity_key_create(&machine_key, $alg) + .expect("Unable to create id key"); + + trace!(?loadable_id_key); + + let id_key = $tpm + .identity_key_load(&machine_key, &loadable_id_key) + .expect("Unable to load id key"); + + let input = "test string"; + let signature = $tpm + .identity_key_sign(&id_key, input.as_bytes()) + .expect("Unable to sign input"); + + trace!(?signature); + + let verify = $tpm.identity_key_verify(&id_key, input.as_bytes(), signature.as_slice()); + + trace!(?verify); + + // Internal verification + assert!(verify.expect("Unable to sign input")); + }; + } + #[macro_export] macro_rules! test_tpm_identity { ( $tpm:expr, $alg:expr ) => { diff --git a/src/soft.rs b/src/soft.rs index eb020bc..778d928 100644 --- a/src/soft.rs +++ b/src/soft.rs @@ -327,6 +327,9 @@ impl Tpm for SoftTpm { TpmError::IdentityKeyPublicToDer }) } + IdentityKey::TpmEcdsa256 { .. } | IdentityKey::TpmRsa2048 { .. } => { + Err(TpmError::IncorrectKeyType) + } } } @@ -339,6 +342,9 @@ impl Tpm for SoftTpm { TpmError::IdentityKeyPublicToPem }) } + IdentityKey::TpmEcdsa256 { .. } | IdentityKey::TpmRsa2048 { .. } => { + Err(TpmError::IncorrectKeyType) + } } } @@ -355,6 +361,9 @@ impl Tpm for SoftTpm { error!(?ossl_err); TpmError::IdentityKeyX509ToPem }), + IdentityKey::TpmEcdsa256 { .. } | IdentityKey::TpmRsa2048 { .. } => { + Err(TpmError::IncorrectKeyType) + } _ => Err(TpmError::IdentityKeyX509Missing), } } @@ -372,6 +381,9 @@ impl Tpm for SoftTpm { error!(?ossl_err); TpmError::IdentityKeyX509ToDer }), + IdentityKey::TpmEcdsa256 { .. } | IdentityKey::TpmRsa2048 { .. } => { + Err(TpmError::IncorrectKeyType) + } _ => Err(TpmError::IdentityKeyX509Missing), } } @@ -385,12 +397,23 @@ impl Tpm for SoftTpm { TpmError::IdentityKeyInvalidForSigning })? } + IdentityKey::TpmEcdsa256 { .. } | IdentityKey::TpmRsa2048 { .. } => { + return Err(TpmError::IncorrectKeyType) + } }; - signer.sign_oneshot_to_vec(input).map_err(|ossl_err| { - error!(?ossl_err); - TpmError::IdentityKeySignature - }) + signer + .sign_oneshot_to_vec(input) + .map_err(|ossl_err| { + error!(?ossl_err); + TpmError::IdentityKeySignature + }) + .map(|sig| { + let res = openssl::ecdsa::EcdsaSig::from_der(&sig); + tracing::debug!(res = %res.is_ok()); + + sig + }) } fn identity_key_verify( @@ -407,6 +430,9 @@ impl Tpm for SoftTpm { TpmError::IdentityKeyInvalidForVerification })? } + IdentityKey::TpmEcdsa256 { .. } | IdentityKey::TpmRsa2048 { .. } => { + return Err(TpmError::IncorrectKeyType) + } }; verifier @@ -465,6 +491,9 @@ impl Tpm for SoftTpm { TpmError::X509RequestSign })?; } + IdentityKey::TpmEcdsa256 { .. } | IdentityKey::TpmRsa2048 { .. } => { + return Err(TpmError::IncorrectKeyType) + } } req_builder.build().to_der().map_err(|ossl_err| { @@ -499,6 +528,9 @@ impl Tpm for SoftTpm { return Err(TpmError::X509KeyMismatch); } } + IdentityKey::TpmEcdsa256 { .. } | IdentityKey::TpmRsa2048 { .. } => { + return Err(TpmError::IncorrectKeyType) + } }; // At this point we know the cert belongs to this key, so lets @@ -513,6 +545,8 @@ impl Tpm for SoftTpm { LoadableIdentityKey::SoftRsa2048V1 { ref mut x509, .. } => { *x509 = Some(certificate_der.to_vec()); } + LoadableIdentityKey::TpmEcdsa256V1 { .. } + | LoadableIdentityKey::TpmRsa2048V1 { .. } => return Err(TpmError::IncorrectKeyType), }; Ok(cloned_key) diff --git a/src/tpm.rs b/src/tpm.rs index 521fb34..e61c293 100644 --- a/src/tpm.rs +++ b/src/tpm.rs @@ -2,23 +2,36 @@ use crate::{ AuthValue, HmacKey, IdentityKey, KeyAlgorithm, LoadableHmacKey, LoadableIdentityKey, LoadableMachineKey, MachineKey, Tpm, TpmError, }; + +use openssl::bn::BigNum; +use openssl::ecdsa::EcdsaSig; +use openssl::hash::{hash, MessageDigest}; +use openssl::x509::X509; + // use serde::{Deserialize, Serialize}; use tracing::error; use tss_esapi::attributes::{ObjectAttributesBuilder, SessionAttributesBuilder}; use tss_esapi::constants::SessionType; use tss_esapi::structures::{ - Auth, CreateKeyResult, CreatePrimaryKeyResult, Digest, KeyedHashScheme, MaxBuffer, - PublicBuilder, PublicKeyedHashParameters, SymmetricCipherParameters, SymmetricDefinition, - SymmetricDefinitionObject, + Auth, CreateKeyResult, CreatePrimaryKeyResult, Digest, EccParameter, EccPoint, EccScheme, + EccSignature, HashScheme, HashcheckTicket, KeyedHashScheme, MaxBuffer, PublicBuilder, + PublicEccParametersBuilder, PublicKeyRsa, PublicKeyedHashParameters, + PublicRsaParametersBuilder, RsaExponent, RsaScheme, RsaSignature, Signature, SignatureScheme, + SymmetricCipherParameters, SymmetricDefinition, SymmetricDefinitionObject, }; use tss_esapi::Context; use tss_esapi::TctiNameConf; use tss_esapi::interface_types::resource_handles::Hierarchy; +use tss_esapi::constants::tss::TPM2_RH_NULL; +use tss_esapi::constants::tss::TPM2_ST_HASHCHECK; use tss_esapi::interface_types::algorithm::{HashingAlgorithm, PublicAlgorithm}; +use tss_esapi::interface_types::ecc::EccCurve; +use tss_esapi::interface_types::key_bits::RsaKeyBits; use tss_esapi::interface_types::session_handles::AuthSession; +use tss_esapi::tss2_esys::TPMT_TK_HASHCHECK; use tss_esapi::handles::ObjectHandle; @@ -117,13 +130,11 @@ impl TpmTss { TpmError::TpmPrimaryPublicBuilderInvalid })?; + // Create the key under the "owner" hierarchy. Other hierarchies are platform + // which is for boot services, null which is ephemeral and resets after a reboot, + // and endorsement which allows key certification by the TPM manufacturer. self.tpm_ctx - .execute_with_nullauth_session(|ctx| { - // Create the key under the "owner" hierarchy. Other hierarchies are platform - // which is for boot services, null which is ephemeral and resets after a reboot, - // and endorsement which allows key certification by the TPM manufacturer. - ctx.create_primary(Hierarchy::Owner, primary_pub, None, None, None, None) - }) + .create_primary(Hierarchy::Owner, primary_pub, None, None, None, None) .map_err(|tpm_err| { error!(?tpm_err); TpmError::TpmPrimaryCreate @@ -232,16 +243,14 @@ impl Tpm for TpmTss { hsm_ctx .tpm_ctx - .execute_with_nullauth_session(|ctx| { - ctx.create( - primary_key_handle.into(), - key_pub, - Some(tpm_auth_value), - None, - None, - None, - ) - }) + .create( + primary_key_handle.into(), + key_pub, + Some(tpm_auth_value), + None, + None, + None, + ) .map( |CreateKeyResult { out_private: private, @@ -291,12 +300,12 @@ impl Tpm for TpmTss { hsm_ctx .tpm_ctx - .execute_with_nullauth_session(|ctx| { - ctx.load(primary_key_handle.into(), private.clone(), public.clone()) - .and_then(|key_handle| { - ctx.tr_set_auth(key_handle.into(), tpm_auth_value) - .map(|()| key_handle) - }) + .load(primary_key_handle.into(), private.clone(), public.clone()) + .and_then(|key_handle| { + hsm_ctx + .tpm_ctx + .tr_set_auth(key_handle.into(), tpm_auth_value) + .map(|()| key_handle) }) .map(|key_handle| MachineKey::Tpm { key_handle }) .map_err(|tpm_err| { @@ -350,9 +359,7 @@ impl Tpm for TpmTss { })?; self.tpm_ctx - .execute_with_nullauth_session(|ctx| { - ctx.create(mk_key_handle, key_pub, None, None, None, None) - }) + .create(mk_key_handle, key_pub, None, None, None, None) .map( |CreateKeyResult { out_private: private, @@ -385,7 +392,7 @@ impl Tpm for TpmTss { let key_handle = self .tpm_ctx - .execute_with_nullauth_session(|ctx| ctx.load(mk_key_handle, private, public)) + .load(mk_key_handle, private, public) .map_err(|tpm_err| { error!(?tpm_err); TpmError::TpmHmacKeyLoad @@ -430,39 +437,363 @@ impl Tpm for TpmTss { fn identity_key_create( &mut self, - _mk: &MachineKey, - _algorithm: KeyAlgorithm, + mk: &MachineKey, + algorithm: KeyAlgorithm, ) -> Result { - Err(TpmError::TpmOperationUnsupported) + let mk_key_handle = match mk { + MachineKey::Tpm { key_handle } => key_handle.clone(), + _ => return Err(TpmError::IncorrectKeyType), + }; + + let object_attributes = ObjectAttributesBuilder::new() + .with_fixed_tpm(true) + .with_fixed_parent(true) + .with_st_clear(false) + .with_sensitive_data_origin(true) + .with_user_with_auth(true) + .with_sign_encrypt(true) + .build() + .map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmIdentityKeyObjectAttributesInvalid + })?; + + let key_pub = match algorithm { + KeyAlgorithm::Ecdsa256 => { + let ecc_params = PublicEccParametersBuilder::new_unrestricted_signing_key( + EccScheme::EcDsa(HashScheme::new(HashingAlgorithm::Sha256)), + EccCurve::NistP256, + ) + .build() + .map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmIdentityKeyAlgorithmInvalid + })?; + + PublicBuilder::new() + .with_public_algorithm(PublicAlgorithm::Ecc) + .with_name_hashing_algorithm(HashingAlgorithm::Sha256) + .with_object_attributes(object_attributes) + .with_ecc_parameters(ecc_params) + .with_ecc_unique_identifier(EccPoint::default()) + .build() + .map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmIdentityKeyBuilderInvalid + })? + } + KeyAlgorithm::Rsa2048 => { + let rsa_params = PublicRsaParametersBuilder::new_unrestricted_signing_key( + RsaScheme::RsaPss(HashScheme::new(HashingAlgorithm::Sha256)), + RsaKeyBits::Rsa2048, + RsaExponent::default(), + ) + .build() + .map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmIdentityKeyAlgorithmInvalid + })?; + + PublicBuilder::new() + .with_public_algorithm(PublicAlgorithm::Rsa) + .with_name_hashing_algorithm(HashingAlgorithm::Sha256) + .with_object_attributes(object_attributes) + .with_rsa_parameters(rsa_params) + .with_rsa_unique_identifier(PublicKeyRsa::default()) + .build() + .map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmIdentityKeyBuilderInvalid + })? + } + }; + + self.tpm_ctx + .create(mk_key_handle.into(), key_pub, None, None, None, None) + .map( + |CreateKeyResult { + out_private: private, + out_public: public, + creation_data: _, + creation_hash: _, + creation_ticket: _, + }| { + match algorithm { + KeyAlgorithm::Ecdsa256 => LoadableIdentityKey::TpmEcdsa256V1 { + private, + public, + x509: None, + }, + KeyAlgorithm::Rsa2048 => LoadableIdentityKey::TpmRsa2048V1 { + private, + public, + x509: None, + }, + } + }, + ) + .map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmIdentityKeyCreate + }) } fn identity_key_load( &mut self, - _mk: &MachineKey, - _loadable_key: &LoadableIdentityKey, + mk: &MachineKey, + loadable_key: &LoadableIdentityKey, ) -> Result { - Err(TpmError::TpmOperationUnsupported) + let (private, public, algorithm, x509) = match loadable_key { + LoadableIdentityKey::TpmEcdsa256V1 { + private, + public, + x509, + } => ( + private.clone(), + public.clone(), + KeyAlgorithm::Ecdsa256, + x509.as_ref(), + ), + LoadableIdentityKey::TpmRsa2048V1 { + private, + public, + x509, + } => ( + private.clone(), + public.clone(), + KeyAlgorithm::Rsa2048, + x509.as_ref(), + ), + _ => return Err(TpmError::IncorrectKeyType), + }; + + let x509 = match x509 { + Some(der) => { + let x509 = X509::from_der(der).map_err(|ossl_err| { + error!(?ossl_err); + TpmError::X509FromDer + })?; + + /* + let x509_pkey = x509.public_key().map_err(|ossl_err| { + error!(?ossl_err); + TpmError::X509PublicKey + })?; + + if !pkey.public_eq(&x509_pkey) { + return Err(TpmError::X509KeyMismatch); + } + */ + + Some(x509) + } + None => None, + }; + + let mk_key_handle = match mk { + MachineKey::Tpm { key_handle } => key_handle.clone(), + _ => return Err(TpmError::IncorrectKeyType), + }; + + let key_handle = self + .tpm_ctx + .load(mk_key_handle, private, public) + .map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmHmacKeyLoad + })?; + + // Now it's loaded, lets setup the context we will load/unload as needed. In this + // process we WILL be unloading the keyhandle. + self.execute_with_temporary_object(key_handle.into(), |hsm_ctx, hmac_key_handle| { + hsm_ctx + .tpm_ctx + .context_save(hmac_key_handle.into()) + .map(|key_context| match algorithm { + KeyAlgorithm::Ecdsa256 => IdentityKey::TpmEcdsa256 { key_context, x509 }, + KeyAlgorithm::Rsa2048 => IdentityKey::TpmRsa2048 { key_context, x509 }, + }) + .map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmContextSave + }) + }) } fn identity_key_id(&mut self, _key: &IdentityKey) -> Result, TpmError> { Err(TpmError::TpmOperationUnsupported) } - fn identity_key_sign( - &mut self, - _key: &IdentityKey, - _input: &[u8], - ) -> Result, TpmError> { - Err(TpmError::TpmOperationUnsupported) + fn identity_key_sign(&mut self, key: &IdentityKey, input: &[u8]) -> Result, TpmError> { + let (key_context, sig_scheme, digest_alg) = match key { + IdentityKey::TpmEcdsa256 { + key_context, + x509: _, + } => ( + key_context.clone(), + SignatureScheme::Null, + MessageDigest::sha256(), + ), + IdentityKey::TpmRsa2048 { + key_context, + x509: _, + } => ( + key_context.clone(), + SignatureScheme::Null, + MessageDigest::sha256(), + ), + _ => return Err(TpmError::IncorrectKeyType), + }; + + // Future, may need to change this size for non sha256 + // Hash the input. + let bytes = hash(digest_alg, &input).map_err(|ossl_err| { + error!(?ossl_err); + TpmError::IdentityKeyDigest + })?; + + let tpm_digest: Digest = Digest::try_from(&bytes as &[u8]).map_err(|tpm_err| { + error!(?tpm_err); + TpmError::IdentityKeyDigest + })?; + + // No need for hashcheck, unrestricted key. + let validation: HashcheckTicket = TPMT_TK_HASHCHECK { + tag: TPM2_ST_HASHCHECK, + hierarchy: TPM2_RH_NULL, + digest: Default::default(), + } + .try_into() + .unwrap(); + + // Now we can sign. + let signature = + self.execute_with_temporary_object_context(key_context, |hsm_ctx, key_handle| { + hsm_ctx + .tpm_ctx + .sign(key_handle.into(), tpm_digest, sig_scheme, validation) + .map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmIdentityKeySign + }) + })?; + + tracing::debug!(?signature); + + match signature { + Signature::RsaPss(rsasig) => Ok(rsasig.signature().to_vec()), + Signature::EcDsa(ecsig) => { + let s = BigNum::from_slice(ecsig.signature_s().as_slice()).map_err(|ossl_err| { + error!(?ossl_err); + TpmError::TpmIdentityKeyEcdsaSigSInvalid + })?; + + let r = BigNum::from_slice(ecsig.signature_r().as_slice()).map_err(|ossl_err| { + error!(?ossl_err); + TpmError::TpmIdentityKeyEcdsaSigRInvalid + })?; + + let sig = EcdsaSig::from_private_components(r, s).map_err(|ossl_err| { + error!(?ossl_err); + TpmError::TpmIdentityKeyEcdsaSigFromParams + })?; + + sig.to_der().map_err(|ossl_err| { + error!(?ossl_err); + TpmError::TpmIdentityKeyEcdsaSigToDer + }) + } + _ => { + error!("tpm returned an invalid signature type"); + Err(TpmError::TpmIdentityKeySignatureInvalid) + } + } } fn identity_key_verify( &mut self, - _key: &IdentityKey, - _input: &[u8], - _signature: &[u8], + key: &IdentityKey, + input: &[u8], + signature: &[u8], ) -> Result { - Err(TpmError::TpmOperationUnsupported) + let (key_context, tpm_signature, digest_alg) = match key { + IdentityKey::TpmEcdsa256 { + key_context, + x509: _, + } => { + let sig = EcdsaSig::from_der(signature).map_err(|ossl_err| { + error!(?ossl_err); + TpmError::TpmIdentityKeyDerToEcdsaSig + })?; + + let r = EccParameter::try_from(sig.r().to_vec()).map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmIdentityKeyParamRInvalid + })?; + + let s = EccParameter::try_from(sig.s().to_vec()).map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmIdentityKeyParamSInvalid + })?; + + let ecsig = + EccSignature::create(HashingAlgorithm::Sha256, r, s).map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmIdentityKeyParamsToEcdsaSig + })?; + + let tpm_signature = Signature::EcDsa(ecsig); + + tracing::debug!(?tpm_signature); + + (key_context.clone(), tpm_signature, MessageDigest::sha256()) + } + IdentityKey::TpmRsa2048 { + key_context, + x509: _, + } => { + let pk_rsa = PublicKeyRsa::try_from(signature).map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmIdentityKeyParamInvalid + })?; + + let rsa_sig = + RsaSignature::create(HashingAlgorithm::Sha256, pk_rsa).map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmIdentityKeyParamsToRsaSig + })?; + + let tpm_signature = Signature::RsaPss(rsa_sig); + + (key_context.clone(), tpm_signature, MessageDigest::sha256()) + } + _ => return Err(TpmError::IncorrectKeyType), + }; + + let bytes = hash(digest_alg, &input).map_err(|ossl_err| { + error!(?ossl_err); + TpmError::IdentityKeyDigest + })?; + + let tpm_digest: Digest = Digest::try_from(&bytes as &[u8]).map_err(|tpm_err| { + error!(?tpm_err); + TpmError::IdentityKeyDigest + })?; + + let verified = + self.execute_with_temporary_object_context(key_context, |hsm_ctx, key_handle| { + hsm_ctx + .tpm_ctx + .verify_signature(key_handle.into(), tpm_digest, tpm_signature) + .map_err(|tpm_err| { + error!(?tpm_err); + TpmError::TpmIdentityKeyVerify + }) + }); + + tracing::trace!(?verified); + + Ok(verified.is_ok()) } fn identity_key_certificate_request( @@ -503,6 +834,7 @@ impl Tpm for TpmTss { #[cfg(test)] mod tests { use super::TpmTss; + use crate::KeyAlgorithm; #[test] fn tpm_hmac_hw_bound() { @@ -516,4 +848,19 @@ mod tests { crate::test_tpm_hmac!(hsm_a, hsm_b); } + + #[test] + fn tpm_identity_ecdsa256_hw_bound() { + let mut hsm = TpmTss::new("device:/dev/tpmrm0").expect("Unable to build Tpm Context"); + + crate::test_tpm_identity_no_export!(hsm, KeyAlgorithm::Ecdsa256); + } + + #[test] + fn tpm_identity_rsa2048_hw_bound() { + // Create the Hsm. + let mut hsm = TpmTss::new("device:/dev/tpmrm0").expect("Unable to build Tpm Context"); + + crate::test_tpm_identity_no_export!(hsm, KeyAlgorithm::Rsa2048); + } }