Files
Tony Arcieri 1b47ec5298 dsa: impl Generate for Components and SigningKey (#1372)
This renames the old `SigningKey::generate` to
`try_generate_from_rng_with_components`, having the new one generate
random `Components` with a 3072-bit modulus size, which is now the
`Default` for `KeySize`.
2026-06-06 11:27:17 -06:00

156 lines
4.9 KiB
Rust

#![cfg(feature = "hazmat")]
#![allow(deprecated)]
use digest::Digest;
use dsa::{Components, KeySize, Signature, SigningKey};
use getrandom::{SysRng, rand_core::UnwrapErr};
use hex_literal::hex;
use pkcs8::der::{Decode, Encode};
use sha2::Sha256;
use signature::{
DigestVerifier, RandomizedDigestSigner, Signer, Verifier,
hazmat::{PrehashSigner, PrehashVerifier},
};
/// Message to be signed/verified
const MESSAGE: &[u8] = b"test";
/// Message signed by this crate
const MESSAGE_SIGNATURE_CRATE_ASN1: &[u8] = &[
0x30, 0x2c, 0x2, 0x14, 0x4e, 0x12, 0x27, 0x75, 0x18, 0xf6, 0x40, 0xe3, 0x3a, 0xdb, 0x80, 0x6d,
0xe7, 0x98, 0xd3, 0xa3, 0x40, 0xf5, 0x9d, 0xf, 0x2, 0x14, 0x17, 0x78, 0x1e, 0xc8, 0x53, 0x58,
0x91, 0xe0, 0x3f, 0x2d, 0x36, 0x27, 0x36, 0x6b, 0xac, 0x8e, 0xd7, 0xf9, 0xa4, 0xcf,
];
/// Message signed by OpenSSL
///
/// This signature was generated using the SHA-256 digest
const MESSAGE_SIGNATURE_OPENSSL_ASN1: &[u8] = &hex!(
"302c 0214 3a2b 2250 3e2d 21b3 22a1 c834
1668 2c0c 98df 2dee 0214 501d 1ffb bbba
9925 a1d1 7bb8 c835 ca27 0931 ca6a"
);
/// Generate a random DSA keypair
fn generate_random_keypair() -> SigningKey {
let mut rng = UnwrapErr(SysRng);
let components =
Components::try_generate_from_rng_with_key_size(&mut rng, KeySize::DSA_1024_160).unwrap();
SigningKey::try_generate_from_rng_with_components(&mut rng, components).unwrap()
}
#[test]
fn decode_encode_signature() {
let signature_openssl =
Signature::from_der(MESSAGE_SIGNATURE_OPENSSL_ASN1).expect("Failed to decode signature");
let encoded_signature_openssl = signature_openssl
.to_der()
.expect("Failed to encode signature");
assert_eq!(MESSAGE_SIGNATURE_OPENSSL_ASN1, encoded_signature_openssl);
let signature_crate =
Signature::from_der(MESSAGE_SIGNATURE_CRATE_ASN1).expect("Failed to decode signature");
let encoded_signature_crate = signature_crate
.to_der()
.expect("Failed to encode signature");
assert_eq!(MESSAGE_SIGNATURE_CRATE_ASN1, encoded_signature_crate);
}
#[test]
fn sign_verify_message() {
let signing_key = generate_random_keypair();
let mut rng = UnwrapErr(SysRng);
let generated_signature =
signing_key.sign_digest_with_rng(&mut rng, |digest: &mut Sha256| digest.update(MESSAGE));
assert!(
signing_key
.verifying_key()
.verify_digest(
|digest: &mut Sha256| {
digest.update(MESSAGE);
Ok(())
},
&generated_signature
)
.is_ok()
);
}
#[test]
fn signer_verifier_signature() {
let signing_key = generate_random_keypair();
let verifying_key = signing_key.verifying_key();
let message = b"Hello world! This is the message signed as part of the testing process.";
// construct signature manually and by `Signer` defaults. Ensure results are identical.
let manual_digest = Sha256::new_with_prefix(message).finalize();
let manual_signature = signing_key.sign_prehash(&manual_digest).unwrap();
let signer_signature = signing_key.sign(message);
verifying_key.verify(message, &manual_signature).unwrap();
verifying_key.verify(message, &signer_signature).unwrap();
assert_eq!(manual_signature, signer_signature);
// verify signature manually and by `Verifier` defaults. Ensure signatures can be applied interchangeably.
verifying_key
.verify_prehash(&manual_digest, &manual_signature)
.unwrap();
verifying_key
.verify_prehash(&manual_digest, &signer_signature)
.unwrap();
verifying_key.verify(message, &manual_signature).unwrap();
verifying_key.verify(message, &signer_signature).unwrap();
}
/// This test forces the r and s of the signature to a bit precision different to what would
/// otherwise be expected
#[test]
#[allow(clippy::slow_vector_initialization)]
fn verify_signature_precision() {
use der::{Sequence, asn1::Uint};
let signing_key = generate_random_keypair();
let verifying_key = signing_key.verifying_key();
#[derive(Sequence)]
struct MockSignature {
r: Uint,
s: Uint,
}
for value in &[
{
let mut value = vec![];
value.resize(512, 0);
value.push(1);
value
},
{
let mut value = vec![];
value.push(1);
value.resize(512, 0);
value
},
] {
let asn1 = MockSignature {
r: Uint::new(value).unwrap(),
s: Uint::new(value).unwrap(),
}
.to_der()
.expect("Failed to serialize signature");
let signature = Signature::from_der(&asn1)
.expect("Failed to parse ASN.1 representation of the test signature");
let _ = verifying_key.verify_digest(
|digest: &mut Sha256| {
digest.update(MESSAGE);
Ok(())
},
&signature,
);
}
}