Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Issuer API #275

Draft
wants to merge 5 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 11 additions & 20 deletions rcgen/src/certificate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,23 @@ impl Certificate {
pub fn params(&self) -> &CertificateParams {
&self.params
}

/// Calculates a subject key identifier for the certificate subject's public key.
/// This key identifier is used in the SubjectKeyIdentifier X.509v3 extension.
pub fn key_identifier(&self) -> Vec<u8> {
self.params
.key_identifier_method
.derive(&self.subject_public_key_info)
}

/// Get the certificate in DER encoded format.
///
/// [`CertificateDer`] implements `Deref<Target = [u8]>` and `AsRef<[u8]>`, so you can easily
/// extract the DER bytes from the return value.
pub fn der(&self) -> &CertificateDer<'static> {
&self.der
}

/// Get the certificate in PEM encoded format.
#[cfg(feature = "pem")]
pub fn pem(&self) -> String {
Expand Down Expand Up @@ -147,19 +150,7 @@ impl CertificateParams {
///
/// 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 issuer = Issuer {
distinguished_name: &issuer.params.distinguished_name,
key_identifier_method: &issuer.params.key_identifier_method,
key_usages: &issuer.params.key_usages,
key_pair: issuer_key,
};

pub fn signed_by(self, key_pair: &KeyPair, issuer: &Issuer) -> Result<Certificate, Error> {
let subject_public_key_info = key_pair.public_key_der();
let der = self.serialize_der_with_signer(key_pair, issuer)?;
Ok(Certificate {
Expand All @@ -175,14 +166,14 @@ impl CertificateParams {
/// [`Certificate::pem`].
pub fn self_signed(self, key_pair: &KeyPair) -> Result<Certificate, Error> {
let issuer = Issuer {
distinguished_name: &self.distinguished_name,
key_identifier_method: &self.key_identifier_method,
key_usages: &self.key_usages,
key_pair,
distinguished_name: self.distinguished_name,
key_identifier_method: self.key_identifier_method,
key_usages: self.key_usages,
key_pair: todo!(), // TODO: Do we `KeyPair::Clone` or do we make this field a `Cow`?
};

let subject_public_key_info = key_pair.public_key_der();
let der = self.serialize_der_with_signer(key_pair, issuer)?;
let der = self.serialize_der_with_signer(key_pair, &issuer)?;
Ok(Certificate {
params: self,
subject_public_key_info,
Expand Down Expand Up @@ -597,7 +588,7 @@ impl CertificateParams {
pub(crate) fn serialize_der_with_signer<K: PublicKeyData>(
&self,
pub_key: &K,
issuer: Issuer<'_>,
issuer: &Issuer,
) -> Result<CertificateDer<'static>, Error> {
let der = issuer.key_pair.sign_der(|writer| {
let pub_key_spki =
Expand Down Expand Up @@ -656,7 +647,7 @@ impl CertificateParams {
if self.use_authority_key_identifier_extension {
write_x509_authority_key_identifier(
writer.next(),
match issuer.key_identifier_method {
match &issuer.key_identifier_method {
KeyIdMethod::PreSpecified(aki) => aki.clone(),
#[cfg(feature = "crypto")]
_ => issuer
Expand Down
15 changes: 2 additions & 13 deletions rcgen/src/crl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -186,22 +186,11 @@ impl CertificateRevocationListParams {
/// Serializes the certificate revocation list (CRL).
///
/// Including a signature from the issuing certificate authority's key.
pub fn signed_by(
self,
issuer: &Certificate,
issuer_key: &KeyPair,
) -> Result<CertificateRevocationList, Error> {
pub fn signed_by(self, issuer: &Issuer) -> Result<CertificateRevocationList, Error> {
if self.next_update.le(&self.this_update) {
return Err(Error::InvalidCrlNextUpdate);
}

let issuer = Issuer {
distinguished_name: &issuer.params.distinguished_name,
key_identifier_method: &issuer.params.key_identifier_method,
key_usages: &issuer.params.key_usages,
key_pair: issuer_key,
};

if !issuer.key_usages.is_empty() && !issuer.key_usages.contains(&KeyUsagePurpose::CrlSign) {
return Err(Error::IssuerNotCrlSigner);
}
Expand All @@ -212,7 +201,7 @@ impl CertificateRevocationListParams {
})
}

fn serialize_der(&self, issuer: Issuer) -> Result<Vec<u8>, Error> {
fn serialize_der(&self, issuer: &Issuer) -> Result<Vec<u8>, Error> {
issuer.key_pair.sign_der(|writer| {
// Write CRL version.
// RFC 5280 §5.1.2.1:
Expand Down
15 changes: 2 additions & 13 deletions rcgen/src/csr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -184,21 +184,10 @@ impl CertificateSigningRequestParams {
///
/// The returned [`Certificate`] may be serialized using [`Certificate::der`] and
/// [`Certificate::pem`].
pub fn signed_by(
self,
issuer: &Certificate,
issuer_key: &KeyPair,
) -> Result<Certificate, Error> {
let issuer = Issuer {
distinguished_name: &issuer.params.distinguished_name,
key_identifier_method: &issuer.params.key_identifier_method,
key_usages: &issuer.params.key_usages,
key_pair: issuer_key,
};

pub fn signed_by(self, issuer: &Issuer) -> Result<Certificate, Error> {
let der = self
.params
.serialize_der_with_signer(&self.public_key, issuer)?;
.serialize_der_with_signer(&self.public_key, &issuer)?;
let subject_public_key_info = yasna::construct_der(|writer| {
self.public_key.serialize_public_key_der(writer);
});
Expand Down
62 changes: 62 additions & 0 deletions rcgen/src/issuer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use pki_types::CertificateDer;

use crate::{
Certificate, CertificateParams, DistinguishedName, Error, KeyIdMethod, KeyPair, KeyUsagePurpose,
};

/// TODO
pub struct Issuer {
pub(crate) distinguished_name: DistinguishedName,
pub(crate) key_identifier_method: KeyIdMethod,
pub(crate) key_usages: Vec<KeyUsagePurpose>,
pub(crate) key_pair: KeyPair,
}

impl Issuer {
/// TODO
pub fn new(ca_cert: CertificateDer, key_pair: KeyPair) -> Result<Self, Error> {
let params = CertificateParams::from_ca_cert_der(&ca_cert)?;
Ok(Self {
distinguished_name: params.distinguished_name,
key_identifier_method: params.key_identifier_method,
key_usages: params.key_usages,
key_pair,
})
}

/// TODO
pub fn from_params(params: CertificateParams, key_pair: KeyPair) -> Self {
Self {
distinguished_name: params.distinguished_name,
key_identifier_method: params.key_identifier_method,
key_usages: params.key_usages,
key_pair,
}
}

/// TODO
pub fn certificate(&self) -> Certificate {
// let params = CertificateParams::from_ca_cert_der(&der)?;
// Ok(Certificate {
// params,
// subject_public_key_info: keypair.public_key_der(),
// der,
// })
todo!();
}

/// TODO
pub fn cert_pem(&self) -> String {
todo!("required for `rustls-cert-gen`");
}

/// TODO
pub fn key_pem(&self) -> String {
todo!("seems a fitting complement to `Self::cert_pem`");
}

/// TODO
pub fn key_pair(&self) -> &KeyPair {
&self.key_pair
}
}
9 changes: 2 additions & 7 deletions rcgen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ pub use crl::{
};
pub use csr::{CertificateSigningRequest, CertificateSigningRequestParams, PublicKey};
pub use error::{Error, InvalidAsn1String};
pub use issuer::Issuer;
use key_pair::PublicKeyData;
#[cfg(all(feature = "crypto", feature = "aws_lc_rs"))]
pub use key_pair::RsaKeySize;
Expand All @@ -72,6 +73,7 @@ mod certificate;
mod crl;
mod csr;
mod error;
mod issuer;
mod key_pair;
mod oid;
mod ring_like;
Expand Down Expand Up @@ -130,13 +132,6 @@ pub fn generate_simple_self_signed(
Ok(CertifiedKey { cert, key_pair })
}

struct Issuer<'a> {
distinguished_name: &'a DistinguishedName,
key_identifier_method: &'a KeyIdMethod,
key_usages: &'a [KeyUsagePurpose],
key_pair: &'a KeyPair,
}

// https://tools.ietf.org/html/rfc5280#section-4.1.1

// Example certs usable as reference:
Expand Down
25 changes: 10 additions & 15 deletions rustls-cert-gen/src/cert.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,8 @@ use std::{fmt, fs::File, io, path::Path};
use bpaf::Bpaf;
use rcgen::{
BasicConstraints, Certificate, CertificateParams, DistinguishedName, DnType,
DnValue::PrintableString, ExtendedKeyUsagePurpose, IsCa, KeyPair, KeyUsagePurpose, SanType,
DnValue::PrintableString, ExtendedKeyUsagePurpose, IsCa, Issuer, KeyPair, KeyUsagePurpose,
SanType,
};

#[cfg(feature = "aws_lc_rs")]
Expand Down Expand Up @@ -113,29 +114,25 @@ impl CaBuilder {
/// build `Ca` Certificate.
pub fn build(self) -> Result<Ca, rcgen::Error> {
let key_pair = self.alg.to_key_pair()?;
let cert = self.params.self_signed(&key_pair)?;
Ok(Ca { cert, key_pair })
Ok(Ca(Issuer::from_params(self.params, key_pair)))
}
}

/// End-entity [Certificate]
pub struct Ca {
cert: Certificate,
key_pair: KeyPair,
}
pub struct Ca(Issuer);

impl Ca {
/// Self-sign and serialize
pub fn serialize_pem(&self) -> PemCertifiedKey {
PemCertifiedKey {
cert_pem: self.cert.pem(),
private_key_pem: self.key_pair.serialize_pem(),
cert_pem: self.0.pem(),
private_key_pem: self.0.key_pair().serialize_pem(),
}
}
/// Return `&Certificate`
/// Return `Certificate`
#[allow(dead_code)]
pub fn cert(&self) -> &Certificate {
&self.cert
pub fn cert(&self) -> Certificate {
self.0.certificate()
}
}

Expand Down Expand Up @@ -203,9 +200,7 @@ impl EndEntityBuilder {
/// build `EndEntity` Certificate.
pub fn build(self, issuer: &Ca) -> Result<EndEntity, rcgen::Error> {
let key_pair = self.alg.to_key_pair()?;
let cert = self
.params
.signed_by(&key_pair, &issuer.cert, &issuer.key_pair)?;
let cert = self.params.signed_by(&key_pair, &issuer.0)?;
Ok(EndEntity { cert, key_pair })
}
}
Expand Down
Loading