diff --git a/tss-esapi/Cargo.toml b/tss-esapi/Cargo.toml index 41e55d63..9f2eaa9e 100644 --- a/tss-esapi/Cargo.toml +++ b/tss-esapi/Cargo.toml @@ -29,6 +29,7 @@ zeroize = { version = "1.5.7", features = ["zeroize_derive"] } tss-esapi-sys = { path = "../tss-esapi-sys", version = "0.5.0" } x509-cert = { version = "0.2.0", optional = true } elliptic-curve = { version = "0.13.8", optional = true, features = ["alloc", "pkcs8"] } +ecdsa = { version = "0.16.9" } p192 = { version = "0.13.0", optional = true } p224 = { version = "0.13.2", optional = true } p256 = { version = "0.13.2", optional = true } @@ -41,6 +42,7 @@ sha3 = { version = "0.10.8", optional = true } sm2 = { version = "0.13.3", optional = true } sm3 = { version = "0.4.2", optional = true } digest = "0.10.7" +signature = "2.2.0" cfg-if = "1.0.0" strum = { version = "0.25.0", optional = true } strum_macros = { version = "0.25.0", optional = true } diff --git a/tss-esapi/src/abstraction/transient/mod.rs b/tss-esapi/src/abstraction/transient/mod.rs index eea4a234..4e545a46 100644 --- a/tss-esapi/src/abstraction/transient/mod.rs +++ b/tss-esapi/src/abstraction/transient/mod.rs @@ -34,8 +34,10 @@ use std::convert::{AsMut, AsRef, TryFrom, TryInto}; use zeroize::Zeroize; mod key_attestation; +mod signer; pub use key_attestation::MakeCredParams; +pub use signer::Ecdsa; /// Parameters for the kinds of keys supported by the context #[derive(Debug, Clone, Copy)] diff --git a/tss-esapi/src/abstraction/transient/signer.rs b/tss-esapi/src/abstraction/transient/signer.rs new file mode 100644 index 00000000..8c172894 --- /dev/null +++ b/tss-esapi/src/abstraction/transient/signer.rs @@ -0,0 +1,169 @@ +// Copyright 2019 Contributors to the Parsec project. +// SPDX-License-Identifier: Apache-2.0 + +//! Module for exposing a [`signature::Signer`] interface for keys +//! +//! This modules presents objects held in a TPM over a [`signature::DigestSigner`] interface. +use super::TransientKeyContext; +use crate::{ + abstraction::{ + public::AssociatedTpmCurve, + transient::{KeyMaterial, KeyParams}, + }, + interface_types::algorithm::{AssociatedHashingAlgorithm, EccSchemeAlgorithm}, + structures::{Auth, Digest as TpmDigest, EccScheme, Signature as TpmSignature}, + Error, +}; + +use std::{convert::TryFrom, ops::Add, sync::Mutex}; + +use digest::{Digest, FixedOutput, Output}; +use ecdsa::{ + der::{MaxOverhead, MaxSize, Signature as DerSignature}, + hazmat::{DigestPrimitive, SignPrimitive}, + Signature, SignatureSize, VerifyingKey, +}; +use elliptic_curve::{ + generic_array::ArrayLength, + ops::Invert, + sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint}, + subtle::CtOption, + AffinePoint, CurveArithmetic, FieldBytesSize, PrimeCurve, PublicKey, Scalar, +}; +use signature::{DigestSigner, Error as SError, KeypairRef}; + +#[derive(Debug)] +pub struct Ecdsa<'ctx, C> +where + C: PrimeCurve + CurveArithmetic, +{ + context: Mutex<&'ctx mut TransientKeyContext>, + key_material: KeyMaterial, + key_auth: Option, + verifying_key: VerifyingKey, +} + +impl<'ctx, C> Ecdsa<'ctx, C> +where + C: PrimeCurve + CurveArithmetic, + C: AssociatedTpmCurve, + FieldBytesSize: ModulusSize, + AffinePoint: FromEncodedPoint + ToEncodedPoint, +{ + pub fn new( + context: &'ctx mut TransientKeyContext, + key_material: KeyMaterial, + key_auth: Option, + ) -> Result { + let context = Mutex::new(context); + + let public_key = PublicKey::try_from(key_material.public())?; + let verifying_key = VerifyingKey::from(public_key); + + Ok(Self { + context, + key_material, + key_auth, + verifying_key, + }) + } +} + +impl<'ctx, C> Ecdsa<'ctx, C> +where + C: PrimeCurve + CurveArithmetic, + C: AssociatedTpmCurve, +{ + /// Key parameters for this curve + pub fn key_params_default() -> KeyParams + where + C: DigestPrimitive, + ::Digest: AssociatedHashingAlgorithm, + { + Self::key_params::() + } + + /// Key parameters for this curve + pub fn key_params() -> KeyParams + where + D: AssociatedHashingAlgorithm, + { + KeyParams::Ecc { + curve: C::TPM_CURVE, + scheme: EccScheme::create(EccSchemeAlgorithm::EcDsa, Some(D::TPM_DIGEST), None) + .expect("Failed to create ecc scheme"), + } + } +} + +impl<'ctx, C> AsRef> for Ecdsa<'ctx, C> +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + fn as_ref(&self) -> &VerifyingKey { + &self.verifying_key + } +} + +impl<'ctx, C> KeypairRef for Ecdsa<'ctx, C> +where + C: PrimeCurve + CurveArithmetic, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, +{ + type VerifyingKey = VerifyingKey; +} + +impl<'ctx, C, D> DigestSigner> for Ecdsa<'ctx, C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + C: AssociatedTpmCurve, + D: Digest + FixedOutput>, + D: AssociatedHashingAlgorithm, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, + TpmDigest: From>, +{ + fn try_sign_digest(&self, digest: D) -> Result, SError> { + let digest = TpmDigest::from(digest.finalize_fixed()); + + let key_params = Self::key_params::(); + let mut context = self.context.lock().unwrap(); + let signature = context + .sign( + self.key_material.clone(), + key_params, + self.key_auth.clone(), + digest, + ) + .unwrap(); + let TpmSignature::EcDsa(signature) = signature else { + todo!(); + }; + + let signature = Signature::try_from(signature).unwrap(); + + Ok(signature) + } +} + +impl<'ctx, C, D> DigestSigner> for Ecdsa<'ctx, C> +where + C: PrimeCurve + CurveArithmetic + DigestPrimitive, + C: AssociatedTpmCurve, + D: Digest + FixedOutput>, + D: AssociatedHashingAlgorithm, + Scalar: Invert>> + SignPrimitive, + SignatureSize: ArrayLength, + TpmDigest: From>, + + MaxSize: ArrayLength, + as Add>::Output: Add + ArrayLength, +{ + fn try_sign_digest(&self, digest: D) -> Result, SError> { + let signature: Signature<_> = self.try_sign_digest(digest)?; + Ok(signature.to_der()) + } +}