-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
adds a
signature::Signer
implementation for ecc keys
Signed-off-by: Arthur Gautier <arthur.gautier@arista.com>
- Loading branch information
Showing
3 changed files
with
173 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
// Copyright 2024 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}, | ||
AssociatedHashingAlgorithm, | ||
}, | ||
interface_types::algorithm::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 SigError, KeypairRef}; | ||
|
||
#[derive(Debug)] | ||
pub struct Ecdsa<'ctx, C> | ||
where | ||
C: PrimeCurve + CurveArithmetic, | ||
{ | ||
context: Mutex<&'ctx mut TransientKeyContext>, | ||
key_material: KeyMaterial, | ||
key_auth: Option<Auth>, | ||
verifying_key: VerifyingKey<C>, | ||
} | ||
|
||
impl<'ctx, C> Ecdsa<'ctx, C> | ||
where | ||
C: PrimeCurve + CurveArithmetic, | ||
C: AssociatedTpmCurve, | ||
FieldBytesSize<C>: ModulusSize, | ||
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>, | ||
{ | ||
pub fn new( | ||
context: &'ctx mut TransientKeyContext, | ||
key_material: KeyMaterial, | ||
key_auth: Option<Auth>, | ||
) -> Result<Self, Error> { | ||
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, | ||
<C as DigestPrimitive>::Digest: AssociatedHashingAlgorithm, | ||
{ | ||
Self::key_params::<C::Digest>() | ||
} | ||
|
||
/// Key parameters for this curve | ||
pub fn key_params<D>() -> 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<VerifyingKey<C>> for Ecdsa<'ctx, C> | ||
where | ||
C: PrimeCurve + CurveArithmetic, | ||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, | ||
SignatureSize<C>: ArrayLength<u8>, | ||
{ | ||
fn as_ref(&self) -> &VerifyingKey<C> { | ||
&self.verifying_key | ||
} | ||
} | ||
|
||
impl<'ctx, C> KeypairRef for Ecdsa<'ctx, C> | ||
where | ||
C: PrimeCurve + CurveArithmetic, | ||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, | ||
SignatureSize<C>: ArrayLength<u8>, | ||
{ | ||
type VerifyingKey = VerifyingKey<C>; | ||
} | ||
|
||
impl<'ctx, C, D> DigestSigner<D, Signature<C>> for Ecdsa<'ctx, C> | ||
where | ||
C: PrimeCurve + CurveArithmetic + DigestPrimitive, | ||
C: AssociatedTpmCurve, | ||
D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>, | ||
D: AssociatedHashingAlgorithm, | ||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, | ||
SignatureSize<C>: ArrayLength<u8>, | ||
TpmDigest: From<Output<D>>, | ||
{ | ||
fn try_sign_digest(&self, digest: D) -> Result<Signature<C>, SigError> { | ||
let digest = TpmDigest::from(digest.finalize_fixed()); | ||
|
||
let key_params = Self::key_params::<D>(); | ||
let mut context = self.context.lock().expect("Mutex got poisoned"); | ||
let signature = context | ||
.sign( | ||
self.key_material.clone(), | ||
key_params, | ||
self.key_auth.clone(), | ||
digest, | ||
) | ||
.map_err(SigError::from_source)?; | ||
let TpmSignature::EcDsa(signature) = signature else { | ||
todo!(); | ||
}; | ||
|
||
let signature = Signature::try_from(signature).map_err(SigError::from_source)?; | ||
|
||
Ok(signature) | ||
} | ||
} | ||
|
||
impl<'ctx, C, D> DigestSigner<D, DerSignature<C>> for Ecdsa<'ctx, C> | ||
where | ||
C: PrimeCurve + CurveArithmetic + DigestPrimitive, | ||
C: AssociatedTpmCurve, | ||
D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>, | ||
D: AssociatedHashingAlgorithm, | ||
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>, | ||
SignatureSize<C>: ArrayLength<u8>, | ||
TpmDigest: From<Output<D>>, | ||
|
||
MaxSize<C>: ArrayLength<u8>, | ||
<FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>, | ||
{ | ||
fn try_sign_digest(&self, digest: D) -> Result<DerSignature<C>, SigError> { | ||
let signature: Signature<_> = self.try_sign_digest(digest)?; | ||
Ok(signature.to_der()) | ||
} | ||
} |