Skip to content

Commit df740fd

Browse files
committed
adds a signature::Signer implementation for ecc keys
Signed-off-by: Arthur Gautier <[email protected]>
1 parent ef81f09 commit df740fd

File tree

3 files changed

+173
-0
lines changed

3 files changed

+173
-0
lines changed

tss-esapi/Cargo.toml

+1
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@ sha3 = { version = "0.10.8", optional = true }
4242
sm2 = { version = "0.13.3", optional = true }
4343
sm3 = { version = "0.4.2", optional = true }
4444
digest = "0.10.7"
45+
signature = "2.2.0"
4546
cfg-if = "1.0.0"
4647
strum = { version = "0.25.0", optional = true }
4748
strum_macros = { version = "0.25.0", optional = true }

tss-esapi/src/abstraction/transient/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -34,8 +34,10 @@ use std::convert::{AsMut, AsRef, TryFrom, TryInto};
3434
use zeroize::Zeroize;
3535

3636
mod key_attestation;
37+
mod signer;
3738

3839
pub use key_attestation::MakeCredParams;
40+
pub use signer::Ecdsa;
3941

4042
/// Parameters for the kinds of keys supported by the context
4143
#[derive(Debug, Clone, Copy)]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
// Copyright 2024 Contributors to the Parsec project.
2+
// SPDX-License-Identifier: Apache-2.0
3+
4+
//! Module for exposing a [`signature::Signer`] interface for keys
5+
//!
6+
//! This modules presents objects held in a TPM over a [`signature::DigestSigner`] interface.
7+
use super::TransientKeyContext;
8+
use crate::{
9+
abstraction::{
10+
public::AssociatedTpmCurve,
11+
transient::{KeyMaterial, KeyParams},
12+
AssociatedHashingAlgorithm,
13+
},
14+
interface_types::algorithm::EccSchemeAlgorithm,
15+
structures::{Auth, Digest as TpmDigest, EccScheme, Signature as TpmSignature},
16+
Error,
17+
};
18+
19+
use std::{convert::TryFrom, ops::Add, sync::Mutex};
20+
21+
use digest::{Digest, FixedOutput, Output};
22+
use ecdsa::{
23+
der::{MaxOverhead, MaxSize, Signature as DerSignature},
24+
hazmat::{DigestPrimitive, SignPrimitive},
25+
Signature, SignatureSize, VerifyingKey,
26+
};
27+
use elliptic_curve::{
28+
generic_array::ArrayLength,
29+
ops::Invert,
30+
sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint},
31+
subtle::CtOption,
32+
AffinePoint, CurveArithmetic, FieldBytesSize, PrimeCurve, PublicKey, Scalar,
33+
};
34+
use signature::{DigestSigner, Error as SigError, KeypairRef};
35+
36+
#[derive(Debug)]
37+
pub struct Ecdsa<'ctx, C>
38+
where
39+
C: PrimeCurve + CurveArithmetic,
40+
{
41+
context: Mutex<&'ctx mut TransientKeyContext>,
42+
key_material: KeyMaterial,
43+
key_auth: Option<Auth>,
44+
verifying_key: VerifyingKey<C>,
45+
}
46+
47+
impl<'ctx, C> Ecdsa<'ctx, C>
48+
where
49+
C: PrimeCurve + CurveArithmetic,
50+
C: AssociatedTpmCurve,
51+
FieldBytesSize<C>: ModulusSize,
52+
AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
53+
{
54+
pub fn new(
55+
context: &'ctx mut TransientKeyContext,
56+
key_material: KeyMaterial,
57+
key_auth: Option<Auth>,
58+
) -> Result<Self, Error> {
59+
let context = Mutex::new(context);
60+
61+
let public_key = PublicKey::try_from(key_material.public())?;
62+
let verifying_key = VerifyingKey::from(public_key);
63+
64+
Ok(Self {
65+
context,
66+
key_material,
67+
key_auth,
68+
verifying_key,
69+
})
70+
}
71+
}
72+
73+
impl<'ctx, C> Ecdsa<'ctx, C>
74+
where
75+
C: PrimeCurve + CurveArithmetic,
76+
C: AssociatedTpmCurve,
77+
{
78+
/// Key parameters for this curve
79+
pub fn key_params_default() -> KeyParams
80+
where
81+
C: DigestPrimitive,
82+
<C as DigestPrimitive>::Digest: AssociatedHashingAlgorithm,
83+
{
84+
Self::key_params::<C::Digest>()
85+
}
86+
87+
/// Key parameters for this curve
88+
pub fn key_params<D>() -> KeyParams
89+
where
90+
D: AssociatedHashingAlgorithm,
91+
{
92+
KeyParams::Ecc {
93+
curve: C::TPM_CURVE,
94+
scheme: EccScheme::create(EccSchemeAlgorithm::EcDsa, Some(D::TPM_DIGEST), None)
95+
.expect("Failed to create ecc scheme"),
96+
}
97+
}
98+
}
99+
100+
impl<'ctx, C> AsRef<VerifyingKey<C>> for Ecdsa<'ctx, C>
101+
where
102+
C: PrimeCurve + CurveArithmetic,
103+
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
104+
SignatureSize<C>: ArrayLength<u8>,
105+
{
106+
fn as_ref(&self) -> &VerifyingKey<C> {
107+
&self.verifying_key
108+
}
109+
}
110+
111+
impl<'ctx, C> KeypairRef for Ecdsa<'ctx, C>
112+
where
113+
C: PrimeCurve + CurveArithmetic,
114+
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
115+
SignatureSize<C>: ArrayLength<u8>,
116+
{
117+
type VerifyingKey = VerifyingKey<C>;
118+
}
119+
120+
impl<'ctx, C, D> DigestSigner<D, Signature<C>> for Ecdsa<'ctx, C>
121+
where
122+
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
123+
C: AssociatedTpmCurve,
124+
D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
125+
D: AssociatedHashingAlgorithm,
126+
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
127+
SignatureSize<C>: ArrayLength<u8>,
128+
TpmDigest: From<Output<D>>,
129+
{
130+
fn try_sign_digest(&self, digest: D) -> Result<Signature<C>, SigError> {
131+
let digest = TpmDigest::from(digest.finalize_fixed());
132+
133+
let key_params = Self::key_params::<D>();
134+
let mut context = self.context.lock().expect("Mutex got poisoned");
135+
let signature = context
136+
.sign(
137+
self.key_material.clone(),
138+
key_params,
139+
self.key_auth.clone(),
140+
digest,
141+
)
142+
.map_err(SigError::from_source)?;
143+
let TpmSignature::EcDsa(signature) = signature else {
144+
todo!();
145+
};
146+
147+
let signature = Signature::try_from(signature).map_err(SigError::from_source)?;
148+
149+
Ok(signature)
150+
}
151+
}
152+
153+
impl<'ctx, C, D> DigestSigner<D, DerSignature<C>> for Ecdsa<'ctx, C>
154+
where
155+
C: PrimeCurve + CurveArithmetic + DigestPrimitive,
156+
C: AssociatedTpmCurve,
157+
D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
158+
D: AssociatedHashingAlgorithm,
159+
Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
160+
SignatureSize<C>: ArrayLength<u8>,
161+
TpmDigest: From<Output<D>>,
162+
163+
MaxSize<C>: ArrayLength<u8>,
164+
<FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
165+
{
166+
fn try_sign_digest(&self, digest: D) -> Result<DerSignature<C>, SigError> {
167+
let signature: Signature<_> = self.try_sign_digest(digest)?;
168+
Ok(signature.to_der())
169+
}
170+
}

0 commit comments

Comments
 (0)