Skip to content

Commit

Permalink
Move tests to end_entity.rs, factor out test utils
Browse files Browse the repository at this point in the history
As suggested by @cpu in this comment thread:
rustls#169 (comment)
  • Loading branch information
hawkw committed Sep 7, 2023
1 parent 5fd1a8c commit 5194bd8
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 88 deletions.
61 changes: 61 additions & 0 deletions src/end_entity.rs
Original file line number Diff line number Diff line change
Expand Up @@ -165,3 +165,64 @@ impl<'a> EndEntityCert<'a> {
subject_name::list_cert_dns_names(self)
}
}

#[cfg(feature = "alloc")]
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils;

// This test reproduces https://github.com/rustls/webpki/issues/167 --- an
// end-entity cert where the common name is a `PrintableString` rather than
// a `UTF8String` cannot iterate over its subject alternative names.
#[test]
fn printable_string_common_name() {
const DNS_NAME: &str = "test.example.com";

let issuer = test_utils::make_issuer("Test", None);

let ee_cert_der = {
let mut params = rcgen::CertificateParams::new(vec![DNS_NAME.to_string()]);
// construct a certificate that uses `PrintableString` as the
// common name value, rather than `UTF8String`.
params.distinguished_name.push(
rcgen::DnType::CommonName,
rcgen::DnValue::PrintableString("example.com".to_string()),
);
params.is_ca = rcgen::IsCa::ExplicitNoCa;
params.alg = test_utils::RCGEN_SIGNATURE_ALG;
let cert = rcgen::Certificate::from_params(params)
.expect("failed to make ee cert (this is a test bug)");
let bytes = cert
.serialize_der_with_signer(&issuer)
.expect("failed to serialize signed ee cert (this is a test bug)");
CertificateDer::from(bytes)
};

expect_dns_name(&ee_cert_der, DNS_NAME);
}

// This test reproduces https://github.com/rustls/webpki/issues/167 --- an
// end-entity cert where the common name is an empty SEQUENCE.
#[test]
fn empty_sequence_common_name() {
let ee_cert_der = {
// handcrafted cert DER produced using `ascii2der`, since `rcgen` is
// unwilling to generate this particular weird cert.
let bytes = include_bytes!("../tests/misc/empty_sequence_common_name.der");
CertificateDer::from(&bytes[..])
};
expect_dns_name(&ee_cert_der, "example.com");
}

fn expect_dns_name(der: &CertificateDer<'_>, name: &str) {
let cert =
EndEntityCert::try_from(der).expect("should parse end entity certificate correctly");

let mut names = cert
.dns_names()
.expect("should get all DNS names correctly for end entity cert");
assert_eq!(names.next().map(<&str>::from), Some(name));
assert_eq!(names.next().map(<&str>::from), None);
}
}
3 changes: 3 additions & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ mod crl;
mod verify_cert;
mod x509;

#[cfg(test)]
pub(crate) mod test_utils;

pub use {
cert::{Cert, EndEntityOrCa},
crl::{BorrowedCertRevocationList, BorrowedRevokedCert, CertRevocationList, RevocationReason},
Expand Down
41 changes: 41 additions & 0 deletions src/test_utils.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
#[cfg(feature = "alloc")]
use crate::types::CertificateDer;

/// Signature algorithm used by certificates generated using `make_issuer` and
/// `make_end_entity`. This is exported as a constant so that tests can use the
/// same algorithm when generating certificates using `rcgen`.
#[cfg(feature = "alloc")]
pub(crate) static RCGEN_SIGNATURE_ALG: &rcgen::SignatureAlgorithm = &rcgen::PKCS_ECDSA_P256_SHA256;

#[cfg(feature = "alloc")]
pub(crate) fn make_issuer(
org_name: impl Into<String>,
name_constraints: Option<rcgen::NameConstraints>,
) -> rcgen::Certificate {
let mut ca_params = rcgen::CertificateParams::new(Vec::new());
ca_params
.distinguished_name
.push(rcgen::DnType::OrganizationName, org_name);
ca_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
ca_params.key_usages = vec![
rcgen::KeyUsagePurpose::KeyCertSign,
rcgen::KeyUsagePurpose::DigitalSignature,
rcgen::KeyUsagePurpose::CrlSign,
];
ca_params.alg = RCGEN_SIGNATURE_ALG;
ca_params.name_constraints = name_constraints;
rcgen::Certificate::from_params(ca_params).unwrap()
}

#[cfg(feature = "alloc")]
pub(crate) fn make_end_entity(issuer: &rcgen::Certificate) -> CertificateDer<'static> {
let mut ee_params = rcgen::CertificateParams::new(vec!["example.com".to_string()]);
ee_params.is_ca = rcgen::IsCa::ExplicitNoCa;
ee_params.alg = &RCGEN_SIGNATURE_ALG;
CertificateDer::from(
rcgen::Certificate::from_params(ee_params)
.unwrap()
.serialize_der_with_signer(issuer)
.unwrap(),
)
}
35 changes: 2 additions & 33 deletions src/verify_cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -738,6 +738,8 @@ where
#[cfg(test)]
mod tests {
use super::*;
#[cfg(feature = "alloc")]
use crate::test_utils::{make_end_entity, make_issuer};
use crate::BorrowedCertRevocationList;

#[test]
Expand Down Expand Up @@ -1060,37 +1062,4 @@ mod tests {
time,
)
}

#[cfg(feature = "alloc")]
fn make_issuer(
org_name: impl Into<String>,
name_constraints: Option<rcgen::NameConstraints>,
) -> rcgen::Certificate {
let mut ca_params = rcgen::CertificateParams::new(Vec::new());
ca_params
.distinguished_name
.push(rcgen::DnType::OrganizationName, org_name);
ca_params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
ca_params.key_usages = vec![
rcgen::KeyUsagePurpose::KeyCertSign,
rcgen::KeyUsagePurpose::DigitalSignature,
rcgen::KeyUsagePurpose::CrlSign,
];
ca_params.alg = &rcgen::PKCS_ECDSA_P256_SHA256;
ca_params.name_constraints = name_constraints;
rcgen::Certificate::from_params(ca_params).unwrap()
}

#[cfg(feature = "alloc")]
fn make_end_entity(issuer: &rcgen::Certificate) -> CertificateDer<'static> {
let mut ee_params = rcgen::CertificateParams::new(vec!["example.com".to_string()]);
ee_params.is_ca = rcgen::IsCa::ExplicitNoCa;
ee_params.alg = &rcgen::PKCS_ECDSA_P256_SHA256;
CertificateDer::from(
rcgen::Certificate::from_params(ee_params)
.unwrap()
.serialize_der_with_signer(issuer)
.unwrap(),
)
}
}
55 changes: 0 additions & 55 deletions tests/integration.rs
Original file line number Diff line number Diff line change
Expand Up @@ -352,61 +352,6 @@ mod subject_alt_names {
assert!(names.collect::<Vec<_>>().is_empty());
}

// This test reproduces https://github.com/rustls/webpki/issues/167 --- an
// end-entity cert where the common name is a `PrintableString` rather than
// a `UTF8String` cannot iterate over its subject alternative names.
#[test]
pub fn printable_string_common_name() {
const DNS_NAME: &str = "test.example.com";

let alg = &rcgen::PKCS_ECDSA_P256_SHA256;

let issuer = mk_issuer(alg);

let ee_cert_der = {
let mut params = rcgen::CertificateParams::new(vec![DNS_NAME.to_string()]);
// construct a certificate that uses `PrintableString` as the
// common name value, rather than `UTF8String`.
params.distinguished_name.push(
rcgen::DnType::CommonName,
rcgen::DnValue::PrintableString("example.com".to_string()),
);
params.is_ca = rcgen::IsCa::ExplicitNoCa;
params.alg = alg;
let cert = rcgen::Certificate::from_params(params)
.expect("failed to make ee cert (this is a test bug)");
cert.serialize_der_with_signer(&issuer)
.expect("failed to serialize signed ee cert (this is a test bug)")
};

expect_cert_dns_names(&ee_cert_der, &[DNS_NAME]);
}

// This test reproduces https://github.com/rustls/webpki/issues/167 --- an
// end-entity cert where the common name is an empty SEQUENCE.
#[test]
pub fn empty_sequence_common_name() {
// handcrafted cert DER produced using `ascii2der`, since `rcgen` is
// unwilling to generate this particular weird cert.
let ee_cert_der = include_bytes!("misc/empty_sequence_common_name.der");
expect_cert_dns_names(ee_cert_der, &["example.com"]);
}

fn mk_issuer(alg: &'static rcgen::SignatureAlgorithm) -> rcgen::Certificate {
let mut params = rcgen::CertificateParams::new(Vec::new());
params
.distinguished_name
.push(rcgen::DnType::OrganizationName, "Test".to_string());
params.is_ca = rcgen::IsCa::Ca(rcgen::BasicConstraints::Unconstrained);
params.key_usages = vec![
rcgen::KeyUsagePurpose::KeyCertSign,
rcgen::KeyUsagePurpose::DigitalSignature,
rcgen::KeyUsagePurpose::CrlSign,
];
params.alg = alg;
rcgen::Certificate::from_params(params)
.expect("failed to make issuer cert (this is a test bug)")
}

fn expect_cert_dns_names(data: &[u8], expected_names: &[&str]) {
use std::collections::HashSet;
Expand Down

0 comments on commit 5194bd8

Please sign in to comment.