From 1fc1db4145e478bb62713c1285c1731c6553988f Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Mon, 27 Jan 2025 23:49:37 -0800 Subject: [PATCH 1/3] bump rustcrypto dependencies to pre-release Signed-off-by: Arthur Gautier --- .codespellrc | 2 +- tss-esapi/Cargo.toml | 51 +- tss-esapi/src/abstraction/no_tpm/quote.rs | 69 +- tss-esapi/src/abstraction/public.rs | 48 +- tss-esapi/src/abstraction/signatures.rs | 20 +- tss-esapi/src/abstraction/signer.rs | 143 ++- tss-esapi/src/abstraction/transient/mod.rs | 4 +- .../tpm_commands/asymmetric_primitives.rs | 14 +- .../tpm_commands/context_management.rs | 2 +- .../context/tpm_commands/ephemeral_ec_keys.rs | 2 +- .../tpm_commands/symmetric_primitives.rs | 4 +- tss-esapi/src/structures/buffers.rs | 8 +- tss-esapi/tests/Cargo.lock.frozen | 1106 +++++++++++------ .../abstraction_tests/public_tests.rs | 12 +- .../transient_key_context_tests.rs | 39 +- .../asymmetric_primitives_tests.rs | 6 +- .../tpm_commands/context_management_tests.rs | 10 +- ...nhanced_authorization_ea_commands_tests.rs | 2 +- .../tpm_commands/ephemeral_ec_keys_tests.rs | 2 +- .../tpm_commands/hierarchy_commands_tests.rs | 6 +- .../tpm_commands/object_commands_tests.rs | 6 +- ...igning_and_signature_verification_tests.rs | 48 +- .../symmetric_primitives_tests.rs | 4 +- tss-esapi/tests/lint-checks.sh | 8 +- 24 files changed, 1049 insertions(+), 567 deletions(-) diff --git a/.codespellrc b/.codespellrc index 2e86fc7ff..c4da27a42 100644 --- a/.codespellrc +++ b/.codespellrc @@ -1,3 +1,3 @@ [codespell] skip = .git,target,Cargo.lock -ignore-words-list = acsend,crate,inout,keypair,daa,de,ser +ignore-words-list = acsend,crate,keypair,inout,daa,de,ser diff --git a/tss-esapi/Cargo.toml b/tss-esapi/Cargo.toml index b0ceea0cf..c52b560f3 100644 --- a/tss-esapi/Cargo.toml +++ b/tss-esapi/Cargo.toml @@ -32,44 +32,45 @@ num-derive = "0.4.2" num-traits = "0.2.12" hostname-validator = "1.1.0" regex = "1.3.9" -zeroize = { version = "1.5.7", features = ["zeroize_derive"] } +zeroize = { version = "1.8.2", features = ["zeroize_derive"] } tss-esapi-sys = { path = "../tss-esapi-sys", version = "0.7.0-alpha.1" } -x509-cert = { version = "0.2.0", optional = true } -ecdsa = { version = "0.16.9", features = [ +x509-cert = { version = "0.3.0-rc.4", optional = true } +ecdsa = { version = "0.17.0-rc.23", features = [ + "algorithm", "der", - "hazmat", - "arithmetic", - "verifying", ], optional = true } -elliptic-curve = { version = "0.13.8", optional = true, features = [ +elliptic-curve = { version = "0.14.1", optional = true, features = [ "alloc", "pkcs8", ] } -p192 = { version = "0.13.0", optional = true } -p224 = { version = "0.13.2", optional = true } -p256 = { version = "0.13.2", optional = true } -p384 = { version = "0.13.0", optional = true } -p521 = { version = "0.13.3", optional = true } -pkcs8 = { version = "0.10.2", optional = true } -rsa = { version = "0.9", optional = true } -sha1 = { version = "0.10.6", optional = true } -sha2 = { version = "0.10.8", optional = true } -sha3 = { version = "0.10.8", optional = true } -sm2 = { version = "0.13.3", optional = true } -sm3 = { version = "0.4.2", optional = true } -digest = { version = "0.10.7", optional = true } -signature = { version = "2.2.0", features = ["std"], optional = true } +p192 = { version = "0.14.0-rc.15", optional = true } +p224 = { version = "0.14.0-rc.15", optional = true } +p256 = { version = "0.14.0-rc.15", optional = true } +p384 = { version = "0.14.0-rc.15", optional = true } +p521 = { version = "0.14.0-rc.15", optional = true } +pkcs8 = { version = "0.11", optional = true } +rsa = { version = "0.10.0-rc.18", optional = true } +sha1 = { version = "0.11", optional = true } +sha2 = { version = "0.11", optional = true } +sha3 = { version = "0.12", optional = true } +sm2 = { version = "0.14.0-rc.15", optional = true } +sm3 = { version = "0.5", optional = true } +digest = { version = "0.11.1", optional = true } +signature = { version = "3", features = [ + "alloc", + "digest", +], optional = true } cfg-if = "1.0.0" strum = { version = "0.28.0", optional = true } strum_macros = { version = "0.28.0", optional = true } paste = "1.0.14" -getrandom = "0.2.11" +getrandom = "0.4.0" [dev-dependencies] assert_fs = "1.1.3" env_logger = "0.11.5" serde_json = "^1.0.108" -sha2 = { version = "0.10.8", features = ["oid"] } +sha2 = { version = "0.11", features = ["oid"] } socket2 = "0.6.3" tss-esapi = { path = ".", features = [ "integration-tests", @@ -77,7 +78,9 @@ tss-esapi = { path = ".", features = [ "abstraction", "rustcrypto-full", ] } -x509-cert = { version = "0.2.0", features = ["builder"] } +p256 = { version = "0.14.0-rc.15", features = ["ecdh"] } +rand = "0.10" +x509-cert = { version = "0.3.0-rc.4", features = ["builder"] } [build-dependencies] semver = "1.0.7" diff --git a/tss-esapi/src/abstraction/no_tpm/quote.rs b/tss-esapi/src/abstraction/no_tpm/quote.rs index 974b61bca..22aac1f5f 100644 --- a/tss-esapi/src/abstraction/no_tpm/quote.rs +++ b/tss-esapi/src/abstraction/no_tpm/quote.rs @@ -13,19 +13,16 @@ use digest::{Digest, DynDigest}; #[cfg(any(feature = "p224", feature = "p256", feature = "p384"))] use crate::{abstraction::public::AssociatedTpmCurve, structures::EccSignature}; #[cfg(any(feature = "p224", feature = "p256", feature = "p384"))] -use ecdsa::{ - PrimeCurve, SignatureSize, VerifyingKey, - hazmat::{DigestPrimitive, VerifyPrimitive}, -}; +use ecdsa::{DigestAlgorithm, PrimeCurve, SignatureSize, VerifyingKey}; #[cfg(any(feature = "p224", feature = "p256", feature = "p384"))] use elliptic_curve::{ CurveArithmetic, FieldBytesSize, - generic_array::ArrayLength, + array::ArraySize, point::AffinePoint, - sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint}, + sec1::{FromSec1Point, ModulusSize, ToSec1Point}, }; #[cfg(any(feature = "p224", feature = "p256", feature = "p384"))] -use signature::hazmat::PrehashVerifier; +use signature::DigestVerifier; #[cfg(feature = "rsa")] use rsa::{RsaPublicKey, pkcs1v15, pss}; @@ -40,9 +37,9 @@ fn verify_ecdsa( hashing_algorithm: HashingAlgorithm, ) -> Result where - C: PrimeCurve + CurveArithmetic + DigestPrimitive + AssociatedTpmCurve, - AffinePoint: VerifyPrimitive + FromEncodedPoint + ToEncodedPoint, - SignatureSize: ArrayLength, + C: PrimeCurve + CurveArithmetic + DigestAlgorithm + AssociatedTpmCurve, + AffinePoint: FromSec1Point + ToSec1Point, + SignatureSize: ArraySize, FieldBytesSize: ModulusSize, { let Ok(signature) = ecdsa::Signature::::try_from(signature) else { @@ -56,25 +53,45 @@ where match hashing_algorithm { #[cfg(feature = "sha1")] - HashingAlgorithm::Sha1 => { - let hash = sha1::Sha1::digest(message); - Ok(verifying_key.verify_prehash(&hash, &signature).is_ok()) - } + HashingAlgorithm::Sha1 => Ok(verifying_key + .verify_digest( + |d: &mut sha1::Sha1| { + Digest::update(d, message); + Ok(()) + }, + &signature, + ) + .is_ok()), #[cfg(feature = "sha2")] - HashingAlgorithm::Sha256 => { - let hash = sha2::Sha256::digest(message); - Ok(verifying_key.verify_prehash(&hash, &signature).is_ok()) - } + HashingAlgorithm::Sha256 => Ok(verifying_key + .verify_digest( + |d: &mut sha2::Sha256| { + Digest::update(d, message); + Ok(()) + }, + &signature, + ) + .is_ok()), #[cfg(feature = "sha2")] - HashingAlgorithm::Sha384 => { - let hash = sha2::Sha384::digest(message); - Ok(verifying_key.verify_prehash(&hash, &signature).is_ok()) - } + HashingAlgorithm::Sha384 => Ok(verifying_key + .verify_digest( + |d: &mut sha2::Sha384| { + Digest::update(d, message); + Ok(()) + }, + &signature, + ) + .is_ok()), #[cfg(feature = "sha2")] - HashingAlgorithm::Sha512 => { - let hash = sha2::Sha512::digest(message); - Ok(verifying_key.verify_prehash(&hash, &signature).is_ok()) - } + HashingAlgorithm::Sha512 => Ok(verifying_key + .verify_digest( + |d: &mut sha2::Sha512| { + Digest::update(d, message); + Ok(()) + }, + &signature, + ) + .is_ok()), _ => Err(Error::WrapperError(WrapperErrorKind::UnsupportedParam)), } } diff --git a/tss-esapi/src/abstraction/public.rs b/tss-esapi/src/abstraction/public.rs index 8a83cab27..99ad7d55c 100644 --- a/tss-esapi/src/abstraction/public.rs +++ b/tss-esapi/src/abstraction/public.rs @@ -9,8 +9,8 @@ use crate::{Error, WrapperErrorKind}; use core::convert::TryFrom; use elliptic_curve::{ AffinePoint, CurveArithmetic, FieldBytesSize, PublicKey, - generic_array::typenum::Unsigned, - sec1::{EncodedPoint, FromEncodedPoint, ModulusSize, ToEncodedPoint}, + array::typenum::Unsigned, + sec1::{FromSec1Point, ModulusSize, Sec1Point, ToSec1Point}, }; use x509_cert::spki::SubjectPublicKeyInfoOwned; @@ -18,7 +18,7 @@ use x509_cert::spki::SubjectPublicKeyInfoOwned; #[cfg(feature = "rsa")] use { crate::structures::RsaExponent, - rsa::{BigUint, RsaPublicKey}, + rsa::{BoxedUint, RsaPublicKey}, }; #[cfg(any( @@ -41,7 +41,7 @@ impl TryFrom<&Public> for PublicKey where C: CurveArithmetic + AssociatedTpmCurve, FieldBytesSize: ModulusSize, - AffinePoint: FromEncodedPoint + ToEncodedPoint, + AffinePoint: FromSec1Point + ToSec1Point, { type Error = Error; @@ -57,15 +57,13 @@ where let x = unique.x().as_bytes(); let y = unique.y().as_bytes(); - if x.len() != FieldBytesSize::::USIZE { - return Err(Error::local_error(WrapperErrorKind::InvalidParam)); - } - if y.len() != FieldBytesSize::::USIZE { - return Err(Error::local_error(WrapperErrorKind::InvalidParam)); - } - - let encoded_point = - EncodedPoint::::from_affine_coordinates(x.into(), y.into(), false); + let encoded_point = Sec1Point::::from_affine_coordinates( + x.try_into() + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?, + y.try_into() + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?, + false, + ); let public_key = PublicKey::::try_from(&encoded_point) .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?; @@ -86,10 +84,10 @@ impl TryFrom<&Public> for RsaPublicKey { unique, parameters, .. } => { let exponent = match parameters.exponent() { - RsaExponent::ZERO_EXPONENT => BigUint::from(RSA_DEFAULT_EXP), - _ => BigUint::from(parameters.exponent().value()), + RsaExponent::ZERO_EXPONENT => BoxedUint::from(RSA_DEFAULT_EXP), + _ => BoxedUint::from(parameters.exponent().value()), }; - let modulus = BigUint::from_bytes_be(unique.as_bytes()); + let modulus = BoxedUint::from_be_slice_vartime(unique.as_bytes()); let public_key = RsaPublicKey::new(modulus, exponent) .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?; @@ -163,7 +161,7 @@ impl TryFrom<&TpmPublicKey> for PublicKey where C: CurveArithmetic + AssociatedTpmCurve, FieldBytesSize: ModulusSize, - AffinePoint: FromEncodedPoint + ToEncodedPoint, + AffinePoint: FromSec1Point + ToSec1Point, { type Error = Error; @@ -173,8 +171,6 @@ where let x = x.as_slice(); let y = y.as_slice(); - // TODO: When elliptic_curve bumps to 0.14, we can use the TryFrom implementation instead - // of checking lengths manually if x.len() != FieldBytesSize::::USIZE { return Err(Error::local_error(WrapperErrorKind::InvalidParam)); } @@ -182,8 +178,14 @@ where return Err(Error::local_error(WrapperErrorKind::InvalidParam)); } - let encoded_point = - EncodedPoint::::from_affine_coordinates(x.into(), y.into(), false); + let encoded_point = Sec1Point::::from_affine_coordinates( + x.try_into() + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?, + y.try_into() + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?, + false, + ); + let public_key = PublicKey::::try_from(&encoded_point) .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?; @@ -201,8 +203,8 @@ impl TryFrom<&TpmPublicKey> for RsaPublicKey { fn try_from(value: &TpmPublicKey) -> Result { match value { TpmPublicKey::Rsa(modulus) => { - let exponent = BigUint::from(RSA_DEFAULT_EXP); - let modulus = BigUint::from_bytes_be(modulus.as_slice()); + let exponent = BoxedUint::from(RSA_DEFAULT_EXP); + let modulus = BoxedUint::from_be_slice_vartime(modulus.as_slice()); let public_key = RsaPublicKey::new(modulus, exponent) .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?; diff --git a/tss-esapi/src/abstraction/signatures.rs b/tss-esapi/src/abstraction/signatures.rs index 6f366f999..3ba64929a 100644 --- a/tss-esapi/src/abstraction/signatures.rs +++ b/tss-esapi/src/abstraction/signatures.rs @@ -8,16 +8,16 @@ use crate::{ use std::convert::TryFrom; -use ecdsa::SignatureSize; +use ecdsa::{EcdsaCurve, SignatureSize}; use elliptic_curve::{ FieldBytes, FieldBytesSize, PrimeCurve, - generic_array::{ArrayLength, typenum::Unsigned}, + array::{ArraySize, typenum::Unsigned}, }; impl TryFrom<&EccSignature> for ecdsa::Signature where - C: PrimeCurve, - SignatureSize: ArrayLength, + C: PrimeCurve + EcdsaCurve, + SignatureSize: ArraySize, { type Error = Error; @@ -33,8 +33,12 @@ where } let signature = ecdsa::Signature::from_scalars( - FieldBytes::::clone_from_slice(r), - FieldBytes::::clone_from_slice(s), + FieldBytes::::try_from(r) + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))? + .clone(), + FieldBytes::::try_from(s) + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))? + .clone(), ) .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?; Ok(signature) @@ -43,8 +47,8 @@ where impl TryFrom<&Signature> for ecdsa::Signature where - C: PrimeCurve, - SignatureSize: ArrayLength, + C: PrimeCurve + EcdsaCurve, + SignatureSize: ArraySize, { type Error = Error; diff --git a/tss-esapi/src/abstraction/signer.rs b/tss-esapi/src/abstraction/signer.rs index 121dbe434..b0da5df18 100644 --- a/tss-esapi/src/abstraction/signer.rs +++ b/tss-esapi/src/abstraction/signer.rs @@ -23,15 +23,14 @@ use std::{convert::TryFrom, ops::Add, sync::Mutex}; use digest::{Digest, FixedOutput, Output}; use ecdsa::{ - Signature, SignatureSize, VerifyingKey, + DigestAlgorithm, EcdsaCurve, Signature, SignatureSize, VerifyingKey, der::{MaxOverhead, MaxSize, Signature as DerSignature}, - hazmat::{DigestPrimitive, SignPrimitive}, }; use elliptic_curve::{ AffinePoint, CurveArithmetic, FieldBytesSize, PrimeCurve, PublicKey, Scalar, - generic_array::ArrayLength, + array::ArraySize, ops::Invert, - sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint}, + sec1::{FromSec1Point, ModulusSize, ToSec1Point}, subtle::CtOption, }; use log::error; @@ -139,7 +138,7 @@ impl TpmSigner #[derive(Debug)] pub struct EcSigner where - C: PrimeCurve + CurveArithmetic, + C: PrimeCurve + CurveArithmetic + EcdsaCurve, { context: Ctx, verifying_key: VerifyingKey, @@ -147,10 +146,10 @@ where impl EcSigner where - C: PrimeCurve + CurveArithmetic, + C: PrimeCurve + CurveArithmetic + EcdsaCurve, C: AssociatedTpmCurve, FieldBytesSize: ModulusSize, - AffinePoint: FromEncodedPoint + ToEncodedPoint, + AffinePoint: FromSec1Point + ToSec1Point, Ctx: TpmSigner, { pub fn new(context: Ctx) -> Result { @@ -178,17 +177,17 @@ where impl EcSigner where - C: PrimeCurve + CurveArithmetic, + C: PrimeCurve + CurveArithmetic + EcdsaCurve, C: AssociatedTpmCurve, { - /// Key parameters for this curve, selected digest is the one selected by DigestPrimitive + /// Key parameters for this curve, selected digest is the one selected by DigestAlgorithm pub fn key_params_default() -> KeyParams where - C: DigestPrimitive, - ::Digest: FixedOutput>, - ::Digest: AssociatedHashingAlgorithm, + C: DigestAlgorithm, + ::Digest: FixedOutput, + ::Digest: AssociatedHashingAlgorithm, { - Self::key_params::<::Digest>() + Self::key_params::<::Digest>() } /// Key parameters for this curve @@ -198,7 +197,7 @@ where /// The hashing algorithm `D` is the digest that will be used for signatures (SHA-256, SHA3-256, ...). pub fn key_params() -> KeyParams where - D: FixedOutput>, + D: FixedOutput, D: AssociatedHashingAlgorithm, { KeyParams::Ecc { @@ -211,9 +210,9 @@ where impl AsRef> for EcSigner where - C: PrimeCurve + CurveArithmetic, - Scalar: Invert>> + SignPrimitive, - SignatureSize: ArrayLength, + C: PrimeCurve + CurveArithmetic + EcdsaCurve, + Scalar: Invert>>, + SignatureSize: ArraySize, { fn as_ref(&self) -> &VerifyingKey { &self.verifying_key @@ -222,25 +221,30 @@ where impl KeypairRef for EcSigner where - C: PrimeCurve + CurveArithmetic, - Scalar: Invert>> + SignPrimitive, - SignatureSize: ArrayLength, + C: PrimeCurve + CurveArithmetic + EcdsaCurve, + Scalar: Invert>>, + SignatureSize: ArraySize, { type VerifyingKey = VerifyingKey; } impl DigestSigner> for EcSigner where - C: PrimeCurve + CurveArithmetic, + C: PrimeCurve + CurveArithmetic + EcdsaCurve, C: AssociatedTpmCurve, - D: Digest + FixedOutput>, + D: Digest + FixedOutput, D: AssociatedHashingAlgorithm, - Scalar: Invert>> + SignPrimitive, - SignatureSize: ArrayLength, + Scalar: Invert>>, + SignatureSize: ArraySize, TpmDigest: From>, Ctx: TpmSigner, { - fn try_sign_digest(&self, digest: D) -> Result, SigError> { + fn try_sign_digest Result<(), SigError>>( + &self, + f: F, + ) -> Result, SigError> { + let mut digest = D::new(); + f(&mut digest)?; let digest = TpmDigest::from(digest.finalize_fixed()); //let key_params = Self::key_params::(); @@ -260,60 +264,69 @@ where impl DigestSigner> for EcSigner where - C: PrimeCurve + CurveArithmetic, + C: PrimeCurve + CurveArithmetic + EcdsaCurve, C: AssociatedTpmCurve, - D: Digest + FixedOutput>, + D: Digest + FixedOutput, D: AssociatedHashingAlgorithm, - Scalar: Invert>> + SignPrimitive, - SignatureSize: ArrayLength, + Scalar: Invert>>, + SignatureSize: ArraySize, TpmDigest: From>, - MaxSize: ArrayLength, - as Add>::Output: Add + ArrayLength, + MaxSize: ArraySize, + as Add>::Output: Add + ArraySize, Ctx: TpmSigner, { - fn try_sign_digest(&self, digest: D) -> Result, SigError> { - let signature: Signature<_> = self.try_sign_digest(digest)?; + fn try_sign_digest Result<(), SigError>>( + &self, + f: F, + ) -> Result, SigError> { + let signature: Signature<_> = self.try_sign_digest(f)?; Ok(signature.to_der()) } } impl Signer> for EcSigner where - C: PrimeCurve + CurveArithmetic + DigestPrimitive, + C: PrimeCurve + CurveArithmetic + EcdsaCurve + DigestAlgorithm, C: AssociatedTpmCurve, - ::Digest: AssociatedHashingAlgorithm, - Scalar: Invert>> + SignPrimitive, - SignatureSize: ArrayLength, - TpmDigest: From::Digest>>, + ::Digest: AssociatedHashingAlgorithm + FixedOutput, + Scalar: Invert>>, + SignatureSize: ArraySize, + TpmDigest: From::Digest>>, Ctx: TpmSigner, { fn try_sign(&self, msg: &[u8]) -> Result, SigError> { - self.try_sign_digest(C::Digest::new_with_prefix(msg)) + self.try_sign_digest(|d: &mut C::Digest| { + Digest::update(d, msg); + Ok(()) + }) } } impl Signer> for EcSigner where - C: PrimeCurve + CurveArithmetic + DigestPrimitive, + C: PrimeCurve + CurveArithmetic + EcdsaCurve + DigestAlgorithm, C: AssociatedTpmCurve, - ::Digest: AssociatedHashingAlgorithm, - Scalar: Invert>> + SignPrimitive, - SignatureSize: ArrayLength, - TpmDigest: From::Digest>>, - MaxSize: ArrayLength, - as Add>::Output: Add + ArrayLength, + ::Digest: AssociatedHashingAlgorithm + FixedOutput, + Scalar: Invert>>, + SignatureSize: ArraySize, + TpmDigest: From::Digest>>, + MaxSize: ArraySize, + as Add>::Output: Add + ArraySize, Ctx: TpmSigner, { fn try_sign(&self, msg: &[u8]) -> Result, SigError> { - self.try_sign_digest(C::Digest::new_with_prefix(msg)) + self.try_sign_digest(|d: &mut C::Digest| { + Digest::update(d, msg); + Ok(()) + }) } } impl SignatureAlgorithmIdentifier for EcSigner where - C: PrimeCurve + CurveArithmetic, - Scalar: Invert>> + SignPrimitive, - SignatureSize: ArrayLength, + C: PrimeCurve + CurveArithmetic + EcdsaCurve, + Scalar: Invert>>, + SignatureSize: ArraySize, Signature: AssociatedAlgorithmIdentifier>, { type Params = AnyRef<'static>; @@ -440,7 +453,12 @@ mod rsa { TpmDigest: From>, Ctx: TpmSigner, { - fn try_sign_digest(&self, digest: D) -> Result { + fn try_sign_digest Result<(), SigError>>( + &self, + f: F, + ) -> Result { + let mut digest = D::new(); + f(&mut digest)?; let digest = TpmDigest::from(digest.finalize_fixed()); //let key_params = Self::key_params::(); @@ -461,10 +479,10 @@ mod rsa { Ctx: TpmSigner, { fn try_sign(&self, msg: &[u8]) -> Result { - let mut d = D::new(); - Digest::update(&mut d, msg); - - self.try_sign_digest(d) + self.try_sign_digest(|d: &mut D| { + Digest::update(d, msg); + Ok(()) + }) } } @@ -570,7 +588,12 @@ mod rsa { TpmDigest: From>, Ctx: TpmSigner, { - fn try_sign_digest(&self, digest: D) -> Result { + fn try_sign_digest Result<(), SigError>>( + &self, + f: F, + ) -> Result { + let mut digest = D::new(); + f(&mut digest)?; let digest = TpmDigest::from(digest.finalize_fixed()); let signature = self.context.sign(digest).map_err(SigError::from_source)?; @@ -589,10 +612,10 @@ mod rsa { Ctx: TpmSigner, { fn try_sign(&self, msg: &[u8]) -> Result { - let mut d = D::new(); - Digest::update(&mut d, msg); - - self.try_sign_digest(d) + self.try_sign_digest(|d: &mut D| { + Digest::update(d, msg); + Ok(()) + }) } } diff --git a/tss-esapi/src/abstraction/transient/mod.rs b/tss-esapi/src/abstraction/transient/mod.rs index a625702f7..f061ca5b3 100644 --- a/tss-esapi/src/abstraction/transient/mod.rs +++ b/tss-esapi/src/abstraction/transient/mod.rs @@ -154,7 +154,7 @@ impl TransientKeyContext { let key_auth = if auth_size > 0 { self.set_session_attrs()?; let mut random_bytes = vec![0u8; auth_size]; - getrandom::getrandom(&mut random_bytes).map_err(|_| { + getrandom::fill(&mut random_bytes).map_err(|_| { log::error!("Failed to obtain a random authvalue for key creation"); Error::WrapperError(ErrorKind::InternalError) })?; @@ -671,7 +671,7 @@ impl TransientKeyContextBuilder { let root_key_auth = if self.root_key_auth_size > 0 { let mut random = vec![0u8; self.root_key_auth_size]; - getrandom::getrandom(&mut random).map_err(|_| { + getrandom::fill(&mut random).map_err(|_| { log::error!("Failed to obtain a random value for root key authentication"); Error::WrapperError(ErrorKind::InternalError) })?; diff --git a/tss-esapi/src/context/tpm_commands/asymmetric_primitives.rs b/tss-esapi/src/context/tpm_commands/asymmetric_primitives.rs index 905a7e696..32a162b7e 100644 --- a/tss-esapi/src/context/tpm_commands/asymmetric_primitives.rs +++ b/tss-esapi/src/context/tpm_commands/asymmetric_primitives.rs @@ -87,7 +87,7 @@ impl Context { /// # .expect("Failed to set attributes on session"); /// # context.set_sessions((Some(session), None, None)); /// # let mut random_digest = vec![0u8; 16]; - /// # getrandom::getrandom(&mut random_digest).unwrap(); + /// # getrandom::fill(&mut random_digest).unwrap(); /// # let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); /// # /// # let object_attributes = ObjectAttributesBuilder::new() @@ -248,7 +248,7 @@ impl Context { /// # .expect("Failed to set attributes on session"); /// # context.set_sessions((Some(session), None, None)); /// # let mut random_digest = vec![0u8; 16]; - /// # getrandom::getrandom(&mut random_digest).unwrap(); + /// # getrandom::fill(&mut random_digest).unwrap(); /// # let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); /// # /// # let object_attributes = ObjectAttributesBuilder::new() @@ -370,6 +370,7 @@ impl Context { /// # RsaDecryptionScheme, HashScheme, SymmetricDefinition, /// # }, /// # }; + /// # use rand::Rng; /// # use std::{env, str::FromStr, convert::TryFrom}; /// # // Create context /// # let mut context = @@ -396,7 +397,8 @@ impl Context { /// # .expect("Failed to set attributes on session"); /// # context.set_sessions((Some(session), None, None)); /// # let mut random_digest = vec![0u8; 16]; - /// # getrandom::getrandom(&mut random_digest).unwrap(); + /// # let mut rng = rand::rng(); + /// # rng.fill_bytes(&mut random_digest); /// # let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); /// # /// // Create a key suitable for ECDH key generation @@ -506,6 +508,7 @@ impl Context { /// # RsaDecryptionScheme, HashScheme, SymmetricDefinition, /// # }, /// # }; + /// # use rand::Rng; /// # use std::{env, str::FromStr, convert::TryFrom}; /// # // Create context /// # let mut context = @@ -532,7 +535,8 @@ impl Context { /// # .expect("Failed to set attributes on session"); /// # context.set_sessions((Some(session), None, None)); /// # let mut random_digest = vec![0u8; 16]; - /// # getrandom::getrandom(&mut random_digest).unwrap(); + /// # let mut rng = rand::rng(); + /// # rng.fill_bytes(&mut random_digest); /// # let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); /// # /// // Create a key suitable for ECDH key generation @@ -716,7 +720,7 @@ impl Context { /// # .expect("Failed to set attributes on session"); /// # context.set_sessions((Some(session), None, None)); /// # let mut random_digest = vec![0u8; 16]; - /// # getrandom::getrandom(&mut random_digest).expect("Failed to get random bytes"); + /// # getrandom::fill(&mut random_digest).expect("Failed to get random bytes"); /// # let key_auth = Auth::from_bytes(random_digest.as_slice()).expect("Failed to create key auth"); /// # /// # let ecc_parms = PublicEccParametersBuilder::new() diff --git a/tss-esapi/src/context/tpm_commands/context_management.rs b/tss-esapi/src/context/tpm_commands/context_management.rs index 4f7e9b30a..074bd2c0e 100644 --- a/tss-esapi/src/context/tpm_commands/context_management.rs +++ b/tss-esapi/src/context/tpm_commands/context_management.rs @@ -108,7 +108,7 @@ impl Context { /// // Execute context methods using the session /// context.execute_with_session(Some(session), |ctx| { /// let mut random_digest = vec![0u8; 16]; - /// getrandom::getrandom(&mut random_digest).expect("Call to getrandom failed"); + /// getrandom::fill(&mut random_digest).expect("Call to getrandom failed"); /// let key_auth = Auth::from_bytes(random_digest.as_slice()).expect("Failed to create Auth"); /// let key_handle = ctx /// .create_primary( diff --git a/tss-esapi/src/context/tpm_commands/ephemeral_ec_keys.rs b/tss-esapi/src/context/tpm_commands/ephemeral_ec_keys.rs index 5a0bfd286..6aa1bf8d2 100644 --- a/tss-esapi/src/context/tpm_commands/ephemeral_ec_keys.rs +++ b/tss-esapi/src/context/tpm_commands/ephemeral_ec_keys.rs @@ -78,7 +78,7 @@ impl Context { /// # .expect("Failed to set attributes on session"); /// # context.set_sessions((Some(session), None, None)); /// # let mut random_digest = vec![0u8; 16]; - /// # getrandom::getrandom(&mut random_digest).expect("Failed to get random bytes"); + /// # getrandom::fill(&mut random_digest).expect("Failed to get random bytes"); /// # let key_auth /// # = Auth::from_bytes(random_digest.as_slice()).expect("Failed to create key auth"); /// # diff --git a/tss-esapi/src/context/tpm_commands/symmetric_primitives.rs b/tss-esapi/src/context/tpm_commands/symmetric_primitives.rs index 49bbb9cd0..adf1d533f 100644 --- a/tss-esapi/src/context/tpm_commands/symmetric_primitives.rs +++ b/tss-esapi/src/context/tpm_commands/symmetric_primitives.rs @@ -57,7 +57,7 @@ impl Context { /// # .expect("Failed to set auth to empty for owner"); /// # // Create primary key auth /// # let mut random_digest = vec![0u8; 16]; - /// # getrandom::getrandom(&mut random_digest).expect("get_rand call failed"); + /// # getrandom::fill(&mut random_digest).expect("get_rand call failed"); /// # let primary_key_auth = Auth::from_bytes( /// # random_digest /// # .as_slice() @@ -103,7 +103,7 @@ impl Context { /// # .expect("Failed to create public for symmetric key public"); /// # // Create auth for the symmetric key /// # let mut random_digest = vec![0u8; 16]; - /// # getrandom::getrandom(&mut random_digest).expect("get_rand call failed"); + /// # getrandom::fill(&mut random_digest).expect("get_rand call failed"); /// # let symmetric_key_auth = Auth::from_bytes( /// # random_digest /// # .as_slice() diff --git a/tss-esapi/src/structures/buffers.rs b/tss-esapi/src/structures/buffers.rs index 7e6ef094e..8734c83fa 100644 --- a/tss-esapi/src/structures/buffers.rs +++ b/tss-esapi/src/structures/buffers.rs @@ -225,8 +225,8 @@ pub mod digest { #[cfg(feature = "rustcrypto")] mod rustcrypto { use digest::{ + array::Array, consts::{U20, U32, U48, U64}, - generic_array::GenericArray, typenum::Unsigned, }; @@ -234,15 +234,15 @@ pub mod digest { macro_rules! impl_from_digest { ($($size:ty),+) => { - $(impl From> for Digest { - fn from(mut value: GenericArray) -> Self { + $(impl From> for Digest { + fn from(mut value: Array) -> Self { let value_as_vec = value.as_slice().to_vec(); value.zeroize(); Digest(value_as_vec.into()) } } - impl TryFrom for GenericArray { + impl TryFrom for Array { type Error = Error; fn try_from(value: Digest) -> Result { diff --git a/tss-esapi/tests/Cargo.lock.frozen b/tss-esapi/tests/Cargo.lock.frozen index c7bd8caf9..053ba13eb 100644 --- a/tss-esapi/tests/Cargo.lock.frozen +++ b/tss-esapi/tests/Cargo.lock.frozen @@ -4,18 +4,18 @@ version = 4 [[package]] name = "aho-corasick" -version = "1.1.2" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2969dcb958b36655471fc61f7e416fa76033bdd4bfed0678d8fee1e2d07a1f0" +checksum = "ddd31a130427c27518df266943a5308ed92d4b226cc639f5a8f1002816174301" dependencies = [ "memchr", ] [[package]] name = "anstream" -version = "0.6.19" +version = "0.6.21" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301af1932e46185686725e0fad2f8f2aa7da69dd70bf6ecc44d6b703844a3933" +checksum = "43d5b281e737544384e969a5ccad3f1cdd24b48086a0fc1b2a5262a26b8f4f4a" dependencies = [ "anstyle", "anstyle-parse", @@ -28,9 +28,9 @@ dependencies = [ [[package]] name = "anstyle" -version = "1.0.11" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "862ed96ca487e809f1c8e5a8447f6ee2cf102f846893800b20cebdf541fc6bbd" +checksum = "5192cca8006f1fd4f7237516f40fa183bb07f8fbdfedaa0036de5ea9b0b45e78" [[package]] name = "anstyle-parse" @@ -43,29 +43,49 @@ dependencies = [ [[package]] name = "anstyle-query" -version = "1.1.3" +version = "1.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c8bdeb6047d8983be085bab0ba1472e6dc604e7041dbf6fcd5e71523014fae9" +checksum = "40c48f72fd53cd289104fc64099abca73db4166ad86ea0b4341abe65af83dadc" dependencies = [ - "windows-sys 0.59.0", + "windows-sys 0.61.2", ] [[package]] name = "anstyle-wincon" -version = "3.0.9" +version = "3.0.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "403f75924867bb1033c59fbf0797484329750cfbe3c4325cd33127941fabc882" +checksum = "291e6a250ff86cd4a820112fb8898808a366d8f9f58ce16d1f538353ad55747d" dependencies = [ "anstyle", "once_cell_polyfill", - "windows-sys 0.59.0", + "windows-sys 0.61.2", +] + +[[package]] +name = "anyhow" +version = "1.0.102" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" + +[[package]] +name = "assert_fs" +version = "1.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ecf5c70ca07b7f80220bce936f0556a960ca6fb00fc2bd4125b5e581b218137" +dependencies = [ + "anstyle", + "globwalk", + "predicates", + "predicates-core", + "predicates-tree", + "tempfile", ] [[package]] name = "autocfg" -version = "1.1.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" [[package]] name = "autotools" @@ -78,15 +98,15 @@ dependencies = [ [[package]] name = "base16ct" -version = "0.2.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" +checksum = "fd307490d624467aa6f74b0eabb77633d1f758a7b25f12bceb0b22e08d9726f6" [[package]] name = "base64ct" -version = "1.8.0" +version = "1.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "55248b47b0caf0546f7988906588779981c43bb1bc9d0c44087278f80cdb44ba" +checksum = "2af50177e190e07a26ab74f8b1efbfe2ef87da2116221318cb1c2e82baf7de06" [[package]] name = "bindgen" @@ -130,31 +150,36 @@ dependencies = [ [[package]] name = "bitflags" -version = "2.4.2" +version = "2.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" +checksum = "812e12b5285cc515a9c72a5c1d3b6d46a19dac5acfef5265968c166106e31dd3" [[package]] name = "block-buffer" -version = "0.10.4" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" dependencies = [ - "generic-array", + "hybrid-array", ] [[package]] -name = "byteorder" -version = "1.5.0" +name = "bstr" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" +checksum = "63044e1ae8e69f3b5a92c736ca6269b8d12fa7efe39bf34ddb06d102cf0e2cab" +dependencies = [ + "memchr", + "serde", +] [[package]] name = "cc" -version = "1.2.32" +version = "1.2.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2352e5597e9c544d5e6d9c95190d5d27738ade584fa8db0a16e130e5c2b5296e" +checksum = "7a0aeaff4ff1a90589618835a598e545176939b97874f7abc7851caa0618f203" dependencies = [ + "find-msvc-tools", "shlex", ] @@ -173,17 +198,34 @@ version = "1.0.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801" +[[package]] +name = "chacha20" +version = "0.10.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d524456ba66e72eb8b115ff89e01e497f8e6d11d78b70b1aa13c0fbd97540a81" +dependencies = [ + "cfg-if", + "cpufeatures", + "rand_core", +] + [[package]] name = "clang-sys" -version = "1.7.0" +version = "1.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" +checksum = "0b023947811758c97c59bf9d1c188fd619ad4718dcaa767947df1cadb14f39f4" dependencies = [ "glob", "libc", "libloading", ] +[[package]] +name = "cmov" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3f88a43d011fc4a6876cb7344703e297c71dda42494fee094d5f7c76bf13f746" + [[package]] name = "colorchoice" version = "1.0.4" @@ -192,46 +234,103 @@ checksum = "b05b61dc5112cbb17e4b6cd61790d9845d13888356391624cbe7e41efeac1e75" [[package]] name = "const-oid" -version = "0.9.6" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a6ef517f0926dd24a1582492c791b6a4818a4d94e789a334894aa15b0d12f55c" + +[[package]] +name = "cpubits" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" +checksum = "5ef0c543070d296ea414df2dd7625d1b24866ce206709d8a4a424f28377f5861" [[package]] name = "cpufeatures" -version = "0.2.12" +version = "0.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53fe5e26ff1b7aef8bca9c6080520cfb8d9333c7568e1829cef191a9723e5504" +checksum = "8b2a41393f66f16b0823bb79094d54ac5fbd34ab292ddafb9a0456ac9f87d201" dependencies = [ "libc", ] +[[package]] +name = "crossbeam-deque" +version = "0.8.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9dd111b7b7f7d55b72c0a6ae361660ee5853c9af73f70c3c2ef6858b950e2e51" +dependencies = [ + "crossbeam-epoch", + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.9.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b82ac4a3c2ca9c3460964f020e1402edd5753411d7737aa39c3714ad1b5420e" +dependencies = [ + "crossbeam-utils", +] + +[[package]] +name = "crossbeam-utils" +version = "0.8.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d0a5c400df2834b80a4c3327b3aad3a4c4cd4de0629063962b03235697506a28" + [[package]] name = "crypto-bigint" -version = "0.5.5" +version = "0.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +checksum = "1a52aa3fcda4e6302a9f48734f234d35d4721b96f8fe07d073f07ce9df4f0271" dependencies = [ - "generic-array", + "cpubits", + "ctutils", + "getrandom", + "hybrid-array", + "num-traits", "rand_core", + "serdect", "subtle", "zeroize", ] [[package]] name = "crypto-common" -version = "0.1.6" +version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +checksum = "ce6e4c961d6cd6c9a86db418387425e8bdeaf05b3c8bc1411e6dca4c252f1453" dependencies = [ - "generic-array", - "typenum", + "getrandom", + "hybrid-array", + "rand_core", +] + +[[package]] +name = "crypto-primes" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3633a51a39c69ebbaa4feaa694bd83d241e4093901c84a0963b19d9bb3f0cf8f" +dependencies = [ + "crypto-bigint", + "rand_core", +] + +[[package]] +name = "ctutils" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d5515a3834141de9eafb9717ad39eea8247b5674e6066c404e8c4b365d2a29e" +dependencies = [ + "cmov", + "subtle", ] [[package]] name = "der" -version = "0.7.10" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7c1832837b905bbfb5101e07cc24c8deddf52f93225eee6ead5f4d63d53ddcb" +checksum = "71fd89660b2dc699704064e59e9dba0147b903e85319429e131620d022be411b" dependencies = [ "const-oid", "der_derive", @@ -242,32 +341,38 @@ dependencies = [ [[package]] name = "der_derive" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8034092389675178f570469e6c3b0465d3d30b4505c294a6550db47f3c17ad18" +checksum = "59600e2c2d636fde9b65e99cc6445ac770c63d3628195ff39932b8d6d7409903" dependencies = [ "proc-macro2", "quote", "syn", ] +[[package]] +name = "difflib" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6184e33543162437515c2e2b48714794e37845ec9851711914eec9d308f6ebe8" + [[package]] name = "digest" -version = "0.10.7" +version = "0.11.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +checksum = "f1dd6dbb5841937940781866fa1281a1ff7bd3bf827091440879f9994983d5c2" dependencies = [ "block-buffer", "const-oid", "crypto-common", - "subtle", + "ctutils", ] [[package]] name = "ecdsa" -version = "0.16.9" +version = "0.17.0-rc.23" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +checksum = "dfa0176db12735e38bffeaa3c19ba4470216007496b2088632369bcee6eb5069" dependencies = [ "der", "digest", @@ -275,27 +380,29 @@ dependencies = [ "rfc6979", "signature", "spki", + "zeroize", ] [[package]] name = "either" -version = "1.10.0" +version = "1.15.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11157ac094ffbdde99aa67b23417ebdd801842852b500e395a45a9c0aac03e4a" +checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" [[package]] name = "elliptic-curve" -version = "0.13.8" +version = "0.14.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +checksum = "9d65aa39b3a5c1c9c1b745c9a019234bb7a21b77abcb4f4d266d706e2d577d65" dependencies = [ "base16ct", "crypto-bigint", + "crypto-common", "digest", "ff", - "generic-array", "group", "hkdf", + "hybrid-array", "pem-rfc7468", "pkcs8", "rand_core", @@ -306,18 +413,18 @@ dependencies = [ [[package]] name = "enumflags2" -version = "0.7.9" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3278c9d5fb675e0a51dabcf4c0d355f692b064171535ba72361be1528a9d8e8d" +checksum = "1027f7680c853e056ebcec683615fb6fbbc07dbaa13b4d5d9442b146ded4ecef" dependencies = [ "enumflags2_derive", ] [[package]] name = "enumflags2_derive" -version = "0.7.9" +version = "0.7.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5c785274071b1b420972453b306eeca06acf4633829db4223b58a2a8c5953bc4" +checksum = "67c78a4d8fdf9953a5c9d458f9efe940fd97a0cab0941c075a813ac594733827" dependencies = [ "proc-macro2", "quote", @@ -326,9 +433,9 @@ dependencies = [ [[package]] name = "env_filter" -version = "0.1.3" +version = "0.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "186e05a59d4c50738528153b83b0b0194d3a29507dfec16eccd4b342903397d0" +checksum = "1bf3c259d255ca70051b30e2e95b5446cdb8949ac4cd22c0d7fd634d89f568e2" dependencies = [ "log", "regex", @@ -347,16 +454,50 @@ dependencies = [ "log", ] +[[package]] +name = "equivalent" +version = "1.0.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" + +[[package]] +name = "errno" +version = "0.3.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] + +[[package]] +name = "fastrand" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6" + [[package]] name = "ff" -version = "0.13.1" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b50bfb653653f9ca9095b427bed08ab8d75a137839d9ad64eb11810d5b6393" +checksum = "a1f686ab92a9fb0eaf188f6c6c87b89490baa6fdb0db4544ba4dc47f7942489f" dependencies = [ "rand_core", "subtle", ] +[[package]] +name = "fiat-crypto" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "64cd1e32ddd350061ae6edb1b082d7c54915b5c672c389143b9a63403a109f24" + +[[package]] +name = "find-msvc-tools" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "645cbb3a84e60b7531617d5ae4e57f7e27308f6445f5abf653209ea76dec8dff" + [[package]] name = "flagset" version = "0.4.7" @@ -364,44 +505,81 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b7ac824320a75a52197e8f2d787f6a38b6718bb6897a35142d749af3c0e8f4fe" [[package]] -name = "generic-array" -version = "0.14.7" +name = "foldhash" +version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" -dependencies = [ - "typenum", - "version_check", - "zeroize", -] +checksum = "d9c4f5dac5e15c24eb999c26181a6ca40b39fe946cbe4c263c7209467bc83af2" [[package]] name = "getrandom" -version = "0.2.15" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c4567c8db10ae91089c99af84c68c38da3ec2f087c3f82960bcdbf3656b6f4d7" +checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" dependencies = [ "cfg-if", "libc", - "wasi", + "r-efi", + "rand_core", + "wasip2", + "wasip3", ] [[package]] name = "glob" -version = "0.3.1" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0cc23270f6e1808e30a928bdc84dea0b9b4136a8bc82338574f23baf47bbd280" + +[[package]] +name = "globset" +version = "0.4.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" +checksum = "52dfc19153a48bde0cbd630453615c8151bce3a5adfac7a0aebfbf0a1e1f57e3" +dependencies = [ + "aho-corasick", + "bstr", + "log", + "regex-automata", + "regex-syntax", +] + +[[package]] +name = "globwalk" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0bf760ebf69878d9fd8f110c89703d90ce35095324d1f1edcb595c63945ee757" +dependencies = [ + "bitflags", + "ignore", + "walkdir", +] [[package]] name = "group" -version = "0.13.0" +version = "0.14.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +checksum = "7fd1a1c7a5206c5b7a3f5a0d7ccd3ff85d0c8f5133d62a02680255b0004af5f4" dependencies = [ "ff", "rand_core", "subtle", ] +[[package]] +name = "hashbrown" +version = "0.15.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9229cfe53dfd69f0609a49f65461bd93001ea1ef889cd5529dd176593f5338a1" +dependencies = [ + "foldhash", +] + +[[package]] +name = "hashbrown" +version = "0.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4f467dd6dccf739c208452f8014c75c18bb8301b050ad1cfb27153803edb0f51" + [[package]] name = "heck" version = "0.5.0" @@ -410,18 +588,18 @@ checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" [[package]] name = "hkdf" -version = "0.12.4" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7b5f8eb2ad728638ea2c7d47a21db23b7b58a72ed6a38256b8a1849f15fbbdf7" +checksum = "4aaa26c720c68b866f2c96ef5c1264b3e6f473fe5d4ce61cd44bbe913e553018" dependencies = [ "hmac", ] [[package]] name = "hmac" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +checksum = "6303bc9732ae41b04cb554b844a762b4115a61bfaa81e3e83050991eeb56863f" dependencies = [ "digest", ] @@ -432,45 +610,90 @@ version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f558a64ac9af88b5ba400d99b579451af0d39c6d360980045b91aac966d705e2" +[[package]] +name = "hybrid-array" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "818356c5132c1fede50f837ca96afbe78ff42413047f4abb886217845e1b6c8c" +dependencies = [ + "subtle", + "typenum", + "zeroize", +] + +[[package]] +name = "id-arena" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" + +[[package]] +name = "ignore" +version = "0.4.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b915661dd01db3f05050265b2477bcc6527b3792388e2749b41623cc592be67d" +dependencies = [ + "crossbeam-deque", + "globset", + "log", + "memchr", + "regex-automata", + "same-file", + "walkdir", + "winapi-util", +] + +[[package]] +name = "indexmap" +version = "2.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9" +dependencies = [ + "equivalent", + "hashbrown 0.17.0", + "serde", + "serde_core", +] + [[package]] name = "is_terminal_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7943c866cc5cd64cbc25b2e01621d07fa8eb2a1a23160ee81ce38704e97b8ecf" +checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695" [[package]] name = "itertools" -version = "0.12.1" +version = "0.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ba291022dbbd398a455acf126c1e341954079855bc60dfdda641363bd6922569" +checksum = "413ee7dfc52ee1a4949ceeb7dbc8a33f2d6c088194d9f922fb8318faf1f01186" dependencies = [ "either", ] [[package]] name = "itoa" -version = "1.0.14" +version = "1.0.17" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d75a2a4b1b190afb6f5425f10f6a8f959d2ea0b9c2b1d79553551850539e4674" +checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2" [[package]] name = "jiff" -version = "0.2.14" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a194df1107f33c79f4f93d02c80798520551949d59dfad22b6157048a88cca93" +checksum = "e67e8da4c49d6d9909fe03361f9b620f58898859f5c7aded68351e85e71ecf50" dependencies = [ "jiff-static", "log", "portable-atomic", "portable-atomic-util", - "serde", + "serde_core", ] [[package]] name = "jiff-static" -version = "0.2.14" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6c6e1db7ed32c6c71b759497fae34bf7933636f75a251b9e736555da426f6442" +checksum = "e0c84ee7f197eca9a86c6fd6cb771e55eb991632f15f2bc3ca6ec838929e6e78" dependencies = [ "proc-macro2", "quote", @@ -479,21 +702,19 @@ dependencies = [ [[package]] name = "keccak" -version = "0.1.5" +version = "0.2.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ecc2af9a1119c51f12a14607e783cb977bde58bc069ff0c3da1095e635d70654" +checksum = "9e24a010dd405bd7ed803e5253182815b41bf2e6a80cc3bfc066658e03a198aa" dependencies = [ + "cfg-if", "cpufeatures", ] [[package]] -name = "lazy_static" -version = "1.5.0" +name = "leb128fmt" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" -dependencies = [ - "spin", -] +checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2" [[package]] name = "lenient_semver" @@ -537,31 +758,31 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.158" +version = "0.2.186" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d8adc4bb1803a324070e64a98ae98f38934d91957a99cfb3a43dcbc01bc56439" +checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66" [[package]] name = "libloading" -version = "0.8.1" +version = "0.8.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" +checksum = "d7c4b02199fee7c5d21a5ae7d8cfa79a6ef5bb2fc834d6e9058e89c825efdc55" dependencies = [ "cfg-if", - "windows-sys 0.48.0", + "windows-link", ] [[package]] -name = "libm" -version = "0.2.15" +name = "linux-raw-sys" +version = "0.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9fbbcab51052fe104eb5e5d351cf728d30a5be1fe14d9be8a3b097481fb97de" +checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53" [[package]] name = "log" -version = "0.4.21" +version = "0.4.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "90ed8c1e510134f979dbc4f070f87d4313098b704861a105fe34231c70a3901c" +checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" [[package]] name = "malloced" @@ -571,9 +792,9 @@ checksum = "6dfebb2f9e0b39509c62eead6ec7ae0c0ed45bb61d12bbcf4e976c566c5400ec" [[package]] name = "memchr" -version = "2.7.1" +version = "2.7.6" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "523dc4f511e55ab87b694dc30d0f820d60906ef06413f93d4d7a1385599cc149" +checksum = "f52b00d39961fc5b2736ea853c9cc86238e165017a493d1d5c8eac6bdc4cc273" [[package]] name = "minimal-lexical" @@ -602,23 +823,6 @@ dependencies = [ "minimal-lexical", ] -[[package]] -name = "num-bigint-dig" -version = "0.8.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" -dependencies = [ - "byteorder", - "lazy_static", - "libm", - "num-integer", - "num-iter", - "num-traits", - "rand", - "smallvec", - "zeroize", -] - [[package]] name = "num-derive" version = "0.4.2" @@ -631,100 +835,89 @@ dependencies = [ ] [[package]] -name = "num-integer" -version = "0.1.46" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" -dependencies = [ - "num-traits", -] - -[[package]] -name = "num-iter" -version = "0.1.45" +name = "num-traits" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1429034a0490724d0075ebb2bc9e875d6503c3cf69e235a8941aa757d83ef5bf" +checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" dependencies = [ "autocfg", - "num-integer", - "num-traits", ] [[package]] -name = "num-traits" -version = "0.2.18" +name = "once_cell" +version = "1.21.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" -dependencies = [ - "autocfg", - "libm", -] +checksum = "9f7c3e4beb33f85d45ae3e3a1792185706c8e16d043238c593331cc7cd313b50" [[package]] name = "once_cell_polyfill" -version = "1.70.1" +version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a4895175b425cb1f87721b59f0f286c2092bd4af812243672510e1ac53e2e0ad" +checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" [[package]] name = "p192" -version = "0.13.0" +version = "0.14.0-rc.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b0533bc6c238f2669aab8db75ae52879dc74e88d6bd3685bd4022a00fa85cd2" +checksum = "5a11179a6732903ba21ca35e91fc0bc9ef22ef7acfe6156a1ff2507eff10817a" dependencies = [ "ecdsa", "elliptic-curve", + "primefield", "primeorder", - "sec1", ] [[package]] name = "p224" -version = "0.13.2" +version = "0.14.0-rc.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "30c06436d66652bc2f01ade021592c80a2aad401570a18aa18b82e440d2b9aa1" +checksum = "85577801576d9ddd06276d905db79d25cb5faae34d89d896aa140d75a2ec324f" dependencies = [ "ecdsa", "elliptic-curve", + "primefield", "primeorder", "sha2", ] [[package]] name = "p256" -version = "0.13.2" +version = "0.14.0-rc.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +checksum = "b6bb40a5099e2c38a09dd29321a7a7f045f165a54317679c7cdfb0cbaf8f6b1e" dependencies = [ "ecdsa", "elliptic-curve", + "primefield", "primeorder", "sha2", ] [[package]] name = "p384" -version = "0.13.1" +version = "0.14.0-rc.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fe42f1670a52a47d448f14b6a5c61dd78fce51856e68edaa38f7ae3a46b8d6b6" +checksum = "492f329d7eb11d22dadc988626b9ea1f503b4ab043a8b1e4e2cc4ae45dabdd70" dependencies = [ "ecdsa", "elliptic-curve", + "fiat-crypto", + "primefield", "primeorder", "sha2", ] [[package]] name = "p521" -version = "0.13.3" +version = "0.14.0-rc.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fc9e2161f1f215afdfce23677034ae137bbd45016a880c2eb3ba8eb95f085b2" +checksum = "ff42e4ace5424e3b6d7cb82514be89866b85af87015f80341e37dcc21a66ce6e" dependencies = [ "base16ct", "ecdsa", "elliptic-curve", + "primefield", "primeorder", - "rand_core", "sha2", ] @@ -736,29 +929,28 @@ checksum = "57c0d7b74b563b49d38dae00a0c37d4d6de9b432382b2892f0574ddcae73fd0a" [[package]] name = "pem-rfc7468" -version = "0.7.0" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +checksum = "a6305423e0e7738146434843d1694d621cce767262b2a86910beab705e4493d9" dependencies = [ "base64ct", ] [[package]] name = "pkcs1" -version = "0.7.5" +version = "0.8.0-rc.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +checksum = "986d2e952779af96ea048f160fd9194e1751b4faea78bcf3ceb456efe008088e" dependencies = [ "der", - "pkcs8", "spki", ] [[package]] name = "pkcs8" -version = "0.10.2" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +checksum = "451913da69c775a56034ea8d9003d27ee8948e12443eae7c038ba100a4f21cb7" dependencies = [ "der", "spki", @@ -766,15 +958,15 @@ dependencies = [ [[package]] name = "pkg-config" -version = "0.3.32" +version = "0.3.33" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7edddbd0b52d732b21ad9a5fab5c704c14cd949e5e9a1ec5929a24fded1b904c" +checksum = "19f132c84eca552bf34cab8ec81f1c1dcc229b811638f9d283dceabe58c5569e" [[package]] name = "portable-atomic" -version = "1.11.1" +version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f84267b20a16ea918e43c6a88433c2d54fa145c92a811b5b047ccbe153674483" +checksum = "f89776e4d69bb58bc6993e99ffa1d11f228b839984854c7daeb5d37f87cbe950" [[package]] name = "portable-atomic-util" @@ -786,85 +978,115 @@ dependencies = [ ] [[package]] -name = "ppv-lite86" -version = "0.2.21" +name = "predicates" +version = "3.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ada8f2932f28a27ee7b70dd6c1c39ea0675c55a36879ab92f3a715eaa1e63cfe" +dependencies = [ + "anstyle", + "difflib", + "predicates-core", +] + +[[package]] +name = "predicates-core" +version = "1.0.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cad38746f3166b4031b1a0d39ad9f954dd291e7854fcc0eed52ee41a0b50d144" + +[[package]] +name = "predicates-tree" +version = "1.0.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "85eae3c4ed2f50dcfe72643da4befc30deadb458a9b590d720cde2f2b1e97da9" +checksum = "d0de1b847b39c8131db0467e9df1ff60e6d0562ab8e9a16e568ad0fdb372e2f2" dependencies = [ - "zerocopy", + "predicates-core", + "termtree", ] [[package]] name = "prettyplease" -version = "0.2.15" +version = "0.2.37" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ae005bd773ab59b4725093fd7df83fd7892f7d8eafb48dbd7de6e024e4215f9d" +checksum = "479ca8adacdd7ce8f1fb39ce9ecccbfe93a3f1344b3d0d97f20bc0196208f62b" dependencies = [ "proc-macro2", "syn", ] +[[package]] +name = "primefield" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c555a6e4eb7d4e158fcb028c835c3b8642206ddc279b5c6b202ef9a8bdb592f4" +dependencies = [ + "crypto-bigint", + "crypto-common", + "ff", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "primeorder" -version = "0.13.6" +version = "0.14.0-rc.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +checksum = "478aa2e499c7164b21b4c5e8610018e5b83a284da5f9e0896907dd4749cd76c9" dependencies = [ "elliptic-curve", + "once_cell", + "primefield", + "serdect", + "wnaf", ] [[package]] name = "proc-macro2" -version = "1.0.95" +version = "1.0.105" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" +checksum = "535d180e0ecab6268a3e718bb9fd44db66bbbc256257165fc699dadf70d16fe7" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.40" +version = "1.0.43" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" +checksum = "dc74d9a594b72ae6656596548f56f667211f8a97b3d4c3d467150794690dc40a" dependencies = [ "proc-macro2", ] [[package]] -name = "rand" -version = "0.8.5" +name = "r-efi" +version = "6.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" -dependencies = [ - "rand_chacha", - "rand_core", -] +checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf" [[package]] -name = "rand_chacha" -version = "0.3.1" +name = "rand" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207" dependencies = [ - "ppv-lite86", + "chacha20", + "getrandom", "rand_core", ] [[package]] name = "rand_core" -version = "0.6.4" +version = "0.10.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom", -] +checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69" [[package]] name = "regex" -version = "1.10.3" +version = "1.12.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62dbe01f0b06f9d8dc7d49e05a0785f153b00b2c227856282f671e0318c9b15" +checksum = "843bc0191f75f3e22651ae5f1e72939ab2f72a4bc30fa80a066bd66edefc24d4" dependencies = [ "aho-corasick", "memchr", @@ -874,9 +1096,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.4.5" +version = "0.4.13" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5bb987efffd3c6d0d8f5f89510bb458559eab11e4f869acb20bf845e016259cd" +checksum = "5276caf25ac86c8d810222b3dbb938e512c55c6831a10f3e6ed1c93b84041f1c" dependencies = [ "aho-corasick", "memchr", @@ -885,31 +1107,30 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.8.2" +version = "0.8.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +checksum = "7a2d987857b319362043e95f5353c0535c1f58eec5336fdfcf626430af7def58" [[package]] name = "rfc6979" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +checksum = "b4a459cddafb3fe76b31fd8f1108007566c40301feb64dc7b54656eb7388172b" dependencies = [ + "crypto-bigint", "hmac", - "subtle", ] [[package]] name = "rsa" -version = "0.9.8" +version = "0.10.0-rc.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "78928ac1ed176a5ca1d17e578a1825f3d81ca54cf41053a592584b020cfd691b" +checksum = "30b2aa4ba0d89f73d1e332df05be0eeab8840351c36ca5654341dfdb57bb3caf" dependencies = [ "const-oid", + "crypto-bigint", + "crypto-primes", "digest", - "num-bigint-dig", - "num-integer", - "num-traits", "pkcs1", "pkcs8", "rand_core", @@ -917,7 +1138,6 @@ dependencies = [ "sha2", "signature", "spki", - "subtle", "zeroize", ] @@ -928,21 +1148,37 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d" [[package]] -name = "ryu" -version = "1.0.18" +name = "rustix" +version = "1.1.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3cb5ba0dc43242ce17de99c180e96db90b235b8a9fdc9543c96d2209116bd9f" +checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190" +dependencies = [ + "bitflags", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.61.2", +] + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] [[package]] name = "sec1" -version = "0.7.3" +version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +checksum = "d56d437c2f19203ce5f7122e507831de96f3d2d4d3be5af44a0b0a09d8a80e4d" dependencies = [ "base16ct", + "ctutils", "der", - "generic-array", - "pkcs8", + "hybrid-array", "subtle", "zeroize", ] @@ -955,18 +1191,28 @@ checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" [[package]] name = "serde" -version = "1.0.210" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c8e3592472072e6e22e0a54d5904d9febf8508f65fb8552499a1abc7d1078c3a" +checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" +dependencies = [ + "serde_core", + "serde_derive", +] + +[[package]] +name = "serde_core" +version = "1.0.228" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41d385c7d4ca58e59fc732af25c3983b67ac852c1a25000afe1175de458b67ad" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.210" +version = "1.0.228" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "243902eda00fad750862fc144cea25caca5e20d615af0a81bee94ca738f1df1f" +checksum = "d540f220d3187173da220f885ab66608367b6574e925011a9353e4badda91d79" dependencies = [ "proc-macro2", "quote", @@ -975,21 +1221,32 @@ dependencies = [ [[package]] name = "serde_json" -version = "1.0.136" +version = "1.0.149" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "336a0c23cf42a38d9eaa7cd22c7040d04e1228a19a933890805ffd00a16437d2" +checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" dependencies = [ "itoa", "memchr", - "ryu", + "serde", + "serde_core", + "zmij", +] + +[[package]] +name = "serdect" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9af4a3e75ebd5599b30d4de5768e00b5095d518a79fefc3ecbaf77e665d1ec06" +dependencies = [ + "base16ct", "serde", ] [[package]] name = "sha1" -version = "0.10.6" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba" +checksum = "aacc4cc499359472b4abe1bf11d0b12e688af9a805fa5e3016f9a386dc2d0214" dependencies = [ "cfg-if", "cpufeatures", @@ -998,9 +1255,9 @@ dependencies = [ [[package]] name = "sha2" -version = "0.10.8" +version = "0.11.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +checksum = "446ba717509524cb3f22f17ecc096f10f4822d76ab5c0b9822c5f9c284e825f4" dependencies = [ "cfg-if", "cpufeatures", @@ -1009,12 +1266,13 @@ dependencies = [ [[package]] name = "sha3" -version = "0.10.8" +version = "0.12.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "75872d278a8f37ef87fa0ddbda7802605cb18344497949862c0d4dcb291eba60" +checksum = "bc9bad02c26382724b2d2692c6f179285e4b54eeecd7968f52a50059c3c11759" dependencies = [ "digest", "keccak", + "sponge-cursor", ] [[package]] @@ -1025,9 +1283,9 @@ checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" [[package]] name = "signature" -version = "2.2.0" +version = "3.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +checksum = "28d567dcbaf0049cb8ac2608a76cd95ff9e4412e1899d389ee400918ca7537f5" dependencies = [ "digest", "rand_core", @@ -1035,12 +1293,16 @@ dependencies = [ [[package]] name = "sm2" -version = "0.13.3" +version = "0.14.0-rc.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "98b22092ef242a118f03ee41dc46b2720c0ca076f544116dbc915cacf532cfaa" +checksum = "7363f4a0c854c1d753db638bac877a78a3ac7149d2218ae0cf09971338b40bd8" dependencies = [ + "der", "elliptic-curve", + "fiat-crypto", + "primefield", "primeorder", + "rand_core", "rfc6979", "signature", "sm3", @@ -1048,35 +1310,39 @@ dependencies = [ [[package]] name = "sm3" -version = "0.4.2" +version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ebb9a3b702d0a7e33bc4d85a14456633d2b165c2ad839c5fd9a8417c1ab15860" +checksum = "da6a89ba31723d185fd7413b98c576a575f356d9b84729d8ecb6ead60000a5b6" dependencies = [ "digest", ] [[package]] -name = "smallvec" -version = "1.15.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67b1b7a3b5fe4f1376887184045fcf45c69e92af734b7aaddc05fb777b6fbd03" - -[[package]] -name = "spin" -version = "0.9.8" +name = "socket2" +version = "0.6.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67" +checksum = "52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51" +dependencies = [ + "libc", + "windows-sys 0.61.2", +] [[package]] name = "spki" -version = "0.7.3" +version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +checksum = "1d9efca8738c78ee9484207732f728b1ef517bbb1833d6fc0879ca898a522f6f" dependencies = [ "base64ct", "der", ] +[[package]] +name = "sponge-cursor" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a0219bd7d979d58245a4f41f695e1ac9f8befdffadd7f61f1bae9e39abc6620" + [[package]] name = "strum" version = "0.28.0" @@ -1103,9 +1369,9 @@ checksum = "13c2bddecc57b384dee18652358fb23172facb8a2c51ccc10d74c157bdea3292" [[package]] name = "syn" -version = "2.0.101" +version = "2.0.114" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8ce2b7fc941b3a24138a0a7cf8e858bfc6a992e7978a068a5c760deb0ed43caf" +checksum = "d4d107df263a3013ef9b1879b0df87d706ff80f65a86ea879bd9c31f9b307c2a" dependencies = [ "proc-macro2", "quote", @@ -1118,11 +1384,29 @@ version = "0.13.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca" +[[package]] +name = "tempfile" +version = "3.27.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd" +dependencies = [ + "fastrand", + "once_cell", + "rustix", + "windows-sys 0.61.2", +] + +[[package]] +name = "termtree" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f50febec83f5ee1df3015341d8bd429f2d1cc62bcba7ea2076759d315084683" + [[package]] name = "tls_codec" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b5e78c9c330f8c85b2bae7c8368f2739157db9991235123aa1b15ef9502bfb6a" +checksum = "0de2e01245e2bb89d6f05801c564fa27624dbd7b1846859876c7dad82e90bf6b" dependencies = [ "tls_codec_derive", "zeroize", @@ -1130,9 +1414,9 @@ dependencies = [ [[package]] name = "tls_codec_derive" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8d9ef545650e79f30233c0003bcc2504d7efac6dad25fca40744de773fe2049c" +checksum = "2d2e76690929402faae40aebdda620a2c0e25dd6d3b9afe48867dfd95991f4bd" dependencies = [ "proc-macro2", "quote", @@ -1143,6 +1427,7 @@ dependencies = [ name = "tss-esapi" version = "8.0.0-alpha.2" dependencies = [ + "assert_fs", "bitfield", "cfg-if", "digest", @@ -1163,6 +1448,7 @@ dependencies = [ "p521", "paste", "pkcs8", + "rand", "regex", "rsa", "semver", @@ -1174,6 +1460,7 @@ dependencies = [ "signature", "sm2", "sm3", + "socket2", "strum", "strum_macros", "tss-esapi", @@ -1184,7 +1471,7 @@ dependencies = [ [[package]] name = "tss-esapi-sys" -version = "0.6.0-alpha.2" +version = "0.7.0-alpha.1" dependencies = [ "autotools", "bindgen", @@ -1197,15 +1484,21 @@ dependencies = [ [[package]] name = "typenum" -version = "1.17.0" +version = "1.20.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" +checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20" [[package]] name = "unicode-ident" -version = "1.0.12" +version = "1.0.22" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" +checksum = "9312f7c4f6ff9069b165498234ce8be658059c6728633667c526e27dc2cf1df5" + +[[package]] +name = "unicode-xid" +version = "0.2.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" [[package]] name = "utf8parse" @@ -1214,48 +1507,98 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "06abde3611657adf66d383f00b093d7faecc7fa57071cce2578660c9f1010821" [[package]] -name = "version_check" -version = "0.9.5" +name = "walkdir" +version = "2.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" +checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b" +dependencies = [ + "same-file", + "winapi-util", +] [[package]] -name = "wasi" -version = "0.11.0+wasi-snapshot-preview1" +name = "wasip2" +version = "1.0.1+wasi-0.2.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" +checksum = "0562428422c63773dad2c345a1882263bbf4d65cf3f42e90921f787ef5ad58e7" +dependencies = [ + "wit-bindgen 0.46.0", +] [[package]] -name = "windows-sys" -version = "0.48.0" +name = "wasip3" +version = "0.4.0+wasi-0.3.0-rc-2026-01-06" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" +dependencies = [ + "wit-bindgen 0.51.0", +] + +[[package]] +name = "wasm-encoder" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "990065f2fe63003fe337b932cfb5e3b80e0b4d0f5ff650e6985b1048f62c8319" +dependencies = [ + "leb128fmt", + "wasmparser", +] + +[[package]] +name = "wasm-metadata" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb0e353e6a2fbdc176932bbaab493762eb1255a7900fe0fea1a2f96c296cc909" +dependencies = [ + "anyhow", + "indexmap", + "wasm-encoder", + "wasmparser", +] + +[[package]] +name = "wasmparser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "47b807c72e1bac69382b3a6fb3dbe8ea4c0ed87ff5629b8685ae6b9a611028fe" +dependencies = [ + "bitflags", + "hashbrown 0.15.5", + "indexmap", + "semver", +] + +[[package]] +name = "winapi-util" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22" dependencies = [ - "windows-targets 0.48.5", + "windows-sys 0.61.2", ] +[[package]] +name = "windows-link" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5" + [[package]] name = "windows-sys" version = "0.59.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1e38bc4d79ed67fd075bcc251a1c39b32a1776bbe92e5bef1f0bf1f8c531853b" dependencies = [ - "windows-targets 0.52.6", + "windows-targets", ] [[package]] -name = "windows-targets" -version = "0.48.5" +name = "windows-sys" +version = "0.61.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +checksum = "ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc" dependencies = [ - "windows_aarch64_gnullvm 0.48.5", - "windows_aarch64_msvc 0.48.5", - "windows_i686_gnu 0.48.5", - "windows_i686_msvc 0.48.5", - "windows_x86_64_gnu 0.48.5", - "windows_x86_64_gnullvm 0.48.5", - "windows_x86_64_msvc 0.48.5", + "windows-link", ] [[package]] @@ -1264,46 +1607,28 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9b724f72796e036ab90c1021d4780d4d3d648aca59e491e6b98e725b84e99973" dependencies = [ - "windows_aarch64_gnullvm 0.52.6", - "windows_aarch64_msvc 0.52.6", - "windows_i686_gnu 0.52.6", + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", "windows_i686_gnullvm", - "windows_i686_msvc 0.52.6", - "windows_x86_64_gnu 0.52.6", - "windows_x86_64_gnullvm 0.52.6", - "windows_x86_64_msvc 0.52.6", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", ] -[[package]] -name = "windows_aarch64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" - [[package]] name = "windows_aarch64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "32a4622180e7a0ec044bb555404c800bc9fd9ec262ec147edd5989ccd0c02cd3" -[[package]] -name = "windows_aarch64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" - [[package]] name = "windows_aarch64_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09ec2a7bb152e2252b53fa7803150007879548bc709c039df7627cabbd05d469" -[[package]] -name = "windows_i686_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" - [[package]] name = "windows_i686_gnu" version = "0.52.6" @@ -1316,48 +1641,24 @@ version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0eee52d38c090b3caa76c563b86c3a4bd71ef1a819287c19d586d7334ae8ed66" -[[package]] -name = "windows_i686_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" - [[package]] name = "windows_i686_msvc" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "240948bc05c5e7c6dabba28bf89d89ffce3e303022809e73deaefe4f6ec56c66" -[[package]] -name = "windows_x86_64_gnu" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" - [[package]] name = "windows_x86_64_gnu" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "147a5c80aabfbf0c7d901cb5895d1de30ef2907eb21fbbab29ca94c5b08b1a78" -[[package]] -name = "windows_x86_64_gnullvm" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" - [[package]] name = "windows_x86_64_gnullvm" version = "0.52.6" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "24d5b23dc417412679681396f2b49f3de8c1473deb516bd34410872eff51ed0d" -[[package]] -name = "windows_x86_64_msvc" -version = "0.48.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" - [[package]] name = "windows_x86_64_msvc" version = "0.52.6" @@ -1375,55 +1676,146 @@ dependencies = [ ] [[package]] -name = "x509-cert" -version = "0.2.5" +name = "wit-bindgen" +version = "0.46.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f17a85883d4e6d00e8a97c586de764dabcc06133f7f1d55dce5cdc070ad7fe59" + +[[package]] +name = "wit-bindgen" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1301e935010a701ae5f8655edc0ad17c44bad3ac5ce8c39185f75453b720ae94" +checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5" dependencies = [ - "const-oid", - "der", - "sha1", - "signature", - "spki", - "tls_codec", + "wit-bindgen-rust-macro", +] + +[[package]] +name = "wit-bindgen-core" +version = "0.51.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ea61de684c3ea68cb082b7a88508a8b27fcc8b797d738bfc99a82facf1d752dc" +dependencies = [ + "anyhow", + "heck", + "wit-parser", ] [[package]] -name = "zerocopy" -version = "0.8.26" +name = "wit-bindgen-rust" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1039dd0d3c310cf05de012d8a39ff557cb0d23087fd44cad61df08fc31907a2f" +checksum = "b7c566e0f4b284dd6561c786d9cb0142da491f46a9fbed79ea69cdad5db17f21" dependencies = [ - "zerocopy-derive", + "anyhow", + "heck", + "indexmap", + "prettyplease", + "syn", + "wasm-metadata", + "wit-bindgen-core", + "wit-component", ] [[package]] -name = "zerocopy-derive" -version = "0.8.26" +name = "wit-bindgen-rust-macro" +version = "0.51.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9ecf5b4cc5364572d7f4c329661bcc82724222973f2cab6f050a4e5c22f75181" +checksum = "0c0f9bfd77e6a48eccf51359e3ae77140a7f50b1e2ebfe62422d8afdaffab17a" dependencies = [ + "anyhow", + "prettyplease", "proc-macro2", "quote", "syn", + "wit-bindgen-core", + "wit-bindgen-rust", +] + +[[package]] +name = "wit-component" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d66ea20e9553b30172b5e831994e35fbde2d165325bec84fc43dbf6f4eb9cb2" +dependencies = [ + "anyhow", + "bitflags", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "wasm-encoder", + "wasm-metadata", + "wasmparser", + "wit-parser", +] + +[[package]] +name = "wit-parser" +version = "0.244.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ecc8ac4bc1dc3381b7f59c34f00b67e18f910c2c0f50015669dde7def656a736" +dependencies = [ + "anyhow", + "id-arena", + "indexmap", + "log", + "semver", + "serde", + "serde_derive", + "serde_json", + "unicode-xid", + "wasmparser", +] + +[[package]] +name = "wnaf" +version = "0.14.0-rc.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dbfae175ab8f55e3c604de329bf66f628274c2cda893923670a73ebd1958ead2" +dependencies = [ + "ff", + "group", + "hybrid-array", +] + +[[package]] +name = "x509-cert" +version = "0.3.0-rc.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e21aad3a769f25f3d2d0cbf30ea8b50a1d602354bd6ab687fad112821608ba6" +dependencies = [ + "const-oid", + "der", + "sha1", + "signature", + "spki", + "tls_codec", ] [[package]] name = "zeroize" -version = "1.7.0" +version = "1.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "525b4ec142c6b68a2d10f01f7bbf6755599ca3f81ea53b8431b7dd348f5fdb2d" +checksum = "b97154e67e32c85465826e8bcc1c59429aaaf107c1e4a9e53c8d8ccd5eff88d0" dependencies = [ "zeroize_derive", ] [[package]] name = "zeroize_derive" -version = "1.4.2" +version = "1.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ce36e65b0d2999d2aafac989fb249189a141aee1f53c612c1f37d72631959f69" +checksum = "85a5b4158499876c763cb03bc4e49185d3cccbabb15b33c627f7884f43db852e" dependencies = [ "proc-macro2", "quote", "syn", ] + +[[package]] +name = "zmij" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2fc5a66a20078bf1251bde995aa2fdcc4b800c70b5d92dd2c62abc5c60f679f8" diff --git a/tss-esapi/tests/integration_tests/abstraction_tests/public_tests.rs b/tss-esapi/tests/integration_tests/abstraction_tests/public_tests.rs index bc2573022..f5d110ae8 100644 --- a/tss-esapi/tests/integration_tests/abstraction_tests/public_tests.rs +++ b/tss-esapi/tests/integration_tests/abstraction_tests/public_tests.rs @@ -2,7 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 mod public_rsa_test { - use rsa::{BigUint, pkcs1, traits::PublicKeyParts}; + use rsa::{BoxedUint, pkcs1, traits::PublicKeyParts}; use std::convert::TryFrom; use tss_esapi::{ attributes::ObjectAttributesBuilder, @@ -71,11 +71,11 @@ mod public_rsa_test { #[test] fn test_public_to_decoded_key_rsa() { let public_rsa = get_ext_rsa_pub(); - let default_exponent = BigUint::from(RSA_DEFAULT_EXP); + let default_exponent = BoxedUint::from(RSA_DEFAULT_EXP); let key = rsa::RsaPublicKey::try_from(&public_rsa) .expect("Failed to convert Public structure to DecodedKey (RSA)."); assert_eq!(key.e(), &default_exponent, "RSA exponents are not equal."); - assert_eq!(key.n().to_bytes_be(), RSA_KEY); + assert_eq!(key.n_bytes().as_ref(), RSA_KEY); } #[test] @@ -83,7 +83,7 @@ mod public_rsa_test { let public_rsa = get_ext_rsa_pub(); let key = SubjectPublicKeyInfoOwned::try_from(&public_rsa) .expect("Failed to convert Public structure to SubjectPublicKeyInfo (RSA)."); - let default_exponent = BigUint::from(RSA_DEFAULT_EXP); + let default_exponent = BoxedUint::from(RSA_DEFAULT_EXP); assert_eq!(key.algorithm, pkcs1::ALGORITHM_ID.ref_to_owned()); let pkcs1_key = pkcs1::RsaPublicKey::try_from( key.subject_public_key @@ -94,7 +94,7 @@ mod public_rsa_test { assert_eq!( pkcs1_key.public_exponent.as_bytes(), - default_exponent.to_bytes_be() + default_exponent.to_be_bytes_trimmed_vartime().as_ref() ); assert_eq!(pkcs1_key.modulus.as_bytes(), RSA_KEY); } @@ -168,7 +168,7 @@ mod public_ecc_test { let key = p256::PublicKey::try_from(&public_ecc) .expect("Failed to convert Public structure to DecodedKey (ECC)."); - let ec_point = p256::EncodedPoint::from(key); + let ec_point = p256::Sec1Point::from(key); assert_eq!(ec_point.as_bytes(), EC_POINT.to_vec()); } diff --git a/tss-esapi/tests/integration_tests/abstraction_tests/transient_key_context_tests.rs b/tss-esapi/tests/integration_tests/abstraction_tests/transient_key_context_tests.rs index 2d9a0f0ab..f77eee36a 100644 --- a/tss-esapi/tests/integration_tests/abstraction_tests/transient_key_context_tests.rs +++ b/tss-esapi/tests/integration_tests/abstraction_tests/transient_key_context_tests.rs @@ -511,7 +511,7 @@ fn ctx_migration_test() { // one for just the public part of the key let mut basic_ctx = swtpm.create_session_context(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let prim_key_handle = basic_ctx .create_primary( @@ -901,10 +901,10 @@ fn sign_csr() { let subject = Name::from_str("CN=tpm.example").expect("Parse common name"); let signer = EcSigner::::new((Mutex::new(&mut ctx), tpm_km, key_params, None)) .expect("Create a signer"); - let builder = RequestBuilder::new(subject, &signer).expect("Create certificate request"); + let builder = RequestBuilder::new(subject).expect("Create certificate request"); let cert_req = builder - .build::() + .build::<_, p256::ecdsa::DerSignature>(&signer) .expect("Sign a CSR"); println!( @@ -926,12 +926,21 @@ fn sign_p256_sha2_256() { .expect("Create a signer"); let payload = b"Example of ECDSA with P-256"; - let mut hash = Sha256::new(); - hash.update(payload); - let signature: p256::ecdsa::Signature = signer.sign_digest(hash.clone()); + let signature: p256::ecdsa::Signature = + signer.sign_digest(|hash: &mut Sha256| hash.update(payload)); let verifying_key: VerifyingKey = *signer.as_ref(); - assert!(verifying_key.verify_digest(hash, &signature).is_ok()); + assert!( + verifying_key + .verify_digest( + |hash: &mut Sha256| { + hash.update(payload); + Ok(()) + }, + &signature + ) + .is_ok() + ); } // NOTE(baloo): I believe this is a legitimate case, but support is not available yet in libtpms (or swtpm) @@ -957,13 +966,21 @@ fn sign_p256_sha3_256() { .expect("Create a signer"); let payload = b"Example of ECDSA with P-256"; - let mut hash = Sha3_256::new(); - hash.update(payload); let signature = as DigestSigner>::sign_digest( &signer, - hash.clone(), + |hash: &mut Sha3_256| hash.update(payload), ); let verifying_key: VerifyingKey = *signer.as_ref(); - assert!(verifying_key.verify_digest(hash, &signature).is_ok()); + assert!( + verifying_key + .verify_digest( + |hash: &mut Sha3_256| { + hash.update(payload); + Ok(()) + }, + &signature + ) + .is_ok() + ); } diff --git a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/asymmetric_primitives_tests.rs b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/asymmetric_primitives_tests.rs index eb1a5f26f..8985611e9 100644 --- a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/asymmetric_primitives_tests.rs +++ b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/asymmetric_primitives_tests.rs @@ -20,7 +20,7 @@ mod test_rsa_encrypt_decrypt { fn test_encrypt_decrypt() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context @@ -61,7 +61,7 @@ mod test_rsa_encrypt_decrypt { fn test_ecdh() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let ecc_parms = PublicEccParametersBuilder::new() @@ -126,7 +126,7 @@ mod test_zgen_2phase { fn test_zgen_2phase() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).expect("Failed to get random bytes"); + getrandom::fill(&mut random_digest).expect("Failed to get random bytes"); let key_auth = Auth::from_bytes(random_digest.as_slice()).expect("Failed to create key auth"); diff --git a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/context_management_tests.rs b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/context_management_tests.rs index e3b4998c7..a683fc8a4 100644 --- a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/context_management_tests.rs +++ b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/context_management_tests.rs @@ -8,7 +8,7 @@ mod test_ctx_save { fn test_ctx_save() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context @@ -29,7 +29,7 @@ mod test_ctx_save { fn test_ctx_save_leaf() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let prim_key_handle = context @@ -73,7 +73,7 @@ mod test_ctx_load { fn test_ctx_load() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let prim_key_handle = context .create_primary( @@ -116,7 +116,7 @@ mod test_flush_context { fn test_flush_ctx() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context @@ -138,7 +138,7 @@ mod test_flush_context { fn test_flush_parent_ctx() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let prim_key_handle = context 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 f7a39dcf4..aaf0fcbca 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 @@ -518,7 +518,7 @@ mod test_policy_authorize { fn test_policy_authorize() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context diff --git a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/ephemeral_ec_keys_tests.rs b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/ephemeral_ec_keys_tests.rs index af6301fd1..f1d9862a2 100644 --- a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/ephemeral_ec_keys_tests.rs +++ b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/ephemeral_ec_keys_tests.rs @@ -39,7 +39,7 @@ mod test_commit { fn test_commit() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).expect("Failed to get random bytes"); + getrandom::fill(&mut random_digest).expect("Failed to get random bytes"); let key_auth = Auth::from_bytes(random_digest.as_slice()).expect("Failed to create key auth"); diff --git a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/hierarchy_commands_tests.rs b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/hierarchy_commands_tests.rs index 4fc73deae..5240b6705 100644 --- a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/hierarchy_commands_tests.rs +++ b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/hierarchy_commands_tests.rs @@ -10,7 +10,7 @@ mod test_create_primary { fn test_create_primary() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context @@ -95,7 +95,7 @@ mod test_change_auth { .unwrap(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let new_key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let new_private = context @@ -111,7 +111,7 @@ mod test_change_auth { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let new_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); // NOTE: If this test failed on your system, you are probably running it against a diff --git a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/object_commands_tests.rs b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/object_commands_tests.rs index ba28bb4d8..6e883c8e7 100644 --- a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/object_commands_tests.rs +++ b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/object_commands_tests.rs @@ -8,7 +8,7 @@ mod test_create { fn test_create() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let prim_key_handle = context @@ -44,7 +44,7 @@ mod test_load { fn test_load() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let prim_key_handle = context @@ -195,7 +195,7 @@ mod test_read_public { fn test_read_public() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context 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 dbf94917d..8aa6a6645 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 @@ -12,7 +12,7 @@ mod test_verify_signature { fn test_verify_signature() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context @@ -49,7 +49,7 @@ mod test_verify_signature { fn test_verify_wrong_signature() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context @@ -98,7 +98,7 @@ mod test_verify_signature { fn test_verify_wrong_signature_2() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context @@ -137,7 +137,7 @@ mod test_verify_signature { fn test_verify_wrong_signature_3() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context @@ -209,7 +209,7 @@ mod test_sign { fn test_sign() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context @@ -238,7 +238,7 @@ mod test_sign { fn test_sign_empty_digest() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context @@ -267,7 +267,7 @@ mod test_sign { fn test_sign_large_digest() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context @@ -303,7 +303,7 @@ mod test_sign { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context @@ -312,7 +312,7 @@ mod test_sign { .key_handle; let mut random = vec![0u8; 47]; - getrandom::getrandom(&mut random).unwrap(); + getrandom::fill(&mut random).unwrap(); let signer = EcSigner::::new((Mutex::new(&mut *context), key_handle)).unwrap(); let verifying_key = signer.verifying_key(); @@ -326,7 +326,7 @@ mod test_sign { fn test_sign_signer_rsa_pkcs() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let key_handle = context @@ -342,7 +342,7 @@ mod test_sign { .key_handle; let mut payload = vec![0u8; 47]; - getrandom::getrandom(&mut payload).unwrap(); + getrandom::fill(&mut payload).unwrap(); let signer = RsaPkcsSigner::<_, sha2::Sha256>::new((Mutex::new(&mut *context), key_handle)).unwrap(); @@ -351,8 +351,15 @@ mod test_sign { verifying_key.verify(&payload, &signature).unwrap(); - let d = sha2::Sha256::new_with_prefix(&payload); - verifying_key.verify_digest(d, &signature).unwrap(); + verifying_key + .verify_digest( + |d: &mut sha2::Sha256| { + d.update(&payload); + Ok(()) + }, + &signature, + ) + .unwrap(); } #[cfg(feature = "rsa")] @@ -360,7 +367,7 @@ mod test_sign { fn test_sign_signer_rsa_pss() { let mut context = create_ctx_with_session(); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).unwrap(); + getrandom::fill(&mut random_digest).unwrap(); let key_auth = Auth::from_bytes(random_digest.as_slice()).unwrap(); let rsa_pss = utils::create_unrestricted_signing_rsa_public( @@ -377,7 +384,7 @@ mod test_sign { .key_handle; let mut payload = vec![0u8; 47]; - getrandom::getrandom(&mut payload).unwrap(); + getrandom::fill(&mut payload).unwrap(); let signer = RsaPssSigner::<_, sha2::Sha256>::new((Mutex::new(&mut *context), key_handle)).unwrap(); @@ -386,7 +393,14 @@ mod test_sign { verifying_key.verify(&payload, &signature).unwrap(); - let d = sha2::Sha256::new_with_prefix(&payload); - verifying_key.verify_digest(d, &signature).unwrap(); + verifying_key + .verify_digest( + |d: &mut sha2::Sha256| { + d.update(&payload); + Ok(()) + }, + &signature, + ) + .unwrap(); } } diff --git a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/symmetric_primitives_tests.rs b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/symmetric_primitives_tests.rs index 165e97bc0..c2518feec 100644 --- a/tss-esapi/tests/integration_tests/context_tests/tpm_commands/symmetric_primitives_tests.rs +++ b/tss-esapi/tests/integration_tests/context_tests/tpm_commands/symmetric_primitives_tests.rs @@ -25,7 +25,7 @@ mod test_encrypt_decrypt_2 { .expect("Failed to set auth to empty for owner"); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).expect("get_rand call failed"); + getrandom::fill(&mut random_digest).expect("get_rand call failed"); let primary_key_auth = Auth::from_bytes(random_digest.as_slice()).expect("Failed to create primary key auth"); @@ -70,7 +70,7 @@ mod test_encrypt_decrypt_2 { .expect("Failed to create public for symmetric key public"); let mut random_digest = vec![0u8; 16]; - getrandom::getrandom(&mut random_digest).expect("get_rand call failed"); + getrandom::fill(&mut random_digest).expect("get_rand call failed"); let symmetric_key_auth = Auth::from_bytes(random_digest.as_slice()) .expect("Failed to create symmetric key auth"); diff --git a/tss-esapi/tests/lint-checks.sh b/tss-esapi/tests/lint-checks.sh index 0ebfadb90..397d97097 100755 --- a/tss-esapi/tests/lint-checks.sh +++ b/tss-esapi/tests/lint-checks.sh @@ -20,4 +20,10 @@ fi ################## # Execute clippy # ################## -cargo clippy --all-targets --all-features -- -D clippy::all -D clippy::cargo \ No newline at end of file +LINTS="" +LINTS="$LINTS -D clippy::all" +LINTS="$LINTS -D clippy::cargo" +# clippy::cargo disallows multiple versions of the crate in the tree +# We depend on getrandom which itself will depends on both wit-bindgen 0.46 and 0.51 +LINTS="$LINTS -A clippy::multiple-crate-versions" +cargo clippy --all-targets --all-features -- $LINTS From 37d7f2990118f9b722dd141dad746efbd4de9c44 Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 24 Jan 2025 21:28:20 -0800 Subject: [PATCH 2/3] Create credentials Signed-off-by: Arthur Gautier --- tss-esapi/Cargo.toml | 26 +- tss-esapi/src/abstraction/signatures.rs | 6 +- tss-esapi/src/utils/credential.rs | 430 ++++++++++++++++++ tss-esapi/src/utils/kdf.rs | 282 ++++++++++++ tss-esapi/src/utils/mod.rs | 39 ++ tss-esapi/src/utils/secret_sharing.rs | 139 ++++++ tss-esapi/tests/Cargo.lock.frozen | 101 ++++ .../abstraction_tests/credential_tests.rs | 222 +++++++++ .../abstraction_tests/mod.rs | 1 + 9 files changed, 1241 insertions(+), 5 deletions(-) create mode 100644 tss-esapi/src/utils/credential.rs create mode 100644 tss-esapi/src/utils/kdf.rs create mode 100644 tss-esapi/src/utils/secret_sharing.rs create mode 100644 tss-esapi/tests/integration_tests/abstraction_tests/credential_tests.rs diff --git a/tss-esapi/Cargo.toml b/tss-esapi/Cargo.toml index c52b560f3..1eef5bc4d 100644 --- a/tss-esapi/Cargo.toml +++ b/tss-esapi/Cargo.toml @@ -35,6 +35,11 @@ regex = "1.3.9" zeroize = { version = "1.8.2", features = ["zeroize_derive"] } tss-esapi-sys = { path = "../tss-esapi-sys", version = "0.7.0-alpha.1" } x509-cert = { version = "0.3.0-rc.4", optional = true } +aes = { version = "0.9", optional = true } +byte-strings = { version = "0.3.1", optional = true } +cfb-mode = { version = "0.9", optional = true } +cipher = { version = "0.5", optional = true } +des = { version = "0.9", optional = true } ecdsa = { version = "0.17.0-rc.23", features = [ "algorithm", "der", @@ -43,12 +48,14 @@ elliptic-curve = { version = "0.14.1", optional = true, features = [ "alloc", "pkcs8", ] } +hmac = { version = "0.13", optional = true } p192 = { version = "0.14.0-rc.15", optional = true } p224 = { version = "0.14.0-rc.15", optional = true } p256 = { version = "0.14.0-rc.15", optional = true } p384 = { version = "0.14.0-rc.15", optional = true } p521 = { version = "0.14.0-rc.15", optional = true } pkcs8 = { version = "0.11", optional = true } +rand = { version = "0.10", optional = true } rsa = { version = "0.10.0-rc.18", optional = true } sha1 = { version = "0.11", optional = true } sha2 = { version = "0.11", optional = true } @@ -60,6 +67,8 @@ signature = { version = "3", features = [ "alloc", "digest", ], optional = true } +kbkdf = { version = "0.1.0-rc.1", optional = true } +one-step-kdf = { version = "0.1.0-rc.0", optional = true } cfg-if = "1.0.0" strum = { version = "0.28.0", optional = true } strum_macros = { version = "0.28.0", optional = true } @@ -68,7 +77,10 @@ getrandom = "0.4.0" [dev-dependencies] assert_fs = "1.1.3" +aes = "0.9.0-pre.2" env_logger = "0.11.5" +hex-literal = "1" +rsa = { version = "0.10.0-pre.3" } serde_json = "^1.0.108" sha2 = { version = "0.11", features = ["oid"] } socket2 = "0.6.3" @@ -90,16 +102,26 @@ default = ["abstraction"] generate-bindings = ["tss-esapi-sys/generate-bindings"] abstraction = ["rustcrypto"] integration-tests = ["strum", "strum_macros"] + rustcrypto = [ + "byte-strings", + "cfb-mode", + "cipher", + "one-step-kdf", "digest", "ecdsa", - "elliptic-curve", + "elliptic-curve/ecdh", + "hmac", + "kbkdf", "pkcs8", + "rand", "signature", "x509-cert", ] rustcrypto-full = [ "rustcrypto", + "aes", + "des", "p192", "p224", "p256", @@ -112,6 +134,8 @@ rustcrypto-full = [ "sm2", "sm3", ] + +rsa = ["dep:rsa", "kbkdf"] sha1 = ["dep:sha1", "rsa?/sha1"] sha2 = ["dep:sha2", "rsa?/sha2"] bundled = ["tss-esapi-sys/bundled"] diff --git a/tss-esapi/src/abstraction/signatures.rs b/tss-esapi/src/abstraction/signatures.rs index 3ba64929a..e3817546f 100644 --- a/tss-esapi/src/abstraction/signatures.rs +++ b/tss-esapi/src/abstraction/signatures.rs @@ -34,11 +34,9 @@ where let signature = ecdsa::Signature::from_scalars( FieldBytes::::try_from(r) - .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))? - .clone(), + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?, FieldBytes::::try_from(s) - .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))? - .clone(), + .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?, ) .map_err(|_| Error::local_error(WrapperErrorKind::InvalidParam))?; Ok(signature) diff --git a/tss-esapi/src/utils/credential.rs b/tss-esapi/src/utils/credential.rs new file mode 100644 index 000000000..2115d5d92 --- /dev/null +++ b/tss-esapi/src/utils/credential.rs @@ -0,0 +1,430 @@ +// Copyright 2025 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +use core::{ + fmt, + ops::{Add, Mul}, +}; + +use cfb_mode::cipher::BlockCipherEncrypt; +use digest::{ + Digest, FixedOutputReset, Key, KeyInit, Mac, OutputSizeUser, + array::ArraySize, + common::{BlockSizeUser, Iv, KeyIvInit, KeySizeUser}, + consts::{B1, U8}, + typenum::{ + Unsigned, + operator_aliases::{Add1, Sum}, + }, +}; +use ecdsa::elliptic_curve::{ + AffinePoint, Curve, CurveArithmetic, FieldBytesSize, PublicKey, + sec1::{FromSec1Point, ModulusSize, ToSec1Point}, +}; +use hmac::SimpleHmac; +use log::error; +use rand::rng; +use zeroize::Zeroizing; + +#[cfg(feature = "rsa")] +use rsa::RsaPublicKey; + +use crate::{ + error::{Error, Result, WrapperErrorKind}, + structures::{EncryptedSecret, IdObject, Name}, + utils::{TpmHmac, kdf, secret_sharing}, +}; + +/// Test if a key is considered weak according to TCG. +/// +/// TCG will require weak keys to be re-generated, +/// See: +/// ```text +/// 11.4.10.4 Rejection of weak keys +/// https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=82 +/// The Key was considered weak, and we should re-run the creation of the encrypted +/// secret. +/// ``` +pub trait TcgKeyTest: KeyInit { + fn tcg_weak_key_test(key: &Key) -> core::result::Result<(), WeakKeyError>; +} + +/// The error type returned when a key is found to be weak. +#[derive(Copy, Clone, Eq, PartialEq, Debug)] +pub struct WeakKeyError; + +impl fmt::Display for WeakKeyError { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("WeakKey") + } +} + +impl core::error::Error for WeakKeyError {} + +type WeakResult = core::result::Result; + +#[cfg(feature = "aes")] +mod key_test_aes { + use cipher::{Key, KeySizeUser, typenum::Unsigned}; + use elliptic_curve::subtle::{Choice, ConstantTimeGreater}; + + use super::{TcgKeyTest, WeakKeyError}; + + macro_rules! weak_key_test { + ($k: ty) => { + impl TcgKeyTest for $k { + fn tcg_weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + // Check if any bit of the upper half of the key is set + // + // This follows the in terpretation laid out in section `11.4.10.4 Reject of weak keys` + // from the TPM specification: + // ``` + // In the case of AES, at least one bit in the upper half of the key must be set + // ``` + // See: https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=82 + let mut weak = Choice::from(0); + + for v in &key[..(<<$k as KeySizeUser>::KeySize as Unsigned>::USIZE / 2)] { + weak |= <_ as ConstantTimeGreater>::ct_gt(v, &0); + } + + if weak.unwrap_u8() == 0 { + Err(WeakKeyError) + } else { + Ok(()) + } + } + } + }; + } + + weak_key_test!(aes::Aes128); + weak_key_test!(aes::Aes192); + weak_key_test!(aes::Aes256); +} + +#[cfg(feature = "des")] +mod key_test_des { + use cipher::{Key, KeyInit, KeySizeUser, typenum::Unsigned}; + use des::{Des, TdesEde2, TdesEde3, TdesEee2, TdesEee3}; + use elliptic_curve::subtle::{Choice, ConstantTimeEq}; + + use super::{TcgKeyTest, WeakKeyError}; + + static WEAK_KEYS: [[u8; 8]; 64] = [ + [0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01], + [0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE, 0xFE], + [0xE0, 0xE0, 0xE0, 0xE0, 0xF1, 0xF1, 0xF1, 0xF1], + [0x1F, 0x1F, 0x1F, 0x1F, 0x0E, 0x0E, 0x0E, 0x0E], + [0x01, 0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E], + [0x1F, 0x01, 0x1F, 0x01, 0x0E, 0x01, 0x0E, 0x01], + [0x01, 0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1], + [0xE0, 0x01, 0xE0, 0x01, 0xF1, 0x01, 0xF1, 0x01], + [0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE], + [0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01, 0xFE, 0x01], + [0x1F, 0xE0, 0x1F, 0xE0, 0x0E, 0xF1, 0x0E, 0xF1], + [0xE0, 0x1F, 0xE0, 0x1F, 0xF1, 0x0E, 0xF1, 0x0E], + [0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E, 0xFE], + [0xFE, 0x1F, 0xFE, 0x1F, 0xFE, 0x0E, 0xFE, 0x0E], + [0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1, 0xFE], + [0xFE, 0xE0, 0xFE, 0xE0, 0xFE, 0xF1, 0xFE, 0xF1], + [0x01, 0x01, 0x1F, 0x1F, 0x01, 0x01, 0x0E, 0x0E], + [0x1F, 0x1F, 0x01, 0x01, 0x0E, 0x0E, 0x01, 0x01], + [0xE0, 0xE0, 0x1F, 0x1F, 0xF1, 0xF1, 0x0E, 0x0E], + [0x01, 0x01, 0xE0, 0xE0, 0x01, 0x01, 0xF1, 0xF1], + [0x1F, 0x1F, 0xE0, 0xE0, 0x0E, 0x0E, 0xF1, 0xF1], + [0xE0, 0xE0, 0xFE, 0xFE, 0xF1, 0xF1, 0xFE, 0xFE], + [0x01, 0x01, 0xFE, 0xFE, 0x01, 0x01, 0xFE, 0xFE], + [0x1F, 0x1F, 0xFE, 0xFE, 0x0E, 0x0E, 0xFE, 0xFE], + [0xE0, 0xFE, 0x01, 0x1F, 0xF1, 0xFE, 0x01, 0x0E], + [0x01, 0x1F, 0x1F, 0x01, 0x01, 0x0E, 0x0E, 0x01], + [0x1F, 0xE0, 0x01, 0xFE, 0x0E, 0xF1, 0x01, 0xFE], + [0xE0, 0xFE, 0x1F, 0x01, 0xF1, 0xFE, 0x0E, 0x01], + [0x01, 0x1F, 0xE0, 0xFE, 0x01, 0x0E, 0xF1, 0xFE], + [0x1F, 0xE0, 0xE0, 0x1F, 0x0E, 0xF1, 0xF1, 0x0E], + [0xE0, 0xFE, 0xFE, 0xE0, 0xF1, 0xFE, 0xFE, 0xF1], + [0x01, 0x1F, 0xFE, 0xE0, 0x01, 0x0E, 0xFE, 0xF1], + [0x1F, 0xE0, 0xFE, 0x01, 0x0E, 0xF1, 0xFE, 0x01], + [0xFE, 0x01, 0x01, 0xFE, 0xFE, 0x01, 0x01, 0xFE], + [0x01, 0xE0, 0x1F, 0xFE, 0x01, 0xF1, 0x0E, 0xFE], + [0x1F, 0xFE, 0x01, 0xE0, 0x0E, 0xFE, 0x01, 0xF1], + [0xFE, 0x01, 0x1F, 0xE0, 0xFE, 0x01, 0x0E, 0xF1], + [0xFE, 0x01, 0xE0, 0x1F, 0xFE, 0x01, 0xF1, 0x0E], + [0x1F, 0xFE, 0xE0, 0x01, 0x0E, 0xFE, 0xF1, 0x01], + [0xFE, 0x1F, 0x01, 0xE0, 0xFE, 0x0E, 0x01, 0xF1], + [0x01, 0xE0, 0xE0, 0x01, 0x01, 0xF1, 0xF1, 0x01], + [0x1F, 0xFE, 0xFE, 0x1F, 0x0E, 0xFE, 0xFE, 0x0E], + [0xFE, 0x1F, 0xE0, 0x01, 0xFE, 0x0E, 0xF1, 0x01], + [0x01, 0xE0, 0xFE, 0x1F, 0x01, 0xF1, 0xFE, 0x0E], + [0xE0, 0x01, 0x01, 0xE0, 0xF1, 0x01, 0x01, 0xF1], + [0xFE, 0x1F, 0x1F, 0xFE, 0xFE, 0x0E, 0x0E, 0xFE], + [0x01, 0xFE, 0x1F, 0xE0, 0x01, 0xFE, 0x0E, 0xF1], + [0xE0, 0x01, 0x1F, 0xFE, 0xF1, 0x01, 0x0E, 0xFE], + [0xFE, 0xE0, 0x01, 0x1F, 0xFE, 0xF1, 0x01, 0x0E], + [0x01, 0xFE, 0xE0, 0x1F, 0x01, 0xFE, 0xF1, 0x0E], + [0xE0, 0x01, 0xFE, 0x1F, 0xF1, 0x01, 0xFE, 0x0E], + [0xFE, 0xE0, 0x1F, 0x01, 0xFE, 0xF1, 0x0E, 0x01], + [0x01, 0xFE, 0xFE, 0x01, 0x01, 0xFE, 0xFE, 0x01], + [0xE0, 0x1F, 0x01, 0xFE, 0xF1, 0x0E, 0x01, 0xFE], + [0xFE, 0xE0, 0xE0, 0xFE, 0xFE, 0xF1, 0xF1, 0xFE], + [0x1F, 0x01, 0x01, 0x1F, 0x0E, 0x01, 0x01, 0x0E], + [0xE0, 0x1F, 0x1F, 0xE0, 0xF1, 0x0E, 0x0E, 0xF1], + [0xFE, 0xFE, 0x01, 0x01, 0xFE, 0xFE, 0x01, 0x01], + [0x1F, 0x01, 0xE0, 0xFE, 0x0E, 0x01, 0xF1, 0xFE], + [0xE0, 0x1F, 0xFE, 0x01, 0xF1, 0x0E, 0xFE, 0x01], + [0xFE, 0xFE, 0x1F, 0x1F, 0xFE, 0xFE, 0x0E, 0x0E], + [0x1F, 0x01, 0xFE, 0xE0, 0x0E, 0x01, 0xFE, 0xF1], + [0xE0, 0xE0, 0x01, 0x01, 0xF1, 0xF1, 0x01, 0x01], + [0xFE, 0xFE, 0xE0, 0xE0, 0xFE, 0xFE, 0xF1, 0xF1], + ]; + + impl TcgKeyTest for Des { + #[inline] + fn tcg_weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + let mut weak = Choice::from(0); + + for weak_key in &WEAK_KEYS { + weak |= key.ct_eq(weak_key.into()); + } + + if weak.unwrap_u8() == 0 { + Ok(()) + } else { + Err(WeakKeyError) + } + } + } + + #[inline] + fn weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + let mut tmp = Key::::default(); + + for i in 0..::KeySize::USIZE { + // count number of set bits in byte, excluding the low-order bit - SWAR method + let mut c = key[i] & 0xFE; + + c = (c & 0x55) + ((c >> 1) & 0x55); + c = (c & 0x33) + ((c >> 2) & 0x33); + c = (c & 0x0F) + ((c >> 4) & 0x0F); + + // if count is even, set low key bit to 1, otherwise 0 + tmp[i] = (key[i] & 0xFE) | u8::from(c & 0x01 != 0x01); + } + + let mut des_key = Key::::default(); + for i in 0..SIZE { + des_key.copy_from_slice( + &tmp.as_slice()[i * ::KeySize::USIZE + ..(i + 1) * ::KeySize::USIZE], + ); + Des::tcg_weak_key_test(&des_key)?; + } + Ok(()) + } + + impl TcgKeyTest for TdesEde3 { + #[inline] + fn tcg_weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test::<3, Self>(key) + } + } + + impl TcgKeyTest for TdesEee3 { + #[inline] + fn tcg_weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test::<3, Self>(key) + } + } + + impl TcgKeyTest for TdesEde2 { + #[inline] + fn tcg_weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test::<2, Self>(key) + } + } + + impl TcgKeyTest for TdesEee2 { + #[inline] + fn tcg_weak_key_test(key: &Key) -> Result<(), WeakKeyError> { + weak_key_test::<2, Self>(key) + } + } +} + +/// [`make_credential_ecc`] creates a credential that will only be decrypted by the target +/// elliptic-curve EK. +/// +/// # Parameters +/// +/// * `ek_public` is the EC Public key of the Endorsement Key, +/// * `secret` is the serialization of the credential, +/// * `name` will usually be the AK held on the TPM. +pub fn make_credential_ecc( + ek_public: PublicKey, + secret: &[u8], + key_name: Name, +) -> Result<(IdObject, EncryptedSecret)> +where + C: Curve + CurveArithmetic, + AffinePoint: FromSec1Point + ToSec1Point, + FieldBytesSize: ModulusSize, + as Add>::Output: Add>, + Sum, FieldBytesSize>: ArraySize, + Sum, FieldBytesSize>: Add, + Sum, FieldBytesSize>, U8>: Add, + Add1, FieldBytesSize>, U8>>: ArraySize, + EkHash: Digest + BlockSizeUser + FixedOutputReset, + ::OutputSize: Mul, + <::OutputSize as Mul>::Output: Unsigned, + ::OutputSize: ArraySize + Mul, + <::OutputSize as Mul>::Output: Unsigned, + EkCipher: KeySizeUser + BlockCipherEncrypt + KeyInit + TcgKeyTest, + ::KeySize: Mul, + <::KeySize as Mul>::Output: ArraySize, +{ + let mut rng = rng(); + + loop { + let (seed, encrypted_secret) = secret_sharing::secret_sharing_ecc_curve::< + _, + kdf::Identity, + C, + TpmHmac, + EkHash, + >(&mut rng, &ek_public)?; + + match secret_to_credential::(&seed, secret, &key_name)? { + Ok(id_object) => return Ok((id_object, encrypted_secret)), + Err(WeakKeyError) => { + // 11.4.10.4 Rejection of weak keys + // https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=82 + + // The Key was considered weak, and we should re-run the creation of the encrypted + // secret. + continue; + } + } + } +} + +/// [`make_credential_rsa`] creates a credential that will only be decrypted by the target RSA EK. +/// +/// # Parameters +/// +/// * `ek_public` is the RSA Public key of the Endorsement Key, +/// * `secret` is the serialization of the credential, +/// * `name` will usually be the AK held on the TPM. +#[cfg(feature = "rsa")] +pub fn make_credential_rsa( + ek_public: &RsaPublicKey, + secret: &[u8], + key_name: Name, +) -> Result<(IdObject, EncryptedSecret)> +where + EkHash: Digest + BlockSizeUser + FixedOutputReset, + ::OutputSize: Mul, + <::OutputSize as Mul>::Output: Unsigned, + ::OutputSize: ArraySize + Mul, + <::OutputSize as Mul>::Output: Unsigned, + EkCipher: KeySizeUser + BlockCipherEncrypt + KeyInit + TcgKeyTest, + ::KeySize: Mul, + <::KeySize as Mul>::Output: ArraySize, +{ + let mut rng = rng(); + + loop { + let (random_seed, encrypted_secret) = + secret_sharing::secret_sharing_rsa::<_, kdf::Identity, TpmHmac, EkHash>( + &mut rng, ek_public, + )?; + + match secret_to_credential::(&random_seed, secret, &key_name)? { + Ok(id_object) => return Ok((id_object, encrypted_secret)), + Err(WeakKeyError) => { + // 11.4.10.4 Rejection of weak keys + // https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=82 + + // The Key was considered weak, and we should re-run the creation of the encrypted + // secret. + continue; + } + } + } +} + +fn secret_to_credential( + seed: &Key>, + secret: &[u8], + key_name: &Name, +) -> Result> +where + EkHash: Digest + BlockSizeUser + FixedOutputReset, + ::OutputSize: Mul, + <::OutputSize as Mul>::Output: Unsigned, + ::OutputSize: ArraySize + Mul, + <::OutputSize as Mul>::Output: Unsigned, + EkCipher: KeySizeUser + BlockCipherEncrypt + KeyInit + TcgKeyTest, + ::KeySize: Mul, + <::KeySize as Mul>::Output: ArraySize, +{ + // Prepare the sensitive data + // this will be then encrypted using AES-CFB (size of the symmetric key depends on the EK). + let mut sensitive_data = { + let mut out = Zeroizing::new(vec![]); + out.extend_from_slice( + &u16::try_from(secret.len()) + .map_err(|_| { + error!("secret may only be 2^16 bytes long"); + Error::local_error(WrapperErrorKind::WrongParamSize) + })? + .to_be_bytes()[..], + ); + out.extend_from_slice(secret); + out + }; + + // We'll now encrypt the sensitive data, and hmac the result of the encryption + // https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=201 + // See 24.4 Symmetric Encryption + let sym_key = kdf::kdfa::(seed, key_name.value(), &[])?; + + if EkCipher::tcg_weak_key_test(&sym_key).is_err() { + // 11.4.10.4 Rejection of weak keys + // https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=82 + // The Key was considered weak, and we should re-run the creation of the encrypted + // secret. + + return Ok(Err(WeakKeyError)); + } + + let iv: Iv> = Default::default(); + + cfb_mode::Encryptor::::new(&sym_key, &iv).encrypt(&mut sensitive_data); + + // See 24.5 HMAC + let hmac_key = kdf::kdfa::>(seed, &[], &[])?; + let mut hmac = SimpleHmac::::new_from_slice(&hmac_key).map_err(|e| { + error!("HMAC initialization error: {e}"); + Error::local_error(WrapperErrorKind::WrongParamSize) + })?; + Mac::update(&mut hmac, &sensitive_data); + Mac::update(&mut hmac, key_name.value()); + let hmac = hmac.finalize(); + + // We'll now serialize the object and get everything through the door. + let mut out = vec![]; + out.extend_from_slice( + &u16::try_from(hmac.into_bytes().len()) + .map_err(|_| { + // NOTE: this shouldn't ever trigger ... but ... + error!("HMAC output may only be 2^16 bytes long"); + Error::local_error(WrapperErrorKind::WrongParamSize) + })? + .to_be_bytes()[..], + ); + out.extend_from_slice(&hmac.into_bytes()); + out.extend_from_slice(&sensitive_data); + + IdObject::from_bytes(&out).map(Ok) +} diff --git a/tss-esapi/src/utils/kdf.rs b/tss-esapi/src/utils/kdf.rs new file mode 100644 index 000000000..ca95bd123 --- /dev/null +++ b/tss-esapi/src/utils/kdf.rs @@ -0,0 +1,282 @@ +// Copyright 2025 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +use core::ops::Mul; + +use byte_strings::concat_bytes; +use digest::{ + Digest, FixedOutputReset, Key, OutputSizeUser, + array::ArraySize, + common::{BlockSizeUser, KeySizeUser}, + consts::U8, + typenum::Unsigned, +}; +use ecdsa::elliptic_curve::{ + AffinePoint, Curve, CurveArithmetic, FieldBytesSize, PublicKey, + ecdh::SharedSecret, + point::AffineCoordinates, + sec1::{FromSec1Point, ModulusSize, ToSec1Point}, +}; +use hmac::SimpleHmac; +use kbkdf::{Counter, Kbkdf, Params}; +use log::error; + +use crate::{Error, Result, WrapperErrorKind}; + +/// Label to be applied when deriving a key with either [`kdfa`] or [`kdfe`] +pub trait KdfLabel { + /// Label that should be used for a given application + const LABEL: &[u8]; + /// Label for a given application encoded as C string (terminated with `\0`]. + const C_LABEL: &[u8]; +} + +macro_rules! impl_kdf_label { + ($usage:ty, $value: expr) => { + impl KdfLabel for $usage { + const LABEL: &[u8] = $value; + const C_LABEL: &[u8] = concat_bytes!($value, b"\0"); + } + }; +} + +#[derive(Copy, Clone, Debug)] +pub struct Secret; +impl_kdf_label!(Secret, b"SECRET"); + +#[derive(Copy, Clone, Debug)] +pub struct Context; +impl_kdf_label!(Context, b"CONTEXT"); + +#[derive(Copy, Clone, Debug)] +pub struct Obfuscate; +impl_kdf_label!(Obfuscate, b"OBFUSCATE"); + +#[derive(Copy, Clone, Debug)] +pub struct Storage; +impl_kdf_label!(Storage, b"STORAGE"); + +#[derive(Copy, Clone, Debug)] +pub struct Integrity; +impl_kdf_label!(Integrity, b"INTEGRITY"); + +#[derive(Copy, Clone, Debug)] +pub struct Commit; +impl_kdf_label!(Commit, b"COMMIT"); + +#[derive(Copy, Clone, Debug)] +pub struct Cfb; +impl_kdf_label!(Cfb, b"CFB"); + +#[derive(Copy, Clone, Debug)] +pub struct Xor; +impl_kdf_label!(Xor, b"XOR"); + +#[derive(Copy, Clone, Debug)] +pub struct Session; +impl_kdf_label!(Session, b"SESSION"); + +#[derive(Copy, Clone, Debug)] +pub struct Identity; +impl_kdf_label!(Identity, b"IDENTITY"); + +/// KDFa +/// +/// This is a counter mode KDF from SP 800-108. It uses HMAC as the pseudo-random function (PRF). It is referred +/// to in the [specification as `KDFa()`, defined in Section 9.4.10.2 KDFa()]. +/// +/// [specification as `KDFa()`, defined in Section 9.4.10.2 KDFa()]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-1-Version-184_pub.pdf#page=50 +/// +/// # Parameters +/// +/// - Type parameters: +/// - `HashAlg` is the [`Digest`] to be used, +/// - `Label` is the indicated use of the key eg: [`Context`], [`Storage`], [`Integrity`], ... +/// - `K` is the number of of **bytes** in the output key, +/// Note: Spec calls for **bits** but we have no support for partial bytes, +/// +/// - Parameters: +/// - `key` is a variable-sized value use as Kin, +/// - `context_u` (`contextU` in the spec), is a variable-sized value concatenated with `context_v` +/// to create the `Context` parameter used of the Counter mode KDF, +/// - `context_v` (`contextV` in the spec), is a variable-sized value concatenated with +/// `context_u` (see above). +/// +/// # Usage +/// +/// ```ignore +/// // KDFa(sha256, key, "STORAGE", contextU, contextV, 256) +/// kdfa::>(key, contextU, contextV); +/// ``` +// TODO: Support generation of non-complete bytes: +// See: +// ``` +// If KDFa() were used to produce a 521-bit ECC private key, the returned value would occupy 66 octets, with +// the upper 7 bits of the octet at offset zero set to 0. +// ``` +// https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-1-Version-184_pub.pdf#page=51 +pub fn kdfa(key: &[u8], context_u: &[u8], context_v: &[u8]) -> Result> +where + Label: KdfLabel, + HashAlg: Digest + BlockSizeUser, + K: KeySizeUser, + K::KeySize: ArraySize + Mul, + >::Output: Unsigned, + ::OutputSize: ArraySize + Mul, + <::OutputSize as Mul>::Output: Unsigned, +{ + let mut context = Vec::with_capacity(context_u.len() + context_v.len()); + context.extend_from_slice(context_u); + context.extend_from_slice(context_v); + + let kdf = Counter::, K>::default(); + kdf.derive( + Params::builder(key) + .with_label(Label::LABEL) + .with_context(&context) + .build(), + ) + .map_err(|e| { + error!("KDFa derivation error: {e}"); + Error::local_error(WrapperErrorKind::InternalError) + }) +} + +/// KDFe for ECDH +/// +/// This provides a symmetric encryption key for an ECC-protected object. It is defined in +/// [Section 9.4.10.3 KDFe for ECDH] of the spec +/// +/// [Section 9.4.10.3 KDFe for ECDH]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-1-Version-184_pub.pdf#page=52 +/// +/// # Parameters +/// +/// - Type parameters: +/// - `Use` is the indicated use of the key eg: [`Context`], [`Storage`], [`Integrity`], ... +/// - `HashAlg` is the [`Digest`] to be used, +/// - `C` is the [`Curve`] used by the ECC key, +/// - `K` is the number of of **bytes** in the output key, +/// Note: Spec calls for **bits** but we have no support for partial bytes, +/// +/// - Parameters: +/// - `z` (`Z` in the spec) is the product of a public point and a private x coordinate. This will be an ECDH +/// [`SharedSecret`] on the curve (`C`), +/// - `party_u_info` (`PartyUInfo` in the spec), is the public point of the ephemeral used to +/// compute `Z`, +/// - `party_v_info` (`PartyVInfo` in the spec), is the public point of a static TPM key +pub fn kdfe( + z: &SharedSecret, + party_u_info: &PublicKey, + party_v_info: &PublicKey, +) -> Result> +where + Use: KdfLabel, + HashAlg: Digest + FixedOutputReset, + C: Curve + CurveArithmetic, + K: KeySizeUser, + AffinePoint: FromSec1Point + ToSec1Point, + FieldBytesSize: ModulusSize, +{ + let mut key = Key::::default(); + + let label_size = Use::C_LABEL.len(); + let mut other_info = vec![0; label_size + (2 * FieldBytesSize::::USIZE)]; + other_info[..label_size].copy_from_slice(Use::C_LABEL); + other_info[label_size..label_size + FieldBytesSize::::USIZE] + .copy_from_slice(&party_u_info.as_affine().x()); + other_info[label_size + FieldBytesSize::::USIZE..] + .copy_from_slice(&party_v_info.as_affine().x()); + + one_step_kdf::derive_key_into::(z.raw_secret_bytes(), &other_info, &mut key).map_err( + |e| { + error!("KDFe derivation error: {e}"); + Error::local_error(WrapperErrorKind::InternalError) + }, + )?; + + Ok(key) +} + +#[cfg(test)] +mod tests { + use super::*; + + use aes::Aes256; + use cipher::Array; + use hex_literal::hex; + use sha2::Sha256; + + #[test] + fn test_kdfe() { + struct Vector { + shared_secret: [u8; S], + local_key: [u8; K], + remote_key: [u8; K], + expected: [u8; E], + } + + // Test vectors here were manually generated from tpm2-pytss + static TEST_VECTORS_SHA256: [Vector< + { FieldBytesSize::::USIZE }, + { as ModulusSize>::CompressedPointSize::USIZE }, + 32, + >; 2] = [ + Vector { + shared_secret: hex!( + "c75afb6f49c941ef194b232d7615769f5152d20de5dee19a991067f337dd65bc" + ), + local_key: hex!( + "031ba4030de068a2f07919c42ef6b19f302884f35f45e7d4e4bb90ffbb0bd9d099" + ), + remote_key: hex!( + "038f2b219a29c2ff9ba69cedff2d08d33a5dbca3da6bc8af8acd3ff6f5ec4dfbef" + ), + expected: hex!("e3a0079db19724f9b76101e9364c4a149cea3501336abc3b603f94b22b6309a5"), + }, + Vector { + shared_secret: hex!( + "a90a1c095155428500ed19e87c0df078df3dd2e66a0e3bbe664ba9ff62113b4a" + ), + local_key: hex!( + "03e9c7d6a853ba6176b65ec2f328bdea25f61c4e1b23a4e1c08e1da8c723381a04" + ), + remote_key: hex!( + "036ccf059628d3cdf8e1b4c4ba6d14696ba51cc8d4a96df4016f0b214782d5cee6" + ), + expected: hex!("865f8093e2c4b801dc8c236eeb2806c7b1c51c2cb04101c035f7f2511ea0aeda"), + }, + ]; + + for v in &TEST_VECTORS_SHA256 { + let out = kdfe::( + &SharedSecret::from(Array::from(v.shared_secret)), + &PublicKey::try_from(Array::from(v.local_key)).unwrap(), + &PublicKey::try_from(Array::from(v.remote_key)).unwrap(), + ) + .unwrap(); + assert_eq!(out, v.expected); + } + } + + #[test] + fn test_kdfa() { + struct Vector { + key: &'static [u8], + context_u: &'static [u8], + context_v: &'static [u8], + expected: &'static [u8], + } + + static TEST_VECTORS_SHA256: [Vector; 1] = [Vector { + key: &hex!("000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"), + context_u: b"", + context_v: &hex!("0506070809"), + expected: &hex!("de275f7f5cfeaac226b30d42377903b34705f178730d96400ccafb736e3d28a4"), + }]; + + for v in &TEST_VECTORS_SHA256 { + let out = kdfa::(v.key, v.context_u, v.context_v).unwrap(); + assert_eq!(out.as_slice(), v.expected); + } + } +} diff --git a/tss-esapi/src/utils/mod.rs b/tss-esapi/src/utils/mod.rs index 3bce90967..36543a148 100644 --- a/tss-esapi/src/utils/mod.rs +++ b/tss-esapi/src/utils/mod.rs @@ -23,6 +23,24 @@ use crate::{Context, Error, Result, WrapperErrorKind}; use std::convert::TryFrom; use zeroize::Zeroize; +#[cfg(feature = "rustcrypto")] +use { + core::marker::PhantomData, + digest::{OutputSizeUser, common::KeySizeUser}, +}; + +#[cfg(feature = "rustcrypto")] +mod credential; +#[cfg(feature = "rustcrypto")] +pub mod kdf; +#[cfg(feature = "rustcrypto")] +mod secret_sharing; + +#[cfg(feature = "rustcrypto")] +pub use self::credential::make_credential_ecc; +#[cfg(all(feature = "rustcrypto", feature = "rsa"))] +pub use self::credential::make_credential_rsa; + /// Create the [Public] structure for a restricted decryption key. /// /// * `symmetric` - Cipher to be used for decrypting children of the key @@ -268,3 +286,24 @@ pub fn get_tpm_vendor(context: &mut Context) -> Result { // Collect to a single string .collect()) } +// [`TpmHmac`] intends to code for the key expected for hmac +// in the KDFa and KDFe derivations. There are no standard sizes for hmac keys really, +// upstream RustCrypto considers it to be [BlockSize], but TPM specification +// has a different opinion on the matter, and expect the key to the output +// bit size of the hash algorithm used. +// +// See https://trustedcomputinggroup.org/wp-content/uploads/TPM-2.0-1.83-Part-1-Architecture.pdf#page=202 +// section 24.5 HMAC: +// bits the number of bits in the digest produced by ekNameAlg +// +// [BlockSize]: https://docs.rs/hmac/0.12.1/hmac/struct.HmacCore.html#impl-KeySizeUser-for-HmacCore%3CD%3E +#[cfg(feature = "rustcrypto")] +pub(super) struct TpmHmac(PhantomData); + +#[cfg(feature = "rustcrypto")] +impl KeySizeUser for TpmHmac +where + H: OutputSizeUser, +{ + type KeySize = H::OutputSize; +} diff --git a/tss-esapi/src/utils/secret_sharing.rs b/tss-esapi/src/utils/secret_sharing.rs new file mode 100644 index 000000000..2065d7c60 --- /dev/null +++ b/tss-esapi/src/utils/secret_sharing.rs @@ -0,0 +1,139 @@ +// Copyright 2019 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +//! Secret sharing +//! +//! This provides encryption for the seed used for credential or duplication wrappers + +use cipher::common::{Key, KeySizeUser, typenum::Unsigned}; +use digest::{Digest, FixedOutputReset}; +use elliptic_curve::{ + AffinePoint, Curve, CurveArithmetic, FieldBytesSize, Generate, PublicKey, + ecdh::{EphemeralSecret, SharedSecret}, + sec1::{Coordinates, FromSec1Point, ModulusSize, ToSec1Point}, +}; +use log::error; +use rand::CryptoRng; +use zeroize::Zeroizing; + +#[cfg(feature = "rsa")] +use rsa::{Oaep, RsaPublicKey}; + +use crate::{ + error::{Error, Result, WrapperErrorKind}, + structures::EncryptedSecret, + utils::kdf::{self, KdfLabel}, +}; +/// Generates and encrypt a seed for a given ECC Public key on the curve +/// +/// See [B.6 Secret Sharing] +/// +/// # Parameters +// TODO +/// - Type parameters +/// - `R` a [`CryptoRng`] +/// - `Use` an application-dependent value +/// See [Table 27: Protection Values], for the appropriate `seed Label` +/// - `C` is the [`Curve`] of the storage key to encrypt the seed to. +/// - `K` is the type of [`Key`] we should provide a seed for +/// - `NameHash` is the naming hash algorithm of the recipient key +/// - Values +/// - `rng` the [`CryptoRng`] to derive an ephemeral from for the ECDH +/// - `recipient_key` is the Public key we shall encrypt the seed to. +/// +/// [B.6 Secret Sharing]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-1-Version-184_pub.pdf#page=284 +/// [Table 27: Protection Values]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-1-Version-184_pub.pdf#page=155 +pub(super) fn secret_sharing_ecc_curve( + rng: &mut R, + recipient_key: &PublicKey, +) -> Result<(Zeroizing>, EncryptedSecret)> +where + R: CryptoRng + ?Sized, + Use: KdfLabel, + C: Curve + CurveArithmetic, + K: KeySizeUser, + NameHash: Digest + FixedOutputReset, + AffinePoint: FromSec1Point + ToSec1Point, + FieldBytesSize: ModulusSize, +{ + let local = EphemeralSecret::::generate_from_rng(rng); + let ecdh_secret: SharedSecret = local.diffie_hellman(recipient_key); + let local_public = local.public_key(); + drop(local); + + let seed = Zeroizing::new(kdf::kdfe::( + &ecdh_secret, + &local_public, + recipient_key, + )?); + drop(ecdh_secret); + + // The local ECDH pair is used as "encrypted seed" + let encoded_point = local_public.to_sec1_point(false); + let Coordinates::Uncompressed { + x: point_x, + y: point_y, + } = encoded_point.coordinates() + else { + // NOTE: The only way this could trigger would be for the local key to be identity. + error!("Couldn't compute coordinates for the local public key"); + return Err(Error::local_error(WrapperErrorKind::InvalidParam)); + }; + let encrypted_seed = { + let mut out = vec![]; + out.extend_from_slice(&FieldBytesSize::::U16.to_be_bytes()[..]); + out.extend_from_slice(point_x); + out.extend_from_slice(&FieldBytesSize::::U16.to_be_bytes()[..]); + out.extend_from_slice(point_y); + out + }; + let encrypted_seed = EncryptedSecret::from_bytes(&encrypted_seed)?; + + Ok((seed, encrypted_seed)) +} + +/// Generates and encrypt a seed for a given RSA public key +/// +/// See [A.10 Secret Sharing] +/// +/// # Parameters +/// - Type parameters +/// - `R` a [`CryptoRng`] +/// - `Use` an application-dependent value +/// See [Table 27: Protection Values], for the appropriate `seed Label` +/// - `K` is the type of [`Key`] we should provide a seed for +/// - `NameHash` is the naming hash algorithm of the recipient key +/// - Values +/// - `rng` the [`CryptoRng`] to derive a random seed from, +/// - `recipient_key` is the [`RsaPublicKey`] we shall encrypt the seed to. +/// +/// [A.10 Secret Sharing]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-1-Version-184_pub.pdf#page=284 +/// [Table 27: Protection Values]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-1-Version-184_pub.pdf#page=155 +#[cfg(feature = "rsa")] +pub(super) fn secret_sharing_rsa( + rng: &mut R, + recipient_key: &RsaPublicKey, +) -> Result<(Zeroizing>, EncryptedSecret)> +where + R: CryptoRng + ?Sized, + Use: KdfLabel, + K: KeySizeUser, + NameHash: Digest + FixedOutputReset, +{ + let random_seed = { + let mut out = Zeroizing::new(Key::::default()); + rng.fill_bytes(&mut out); + out + }; + let encrypted_seed = { + let padding = Oaep::::new_with_label(Use::C_LABEL); + recipient_key + .encrypt(rng, padding, &random_seed) + .map_err(|e| { + error!("RSA OAEP encryption error: {e}"); + Error::local_error(WrapperErrorKind::InternalError) + })? + }; + let encrypted_secret = EncryptedSecret::from_bytes(&encrypted_seed)?; + + Ok((random_seed, encrypted_secret)) +} diff --git a/tss-esapi/tests/Cargo.lock.frozen b/tss-esapi/tests/Cargo.lock.frozen index 053ba13eb..e3b6f91b2 100644 --- a/tss-esapi/tests/Cargo.lock.frozen +++ b/tss-esapi/tests/Cargo.lock.frozen @@ -2,6 +2,17 @@ # It is not intended for manual editing. version = 4 +[[package]] +name = "aes" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1fc76eaeac4c9164506c466d4ffdd8ec9d0c5bf57ee97177c4d8eceb3a0e138" +dependencies = [ + "cipher", + "cpubits", + "cpufeatures", +] + [[package]] name = "aho-corasick" version = "1.1.4" @@ -173,6 +184,26 @@ dependencies = [ "serde", ] +[[package]] +name = "byte-strings" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "002ee5531feb8450e59862fefa550eeac39b726d60b186071672751045ebc29a" +dependencies = [ + "byte-strings-proc_macros", +] + +[[package]] +name = "byte-strings-proc_macros" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "62f7e0e71f98d6c71bfe42b0a7a47d0f870ad808401fad2d44fa156ed5b0ae03" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "cc" version = "1.2.51" @@ -192,6 +223,15 @@ dependencies = [ "nom", ] +[[package]] +name = "cfb-mode" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac64b0984be8510caae81455ea2c8c23e5af6be61c36129df62f3380d5d64e1f" +dependencies = [ + "cipher", +] + [[package]] name = "cfg-if" version = "1.0.4" @@ -209,6 +249,16 @@ dependencies = [ "rand_core", ] +[[package]] +name = "cipher" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" +dependencies = [ + "crypto-common", + "inout", +] + [[package]] name = "clang-sys" version = "1.8.1" @@ -350,6 +400,15 @@ dependencies = [ "syn", ] +[[package]] +name = "des" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "916a94e407b54f9034d71dd748234cd1e516ced6284009906ae246f177eafe5a" +dependencies = [ + "cipher", +] + [[package]] name = "difflib" version = "0.4.0" @@ -586,6 +645,12 @@ version = "0.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2304e00983f87ffb38b55b444b5e3b60a884b5d30c0fca7d82fe33449bbe55ea" +[[package]] +name = "hex-literal" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1" + [[package]] name = "hkdf" version = "0.13.0" @@ -655,6 +720,15 @@ dependencies = [ "serde_core", ] +[[package]] +name = "inout" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4250ce6452e92010fdf7268ccc5d14faa80bb12fc741938534c58f16804e03c7" +dependencies = [ + "hybrid-array", +] + [[package]] name = "is_terminal_polyfill" version = "1.70.2" @@ -700,6 +774,15 @@ dependencies = [ "syn", ] +[[package]] +name = "kbkdf" +version = "0.1.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90ac93c9768b8d587407881c98b0c3a5d3e3049daa73408ebe5bfb1ab1cb9c84" +dependencies = [ + "digest", +] + [[package]] name = "keccak" version = "0.2.0" @@ -855,6 +938,15 @@ version = "1.70.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" +[[package]] +name = "one-step-kdf" +version = "0.1.0-rc.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd4dc68a57d9494825faa914644f4ec754f23366f51b4f09d8feea37c64808db" +dependencies = [ + "digest", +] + [[package]] name = "p192" version = "0.14.0-rc.15" @@ -1427,20 +1519,29 @@ dependencies = [ name = "tss-esapi" version = "8.0.0-alpha.2" dependencies = [ + "aes", "assert_fs", "bitfield", + "byte-strings", + "cfb-mode", "cfg-if", + "cipher", + "des", "digest", "ecdsa", "elliptic-curve", "enumflags2", "env_logger", "getrandom", + "hex-literal", + "hmac", "hostname-validator", + "kbkdf", "log", "malloced", "num-derive", "num-traits", + "one-step-kdf", "p192", "p224", "p256", diff --git a/tss-esapi/tests/integration_tests/abstraction_tests/credential_tests.rs b/tss-esapi/tests/integration_tests/abstraction_tests/credential_tests.rs new file mode 100644 index 000000000..7d683ebfa --- /dev/null +++ b/tss-esapi/tests/integration_tests/abstraction_tests/credential_tests.rs @@ -0,0 +1,222 @@ +// Copyright 2025 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +use tss_esapi::{ + abstraction::{AsymmetricAlgorithmSelection, ak, ek}, + attributes::SessionAttributesBuilder, + constants::SessionType, + handles::AuthHandle, + interface_types::{ + algorithm::{HashingAlgorithm, SignatureSchemeAlgorithm}, + ecc::EccCurve, + key_bits::RsaKeyBits, + session_handles::PolicySession, + }, + structures::{Digest, SymmetricDefinition}, + utils, +}; + +use elliptic_curve::PublicKey; +use rsa::RsaPublicKey; + +use crate::common::create_ctx_without_session; + +#[test] +fn test_credential_ecc() { + let mut context = create_ctx_without_session(); + + let ek_ecc = ek::create_ek_object( + &mut context, + AsymmetricAlgorithmSelection::Ecc(EccCurve::NistP256), + None, + ) + .unwrap(); + + let (ek_pub, _, _) = context.read_public(ek_ecc).unwrap(); + + let ak_res = ak::create_ak( + &mut context, + ek_ecc, + HashingAlgorithm::Sha384, + AsymmetricAlgorithmSelection::Ecc(EccCurve::NistP384), + SignatureSchemeAlgorithm::EcDsa, + None, + None, + ) + .unwrap(); + + let ak_ecc = ak::load_ak( + &mut context, + ek_ecc, + None, + ak_res.out_private, + ak_res.out_public, + ) + .unwrap(); + + let (_, key_name, _) = context.read_public(ak_ecc).unwrap(); + let cred = vec![1, 2, 3, 4, 5]; + let expected = Digest::try_from(vec![1, 2, 3, 4, 5]).unwrap(); + + let (credential_blob, secret) = utils::make_credential_ecc::<_, sha2::Sha256, aes::Aes128>( + PublicKey::::try_from(&ek_pub).unwrap(), + &cred, + key_name, + ) + .expect("Create credential"); + + let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new().build(); + let session_1 = context + .start_auth_session( + None, + None, + None, + SessionType::Hmac, + SymmetricDefinition::AES_256_CFB, + HashingAlgorithm::Sha256, + ) + .expect("Failed to call start_auth_session") + .expect("Failed invalid session value"); + context + .tr_sess_set_attributes(session_1, session_attributes, session_attributes_mask) + .unwrap(); + + let session_2 = context + .start_auth_session( + None, + None, + None, + SessionType::Policy, + SymmetricDefinition::AES_256_CFB, + HashingAlgorithm::Sha256, + ) + .expect("Failed to call start_auth_session") + .expect("Failed invalid session value"); + context + .tr_sess_set_attributes(session_2, session_attributes, session_attributes_mask) + .expect("Failed to call tr_sess_set_attributes"); + + let _ = context + .execute_with_session(Some(session_1), |ctx| { + ctx.policy_secret( + PolicySession::try_from(session_2) + .expect("Failed to convert auth session to policy session"), + AuthHandle::Endorsement, + Default::default(), + Default::default(), + Default::default(), + None, + ) + }) + .unwrap(); + + context.set_sessions((Some(session_1), Some(session_2), None)); + let decrypted = context + .activate_credential(ak_ecc, ek_ecc, credential_blob, secret) + .unwrap(); + + assert_eq!(expected, decrypted); + + context.flush_context(ek_ecc.into()).unwrap(); + context.flush_context(ak_ecc.into()).unwrap(); +} + +#[test] +fn test_credential_rsa() { + let mut context = create_ctx_without_session(); + + let ek_rsa = ek::create_ek_object( + &mut context, + AsymmetricAlgorithmSelection::Rsa(RsaKeyBits::Rsa2048), + None, + ) + .unwrap(); + + let (ek_pub, _, _) = context.read_public(ek_rsa).unwrap(); + + let ak_res = ak::create_ak( + &mut context, + ek_rsa, + HashingAlgorithm::Sha256, + AsymmetricAlgorithmSelection::Rsa(RsaKeyBits::Rsa2048), + SignatureSchemeAlgorithm::RsaPss, + None, + None, + ) + .unwrap(); + + let ak_rsa = ak::load_ak( + &mut context, + ek_rsa, + None, + ak_res.out_private, + ak_res.out_public, + ) + .unwrap(); + + let (_, key_name, _) = context.read_public(ak_rsa).unwrap(); + let cred = vec![1, 2, 3, 4, 5]; + let expected = Digest::try_from(vec![1, 2, 3, 4, 5]).unwrap(); + + let (credential_blob, secret) = utils::make_credential_rsa::( + &RsaPublicKey::try_from(&ek_pub).unwrap(), + &cred, + key_name, + ) + .expect("Create credential"); + + let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new().build(); + let session_1 = context + .start_auth_session( + None, + None, + None, + SessionType::Hmac, + SymmetricDefinition::AES_256_CFB, + HashingAlgorithm::Sha256, + ) + .expect("Failed to call start_auth_session") + .expect("Failed invalid session value"); + context + .tr_sess_set_attributes(session_1, session_attributes, session_attributes_mask) + .unwrap(); + + let session_2 = context + .start_auth_session( + None, + None, + None, + SessionType::Policy, + SymmetricDefinition::AES_256_CFB, + HashingAlgorithm::Sha256, + ) + .expect("Failed to call start_auth_session") + .expect("Failed invalid session value"); + context + .tr_sess_set_attributes(session_2, session_attributes, session_attributes_mask) + .expect("Failed to call tr_sess_set_attributes"); + + let _ = context + .execute_with_session(Some(session_1), |ctx| { + ctx.policy_secret( + PolicySession::try_from(session_2) + .expect("Failed to convert auth session to policy session"), + AuthHandle::Endorsement, + Default::default(), + Default::default(), + Default::default(), + None, + ) + }) + .unwrap(); + + context.set_sessions((Some(session_1), Some(session_2), None)); + let decrypted = context + .activate_credential(ak_rsa, ek_rsa, credential_blob, secret) + .unwrap(); + + assert_eq!(expected, decrypted); + + context.flush_context(ek_rsa.into()).unwrap(); + context.flush_context(ak_rsa.into()).unwrap(); +} diff --git a/tss-esapi/tests/integration_tests/abstraction_tests/mod.rs b/tss-esapi/tests/integration_tests/abstraction_tests/mod.rs index 2d56d05e7..0e2b500ac 100644 --- a/tss-esapi/tests/integration_tests/abstraction_tests/mod.rs +++ b/tss-esapi/tests/integration_tests/abstraction_tests/mod.rs @@ -1,6 +1,7 @@ // Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 mod ak_tests; +mod credential_tests; mod ek_tests; mod no_tpm; mod nv_tests; From 9103353430eae9565a98c03f4689f439057d561a Mon Sep 17 00:00:00 2001 From: Arthur Gautier Date: Fri, 10 Oct 2025 11:59:40 -0700 Subject: [PATCH 3/3] Implement object duplication Key attestation using object duplication are [on the horizon], and we'll need supporting routines for that. This brings a `create_duplicate` that will make the two layers of wraps around the object to protect. [on the horizon]: https://trustedcomputinggroup.org/wp-content/uploads/EK-Based-Key-Attestation-with-TPM-Firmware-Version-V1-RC1_9July2025.pdf Signed-off-by: Arthur Gautier --- test_policy | Bin 0 -> 537296 bytes tss-esapi/Cargo.toml | 7 +- tss-esapi/src/structures/mod.rs | 6 + tss-esapi/src/structures/names/name.rs | 41 ++ tss-esapi/src/structures/tagged/public.rs | 19 +- tss-esapi/src/traits.rs | 37 +- tss-esapi/src/utils/credential.rs | 20 + tss-esapi/src/utils/duplication.rs | 526 ++++++++++++++++++ tss-esapi/src/utils/kdf.rs | 4 + tss-esapi/src/utils/mod.rs | 88 ++- tss-esapi/src/utils/secret_sharing.rs | 100 +++- tss-esapi/tests/Cargo.lock.frozen | 30 + .../abstraction_tests/duplicate_tests.rs | 250 +++++++++ .../abstraction_tests/mod.rs | 1 + 14 files changed, 1121 insertions(+), 8 deletions(-) create mode 100755 test_policy create mode 100644 tss-esapi/src/utils/duplication.rs create mode 100644 tss-esapi/tests/integration_tests/abstraction_tests/duplicate_tests.rs diff --git a/test_policy b/test_policy new file mode 100755 index 0000000000000000000000000000000000000000..c98c877e8ab63656f2269b4f4fafb95999f3c6ce GIT binary patch literal 537296 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

u7B@#YD(3vaYR|>pT!fz0Gxr9#>c!h-DD)4Fv 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∋u!zvE7XnxYq{p%KAzu;}AhA7%`o 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

mr(fX8P0-LmX{w%KN#Wm*0$ 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⪼$?^%1Nh0mX#t!e` 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 for Name { &self.value } } + +#[cfg(feature = "rustcrypto")] +mod as_name { + use digest::{Digest, Update}; + use log::error; + + use super::{Name, TPM2B_NAME}; + use crate::{ + error::{Error, Result, WrapperErrorKind}, + traits::Marshall, + utils::hash_object, + }; + + #[cfg(feature = "rustcrypto")] + pub(crate) fn make_name(object: &T) -> Result + where + D: Digest + Update, + T: Marshall, + { + let mut hasher = D::new(); + + hash_object(&mut hasher, object)?; + + let bytes = hasher.finalize(); + if bytes.len() > Name::MAX_SIZE { + error!("Invalid Digest output size (> {})", Name::MAX_SIZE); + return Err(Error::local_error(WrapperErrorKind::WrongParamSize)); + } + let size = bytes.len() as u16; + + let mut name = [0; Name::MAX_SIZE]; + name[..bytes.len()].copy_from_slice(&bytes); + + Ok(Name { + value: TPM2B_NAME { size, name }, + }) + } +} + +#[cfg(feature = "rustcrypto")] +pub(crate) use self::as_name::make_name; diff --git a/tss-esapi/src/structures/tagged/public.rs b/tss-esapi/src/structures/tagged/public.rs index a4aa856e7..298ff9d8b 100644 --- a/tss-esapi/src/structures/tagged/public.rs +++ b/tss-esapi/src/structures/tagged/public.rs @@ -8,7 +8,7 @@ use crate::{ Error, Result, ReturnCode, WrapperErrorKind, attributes::ObjectAttributes, interface_types::algorithm::{HashingAlgorithm, PublicAlgorithm}, - structures::{Digest, EccPoint, PublicKeyRsa, SymmetricCipherParameters}, + structures::{Digest, EccPoint, Name, PublicKeyRsa, SymmetricCipherParameters}, traits::{Marshall, impl_mu_standard}, tss2_esys::{TPM2B_PUBLIC, TPMT_PUBLIC}, }; @@ -586,3 +586,20 @@ impl TryFrom for TPM2B_PUBLIC { }) } } + +#[cfg(feature = "rustcrypto")] +impl Public { + pub fn name(&self) -> Result { + #[cfg_attr( + not(any(feature = "sha1", feature = "sha2", feature = "sha3", feature = "sm3",)), + allow(unused) + )] + macro_rules! make_name { + ($hash: ty) => { + crate::structures::make_name::<$hash, _>(self) + }; + } + + crate::utils::match_name_hashing_algorithm!(self, make_name) + } +} diff --git a/tss-esapi/src/traits.rs b/tss-esapi/src/traits.rs index 90cccf76c..1a32e8ac0 100644 --- a/tss-esapi/src/traits.rs +++ b/tss-esapi/src/traits.rs @@ -1,6 +1,7 @@ // Copyright 2021 Contributors to the Parsec project. // SPDX-License-Identifier: Apache-2.0 -use crate::{Result, tss2_esys::UINT32}; +use crate::{Error, Result, WrapperErrorKind, tss2_esys::UINT32}; +use log::error; use std::convert::TryFrom; /// Trait for types that can be converted into @@ -25,6 +26,23 @@ pub trait Marshall: Sized { fn marshall_offset(&self, _marshalled_data: &mut [u8], _offset: &mut usize) -> Result<()> { unimplemented!(); } + + /// Returns the type in form of marshalled data prefixed with their length + fn marshall_prefixed(&self) -> Result> { + let data = self.marshall()?; + let mut buffer = vec![0; data.len() + 2]; + buffer[..2].copy_from_slice( + &u16::try_from(data.len()) + .map_err(|_| { + error!("object may only be 2^16 bytes long"); + Error::local_error(WrapperErrorKind::WrongParamSize) + })? + .to_be_bytes()[..], + ); + buffer[2..].copy_from_slice(&data); + + Ok(buffer) + } } /// Trait for types that can be created from @@ -185,3 +203,20 @@ pub(crate) use impl_mu_standard; pub(crate) use impl_unmarshall_trait; // Implementation of Marshall and UnMarshall macro for base TSS types. impl_mu_aliases!(UINT32); + +#[cfg(feature = "rustcrypto")] +impl Marshall for digest::CtOutput +where + T: digest::OutputSizeUser, +{ + const BUFFER_SIZE: usize = ::USIZE; + + fn marshall_offset(&self, buf: &mut [u8], offset: &mut usize) -> Result<()> { + let src = &self.as_bytes()[*offset..]; + let to_write = buf.len().min(src.len()); + buf[..to_write].copy_from_slice(&src[..to_write]); + *offset += to_write; + + Ok(()) + } +} diff --git a/tss-esapi/src/utils/credential.rs b/tss-esapi/src/utils/credential.rs index 2115d5d92..6428437a2 100644 --- a/tss-esapi/src/utils/credential.rs +++ b/tss-esapi/src/utils/credential.rs @@ -252,6 +252,26 @@ mod key_test_des { } } +#[cfg(any(feature = "camellia", feature = "sm4"))] +macro_rules! dummy_weak_key_test { + ($k: ty) => { + impl TcgKeyTest for $k { + fn tcg_weak_key_test(_key: &Key) -> core::result::Result<(), WeakKeyError> { + Ok(()) + } + } + }; +} + +#[cfg(feature = "camellia")] +dummy_weak_key_test!(camellia::Camellia128); +#[cfg(feature = "camellia")] +dummy_weak_key_test!(camellia::Camellia192); +#[cfg(feature = "camellia")] +dummy_weak_key_test!(camellia::Camellia256); +#[cfg(feature = "sm4")] +dummy_weak_key_test!(sm4::Sm4); + /// [`make_credential_ecc`] creates a credential that will only be decrypted by the target /// elliptic-curve EK. /// diff --git a/tss-esapi/src/utils/duplication.rs b/tss-esapi/src/utils/duplication.rs new file mode 100644 index 000000000..aec610cce --- /dev/null +++ b/tss-esapi/src/utils/duplication.rs @@ -0,0 +1,526 @@ +// Copyright 2025 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 +#![cfg_attr( + not(any(feature = "sha1", feature = "sha2", feature = "sha3", feature = "sm3",)), + allow(unused) +)] + +//! This module holds the logic to implement Duplication as +//! defined in the [Section 21.3 Duplication] of the specification. +//! +//! [Section 21.3 Duplication]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-1-Version-184_pub.pdf#page=162 + +use core::ops::Mul; + +use cfb_mode::Encryptor; +use cipher::{ + BlockCipherEncrypt, Iv, Key, KeyInit, KeyIvInit, KeySizeUser, array::ArraySize, consts::U8, + typenum::Unsigned, +}; +use digest::{ + Digest, FixedOutputReset, OutputSizeUser, + common::{BlockSizeUser, OutputSize}, +}; +use hmac::{Mac, SimpleHmac}; +use log::error; +use rand::CryptoRng; +use zeroize::{Zeroize, Zeroizing}; + +use crate::{ + abstraction::AssociatedHashingAlgorithm, + error::{Error, Result, WrapperErrorKind}, + interface_types::{ + algorithm::SymmetricMode, + key_bits::{AesKeyBits, CamelliaKeyBits, Sm4KeyBits}, + }, + structures::{EncryptedSecret, Name, Private, Public, Sensitive, SymmetricDefinitionObject}, + traits::Marshall, + utils::{ + TpmHmac, + credential::TcgKeyTest, + hash_object, + kdf::{self, kdfa}, + secret_sharing, + }, +}; + +struct InnerWrapper { + sym_key: Option>>, + enc_sensitive: Zeroizing>, +} + +/// In the first phase, we'll compute the integrity hash of the sensitive data. The hash includes +/// the Name of the public area associated with this object. +/// +/// # Parameters +/// +/// - Type parameters: +/// - `H` is the [`Digest`] nameAlg of the object. +/// - Parameters +/// - `sensitive` +/// +/// +/// See [Section 21.3.2.2 Inner Duplication Wrapper] for details. +/// +/// [Section 21.3.2.2 Inner Duplication Wrapper]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-1-Version-184_pub.pdf#page=162 +fn inner_wrapper( + rng: &mut R, + sensitive_kp: (&Public, &Sensitive), +) -> Result +where + R: CryptoRng + ?Sized, + PSymAlg: BlockCipherEncrypt + KeyInit + TcgKeyTest, +{ + fn inner_wrapper_hash( + rng: &mut R, + sensitive_kp: (&Public, &Sensitive), + ) -> Result + where + R: CryptoRng + ?Sized, + PSymAlg: BlockCipherEncrypt + KeyInit + TcgKeyTest, + NameAlg: Digest, + { + let (sensitive_pub, sensitive_priv) = sensitive_kp; + + let sym_key = Zeroizing::new(loop { + let mut key = Key::::default(); + rng.fill_bytes(&mut key); + + if PSymAlg::tcg_weak_key_test(&key).is_ok() { + break key; + } + }); + + // Name of the object being protected + let name = sensitive_pub.name()?; + + // innerIntegrity ∶= H_nameAlg(sensitive ∥ name) + let inner_integrity = { + let mut d = NameAlg::new(); + hash_object(&mut d, sensitive_priv)?; + d.update(name.value()); + + d.finalize() + }; + + // encSensitive ∶= CFB_pSymAlg(symKey, 0, innerIntegrity ∥ sensitive) + let mut enc_sensitive: Zeroizing> = Zeroizing::new({ + let mut out = Vec::with_capacity(inner_integrity.len() + 2 + Sensitive::BUFFER_SIZE); + out.extend_from_slice(&inner_integrity); + out.append(&mut sensitive_priv.marshall_prefixed()?); + out.to_vec().into() + }); + let iv = { + let mut iv = Iv::>::default(); + iv.zeroize(); + iv + }; + let enc = Encryptor::::new(&sym_key, &iv); + enc.encrypt(enc_sensitive.as_mut().as_mut()); + + Ok(InnerWrapper { + enc_sensitive, + sym_key: Some(Zeroizing::new({ + let key: &[u8] = sym_key.as_ref(); + key.to_vec().into() + })), + }) + } + + let (sensitive_pub, _sensitive_priv) = sensitive_kp; + + // TODO: is this really? There are subtilities of the key is FIXED_TPM + //if !sensitive_pub.object_attributes().encrypted_duplication() { + // if new_parent.is_none() { + // todo!("error, the new parent can't be null"); + // } + + // // encSensitive := sensitive + // todo!("no inner wrapper, encsensitive is directly sensitive"); + //} + + macro_rules! match_inner { + ($hash: ty) => { + inner_wrapper_hash::(rng, sensitive_kp) + }; + } + + super::match_name_hashing_algorithm!(sensitive_pub, match_inner) +} + +/// See [Section 21.3.2.3 Outer Duplication Wrapper] for details. +/// +/// [Section 21.3.2.3 Outer Duplication Wrapper]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-1-Version-184_pub.pdf#page=163 +fn outer_wrapper( + rng: &mut R, + new_parent: &Public, + enc_sensitive: &mut Zeroizing>, + sensitive_public: &Public, +) -> Result<(EncryptedSecret, Private)> +where + R: CryptoRng + ?Sized, + // NOTE: NP stands for New Parent + NpNameAlg: Digest + BlockSizeUser + FixedOutputReset, + NpSymAlg: BlockCipherEncrypt + KeyInit, + NpNameAlg: OutputSizeUser, + NpNameAlg: AssociatedHashingAlgorithm, + // Use of kdfa + // vvvvvvvvvvv + NpNameAlg::OutputSize: ArraySize + Mul, + >::Output: Unsigned, + NpSymAlg: KeySizeUser, + NpSymAlg::KeySize: ArraySize + Mul, + >::Output: Unsigned, + ::OutputSize: ArraySize + Mul, + <::OutputSize as Mul>::Output: Unsigned, +{ + fn outer_wrapper_obj( + rng: &mut R, + new_parent: &Public, + enc_sensitive: &mut Zeroizing>, + sensitive_name: Name, + ) -> Result<(EncryptedSecret, Private)> + where + R: CryptoRng + ?Sized, + // ObjNameAlg is the Name Algorithm of the object being duplicated + ObjNameAlg: AssociatedHashingAlgorithm, + // NOTE: NP stands for New Parent + NpNameAlg: Digest + BlockSizeUser + FixedOutputReset, + NpSymAlg: BlockCipherEncrypt + KeyInit, + NpNameAlg: OutputSizeUser, + NpNameAlg: AssociatedHashingAlgorithm, + // Use of kdfa + // vvvvvvvvvvv + NpNameAlg::OutputSize: ArraySize + Mul, + >::Output: Unsigned, + NpSymAlg: KeySizeUser, + NpSymAlg::KeySize: ArraySize + Mul, + >::Output: Unsigned, + ::OutputSize: ArraySize + Mul, + <::OutputSize as Mul>::Output: Unsigned, + { + // Create a seed and encrypt it for the new parent + let (seed, seed_ciphertext) = encapsulate::>(rng, new_parent)?; + + // symKey ∶= KDFa(npNameAlg, seed, "STORAGE", Name, NULL, bits) + let mut name = vec![]; + let hash_prefix = &u16::from(ObjNameAlg::TPM_DIGEST).to_be_bytes()[..]; + name.extend_from_slice(hash_prefix); + name.extend_from_slice(sensitive_name.value()); + let sym_key = kdfa::(&seed, &name, &[])?; + + // dupSensitive ∶= CFB_npSymAlg(symKey, 0, encSensitive) + let iv = { + let mut iv = Iv::>::default(); + iv.zeroize(); + iv + }; + let enc = Encryptor::::new(&sym_key, &iv); + enc.encrypt(enc_sensitive.as_mut().as_mut()); + + // HMACkey ∶= KDFa(npNameAlg, seed, "INTEGRITY", NULL, NULL, bits) + let hmac_key = kdfa::>(&seed, &[], &[])?; + + // outerHMAC ∶= HMAC_npNameAlg(HMACkey, dupSensitive ∥ Name) + let mut outer_hmac = SimpleHmac::::new_from_slice(&hmac_key).map_err(|e| { + error!("Outer HMAC key derivation error: {e}"); + Error::local_error(WrapperErrorKind::InternalError) + })?; + outer_hmac.update(enc_sensitive.as_ref()); + let hash_prefix = &u16::from(ObjNameAlg::TPM_DIGEST).to_be_bytes()[..]; + outer_hmac.update(hash_prefix); + outer_hmac.update(sensitive_name.value()); + let outer_hmac = outer_hmac.finalize(); + + let mut out = Vec::with_capacity( + (u16::BITS / 8) as usize + + OutputSize::>::USIZE + + enc_sensitive.len(), + ); + out.append(&mut outer_hmac.marshall_prefixed()?); + out.extend_from_slice(enc_sensitive); + Private::from_bytes(&out).map(|p| (seed_ciphertext, p)) + } + + macro_rules! match_inner { + ($hash: ty) => { + outer_wrapper_obj::( + rng, + new_parent, + enc_sensitive, + sensitive_public.name()?, + ) + }; + } + + super::match_name_hashing_algorithm!(sensitive_public, match_inner) +} + +/// Payload for a duplicate object +#[derive(Debug)] +pub struct DuplicatePayload { + /// Symmetric encryption key + pub sym_key: Option>>, + /// Duplicate payload + pub payload: Private, + /// Seed ciphertext + /// This is the seed used to encrypt the outer wrapper of the object + pub seed_ciphertext: EncryptedSecret, +} + +/// [`create_duplicate`] allows to encrypt an object and import it under a Storage Key. +/// +/// This is a mashup of Create and Duplicate commands. The Duplicate command will accept an +/// external key instead of using an object held on TPM. +/// +/// This is used in draft specs like [EK-Based key attestation with TPM firmware version]. +/// +/// [EK-Based key attestation with TPM firmware version]: https://trustedcomputinggroup.org/wp-content/uploads/EK-Based-Key-Attestation-with-TPM-Firmware-Version-V1-RC1_9July2025.pdf +// Note: an implementation can be found used in the reference implementation of the draft. +// See +pub fn create_duplicate( + rng: &mut R, + symmetric_alg: SymmetricDefinitionObject, + new_parent: Public, + sensitive_kp: (&Public, &Sensitive), +) -> Result +where + R: CryptoRng + ?Sized, +{ + fn create_duplicate_inner( + rng: &mut R, + symmetric_alg: SymmetricDefinitionObject, + new_parent: &Public, + sensitive_kp: (&Public, &Sensitive), + ) -> Result + where + R: CryptoRng + ?Sized, + NpSymAlg: BlockCipherEncrypt + KeyInit, + // Use of kdfa + // vvvvvvvvvvv + NpSymAlg: KeySizeUser, + NpSymAlg::KeySize: ArraySize + Mul, + >::Output: Unsigned, + { + // TODO: probably should check sensitive_kp public is not fixed tpm? + + let InnerWrapper { + sym_key, + mut enc_sensitive, + } = match symmetric_alg { + SymmetricDefinitionObject::Null => { + // If symmetric_algorithm is null, then no inner wrapper is required, just return the + // sensitive directly (prepended with its size). + let enc_sensitive: Zeroizing> = + Zeroizing::new(sensitive_kp.1.marshall_prefixed()?.into()); + + Ok(InnerWrapper { + sym_key: None, + enc_sensitive, + }) + } + + // Only CFB mode is supported + SymmetricDefinitionObject::Aes { + mode: + SymmetricMode::Ctr + | SymmetricMode::Ofb + | SymmetricMode::Cbc + | SymmetricMode::Ecb + | SymmetricMode::Null, + .. + } + | SymmetricDefinitionObject::Sm4 { + mode: + SymmetricMode::Ctr + | SymmetricMode::Ofb + | SymmetricMode::Cbc + | SymmetricMode::Ecb + | SymmetricMode::Null, + .. + } + | SymmetricDefinitionObject::Camellia { + mode: + SymmetricMode::Ctr + | SymmetricMode::Ofb + | SymmetricMode::Cbc + | SymmetricMode::Ecb + | SymmetricMode::Null, + .. + } => Err(Error::local_error(WrapperErrorKind::InvalidParam)), + + #[cfg(feature = "aes")] + SymmetricDefinitionObject::Aes { + key_bits: AesKeyBits::Aes128, + mode: SymmetricMode::Cfb, + } => inner_wrapper::(rng, sensitive_kp), + #[cfg(feature = "aes")] + SymmetricDefinitionObject::Aes { + key_bits: AesKeyBits::Aes192, + mode: SymmetricMode::Cfb, + } => inner_wrapper::(rng, sensitive_kp), + #[cfg(feature = "aes")] + SymmetricDefinitionObject::Aes { + key_bits: AesKeyBits::Aes256, + mode: SymmetricMode::Cfb, + } => inner_wrapper::(rng, sensitive_kp), + #[cfg(feature = "sm4")] + SymmetricDefinitionObject::Sm4 { + key_bits: Sm4KeyBits::Sm4_128, + mode: SymmetricMode::Cfb, + } => inner_wrapper::(rng, sensitive_kp), + #[cfg(feature = "camellia")] + SymmetricDefinitionObject::Camellia { + key_bits: CamelliaKeyBits::Camellia128, + mode: SymmetricMode::Cfb, + } => inner_wrapper::(rng, sensitive_kp), + #[cfg(feature = "camellia")] + SymmetricDefinitionObject::Camellia { + key_bits: CamelliaKeyBits::Camellia192, + mode: SymmetricMode::Cfb, + } => inner_wrapper::(rng, sensitive_kp), + #[cfg(feature = "camellia")] + SymmetricDefinitionObject::Camellia { + key_bits: CamelliaKeyBits::Camellia256, + mode: SymmetricMode::Cfb, + } => inner_wrapper::(rng, sensitive_kp), + + #[cfg(not(all(feature = "aes", feature = "sm4", feature = "camellia")))] + _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)), + }?; + + macro_rules! match_inner { + ($hash: ty) => { + outer_wrapper::( + rng, + new_parent, + &mut enc_sensitive, + sensitive_kp.0, + ) + }; + } + + let (seed_ciphertext, payload) = + super::match_name_hashing_algorithm!(new_parent, match_inner)?; + + Ok(DuplicatePayload { + sym_key, + payload, + seed_ciphertext, + }) + } + + match new_parent.symmetric_algorithm()? { + SymmetricDefinitionObject::Null => Err(Error::local_error(WrapperErrorKind::InvalidParam)), + + // Only CFB mode is supported + SymmetricDefinitionObject::Aes { + mode: + SymmetricMode::Ctr + | SymmetricMode::Ofb + | SymmetricMode::Cbc + | SymmetricMode::Ecb + | SymmetricMode::Null, + .. + } + | SymmetricDefinitionObject::Sm4 { + mode: + SymmetricMode::Ctr + | SymmetricMode::Ofb + | SymmetricMode::Cbc + | SymmetricMode::Ecb + | SymmetricMode::Null, + .. + } + | SymmetricDefinitionObject::Camellia { + mode: + SymmetricMode::Ctr + | SymmetricMode::Ofb + | SymmetricMode::Cbc + | SymmetricMode::Ecb + | SymmetricMode::Null, + .. + } => Err(Error::local_error(WrapperErrorKind::InvalidParam)), + + #[cfg(feature = "aes")] + SymmetricDefinitionObject::Aes { + key_bits: AesKeyBits::Aes128, + mode: SymmetricMode::Cfb, + } => { + create_duplicate_inner::(rng, symmetric_alg, &new_parent, sensitive_kp) + } + #[cfg(feature = "aes")] + SymmetricDefinitionObject::Aes { + key_bits: AesKeyBits::Aes192, + mode: SymmetricMode::Cfb, + } => { + create_duplicate_inner::(rng, symmetric_alg, &new_parent, sensitive_kp) + } + #[cfg(feature = "aes")] + SymmetricDefinitionObject::Aes { + key_bits: AesKeyBits::Aes256, + mode: SymmetricMode::Cfb, + } => { + create_duplicate_inner::(rng, symmetric_alg, &new_parent, sensitive_kp) + } + #[cfg(feature = "sm4")] + SymmetricDefinitionObject::Sm4 { + key_bits: Sm4KeyBits::Sm4_128, + mode: SymmetricMode::Cfb, + } => create_duplicate_inner::(rng, symmetric_alg, &new_parent, sensitive_kp), + #[cfg(feature = "camellia")] + SymmetricDefinitionObject::Camellia { + key_bits: CamelliaKeyBits::Camellia128, + mode: SymmetricMode::Cfb, + } => create_duplicate_inner::( + rng, + symmetric_alg, + &new_parent, + sensitive_kp, + ), + #[cfg(feature = "camellia")] + SymmetricDefinitionObject::Camellia { + key_bits: CamelliaKeyBits::Camellia192, + mode: SymmetricMode::Cfb, + } => create_duplicate_inner::( + rng, + symmetric_alg, + &new_parent, + sensitive_kp, + ), + #[cfg(feature = "camellia")] + SymmetricDefinitionObject::Camellia { + key_bits: CamelliaKeyBits::Camellia256, + mode: SymmetricMode::Cfb, + } => create_duplicate_inner::( + rng, + symmetric_alg, + &new_parent, + sensitive_kp, + ), + + #[cfg(not(all(feature = "aes", feature = "sm4", feature = "camellia")))] + _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)), + } +} + +fn encapsulate( + rng: &mut R, + storage_key: &Public, +) -> Result<(Zeroizing>, EncryptedSecret)> +where + R: CryptoRng + ?Sized, + K: KeySizeUser, +{ + if !storage_key.object_attributes().decrypt() { + return Err(Error::local_error(WrapperErrorKind::InvalidParam)); + } + + secret_sharing::secret_sharing::(rng, storage_key) +} + +// NOTES: +// +// Secret sharing +// https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-1-Version-184_pub.pdf#page=284 +// A.10 Secret Sharing diff --git a/tss-esapi/src/utils/kdf.rs b/tss-esapi/src/utils/kdf.rs index ca95bd123..2394614b9 100644 --- a/tss-esapi/src/utils/kdf.rs +++ b/tss-esapi/src/utils/kdf.rs @@ -80,6 +80,10 @@ impl_kdf_label!(Session, b"SESSION"); pub struct Identity; impl_kdf_label!(Identity, b"IDENTITY"); +#[derive(Copy, Clone, Debug)] +pub struct Duplicate; +impl_kdf_label!(Duplicate, b"DUPLICATE"); + /// KDFa /// /// This is a counter mode KDF from SP 800-108. It uses HMAC as the pseudo-random function (PRF). It is referred diff --git a/tss-esapi/src/utils/mod.rs b/tss-esapi/src/utils/mod.rs index 36543a148..c46238968 100644 --- a/tss-esapi/src/utils/mod.rs +++ b/tss-esapi/src/utils/mod.rs @@ -25,21 +25,27 @@ use zeroize::Zeroize; #[cfg(feature = "rustcrypto")] use { + crate::traits::Marshall, core::marker::PhantomData, - digest::{OutputSizeUser, common::KeySizeUser}, + digest::{Digest, OutputSizeUser, common::KeySizeUser}, }; #[cfg(feature = "rustcrypto")] mod credential; #[cfg(feature = "rustcrypto")] +mod duplication; +#[cfg(feature = "rustcrypto")] pub mod kdf; #[cfg(feature = "rustcrypto")] mod secret_sharing; -#[cfg(feature = "rustcrypto")] -pub use self::credential::make_credential_ecc; #[cfg(all(feature = "rustcrypto", feature = "rsa"))] pub use self::credential::make_credential_rsa; +#[cfg(feature = "rustcrypto")] +pub use self::{ + credential::make_credential_ecc, + duplication::{DuplicatePayload, create_duplicate}, +}; /// Create the [Public] structure for a restricted decryption key. /// @@ -286,6 +292,82 @@ pub fn get_tpm_vendor(context: &mut Context) -> Result { // Collect to a single string .collect()) } + +/// Hash an object into a [`Digest`] +#[cfg(feature = "rustcrypto")] +pub(crate) fn hash_object(hasher: &mut D, object: &T) -> Result<()> +where + D: Digest, + T: Marshall, +{ + let buf = object.marshall()?; + hasher.update(buf); + + //const BUF_SIZE: usize = 128; + //let mut buf = [0u8; BUF_SIZE]; + //let mut offset = 0; + + //// TODO: BUFFER_SIZE is a max, we shall stop if offset didn't bodge + //while offset < T::BUFFER_SIZE { + // let remaining = T::BUFFER_SIZE - offset; + // let buf = &mut buf[..BUF_SIZE.min(remaining)]; + + // object.marshall_offset(buf, &mut offset)?; + // hasher.update(buf); + //} + + Ok(()) +} + +/// Helper macro to match on the name_hashing_algorithm of a public object +/// +/// ```ignore +/// macro_rules! match_inner { +/// ($hash: ty) => { +/// inner_wrapper_hash::(rng, sensitive_kp) +/// }; +/// } +/// +/// match_name_hashing_algorithm!(sensitive_pub, match_inner); +/// ``` +macro_rules! match_name_hashing_algorithm { + ($pub_object: expr, $inner: ident) => {{ + use crate::{ + error::{Error, WrapperErrorKind}, + interface_types::algorithm::HashingAlgorithm, + }; + match $pub_object.name_hashing_algorithm() { + HashingAlgorithm::Null => Err(Error::local_error(WrapperErrorKind::InvalidParam)), + #[cfg(feature = "sha1")] + HashingAlgorithm::Sha1 => $inner!(sha1::Sha1), + #[cfg(feature = "sha2")] + HashingAlgorithm::Sha256 => $inner!(sha2::Sha256), + #[cfg(feature = "sha2")] + HashingAlgorithm::Sha384 => $inner!(sha2::Sha384), + #[cfg(feature = "sha2")] + HashingAlgorithm::Sha512 => $inner!(sha2::Sha512), + #[cfg(feature = "sha3")] + HashingAlgorithm::Sha3_256 => $inner!(sha3::Sha3_256), + #[cfg(feature = "sha3")] + HashingAlgorithm::Sha3_384 => $inner!(sha3::Sha3_384), + #[cfg(feature = "sha3")] + HashingAlgorithm::Sha3_512 => $inner!(sha3::Sha3_512), + #[cfg(feature = "sm3")] + HashingAlgorithm::Sm3_256 => $inner!(sm3::Sm3), + #[cfg(not(all( + feature = "sha1", + feature = "sha2", + feature = "sha3", + feature = "sm3", + )))] + _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)), + } + }}; +} + +// Ensure we can use the macro elsewhere in the crate +pub(crate) use match_name_hashing_algorithm; + // [`TpmHmac`] intends to code for the key expected for hmac // in the KDFa and KDFe derivations. There are no standard sizes for hmac keys really, // upstream RustCrypto considers it to be [BlockSize], but TPM specification diff --git a/tss-esapi/src/utils/secret_sharing.rs b/tss-esapi/src/utils/secret_sharing.rs index 2065d7c60..e9e60b966 100644 --- a/tss-esapi/src/utils/secret_sharing.rs +++ b/tss-esapi/src/utils/secret_sharing.rs @@ -20,15 +20,111 @@ use rsa::{Oaep, RsaPublicKey}; use crate::{ error::{Error, Result, WrapperErrorKind}, - structures::EncryptedSecret, + structures::{EncryptedSecret, Public}, utils::kdf::{self, KdfLabel}, }; + +/// Generates and encrypt a seed for a public key +/// +/// See [A.10 Secret Sharing] for RSA +/// See [B.6 Secret Sharing] for ECC +/// +/// # Parameters +/// - Type parameters +/// - `R` a [`CryptoRng`] +/// - `Use` an application-dependent value +/// See [Table 27: Protection Values], for the appropriate `seed Label` +/// - `K` is the type of [`Key`] we should provide a seed for +/// - Values +/// - `rng` the [`CryptoRng`] to derive a random seed or an ephemeral for the ECDH, +/// - `recipient_key` is the Public key we shall encrypt the seed to. +/// +/// [A.10 Secret Sharing]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-1-Version-184_pub.pdf#page=284 +/// [B.6 Secret Sharing]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-1-Version-184_pub.pdf#page=284 +/// [Table 27: Protection Values]: https://trustedcomputinggroup.org/wp-content/uploads/Trusted-Platform-Module-2.0-Library-Part-1-Version-184_pub.pdf#page=155 +pub(super) fn secret_sharing( + rng: &mut R, + recipient_key: &Public, +) -> Result<(Zeroizing>, EncryptedSecret)> +where + R: CryptoRng + ?Sized, + Use: KdfLabel, + K: KeySizeUser, +{ + #[allow(unused)] + fn secret_sharing_hash( + rng: &mut R, + recipient_key: &Public, + ) -> Result<(Zeroizing>, EncryptedSecret)> + where + R: CryptoRng + ?Sized, + Use: KdfLabel, + K: KeySizeUser, + NameHash: Digest + FixedOutputReset, + { + let _ = rng; + + match recipient_key { + Public::KeyedHash { .. } | Public::SymCipher { .. } => { + Err(Error::local_error(WrapperErrorKind::InvalidParam)) + } + #[cfg(feature = "rsa")] + Public::Rsa { .. } => { + let recipient_key = RsaPublicKey::try_from(recipient_key)?; + secret_sharing_rsa::(rng, &recipient_key) + } + Public::Ecc { parameters, .. } => { + #[allow(unused_macros)] // macro may go unused if no curves are compiled in. + macro_rules! impl_curve { + ($curve: ty) => {{ + use crate::abstraction::public::AssociatedTpmCurve; + if parameters.ecc_curve() == <$curve>::TPM_CURVE { + let recipient_key = PublicKey::<$curve>::try_from(recipient_key)?; + return secret_sharing_ecc_curve::( + rng, + &recipient_key, + ); + } + }}; + } + + let _ = parameters; + + #[cfg(feature = "p192")] + impl_curve!(p192::NistP192); + #[cfg(feature = "p224")] + impl_curve!(p224::NistP224); + #[cfg(feature = "p256")] + impl_curve!(p256::NistP256); + #[cfg(feature = "p384")] + impl_curve!(p384::NistP384); + #[cfg(feature = "p521")] + impl_curve!(p521::NistP521); + // TODO bnp256, bnp638, sm2p256 + + Err(Error::local_error(WrapperErrorKind::InvalidParam)) + } + #[cfg(not(feature = "rsa"))] + _ => Err(Error::local_error(WrapperErrorKind::UnsupportedParam)), + } + } + let _ = rng; + + #[allow(unused_macros)] // macro may go unused if no hashes are compiled in. + macro_rules! match_inner { + ($hash: ty) => { + secret_sharing_hash::(rng, recipient_key) + }; + } + + super::match_name_hashing_algorithm!(recipient_key, match_inner) +} + /// Generates and encrypt a seed for a given ECC Public key on the curve /// /// See [B.6 Secret Sharing] /// /// # Parameters -// TODO /// - Type parameters /// - `R` a [`CryptoRng`] /// - `Use` an application-dependent value diff --git a/tss-esapi/tests/Cargo.lock.frozen b/tss-esapi/tests/Cargo.lock.frozen index e3b6f91b2..ed0b73ba6 100644 --- a/tss-esapi/tests/Cargo.lock.frozen +++ b/tss-esapi/tests/Cargo.lock.frozen @@ -172,6 +172,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "cdd35008169921d80bc60d3d0ab416eecb028c4cd653352907921d95084790be" dependencies = [ "hybrid-array", + "zeroize", ] [[package]] @@ -204,6 +205,22 @@ dependencies = [ "syn", ] +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "camellia" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26f8497bae7a64e5ba66a107df01378570a9a6b282a61913d1e9c28e76f8c65a" +dependencies = [ + "byteorder", + "cipher", +] + [[package]] name = "cc" version = "1.2.51" @@ -255,8 +272,10 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e8cf2a2c93cd704877c0858356ed03480ff301ee950b43f1cbe4573b088bfa6c" dependencies = [ + "block-buffer", "crypto-common", "inout", + "zeroize", ] [[package]] @@ -1409,6 +1428,15 @@ dependencies = [ "digest", ] +[[package]] +name = "sm4" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff2d621883cdeeaee6759d39f4bc8cd314b29db72b6ac3d6714b31422512ee11" +dependencies = [ + "cipher", +] + [[package]] name = "socket2" version = "0.6.4" @@ -1523,6 +1551,7 @@ dependencies = [ "assert_fs", "bitfield", "byte-strings", + "camellia", "cfb-mode", "cfg-if", "cipher", @@ -1561,6 +1590,7 @@ dependencies = [ "signature", "sm2", "sm3", + "sm4", "socket2", "strum", "strum_macros", diff --git a/tss-esapi/tests/integration_tests/abstraction_tests/duplicate_tests.rs b/tss-esapi/tests/integration_tests/abstraction_tests/duplicate_tests.rs new file mode 100644 index 000000000..11bbc2976 --- /dev/null +++ b/tss-esapi/tests/integration_tests/abstraction_tests/duplicate_tests.rs @@ -0,0 +1,250 @@ +// Copyright 2025 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +use cipher::Array; +use digest::{Output, consts::U20}; +use paste::paste; +use rand::CryptoRng; + +use tss_esapi::{ + abstraction::{AssociatedHashingAlgorithm, AsymmetricAlgorithmSelection, ek}, + attributes::{ObjectAttributesBuilder, SessionAttributesBuilder}, + constants::SessionType, + handles::{AuthHandle, ObjectHandle}, + interface_types::{ + algorithm::{HashingAlgorithm, PublicAlgorithm}, + session_handles::{AuthSession, PolicySession}, + }, + structures::{ + Digest, HmacScheme, KeyedHashScheme, Public, PublicBuilder, PublicKeyedHashParameters, + Sensitive, SensitiveData, SymmetricDefinition, SymmetricDefinitionObject, + }, + utils, +}; + +#[cfg(feature = "rsa")] +use tss_esapi::interface_types::key_bits::RsaKeyBits; + +#[cfg(any(feature = "p256", feature = "p384"))] +use tss_esapi::interface_types::ecc::EccCurve; + +use crate::common::create_ctx_with_session; + +fn create_hmac(rng: &mut R) -> (Public, Sensitive) +where + R: CryptoRng + ?Sized, + NameAlg: digest::Digest + AssociatedHashingAlgorithm, + HashAlg: digest::Digest + AssociatedHashingAlgorithm, +{ + let seed = { + let mut seed = Output::::default(); + rng.fill_bytes(&mut seed); + seed + }; + let seed = Digest::from_bytes(&seed).unwrap(); + + let key = { + let mut key = Array::::default(); + rng.fill_bytes(&mut key); + key + }; + + let unique = { + let mut hash = NameAlg::new(); + hash.update(seed.as_bytes()); + hash.update(key); + hash.finalize() + }; + let unique = Digest::from_bytes(&unique).unwrap(); + + let sensitive = Sensitive::Bits { + auth_value: Default::default(), + seed_value: seed.clone(), + sensitive: SensitiveData::from_bytes(&key).unwrap(), + }; + + let object_attributes = ObjectAttributesBuilder::new() + .with_sign_encrypt(true) + .with_user_with_auth(true) + .with_no_da(true) + .with_restricted(true) + .build() + .expect("Failed to build object attributes"); + let public = PublicBuilder::new() + .with_public_algorithm(PublicAlgorithm::KeyedHash) + .with_name_hashing_algorithm(NameAlg::TPM_DIGEST) + .with_object_attributes(object_attributes) + .with_keyed_hash_parameters(PublicKeyedHashParameters::new(KeyedHashScheme::Hmac { + hmac_scheme: HmacScheme::new(HashAlg::TPM_DIGEST), + })) + .with_keyed_hash_unique_identifier(unique) + .build() + .unwrap(); + + (public, sensitive) +} + +fn test_create_duplicate_hmac(ek_alg: AsymmetricAlgorithmSelection) +where + HmacNameAlg: digest::Digest + AssociatedHashingAlgorithm, + HmacHashAlg: digest::Digest + AssociatedHashingAlgorithm, +{ + let mut rng = rand::rng(); + let mut context = create_ctx_with_session(); + + let ek_ecc = ek::create_ek_object(&mut context, ek_alg, None).unwrap(); + + let (ek_pub, _, _) = context.read_public(ek_ecc).unwrap(); + + let (sensitive_public, sensitive_private) = + create_hmac::<_, HmacNameAlg, HmacHashAlg>(&mut rng); + + let dup = utils::create_duplicate( + &mut rng, + SymmetricDefinitionObject::Null, + ek_pub.clone(), + (&sensitive_public, &sensitive_private), + ) + .expect("Create duplicate"); + + // From that point, we don't have the private key anymore, only the TPM will + drop(sensitive_private); + + let auth_hash_alg = match ek_alg { + #[cfg(feature = "rsa")] + AsymmetricAlgorithmSelection::Rsa(RsaKeyBits::Rsa2048) => HashingAlgorithm::Sha256, + #[cfg(feature = "rsa")] + AsymmetricAlgorithmSelection::Rsa(RsaKeyBits::Rsa3072 | RsaKeyBits::Rsa4096) => { + HashingAlgorithm::Sha384 + } + #[cfg(feature = "p256")] + AsymmetricAlgorithmSelection::Ecc(EccCurve::NistP256) => HashingAlgorithm::Sha256, + #[cfg(feature = "p384")] + AsymmetricAlgorithmSelection::Ecc(EccCurve::NistP384) => HashingAlgorithm::Sha384, + #[cfg(feature = "p521")] + AsymmetricAlgorithmSelection::Ecc(EccCurve::NistP521) => HashingAlgorithm::Sha512, + other => unimplemented!("support for {other:?} is not implemented"), + }; + let policy_session = context + .start_auth_session( + None, + None, + None, + SessionType::Policy, + SymmetricDefinition::AES_256_CFB, + auth_hash_alg, + ) + .expect("Failed to call start_auth_session") + .expect("Failed invalid session value"); + let (session_attributes, session_attributes_mask) = SessionAttributesBuilder::new().build(); + context + .tr_sess_set_attributes(policy_session, session_attributes, session_attributes_mask) + .expect("Failed to call tr_sess_set_attributes"); + + let _ = context + .execute_with_session(Some(AuthSession::Password), |ctx| { + ctx.policy_secret( + PolicySession::try_from(policy_session) + .expect("Failed to convert auth session to policy session"), + AuthHandle::Endorsement, + Default::default(), + Default::default(), + Default::default(), + None, + ) + }) + .unwrap(); + + let new_parent_handle: ObjectHandle = ek_ecc.into(); + + // For some profiles userWithAuth is true, so we can use Password session. + // However, since we don't have the userAuth, and userWithAuth is true, the authValue is empty. + // For profiles where userWithAuth is false (P256, RSA2048), we MUST use the policy. + let auth_session = match ek_alg { + #[cfg(feature = "rsa")] + AsymmetricAlgorithmSelection::Rsa(RsaKeyBits::Rsa2048) => Some(policy_session), + #[cfg(feature = "p256")] + AsymmetricAlgorithmSelection::Ecc(EccCurve::NistP256) => Some(policy_session), + _ => Some(AuthSession::Password.into()), + }; + + // Try to import the duplicated object. + let _hmac_key = context + .execute_with_session(auth_session, |ctx| { + ctx.import( + new_parent_handle, + None, + sensitive_public, + dup.payload, + dup.seed_ciphertext, + SymmetricDefinitionObject::Null, + ) + }) + .unwrap(); +} + +macro_rules! test_import { + ($hmac_name: ty, $hmac_hash: ty) => { + paste! { + #[cfg(feature = "rsa")] + #[test] + fn []() { + test_create_duplicate_hmac::<$hmac_name, $hmac_hash>( + AsymmetricAlgorithmSelection::Rsa(RsaKeyBits::Rsa2048) + ) + } + + #[cfg(feature = "rsa")] + #[test] + fn []() { + test_create_duplicate_hmac::<$hmac_name, $hmac_hash>( + AsymmetricAlgorithmSelection::Rsa(RsaKeyBits::Rsa3072) + ) + } + + #[cfg(feature = "p256")] + #[test] + fn []() { + test_create_duplicate_hmac::<$hmac_name, $hmac_hash>( + AsymmetricAlgorithmSelection::Ecc(EccCurve::NistP256), + ) + } + + #[cfg(feature = "p384")] + #[test] + fn []() { + test_create_duplicate_hmac::<$hmac_name, $hmac_hash>( + AsymmetricAlgorithmSelection::Ecc(EccCurve::NistP384), + ) + } + } + }; + (hmac_name=$hmac_name:ty, hmac_hashes=($hmac_hash:ty)) => { + test_import!($hmac_name, $hmac_hash); + }; + (hmac_name=$hmac_name:ty, hmac_hashes=($hmac_hash:ty, $($hmac_hashes:ty),+)) => { + test_import!($hmac_name, $hmac_hash); + test_import!(hmac_name=$hmac_name, hmac_hashes=($($hmac_hashes),+)); + }; + (hmac_names=($hmac_name:ty), hmac_hashes=($($hmac_hashes:ty),+)) => { + test_import!(hmac_name=$hmac_name, hmac_hashes=($($hmac_hashes),+)); + }; + (hmac_names=($hmac_name:ty, $($hmac_names:ty),+), hmac_hashes=($($hmac_hashes:ty),+)) => { + test_import!(hmac_name=$hmac_name, hmac_hashes=($($hmac_hashes),+)); + test_import!(hmac_names=($($hmac_names),+), hmac_hashes=($($hmac_hashes),+)); + }; +} + +#[cfg(feature = "sha1")] +use sha1::Sha1; +#[cfg(feature = "sha1")] +test_import!(hmac_names = (Sha1), hmac_hashes = (Sha1)); + +#[cfg(feature = "sha2")] +use sha2::{Sha256, Sha384, Sha512}; + +#[cfg(feature = "sha2")] +test_import!( + hmac_names = (Sha256, Sha384, Sha512), + hmac_hashes = (Sha256, Sha384, Sha512) +); diff --git a/tss-esapi/tests/integration_tests/abstraction_tests/mod.rs b/tss-esapi/tests/integration_tests/abstraction_tests/mod.rs index 0e2b500ac..00942a1e7 100644 --- a/tss-esapi/tests/integration_tests/abstraction_tests/mod.rs +++ b/tss-esapi/tests/integration_tests/abstraction_tests/mod.rs @@ -2,6 +2,7 @@ // SPDX-License-Identifier: Apache-2.0 mod ak_tests; mod credential_tests; +mod duplicate_tests; mod ek_tests; mod no_tpm; mod nv_tests;