Skip to content

Commit

Permalink
Create Certificates via methods on CertificateParams
Browse files Browse the repository at this point in the history
  • Loading branch information
djc committed Mar 14, 2024
1 parent bfa6663 commit 89e13be
Show file tree
Hide file tree
Showing 12 changed files with 141 additions and 144 deletions.
4 changes: 2 additions & 2 deletions rcgen/examples/rsa-irc-openssl.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
fn main() -> Result<(), Box<dyn std::error::Error>> {
use rcgen::{date_time_ymd, Certificate, CertificateParams, DistinguishedName};
use rcgen::{date_time_ymd, CertificateParams, DistinguishedName};
use std::fmt::Write;
use std::fs;

Expand All @@ -12,7 +12,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let key_pair_pem = String::from_utf8(pkey.private_key_to_pem_pkcs8()?)?;
let key_pair = rcgen::KeyPair::from_pem(&key_pair_pem)?;

let cert = Certificate::generate_self_signed(params, &key_pair)?;
let cert = params.self_signed(&key_pair)?;
let pem_serialized = cert.pem();
let pem = pem::parse(&pem_serialized)?;
let der_serialized = pem.contents();
Expand Down
4 changes: 2 additions & 2 deletions rcgen/examples/rsa-irc.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
use rsa::pkcs8::EncodePrivateKey;
use rsa::RsaPrivateKey;

use rcgen::{date_time_ymd, Certificate, CertificateParams, DistinguishedName};
use rcgen::{date_time_ymd, CertificateParams, DistinguishedName};
use std::fmt::Write;
use std::fs;

Expand All @@ -18,7 +18,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
let private_key_der = private_key.to_pkcs8_der()?;
let key_pair = rcgen::KeyPair::try_from(private_key_der.as_bytes()).unwrap();

let cert = Certificate::generate_self_signed(params, &key_pair)?;
let cert = params.self_signed(&key_pair)?;
let pem_serialized = cert.pem();
let pem = pem::parse(&pem_serialized)?;
let der_serialized = pem.contents();
Expand Down
4 changes: 2 additions & 2 deletions rcgen/examples/sign-leaf-with-ca.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ fn new_ca() -> Certificate {
params.not_after = tomorrow;

let key_pair = KeyPair::generate().unwrap();
Certificate::generate_self_signed(params, &key_pair).unwrap()
params.self_signed(&key_pair).unwrap()
}

fn new_end_entity() -> Certificate {
Expand All @@ -53,7 +53,7 @@ fn new_end_entity() -> Certificate {
params.not_after = tomorrow;

let key_pair = KeyPair::generate().unwrap();
Certificate::generate_self_signed(params, &key_pair).unwrap()
params.self_signed(&key_pair).unwrap()
}

fn validity_period() -> (OffsetDateTime, OffsetDateTime) {
Expand Down
6 changes: 2 additions & 4 deletions rcgen/examples/simple.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
use rcgen::{
date_time_ymd, Certificate, CertificateParams, DistinguishedName, DnType, KeyPair, SanType,
};
use rcgen::{date_time_ymd, CertificateParams, DistinguishedName, DnType, KeyPair, SanType};
use std::fs;

fn main() -> Result<(), Box<dyn std::error::Error>> {
Expand All @@ -20,7 +18,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
];

let key_pair = KeyPair::generate()?;
let cert = Certificate::generate_self_signed(params, &key_pair)?;
let cert = params.self_signed(&key_pair)?;

let pem_serialized = cert.pem();
let pem = pem::parse(&pem_serialized)?;
Expand Down
100 changes: 48 additions & 52 deletions rcgen/src/certificate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,52 +27,6 @@ pub struct Certificate {
}

impl Certificate {
/// Generates a new self-signed certificate from the given parameters.
///
/// The returned [`Certificate`] may be serialized using [`Certificate::der`] and
/// [`Certificate::pem`].
pub fn generate_self_signed(
params: CertificateParams,
key_pair: &KeyPair,
) -> Result<Certificate, Error> {
let subject_public_key_info = key_pair.public_key_der();
let der =
params.serialize_der_with_signer(key_pair, key_pair, &params.distinguished_name)?;
Ok(Certificate {
params,
subject_public_key_info,
der,
})
}
/// Generate a new certificate from the given parameters, signed by the provided issuer.
///
/// 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`.
///
/// Note that no validation of the `issuer` certificate is performed. Rcgen will not require
/// 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`].
pub fn generate(
params: CertificateParams,
key_pair: &KeyPair,
issuer: &Certificate,
issuer_key: &KeyPair,
) -> Result<Certificate, Error> {
let subject_public_key_info = key_pair.public_key_der();
let der = params.serialize_der_with_signer(
key_pair,
issuer_key,
&issuer.params.distinguished_name,
)?;
Ok(Certificate {
params,
subject_public_key_info,
der,
})
}
/// Returns the certificate parameters
pub fn params(&self) -> &CertificateParams {
&self.params
Expand Down Expand Up @@ -214,6 +168,50 @@ impl CertificateParams {
})
}

/// Generate a new certificate from the given parameters, signed by the provided issuer.
///
/// 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`.
///
/// Note that no validation of the `issuer` certificate is performed. Rcgen will not require
/// 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`].
pub fn signed_by(
self,
key_pair: &KeyPair,
issuer: &Certificate,
issuer_key: &KeyPair,
) -> Result<Certificate, Error> {
let subject_public_key_info = key_pair.public_key_der();
let der = self.serialize_der_with_signer(
key_pair,
issuer_key,
&issuer.params.distinguished_name,
)?;
Ok(Certificate {
params: self,
subject_public_key_info,
der,
})
}

/// Generates a new self-signed certificate from the given parameters.
///
/// The returned [`Certificate`] may be serialized using [`Certificate::der`] and
/// [`Certificate::pem`].
pub fn self_signed(self, key_pair: &KeyPair) -> Result<Certificate, Error> {
let subject_public_key_info = key_pair.public_key_der();
let der = self.serialize_der_with_signer(key_pair, key_pair, &self.distinguished_name)?;
Ok(Certificate {
params: self,
subject_public_key_info,
der,
})
}

/// Parses an existing ca certificate from the ASCII PEM format.
///
/// See [`from_ca_cert_der`](Self::from_ca_cert_der) for more details.
Expand All @@ -228,7 +226,7 @@ impl CertificateParams {
/// 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 constructed [`CertificateParams`] and the [`KeyPair`]
/// associated with your existing `ca_cert` you can use [`Certificate::generate()`]
/// associated with your existing `ca_cert` you can use [`CertificateParams::signed_by()`]
/// or [`crate::CertificateSigningRequestParams::signed_by()`] to issue new certificates
/// using the CA cert.
///
Expand Down Expand Up @@ -1328,17 +1326,15 @@ mod tests {
#[cfg(windows)]
fn test_windows_line_endings() {
let key_pair = KeyPair::generate().unwrap();
let cert =
Certificate::generate_self_signed(CertificateParams::default(), &key_pair).unwrap();
let cert = CertificateParams::default().self_signed(&key_pair).unwrap();
assert!(cert.pem().contains("\r\n"));
}

#[test]
#[cfg(not(windows))]
fn test_not_windows_line_endings() {
let key_pair = KeyPair::generate().unwrap();
let cert =
Certificate::generate_self_signed(CertificateParams::default(), &key_pair).unwrap();
let cert = CertificateParams::default().self_signed(&key_pair).unwrap();
assert!(!cert.pem().contains('\r'));
}
}
Expand Down Expand Up @@ -1445,7 +1441,7 @@ PITGdT9dgN88nHPCle0B1+OY+OZ5
);

let kp = KeyPair::from_pem(ca_key).unwrap();
let ca_cert = Certificate::generate_self_signed(params, &kp).unwrap();
let ca_cert = params.self_signed(&kp).unwrap();
assert_eq!(&expected_ski, &ca_cert.key_identifier());

let (_remainder, x509) = x509_parser::parse_x509_certificate(ca_cert.der()).unwrap();
Expand Down
7 changes: 3 additions & 4 deletions rcgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ This crate provides a way to generate self signed X.509 certificates.
The most simple way of using this crate is by calling the
[`generate_simple_self_signed`] function.
For more customization abilities, we provide the lower level
[`Certificate::generate_self_signed`] and [`Certificate::generate`] functions.
For more customization abilities, construct a [`CertificateParams`] and
a key pair to call [`CertificateParams::signed_by()`] or [`CertificateParams::self_signed()`].
*/
#![cfg_attr(
feature = "pem",
Expand Down Expand Up @@ -124,8 +124,7 @@ pub fn generate_simple_self_signed(
subject_alt_names: impl Into<Vec<String>>,
) -> Result<CertifiedKey, Error> {
let key_pair = KeyPair::generate()?;
let cert =
Certificate::generate_self_signed(CertificateParams::new(subject_alt_names)?, &key_pair)?;
let cert = CertificateParams::new(subject_alt_names)?.self_signed(&key_pair)?;
Ok(CertifiedKey { cert, key_pair })
}

Expand Down
43 changes: 23 additions & 20 deletions rcgen/tests/botan.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ fn check_cert_ca(cert_der: &[u8], _cert: &Certificate, ca_der: &[u8]) {
#[test]
fn test_botan() {
let (params, key_pair) = default_params();
let cert = Certificate::generate_self_signed(params, &key_pair).unwrap();
let cert = params.self_signed(&key_pair).unwrap();

// Now verify the certificate.
check_cert(cert.der(), &cert);
Expand All @@ -60,7 +60,7 @@ fn test_botan() {
fn test_botan_256() {
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();
let cert = params.self_signed(&key_pair).unwrap();

// Now verify the certificate.
check_cert(cert.der(), &cert);
Expand All @@ -70,7 +70,7 @@ fn test_botan_256() {
fn test_botan_384() {
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();
let cert = params.self_signed(&key_pair).unwrap();

// Now verify the certificate.
check_cert(cert.der(), &cert);
Expand All @@ -80,7 +80,7 @@ fn test_botan_384() {
fn test_botan_25519() {
let (params, _) = default_params();
let key_pair = KeyPair::generate_for(&rcgen::PKCS_ED25519).unwrap();
let cert = Certificate::generate_self_signed(params, &key_pair).unwrap();
let cert = params.self_signed(&key_pair).unwrap();

// Now verify the certificate.
check_cert(cert.der(), &cert);
Expand All @@ -90,7 +90,7 @@ fn test_botan_25519() {
fn test_botan_25519_v1_given() {
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();
let cert = params.self_signed(&key_pair).unwrap();

// Now verify the certificate.
check_cert(cert.der(), &cert);
Expand All @@ -100,7 +100,7 @@ fn test_botan_25519_v1_given() {
fn test_botan_25519_v2_given() {
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();
let cert = params.self_signed(&key_pair).unwrap();

// Now verify the certificate.
check_cert(cert.der(), &cert);
Expand All @@ -110,7 +110,7 @@ fn test_botan_25519_v2_given() {
fn test_botan_rsa_given() {
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();
let cert = params.self_signed(&key_pair).unwrap();

// Now verify the certificate.
check_cert(cert.der(), &cert);
Expand All @@ -120,7 +120,7 @@ fn test_botan_rsa_given() {
fn test_botan_separate_ca() {
let (mut params, ca_key) = default_params();
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
let ca_cert = Certificate::generate_self_signed(params, &ca_key).unwrap();
let ca_cert = params.self_signed(&ca_key).unwrap();

let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]).unwrap();
params
Expand All @@ -133,7 +133,7 @@ fn test_botan_separate_ca() {
params.not_after = rcgen::date_time_ymd(3016, 1, 1);

let key_pair = KeyPair::generate().unwrap();
let cert = Certificate::generate(params, &key_pair, &ca_cert, &ca_key).unwrap();
let cert = params.signed_by(&key_pair, &ca_cert, &ca_key).unwrap();
check_cert_ca(cert.der(), &cert, ca_cert.der());
}

Expand All @@ -142,13 +142,12 @@ fn test_botan_separate_ca() {
fn test_botan_imported_ca() {
let (mut params, ca_key) = default_params();
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
let ca_cert = Certificate::generate_self_signed(params, &ca_key).unwrap();
let ca_cert = params.self_signed(&ca_key).unwrap();

let ca_cert_der = ca_cert.der();

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 imported_ca_cert = imported_ca_cert_params.self_signed(&ca_key).unwrap();

let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]).unwrap();
params
Expand All @@ -161,7 +160,9 @@ fn test_botan_imported_ca() {
params.not_after = rcgen::date_time_ymd(3016, 1, 1);

let key_pair = KeyPair::generate().unwrap();
let cert = Certificate::generate(params, &key_pair, &imported_ca_cert, &ca_key).unwrap();
let cert = params
.signed_by(&key_pair, &imported_ca_cert, &ca_key)
.unwrap();
check_cert_ca(cert.der(), &cert, ca_cert_der);
}

Expand All @@ -174,13 +175,14 @@ fn test_botan_imported_ca_with_printable_string() {
DnValue::PrintableString("US".try_into().unwrap()),
);
params.is_ca = IsCa::Ca(BasicConstraints::Unconstrained);
let ca_cert = Certificate::generate_self_signed(params, &imported_ca_key).unwrap();
let ca_cert = params.self_signed(&imported_ca_key).unwrap();

let ca_cert_der = ca_cert.der();

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 imported_ca_cert = imported_ca_cert_params
.self_signed(&imported_ca_key)
.unwrap();

let mut params = CertificateParams::new(vec!["crabs.crabs".to_string()]).unwrap();
params
Expand All @@ -192,8 +194,9 @@ fn test_botan_imported_ca_with_printable_string() {
// Botan has a sanity check that enforces a maximum expiration date
params.not_after = rcgen::date_time_ymd(3016, 1, 1);
let key_pair = KeyPair::generate().unwrap();
let cert =
Certificate::generate(params, &key_pair, &imported_ca_cert, &imported_ca_key).unwrap();
let cert = params
.signed_by(&key_pair, &imported_ca_cert, &imported_ca_key)
.unwrap();

check_cert_ca(cert.der(), &cert, ca_cert_der);
}
Expand All @@ -210,7 +213,7 @@ fn test_botan_crl_parse() {
KeyUsagePurpose::CrlSign,
];
let issuer_key = KeyPair::generate_for(alg).unwrap();
let issuer = Certificate::generate_self_signed(issuer, &issuer_key).unwrap();
let issuer = issuer.self_signed(&issuer_key).unwrap();

// Create an end entity cert issued by the issuer.
let (mut ee, _) = util::default_params();
Expand All @@ -219,7 +222,7 @@ fn test_botan_crl_parse() {
// Botan has a sanity check that enforces a maximum expiration date
ee.not_after = rcgen::date_time_ymd(3016, 1, 1);
let ee_key = KeyPair::generate_for(alg).unwrap();
let ee = Certificate::generate(ee, &ee_key, &issuer, &issuer_key).unwrap();
let ee = ee.signed_by(&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.
Expand Down
Loading

0 comments on commit 89e13be

Please sign in to comment.