mod util;
#[cfg(feature = "pem")]
mod test_key_params_mismatch {
use crate::util;
use rcgen::{Certificate, Error, KeyPair};
use std::collections::hash_map::DefaultHasher;
use std::hash::{Hash, Hasher};
fn generate_hash<T: Hash>(subject: &T) -> u64 {
let mut hasher = DefaultHasher::new();
subject.hash(&mut hasher);
hasher.finish()
}
#[test]
fn test_key_params_mismatch() {
let available_key_params = [
&rcgen::PKCS_RSA_SHA256,
&rcgen::PKCS_ECDSA_P256_SHA256,
&rcgen::PKCS_ECDSA_P384_SHA384,
&rcgen::PKCS_ED25519,
];
for (i, kalg_1) in available_key_params.iter().enumerate() {
for (j, kalg_2) in available_key_params.iter().enumerate() {
if i == j {
assert_eq!(*kalg_1, *kalg_2);
assert_eq!(generate_hash(*kalg_1), generate_hash(*kalg_2));
continue;
}
assert_ne!(*kalg_1, *kalg_2);
assert_ne!(generate_hash(*kalg_1), generate_hash(*kalg_2));
let mut wrong_params = util::default_params();
if i != 0 {
wrong_params.key_pair = Some(KeyPair::generate(kalg_1).unwrap());
} else {
let kp = KeyPair::from_pem(util::RSA_TEST_KEY_PAIR_PEM).unwrap();
wrong_params.key_pair = Some(kp);
}
wrong_params.alg = *kalg_2;
assert_eq!(
Certificate::from_params(wrong_params).err(),
Some(Error::CertificateKeyPairMismatch),
"i: {} j: {}",
i,
j
);
}
}
}
}
#[cfg(feature = "x509-parser")]
mod test_convert_x509_subject_alternative_name {
use rcgen::{
BasicConstraints, Certificate, CertificateParams, IsCa, KeyPair, SanType,
PKCS_ECDSA_P256_SHA256,
};
use std::net::{IpAddr, Ipv4Addr};
#[test]
fn converts_from_ip() {
let ip = Ipv4Addr::new(2, 4, 6, 8);
let ip_san = SanType::IpAddress(IpAddr::V4(ip));
let mut params = super::util::default_params();
params.subject_alt_names.push(ip_san.clone());
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
let cert = Certificate::from_params(params).unwrap();
let ca_der = cert.serialize_der().unwrap();
let key_pair = KeyPair::generate(&PKCS_ECDSA_P256_SHA256).unwrap();
let actual = CertificateParams::from_ca_cert_der(&ca_der, key_pair).unwrap();
assert!(actual.subject_alt_names.contains(&ip_san));
}
}
#[cfg(feature = "x509-parser")]
mod test_x509_custom_ext {
use crate::util;
use rcgen::{Certificate, CustomExtension};
use x509_parser::oid_registry::asn1_rs;
use x509_parser::prelude::{
FromDer, ParsedCriAttribute, X509Certificate, X509CertificationRequest,
};
#[test]
fn custom_ext() {
let test_oid = asn1_rs::Oid::from(&[2, 5, 29, 999999]).unwrap();
let test_ext = yasna::construct_der(|writer| {
writer.write_utf8_string("🦀 greetz to ferris 🦀");
});
let mut custom_ext = CustomExtension::from_oid_content(
test_oid.iter().unwrap().collect::<Vec<u64>>().as_slice(),
test_ext.clone(),
);
custom_ext.set_criticality(true);
let mut params = util::default_params();
params.custom_extensions = vec![custom_ext];
params.subject_alt_names = Vec::default();
let test_cert = Certificate::from_params(params).unwrap();
let test_cert_der = test_cert.serialize_der().unwrap();
let (_, x509_test_cert) = X509Certificate::from_der(&test_cert_der).unwrap();
let favorite_drink_ext = x509_test_cert
.get_extension_unique(&test_oid)
.expect("invalid extensions")
.expect("missing custom extension");
assert!(favorite_drink_ext.critical);
assert_eq!(favorite_drink_ext.value, test_ext);
let test_cert_csr_der = test_cert.serialize_request_der().unwrap();
let (_, x509_csr) = X509CertificationRequest::from_der(&test_cert_csr_der).unwrap();
let exts = x509_csr
.certification_request_info
.iter_attributes()
.find_map(|attr| {
if let ParsedCriAttribute::ExtensionRequest(requested) = &attr.parsed_attribute() {
Some(requested.extensions.iter().collect::<Vec<_>>())
} else {
None
}
})
.expect("missing requested extensions");
let custom_ext = exts
.iter()
.find(|ext| ext.oid == test_oid)
.expect("missing requested custom extension");
assert!(custom_ext.critical);
assert_eq!(custom_ext.value, test_ext);
}
}
#[cfg(feature = "x509-parser")]
mod test_x509_parser_crl {
use crate::util;
use x509_parser::num_bigint::BigUint;
use x509_parser::prelude::{FromDer, X509Certificate};
use x509_parser::revocation_list::CertificateRevocationList;
use x509_parser::x509::X509Version;
#[test]
fn parse_crl() {
let (crl, issuer) = util::test_crl();
let revoked_cert = crl.get_params().revoked_certs.first().unwrap();
let revoked_cert_serial = BigUint::from_bytes_be(revoked_cert.serial_number.as_ref());
let issuer_der = issuer.serialize_der().unwrap();
let (_, x509_issuer) = X509Certificate::from_der(&issuer_der).unwrap();
let crl_der = crl.serialize_der_with_signer(&issuer).unwrap();
let (_, x509_crl) =
CertificateRevocationList::from_der(&crl_der).expect("failed to parse CRL DER");
assert_eq!(x509_crl.version().unwrap(), X509Version(1));
assert_eq!(x509_crl.issuer(), x509_issuer.subject());
assert_eq!(
x509_crl.last_update().to_datetime().unix_timestamp(),
crl.get_params().this_update.unix_timestamp()
);
assert_eq!(
x509_crl
.next_update()
.unwrap()
.to_datetime()
.unix_timestamp(),
crl.get_params().next_update.unix_timestamp()
);
let x509_revoked_cert = x509_crl
.iter_revoked_certificates()
.next()
.expect("failed to find revoked cert in CRL");
assert_eq!(x509_revoked_cert.user_certificate, revoked_cert_serial);
let (_, reason_code) = x509_revoked_cert.reason_code().unwrap();
assert_eq!(reason_code.0, revoked_cert.reason_code.unwrap() as u8);
let issuing_dp_ext = x509_crl
.extensions()
.iter()
.find(|ext| {
ext.oid == x509_parser::oid_registry::OID_X509_EXT_ISSUER_DISTRIBUTION_POINT
})
.expect("failed to find issuing distribution point extension");
assert!(issuing_dp_ext.critical);
assert!(x509_crl.verify_signature(x509_issuer.public_key()).is_ok());
}
}
#[cfg(feature = "x509-parser")]
mod test_parse_crl_dps {
use crate::util;
use x509_parser::extensions::{DistributionPointName, ParsedExtension};
#[test]
fn parse_crl_dps() {
let der = util::cert_with_crl_dps();
let (_, parsed_cert) = x509_parser::parse_x509_certificate(&der).unwrap();
let crl_dps = parsed_cert
.get_extension_unique(&x509_parser::oid_registry::OID_X509_EXT_CRL_DISTRIBUTION_POINTS)
.expect("malformed CRL distribution points extension")
.expect("missing CRL distribution points extension");
assert!(!crl_dps.critical);
let crl_dps = match crl_dps.parsed_extension() {
ParsedExtension::CRLDistributionPoints(crl_dps) => crl_dps,
_ => panic!("unexpected parsed extension type"),
};
assert_eq!(crl_dps.points.len(), 2);
let general_names = crl_dps
.points
.iter()
.flat_map(|dp| {
assert!(dp.crl_issuer.is_none());
assert!(dp.reasons.is_none());
match dp
.distribution_point
.as_ref()
.expect("missing distribution point name")
{
DistributionPointName::FullName(general_names) => general_names.iter(),
DistributionPointName::NameRelativeToCRLIssuer(_) => {
panic!("unexpected name relative to cRL issuer")
},
}
})
.collect::<Vec<_>>();
let uris = general_names
.iter()
.map(|general_name| match general_name {
x509_parser::extensions::GeneralName::URI(uri) => *uri,
_ => panic!("unexpected general name type"),
})
.collect::<Vec<_>>();
assert_eq!(
uris,
&[
"http://example.com/crl.der",
"http://crls.example.com/1234",
"ldap://example.com/crl.der"
]
);
}
}
#[cfg(feature = "x509-parser")]
mod test_parse_ia5string_subject {
use crate::util;
use rcgen::DnType::CustomDnType;
use rcgen::{Certificate, CertificateParams, DistinguishedName, DnValue, KeyPair};
#[test]
fn parse_ia5string_subject() {
let email_address_dn_type = CustomDnType(vec![1, 2, 840, 113549, 1, 9, 1]); let email_address_dn_value = DnValue::Ia5String("foo@bar.com".into());
let mut params = util::default_params();
params.distinguished_name = DistinguishedName::new();
params.distinguished_name.push(
email_address_dn_type.clone(),
email_address_dn_value.clone(),
);
let cert = Certificate::from_params(params).unwrap();
let cert_der = cert.serialize_der().unwrap();
assert!(x509_parser::parse_x509_certificate(&cert_der).is_ok());
let key_pair = KeyPair::generate(&rcgen::PKCS_ECDSA_P256_SHA256).unwrap();
let params_from_cert = CertificateParams::from_ca_cert_der(&cert_der, key_pair).unwrap();
let expected_names = &[(&email_address_dn_type, &email_address_dn_value)];
let names = params_from_cert
.distinguished_name
.iter()
.collect::<Vec<(_, _)>>();
assert_eq!(names, expected_names);
}
}