diff --git a/Cargo.lock b/Cargo.lock index 0b734ca2..3ce5dce4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1005,14 +1005,14 @@ dependencies = [ "rand", "rcgen", "ring 0.17.7", + "rustls-pki-types", "x509-parser", ] [[package]] name = "rustls-pki-types" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e9d979b3ce68192e42760c7810125eb6cf2ea10efae545a156063e61f314e2a" +version = "1.2.0" +source = "git+https://github.com/Tudyx/pki-types.git?branch=add_CertificateSigningRequestDer_type#2d25f6190b839990a04d884d84b1fc5531d5fd5a" [[package]] name = "rustls-webpki" diff --git a/Cargo.toml b/Cargo.toml index 43641bee..b931f561 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ resolver = "2" [workspace.dependencies] pem = "3.0.2" +pki-types = { package = "rustls-pki-types", version = "1" } rand = "0.8" ring = "0.17" x509-parser = "0.15.1" @@ -21,3 +22,6 @@ keywords = ["mkcert", "ca", "certificate"] # ignores profile overrides for non leaf packages) [profile.dev.package.num-bigint-dig] opt-level = 3 + +[patch.crates-io] +pki-types = { package = "rustls-pki-types", git = "https://github.com/Tudyx/pki-types.git", branch = "add_CertificateSigningRequestDer_type" } diff --git a/rcgen/Cargo.toml b/rcgen/Cargo.toml index c237bc7b..9254225d 100644 --- a/rcgen/Cargo.toml +++ b/rcgen/Cargo.toml @@ -33,6 +33,7 @@ pem = { workspace = true, optional = true } time = { version = "0.3.6", default-features = false } x509-parser = { workspace = true, features = ["verify"], optional = true } zeroize = { version = "1.2", optional = true } +pki-types = { workspace = true } [features] default = ["crypto", "pem", "ring"] @@ -40,19 +41,18 @@ crypto = [] aws_lc_rs = ["crypto", "dep:aws-lc-rs"] ring = ["crypto", "dep:ring"] - [package.metadata.docs.rs] features = ["x509-parser"] [package.metadata.cargo_check_external_types] allowed_external_types = [ "time::offset_date_time::OffsetDateTime", - "zeroize::Zeroize" + "zeroize::Zeroize", + "rustls_pki_types::*" ] [dev-dependencies] openssl = "0.10" -pki-types = { package = "rustls-pki-types", version = "1" } x509-parser = { workspace = true, features = ["verify"] } rustls-webpki = { version = "0.102", features = ["std"] } botan = { version = "0.10", features = ["vendored"] } diff --git a/rcgen/examples/rsa-irc.rs b/rcgen/examples/rsa-irc.rs index 3c38962b..1399267d 100644 --- a/rcgen/examples/rsa-irc.rs +++ b/rcgen/examples/rsa-irc.rs @@ -16,7 +16,9 @@ fn main() -> Result<(), Box> { 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(); + let key_pair = rcgen::KeyPair::from_der(pki_types::PrivatePkcs8KeyDer::from( + private_key_der.as_bytes(), + ))?; let cert = Certificate::generate_self_signed(params, &key_pair)?; let pem_serialized = cert.pem(); diff --git a/rcgen/src/csr.rs b/rcgen/src/csr.rs index 3b4ae040..b23d0ce0 100644 --- a/rcgen/src/csr.rs +++ b/rcgen/src/csr.rs @@ -1,5 +1,7 @@ #[cfg(feature = "x509-parser")] use crate::{DistinguishedName, Error, SanType}; +#[cfg(feature = "x509-parser")] +use pki_types::CertificateSigningRequestDer; use std::hash::Hash; use crate::{CertificateParams, PublicKeyData, SignatureAlgorithm}; @@ -36,7 +38,7 @@ impl CertificateSigningRequestParams { #[cfg(all(feature = "pem", feature = "x509-parser"))] pub fn from_pem(pem_str: &str) -> Result { let csr = pem::parse(pem_str).or(Err(Error::CouldNotParseCertificationRequest))?; - Self::from_der(csr.contents()) + Self::from_der(&csr.contents().into()) } /// Parse a certificate signing request from DER-encoded bytes @@ -44,9 +46,9 @@ impl CertificateSigningRequestParams { /// Currently, this only supports the `Subject Alternative Name` extension. /// On encountering other extensions, this function will return an error. #[cfg(feature = "x509-parser")] - pub fn from_der(csr: &[u8]) -> Result { + pub fn from_der(csr: &CertificateSigningRequestDer<'_>) -> Result { use x509_parser::prelude::FromDer; - let csr = x509_parser::certification_request::X509CertificationRequest::from_der(csr) + let csr = x509_parser::certification_request::X509CertificationRequest::from_der(&csr) .map_err(|_| Error::CouldNotParseCertificationRequest)? .1; csr.verify_signature().map_err(|_| Error::RingUnspecified)?; diff --git a/rcgen/src/key_pair.rs b/rcgen/src/key_pair.rs index 84d5d0aa..ec2283fa 100644 --- a/rcgen/src/key_pair.rs +++ b/rcgen/src/key_pair.rs @@ -1,6 +1,8 @@ #[cfg(feature = "pem")] use pem::Pem; #[cfg(feature = "crypto")] +use pki_types::PrivatePkcs8KeyDer; +#[cfg(feature = "crypto")] use std::convert::TryFrom; use std::fmt; use yasna::DERWriter; @@ -116,8 +118,8 @@ impl KeyPair { /// /// Equivalent to using the [`TryFrom`] implementation. #[cfg(feature = "crypto")] - pub fn from_der(der: &[u8]) -> Result { - Ok(der.try_into()?) + pub fn from_der<'a>(der: impl Into>) -> Result { + der.into().try_into() } /// Returns the key pair's signature algorithm @@ -126,11 +128,13 @@ impl KeyPair { } /// Parses the key pair from the ASCII PEM format + /// + /// The key must be in the PKCS#8 format. #[cfg(all(feature = "pem", feature = "crypto"))] pub fn from_pem(pem_str: &str) -> Result { let private_key = pem::parse(pem_str)._err()?; let private_key_der: &[_] = private_key.contents(); - Ok(private_key_der.try_into()?) + Self::from_der(PrivatePkcs8KeyDer::from(private_key_der)) } /// Obtains the key pair from a raw public key and a remote private key @@ -145,6 +149,7 @@ impl KeyPair { /// Obtains the key pair from a DER formatted key /// using the specified [`SignatureAlgorithm`] /// + /// The key must be in the PKCS#8 format. /// Same as [from_pem_and_sign_algo](Self::from_pem_and_sign_algo). #[cfg(all(feature = "pem", feature = "crypto"))] pub fn from_pem_and_sign_algo( @@ -153,7 +158,10 @@ impl KeyPair { ) -> Result { let private_key = pem::parse(pem_str)._err()?; let private_key_der: &[_] = private_key.contents(); - Ok(Self::from_der_and_sign_algo(private_key_der, alg)?) + Ok(Self::from_der_and_sign_algo( + PrivatePkcs8KeyDer::from(private_key_der), + alg, + )?) } /// Obtains the key pair from a DER formatted key @@ -166,38 +174,37 @@ impl KeyPair { /// same der key. In that instance, you can use this function to precisely /// specify the `SignatureAlgorithm`. #[cfg(feature = "crypto")] - pub fn from_der_and_sign_algo( - pkcs8: &[u8], + pub fn from_der_and_sign_algo<'a>( + der: impl Into>, alg: &'static SignatureAlgorithm, ) -> Result { let rng = &SystemRandom::new(); - let pkcs8_vec = pkcs8.to_vec(); - + let serialized_der = der.into().secret_pkcs8_der().to_vec(); let kind = if alg == &PKCS_ED25519 { - KeyPairKind::Ed(Ed25519KeyPair::from_pkcs8_maybe_unchecked(pkcs8)._err()?) + KeyPairKind::Ed(Ed25519KeyPair::from_pkcs8_maybe_unchecked(&serialized_der)._err()?) } else if alg == &PKCS_ECDSA_P256_SHA256 { KeyPairKind::Ec(ecdsa_from_pkcs8( &signature::ECDSA_P256_SHA256_ASN1_SIGNING, - pkcs8, + &serialized_der, rng, )?) } else if alg == &PKCS_ECDSA_P384_SHA384 { KeyPairKind::Ec(ecdsa_from_pkcs8( &signature::ECDSA_P384_SHA384_ASN1_SIGNING, - pkcs8, + &serialized_der, rng, )?) } else if alg == &PKCS_RSA_SHA256 { - let rsakp = RsaKeyPair::from_pkcs8(pkcs8)._err()?; + let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?; KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA256) } else if alg == &PKCS_RSA_SHA384 { - let rsakp = RsaKeyPair::from_pkcs8(pkcs8)._err()?; + let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?; KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA384) } else if alg == &PKCS_RSA_SHA512 { - let rsakp = RsaKeyPair::from_pkcs8(pkcs8)._err()?; + let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?; KeyPairKind::Rsa(rsakp, &signature::RSA_PKCS1_SHA512) } else if alg == &PKCS_RSA_PSS_SHA256 { - let rsakp = RsaKeyPair::from_pkcs8(pkcs8)._err()?; + let rsakp = RsaKeyPair::from_pkcs8(&serialized_der)._err()?; KeyPairKind::Rsa(rsakp, &signature::RSA_PSS_SHA256) } else { panic!("Unknown SignatureAlgorithm specified!"); @@ -206,14 +213,15 @@ impl KeyPair { Ok(KeyPair { kind, alg, - serialized_der: pkcs8_vec, + serialized_der, }) } #[cfg(feature = "crypto")] pub(crate) fn from_raw( - pkcs8: &[u8], + pkcs8: &PrivatePkcs8KeyDer, ) -> Result<(KeyPairKind, &'static SignatureAlgorithm), Error> { + let pkcs8 = pkcs8.secret_pkcs8_der(); let rng = SystemRandom::new(); let (kind, alg) = if let Ok(edkp) = Ed25519KeyPair::from_pkcs8_maybe_unchecked(pkcs8) { (KeyPairKind::Ed(edkp), &PKCS_ED25519) @@ -352,29 +360,15 @@ impl KeyPair { } #[cfg(feature = "crypto")] -impl TryFrom<&[u8]> for KeyPair { - type Error = Error; - - fn try_from(pkcs8: &[u8]) -> Result { - let (kind, alg) = KeyPair::from_raw(pkcs8)?; - Ok(KeyPair { - kind, - alg, - serialized_der: pkcs8.to_vec(), - }) - } -} - -#[cfg(feature = "crypto")] -impl TryFrom> for KeyPair { +impl TryFrom> for KeyPair { type Error = Error; - fn try_from(pkcs8: Vec) -> Result { - let (kind, alg) = KeyPair::from_raw(pkcs8.as_slice())?; + fn try_from(private_key: PrivatePkcs8KeyDer<'_>) -> Result { + let (kind, alg) = KeyPair::from_raw(&private_key)?; Ok(KeyPair { kind, alg, - serialized_der: pkcs8, + serialized_der: private_key.secret_pkcs8_der().into(), }) } } diff --git a/rcgen/src/lib.rs b/rcgen/src/lib.rs index 8a6295fd..d5a3cca8 100644 --- a/rcgen/src/lib.rs +++ b/rcgen/src/lib.rs @@ -35,6 +35,7 @@ println!("{}", key_pair.serialize_pem()); #[cfg(feature = "pem")] use pem::Pem; +use pki_types::{CertificateDer, CertificateSigningRequestDer}; #[cfg(feature = "crypto")] use ring_like::digest; use std::collections::HashMap; @@ -83,7 +84,7 @@ pub struct CertifiedKey { pub struct Certificate { params: CertificateParams, subject_public_key_info: Vec, - der: Vec, + der: CertificateDer<'static>, } /** @@ -664,7 +665,7 @@ impl CertificateParams { #[cfg(all(feature = "pem", feature = "x509-parser"))] 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()) + Self::from_ca_cert_der(&certificate.contents().into()) } /// Parses an existing ca certificate from the DER format. @@ -682,8 +683,8 @@ 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]) -> Result { - let (_remainder, x509) = x509_parser::parse_x509_certificate(ca_cert) + pub fn from_ca_cert_der(ca_cert: &CertificateDer<'_>) -> Result { + let (_remainder, x509) = x509_parser::parse_x509_certificate(&ca_cert) .or(Err(Error::CouldNotParseCertificate))?; let dn = DistinguishedName::from_name(&x509.tbs_certificate.subject)?; @@ -1252,7 +1253,7 @@ impl CertificateParams { pub_key: &K, issuer: &KeyPair, issuer_name: &DistinguishedName, - ) -> Result, Error> { + ) -> Result, Error> { yasna::try_construct_der(|writer| { writer.write_sequence(|writer| { let tbs_cert_list_serialized = yasna::try_construct_der(|writer| { @@ -1271,6 +1272,7 @@ impl CertificateParams { Ok(()) }) }) + .map(CertificateDer::from) } } @@ -1692,13 +1694,13 @@ impl Certificate { .derive(&self.subject_public_key_info) } /// Get the certificate in DER encoded format. - pub fn der(&self) -> &[u8] { + pub fn der(&self) -> &CertificateDer<'_> { &self.der } /// Get the certificate in PEM encoded format. #[cfg(feature = "pem")] pub fn pem(&self) -> String { - pem::encode_config(&Pem::new("CERTIFICATE", self.der()), ENCODE_CONFIG) + pem::encode_config(&Pem::new("CERTIFICATE", self.der().to_vec()), ENCODE_CONFIG) } /// Generate and serialize a certificate signing request (CSR) in binary DER format. /// @@ -1710,7 +1712,10 @@ impl Certificate { /// should not call `serialize_request_der` and then `serialize_request_pem`. This will /// result in two different CSRs. Instead call only `serialize_request_pem` and base64 /// decode the inner content to get the DER encoded CSR using a library like `pem`. - pub fn serialize_request_der(&self, subject_key: &KeyPair) -> Result, Error> { + pub fn serialize_request_der( + &self, + subject_key: &KeyPair, + ) -> Result, Error> { yasna::try_construct_der(|writer| { writer.write_sequence(|writer| { let cert_data = yasna::try_construct_der(|writer| { @@ -1727,6 +1732,7 @@ impl Certificate { Ok(()) }) }) + .map(CertificateSigningRequestDer::from) } /// Generate and serialize a certificate signing request (CSR) in binary DER format. /// @@ -1741,7 +1747,7 @@ impl Certificate { #[cfg(feature = "pem")] pub fn serialize_request_pem(&self, subject_key: &KeyPair) -> Result { let contents = self.serialize_request_der(subject_key)?; - let p = Pem::new("CERTIFICATE REQUEST", contents); + let p = Pem::new("CERTIFICATE REQUEST", contents.to_vec()); Ok(pem::encode_config(&p, ENCODE_CONFIG)) } } diff --git a/rcgen/tests/botan.rs b/rcgen/tests/botan.rs index 9d1b9b0a..430eaf3b 100644 --- a/rcgen/tests/botan.rs +++ b/rcgen/tests/botan.rs @@ -1,5 +1,6 @@ #![cfg(all(feature = "crypto", feature = "x509-parser"))] +use pki_types::CertificateDer; use rcgen::{BasicConstraints, Certificate, CertificateParams, DnType, IsCa}; use rcgen::{ CertificateRevocationList, CertificateRevocationListParams, RevocationReason, RevokedCertParams, @@ -17,12 +18,12 @@ fn default_params() -> (CertificateParams, KeyPair) { (params, key_pair) } -fn check_cert(cert_der: &[u8], cert: &Certificate) { +fn check_cert(cert_der: &CertificateDer<'_>, cert: &Certificate) { println!("{}", cert.pem()); check_cert_ca(cert_der, cert, cert_der); } -fn check_cert_ca(cert_der: &[u8], _cert: &Certificate, ca_der: &[u8]) { +fn check_cert_ca(cert_der: &CertificateDer<'_>, _cert: &Certificate, ca_der: &CertificateDer<'_>) { println!( "botan version: {}", botan::Version::current().unwrap().string diff --git a/rcgen/tests/webpki.rs b/rcgen/tests/webpki.rs index 9588c55c..4d2e766d 100644 --- a/rcgen/tests/webpki.rs +++ b/rcgen/tests/webpki.rs @@ -54,7 +54,7 @@ fn sign_msg_rsa(key_pair: &KeyPair, msg: &[u8], encoding: &'static dyn RsaEncodi } fn check_cert<'a, 'b>( - cert_der: &[u8], + cert_der: &CertificateDer<'_>, cert: &'a Certificate, cert_key: &'a KeyPair, alg: &dyn SignatureVerificationAlgorithm, @@ -68,18 +68,16 @@ fn check_cert<'a, 'b>( } fn check_cert_ca<'a, 'b>( - cert_der: &[u8], + cert_der: &CertificateDer<'_>, cert_key: &'a KeyPair, - ca_der: &[u8], + ca_der: &CertificateDer<'_>, cert_alg: &dyn SignatureVerificationAlgorithm, ca_alg: &dyn SignatureVerificationAlgorithm, sign_fn: impl FnOnce(&'a KeyPair, &'b [u8]) -> Vec, ) { - let ca_der = CertificateDer::from(ca_der); - let trust_anchor = anchor_from_trusted_cert(&ca_der).unwrap(); + let trust_anchor = anchor_from_trusted_cert(ca_der).unwrap(); let trust_anchor_list = &[trust_anchor]; - let cert_der = CertificateDer::from(cert_der); - let end_entity_cert = EndEntityCert::try_from(&cert_der).unwrap(); + let end_entity_cert = EndEntityCert::try_from(cert_der).unwrap(); // Set time to Jan 10, 2004 let time = UnixTime::since_unix_epoch(StdDuration::from_secs(0x40_00_00_00)); @@ -590,11 +588,9 @@ fn test_webpki_crl_revoke() { let ee = Certificate::generate(ee, &ee_key, &issuer, &issuer_key).unwrap(); // Set up webpki's verification requirements. - let ca_der = CertificateDer::from(issuer.der()); - let trust_anchor = anchor_from_trusted_cert(&ca_der).unwrap(); + let trust_anchor = anchor_from_trusted_cert(issuer.der()).unwrap(); let trust_anchor_list = &[trust_anchor]; - let ee_der = CertificateDer::from(ee.der()); - let end_entity_cert = EndEntityCert::try_from(&ee_der).unwrap(); + let end_entity_cert = EndEntityCert::try_from(ee.der()).unwrap(); let unix_time = 0x40_00_00_00; let time = UnixTime::since_unix_epoch(StdDuration::from_secs(unix_time)); diff --git a/rustls-cert-gen/Cargo.toml b/rustls-cert-gen/Cargo.toml index ba29e89b..241fee1e 100644 --- a/rustls-cert-gen/Cargo.toml +++ b/rustls-cert-gen/Cargo.toml @@ -12,6 +12,7 @@ bpaf = { version = "0.9.5", features = ["derive"] } pem = { workspace = true } ring = { workspace = true } rand = { workspace = true } +pki-types = { workspace = true } anyhow = "1.0.75" [dev-dependencies] diff --git a/rustls-cert-gen/src/cert.rs b/rustls-cert-gen/src/cert.rs index a1251433..cb9fceb2 100644 --- a/rustls-cert-gen/src/cert.rs +++ b/rustls-cert-gen/src/cert.rs @@ -1,4 +1,5 @@ use bpaf::Bpaf; +use pki_types::PrivatePkcs8KeyDer; use rcgen::{ BasicConstraints, Certificate, CertificateParams, DistinguishedName, DnType, DnValue::PrintableString, ExtendedKeyUsagePurpose, IsCa, KeyPair, KeyUsagePurpose, SanType, @@ -232,8 +233,10 @@ impl KeyPairAlgorithm { let alg = &rcgen::PKCS_ED25519; let pkcs8_bytes = Ed25519KeyPair::generate_pkcs8(&rng).or(Err(rcgen::Error::RingUnspecified))?; - - rcgen::KeyPair::from_der_and_sign_algo(pkcs8_bytes.as_ref(), alg) + rcgen::KeyPair::from_der_and_sign_algo( + PrivatePkcs8KeyDer::from(pkcs8_bytes.as_ref()), + alg, + ) }, KeyPairAlgorithm::EcdsaP256 => { use ring::signature::EcdsaKeyPair; @@ -244,7 +247,10 @@ impl KeyPairAlgorithm { let pkcs8_bytes = EcdsaKeyPair::generate_pkcs8(&ECDSA_P256_SHA256_ASN1_SIGNING, &rng) .or(Err(rcgen::Error::RingUnspecified))?; - rcgen::KeyPair::from_der_and_sign_algo(pkcs8_bytes.as_ref(), alg) + rcgen::KeyPair::from_der_and_sign_algo( + PrivatePkcs8KeyDer::from(pkcs8_bytes.as_ref()), + alg, + ) }, KeyPairAlgorithm::EcdsaP384 => { use ring::signature::EcdsaKeyPair; @@ -256,7 +262,10 @@ impl KeyPairAlgorithm { EcdsaKeyPair::generate_pkcs8(&ECDSA_P384_SHA384_ASN1_SIGNING, &rng) .or(Err(rcgen::Error::RingUnspecified))?; - rcgen::KeyPair::from_der_and_sign_algo(pkcs8_bytes.as_ref(), alg) + rcgen::KeyPair::from_der_and_sign_algo( + PrivatePkcs8KeyDer::from(pkcs8_bytes.as_ref()), + alg, + ) }, } }