// Real keys and real certificates, generated at run time. // // Shared by `signing_roundtrip.rs` and `signing_security.rs`. // // Certificates are **genuinely signed by their issuer**, not stamped with // a placeholder. That matters: chain validation checks issuer signatures, // so a fixture with a fake signature would make every chain test pass // vacuously โ€” it would prove the chain walk found a name match and // nothing about whether it verified anything. use der::asn1::{BitString, SetOfVec, UtcTime}; use der::{Encode, Sequence}; use x509_cert::name::{Name, RdnSequence}; /// A deterministic RNG adaptor: `rsa` wants `rand_core` 0.6 and this crate /// does not otherwise depend on it. pub struct TestRng; impl rsa::rand_core::RngCore for TestRng { fn next_u32(&mut self) -> u32 { let mut b = [0u8; 4]; getrandom::getrandom(&mut b).expect("entropy"); u32::from_le_bytes(b) } fn next_u64(&mut self) -> u64 { let mut b = [0u8; 8]; getrandom::getrandom(&mut b).expect("entropy"); u64::from_le_bytes(b) } fn fill_bytes(&mut self, dest: &mut [u8]) { getrandom::getrandom(dest).expect("entropy"); } fn try_fill_bytes(&mut self, dest: &mut [u8]) -> Result<(), rsa::rand_core::Error> { getrandom::getrandom(dest).map_err(rsa::rand_core::Error::new) } } impl rsa::rand_core::CryptoRng for TestRng {} /// A distinguished name with a single CN. fn name_with_cn(common_name: &str) -> Name { let cn: der::asn1::ObjectIdentifier = "2.5.4.3".parse().expect("static OID"); let value = der::asn1::Utf8StringRef::new(common_name).expect("utf8"); let atv = x509_cert::attr::AttributeTypeAndValue { oid: cn, value: der::Any::from(value), }; let mut set = SetOfVec::new(); set.insert(atv).expect("set"); let rdn = x509_cert::name::RelativeDistinguishedName::from(set); Name::from(RdnSequence::from(vec![rdn])) } fn validity() -> x509_cert::time::Validity { // UTCTime encodes a two-digit year and cannot represent anything past // 2049 (RFC 5280 ยง4.1.2.5.1); 2_400_000_000 is 2046. x509_cert::time::Validity { not_before: x509_cert::time::Time::UtcTime( UtcTime::from_unix_duration(std::time::Duration::from_secs(1_600_000_000)) .expect("time"), ), not_after: x509_cert::time::Time::UtcTime( UtcTime::from_unix_duration(std::time::Duration::from_secs(2_400_000_000)) .expect("time"), ), } } /// Build a certificate for `subject`, signed by `issuer_key` under /// `issuer_name`. /// /// Pass the subject's own key and name to produce a self-signed root. #[allow(clippy::too_many_arguments)] pub fn signed_certificate( subject_cn: &str, subject_key_oid: &str, subject_public_key_bits: &[u8], issuer_cn: &str, issuer_key: &rsa::RsaPrivateKey, serial: u8, ) -> Vec { use sha2::{Digest, Sha256}; const SHA256_WITH_RSA: &str = "1.2.840.113549.1.1.11"; #[derive(Sequence)] struct AlgId { algorithm: der::asn1::ObjectIdentifier, } let _ = AlgId { algorithm: SHA256_WITH_RSA.parse().expect("static OID"), }; let spki = x509_cert::spki::SubjectPublicKeyInfoOwned { algorithm: x509_cert::spki::AlgorithmIdentifierOwned { oid: subject_key_oid.parse().expect("static OID"), parameters: None, }, subject_public_key: BitString::from_bytes(subject_public_key_bits).expect("bit string"), }; let tbs = x509_cert::TbsCertificate { version: x509_cert::Version::V3, serial_number: x509_cert::serial_number::SerialNumber::new(&[serial]).expect("serial"), signature: x509_cert::spki::AlgorithmIdentifierOwned { oid: SHA256_WITH_RSA.parse().expect("static OID"), parameters: None, }, issuer: name_with_cn(issuer_cn), validity: validity(), subject: name_with_cn(subject_cn), subject_public_key_info: spki, issuer_unique_id: None, subject_unique_id: None, extensions: None, }; // Sign the TBS for real: chain validation checks this, and a // placeholder would make every chain test pass without proving // anything. let tbs_der = tbs.to_der().expect("TBS DER"); let digest = Sha256::digest(&tbs_der); let signature = issuer_key .sign(rsa::Pkcs1v15Sign::new::(), &digest) .expect("sign certificate"); x509_cert::Certificate { tbs_certificate: tbs, signature_algorithm: x509_cert::spki::AlgorithmIdentifierOwned { oid: SHA256_WITH_RSA.parse().expect("static OID"), parameters: None, }, signature: BitString::from_bytes(&signature).expect("bit string"), } .to_der() .expect("certificate DER") } /// An RSA key and a self-signed certificate for it. pub fn self_signed_rsa() -> (rsa::RsaPrivateKey, Vec) { self_signed_rsa_named("nigig-test-rsa") } pub fn self_signed_rsa_named(cn: &str) -> (rsa::RsaPrivateKey, Vec) { use rsa::pkcs1::EncodeRsaPublicKey; // 1024 bits: too small for production, fast enough for a suite that // generates keys on every run. The algorithm under test is unchanged. let mut rng = TestRng; let key = rsa::RsaPrivateKey::new(&mut rng, 1024).expect("generate RSA key"); let public = key.to_public_key().to_pkcs1_der().expect("public key DER"); let der = signed_certificate( cn, "1.2.840.113549.1.1.1", public.as_bytes(), cn, &key, 0x01, ); (key, der) } /// A P-256 key and a self-signed certificate. /// /// The certificate's own signature is RSA, because the chain walk needs an /// issuer key and generating a second EC identity to sign it would test /// nothing extra here. pub fn self_signed_p256() -> (p256::ecdsa::SigningKey, Vec) { let mut seed = [0u8; 32]; getrandom::getrandom(&mut seed).expect("entropy"); let key = p256::ecdsa::SigningKey::from_bytes(&seed.into()).expect("P-256 key"); let point = key.verifying_key().to_encoded_point(false); let mut rng = TestRng; let issuer = rsa::RsaPrivateKey::new(&mut rng, 1024).expect("issuer key"); let der = signed_certificate( "nigig-test-p256", "1.2.840.10045.2.1", point.as_bytes(), "nigig-test-p256", &issuer, 0x02, ); (key, der) } /// An Ed25519 key and a self-signed certificate. pub fn self_signed_ed25519() -> (ed25519_dalek::SigningKey, Vec) { let mut seed = [0u8; 32]; getrandom::getrandom(&mut seed).expect("entropy"); let key = ed25519_dalek::SigningKey::from_bytes(&seed); let mut rng = TestRng; let issuer = rsa::RsaPrivateKey::new(&mut rng, 1024).expect("issuer key"); let der = signed_certificate( "nigig-test-ed25519", "1.3.101.112", key.verifying_key().as_bytes(), "nigig-test-ed25519", &issuer, 0x03, ); (key, der) } /// A three-level PKI: root โ†’ intermediate โ†’ leaf, every link really /// signed by the one above it. pub struct Hierarchy { pub root_der: Vec, pub intermediate_der: Vec, pub leaf_key: rsa::RsaPrivateKey, pub leaf_der: Vec, } pub fn rsa_hierarchy() -> Hierarchy { use rsa::pkcs1::EncodeRsaPublicKey; let mut rng = TestRng; let root_key = rsa::RsaPrivateKey::new(&mut rng, 1024).expect("root key"); let root_pub = root_key.to_public_key().to_pkcs1_der().expect("root pub"); let root_der = signed_certificate( "nigig-root", "1.2.840.113549.1.1.1", root_pub.as_bytes(), "nigig-root", &root_key, 0x10, ); let inter_key = rsa::RsaPrivateKey::new(&mut rng, 1024).expect("intermediate key"); let inter_pub = inter_key.to_public_key().to_pkcs1_der().expect("inter pub"); let intermediate_der = signed_certificate( "nigig-intermediate", "1.2.840.113549.1.1.1", inter_pub.as_bytes(), "nigig-root", &root_key, 0x11, ); let leaf_key = rsa::RsaPrivateKey::new(&mut rng, 1024).expect("leaf key"); let leaf_pub = leaf_key.to_public_key().to_pkcs1_der().expect("leaf pub"); let leaf_der = signed_certificate( "nigig-leaf", "1.2.840.113549.1.1.1", leaf_pub.as_bytes(), "nigig-intermediate", &inter_key, 0x12, ); Hierarchy { root_der, intermediate_der, leaf_key, leaf_der, } }