Skip to content

Commit

Permalink
Implement DigestSigner/Verifier for PKCS1v15 structs
Browse files Browse the repository at this point in the history
Implement the experimental (preview) DigestSigner and DigestVerifier
traits for the PKCS1v15 structs.

Signed-off-by: Dmitry Baryshkov <dmitry.baryshkov@linaro.org>
  • Loading branch information
lumag committed Aug 30, 2022
1 parent 770d0fc commit db1b854
Show file tree
Hide file tree
Showing 2 changed files with 122 additions and 0 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ nightly = ["num-bigint/nightly"]
serde = ["num-bigint/serde", "serde_crate"]
expose-internals = []
std = ["digest/std", "pkcs1/std", "pkcs8/std", "rand_core/std", "signature/std"]
digest-preview = ["signature/digest-preview" ]
pem = ["pkcs1/pem", "pkcs8/pem"]
pkcs5 = ["pkcs8/encryption"]
getrandom = ["rand_core/getrandom"]
Expand Down
121 changes: 121 additions & 0 deletions src/pkcs1v15.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use core::fmt::{Debug, Display, Formatter, LowerHex, UpperHex};
use core::marker::PhantomData;
use digest::Digest;
use rand_core::{CryptoRng, RngCore};
#[cfg(feature = "digest-preview")]
use signature::{DigestSigner, DigestVerifier, RandomizedDigestSigner};
use signature::{RandomizedSigner, Signature as SignSignature, Signer, Verifier};
use subtle::{Choice, ConditionallySelectable, ConstantTimeEq};
use zeroize::Zeroizing;
Expand Down Expand Up @@ -356,6 +358,39 @@ where
}
}

#[cfg(feature = "digest-preview")]
impl<D> DigestSigner<D, Signature> for SigningKey<D>
where
D: Digest,
{
fn try_sign_digest(&self, digest: D) -> signature::Result<Signature> {
sign::<DummyRng, _>(None, &self.inner, self.hash.as_ref(), &digest.finalize())
.map(|v| v.into())
.map_err(|e| e.into())
}
}

#[cfg(feature = "digest-preview")]
impl<D> RandomizedDigestSigner<D, Signature> for SigningKey<D>
where
D: Digest,
{
fn try_sign_digest_with_rng(
&self,
mut rng: impl CryptoRng + RngCore,
digest: D,
) -> signature::Result<Signature> {
sign(
Some(&mut rng),
&self.inner,
self.hash.as_ref(),
&digest.finalize(),
)
.map(|v| v.into())
.map_err(|e| e.into())
}
}

pub struct VerifyingKey<D>
where
D: Digest,
Expand Down Expand Up @@ -427,6 +462,22 @@ where
}
}

#[cfg(feature = "digest-preview")]
impl<D> DigestVerifier<D, Signature> for VerifyingKey<D>
where
D: Digest,
{
fn verify_digest(&self, digest: D, signature: &Signature) -> signature::Result<()> {
verify(
&self.inner,
self.hash.as_ref(),
&digest.finalize(),
signature.as_ref(),
)
.map_err(|e| e.into())
}
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down Expand Up @@ -588,6 +639,37 @@ mod tests {
}
}

#[cfg(feature = "digest-preview")]
#[test]
fn test_sign_pkcs1v15_digest_signer() {
let priv_key = get_private_key();

let tests = [(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
),
)];

let signing_key = SigningKey::new_with_hash(priv_key, Hash::SHA1);

for (text, expected) in &tests {
let mut digest = Sha1::new();
digest.update(text.as_bytes());
let out = signing_key.sign_digest(digest);
assert_ne!(out.as_ref(), text.as_bytes());
assert_ne!(out.as_ref(), &Sha1::digest(text.as_bytes()).to_vec());
assert_eq!(out.as_ref(), expected);

let mut rng = ChaCha8Rng::from_seed([42; 32]);
let mut digest = Sha1::new();
digest.update(text.as_bytes());
let out2 = signing_key.sign_digest_with_rng(&mut rng, digest);
assert_eq!(out2.as_ref(), expected);
}
}

#[test]
fn test_verify_pkcs1v15() {
let priv_key = get_private_key();
Expand Down Expand Up @@ -668,6 +750,45 @@ mod tests {
}
}

#[cfg(feature = "digest-preview")]
#[test]
fn test_verify_pkcs1v15_digest_signer() {
let priv_key = get_private_key();

let tests = [
(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"
),
true,
),
(
"Test.\n",
hex!(
"a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e33"
"6ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362af"
),
false,
),
];
let pub_key: RsaPublicKey = priv_key.into();
let verifying_key = VerifyingKey::new_with_hash(pub_key, Hash::SHA1);

for (text, sig, expected) in &tests {
let mut digest = Sha1::new();
digest.update(text.as_bytes());
let result = verifying_key.verify_digest(digest, &Signature::from_bytes(sig).unwrap());
match expected {
true => result.expect("failed to verify"),
false => {
result.expect_err("expected verifying error");
()
}
}
}
}
#[test]
fn test_unpadded_signature() {
let msg = b"Thu Dec 19 18:06:16 EST 2013\n";
Expand Down

0 comments on commit db1b854

Please sign in to comment.