1use crate::{
8 abstraction::{
9 public::AssociatedTpmCurve,
10 transient::{KeyMaterial, KeyParams, TransientKeyContext},
11 AssociatedHashingAlgorithm,
12 },
13 handles::KeyHandle,
14 interface_types::algorithm::EccSchemeAlgorithm,
15 structures::{
16 Auth, Digest as TpmDigest, EccScheme, Public, Signature as TpmSignature, SignatureScheme,
17 },
18 utils::PublicKey as TpmPublicKey,
19 Context, Error, WrapperErrorKind,
20};
21
22use std::{convert::TryFrom, ops::Add, sync::Mutex};
23
24use digest::{Digest, FixedOutput, Output};
25use ecdsa::{
26 der::{MaxOverhead, MaxSize, Signature as DerSignature},
27 hazmat::{DigestPrimitive, SignPrimitive},
28 Signature, SignatureSize, VerifyingKey,
29};
30use elliptic_curve::{
31 generic_array::ArrayLength,
32 ops::Invert,
33 sec1::{FromEncodedPoint, ModulusSize, ToEncodedPoint},
34 subtle::CtOption,
35 AffinePoint, CurveArithmetic, FieldBytesSize, PrimeCurve, PublicKey, Scalar,
36};
37use log::error;
38use signature::{DigestSigner, Error as SigError, KeypairRef, Signer};
39use x509_cert::{
40 der::asn1::AnyRef,
41 spki::{AlgorithmIdentifier, AssociatedAlgorithmIdentifier, SignatureAlgorithmIdentifier},
42};
43
44pub trait TpmSigner {
45 fn public(&self) -> crate::Result<TpmPublicKey>;
46 fn key_params(&self) -> crate::Result<KeyParams>;
47 fn sign(&self, digest: TpmDigest) -> crate::Result<TpmSignature>;
48}
49
50impl TpmSigner for (Mutex<&'_ mut Context>, KeyHandle) {
51 fn public(&self) -> crate::Result<TpmPublicKey> {
52 let mut context = self.0.lock().expect("Mutex got poisoned");
53 let (public, _, _) = context.read_public(self.1)?;
54
55 TpmPublicKey::try_from(public)
56 }
57
58 fn key_params(&self) -> crate::Result<KeyParams> {
59 let mut context = self.0.lock().expect("Mutex got poisoned");
60 let (public, _, _) = context.read_public(self.1)?;
61
62 match public {
63 Public::Rsa { parameters, .. } => Ok(KeyParams::Rsa {
64 size: parameters.key_bits(),
65 scheme: parameters.rsa_scheme(),
66 pub_exponent: parameters.exponent(),
67 }),
68 Public::Ecc { parameters, .. } => Ok(KeyParams::Ecc {
69 curve: parameters.ecc_curve(),
70 scheme: parameters.ecc_scheme(),
71 }),
72 other => {
73 error!("Unsupported key parameter used: {other:?}");
74 Err(Error::local_error(WrapperErrorKind::InvalidParam))
75 }
76 }
77 }
78
79 fn sign(&self, digest: TpmDigest) -> crate::Result<TpmSignature> {
80 let mut context = self.0.lock().expect("Mutex got poisoned");
81 context.sign(self.1, digest, SignatureScheme::Null, None)
82 }
83}
84
85impl TpmSigner
86 for (
87 Mutex<&'_ mut TransientKeyContext>,
88 KeyMaterial,
89 KeyParams,
90 Option<Auth>,
91 )
92{
93 fn public(&self) -> crate::Result<TpmPublicKey> {
94 Ok(self.1.public().clone())
95 }
96
97 fn key_params(&self) -> crate::Result<KeyParams> {
98 Ok(self.2)
99 }
100
101 fn sign(&self, digest: TpmDigest) -> crate::Result<TpmSignature> {
102 let mut context = self.0.lock().expect("Mutex got poisoned");
103 context.sign(self.1.clone(), self.2, self.3.clone(), digest)
104 }
105}
106
107#[derive(Debug)]
140pub struct EcSigner<C, Ctx>
141where
142 C: PrimeCurve + CurveArithmetic,
143{
144 context: Ctx,
145 verifying_key: VerifyingKey<C>,
146}
147
148impl<C, Ctx> EcSigner<C, Ctx>
149where
150 C: PrimeCurve + CurveArithmetic,
151 C: AssociatedTpmCurve,
152 FieldBytesSize<C>: ModulusSize,
153 AffinePoint<C>: FromEncodedPoint<C> + ToEncodedPoint<C>,
154
155 Ctx: TpmSigner,
156{
157 pub fn new(context: Ctx) -> Result<Self, Error> {
158 match context.key_params()? {
159 KeyParams::Ecc { curve, .. } if curve == C::TPM_CURVE => {}
160 other => {
161 error!(
162 "Unsupported key parameters: {other:?}, expected Ecc(curve: {:?})",
163 C::default()
164 );
165 return Err(Error::local_error(WrapperErrorKind::InvalidParam));
166 }
167 }
168
169 let public_key = context.public()?;
170 let public_key = PublicKey::try_from(&public_key)?;
171 let verifying_key = VerifyingKey::from(public_key);
172
173 Ok(Self {
174 context,
175 verifying_key,
176 })
177 }
178}
179
180impl<C, Ctx> EcSigner<C, Ctx>
181where
182 C: PrimeCurve + CurveArithmetic,
183 C: AssociatedTpmCurve,
184{
185 pub fn key_params_default() -> KeyParams
187 where
188 C: DigestPrimitive,
189 <C as DigestPrimitive>::Digest: FixedOutput<OutputSize = FieldBytesSize<C>>,
190 <C as DigestPrimitive>::Digest: AssociatedHashingAlgorithm,
191 {
192 Self::key_params::<<C as DigestPrimitive>::Digest>()
193 }
194
195 pub fn key_params<D>() -> KeyParams
201 where
202 D: FixedOutput<OutputSize = FieldBytesSize<C>>,
203 D: AssociatedHashingAlgorithm,
204 {
205 KeyParams::Ecc {
206 curve: C::TPM_CURVE,
207 scheme: EccScheme::create(EccSchemeAlgorithm::EcDsa, Some(D::TPM_DIGEST), None)
208 .expect("Failed to create ecc scheme"),
209 }
210 }
211}
212
213impl<C, Ctx> AsRef<VerifyingKey<C>> for EcSigner<C, Ctx>
214where
215 C: PrimeCurve + CurveArithmetic,
216 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
217 SignatureSize<C>: ArrayLength<u8>,
218{
219 fn as_ref(&self) -> &VerifyingKey<C> {
220 &self.verifying_key
221 }
222}
223
224impl<C, Ctx> KeypairRef for EcSigner<C, Ctx>
225where
226 C: PrimeCurve + CurveArithmetic,
227 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
228 SignatureSize<C>: ArrayLength<u8>,
229{
230 type VerifyingKey = VerifyingKey<C>;
231}
232
233impl<C, Ctx, D> DigestSigner<D, Signature<C>> for EcSigner<C, Ctx>
234where
235 C: PrimeCurve + CurveArithmetic,
236 C: AssociatedTpmCurve,
237 D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
238 D: AssociatedHashingAlgorithm,
239 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
240 SignatureSize<C>: ArrayLength<u8>,
241 TpmDigest: From<Output<D>>,
242 Ctx: TpmSigner,
243{
244 fn try_sign_digest(&self, digest: D) -> Result<Signature<C>, SigError> {
245 let digest = TpmDigest::from(digest.finalize_fixed());
246
247 let signature = self.context.sign(digest).map_err(SigError::from_source)?;
249
250 let TpmSignature::EcDsa(signature) = signature else {
251 return Err(SigError::from_source(Error::local_error(
252 WrapperErrorKind::InvalidParam,
253 )));
254 };
255
256 let signature = Signature::try_from(&signature).map_err(SigError::from_source)?;
257
258 Ok(signature)
259 }
260}
261
262impl<C, Ctx, D> DigestSigner<D, DerSignature<C>> for EcSigner<C, Ctx>
263where
264 C: PrimeCurve + CurveArithmetic,
265 C: AssociatedTpmCurve,
266 D: Digest + FixedOutput<OutputSize = FieldBytesSize<C>>,
267 D: AssociatedHashingAlgorithm,
268 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
269 SignatureSize<C>: ArrayLength<u8>,
270 TpmDigest: From<Output<D>>,
271
272 MaxSize<C>: ArrayLength<u8>,
273 <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
274
275 Ctx: TpmSigner,
276{
277 fn try_sign_digest(&self, digest: D) -> Result<DerSignature<C>, SigError> {
278 let signature: Signature<_> = self.try_sign_digest(digest)?;
279 Ok(signature.to_der())
280 }
281}
282
283impl<C, Ctx> Signer<Signature<C>> for EcSigner<C, Ctx>
284where
285 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
286 C: AssociatedTpmCurve,
287 <C as DigestPrimitive>::Digest: AssociatedHashingAlgorithm,
288 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
289 SignatureSize<C>: ArrayLength<u8>,
290 TpmDigest: From<Output<<C as DigestPrimitive>::Digest>>,
291
292 Ctx: TpmSigner,
293{
294 fn try_sign(&self, msg: &[u8]) -> Result<Signature<C>, SigError> {
295 self.try_sign_digest(C::Digest::new_with_prefix(msg))
296 }
297}
298
299impl<C, Ctx> Signer<DerSignature<C>> for EcSigner<C, Ctx>
300where
301 C: PrimeCurve + CurveArithmetic + DigestPrimitive,
302 C: AssociatedTpmCurve,
303 <C as DigestPrimitive>::Digest: AssociatedHashingAlgorithm,
304 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
305 SignatureSize<C>: ArrayLength<u8>,
306 TpmDigest: From<Output<<C as DigestPrimitive>::Digest>>,
307
308 MaxSize<C>: ArrayLength<u8>,
309 <FieldBytesSize<C> as Add>::Output: Add<MaxOverhead> + ArrayLength<u8>,
310
311 Ctx: TpmSigner,
312{
313 fn try_sign(&self, msg: &[u8]) -> Result<DerSignature<C>, SigError> {
314 self.try_sign_digest(C::Digest::new_with_prefix(msg))
315 }
316}
317
318impl<C, Ctx> SignatureAlgorithmIdentifier for EcSigner<C, Ctx>
319where
320 C: PrimeCurve + CurveArithmetic,
321 Scalar<C>: Invert<Output = CtOption<Scalar<C>>> + SignPrimitive<C>,
322 SignatureSize<C>: ArrayLength<u8>,
323 Signature<C>: AssociatedAlgorithmIdentifier<Params = AnyRef<'static>>,
324{
325 type Params = AnyRef<'static>;
326
327 const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
328 Signature::<C>::ALGORITHM_IDENTIFIER;
329}
330
331#[cfg(feature = "rsa")]
332mod rsa {
333 use super::TpmSigner;
334
335 use crate::{
336 abstraction::{signer::KeyParams, AssociatedHashingAlgorithm},
337 structures::{Digest as TpmDigest, RsaScheme},
338 Error, WrapperErrorKind,
339 };
340
341 use std::fmt;
342
343 use digest::{Digest, FixedOutput, Output};
344 use log::error;
345 use pkcs8::AssociatedOid;
346 use signature::{DigestSigner, Error as SigError, Keypair, Signer};
347 use x509_cert::{
348 der::asn1::AnyRef,
349 spki::{
350 self, AlgorithmIdentifier, AlgorithmIdentifierOwned, AssociatedAlgorithmIdentifier,
351 DynSignatureAlgorithmIdentifier, SignatureAlgorithmIdentifier,
352 },
353 };
354
355 use ::rsa::{pkcs1v15, pss, RsaPublicKey};
356
357 #[derive(Debug)]
392 pub struct RsaPkcsSigner<Ctx, D>
393 where
394 D: Digest,
395 {
396 context: Ctx,
397 verifying_key: pkcs1v15::VerifyingKey<D>,
398 }
399
400 impl<Ctx, D> RsaPkcsSigner<Ctx, D>
401 where
402 Ctx: TpmSigner,
403 D: Digest + AssociatedOid + AssociatedHashingAlgorithm + fmt::Debug,
404 {
405 pub fn new(context: Ctx) -> Result<Self, Error> {
406 match context.key_params()? {
407 KeyParams::Rsa {
408 scheme: RsaScheme::RsaSsa(hash),
409 ..
410 } if hash.hashing_algorithm() == D::TPM_DIGEST => {}
411 other => {
412 error!(
413 "Unsupported key parameters: {other:?}, expected RsaSsa({:?})",
414 D::new()
415 );
416 return Err(Error::local_error(WrapperErrorKind::InvalidParam));
417 }
418 }
419
420 let public_key = context.public()?;
421 let public_key = RsaPublicKey::try_from(&public_key)?;
422 let verifying_key = pkcs1v15::VerifyingKey::new(public_key);
423
424 Ok(Self {
425 context,
426 verifying_key,
427 })
428 }
429 }
430
431 impl<Ctx, D> Keypair for RsaPkcsSigner<Ctx, D>
432 where
433 D: Digest,
434 {
435 type VerifyingKey = pkcs1v15::VerifyingKey<D>;
436
437 fn verifying_key(&self) -> Self::VerifyingKey {
438 self.verifying_key.clone()
439 }
440 }
441
442 impl<Ctx, D> DigestSigner<D, pkcs1v15::Signature> for RsaPkcsSigner<Ctx, D>
443 where
444 D: Digest + FixedOutput,
445 D: AssociatedHashingAlgorithm,
446 TpmDigest: From<Output<D>>,
447 Ctx: TpmSigner,
448 {
449 fn try_sign_digest(&self, digest: D) -> Result<pkcs1v15::Signature, SigError> {
450 let digest = TpmDigest::from(digest.finalize_fixed());
451
452 let signature = self.context.sign(digest).map_err(SigError::from_source)?;
454
455 let signature =
456 pkcs1v15::Signature::try_from(&signature).map_err(SigError::from_source)?;
457
458 Ok(signature)
459 }
460 }
461
462 impl<Ctx, D> Signer<pkcs1v15::Signature> for RsaPkcsSigner<Ctx, D>
463 where
464 D: Digest + FixedOutput,
465 D: AssociatedHashingAlgorithm,
466 TpmDigest: From<Output<D>>,
467 Ctx: TpmSigner,
468 {
469 fn try_sign(&self, msg: &[u8]) -> Result<pkcs1v15::Signature, SigError> {
470 let mut d = D::new();
471 Digest::update(&mut d, msg);
472
473 self.try_sign_digest(d)
474 }
475 }
476
477 impl<Ctx, D> SignatureAlgorithmIdentifier for RsaPkcsSigner<Ctx, D>
478 where
479 D: Digest + pkcs1v15::RsaSignatureAssociatedOid,
480 {
481 type Params = AnyRef<'static>;
482
483 const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
484 pkcs1v15::SigningKey::<D>::ALGORITHM_IDENTIFIER;
485 }
486
487 #[derive(Debug)]
522 pub struct RsaPssSigner<Ctx, D>
523 where
524 D: Digest,
525 {
526 context: Ctx,
527 verifying_key: pss::VerifyingKey<D>,
528 }
529
530 impl<Ctx, D> RsaPssSigner<Ctx, D>
531 where
532 Ctx: TpmSigner,
533 D: Digest + AssociatedHashingAlgorithm + fmt::Debug,
534 {
535 pub fn new(context: Ctx) -> Result<Self, Error> {
536 match context.key_params()? {
537 KeyParams::Rsa {
538 scheme: RsaScheme::RsaPss(hash),
539 ..
540 } if hash.hashing_algorithm() == D::TPM_DIGEST => {}
541 other => {
542 error!(
543 "Unsupported key parameters: {other:?}, expected RsaSsa({:?})",
544 D::new()
545 );
546 return Err(Error::local_error(WrapperErrorKind::InvalidParam));
547 }
548 }
549
550 let public_key = context.public()?;
551 let public_key = RsaPublicKey::try_from(&public_key)?;
552 let verifying_key = pss::VerifyingKey::new(public_key);
553
554 Ok(Self {
555 context,
556 verifying_key,
557 })
558 }
559 }
560
561 impl<Ctx, D> Keypair for RsaPssSigner<Ctx, D>
562 where
563 D: Digest,
564 {
565 type VerifyingKey = pss::VerifyingKey<D>;
566
567 fn verifying_key(&self) -> Self::VerifyingKey {
568 self.verifying_key.clone()
569 }
570 }
571
572 impl<Ctx, D> DigestSigner<D, pss::Signature> for RsaPssSigner<Ctx, D>
573 where
574 D: Digest + FixedOutput,
575 D: AssociatedHashingAlgorithm,
576 TpmDigest: From<Output<D>>,
577 Ctx: TpmSigner,
578 {
579 fn try_sign_digest(&self, digest: D) -> Result<pss::Signature, SigError> {
580 let digest = TpmDigest::from(digest.finalize_fixed());
581
582 let signature = self.context.sign(digest).map_err(SigError::from_source)?;
583
584 let signature = pss::Signature::try_from(&signature).map_err(SigError::from_source)?;
585
586 Ok(signature)
587 }
588 }
589
590 impl<Ctx, D> Signer<pss::Signature> for RsaPssSigner<Ctx, D>
591 where
592 D: Digest + FixedOutput,
593 D: AssociatedHashingAlgorithm,
594 TpmDigest: From<Output<D>>,
595 Ctx: TpmSigner,
596 {
597 fn try_sign(&self, msg: &[u8]) -> Result<pss::Signature, SigError> {
598 let mut d = D::new();
599 Digest::update(&mut d, msg);
600
601 self.try_sign_digest(d)
602 }
603 }
604
605 impl<Ctx, D> DynSignatureAlgorithmIdentifier for RsaPssSigner<Ctx, D>
606 where
607 D: Digest + AssociatedOid,
608 {
609 fn signature_algorithm_identifier(&self) -> spki::Result<AlgorithmIdentifierOwned> {
610 pss::get_default_pss_signature_algo_id::<D>()
611 }
612 }
613}
614
615#[cfg(feature = "rsa")]
616pub use self::rsa::{RsaPkcsSigner, RsaPssSigner};