diff --git a/src/lib.rs b/src/lib.rs index aa2e1ab2..03524004 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -437,6 +437,15 @@ impl DistinguishedName { removed } /// Inserts or updates an attribute that consists of type and name + /// + /// ``` + /// # use rcgen::{DistinguishedName, DnType, DnValue}; + /// let mut dn = DistinguishedName::new(); + /// dn.push(DnType::OrganizationName, "Crab widgits SE"); + /// dn.push(DnType::CommonName, DnValue::PrintableString("Master Cert".to_string())); + /// assert_eq!(dn.get(&DnType::OrganizationName), Some(&DnValue::Utf8String("Crab widgits SE".to_string()))); + /// assert_eq!(dn.get(&DnType::CommonName), Some(&DnValue::PrintableString("Master Cert".to_string()))); + /// ``` pub fn push(&mut self, ty :DnType, s :impl Into) { if !self.entries.contains_key(&ty) { self.order.push(ty.clone()); diff --git a/tests/botan.rs b/tests/botan.rs index a2f8e1b1..6100bc7e 100644 --- a/tests/botan.rs +++ b/tests/botan.rs @@ -1,6 +1,8 @@ extern crate botan; extern crate rcgen; +#[cfg(feature = "x509-parser")] +use rcgen::DnValue; use rcgen::{BasicConstraints, Certificate, CertificateParams, DnType, IsCa}; mod util; @@ -174,3 +176,30 @@ fn test_botan_imported_ca() { check_cert_ca(&cert_der, &cert, &ca_cert_der); } + +#[cfg(feature = "x509-parser")] +#[test] +fn test_botan_imported_ca_with_printable_string() { + use std::convert::TryInto; + let mut params = default_params(); + params.distinguished_name.push(DnType::CountryName, DnValue::PrintableString("US".to_string())); + params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); + let ca_cert = Certificate::from_params(params).unwrap(); + + let (ca_cert_der, ca_key_der) = (ca_cert.serialize_der().unwrap(), ca_cert.serialize_private_key_der()); + + let ca_key_pair = ca_key_der.as_slice().try_into().unwrap(); + let imported_ca_cert_params = CertificateParams::from_ca_cert_der(ca_cert_der.as_slice(), ca_key_pair) + .unwrap(); + let imported_ca_cert = Certificate::from_params(imported_ca_cert_params).unwrap(); + + let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]); + params.distinguished_name.push(DnType::OrganizationName, "Crab widgits SE"); + params.distinguished_name.push(DnType::CommonName, "Dev domain"); + // Botan has a sanity check that enforces a maximum expiration date + params.not_after = rcgen::date_time_ymd(3016, 01, 01); + let cert = Certificate::from_params(params).unwrap(); + let cert_der = cert.serialize_der_with_signer(&imported_ca_cert).unwrap(); + + check_cert_ca(&cert_der, &cert, &ca_cert_der); +} diff --git a/tests/openssl.rs b/tests/openssl.rs index 9c98ee37..d802a9c5 100644 --- a/tests/openssl.rs +++ b/tests/openssl.rs @@ -2,7 +2,7 @@ extern crate openssl; extern crate rcgen; use rcgen::{Certificate, NameConstraints, GeneralSubtree, IsCa, - BasicConstraints, CertificateParams, DnType}; + BasicConstraints, CertificateParams, DnType, DnValue}; use openssl::pkey::PKey; use openssl::x509::{X509, X509Req, X509StoreContext}; use openssl::x509::store::{X509StoreBuilder, X509Store}; @@ -325,6 +325,24 @@ fn test_openssl_separate_ca() { verify_cert_ca(&cert_pem, &key, &ca_cert_pem); } +#[test] +fn test_openssl_separate_ca_with_printable_string() { + let mut params = util::default_params(); + params.distinguished_name.push(DnType::CountryName, DnValue::PrintableString("US".to_string())); + params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); + let ca_cert = Certificate::from_params(params).unwrap(); + let ca_cert_pem = ca_cert.serialize_pem().unwrap(); + + let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]); + params.distinguished_name.push(DnType::OrganizationName, "Crab widgits SE"); + params.distinguished_name.push(DnType::CommonName, "Dev domain"); + let cert = Certificate::from_params(params).unwrap(); + let cert_pem = cert.serialize_pem_with_signer(&ca_cert).unwrap(); + let key = cert.serialize_private_key_der(); + + verify_cert_ca(&cert_pem, &key, &ca_cert_pem); +} + #[test] fn test_openssl_separate_ca_with_other_signing_alg() { let mut params = util::default_params(); diff --git a/tests/webpki.rs b/tests/webpki.rs index 8737c4f0..37f2b62d 100644 --- a/tests/webpki.rs +++ b/tests/webpki.rs @@ -4,7 +4,7 @@ extern crate ring; extern crate pem; #[cfg(feature = "x509-parser")] -use rcgen::CertificateSigningRequest; +use rcgen::{CertificateSigningRequest, DnValue}; use rcgen::{BasicConstraints, Certificate, CertificateParams, DnType, IsCa, KeyPair, RemoteKeyPair}; use webpki::{EndEntityCert, TlsServerTrustAnchors, TrustAnchor}; use webpki::SignatureAlgorithm; @@ -362,6 +362,34 @@ fn test_webpki_imported_ca() { &webpki::ECDSA_P256_SHA256, &webpki::ECDSA_P256_SHA256, sign_fn); } +#[cfg(feature = "x509-parser")] +#[test] +fn test_webpki_imported_ca_with_printable_string() { + use std::convert::TryInto; + let mut params = util::default_params(); + params.distinguished_name.push(DnType::CountryName, DnValue::PrintableString("US".to_string())); + params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); + let ca_cert = Certificate::from_params(params).unwrap(); + + let (ca_cert_der, ca_key_der) = (ca_cert.serialize_der().unwrap(), ca_cert.serialize_private_key_der()); + + let ca_key_pair = ca_key_der.as_slice().try_into().unwrap(); + let imported_ca_cert_params = CertificateParams::from_ca_cert_der(ca_cert_der.as_slice(), ca_key_pair) + .unwrap(); + let imported_ca_cert = Certificate::from_params(imported_ca_cert_params).unwrap(); + + let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]); + params.distinguished_name.push(DnType::OrganizationName, "Crab widgits SE"); + params.distinguished_name.push(DnType::CommonName, "Dev domain"); + let cert = Certificate::from_params(params).unwrap(); + let cert_der = cert.serialize_der_with_signer(&imported_ca_cert).unwrap(); + + let sign_fn = |cert, msg| sign_msg_ecdsa(cert, msg, + &signature::ECDSA_P256_SHA256_ASN1_SIGNING); + check_cert_ca(&cert_der, &cert, &ca_cert_der, + &webpki::ECDSA_P256_SHA256, &webpki::ECDSA_P256_SHA256, sign_fn); +} + #[cfg(feature = "x509-parser")] #[test] fn test_certificate_from_csr() {