use crate::der::{Reader, parse_oid};
use crate::hash::{Sha1, Sha256, Sha384, Sha512};
use crate::rsa::BoxedRsaPublicKey;
use crate::signature_registry::SignatureAlgorithm;
use crate::x509::{Error, oid};
fn parse_rsa_spki(spki: &[u8]) -> Result<BoxedRsaPublicKey, Error> {
let mut reader = Reader::new(spki);
let mut outer = reader.read_sequence()?;
let mut algid = outer.read_sequence()?;
let alg = parse_oid(algid.read_oid()?)?;
if alg.as_slice() == oid::RSA_ENCRYPTION {
algid.read_null()?;
algid.finish()?;
} else if alg.as_slice() == oid::ID_RSASSA_PSS {
while !algid.is_empty() {
algid.read_element()?;
}
} else {
return Err(Error::UnsupportedAlgorithm);
}
let key_bits = outer.read_bit_string()?;
outer.finish()?;
Ok(BoxedRsaPublicKey::from_pkcs1_der(key_bits)?)
}
fn rsa_bits(spki: &[u8]) -> Option<u32> {
parse_rsa_spki(spki)
.ok()
.map(|k| k.modulus().bit_len() as u32)
}
macro_rules! rsa_pkcs1_entry {
($(#[$m:meta])* $name:ident, $id:expr, $oid:expr, $tls:expr, $digest:ty) => {
$(#[$m])*
pub(crate) struct $name;
impl SignatureAlgorithm for $name {
fn id(&self) -> &'static str { $id }
fn x509_oids(&self) -> &'static [&'static [u64]] { &[$oid] }
fn tls_schemes(&self) -> &'static [u16] { $tls }
fn verify(&self, spki: &[u8], message: &[u8], signature: &[u8]) -> Result<(), Error> {
let key = parse_rsa_spki(spki)?;
key.verify_pkcs1v15::<$digest>(message, signature).map_err(Error::Rsa)
}
fn rsa_modulus_bits(&self, spki: &[u8]) -> Option<u32> { rsa_bits(spki) }
}
};
}
macro_rules! rsa_pss_entry {
($(#[$m:meta])* $name:ident, $id:expr, $oid:expr, $tls:expr, $digest:ty) => {
$(#[$m])*
pub(crate) struct $name;
impl SignatureAlgorithm for $name {
fn id(&self) -> &'static str { $id }
fn x509_oids(&self) -> &'static [&'static [u64]] { &[$oid] }
fn tls_schemes(&self) -> &'static [u16] { $tls }
fn verify(&self, spki: &[u8], message: &[u8], signature: &[u8]) -> Result<(), Error> {
let key = parse_rsa_spki(spki)?;
key.verify_pss::<$digest>(message, signature).map_err(Error::Rsa)
}
fn rsa_modulus_bits(&self, spki: &[u8]) -> Option<u32> { rsa_bits(spki) }
}
};
}
rsa_pkcs1_entry!(
Pkcs1Sha1,
"rsa-pkcs1-sha1",
oid::SHA1_WITH_RSA,
&[],
Sha1
);
rsa_pkcs1_entry!(
Pkcs1Sha256,
"rsa-pkcs1-sha256",
oid::SHA256_WITH_RSA,
&[0x0401],
Sha256
);
rsa_pkcs1_entry!(
Pkcs1Sha384,
"rsa-pkcs1-sha384",
oid::SHA384_WITH_RSA,
&[0x0501],
Sha384
);
rsa_pkcs1_entry!(
Pkcs1Sha512,
"rsa-pkcs1-sha512",
oid::SHA512_WITH_RSA,
&[],
Sha512
);
rsa_pss_entry!(
PssRsaeSha256,
"rsa-pss-rsae-sha256",
oid::SHA256_WITH_RSA,
&[0x0804],
Sha256
);
rsa_pss_entry!(
PssRsaeSha384,
"rsa-pss-rsae-sha384",
oid::SHA384_WITH_RSA,
&[0x0805],
Sha384
);
rsa_pss_entry!(
PssRsaeSha512,
"rsa-pss-rsae-sha512",
oid::SHA512_WITH_RSA,
&[0x0806],
Sha512
);
rsa_pss_entry!(
PssPssSha256,
"rsa-pss-pss-sha256",
oid::ID_RSASSA_PSS,
&[],
Sha256
);
#[cfg(test)]
mod tests {
use super::*;
use crate::signature_registry::{find_by_id, find_by_oid, find_by_tls_scheme};
use crate::test_util::rsa_test_key_a;
use crate::x509::AnyPublicKey;
#[test]
fn ids_and_oids_resolve() {
for (id, scheme) in [
("rsa-pkcs1-sha256", 0x0401u16),
("rsa-pkcs1-sha384", 0x0501),
("rsa-pss-rsae-sha256", 0x0804),
("rsa-pss-rsae-sha384", 0x0805),
("rsa-pss-rsae-sha512", 0x0806),
] {
let by_id = find_by_id(id).expect(id);
assert_eq!(by_id.id(), id);
let by_scheme = find_by_tls_scheme(scheme).expect(id);
assert_eq!(by_scheme.id(), id);
}
assert!(find_by_id("rsa-pkcs1-sha512").is_some());
assert!(find_by_oid(oid::SHA512_WITH_RSA).is_some());
}
fn boxed_pk_from_rsa_test_key() -> BoxedRsaPublicKey {
let pk = rsa_test_key_a().public_key();
let mut n = [0u8; 256];
pk.modulus().write_be_bytes(&mut n);
let mut e = [0u8; 256];
pk.exponent().write_be_bytes(&mut e);
BoxedRsaPublicKey::new(
crate::bignum::BoxedUint::from_be_bytes(&n),
crate::bignum::BoxedUint::from_be_bytes(&e),
)
}
#[test]
fn pkcs1_sha1_verify_via_registry() {
let key = rsa_test_key_a();
let spki = AnyPublicKey::Rsa(boxed_pk_from_rsa_test_key()).to_spki_der();
let sig = key.sign_pkcs1v15::<crate::hash::Sha1>(b"hi").unwrap();
let algo = find_by_id("rsa-pkcs1-sha1").expect("rsa-pkcs1-sha1");
algo.verify(&spki, b"hi", &sig).unwrap();
assert!(algo.verify(&spki, b"other", &sig).is_err());
assert!(algo.tls_schemes().is_empty());
}
#[test]
fn pss_pss_sha256_verify_accepts_rsa_encryption_spki() {
let key = rsa_test_key_a();
let spki = AnyPublicKey::Rsa(boxed_pk_from_rsa_test_key()).to_spki_der();
let mut rng = crate::rng::HmacDrbg::<Sha256>::new(b"reg-pss-pss", b"n", &[]);
let sig = key.sign_pss::<Sha256, _>(b"hi", &mut rng).unwrap();
let algo = find_by_id("rsa-pss-pss-sha256").unwrap();
algo.verify(&spki, b"hi", &sig).unwrap();
}
#[test]
fn pkcs1_sha256_verify_via_registry() {
let key = rsa_test_key_a();
let spki = AnyPublicKey::Rsa(boxed_pk_from_rsa_test_key()).to_spki_der();
let sig = key.sign_pkcs1v15::<Sha256>(b"hi").unwrap();
let algo = find_by_id("rsa-pkcs1-sha256").unwrap();
algo.verify(&spki, b"hi", &sig).unwrap();
assert!(algo.verify(&spki, b"other", &sig).is_err());
assert_eq!(algo.rsa_modulus_bits(&spki), Some(2048));
}
}