use alloc::boxed::Box;
use alloc::format;
use alloc::sync::Arc;
use alloc::vec::Vec;
use ic_core::traits::SignatureScheme as _;
use ic_core::Zeroize;
use rustls::crypto::KeyProvider;
use rustls::pki_types::PrivateKeyDer;
use rustls::sign::{Signer, SigningKey};
use rustls::{Error, SignatureAlgorithm, SignatureScheme};
#[derive(Debug)]
pub struct Keys;
impl KeyProvider for Keys {
fn load_private_key(&self, key: PrivateKeyDer<'static>) -> Result<Arc<dyn SigningKey>, Error> {
let parsed = match &key {
PrivateKeyDer::Pkcs8(k) => ic_pkix::PrivateKeyInfo::from_der(k.secret_pkcs8_der()),
PrivateKeyDer::Sec1(k) => {
ic_pkix::private_key::parse_ec_private_key(k.secret_sec1_der(), None)
}
PrivateKeyDer::Pkcs1(k) => {
ic_pkix::private_key::parse_rsa_private_key(k.secret_pkcs1_der())
}
_ => return Err(Error::General("unrecognised private key format".into())),
};
let parsed = parsed.map_err(|e| {
Error::General(format!(
"could not parse the private key: {}",
e.kind().id()
))
})?;
match parsed {
ic_pkix::PrivateKeyInfo::Ec {
algorithm,
private_key,
..
} => {
let curve = Curve::from_algorithm(algorithm).ok_or_else(|| {
Error::General(format!(
"ic-rustls verifies ECDSA on P-256 and P-384; {} is not one of them",
algorithm.id()
))
})?;
if private_key.len() != curve.scalar_len() {
return Err(Error::General(format!(
"a {} scalar is {} bytes, not {}",
algorithm.id(),
curve.scalar_len(),
private_key.len()
)));
}
Ok(Arc::new(EcdsaSigningKey {
curve,
secret: private_key.to_vec(),
}))
}
ic_pkix::PrivateKeyInfo::Rsa {
modulus,
public_exponent,
private_exponent,
prime1,
prime2,
..
} => {
let key = rsa_key_from(modulus, public_exponent, private_exponent, prime1, prime2)?;
Ok(Arc::new(RsaSigningKey { key: Arc::new(key) }))
}
ic_pkix::PrivateKeyInfo::Ed25519(seed) => {
if seed.len() != 32 {
return Err(Error::General(format!(
"an ed25519 seed is 32 bytes, not {}",
seed.len()
)));
}
let key = ic_ec::Ed25519Key::from_seed(seed)
.map_err(|e| Error::General(format!("unusable Ed25519 key: {e}")))?;
Ok(Arc::new(Ed25519SigningKey { key: Arc::new(key) }))
}
other => Err(Error::General(format!(
"ic-rustls signs with ECDSA, Ed25519 and RSA; this key is {}, which crate::verify \
cannot check, so offering to sign with it would advertise something this \
provider cannot complete",
other.algorithm().id()
))),
}
}
fn fips(&self) -> bool {
false
}
}
#[derive(Debug, Clone, Copy, PartialEq)]
enum Curve {
P256,
P384,
}
impl Curve {
fn from_algorithm(algorithm: ic_pkix::KeyAlgorithm) -> Option<Self> {
match algorithm {
ic_pkix::KeyAlgorithm::EcP256 => Some(Self::P256),
ic_pkix::KeyAlgorithm::EcP384 => Some(Self::P384),
_ => None,
}
}
fn scalar_len(self) -> usize {
match self {
Self::P256 => 32,
Self::P384 => 48,
}
}
fn scheme(self) -> SignatureScheme {
match self {
Self::P256 => SignatureScheme::ECDSA_NISTP256_SHA256,
Self::P384 => SignatureScheme::ECDSA_NISTP384_SHA384,
}
}
}
#[derive(Debug)]
struct EcdsaSigningKey {
curve: Curve,
secret: Vec<u8>,
}
impl Drop for EcdsaSigningKey {
fn drop(&mut self) {
self.secret.zeroize();
}
}
impl SigningKey for EcdsaSigningKey {
fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
let scheme = self.curve.scheme();
offered.contains(&scheme).then(|| {
Box::new(EcdsaSigner {
curve: self.curve,
secret: self.secret.clone(),
scheme,
}) as Box<dyn Signer>
})
}
fn algorithm(&self) -> SignatureAlgorithm {
SignatureAlgorithm::ECDSA
}
}
#[derive(Debug)]
struct EcdsaSigner {
curve: Curve,
secret: Vec<u8>,
scheme: SignatureScheme,
}
impl Drop for EcdsaSigner {
fn drop(&mut self) {
self.secret.zeroize();
}
}
impl Signer for EcdsaSigner {
fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
let mut fixed = [0u8; 96];
let fixed = &mut fixed[..self.curve.scalar_len() * 2];
let signed = match self.curve {
Curve::P256 => ic_ec::p256::EcdsaP256Sha256::sign(&self.secret, message, fixed),
Curve::P384 => ic_ec::p384::EcdsaP384Sha384::sign(&self.secret, message, fixed),
};
signed.map_err(|e| Error::General(format!("signing failed: {}", e.kind().id())))?;
let mut der = [0u8; 112];
let n = ic_pkix::ecdsa_signature::to_der(fixed, &mut der).map_err(|e| {
Error::General(format!("could not encode the signature: {}", e.kind().id()))
})?;
fixed.zeroize();
Ok(der[..n].to_vec())
}
fn scheme(&self) -> SignatureScheme {
self.scheme
}
}
struct Ed25519SigningKey {
key: Arc<ic_ec::Ed25519Key>,
}
impl core::fmt::Debug for Ed25519SigningKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("Ed25519SigningKey(..)")
}
}
impl SigningKey for Ed25519SigningKey {
fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
offered.contains(&SignatureScheme::ED25519).then(|| {
Box::new(Ed25519Signer {
key: Arc::clone(&self.key),
}) as Box<dyn Signer>
})
}
fn algorithm(&self) -> SignatureAlgorithm {
SignatureAlgorithm::ED25519
}
}
struct Ed25519Signer {
key: Arc<ic_ec::Ed25519Key>,
}
impl core::fmt::Debug for Ed25519Signer {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("Ed25519Signer(..)")
}
}
impl Signer for Ed25519Signer {
fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
let mut sig = [0u8; 64];
self.key
.sign(message, &mut sig)
.map_err(|e| Error::General(format!("signing failed: {e}")))?;
Ok(sig.to_vec())
}
fn scheme(&self) -> SignatureScheme {
SignatureScheme::ED25519
}
}
fn rsa_key_from(
modulus: &[u8],
public_exponent: u64,
private_exponent: &[u8],
prime1: &[u8],
prime2: &[u8],
) -> Result<ic_rsa::RsaPrivateKey, Error> {
let key = if prime1.is_empty() || prime2.is_empty() {
ic_rsa::RsaPrivateKey::from_components(modulus, public_exponent, private_exponent)
} else {
ic_rsa::RsaPrivateKey::from_primes(prime1, prime2, public_exponent)
}
.map_err(|e| Error::General(format!("unusable RSA key: {e}")))?;
let mut derived = alloc::vec![0u8; key.public_key().size()];
key.public_key()
.modulus_bytes(&mut derived)
.map_err(|e| Error::General(format!("unusable RSA key: {e}")))?;
if derived != modulus {
return Err(Error::General(
"the RSA key's primes do not multiply to the modulus it carries".into(),
));
}
Ok(key)
}
const RSA_SCHEMES: &[SignatureScheme] = &[
SignatureScheme::RSA_PSS_SHA512,
SignatureScheme::RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA256,
SignatureScheme::RSA_PKCS1_SHA512,
SignatureScheme::RSA_PKCS1_SHA384,
SignatureScheme::RSA_PKCS1_SHA256,
];
struct RsaSigningKey {
key: Arc<ic_rsa::RsaPrivateKey>,
}
impl core::fmt::Debug for RsaSigningKey {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("RsaSigningKey(..)")
}
}
impl SigningKey for RsaSigningKey {
fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>> {
let scheme = *RSA_SCHEMES.iter().find(|s| offered.contains(s))?;
Some(Box::new(RsaSigner {
key: Arc::clone(&self.key),
scheme,
}))
}
fn algorithm(&self) -> SignatureAlgorithm {
SignatureAlgorithm::RSA
}
}
struct RsaSigner {
key: Arc<ic_rsa::RsaPrivateKey>,
scheme: SignatureScheme,
}
impl core::fmt::Debug for RsaSigner {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.write_str("RsaSigner(..)")
}
}
impl Signer for RsaSigner {
fn sign(&self, message: &[u8]) -> Result<Vec<u8>, Error> {
let mut sig = alloc::vec![0u8; self.key.public_key().size()];
let signed = match self.scheme {
SignatureScheme::RSA_PKCS1_SHA256 => {
ic_rsa::Pkcs1Sha256::sign(&self.key, message, &mut sig)
}
SignatureScheme::RSA_PKCS1_SHA384 => {
ic_rsa::Pkcs1Sha384::sign(&self.key, message, &mut sig)
}
SignatureScheme::RSA_PKCS1_SHA512 => {
ic_rsa::Pkcs1Sha512::sign(&self.key, message, &mut sig)
}
scheme @ (SignatureScheme::RSA_PSS_SHA256
| SignatureScheme::RSA_PSS_SHA384
| SignatureScheme::RSA_PSS_SHA512) => {
let mut rng = ic_drbg::Rng::from_os()
.map_err(|e| Error::General(format!("no randomness for PSS: {e}")))?;
match scheme {
SignatureScheme::RSA_PSS_SHA256 => {
ic_rsa::PssSha256::sign(&self.key, message, &mut rng, &mut sig)
}
SignatureScheme::RSA_PSS_SHA384 => {
ic_rsa::PssSha384::sign(&self.key, message, &mut rng, &mut sig)
}
_ => ic_rsa::PssSha512::sign(&self.key, message, &mut rng, &mut sig),
}
}
other => {
return Err(Error::General(format!(
"ic-rustls cannot sign with {other:?}"
)))
}
};
signed.map_err(|e| Error::General(format!("signing failed: {e}")))?;
Ok(sig)
}
fn scheme(&self) -> SignatureScheme {
self.scheme
}
}
#[cfg(test)]
mod tests {
use super::*;
use rustls::pki_types::{PrivateKeyDer, PrivatePkcs8KeyDer};
fn p256_pkcs8(scalar: &[u8; 32]) -> PrivateKeyDer<'static> {
let mut point = [0u8; 65];
ic_ec::p256::EcdsaP256Sha256::public_key(scalar, &mut point).unwrap();
let mut der = [0u8; 256];
let n = ic_pkix::PrivateKeyInfo::Ec {
algorithm: ic_pkix::KeyAlgorithm::EcP256,
private_key: scalar,
public_key: Some(&point),
}
.to_der(&mut der)
.unwrap();
PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(der[..n].to_vec()))
}
#[test]
fn a_signature_verifies_through_this_providers_verifier() {
use rustls::pki_types::SignatureVerificationAlgorithm;
let scalar = [7u8; 32];
let key = Keys.load_private_key(p256_pkcs8(&scalar)).unwrap();
assert_eq!(key.algorithm(), SignatureAlgorithm::ECDSA);
let signer = key
.choose_scheme(&[SignatureScheme::ECDSA_NISTP256_SHA256])
.expect("the scheme it names should be choosable");
assert_eq!(signer.scheme(), SignatureScheme::ECDSA_NISTP256_SHA256);
let message = b"the transcript a CertificateVerify covers";
let sig = signer.sign(message).expect("signing should work");
let mut point = [0u8; 65];
ic_ec::p256::EcdsaP256Sha256::public_key(&scalar, &mut point).unwrap();
crate::verify::ECDSA_P256_SHA256
.verify_signature(&point, message, &sig)
.expect("a signature this provider made must verify through its own verifier");
assert!(crate::verify::ECDSA_P256_SHA256
.verify_signature(&point, b"a different transcript", &sig)
.is_err());
}
#[test]
fn a_p384_signature_verifies_through_this_providers_verifier() {
use rustls::pki_types::SignatureVerificationAlgorithm;
let scalar = [0x5au8; 48];
let mut point = [0u8; 97];
ic_ec::p384::EcdsaP384Sha384::public_key(&scalar, &mut point).unwrap();
let mut der = [0u8; 256];
let n = ic_pkix::PrivateKeyInfo::Ec {
algorithm: ic_pkix::KeyAlgorithm::EcP384,
private_key: &scalar,
public_key: Some(&point),
}
.to_der(&mut der)
.unwrap();
let key = Keys
.load_private_key(PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
der[..n].to_vec(),
)))
.unwrap();
let signer = key
.choose_scheme(&[SignatureScheme::ECDSA_NISTP384_SHA384])
.expect("a P-384 key should choose the P-384 scheme");
assert_eq!(signer.scheme(), SignatureScheme::ECDSA_NISTP384_SHA384);
let message = b"the transcript a CertificateVerify covers";
let sig = signer.sign(message).expect("signing should work");
crate::verify::ECDSA_P384_SHA384
.verify_signature(&point, message, &sig)
.expect("a signature this provider made must verify through its own verifier");
assert!(crate::verify::ECDSA_P384_SHA384
.verify_signature(&point, b"a different transcript", &sig)
.is_err());
}
#[test]
fn each_curve_names_the_scheme_its_verifier_implements() {
assert_eq!(Curve::P256.scheme(), SignatureScheme::ECDSA_NISTP256_SHA256);
assert_eq!(Curve::P384.scheme(), SignatureScheme::ECDSA_NISTP384_SHA384);
assert_ne!(Curve::P256.scheme(), Curve::P384.scheme());
for c in [Curve::P256, Curve::P384] {
assert!(
crate::SUPPORTED_SIG_ALGS
.mapping
.iter()
.any(|(scheme, _)| *scheme == c.scheme()),
"{:?} signs under a scheme the provider does not verify",
c
);
}
}
#[test]
fn only_an_offered_scheme_is_chosen() {
let key = Keys.load_private_key(p256_pkcs8(&[9u8; 32])).unwrap();
assert!(key.choose_scheme(&[]).is_none());
assert!(key
.choose_scheme(&[SignatureScheme::ED25519, SignatureScheme::RSA_PSS_SHA256])
.is_none());
assert!(key
.choose_scheme(&[SignatureScheme::ECDSA_NISTP384_SHA384])
.is_none());
assert!(key
.choose_scheme(&[
SignatureScheme::ED25519,
SignatureScheme::ECDSA_NISTP256_SHA256
])
.is_some());
}
#[test]
fn a_key_this_provider_cannot_verify_with_is_refused() {
let mut der = [0u8; 128];
let n = ic_pkix::PrivateKeyInfo::X25519(&[3u8; 32])
.to_der(&mut der)
.unwrap();
let x = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(der[..n].to_vec()));
let err = Keys.load_private_key(x).unwrap_err();
let text = format!("{err}");
assert!(
text.contains("x25519") && text.contains("cannot"),
"the refusal should name the key and say why: {text}"
);
for bad in [
vec![],
vec![0x30],
vec![0xffu8; 64],
vec![0x30, 0x82, 0xff, 0xff],
] {
let key = PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(bad));
assert!(Keys.load_private_key(key).is_err());
}
}
#[test]
fn the_key_provider_claims_no_fips_validation() {
assert!(!Keys.fips());
}
#[test]
fn an_ed25519_signature_verifies_through_this_providers_verifier() {
use rustls::pki_types::SignatureVerificationAlgorithm;
let seed = [0x9du8; 32];
let mut der = [0u8; 128];
let n = ic_pkix::PrivateKeyInfo::Ed25519(&seed)
.to_der(&mut der)
.unwrap();
let key = Keys
.load_private_key(PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(
der[..n].to_vec(),
)))
.unwrap();
assert_eq!(key.algorithm(), SignatureAlgorithm::ED25519);
let signer = key
.choose_scheme(&[SignatureScheme::ED25519])
.expect("an Ed25519 key should choose the Ed25519 scheme");
assert_eq!(signer.scheme(), SignatureScheme::ED25519);
let message = b"the transcript a CertificateVerify covers";
let sig = signer.sign(message).expect("signing should work");
assert_eq!(sig.len(), 64, "an Ed25519 signature is 64 bytes");
let mut public = [0u8; 32];
ic_ec::Ed25519::public_key(&seed, &mut public).unwrap();
crate::verify::ED25519
.verify_signature(&public, message, &sig)
.expect("a signature this provider made must verify through its own verifier");
assert!(crate::verify::ED25519
.verify_signature(&public, b"a different transcript", &sig)
.is_err());
assert_eq!(signer.sign(message).unwrap(), sig);
assert!(key.choose_scheme(&[]).is_none());
assert!(key
.choose_scheme(&[
SignatureScheme::ECDSA_NISTP256_SHA256,
SignatureScheme::RSA_PSS_SHA256
])
.is_none());
let mut short = [0u8; 128];
assert!(
ic_pkix::PrivateKeyInfo::Ed25519(&[1u8; 31])
.to_der(&mut short)
.is_err(),
"the encoder accepted a 31-byte seed"
);
}
fn rsa_key() -> &'static ic_rsa::RsaPrivateKey {
use std::sync::OnceLock;
static KEY: OnceLock<ic_rsa::RsaPrivateKey> = OnceLock::new();
KEY.get_or_init(|| {
let mut rng = ic_drbg::Rng::from_os().expect("os randomness");
ic_rsa::generate(2048, &mut rng).expect("rsa key generation")
})
}
fn rsa_pkcs8(key: &ic_rsa::RsaPrivateKey) -> PrivateKeyDer<'static> {
let half = key.size() / 2;
let (mut modulus, mut d) = (alloc::vec![0u8; key.size()], alloc::vec![0u8; key.size()]);
let (mut p, mut q) = (alloc::vec![0u8; half], alloc::vec![0u8; half]);
let (mut dp, mut dq, mut qinv) = (
alloc::vec![0u8; half],
alloc::vec![0u8; half],
alloc::vec![0u8; half],
);
key.public_key().modulus_bytes(&mut modulus).unwrap();
key.exponent_bytes(&mut d).unwrap();
key.prime_bytes(&mut p, &mut q).unwrap();
key.crt_exponent_bytes(&mut dp, &mut dq, &mut qinv).unwrap();
let mut der = alloc::vec![0u8; 4096];
let n = ic_pkix::PrivateKeyInfo::Rsa {
modulus: &modulus,
public_exponent: key.public_key().exponent(),
private_exponent: &d,
prime1: &p,
prime2: &q,
exponent1: &dp,
exponent2: &dq,
coefficient: &qinv,
}
.to_der(&mut der)
.unwrap();
der.truncate(n);
PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(der))
}
#[test]
fn rsa_signatures_verify_through_this_providers_verifier() {
use rustls::pki_types::SignatureVerificationAlgorithm;
let key = Keys.load_private_key(rsa_pkcs8(rsa_key())).unwrap();
assert_eq!(key.algorithm(), SignatureAlgorithm::RSA);
let mut spki = alloc::vec![0u8; rsa_key().size()];
rsa_key().public_key().modulus_bytes(&mut spki).unwrap();
let mut pk_der = alloc::vec![0u8; 1024];
let n =
ic_pkix::write_rsa_public_key(&spki, rsa_key().public_key().exponent(), &mut pk_der)
.unwrap();
let pk = &pk_der[..n];
let message = b"the transcript a CertificateVerify covers";
let mut checked = 0;
for scheme in RSA_SCHEMES {
let signer = key
.choose_scheme(&[*scheme])
.unwrap_or_else(|| panic!("{scheme:?} is listed but was not choosable"));
assert_eq!(signer.scheme(), *scheme);
let sig = signer.sign(message).expect("signing should work");
let verifier: &dyn SignatureVerificationAlgorithm = match *scheme {
SignatureScheme::RSA_PKCS1_SHA256 => &crate::verify::RSA_PKCS1_SHA256,
SignatureScheme::RSA_PKCS1_SHA384 => &crate::verify::RSA_PKCS1_SHA384,
SignatureScheme::RSA_PKCS1_SHA512 => &crate::verify::RSA_PKCS1_SHA512,
SignatureScheme::RSA_PSS_SHA256 => &crate::verify::RSA_PSS_SHA256,
SignatureScheme::RSA_PSS_SHA384 => &crate::verify::RSA_PSS_SHA384,
SignatureScheme::RSA_PSS_SHA512 => &crate::verify::RSA_PSS_SHA512,
other => panic!("{other:?} is in RSA_SCHEMES but has no verifier"),
};
verifier
.verify_signature(pk, message, &sig)
.unwrap_or_else(|_| {
panic!("{scheme:?}: a signature this provider made did not verify")
});
assert!(
verifier
.verify_signature(pk, b"a different transcript", &sig)
.is_err(),
"{scheme:?}: verified against the wrong message"
);
checked += 1;
}
assert_eq!(checked, 6, "not every RSA scheme was exercised");
}
#[test]
fn a_loaded_rsa_key_takes_the_crt_path() {
let key = rsa_key();
let half = key.size() / 2;
let (mut p, mut q) = (alloc::vec![0u8; half], alloc::vec![0u8; half]);
let (mut d, mut modulus) = (alloc::vec![0u8; key.size()], alloc::vec![0u8; key.size()]);
key.prime_bytes(&mut p, &mut q).unwrap();
key.exponent_bytes(&mut d).unwrap();
key.public_key().modulus_bytes(&mut modulus).unwrap();
let e = key.public_key().exponent();
let loaded = rsa_key_from(&modulus, e, &d, &p, &q).unwrap();
assert!(
loaded.uses_crt(),
"the loader built a key without CRT parameters, so every signature \
it makes costs several times what it should"
);
let without_primes = rsa_key_from(&modulus, e, &d, &[], &[]).unwrap();
assert!(
!without_primes.uses_crt(),
"the n/e/d fallback should not carry CRT parameters"
);
let mut a = alloc::vec![0u8; loaded.size()];
let mut b = alloc::vec![0u8; without_primes.size()];
ic_rsa::Pkcs1Sha256::sign(&loaded, b"message", &mut a).unwrap();
ic_rsa::Pkcs1Sha256::sign(&without_primes, b"message", &mut b).unwrap();
assert_eq!(a, b, "the CRT and non-CRT paths disagreed");
}
#[test]
fn an_rsa_key_whose_primes_contradict_its_modulus_is_refused() {
let key = rsa_key();
let half = key.size() / 2;
let (mut p, mut q) = (alloc::vec![0u8; half], alloc::vec![0u8; half]);
let (mut dp, mut dq, mut qinv) = (
alloc::vec![0u8; half],
alloc::vec![0u8; half],
alloc::vec![0u8; half],
);
let (mut modulus, mut d) = (alloc::vec![0u8; key.size()], alloc::vec![0u8; key.size()]);
key.prime_bytes(&mut p, &mut q).unwrap();
key.crt_exponent_bytes(&mut dp, &mut dq, &mut qinv).unwrap();
key.exponent_bytes(&mut d).unwrap();
key.public_key().modulus_bytes(&mut modulus).unwrap();
let mut other = ic_drbg::Rng::from_os().unwrap();
let other_key = ic_rsa::generate(2048, &mut other).unwrap();
let mut other_modulus = alloc::vec![0u8; other_key.size()];
other_key
.public_key()
.modulus_bytes(&mut other_modulus)
.unwrap();
let mut der = alloc::vec![0u8; 4096];
let n = ic_pkix::PrivateKeyInfo::Rsa {
modulus: &other_modulus,
public_exponent: key.public_key().exponent(),
private_exponent: &d,
prime1: &p,
prime2: &q,
exponent1: &dp,
exponent2: &dq,
coefficient: &qinv,
}
.to_der(&mut der)
.unwrap();
der.truncate(n);
let err = Keys
.load_private_key(PrivateKeyDer::Pkcs8(PrivatePkcs8KeyDer::from(der)))
.expect_err("a key whose primes contradict its modulus was accepted");
let text = format!("{err}");
assert!(
text.contains("modulus"),
"the refusal should say what was wrong: {text}"
);
assert!(Keys.load_private_key(rsa_pkcs8(key)).is_ok());
}
#[test]
fn an_rsa_key_only_chooses_an_offered_rsa_scheme() {
let key = Keys.load_private_key(rsa_pkcs8(rsa_key())).unwrap();
assert!(key.choose_scheme(&[]).is_none());
assert!(key
.choose_scheme(&[
SignatureScheme::ECDSA_NISTP256_SHA256,
SignatureScheme::ED25519
])
.is_none());
let signer = key
.choose_scheme(&[
SignatureScheme::RSA_PKCS1_SHA256,
SignatureScheme::RSA_PSS_SHA256,
])
.expect("one of the two should be chosen");
assert_eq!(
signer.scheme(),
SignatureScheme::RSA_PSS_SHA256,
"PKCS#1 v1.5 was chosen where PSS was also on offer"
);
}
#[test]
fn pss_signatures_are_randomized() {
let key = Keys.load_private_key(rsa_pkcs8(rsa_key())).unwrap();
let signer = key
.choose_scheme(&[SignatureScheme::RSA_PSS_SHA256])
.unwrap();
let a = signer.sign(b"one message").unwrap();
let b = signer.sign(b"one message").unwrap();
assert_ne!(a, b, "two PSS signatures over one message were identical");
let signer = key
.choose_scheme(&[SignatureScheme::RSA_PKCS1_SHA256])
.unwrap();
let a = signer.sign(b"one message").unwrap();
let b = signer.sign(b"one message").unwrap();
assert_eq!(a, b, "PKCS#1 v1.5 should be deterministic");
}
}