Skip to content

Commit 3bd3067

Browse files
committed
Move CA parser functions to Issuer
1 parent adc5441 commit 3bd3067

File tree

4 files changed

+58
-35
lines changed

4 files changed

+58
-35
lines changed

rcgen/src/certificate.rs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1133,6 +1133,9 @@ pub enum BasicConstraints {
11331133

11341134
#[cfg(test)]
11351135
mod tests {
1136+
#[cfg(feature = "x509-parser")]
1137+
use pki_types::pem::PemObject;
1138+
11361139
#[cfg(feature = "pem")]
11371140
use super::*;
11381141
#[cfg(feature = "crypto")]
@@ -1290,7 +1293,7 @@ mod tests {
12901293
}
12911294
}
12921295

1293-
#[cfg(all(feature = "pem", feature = "x509-parser"))]
1296+
#[cfg(all(feature = "x509-parser"))]
12941297
mod test_key_identifier_from_ca {
12951298
use super::*;
12961299

@@ -1380,22 +1383,20 @@ JiY98T5oN1X0C/qAXxJfSvklbru9fipwGt3dho5Tm6Ee3cYf+plnk4WZhSnqyef4
13801383
PITGdT9dgN88nHPCle0B1+OY+OZ5
13811384
-----END PRIVATE KEY-----"#;
13821385

1383-
let params = CertificateParams::from_ca_cert_pem(ca_cert).unwrap();
1386+
let ca_kp = KeyPair::from_pem(ca_key).unwrap();
1387+
let ca = Issuer::from_ca_cert_pem(ca_cert, ca_kp).unwrap();
13841388
let ca_ski = vec![
13851389
0x97, 0xD4, 0x76, 0xA1, 0x9B, 0x1A, 0x71, 0x35, 0x2A, 0xC7, 0xF4, 0xA1, 0x84, 0x12,
13861390
0x56, 0x06, 0xBA, 0x5D, 0x61, 0x84,
13871391
];
13881392

13891393
assert_eq!(
1390-
KeyIdMethod::PreSpecified(ca_ski.clone()),
1391-
params.key_identifier_method
1394+
&KeyIdMethod::PreSpecified(ca_ski.clone()),
1395+
ca.key_identifier_method.as_ref()
13921396
);
13931397

1394-
let ca_kp = KeyPair::from_pem(ca_key).unwrap();
1395-
let ca_cert = params.self_signed(&ca_kp).unwrap();
1396-
assert_eq!(ca_ski, params.key_identifier(&ca_kp));
1397-
1398-
let (_, x509_ca) = x509_parser::parse_x509_certificate(ca_cert.der()).unwrap();
1398+
let ca_cert_der = CertificateDer::from_pem_slice(ca_cert.as_bytes()).unwrap();
1399+
let (_, x509_ca) = x509_parser::parse_x509_certificate(ca_cert_der.as_ref()).unwrap();
13991400
assert_eq!(
14001401
&ca_ski,
14011402
&x509_ca
@@ -1409,13 +1410,12 @@ PITGdT9dgN88nHPCle0B1+OY+OZ5
14091410
.unwrap()
14101411
);
14111412

1412-
let issuer = Issuer::new(params, ca_kp);
14131413
let ee_key = KeyPair::generate().unwrap();
14141414
let ee_params = CertificateParams {
14151415
use_authority_key_identifier_extension: true,
14161416
..CertificateParams::default()
14171417
};
1418-
let ee_cert = ee_params.signed_by(&ee_key, &issuer).unwrap();
1418+
let ee_cert = ee_params.signed_by(&ee_key, &ca).unwrap();
14191419

14201420
let (_, x509_ee) = x509_parser::parse_x509_certificate(ee_cert.der()).unwrap();
14211421
assert_eq!(

rcgen/src/lib.rs

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,8 @@ use std::net::IpAddr;
4141
use std::net::{Ipv4Addr, Ipv6Addr};
4242
use std::ops::Deref;
4343

44+
#[cfg(feature = "x509-parser")]
45+
use pki_types::CertificateDer;
4446
use time::{OffsetDateTime, Time};
4547
use yasna::models::ObjectIdentifier;
4648
use yasna::models::{GeneralizedTime, UTCTime};
@@ -165,6 +167,43 @@ impl<'a, S: SigningKey> Issuer<'a, S> {
165167
}
166168
}
167169

170+
/// Parses an existing CA certificate from the ASCII PEM format.
171+
///
172+
/// See [`from_ca_cert_der`](Self::from_ca_cert_der) for more details.
173+
#[cfg(all(feature = "pem", feature = "x509-parser"))]
174+
pub fn from_ca_cert_pem(pem_str: &str, signing_key: S) -> Result<Self, Error> {
175+
let certificate = pem::parse(pem_str).map_err(|_| Error::CouldNotParseCertificate)?;
176+
Self::from_ca_cert_der(&certificate.contents().into(), signing_key)
177+
}
178+
179+
/// Parses an existing CA certificate from the DER format.
180+
///
181+
/// This function assumes the provided certificate is a CA. It will not check
182+
/// for the presence of the `BasicConstraints` extension, or perform any other
183+
/// validation.
184+
///
185+
/// If you already have a byte slice containing DER, it can trivially be converted into
186+
/// [`CertificateDer`] using the [`Into`] trait.
187+
#[cfg(feature = "x509-parser")]
188+
pub fn from_ca_cert_der(ca_cert: &CertificateDer<'_>, signing_key: S) -> Result<Self, Error> {
189+
let (_remainder, x509) = x509_parser::parse_x509_certificate(ca_cert)
190+
.map_err(|_| Error::CouldNotParseCertificate)?;
191+
192+
Ok(Self {
193+
key_usages: Cow::Owned(KeyUsagePurpose::from_x509(&x509)?),
194+
key_identifier_method: Cow::Owned(KeyIdMethod::from_x509(&x509)?),
195+
distinguished_name: Cow::Owned(DistinguishedName::from_name(
196+
&x509.tbs_certificate.subject,
197+
)?),
198+
signing_key: MaybeOwned::Owned(signing_key),
199+
})
200+
}
201+
202+
/// Allowed key usages for this issuer.
203+
pub fn key_usages(&self) -> &[KeyUsagePurpose] {
204+
&self.key_usages
205+
}
206+
168207
/// Yield a reference to the signing key.
169208
pub fn key(&self) -> &S {
170209
&self.signing_key

rcgen/tests/botan.rs

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -154,10 +154,8 @@ fn test_botan_imported_ca() {
154154
let (mut params, ca_key) = default_params();
155155
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
156156
let ca_cert = params.self_signed(&ca_key).unwrap();
157-
158157
let ca_cert_der = ca_cert.der();
159-
160-
let imported_ca_cert_params = CertificateParams::from_ca_cert_der(ca_cert_der).unwrap();
158+
let ca = Issuer::from_ca_cert_der(ca_cert.der(), ca_key).unwrap();
161159

162160
let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]).unwrap();
163161
params
@@ -170,7 +168,6 @@ fn test_botan_imported_ca() {
170168
params.not_after = rcgen::date_time_ymd(3016, 1, 1);
171169

172170
let key_pair = KeyPair::generate().unwrap();
173-
let ca = Issuer::new(imported_ca_cert_params, ca_key);
174171
let cert = params.signed_by(&key_pair, &ca).unwrap();
175172
check_cert_ca(cert.der(), &cert, ca_cert_der);
176173
}
@@ -185,10 +182,7 @@ fn test_botan_imported_ca_with_printable_string() {
185182
);
186183
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
187184
let ca_cert = params.self_signed(&imported_ca_key).unwrap();
188-
189-
let ca_cert_der = ca_cert.der();
190-
191-
let imported_ca_cert_params = CertificateParams::from_ca_cert_der(ca_cert_der).unwrap();
185+
let ca = Issuer::from_ca_cert_der(ca_cert.der(), imported_ca_key).unwrap();
192186

193187
let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]).unwrap();
194188
params
@@ -200,10 +194,9 @@ fn test_botan_imported_ca_with_printable_string() {
200194
// Botan has a sanity check that enforces a maximum expiration date
201195
params.not_after = rcgen::date_time_ymd(3016, 1, 1);
202196
let key_pair = KeyPair::generate().unwrap();
203-
let ca = Issuer::new(imported_ca_cert_params, imported_ca_key);
204197
let cert = params.signed_by(&key_pair, &ca).unwrap();
205198

206-
check_cert_ca(cert.der(), &cert, ca_cert_der);
199+
check_cert_ca(cert.der(), &cert, ca_cert.der());
207200
}
208201

209202
#[test]

rcgen/tests/webpki.rs

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -420,13 +420,8 @@ fn test_webpki_imported_ca() {
420420
params.key_usages.push(KeyUsagePurpose::KeyCertSign);
421421
let ca_cert = params.self_signed(&ca_key).unwrap();
422422

423-
let ca_cert_der = ca_cert.der();
424-
425-
let imported_ca_cert_params = CertificateParams::from_ca_cert_der(ca_cert_der).unwrap();
426-
assert_eq!(
427-
imported_ca_cert_params.key_usages,
428-
vec![KeyUsagePurpose::KeyCertSign]
429-
);
423+
let ca = Issuer::from_ca_cert_der(ca_cert.der(), ca_key).unwrap();
424+
assert_eq!(ca.key_usages(), &[KeyUsagePurpose::KeyCertSign]);
430425

431426
let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]).unwrap();
432427
params
@@ -436,14 +431,13 @@ fn test_webpki_imported_ca() {
436431
.distinguished_name
437432
.push(DnType::CommonName, "Dev domain");
438433
let cert_key = KeyPair::generate().unwrap();
439-
let ca = Issuer::new(imported_ca_cert_params, ca_key);
440434
let cert = params.signed_by(&cert_key, &ca).unwrap();
441435

442436
let sign_fn = |cert, msg| sign_msg_ecdsa(cert, msg, &signature::ECDSA_P256_SHA256_ASN1_SIGNING);
443437
check_cert_ca(
444438
cert.der(),
445439
&cert_key,
446-
ca_cert_der,
440+
ca_cert.der(),
447441
webpki::ring::ECDSA_P256_SHA256,
448442
webpki::ring::ECDSA_P256_SHA256,
449443
sign_fn,
@@ -460,9 +454,7 @@ fn test_webpki_imported_ca_with_printable_string() {
460454
);
461455
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
462456
let ca_cert = params.self_signed(&ca_key).unwrap();
463-
464-
let ca_cert_der = ca_cert.der();
465-
let imported_ca_cert_params = CertificateParams::from_ca_cert_der(ca_cert_der).unwrap();
457+
let ca = Issuer::from_ca_cert_der(ca_cert.der(), ca_key).unwrap();
466458

467459
let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]).unwrap();
468460
params
@@ -472,14 +464,13 @@ fn test_webpki_imported_ca_with_printable_string() {
472464
.distinguished_name
473465
.push(DnType::CommonName, "Dev domain");
474466
let cert_key = KeyPair::generate().unwrap();
475-
let ca = Issuer::new(imported_ca_cert_params, ca_key);
476467
let cert = params.signed_by(&cert_key, &ca).unwrap();
477468

478469
let sign_fn = |cert, msg| sign_msg_ecdsa(cert, msg, &signature::ECDSA_P256_SHA256_ASN1_SIGNING);
479470
check_cert_ca(
480471
cert.der(),
481472
&cert_key,
482-
ca_cert_der,
473+
ca_cert.der(),
483474
webpki::ring::ECDSA_P256_SHA256,
484475
webpki::ring::ECDSA_P256_SHA256,
485476
sign_fn,

0 commit comments

Comments
 (0)