diff --git a/rcgen/examples/rsa-irc-openssl.rs b/rcgen/examples/rsa-irc-openssl.rs index 38a22de3..a2f143b0 100644 --- a/rcgen/examples/rsa-irc-openssl.rs +++ b/rcgen/examples/rsa-irc-openssl.rs @@ -1,5 +1,3 @@ -use rcgen::CertifiedKey; - fn main() -> Result<(), Box> { use rcgen::{date_time_ymd, Certificate, CertificateParams, DistinguishedName}; use std::fmt::Write; @@ -10,14 +8,11 @@ fn main() -> Result<(), Box> { params.not_after = date_time_ymd(4096, 1, 1); params.distinguished_name = DistinguishedName::new(); - params.alg = &rcgen::PKCS_RSA_SHA256; - let pkey: openssl::pkey::PKey<_> = openssl::rsa::Rsa::generate(2048)?.try_into()?; let key_pair_pem = String::from_utf8(pkey.private_key_to_pem_pkcs8()?)?; let key_pair = rcgen::KeyPair::from_pem(&key_pair_pem)?; - params.key_pair = Some(key_pair); - let CertifiedKey { cert, key_pair } = Certificate::generate_self_signed(params)?; + let cert = Certificate::generate_self_signed(params, &key_pair)?; let pem_serialized = cert.pem(); let pem = pem::parse(&pem_serialized)?; let der_serialized = pem.contents(); diff --git a/rcgen/examples/rsa-irc.rs b/rcgen/examples/rsa-irc.rs index 8c30d821..3c38962b 100644 --- a/rcgen/examples/rsa-irc.rs +++ b/rcgen/examples/rsa-irc.rs @@ -1,5 +1,3 @@ -use rcgen::CertifiedKey; - fn main() -> Result<(), Box> { use rand::rngs::OsRng; use rsa::pkcs8::EncodePrivateKey; @@ -14,16 +12,13 @@ fn main() -> Result<(), Box> { params.not_after = date_time_ymd(4096, 1, 1); params.distinguished_name = DistinguishedName::new(); - params.alg = &rcgen::PKCS_RSA_SHA256; - let mut rng = OsRng; let bits = 2048; let private_key = RsaPrivateKey::new(&mut rng, bits)?; let private_key_der = private_key.to_pkcs8_der()?; let key_pair = rcgen::KeyPair::try_from(private_key_der.as_bytes()).unwrap(); - params.key_pair = Some(key_pair); - let CertifiedKey { cert, key_pair } = Certificate::generate_self_signed(params)?; + let cert = Certificate::generate_self_signed(params, &key_pair)?; let pem_serialized = cert.pem(); let pem = pem::parse(&pem_serialized)?; let der_serialized = pem.contents(); diff --git a/rcgen/examples/sign-leaf-with-ca.rs b/rcgen/examples/sign-leaf-with-ca.rs index d1f4b250..55403caa 100644 --- a/rcgen/examples/sign-leaf-with-ca.rs +++ b/rcgen/examples/sign-leaf-with-ca.rs @@ -1,22 +1,22 @@ use rcgen::{ - BasicConstraints, Certificate, CertificateParams, CertifiedKey, DnType, - DnValue::PrintableString, ExtendedKeyUsagePurpose, IsCa, KeyUsagePurpose, + BasicConstraints, Certificate, CertificateParams, DnType, DnValue::PrintableString, + ExtendedKeyUsagePurpose, IsCa, KeyPair, KeyUsagePurpose, }; use time::{Duration, OffsetDateTime}; /// Example demonstrating signing end-endity certificate with ca fn main() { - let ca = new_ca().cert; + let ca = new_ca(); let end_entity = new_end_entity(); let end_entity_pem = end_entity.pem(); println!("directly signed end-entity certificate: {end_entity_pem}"); let ca_cert_pem = ca.pem(); - println!("ca certificate: {ca_cert_pem}",); + println!("ca certificate: {ca_cert_pem}"); } -fn new_ca() -> CertifiedKey { +fn new_ca() -> Certificate { let mut params = CertificateParams::new(Vec::default()); let (yesterday, tomorrow) = validity_period(); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); @@ -32,7 +32,9 @@ fn new_ca() -> CertifiedKey { params.not_before = yesterday; params.not_after = tomorrow; - Certificate::generate_self_signed(params).unwrap() + + let key_pair = KeyPair::generate().unwrap(); + Certificate::generate_self_signed(params, &key_pair).unwrap() } fn new_end_entity() -> Certificate { @@ -47,7 +49,9 @@ fn new_end_entity() -> Certificate { .push(ExtendedKeyUsagePurpose::ServerAuth); params.not_before = yesterday; params.not_after = tomorrow; - Certificate::generate_self_signed(params).unwrap().cert + + let key_pair = KeyPair::generate().unwrap(); + Certificate::generate_self_signed(params, &key_pair).unwrap() } fn validity_period() -> (OffsetDateTime, OffsetDateTime) { diff --git a/rcgen/examples/simple.rs b/rcgen/examples/simple.rs index 58824f29..436181f4 100644 --- a/rcgen/examples/simple.rs +++ b/rcgen/examples/simple.rs @@ -1,5 +1,5 @@ use rcgen::{ - date_time_ymd, Certificate, CertificateParams, CertifiedKey, DistinguishedName, DnType, SanType, + date_time_ymd, Certificate, CertificateParams, DistinguishedName, DnType, KeyPair, SanType, }; use std::fs; @@ -19,7 +19,8 @@ fn main() -> Result<(), Box> { SanType::DnsName("localhost".to_string()), ]; - let CertifiedKey { cert, key_pair } = Certificate::generate_self_signed(params)?; + let key_pair = KeyPair::generate()?; + let cert = Certificate::generate_self_signed(params, &key_pair)?; let pem_serialized = cert.pem(); let pem = pem::parse(&pem_serialized)?; diff --git a/rcgen/src/crl.rs b/rcgen/src/crl.rs index 74d62d7e..78a539e1 100644 --- a/rcgen/src/crl.rs +++ b/rcgen/src/crl.rs @@ -11,7 +11,7 @@ use crate::{ write_distinguished_name, write_dt_utc_or_generalized, write_x509_authority_key_identifier, write_x509_extension, DistinguishedName, KeyPair, }; -use crate::{Certificate, Error, KeyIdMethod, KeyUsagePurpose, SerialNumber, SignatureAlgorithm}; +use crate::{Certificate, Error, KeyIdMethod, KeyUsagePurpose, SerialNumber}; /// A certificate revocation list (CRL) /// @@ -26,7 +26,8 @@ use crate::{Certificate, Error, KeyIdMethod, KeyUsagePurpose, SerialNumber, Sign /// let mut issuer_params = CertificateParams::new(vec!["crl.issuer.example.com".to_string()]); /// issuer_params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); /// issuer_params.key_usages = vec![KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::DigitalSignature, KeyUsagePurpose::CrlSign]; -/// let issuer = Certificate::generate_self_signed(issuer_params).unwrap(); +/// let key_pair = KeyPair::generate().unwrap(); +/// let issuer = Certificate::generate_self_signed(issuer_params, &key_pair).unwrap(); /// // Describe a revoked certificate. /// let revoked_cert = RevokedCertParams{ /// serial_number: SerialNumber::from(9999), @@ -41,7 +42,6 @@ use crate::{Certificate, Error, KeyIdMethod, KeyUsagePurpose, SerialNumber, Sign /// crl_number: SerialNumber::from(1234), /// issuing_distribution_point: None, /// revoked_certs: vec![revoked_cert], -/// alg: &PKCS_ECDSA_P256_SHA256, /// key_identifier_method: KeyIdMethod::Sha256, /// }; /// let crl = CertificateRevocationList::from_params(crl).unwrap(); @@ -74,11 +74,8 @@ impl CertificateRevocationList { { return Err(Error::IssuerNotCrlSigner); } - self.params.serialize_der_with_signer( - self.params.alg, - ca_key, - &ca.params.distinguished_name, - ) + self.params + .serialize_der_with_signer(ca_key, &ca.params.distinguished_name) } /// Serializes the certificate revocation list (CRL) in ASCII PEM format, signed with /// the issuing certificate authority's key. @@ -175,8 +172,6 @@ pub struct CertificateRevocationListParams { pub issuing_distribution_point: Option, /// A list of zero or more parameters describing revoked certificates included in the CRL. pub revoked_certs: Vec, - /// Signature algorithm to use when signing the serialized CRL. - pub alg: &'static SignatureAlgorithm, /// Method to generate key identifiers from public keys /// /// Defaults to SHA-256. @@ -186,7 +181,6 @@ pub struct CertificateRevocationListParams { impl CertificateRevocationListParams { fn serialize_der_with_signer( &self, - sig_alg: &SignatureAlgorithm, issuer: &KeyPair, issuer_name: &DistinguishedName, ) -> Result, Error> { @@ -194,7 +188,7 @@ impl CertificateRevocationListParams { // https://www.rfc-editor.org/rfc/rfc5280#section-5.1 writer.write_sequence(|writer| { let tbs_cert_list_serialized = yasna::try_construct_der(|writer| { - self.write_crl(writer, sig_alg, issuer, issuer_name)?; + self.write_crl(writer, issuer, issuer_name)?; Ok::<(), Error>(()) })?; @@ -202,7 +196,7 @@ impl CertificateRevocationListParams { writer.next().write_der(&tbs_cert_list_serialized); // Write signatureAlgorithm - sig_alg.write_alg_ident(writer.next()); + issuer.alg.write_alg_ident(writer.next()); // Write signature issuer.sign(&tbs_cert_list_serialized, writer.next())?; @@ -214,7 +208,6 @@ impl CertificateRevocationListParams { fn write_crl( &self, writer: DERWriter, - sig_alg: &SignatureAlgorithm, issuer: &KeyPair, issuer_name: &DistinguishedName, ) -> Result<(), Error> { @@ -234,7 +227,7 @@ impl CertificateRevocationListParams { // RFC 5280 §5.1.2.2: // This field MUST contain the same algorithm identifier as the // signatureAlgorithm field in the sequence CertificateList - sig_alg.write_alg_ident(writer.next()); + issuer.alg.write_alg_ident(writer.next()); // Write issuer. // RFC 5280 §5.1.2.3: diff --git a/rcgen/src/csr.rs b/rcgen/src/csr.rs index 1871f92e..3b4ae040 100644 --- a/rcgen/src/csr.rs +++ b/rcgen/src/csr.rs @@ -60,7 +60,6 @@ impl CertificateSigningRequestParams { let info = &csr.certification_request_info; let mut params = CertificateParams::default(); - params.alg = alg; params.distinguished_name = DistinguishedName::from_name(&info.subject)?; let raw = info.subject_pki.subject_public_key.data.to_vec(); diff --git a/rcgen/src/error.rs b/rcgen/src/error.rs index acffe1be..3d1d3b04 100644 --- a/rcgen/src/error.rs +++ b/rcgen/src/error.rs @@ -27,9 +27,6 @@ pub enum Error { RingUnspecified, /// The `ring` library rejected the key upon loading RingKeyRejected(String), - /// The provided certificate's signature algorithm - /// is incompatible with the given key pair - CertificateKeyPairMismatch, /// Time conversion related errors Time, #[cfg(feature = "pem")] @@ -75,11 +72,6 @@ impl fmt::Display for Error { UnsupportedExtension => write!(f, "Unsupported extension requested in CSR")?, RingUnspecified => write!(f, "Unspecified ring error")?, RingKeyRejected(e) => write!(f, "Key rejected by ring: {}", e)?, - CertificateKeyPairMismatch => write!( - f, - "The provided certificate's signature \ - algorithm is incompatible with the given key pair" - )?, Time => write!(f, "Time error")?, RemoteKeyError => write!(f, "Remote key error")?, diff --git a/rcgen/src/key_pair.rs b/rcgen/src/key_pair.rs index 1c61b08c..fef14edd 100644 --- a/rcgen/src/key_pair.rs +++ b/rcgen/src/key_pair.rs @@ -56,6 +56,49 @@ pub struct KeyPair { } impl KeyPair { + /// Generate a new random [`PKCS_ECDSA_P256_SHA256`] key pair + pub fn generate() -> Result { + Self::generate_for(&PKCS_ECDSA_P256_SHA256) + } + + /// Generate a new random key pair for the specified signature algorithm + /// + /// If you're not sure which algorithm to use, [`PKCS_ECDSA_P256_SHA256`] is a good choice. + pub fn generate_for(alg: &'static SignatureAlgorithm) -> Result { + let rng = &SystemRandom::new(); + + match alg.sign_alg { + SignAlgo::EcDsa(sign_alg) => { + let key_pair_doc = EcdsaKeyPair::generate_pkcs8(sign_alg, rng)._err()?; + let key_pair_serialized = key_pair_doc.as_ref().to_vec(); + + let key_pair = ecdsa_from_pkcs8(&sign_alg, &&key_pair_doc.as_ref(), rng).unwrap(); + Ok(KeyPair { + kind: KeyPairKind::Ec(key_pair), + alg, + serialized_der: key_pair_serialized, + }) + }, + SignAlgo::EdDsa(_sign_alg) => { + let key_pair_doc = Ed25519KeyPair::generate_pkcs8(rng)._err()?; + let key_pair_serialized = key_pair_doc.as_ref().to_vec(); + + let key_pair = Ed25519KeyPair::from_pkcs8(&&key_pair_doc.as_ref()).unwrap(); + Ok(KeyPair { + kind: KeyPairKind::Ed(key_pair), + alg, + serialized_der: key_pair_serialized, + }) + }, + // Ring doesn't have RSA key generation yet: + // https://github.com/briansmith/ring/issues/219 + // https://github.com/briansmith/ring/pull/733 + // Nor does aws-lc-rs: + // https://github.com/aws/aws-lc-rs/issues/296 + SignAlgo::Rsa() => Err(Error::KeyGenerationUnavailable), + } + } + /// Parses the key pair from the DER format /// /// Equivalent to using the [`TryFrom`] implementation. @@ -177,60 +220,6 @@ impl KeyPair { Ok((kind, alg)) } - /// Generate a new random key pair for the specified signature algorithm - pub fn generate(alg: &'static SignatureAlgorithm) -> Result { - let rng = &SystemRandom::new(); - - match alg.sign_alg { - SignAlgo::EcDsa(sign_alg) => { - let key_pair_doc = EcdsaKeyPair::generate_pkcs8(sign_alg, rng)._err()?; - let key_pair_serialized = key_pair_doc.as_ref().to_vec(); - - let key_pair = ecdsa_from_pkcs8(&sign_alg, &&key_pair_doc.as_ref(), rng).unwrap(); - Ok(KeyPair { - kind: KeyPairKind::Ec(key_pair), - alg, - serialized_der: key_pair_serialized, - }) - }, - SignAlgo::EdDsa(_sign_alg) => { - let key_pair_doc = Ed25519KeyPair::generate_pkcs8(rng)._err()?; - let key_pair_serialized = key_pair_doc.as_ref().to_vec(); - - let key_pair = Ed25519KeyPair::from_pkcs8(&&key_pair_doc.as_ref()).unwrap(); - Ok(KeyPair { - kind: KeyPairKind::Ed(key_pair), - alg, - serialized_der: key_pair_serialized, - }) - }, - // Ring doesn't have RSA key generation yet: - // https://github.com/briansmith/ring/issues/219 - // https://github.com/briansmith/ring/pull/733 - SignAlgo::Rsa() => Err(Error::KeyGenerationUnavailable), - } - } - - /// Validate a provided key pair's compatibility with `sig_alg` or generate a new one. - /// - /// If a provided `existing_key_pair` is not compatible with the `sig_alg` an error is - /// returned. - /// - /// If `None` is provided for `existing_key_pair` a new key pair compatible with `sig_alg` - /// is generated from scratch. - pub(crate) fn validate_or_generate( - existing_key_pair: &mut Option, - sig_alg: &'static SignatureAlgorithm, - ) -> Result { - match existing_key_pair.take() { - Some(kp) if !kp.is_compatible(sig_alg) => { - return Err(Error::CertificateKeyPairMismatch) - }, - Some(kp) => Ok(kp), - None => KeyPair::generate(sig_alg), - } - } - /// Get the raw public key of this key pair /// /// The key is in raw format, as how [`ring::signature::KeyPair::public_key`] diff --git a/rcgen/src/lib.rs b/rcgen/src/lib.rs index 5afdb9fd..e4c1fff7 100644 --- a/rcgen/src/lib.rs +++ b/rcgen/src/lib.rs @@ -21,7 +21,7 @@ use rcgen::{generate_simple_self_signed, CertifiedKey}; let subject_alt_names = vec!["hello.world.example".to_string(), "localhost".to_string()]; -let CertifiedKey{cert, key_pair} = generate_simple_self_signed(subject_alt_names).unwrap(); +let CertifiedKey { cert, key_pair } = generate_simple_self_signed(subject_alt_names).unwrap(); println!("{}", cert.pem()); println!("{}", key_pair.serialize_pem()); # } @@ -98,13 +98,14 @@ and key pair as output. ## Example ``` -extern crate rcgen; use rcgen::{generate_simple_self_signed, CertifiedKey}; # fn main () { -let subject_alt_names :&[_] = &["hello.world.example".to_string(), +// Generate a certificate that's valid for "localhost" and "hello.world.example" +let subject_alt_names = vec!["hello.world.example".to_string(), "localhost".to_string()]; -let CertifiedKey{cert, key_pair} = generate_simple_self_signed(subject_alt_names).unwrap(); +let CertifiedKey { cert, key_pair } = generate_simple_self_signed(subject_alt_names).unwrap(); + // The certificate is now valid for localhost and the domain "hello.world.example" println!("{}", cert.pem()); println!("{}", key_pair.serialize_pem()); @@ -115,7 +116,10 @@ println!("{}", key_pair.serialize_pem()); pub fn generate_simple_self_signed( subject_alt_names: impl Into>, ) -> Result { - Certificate::generate_self_signed(CertificateParams::new(subject_alt_names)) + let key_pair = KeyPair::generate()?; + let cert = + Certificate::generate_self_signed(CertificateParams::new(subject_alt_names), &key_pair)?; + Ok(CertifiedKey { cert, key_pair }) } // https://tools.ietf.org/html/rfc5280#section-4.1.1 @@ -523,7 +527,6 @@ impl<'a> Iterator for DistinguishedNameIterator<'a> { #[allow(missing_docs)] #[non_exhaustive] pub struct CertificateParams { - pub alg: &'static SignatureAlgorithm, pub not_before: OffsetDateTime, pub not_after: OffsetDateTime, pub serial_number: Option, @@ -540,8 +543,6 @@ pub struct CertificateParams { /// [^1]: pub crl_distribution_points: Vec, pub custom_extensions: Vec, - /// The certificate's key pair, a new random key pair will be generated if this is `None` - pub key_pair: Option, /// If `true`, the 'Authority Key Identifier' extension will be added to the generated cert pub use_authority_key_identifier_extension: bool, /// Method to generate key identifiers from public keys @@ -558,7 +559,6 @@ impl Default for CertificateParams { let mut distinguished_name = DistinguishedName::new(); distinguished_name.push(DnType::CommonName, "rcgen self signed cert"); CertificateParams { - alg: &PKCS_ECDSA_P256_SHA256, not_before, not_after, serial_number: None, @@ -570,7 +570,6 @@ impl Default for CertificateParams { name_constraints: None, crl_distribution_points: Vec::new(), custom_extensions: Vec::new(), - key_pair: None, use_authority_key_identifier_extension: false, key_identifier_method: KeyIdMethod::Sha256, } @@ -598,19 +597,18 @@ impl CertificateParams { /// /// See [`from_ca_cert_der`](Self::from_ca_cert_der) for more details. #[cfg(all(feature = "pem", feature = "x509-parser"))] - pub fn from_ca_cert_pem(pem_str: &str, key_pair: KeyPair) -> Result { + pub fn from_ca_cert_pem(pem_str: &str) -> Result { let certificate = pem::parse(pem_str).or(Err(Error::CouldNotParseCertificate))?; - Self::from_ca_cert_der(certificate.contents(), key_pair) + Self::from_ca_cert_der(certificate.contents()) } /// Parses an existing ca certificate from the DER format. /// /// This function is only of use if you have an existing CA certificate /// you would like to use to sign a certificate generated by `rcgen`. - /// By providing the returned [`Certificate`] and the passed-through - /// [`KeyPair`] to [`Certificate::generate`] or - /// [`Certificate::from_request`] functions you can generate a new certificate - /// from [`CertificateParams`], signed by the pre-existing CA. + /// By providing the constructed [`CertificateParams`] and the [`KeyPair`] + /// associated with your existing `ca_cert` you can use [`Certificate::generate()`] + /// or [`Certificate::from_request()`] to issue new certificates using the CA cert. /// /// In general this function only extracts the information needed for signing. /// Other attributes of the [`Certificate`] may be left as defaults. @@ -619,17 +617,10 @@ impl CertificateParams { /// for the presence of the `BasicConstraints` extension, or perform any other /// validation. #[cfg(feature = "x509-parser")] - pub fn from_ca_cert_der(ca_cert: &[u8], key_pair: KeyPair) -> Result { + pub fn from_ca_cert_der(ca_cert: &[u8]) -> Result { let (_remainder, x509) = x509_parser::parse_x509_certificate(ca_cert) .or(Err(Error::CouldNotParseCertificate))?; - let alg_oid = x509 - .signature_algorithm - .algorithm - .iter() - .ok_or(Error::CouldNotParseCertificate)?; - let alg = SignatureAlgorithm::from_oid(&alg_oid.collect::>())?; - let dn = DistinguishedName::from_name(&x509.tbs_certificate.subject)?; let is_ca = Self::convert_x509_is_ca(&x509)?; let validity = x509.validity(); @@ -650,7 +641,6 @@ impl CertificateParams { .unwrap_or(KeyIdMethod::Sha256); Ok(CertificateParams { - alg, is_ca, subject_alt_names, key_usages, @@ -659,7 +649,6 @@ impl CertificateParams { serial_number, key_identifier_method, distinguished_name: dn, - key_pair: Some(key_pair), not_before: validity.not_before.to_datetime(), not_after: validity.not_after.to_datetime(), ..Default::default() @@ -878,7 +867,6 @@ impl CertificateParams { // No .. pattern, we use this to ensure every field is used #[deny(unused)] let Self { - alg, not_before, not_after, serial_number, @@ -890,7 +878,6 @@ impl CertificateParams { name_constraints, crl_distribution_points, custom_extensions, - key_pair, use_authority_key_identifier_extension, key_identifier_method, } = self; @@ -900,7 +887,7 @@ impl CertificateParams { // in the CSR, but in the current API it can't be distinguished // from the defaults so this is left for a later version if // needed. - let _ = (alg, key_pair, not_before, not_after, key_identifier_method); + let _ = (not_before, not_after, key_identifier_method); if serial_number.is_some() || *is_ca != IsCa::NoCa || !key_usages.is_empty() @@ -951,7 +938,6 @@ impl CertificateParams { &self, writer: DERWriter, pub_key: &K, - sig_alg: &SignatureAlgorithm, issuer: &KeyPair, issuer_name: &DistinguishedName, ) -> Result<(), Error> { @@ -972,7 +958,7 @@ impl CertificateParams { writer.next().write_bigint_bytes(&sl, true); }; // Write signature algorithm - sig_alg.write_alg_ident(writer.next()); + issuer.alg.write_alg_ident(writer.next()); // Write issuer name write_distinguished_name(writer.next(), issuer_name); // Write validity @@ -1176,21 +1162,20 @@ impl CertificateParams { fn serialize_der_with_signer( &self, pub_key: &K, - sig_alg: &SignatureAlgorithm, issuer: &KeyPair, issuer_name: &DistinguishedName, ) -> Result, Error> { yasna::try_construct_der(|writer| { writer.write_sequence(|writer| { let tbs_cert_list_serialized = yasna::try_construct_der(|writer| { - self.write_cert(writer, pub_key, sig_alg, issuer, issuer_name)?; + self.write_cert(writer, pub_key, issuer, issuer_name)?; Ok::<(), Error>(()) })?; // Write tbsCertList writer.next().write_der(&tbs_cert_list_serialized); // Write signatureAlgorithm - sig_alg.write_alg_ident(writer.next()); + issuer.alg.write_alg_ident(writer.next()); // Write signature issuer.sign(&tbs_cert_list_serialized, writer.next())?; @@ -1516,35 +1501,23 @@ fn write_general_subtrees(writer: DERWriter, tag: u64, general_subtrees: &[Gener impl Certificate { /// Generates a new self-signed certificate from the given parameters. /// - /// If [`CertificateParams::key_pair`] is not set to a pre-generated key, a new key pair - /// is generated using reasonable defaults. - /// /// The returned [`Certificate`] may be serialized using [`Certificate::der`] and - /// [`Certificate::pem`]. Similarly the private key of the returned [`KeyPair`] may be - /// serialized using [`KeyPair::serialize_der`] and [`KeyPair::serialize_pem`]. - pub fn generate_self_signed(mut params: CertificateParams) -> Result { - let key_pair = KeyPair::validate_or_generate(&mut params.key_pair, params.alg)?; + /// [`Certificate::pem`]. + pub fn generate_self_signed( + params: CertificateParams, + key_pair: &KeyPair, + ) -> Result { let subject_public_key_info = key_pair.public_key_der(); - let der = params.serialize_der_with_signer( - &key_pair, - params.alg, - &key_pair, - ¶ms.distinguished_name, - )?; - Ok(CertifiedKey { - cert: Certificate { - params, - subject_public_key_info, - der, - }, - key_pair, + let der = + params.serialize_der_with_signer(key_pair, key_pair, ¶ms.distinguished_name)?; + Ok(Certificate { + params, + subject_public_key_info, + der, }) } /// Generate a new certificate from the given parameters, signed by the provided issuer. /// - /// If [`CertificateParams::key_pair`] is not set to a pre-generated key, a new key pair - /// is generated using reasonable defaults. - /// /// The returned certificate will have its issuer field set to the subject of the /// provided `issuer`, and the authority key identifier extension will be populated using /// the subject public key of `issuer`. It will be signed by `issuer_key`. @@ -1553,28 +1526,23 @@ impl Certificate { /// the certificate to be a CA certificate, or have key usage extensions that allow signing. /// /// The returned [`Certificate`] may be serialized using [`Certificate::der`] and - /// [`Certificate::pem`]. Similarly the private key of the returned [`KeyPair`] may be - /// serialized using [`KeyPair::serialize_der`] and [`KeyPair::serialize_pem`]. + /// [`Certificate::pem`]. pub fn generate( - mut params: CertificateParams, + params: CertificateParams, + key_pair: &KeyPair, issuer: &Certificate, issuer_key: &KeyPair, - ) -> Result { - let key_pair = KeyPair::validate_or_generate(&mut params.key_pair, params.alg)?; + ) -> Result { let subject_public_key_info = key_pair.public_key_der(); let der = params.serialize_der_with_signer( - &key_pair, - &issuer.params.alg, + key_pair, issuer_key, &issuer.params.distinguished_name, )?; - Ok(CertifiedKey { - cert: Certificate { - params, - subject_public_key_info, - der, - }, - key_pair, + Ok(Certificate { + params, + subject_public_key_info, + der, }) } /// Generate a new certificate using the certificate signing request parameters, signed by @@ -1596,7 +1564,6 @@ impl Certificate { ) -> Result { let der = request.params.serialize_der_with_signer( &request.public_key, - request.params.alg, issuer_key, &issuer.params.distinguished_name, )?; @@ -1648,7 +1615,7 @@ impl Certificate { writer.next().write_der(&cert_data); // Write signatureAlgorithm - self.params.alg.write_alg_ident(writer.next()); + subject_key.alg.write_alg_ident(writer.next()); // Write signature subject_key.sign(&cert_data, writer.next())?; @@ -1731,20 +1698,6 @@ impl zeroize::Zeroize for KeyPair { } } -#[cfg(feature = "zeroize")] -impl zeroize::Zeroize for CertificateSigningRequestParams { - fn zeroize(&mut self) { - self.params.zeroize(); - } -} - -#[cfg(feature = "zeroize")] -impl zeroize::Zeroize for CertificateParams { - fn zeroize(&mut self) { - self.key_pair.zeroize(); - } -} - /// A certificate serial number. #[derive(Debug, PartialEq, Eq, Hash, Clone)] pub struct SerialNumber { @@ -1856,7 +1809,8 @@ mod tests { params.is_ca = IsCa::Ca(BasicConstraints::Constrained(0)); // Make the cert - let cert = Certificate::generate_self_signed(params).unwrap().cert; + let key_pair = KeyPair::generate().unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Parse it let (_rem, cert) = x509_parser::parse_x509_certificate(cert.der()).unwrap(); @@ -1893,7 +1847,8 @@ mod tests { params.is_ca = IsCa::Ca(BasicConstraints::Constrained(0)); // Make the cert - let cert = Certificate::generate_self_signed(params).unwrap().cert; + let key_pair = KeyPair::generate().unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Parse it let (_rem, cert) = x509_parser::parse_x509_certificate(cert.der()).unwrap(); @@ -1927,7 +1882,8 @@ mod tests { params.extended_key_usages = vec![ExtendedKeyUsagePurpose::Any]; // Make the cert - let cert = Certificate::generate_self_signed(params).unwrap().cert; + let key_pair = KeyPair::generate().unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Parse it let (_rem, cert) = x509_parser::parse_x509_certificate(cert.der()).unwrap(); @@ -1952,7 +1908,8 @@ mod tests { ]; // Make the cert - let cert = Certificate::generate_self_signed(params).unwrap().cert; + let key_pair = KeyPair::generate().unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Parse it let (_rem, cert) = x509_parser::parse_x509_certificate(cert.der()).unwrap(); @@ -1985,24 +1942,23 @@ mod tests { #[cfg(feature = "pem")] mod test_pem_serialization { - use crate::Certificate; - use crate::CertificateParams; + use crate::{Certificate, CertificateParams, KeyPair}; #[test] #[cfg(windows)] fn test_windows_line_endings() { - let cert = Certificate::generate_self_signed(CertificateParams::default()) - .unwrap() - .cert; + let key_pair = KeyPair::generate().unwrap(); + let cert = + Certificate::generate_self_signed(CertificateParams::default(), &key_pair).unwrap(); assert!(cert.pem().contains("\r\n")); } #[test] #[cfg(not(windows))] fn test_not_windows_line_endings() { - let cert = Certificate::generate_self_signed(CertificateParams::default()) - .unwrap() - .cert; + let key_pair = KeyPair::generate().unwrap(); + let cert = + Certificate::generate_self_signed(CertificateParams::default(), &key_pair).unwrap(); assert!(!cert.pem().contains('\r')); } } @@ -2161,8 +2117,7 @@ JiY98T5oN1X0C/qAXxJfSvklbru9fipwGt3dho5Tm6Ee3cYf+plnk4WZhSnqyef4 PITGdT9dgN88nHPCle0B1+OY+OZ5 -----END PRIVATE KEY-----"#; - let kp = KeyPair::from_pem(&ca_key).unwrap(); - let params = CertificateParams::from_ca_cert_pem(ca_cert, kp).unwrap(); + let params = CertificateParams::from_ca_cert_pem(ca_cert).unwrap(); let expected_ski = vec![ 0x97, 0xD4, 0x76, 0xA1, 0x9B, 0x1A, 0x71, 0x35, 0x2A, 0xC7, 0xF4, 0xA1, 0x84, 0x12, 0x56, 0x06, 0xBA, 0x5D, 0x61, 0x84, @@ -2173,7 +2128,8 @@ PITGdT9dgN88nHPCle0B1+OY+OZ5 params.key_identifier_method ); - let ca_cert = Certificate::generate_self_signed(params).unwrap().cert; + let kp = KeyPair::from_pem(&ca_key).unwrap(); + let ca_cert = Certificate::generate_self_signed(params, &kp).unwrap(); assert_eq!(&expected_ski, &ca_cert.get_key_identifier()); let (_remainder, x509) = x509_parser::parse_x509_certificate(ca_cert.der()).unwrap(); diff --git a/rcgen/tests/botan.rs b/rcgen/tests/botan.rs index 38666562..376a253a 100644 --- a/rcgen/tests/botan.rs +++ b/rcgen/tests/botan.rs @@ -4,17 +4,17 @@ use rcgen::{BasicConstraints, Certificate, CertificateParams, DnType, IsCa}; use rcgen::{ CertificateRevocationList, CertificateRevocationListParams, RevocationReason, RevokedCertParams, }; -use rcgen::{CertifiedKey, DnValue}; +use rcgen::{DnValue, KeyPair}; use rcgen::{KeyUsagePurpose, SerialNumber}; use time::{Duration, OffsetDateTime}; mod util; -fn default_params() -> CertificateParams { - let mut params = util::default_params(); +fn default_params() -> (CertificateParams, KeyPair) { + let (mut params, key_pair) = util::default_params(); // Botan has a sanity check that enforces a maximum expiration date params.not_after = rcgen::date_time_ymd(3016, 1, 1); - params + (params, key_pair) } fn check_cert(cert_der: &[u8], cert: &Certificate) { @@ -49,8 +49,8 @@ fn check_cert_ca(cert_der: &[u8], _cert: &Certificate, ca_der: &[u8]) { #[test] fn test_botan() { - let params = default_params(); - let cert = Certificate::generate_self_signed(params).unwrap().cert; + let (params, key_pair) = default_params(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. check_cert(cert.der(), &cert); @@ -58,10 +58,9 @@ fn test_botan() { #[test] fn test_botan_256() { - let mut params = default_params(); - params.alg = &rcgen::PKCS_ECDSA_P256_SHA256; - - let cert = Certificate::generate_self_signed(params).unwrap().cert; + let (params, _) = default_params(); + let key_pair = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. check_cert(cert.der(), &cert); @@ -69,10 +68,9 @@ fn test_botan_256() { #[test] fn test_botan_384() { - let mut params = default_params(); - params.alg = &rcgen::PKCS_ECDSA_P384_SHA384; - - let cert = Certificate::generate_self_signed(params).unwrap().cert; + let (params, _) = default_params(); + let key_pair = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P384_SHA384).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. check_cert(cert.der(), &cert); @@ -80,10 +78,9 @@ fn test_botan_384() { #[test] fn test_botan_25519() { - let mut params = default_params(); - params.alg = &rcgen::PKCS_ED25519; - - let cert = Certificate::generate_self_signed(params).unwrap().cert; + let (params, _) = default_params(); + let key_pair = KeyPair::generate_for(&rcgen::PKCS_ED25519).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. check_cert(cert.der(), &cert); @@ -91,13 +88,9 @@ fn test_botan_25519() { #[test] fn test_botan_25519_v1_given() { - let mut params = default_params(); - params.alg = &rcgen::PKCS_ED25519; - - let kp = rcgen::KeyPair::from_pem(util::ED25519_TEST_KEY_PAIR_PEM_V1).unwrap(); - params.key_pair = Some(kp); - - let cert = Certificate::generate_self_signed(params).unwrap().cert; + let (params, _) = default_params(); + let key_pair = KeyPair::from_pem(util::ED25519_TEST_KEY_PAIR_PEM_V1).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. check_cert(cert.der(), &cert); @@ -105,13 +98,9 @@ fn test_botan_25519_v1_given() { #[test] fn test_botan_25519_v2_given() { - let mut params = default_params(); - params.alg = &rcgen::PKCS_ED25519; - - let kp = rcgen::KeyPair::from_pem(util::ED25519_TEST_KEY_PAIR_PEM_V2).unwrap(); - params.key_pair = Some(kp); - - let cert = Certificate::generate_self_signed(params).unwrap().cert; + let (params, _) = default_params(); + let key_pair = KeyPair::from_pem(util::ED25519_TEST_KEY_PAIR_PEM_V2).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. check_cert(cert.der(), &cert); @@ -119,13 +108,9 @@ fn test_botan_25519_v2_given() { #[test] fn test_botan_rsa_given() { - let mut params = default_params(); - params.alg = &rcgen::PKCS_RSA_SHA256; - - let kp = rcgen::KeyPair::from_pem(util::RSA_TEST_KEY_PAIR_PEM).unwrap(); - params.key_pair = Some(kp); - - let cert = Certificate::generate_self_signed(params).unwrap().cert; + let (params, _) = default_params(); + let key_pair = KeyPair::from_pem(util::RSA_TEST_KEY_PAIR_PEM).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. check_cert(cert.der(), &cert); @@ -133,12 +118,9 @@ fn test_botan_rsa_given() { #[test] fn test_botan_separate_ca() { - let mut params = default_params(); + let (mut params, ca_key) = default_params(); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let CertifiedKey { - cert: ca_cert, - key_pair: ca_key, - } = Certificate::generate_self_signed(params).unwrap(); + let ca_cert = Certificate::generate_self_signed(params, &ca_key).unwrap(); let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]); params @@ -150,32 +132,23 @@ fn test_botan_separate_ca() { // Botan has a sanity check that enforces a maximum expiration date params.not_after = rcgen::date_time_ymd(3016, 1, 1); - let cert = Certificate::generate(params, &ca_cert, &ca_key) - .unwrap() - .cert; + let key_pair = KeyPair::generate().unwrap(); + let cert = Certificate::generate(params, &key_pair, &ca_cert, &ca_key).unwrap(); check_cert_ca(cert.der(), &cert, ca_cert.der()); } #[cfg(feature = "x509-parser")] #[test] fn test_botan_imported_ca() { - use std::convert::TryInto; - let mut params = default_params(); + let (mut params, ca_key) = default_params(); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let CertifiedKey { - cert: ca_cert, - key_pair: cert_key, - } = Certificate::generate_self_signed(params).unwrap(); + let ca_cert = Certificate::generate_self_signed(params, &ca_key).unwrap(); - let (ca_cert_der, ca_key_der) = (ca_cert.der(), cert_key.serialize_der()); + let ca_cert_der = ca_cert.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, ca_key_pair).unwrap(); - let CertifiedKey { - cert: imported_ca_cert, - key_pair: ca_key, - } = Certificate::generate_self_signed(imported_ca_cert_params).unwrap(); + let imported_ca_cert_params = CertificateParams::from_ca_cert_der(ca_cert_der).unwrap(); + let imported_ca_cert = + Certificate::generate_self_signed(imported_ca_cert_params, &ca_key).unwrap(); let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]); params @@ -187,36 +160,27 @@ fn test_botan_imported_ca() { // Botan has a sanity check that enforces a maximum expiration date params.not_after = rcgen::date_time_ymd(3016, 1, 1); - let cert = Certificate::generate(params, &imported_ca_cert, &ca_key) - .unwrap() - .cert; + let key_pair = KeyPair::generate().unwrap(); + let cert = Certificate::generate(params, &key_pair, &imported_ca_cert, &ca_key).unwrap(); 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(); + let (mut params, imported_ca_key) = default_params(); params.distinguished_name.push( DnType::CountryName, DnValue::PrintableString("US".to_string()), ); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let CertifiedKey { - cert: ca_cert, - key_pair: ca_key, - } = Certificate::generate_self_signed(params).unwrap(); + let ca_cert = Certificate::generate_self_signed(params, &imported_ca_key).unwrap(); - let (ca_cert_der, ca_key_der) = (ca_cert.der(), ca_key.serialize_der()); + let ca_cert_der = ca_cert.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, ca_key_pair).unwrap(); - let CertifiedKey { - cert: imported_ca_cert, - key_pair: imported_ca_key, - } = Certificate::generate_self_signed(imported_ca_cert_params).unwrap(); + let imported_ca_cert_params = CertificateParams::from_ca_cert_der(ca_cert_der).unwrap(); + let imported_ca_cert = + Certificate::generate_self_signed(imported_ca_cert_params, &imported_ca_key).unwrap(); let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]); params @@ -227,9 +191,9 @@ fn test_botan_imported_ca_with_printable_string() { .push(DnType::CommonName, "Dev domain"); // Botan has a sanity check that enforces a maximum expiration date params.not_after = rcgen::date_time_ymd(3016, 1, 1); - let cert = Certificate::generate(params, &imported_ca_cert, &imported_ca_key) - .unwrap() - .cert; + let key_pair = KeyPair::generate().unwrap(); + let cert = + Certificate::generate(params, &key_pair, &imported_ca_cert, &imported_ca_key).unwrap(); check_cert_ca(cert.der(), &cert, ca_cert_der); } @@ -238,29 +202,24 @@ fn test_botan_imported_ca_with_printable_string() { fn test_botan_crl_parse() { // Create an issuer CA. let alg = &rcgen::PKCS_ECDSA_P256_SHA256; - let mut issuer = util::default_params(); + let (mut issuer, _) = util::default_params(); issuer.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); issuer.key_usages = vec![ KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::DigitalSignature, KeyUsagePurpose::CrlSign, ]; - issuer.alg = alg; - let CertifiedKey { - cert: issuer, - key_pair: issuer_key, - } = Certificate::generate_self_signed(issuer).unwrap(); + let issuer_key = KeyPair::generate_for(alg).unwrap(); + let issuer = Certificate::generate_self_signed(issuer, &issuer_key).unwrap(); // Create an end entity cert issued by the issuer. - let mut ee = util::default_params(); - ee.alg = alg; + let (mut ee, _) = util::default_params(); ee.is_ca = IsCa::NoCa; ee.serial_number = Some(SerialNumber::from(99999)); // Botan has a sanity check that enforces a maximum expiration date ee.not_after = rcgen::date_time_ymd(3016, 1, 1); - let ee = Certificate::generate(ee, &issuer, &issuer_key) - .unwrap() - .cert; + let ee_key = KeyPair::generate_for(alg).unwrap(); + let ee = Certificate::generate(ee, &ee_key, &issuer, &issuer_key).unwrap(); let botan_ee = botan::Certificate::load(ee.der()).unwrap(); // Generate a CRL with the issuer that revokes the EE cert. @@ -277,7 +236,6 @@ fn test_botan_crl_parse() { invalidity_date: None, }], key_identifier_method: rcgen::KeyIdMethod::Sha256, - alg, }; let crl = CertificateRevocationList::from_params(crl).unwrap(); diff --git a/rcgen/tests/generic.rs b/rcgen/tests/generic.rs index 688bdd7e..8d9d0719 100644 --- a/rcgen/tests/generic.rs +++ b/rcgen/tests/generic.rs @@ -2,9 +2,6 @@ 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}; @@ -32,23 +29,6 @@ mod test_key_params_mismatch { 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::generate_self_signed(wrong_params).err(), - Some(Error::CertificateKeyPairMismatch), - "i: {} j: {}", - i, - j - ); } } } @@ -56,10 +36,7 @@ mod test_key_params_mismatch { #[cfg(feature = "x509-parser")] mod test_convert_x509_subject_alternative_name { - use rcgen::{ - BasicConstraints, Certificate, CertificateParams, IsCa, KeyPair, SanType, - PKCS_ECDSA_P256_SHA256, - }; + use rcgen::{BasicConstraints, Certificate, CertificateParams, IsCa, SanType}; use std::net::{IpAddr, Ipv4Addr}; #[test] @@ -67,7 +44,7 @@ mod test_convert_x509_subject_alternative_name { let ip = Ipv4Addr::new(2, 4, 6, 8); let ip_san = SanType::IpAddress(IpAddr::V4(ip)); - let mut params = super::util::default_params(); + let (mut params, ca_key) = super::util::default_params(); // Add the SAN we want to test the parsing for params.subject_alt_names.push(ip_san.clone()); @@ -75,16 +52,12 @@ mod test_convert_x509_subject_alternative_name { // Because we're using a function for CA certificates params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let cert = Certificate::generate_self_signed(params).unwrap().cert; + let cert = Certificate::generate_self_signed(params, &ca_key).unwrap(); // Serialize our cert that has our chosen san, so we can testing parsing/deserializing it. let ca_der = cert.der(); - // Arbitrary key pair not used with the test, but required by the parsing function - let key_pair = KeyPair::generate(&PKCS_ECDSA_P256_SHA256).unwrap(); - - let actual = CertificateParams::from_ca_cert_der(ca_der, key_pair).unwrap(); - + let actual = CertificateParams::from_ca_cert_der(ca_der).unwrap(); assert!(actual.subject_alt_names.contains(&ip_san)); } } @@ -93,7 +66,7 @@ mod test_convert_x509_subject_alternative_name { mod test_x509_custom_ext { use crate::util; - use rcgen::{Certificate, CertifiedKey, CustomExtension}; + use rcgen::{Certificate, CustomExtension}; use x509_parser::oid_registry::asn1_rs; use x509_parser::prelude::{ FromDer, ParsedCriAttribute, X509Certificate, X509CertificationRequest, @@ -113,15 +86,12 @@ mod test_x509_custom_ext { custom_ext.set_criticality(true); // Generate a certificate with the custom extension, parse it with x509-parser. - let mut params = util::default_params(); + let (mut params, test_key) = util::default_params(); params.custom_extensions = vec![custom_ext]; // Ensure the custom exts. being omitted into a CSR doesn't require SAN ext being present. // See https://github.com/rustls/rcgen/issues/122 params.subject_alt_names = Vec::default(); - let CertifiedKey { - cert: test_cert, - key_pair: test_key, - } = Certificate::generate_self_signed(params).unwrap(); + let test_cert = Certificate::generate_self_signed(params, &test_key).unwrap(); let (_, x509_test_cert) = X509Certificate::from_der(test_cert.der()).unwrap(); // We should be able to find the extension by OID, with expected criticality and value. @@ -305,28 +275,27 @@ mod test_parse_crl_dps { mod test_parse_ia5string_subject { use crate::util; use rcgen::DnType::CustomDnType; - use rcgen::{Certificate, CertificateParams, DistinguishedName, DnValue, KeyPair}; + use rcgen::{Certificate, CertificateParams, DistinguishedName, DnValue}; #[test] fn parse_ia5string_subject() { // Create and serialize a certificate with a subject containing an IA5String email address. let email_address_dn_type = CustomDnType(vec![1, 2, 840, 113549, 1, 9, 1]); // id-emailAddress let email_address_dn_value = DnValue::Ia5String("foo@bar.com".into()); - let mut params = util::default_params(); + let (mut params, key_pair) = 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::generate_self_signed(params).unwrap().cert; + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); let cert_der = cert.der(); // We should be able to parse the certificate with x509-parser. assert!(x509_parser::parse_x509_certificate(cert_der).is_ok()); // We should be able to reconstitute params from the DER using x509-parser. - 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 params_from_cert = CertificateParams::from_ca_cert_der(cert_der).unwrap(); // We should find the expected distinguished name in the reconstituted params. let expected_names = &[(&email_address_dn_type, &email_address_dn_value)]; diff --git a/rcgen/tests/openssl.rs b/rcgen/tests/openssl.rs index 891d0b6d..d3daaaa2 100644 --- a/rcgen/tests/openssl.rs +++ b/rcgen/tests/openssl.rs @@ -7,8 +7,8 @@ use openssl::stack::Stack; use openssl::x509::store::{X509Store, X509StoreBuilder}; use openssl::x509::{CrlStatus, X509Crl, X509Req, X509StoreContext, X509}; use rcgen::{ - BasicConstraints, Certificate, CertificateParams, CertifiedKey, DnType, DnValue, - GeneralSubtree, IsCa, NameConstraints, + BasicConstraints, Certificate, CertificateParams, DnType, DnValue, GeneralSubtree, IsCa, + KeyPair, NameConstraints, }; use std::cell::RefCell; use std::io::{Error, ErrorKind, Read, Result as ioResult, Write}; @@ -89,10 +89,10 @@ impl Read for PipeEnd { } } -fn verify_cert(certified_key: &CertifiedKey) { - verify_cert_basic(&certified_key.cert); - let key = certified_key.key_pair.serialize_der(); - verify_cert_ca(&certified_key.cert.pem(), &key, &certified_key.cert.pem()); +fn verify_cert(cert: &Certificate, key_pair: &KeyPair) { + verify_cert_basic(cert); + let key = key_pair.serialize_der(); + verify_cert_ca(&cert.pem(), &key, &cert.pem()); } fn verify_cert_ca(cert_pem: &str, key: &[u8], ca_cert_pem: &str) { @@ -160,13 +160,10 @@ fn verify_cert_ca(cert_pem: &str, key: &[u8], ca_cert_pem: &str) { // TODO read the data we just wrote from the streams } -fn verify_csr(certified_key: &CertifiedKey) { - let csr = certified_key - .cert - .serialize_request_pem(&certified_key.key_pair) - .unwrap(); +fn verify_csr(cert: &Certificate, key_pair: &KeyPair) { + let csr = cert.serialize_request_pem(key_pair).unwrap(); println!("{csr}"); - let key = certified_key.key_pair.serialize_der(); + let key = key_pair.serialize_der(); let pkey = PKey::private_key_from_der(&key).unwrap(); let req = X509Req::from_pem(csr.as_bytes()).unwrap(); @@ -175,44 +172,45 @@ fn verify_csr(certified_key: &CertifiedKey) { #[test] fn test_openssl() { - verify_cert(&Certificate::generate_self_signed(util::default_params()).unwrap()); + let (params, key_pair) = util::default_params(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); + verify_cert(&cert, &key_pair); } #[test] fn test_request() { - verify_csr(&Certificate::generate_self_signed(util::default_params()).unwrap()); + let (params, key_pair) = util::default_params(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); + verify_csr(&cert, &key_pair); } #[test] fn test_openssl_256() { - let mut params = util::default_params(); - params.alg = &rcgen::PKCS_ECDSA_P256_SHA256; - - let certified_key = Certificate::generate_self_signed(params).unwrap(); + let (params, _) = util::default_params(); + let key_pair = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. - verify_cert(&certified_key); - verify_csr(&certified_key); + verify_cert(&cert, &key_pair); + verify_csr(&cert, &key_pair); } #[test] fn test_openssl_384() { - let mut params = util::default_params(); - params.alg = &rcgen::PKCS_ECDSA_P384_SHA384; - - let certified_key = Certificate::generate_self_signed(params).unwrap(); + let (params, _) = util::default_params(); + let key_pair = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P384_SHA384).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. - verify_cert(&certified_key); - verify_csr(&certified_key); + verify_cert(&cert, &key_pair); + verify_csr(&cert, &key_pair); } #[test] fn test_openssl_25519() { - let mut params = util::default_params(); - params.alg = &rcgen::PKCS_ED25519; - - let cert = Certificate::generate_self_signed(params).unwrap().cert; + let (params, _) = util::default_params(); + let key_pair = KeyPair::generate_for(&rcgen::PKCS_ED25519).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. // TODO openssl doesn't support v2 keys (yet) @@ -224,35 +222,27 @@ fn test_openssl_25519() { #[test] fn test_openssl_25519_v1_given() { - let mut params = util::default_params(); - params.alg = &rcgen::PKCS_ED25519; - - let kp = rcgen::KeyPair::from_pem(util::ED25519_TEST_KEY_PAIR_PEM_V1).unwrap(); - params.key_pair = Some(kp); - - let certified_key = Certificate::generate_self_signed(params).unwrap(); + let (params, _) = util::default_params(); + let key_pair = rcgen::KeyPair::from_pem(util::ED25519_TEST_KEY_PAIR_PEM_V1).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate as well as CSR, // but only on OpenSSL >= 1.1.1 // On prior versions, only do basic verification #[allow(clippy::unusual_byte_groupings)] if openssl::version::number() >= 0x1_01_01_00_f { - verify_cert(&certified_key); - verify_csr(&certified_key); + verify_cert(&cert, &key_pair); + verify_csr(&cert, &key_pair); } else { - verify_cert_basic(&certified_key.cert); + verify_cert_basic(&cert); } } #[test] fn test_openssl_25519_v2_given() { - let mut params = util::default_params(); - params.alg = &rcgen::PKCS_ED25519; - - let kp = rcgen::KeyPair::from_pem(util::ED25519_TEST_KEY_PAIR_PEM_V2).unwrap(); - params.key_pair = Some(kp); - - let cert = Certificate::generate_self_signed(params).unwrap().cert; + let (params, _) = util::default_params(); + let key_pair = rcgen::KeyPair::from_pem(util::ED25519_TEST_KEY_PAIR_PEM_V2).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. // TODO openssl doesn't support v2 keys (yet) @@ -264,17 +254,13 @@ fn test_openssl_25519_v2_given() { #[test] fn test_openssl_rsa_given() { - let mut params = util::default_params(); - params.alg = &rcgen::PKCS_RSA_SHA256; - - let kp = rcgen::KeyPair::from_pem(util::RSA_TEST_KEY_PAIR_PEM).unwrap(); - params.key_pair = Some(kp); - - let certified_key = Certificate::generate_self_signed(params).unwrap(); + let (params, _) = util::default_params(); + let key_pair = KeyPair::from_pem(util::RSA_TEST_KEY_PAIR_PEM).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. - verify_cert(&certified_key); - verify_csr(&certified_key); + verify_cert(&cert, &key_pair); + verify_csr(&cert, &key_pair); } #[test] @@ -286,34 +272,27 @@ fn test_openssl_rsa_combinations_given() { //&rcgen::PKCS_RSA_PSS_SHA256, ]; for (i, alg) in alg_list.iter().enumerate() { - let mut params = util::default_params(); - params.alg = alg; - - let kp = rcgen::KeyPair::from_pem_and_sign_algo(util::RSA_TEST_KEY_PAIR_PEM, alg).unwrap(); - params.key_pair = Some(kp); - - let certified_key = Certificate::generate_self_signed(params).unwrap(); + let (params, _) = util::default_params(); + let key_pair = KeyPair::from_pem_and_sign_algo(util::RSA_TEST_KEY_PAIR_PEM, alg).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. if i >= 4 { - verify_cert(&certified_key); - verify_csr(&certified_key); + verify_cert(&cert, &key_pair); + verify_csr(&cert, &key_pair); } else { // The PSS key types are not fully supported. // An attempt to use them gives a handshake error. - verify_cert_basic(&certified_key.cert); + verify_cert_basic(&cert); } } } #[test] fn test_openssl_separate_ca() { - let mut params = util::default_params(); + let (mut params, ca_key) = util::default_params(); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let CertifiedKey { - cert: ca_cert, - key_pair: ca_key, - } = Certificate::generate_self_signed(params).unwrap(); + let ca_cert = Certificate::generate_self_signed(params, &ca_key).unwrap(); let ca_cert_pem = ca_cert.pem(); let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]); @@ -323,10 +302,8 @@ fn test_openssl_separate_ca() { params .distinguished_name .push(DnType::CommonName, "Dev domain"); - let CertifiedKey { - cert, - key_pair: cert_key, - } = Certificate::generate(params, &ca_cert, &ca_key).unwrap(); + let cert_key = KeyPair::generate().unwrap(); + let cert = Certificate::generate(params, &cert_key, &ca_cert, &ca_key).unwrap(); let key = cert_key.serialize_der(); verify_cert_ca(&cert.pem(), &key, &ca_cert_pem); @@ -334,16 +311,13 @@ fn test_openssl_separate_ca() { #[test] fn test_openssl_separate_ca_with_printable_string() { - let mut params = util::default_params(); + let (mut params, ca_key) = util::default_params(); params.distinguished_name.push( DnType::CountryName, DnValue::PrintableString("US".to_string()), ); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let CertifiedKey { - cert: ca_cert, - key_pair: ca_key, - } = Certificate::generate_self_signed(params).unwrap(); + let ca_cert = Certificate::generate_self_signed(params, &ca_key).unwrap(); let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]); params @@ -352,10 +326,8 @@ fn test_openssl_separate_ca_with_printable_string() { params .distinguished_name .push(DnType::CommonName, "Dev domain"); - let CertifiedKey { - cert, - key_pair: cert_key, - } = Certificate::generate(params, &ca_cert, &ca_key).unwrap(); + let cert_key = KeyPair::generate().unwrap(); + let cert = Certificate::generate(params, &cert_key, &ca_cert, &ca_key).unwrap(); let key = cert_key.serialize_der(); verify_cert_ca(&cert.pem(), &key, &ca_cert.pem()); @@ -363,26 +335,20 @@ fn test_openssl_separate_ca_with_printable_string() { #[test] fn test_openssl_separate_ca_with_other_signing_alg() { - let mut params = util::default_params(); - params.alg = &rcgen::PKCS_ECDSA_P256_SHA256; + let (mut params, _) = util::default_params(); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let CertifiedKey { - cert: ca_cert, - key_pair: ca_key, - } = Certificate::generate_self_signed(params).unwrap(); + let ca_key = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256).unwrap(); + let ca_cert = Certificate::generate_self_signed(params, &ca_key).unwrap(); let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]); - params.alg = &rcgen::PKCS_ECDSA_P384_SHA384; params .distinguished_name .push(DnType::OrganizationName, "Crab widgits SE"); params .distinguished_name .push(DnType::CommonName, "Dev domain"); - let CertifiedKey { - cert, - key_pair: cert_key, - } = Certificate::generate(params, &ca_cert, &ca_key).unwrap(); + let cert_key = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P384_SHA384).unwrap(); + let cert = Certificate::generate(params, &cert_key, &ca_cert, &ca_key).unwrap(); let key = cert_key.serialize_der(); verify_cert_ca(&cert.pem(), &key, &ca_cert.pem()); @@ -390,7 +356,7 @@ fn test_openssl_separate_ca_with_other_signing_alg() { #[test] fn test_openssl_separate_ca_name_constraints() { - let mut params = util::default_params(); + let (mut params, ca_key) = util::default_params(); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); println!("openssl version: {:x}", openssl::version::number()); @@ -402,10 +368,7 @@ fn test_openssl_separate_ca_name_constraints() { //excluded_subtrees : vec![GeneralSubtree::DnsName(".v".to_string())], excluded_subtrees: Vec::new(), }); - let CertifiedKey { - cert: ca_cert, - key_pair: ca_key, - } = Certificate::generate_self_signed(params).unwrap(); + let ca_cert = Certificate::generate_self_signed(params, &ca_key).unwrap(); let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]); params @@ -414,10 +377,8 @@ fn test_openssl_separate_ca_name_constraints() { params .distinguished_name .push(DnType::CommonName, "Dev domain"); - let CertifiedKey { - cert, - key_pair: cert_key, - } = Certificate::generate(params, &ca_cert, &ca_key).unwrap(); + let cert_key = KeyPair::generate().unwrap(); + let cert = Certificate::generate(params, &cert_key, &ca_cert, &ca_key).unwrap(); let key = cert_key.serialize_der(); verify_cert_ca(&cert.pem(), &key, &ca_cert.pem()); diff --git a/rcgen/tests/util.rs b/rcgen/tests/util.rs index aea8f4d6..056d2702 100644 --- a/rcgen/tests/util.rs +++ b/rcgen/tests/util.rs @@ -1,11 +1,9 @@ -use rcgen::{BasicConstraints, Certificate, CertificateParams, CertifiedKey, KeyPair}; +use rcgen::{BasicConstraints, Certificate, CertificateParams, KeyPair}; use rcgen::{ CertificateRevocationList, CrlDistributionPoint, CrlIssuingDistributionPoint, CrlScope, }; use rcgen::{CertificateRevocationListParams, DnType, IsCa, KeyIdMethod}; -use rcgen::{ - KeyUsagePurpose, RevocationReason, RevokedCertParams, SerialNumber, PKCS_ECDSA_P256_SHA256, -}; +use rcgen::{KeyUsagePurpose, RevocationReason, RevokedCertParams, SerialNumber}; use time::{Duration, OffsetDateTime}; // Generated by adding `println!("{}", cert.serialize_private_key_pem());` @@ -35,6 +33,7 @@ Generated by: openssl genpkey -algorithm RSA \ -pkeyopt rsa_keygen_pubexp:65537 | \ openssl pkcs8 -topk8 -nocrypt -outform pem */ +#[allow(dead_code)] // Used in some but not all test compilation units. #[cfg(feature = "pem")] pub const RSA_TEST_KEY_PAIR_PEM: &str = r#" -----BEGIN PRIVATE KEY----- @@ -67,7 +66,7 @@ YPTHy8SWRA2sMII3ArhHJ8A= -----END PRIVATE KEY----- "#; -pub fn default_params() -> CertificateParams { +pub fn default_params() -> (CertificateParams, KeyPair) { let mut params = CertificateParams::new(vec!["crabs.crabs".to_string(), "localhost".to_string()]); params @@ -76,22 +75,21 @@ pub fn default_params() -> CertificateParams { params .distinguished_name .push(DnType::CommonName, "Master CA"); - params + + let key_pair = KeyPair::generate().unwrap(); + (params, key_pair) } #[allow(unused)] // Used by openssl + x509-parser features. pub fn test_crl() -> (CertificateRevocationList, Certificate, KeyPair) { - let mut issuer = default_params(); + let (mut issuer, key_pair) = default_params(); issuer.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); issuer.key_usages = vec![ KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::DigitalSignature, KeyUsagePurpose::CrlSign, ]; - let CertifiedKey { - cert: issuer, - key_pair, - } = Certificate::generate_self_signed(issuer).unwrap(); + let issuer = Certificate::generate_self_signed(issuer, &key_pair).unwrap(); let now = OffsetDateTime::now_utc(); let next_week = now + Duration::weeks(1); @@ -113,7 +111,6 @@ pub fn test_crl() -> (CertificateRevocationList, Certificate, KeyPair) { scope: Some(CrlScope::UserCertsOnly), }), revoked_certs: vec![revoked_cert], - alg: &PKCS_ECDSA_P256_SHA256, key_identifier_method: KeyIdMethod::Sha256, }; let crl = CertificateRevocationList::from_params(crl).unwrap(); @@ -123,7 +120,7 @@ pub fn test_crl() -> (CertificateRevocationList, Certificate, KeyPair) { #[allow(unused)] // Used by openssl + x509-parser features. pub fn cert_with_crl_dps() -> Vec { - let mut params = default_params(); + let (mut params, key_pair) = default_params(); params.crl_distribution_points = vec![ CrlDistributionPoint { uris: vec![ @@ -136,9 +133,8 @@ pub fn cert_with_crl_dps() -> Vec { }, ]; - Certificate::generate_self_signed(params) + Certificate::generate_self_signed(params, &key_pair) .unwrap() - .cert .der() .to_vec() } diff --git a/rcgen/tests/webpki.rs b/rcgen/tests/webpki.rs index 5dded30b..63964a0b 100644 --- a/rcgen/tests/webpki.rs +++ b/rcgen/tests/webpki.rs @@ -1,7 +1,6 @@ use pki_types::{CertificateDer, ServerName, SignatureVerificationAlgorithm, UnixTime}; use rcgen::{ - BasicConstraints, Certificate, CertificateParams, CertifiedKey, DnType, Error, IsCa, KeyPair, - RemoteKeyPair, + BasicConstraints, Certificate, CertificateParams, DnType, Error, IsCa, KeyPair, RemoteKeyPair, }; use rcgen::{ CertificateRevocationList, CertificateRevocationListParams, RevocationReason, RevokedCertParams, @@ -112,8 +111,8 @@ fn check_cert_ca<'a, 'b>( #[test] fn test_webpki() { - let params = util::default_params(); - let CertifiedKey { cert, key_pair } = Certificate::generate_self_signed(params).unwrap(); + let (params, key_pair) = util::default_params(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. let sign_fn = @@ -129,10 +128,9 @@ fn test_webpki() { #[test] fn test_webpki_256() { - let mut params = util::default_params(); - params.alg = &rcgen::PKCS_ECDSA_P256_SHA256; - - let CertifiedKey { cert, key_pair } = Certificate::generate_self_signed(params).unwrap(); + let (params, _) = util::default_params(); + let key_pair = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. let sign_fn = |cert, msg| sign_msg_ecdsa(cert, msg, &signature::ECDSA_P256_SHA256_ASN1_SIGNING); @@ -147,10 +145,9 @@ fn test_webpki_256() { #[test] fn test_webpki_384() { - let mut params = util::default_params(); - params.alg = &rcgen::PKCS_ECDSA_P384_SHA384; - - let CertifiedKey { cert, key_pair } = Certificate::generate_self_signed(params).unwrap(); + let (params, _) = util::default_params(); + let key_pair = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P384_SHA384).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. let sign_fn = |cert, msg| sign_msg_ecdsa(cert, msg, &signature::ECDSA_P384_SHA384_ASN1_SIGNING); @@ -165,10 +162,9 @@ fn test_webpki_384() { #[test] fn test_webpki_25519() { - let mut params = util::default_params(); - params.alg = &rcgen::PKCS_ED25519; - - let CertifiedKey { cert, key_pair } = Certificate::generate_self_signed(params).unwrap(); + let (params, _) = util::default_params(); + let key_pair = KeyPair::generate_for(&rcgen::PKCS_ED25519).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. check_cert( @@ -183,13 +179,9 @@ fn test_webpki_25519() { #[cfg(feature = "pem")] #[test] fn test_webpki_25519_v1_given() { - let mut params = util::default_params(); - params.alg = &rcgen::PKCS_ED25519; - - let kp = rcgen::KeyPair::from_pem(util::ED25519_TEST_KEY_PAIR_PEM_V1).unwrap(); - params.key_pair = Some(kp); - - let CertifiedKey { cert, key_pair } = Certificate::generate_self_signed(params).unwrap(); + let (params, _) = util::default_params(); + let key_pair = rcgen::KeyPair::from_pem(util::ED25519_TEST_KEY_PAIR_PEM_V1).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. check_cert( @@ -204,13 +196,9 @@ fn test_webpki_25519_v1_given() { #[cfg(feature = "pem")] #[test] fn test_webpki_25519_v2_given() { - let mut params = util::default_params(); - params.alg = &rcgen::PKCS_ED25519; - - let kp = rcgen::KeyPair::from_pem(util::ED25519_TEST_KEY_PAIR_PEM_V2).unwrap(); - params.key_pair = Some(kp); - - let CertifiedKey { cert, key_pair } = Certificate::generate_self_signed(params).unwrap(); + let (params, _) = util::default_params(); + let key_pair = rcgen::KeyPair::from_pem(util::ED25519_TEST_KEY_PAIR_PEM_V2).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. check_cert( @@ -225,13 +213,9 @@ fn test_webpki_25519_v2_given() { #[cfg(feature = "pem")] #[test] fn test_webpki_rsa_given() { - let mut params = util::default_params(); - params.alg = &rcgen::PKCS_RSA_SHA256; - - let kp = rcgen::KeyPair::from_pem(util::RSA_TEST_KEY_PAIR_PEM).unwrap(); - params.key_pair = Some(kp); - - let CertifiedKey { cert, key_pair } = Certificate::generate_self_signed(params).unwrap(); + let (params, _) = util::default_params(); + let key_pair = rcgen::KeyPair::from_pem(util::RSA_TEST_KEY_PAIR_PEM).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. check_cert( @@ -265,12 +249,10 @@ fn test_webpki_rsa_combinations_given() { //(&rcgen::PKCS_RSA_PSS_SHA256, &webpki::RSA_PSS_2048_8192_SHA256_LEGACY_KEY, &signature::RSA_PSS_SHA256), ]; for c in configs { - let mut params = util::default_params(); - params.alg = c.0; - let kp = rcgen::KeyPair::from_pem_and_sign_algo(util::RSA_TEST_KEY_PAIR_PEM, c.0).unwrap(); - params.key_pair = Some(kp); - - let CertifiedKey { cert, key_pair } = Certificate::generate_self_signed(params).unwrap(); + let (params, _) = util::default_params(); + let key_pair = + rcgen::KeyPair::from_pem_and_sign_algo(util::RSA_TEST_KEY_PAIR_PEM, c.0).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. check_cert(cert.der(), &cert, &key_pair, c.1, |msg, cert| { @@ -281,12 +263,9 @@ fn test_webpki_rsa_combinations_given() { #[test] fn test_webpki_separate_ca() { - let mut params = util::default_params(); + let (mut params, ca_key) = util::default_params(); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let CertifiedKey { - cert: ca_cert, - key_pair: ca_key, - } = Certificate::generate_self_signed(params).unwrap(); + let ca_cert = Certificate::generate_self_signed(params, &ca_key).unwrap(); let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]); params @@ -296,7 +275,8 @@ fn test_webpki_separate_ca() { .distinguished_name .push(DnType::CommonName, "Dev domain"); - let CertifiedKey { cert, key_pair } = Certificate::generate(params, &ca_cert, &ca_key).unwrap(); + let key_pair = KeyPair::generate().unwrap(); + let cert = Certificate::generate(params, &key_pair, &ca_cert, &ca_key).unwrap(); let sign_fn = |cert, msg| sign_msg_ecdsa(cert, msg, &signature::ECDSA_P256_SHA256_ASN1_SIGNING); check_cert_ca( cert.der(), @@ -310,16 +290,12 @@ fn test_webpki_separate_ca() { #[test] fn test_webpki_separate_ca_with_other_signing_alg() { - let mut params = util::default_params(); + let (mut params, _) = util::default_params(); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - params.alg = &rcgen::PKCS_ECDSA_P256_SHA256; - let CertifiedKey { - cert: ca_cert, - key_pair: ca_key, - } = Certificate::generate_self_signed(params).unwrap(); + let ca_key = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256).unwrap(); + let ca_cert = Certificate::generate_self_signed(params, &ca_key).unwrap(); let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]); - params.alg = &rcgen::PKCS_ED25519; params .distinguished_name .push(DnType::OrganizationName, "Crab widgits SE"); @@ -327,7 +303,8 @@ fn test_webpki_separate_ca_with_other_signing_alg() { .distinguished_name .push(DnType::CommonName, "Dev domain"); - let CertifiedKey { cert, key_pair } = Certificate::generate(params, &ca_cert, &ca_key).unwrap(); + let key_pair = KeyPair::generate_for(&rcgen::PKCS_ED25519).unwrap(); + let cert = Certificate::generate(params, &key_pair, &ca_cert, &ca_key).unwrap(); check_cert_ca( cert.der(), &key_pair, @@ -361,7 +338,7 @@ fn from_remote() { } let rng = ring::rand::SystemRandom::new(); - let key_pair = KeyPair::generate(&rcgen::PKCS_ECDSA_P256_SHA256).unwrap(); + let key_pair = KeyPair::generate_for(&rcgen::PKCS_ECDSA_P256_SHA256).unwrap(); let remote = EcdsaKeyPair::from_pkcs8( &signature::ECDSA_P256_SHA256_ASN1_SIGNING, &key_pair.serialize_der(), @@ -376,13 +353,8 @@ fn from_remote() { .unwrap(); let remote = KeyPair::from_remote(Box::new(Remote(remote))).unwrap(); - let mut params = util::default_params(); - params.alg = &rcgen::PKCS_ECDSA_P256_SHA256; - params.key_pair = Some(remote); - let CertifiedKey { - cert, - key_pair: cert_kp, - } = Certificate::generate_self_signed(params).unwrap(); + let (params, _) = util::default_params(); + let cert = Certificate::generate_self_signed(params, &remote).unwrap(); // Now verify the certificate. let sign_fn = move |_, msg| { @@ -393,7 +365,7 @@ fn from_remote() { check_cert( cert.der(), &cert, - &cert_kp, + &remote, webpki::ring::ECDSA_P256_SHA256, sign_fn, ); @@ -440,23 +412,15 @@ fn test_webpki_separate_ca_name_constraints() { #[cfg(feature = "x509-parser")] #[test] fn test_webpki_imported_ca() { - use std::convert::TryInto; - let mut params = util::default_params(); + let (mut params, ca_key) = util::default_params(); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let CertifiedKey { - cert: ca_cert, - key_pair: ca_key, - } = Certificate::generate_self_signed(params).unwrap(); + let ca_cert = Certificate::generate_self_signed(params, &ca_key).unwrap(); - let (ca_cert_der, ca_key_der) = (ca_cert.der(), ca_key.serialize_der()); + let ca_cert_der = ca_cert.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, ca_key_pair).unwrap(); - let CertifiedKey { - cert: imported_ca_cert, - key_pair: ca_key, - } = Certificate::generate_self_signed(imported_ca_cert_params).unwrap(); + let imported_ca_cert_params = CertificateParams::from_ca_cert_der(ca_cert_der).unwrap(); + let imported_ca_cert = + Certificate::generate_self_signed(imported_ca_cert_params, &ca_key).unwrap(); let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]); params @@ -465,10 +429,8 @@ fn test_webpki_imported_ca() { params .distinguished_name .push(DnType::CommonName, "Dev domain"); - let CertifiedKey { - cert, - key_pair: cert_key, - } = Certificate::generate(params, &imported_ca_cert, &ca_key).unwrap(); + let cert_key = KeyPair::generate().unwrap(); + let cert = Certificate::generate(params, &cert_key, &imported_ca_cert, &ca_key).unwrap(); let sign_fn = |cert, msg| sign_msg_ecdsa(cert, msg, &signature::ECDSA_P256_SHA256_ASN1_SIGNING); check_cert_ca( @@ -484,27 +446,19 @@ fn test_webpki_imported_ca() { #[cfg(feature = "x509-parser")] #[test] fn test_webpki_imported_ca_with_printable_string() { - use std::convert::TryInto; - let mut params = util::default_params(); + let (mut params, ca_key) = util::default_params(); params.distinguished_name.push( DnType::CountryName, DnValue::PrintableString("US".to_string()), ); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let CertifiedKey { - cert: ca_cert, - key_pair: ca_key, - } = Certificate::generate_self_signed(params).unwrap(); + let ca_cert = Certificate::generate_self_signed(params, &ca_key).unwrap(); - let (ca_cert_der, ca_key_der) = (ca_cert.der(), ca_key.serialize_der()); + let ca_cert_der = ca_cert.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, ca_key_pair).unwrap(); - let CertifiedKey { - cert: imported_ca_cert, - key_pair: ca_key, - } = Certificate::generate_self_signed(imported_ca_cert_params).unwrap(); + let imported_ca_cert_params = CertificateParams::from_ca_cert_der(ca_cert_der).unwrap(); + let imported_ca_cert = + Certificate::generate_self_signed(imported_ca_cert_params, &ca_key).unwrap(); let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]); params @@ -513,10 +467,8 @@ fn test_webpki_imported_ca_with_printable_string() { params .distinguished_name .push(DnType::CommonName, "Dev domain"); - let CertifiedKey { - cert, - key_pair: cert_key, - } = Certificate::generate(params, &imported_ca_cert, &ca_key).unwrap(); + let cert_key = KeyPair::generate().unwrap(); + let cert = Certificate::generate(params, &cert_key, &imported_ca_cert, &ca_key).unwrap(); let sign_fn = |cert, msg| sign_msg_ecdsa(cert, msg, &signature::ECDSA_P256_SHA256_ASN1_SIGNING); check_cert_ca( @@ -539,19 +491,14 @@ fn test_certificate_from_csr() { params .distinguished_name .push(DnType::CommonName, "Dev domain"); - let CertifiedKey { - cert, - key_pair: cert_key, - } = Certificate::generate_self_signed(params).unwrap(); + let cert_key = KeyPair::generate().unwrap(); + let cert = Certificate::generate_self_signed(params, &cert_key).unwrap(); let csr_der = cert.serialize_request_der(&cert_key).unwrap(); let csr = CertificateSigningRequestParams::from_der(&csr_der).unwrap(); - let mut params = util::default_params(); + let (mut params, ca_key) = util::default_params(); params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); - let CertifiedKey { - cert: ca_cert, - key_pair: ca_key, - } = Certificate::generate_self_signed(params).unwrap(); + let ca_cert = Certificate::generate_self_signed(params, &ca_key).unwrap(); let cert = Certificate::from_request(csr, &ca_cert, &ca_key).unwrap(); let sign_fn = @@ -568,9 +515,9 @@ fn test_certificate_from_csr() { #[test] fn test_webpki_serial_number() { - let mut params = util::default_params(); + let (mut params, key_pair) = util::default_params(); params.serial_number = Some(vec![0, 1, 2].into()); - let CertifiedKey { cert, key_pair } = Certificate::generate_self_signed(params).unwrap(); + let cert = Certificate::generate_self_signed(params, &key_pair).unwrap(); // Now verify the certificate. let sign_fn = |cert, msg| sign_msg_ecdsa(cert, msg, &signature::ECDSA_P256_SHA256_ASN1_SIGNING); @@ -622,28 +569,23 @@ fn test_webpki_crl_parse() { fn test_webpki_crl_revoke() { // Create an issuer CA. let alg = &rcgen::PKCS_ECDSA_P256_SHA256; - let mut issuer = util::default_params(); + let (mut issuer, _) = util::default_params(); issuer.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); issuer.key_usages = vec![ KeyUsagePurpose::KeyCertSign, KeyUsagePurpose::DigitalSignature, KeyUsagePurpose::CrlSign, ]; - issuer.alg = alg; - let CertifiedKey { - cert: issuer, - key_pair: issuer_key, - } = Certificate::generate_self_signed(issuer).unwrap(); + let issuer_key = KeyPair::generate_for(alg).unwrap(); + let issuer = Certificate::generate_self_signed(issuer, &issuer_key).unwrap(); // Create an end entity cert issued by the issuer. - let mut ee = util::default_params(); + let (mut ee, _) = util::default_params(); ee.is_ca = IsCa::NoCa; ee.extended_key_usages = vec![ExtendedKeyUsagePurpose::ClientAuth]; - ee.alg = alg; ee.serial_number = Some(SerialNumber::from(99999)); - let ee = Certificate::generate(ee, &issuer, &issuer_key) - .unwrap() - .cert; + let ee_key = KeyPair::generate_for(alg).unwrap(); + let ee = Certificate::generate(ee, &ee_key, &issuer, &issuer_key).unwrap(); // Set up webpki's verification requirements. let ca_der = CertificateDer::from(issuer.der()); @@ -681,7 +623,6 @@ fn test_webpki_crl_revoke() { invalidity_date: None, }], key_identifier_method: rcgen::KeyIdMethod::Sha256, - alg, }; let crl = CertificateRevocationList::from_params(crl).unwrap(); let crl_der = crl.serialize_der_with_signer(&issuer, &issuer_key).unwrap(); diff --git a/rustls-cert-gen/src/cert.rs b/rustls-cert-gen/src/cert.rs index 87e03c2e..57a99263 100644 --- a/rustls-cert-gen/src/cert.rs +++ b/rustls-cert-gen/src/cert.rs @@ -1,6 +1,6 @@ use bpaf::Bpaf; use rcgen::{ - BasicConstraints, Certificate, CertificateParams, CertifiedKey, DistinguishedName, DnType, + BasicConstraints, Certificate, CertificateParams, DistinguishedName, DnType, DnValue::PrintableString, ExtendedKeyUsagePurpose, IsCa, KeyPair, KeyUsagePurpose, SanType, }; use std::{fmt, fs::File, io, path::Path}; @@ -34,6 +34,7 @@ impl PemCertifiedKey { #[derive(Default)] pub struct CertificateBuilder { params: CertificateParams, + alg: KeyPairAlgorithm, } impl CertificateBuilder { @@ -47,13 +48,14 @@ impl CertificateBuilder { let mut params = CertificateParams::default(); // override default Common Name params.distinguished_name = DistinguishedName::new(); - Self { params } + Self { + params, + alg: KeyPairAlgorithm::EcdsaP256, + } } /// Set signature algorithm (instead of default). - pub fn signature_algorithm(mut self, alg: &KeypairAlgorithm) -> anyhow::Result { - let keypair = alg.to_keypair()?; - self.params.alg = keypair.algorithm(); - self.params.key_pair = Some(keypair); + pub fn signature_algorithm(mut self, alg: KeyPairAlgorithm) -> anyhow::Result { + self.alg = alg; Ok(self) } /// Set options for Ca Certificates @@ -63,27 +65,28 @@ impl CertificateBuilder { /// let cert = CertificateBuilder::new().certificate_authority(); /// ``` pub fn certificate_authority(self) -> CaBuilder { - CaBuilder::new(self.params) + CaBuilder::new(self.params, self.alg) } /// Set options for `EndEntity` Certificates pub fn end_entity(self) -> EndEntityBuilder { - EndEntityBuilder::new(self.params) + EndEntityBuilder::new(self.params, self.alg) } } /// [CertificateParams] from which an [Ca] [Certificate] can be built pub struct CaBuilder { params: CertificateParams, + alg: KeyPairAlgorithm, } impl CaBuilder { /// Initialize `CaBuilder` - pub fn new(mut params: CertificateParams) -> Self { + pub fn new(mut params: CertificateParams, alg: KeyPairAlgorithm) -> Self { params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained); params.key_usages.push(KeyUsagePurpose::DigitalSignature); params.key_usages.push(KeyUsagePurpose::KeyCertSign); params.key_usages.push(KeyUsagePurpose::CrlSign); - Self { params } + Self { params, alg } } /// Add CountryName to `distinguished_name`. Multiple calls will /// replace previous value. @@ -103,7 +106,8 @@ impl CaBuilder { } /// build `Ca` Certificate. pub fn build(self) -> Result { - let CertifiedKey { cert, key_pair } = Certificate::generate_self_signed(self.params)?; + let key_pair = self.alg.to_key_pair()?; + let cert = Certificate::generate_self_signed(self.params, &key_pair)?; Ok(Ca { cert, key_pair }) } } @@ -148,15 +152,16 @@ impl EndEntity { /// [CertificateParams] from which an [EndEntity] [Certificate] can be built pub struct EndEntityBuilder { params: CertificateParams, + alg: KeyPairAlgorithm, } impl EndEntityBuilder { /// Initialize `EndEntityBuilder` - pub fn new(mut params: CertificateParams) -> Self { + pub fn new(mut params: CertificateParams, alg: KeyPairAlgorithm) -> Self { params.is_ca = IsCa::NoCa; params.use_authority_key_identifier_extension = true; params.key_usages.push(KeyUsagePurpose::DigitalSignature); - Self { params } + Self { params, alg } } /// Add CommonName to `distinguished_name`. Multiple calls will /// replace previous value. @@ -191,35 +196,36 @@ impl EndEntityBuilder { } /// build `EndEntity` Certificate. pub fn build(self, issuer: &Ca) -> Result { - let CertifiedKey { cert, key_pair } = - Certificate::generate(self.params, &issuer.cert, &issuer.key_pair)?; + let key_pair = self.alg.to_key_pair()?; + let cert = Certificate::generate(self.params, &key_pair, &issuer.cert, &issuer.key_pair)?; Ok(EndEntity { cert, key_pair }) } } -#[derive(Clone, Debug, Bpaf)] /// Supported Keypair Algorithms -pub enum KeypairAlgorithm { +#[derive(Clone, Copy, Debug, Default, Bpaf, PartialEq)] +pub enum KeyPairAlgorithm { Ed25519, + #[default] EcdsaP256, EcdsaP384, } -impl fmt::Display for KeypairAlgorithm { +impl fmt::Display for KeyPairAlgorithm { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { - KeypairAlgorithm::Ed25519 => write!(f, "ed25519"), - KeypairAlgorithm::EcdsaP256 => write!(f, "ecdsa-p256"), - KeypairAlgorithm::EcdsaP384 => write!(f, "ecdsa-p384"), + KeyPairAlgorithm::Ed25519 => write!(f, "ed25519"), + KeyPairAlgorithm::EcdsaP256 => write!(f, "ecdsa-p256"), + KeyPairAlgorithm::EcdsaP384 => write!(f, "ecdsa-p384"), } } } -impl KeypairAlgorithm { +impl KeyPairAlgorithm { /// Return an `rcgen::KeyPair` for the given varient - fn to_keypair(&self) -> Result { + fn to_key_pair(self) -> Result { match self { - KeypairAlgorithm::Ed25519 => { + KeyPairAlgorithm::Ed25519 => { use ring::signature::Ed25519KeyPair; let rng = ring::rand::SystemRandom::new(); @@ -229,7 +235,7 @@ impl KeypairAlgorithm { rcgen::KeyPair::from_der_and_sign_algo(pkcs8_bytes.as_ref(), alg) }, - KeypairAlgorithm::EcdsaP256 => { + KeyPairAlgorithm::EcdsaP256 => { use ring::signature::EcdsaKeyPair; use ring::signature::ECDSA_P256_SHA256_ASN1_SIGNING; @@ -240,7 +246,7 @@ impl KeypairAlgorithm { .or(Err(rcgen::Error::RingUnspecified))?; rcgen::KeyPair::from_der_and_sign_algo(pkcs8_bytes.as_ref(), alg) }, - KeypairAlgorithm::EcdsaP384 => { + KeyPairAlgorithm::EcdsaP384 => { use ring::signature::EcdsaKeyPair; use ring::signature::ECDSA_P384_SHA384_ASN1_SIGNING; @@ -292,7 +298,7 @@ mod tests { fn with_sig_algo_default() -> anyhow::Result<()> { let end_entity = CertificateBuilder::new().end_entity(); - assert_eq!(end_entity.params.alg, &rcgen::PKCS_ECDSA_P256_SHA256); + assert_eq!(end_entity.alg, KeyPairAlgorithm::EcdsaP256); Ok(()) } #[test] @@ -318,7 +324,7 @@ mod tests { fn serialize_end_entity_ecdsa_p384_sha384_sig() -> anyhow::Result<()> { let ca = CertificateBuilder::new().certificate_authority().build()?; let end_entity = CertificateBuilder::new() - .signature_algorithm(&KeypairAlgorithm::EcdsaP384)? + .signature_algorithm(KeyPairAlgorithm::EcdsaP384)? .end_entity() .build(&ca)? .serialize_pem(); @@ -337,7 +343,7 @@ mod tests { fn serialize_end_entity_ed25519_sig() -> anyhow::Result<()> { let ca = CertificateBuilder::new().certificate_authority().build()?; let end_entity = CertificateBuilder::new() - .signature_algorithm(&KeypairAlgorithm::Ed25519)? + .signature_algorithm(KeyPairAlgorithm::Ed25519)? .end_entity() .build(&ca)? .serialize_pem(); @@ -359,7 +365,7 @@ mod tests { #[test] fn init_end_endity() { let params = CertificateParams::default(); - let cert = EndEntityBuilder::new(params); + let cert = EndEntityBuilder::new(params, KeyPairAlgorithm::default()); assert_eq!(cert.params.is_ca, IsCa::NoCa) } #[test] @@ -369,7 +375,7 @@ mod tests { .build() .unwrap(); let params = CertificateParams::default(); - let mut cert = EndEntityBuilder::new(params); + let mut cert = EndEntityBuilder::new(params, KeyPairAlgorithm::default()); assert_eq!(cert.params.is_ca, IsCa::NoCa); assert_eq!( cert.client_auth().params.extended_key_usages, @@ -383,7 +389,7 @@ mod tests { .build() .unwrap(); let params = CertificateParams::default(); - let mut cert = EndEntityBuilder::new(params); + let mut cert = EndEntityBuilder::new(params, KeyPairAlgorithm::default()); assert_eq!(cert.params.is_ca, IsCa::NoCa); assert_eq!( cert.server_auth().params.extended_key_usages, @@ -399,7 +405,8 @@ mod tests { let name = "unexpected.oomyoo.xyz"; let names = vec![SanType::DnsName(name.into())]; let params = CertificateParams::default(); - let cert = EndEntityBuilder::new(params).subject_alternative_names(names); + let cert = EndEntityBuilder::new(params, KeyPairAlgorithm::default()) + .subject_alternative_names(names); assert_eq!( cert.params.subject_alt_names, vec![rcgen::SanType::DnsName(name.into())] @@ -413,20 +420,21 @@ mod tests { .unwrap(); let names = vec![]; let params = CertificateParams::default(); - let cert = EndEntityBuilder::new(params).subject_alternative_names(names); + let cert = EndEntityBuilder::new(params, KeyPairAlgorithm::default()) + .subject_alternative_names(names); assert_eq!(cert.params.subject_alt_names, vec![]); } #[test] - fn keypair_algorithm_to_keypair() -> anyhow::Result<()> { - let keypair = KeypairAlgorithm::Ed25519.to_keypair()?; + fn key_pair_algorithm_to_keypair() -> anyhow::Result<()> { + let keypair = KeyPairAlgorithm::Ed25519.to_key_pair()?; assert_eq!(format!("{:?}", keypair.algorithm()), "PKCS_ED25519"); - let keypair = KeypairAlgorithm::EcdsaP256.to_keypair()?; + let keypair = KeyPairAlgorithm::EcdsaP256.to_key_pair()?; assert_eq!( format!("{:?}", keypair.algorithm()), "PKCS_ECDSA_P256_SHA256" ); - let keypair = KeypairAlgorithm::EcdsaP384.to_keypair()?; + let keypair = KeyPairAlgorithm::EcdsaP384.to_key_pair()?; assert_eq!( format!("{:?}", keypair.algorithm()), "PKCS_ECDSA_P384_SHA384" diff --git a/rustls-cert-gen/src/main.rs b/rustls-cert-gen/src/main.rs index 8624a40a..9ee7b7cc 100644 --- a/rustls-cert-gen/src/main.rs +++ b/rustls-cert-gen/src/main.rs @@ -3,20 +3,20 @@ use rcgen::SanType; use std::{net::IpAddr, path::PathBuf}; mod cert; -use cert::{keypair_algorithm, CertificateBuilder, KeypairAlgorithm}; +use cert::{key_pair_algorithm, CertificateBuilder, KeyPairAlgorithm}; fn main() -> anyhow::Result<()> { let opts = options().run(); let ca = CertificateBuilder::new() - .signature_algorithm(&opts.keypair_algorithm)? + .signature_algorithm(opts.keypair_algorithm)? .certificate_authority() .country_name(&opts.country_name) .organization_name(&opts.organization_name) .build()?; let mut entity = CertificateBuilder::new() - .signature_algorithm(&opts.keypair_algorithm)? + .signature_algorithm(opts.keypair_algorithm)? .end_entity() .common_name(&opts.common_name) .subject_alternative_names(opts.san); @@ -48,12 +48,12 @@ struct Options { pub output: PathBuf, /// Keypair algorithm #[bpaf( - external(keypair_algorithm), - fallback(KeypairAlgorithm::EcdsaP256), + external(key_pair_algorithm), + fallback(KeyPairAlgorithm::EcdsaP256), display_fallback, group_help("Keypair Algorithm:") )] - pub keypair_algorithm: KeypairAlgorithm, + pub keypair_algorithm: KeyPairAlgorithm, /// Extended Key Usage Purpose: ClientAuth #[bpaf(long)] pub client_auth: bool,