Skip to content

Commit 2cc63f4

Browse files
committed
implement Signer for rsa
Signed-off-by: Arthur Gautier <[email protected]>
1 parent 148cd25 commit 2cc63f4

File tree

3 files changed

+374
-4
lines changed

3 files changed

+374
-4
lines changed

tss-esapi/src/abstraction/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ mod signatures;
1414
mod signer;
1515
pub use hashing::AssociatedHashingAlgorithm;
1616
pub use signer::EcSigner;
17+
#[cfg(feature = "rsa")]
18+
pub use signer::{RsaPkcsSigner, RsaPssSigner};
1719

1820
use std::convert::TryFrom;
1921

tss-esapi/src/abstraction/signer.rs

+287
Original file line numberDiff line numberDiff line change
@@ -327,3 +327,290 @@ where
327327
const SIGNATURE_ALGORITHM_IDENTIFIER: AlgorithmIdentifier<Self::Params> =
328328
Signature::<C>::ALGORITHM_IDENTIFIER;
329329
}
330+
331+
#[cfg(feature = "rsa")]
332+
mod 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+
/// [`RsaPkcsSigner`] will sign a payload with an RSA secret key stored on the TPM.
358+
///
359+
/// ```no_run
360+
/// # use std::sync::Mutex;
361+
/// # use tss_esapi::{
362+
/// # abstraction::{RsaPkcsSigner, transient::{TransientKeyContextBuilder, KeyParams}},
363+
/// # interface_types::{algorithm::{HashingAlgorithm, RsaSchemeAlgorithm}, key_bits::RsaKeyBits},
364+
/// # structures::{RsaExponent, RsaScheme},
365+
/// # TctiNameConf
366+
/// # };
367+
/// use signature::Signer;
368+
/// #
369+
/// # // Create context
370+
/// # let mut context = TransientKeyContextBuilder::new()
371+
/// # .with_tcti(
372+
/// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
373+
/// # )
374+
/// # .build()
375+
/// # .expect("Failed to create Context");
376+
///
377+
/// let key_params = KeyParams::Rsa {
378+
/// size: RsaKeyBits::Rsa1024,
379+
/// scheme: RsaScheme::create(RsaSchemeAlgorithm::RsaSsa, Some(HashingAlgorithm::Sha256))
380+
/// .expect("Failed to create RSA scheme"),
381+
/// pub_exponent: RsaExponent::default(),
382+
/// };
383+
/// let (tpm_km, _tpm_auth) = context
384+
/// .create_key(key_params, 0)
385+
/// .expect("Failed to create a private keypair");
386+
///
387+
/// let signer = RsaPkcsSigner::<_, sha2::Sha256>::new((Mutex::new(&mut context), tpm_km, key_params, None))
388+
/// .expect("Failed to create a signer");
389+
/// let signature = signer.sign(b"Hello Bob, Alice here.");
390+
/// ```
391+
#[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 key_params = Self::key_params::<D>();
453+
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+
/// [`RsaPssSigner`] will sign a payload with an RSA secret key stored on the TPM.
488+
///
489+
/// ```no_run
490+
/// # use std::sync::Mutex;
491+
/// # use tss_esapi::{
492+
/// # abstraction::{RsaPssSigner, transient::{TransientKeyContextBuilder, KeyParams}},
493+
/// # interface_types::{algorithm::{HashingAlgorithm, RsaSchemeAlgorithm}, key_bits::RsaKeyBits},
494+
/// # structures::{RsaExponent, RsaScheme},
495+
/// # TctiNameConf
496+
/// # };
497+
/// use signature::Signer;
498+
/// #
499+
/// # // Create context
500+
/// # let mut context = TransientKeyContextBuilder::new()
501+
/// # .with_tcti(
502+
/// # TctiNameConf::from_environment_variable().expect("Failed to get TCTI"),
503+
/// # )
504+
/// # .build()
505+
/// # .expect("Failed to create Context");
506+
///
507+
/// let key_params = KeyParams::Rsa {
508+
/// size: RsaKeyBits::Rsa1024,
509+
/// scheme: RsaScheme::create(RsaSchemeAlgorithm::RsaPss, Some(HashingAlgorithm::Sha256))
510+
/// .expect("Failed to create RSA scheme"),
511+
/// pub_exponent: RsaExponent::default(),
512+
/// };
513+
/// let (tpm_km, _tpm_auth) = context
514+
/// .create_key(key_params, 0)
515+
/// .expect("Failed to create a private keypair");
516+
///
517+
/// let signer = RsaPssSigner::<_, sha2::Sha256>::new((Mutex::new(&mut context), tpm_km, key_params, None))
518+
/// .expect("Failed to create a signer");
519+
/// let signature = signer.sign(b"Hello Bob, Alice here.");
520+
/// ```
521+
#[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")]
616+
pub use self::rsa::{RsaPkcsSigner, RsaPssSigner};

0 commit comments

Comments
 (0)