Skip to content

Fixes KeyPair Ownership and Removes Need for Issuer Lifetimes #326

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

Closed
32 changes: 9 additions & 23 deletions rcgen/src/certificate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -158,16 +158,8 @@ impl CertificateParams {
pub fn signed_by(
self,
public_key: &impl PublicKeyData,
issuer: &Certificate,
issuer_key: &KeyPair,
issuer: &Issuer,
) -> 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,
};

let subject_public_key_info =
yasna::construct_der(|writer| serialize_public_key_der(public_key, writer));
let der = self.serialize_der_with_signer(public_key, issuer)?;
Expand All @@ -182,16 +174,9 @@ impl CertificateParams {
///
/// The returned [`Certificate`] may be serialized using [`Certificate::der`] and
/// [`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,
};

let subject_public_key_info = key_pair.public_key_der();
let der = self.serialize_der_with_signer(key_pair, issuer)?;
pub fn self_signed(self, issuer: &Issuer) -> Result<Certificate, Error> {
let subject_public_key_info = issuer.public_key_der();
let der = self.serialize_der_with_signer(issuer, &issuer)?;
Ok(Certificate {
params: self,
subject_public_key_info,
Expand Down Expand Up @@ -645,7 +630,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 All @@ -672,7 +657,7 @@ impl CertificateParams {
}
};
// Write signature algorithm
issuer.key_pair.alg.write_alg_ident(writer.next());
issuer.key_pair.algorithm().write_alg_ident(writer.next());
// Write issuer name
write_distinguished_name(writer.next(), &issuer.distinguished_name);
// Write validity
Expand Down Expand Up @@ -704,7 +689,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 Expand Up @@ -1494,6 +1479,7 @@ PITGdT9dgN88nHPCle0B1+OY+OZ5
let ca_kp = KeyPair::from_pem(ca_key).unwrap();
let ca_cert = params.self_signed(&ca_kp).unwrap();
assert_eq!(&ca_ski, &ca_cert.key_identifier());
let ca_issuer = Issuer::new(ca_cert, &ca_kp);

let (_, x509_ca) = x509_parser::parse_x509_certificate(ca_cert.der()).unwrap();
assert_eq!(
Expand All @@ -1512,7 +1498,7 @@ PITGdT9dgN88nHPCle0B1+OY+OZ5
let ee_key = KeyPair::generate().unwrap();
let mut ee_params = CertificateParams::default();
ee_params.use_authority_key_identifier_extension = true;
let ee_cert = ee_params.signed_by(&ee_key, &ca_cert, &ee_key).unwrap();
let ee_cert = ee_params.signed_by(&ee_key, &ca_issuer).unwrap();

let (_, x509_ee) = x509_parser::parse_x509_certificate(ee_cert.der()).unwrap();
assert_eq!(
Expand Down
21 changes: 5 additions & 16 deletions rcgen/src/crl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,8 @@ use yasna::Tag;
use crate::ENCODE_CONFIG;
use crate::{
oid, write_distinguished_name, write_dt_utc_or_generalized,
write_x509_authority_key_identifier, write_x509_extension, Certificate, Error, Issuer,
KeyIdMethod, KeyPair, KeyUsagePurpose, SerialNumber,
write_x509_authority_key_identifier, write_x509_extension, Error, Issuer, KeyIdMethod,
KeyUsagePurpose, SerialNumber,
};

/// A certificate revocation list (CRL)
Expand Down Expand Up @@ -188,22 +188,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 @@ -214,7 +203,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 All @@ -231,7 +220,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
issuer.key_pair.alg.write_alg_ident(writer.next());
issuer.key_pair.algorithm().write_alg_ident(writer.next());

// Write issuer.
// RFC 5280 §5.1.2.3:
Expand Down
15 changes: 2 additions & 13 deletions rcgen/src/csr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use pki_types::CertificateSigningRequestDer;
#[cfg(feature = "pem")]
use crate::ENCODE_CONFIG;
use crate::{
key_pair::serialize_public_key_der, Certificate, CertificateParams, Error, Issuer, KeyPair,
key_pair::serialize_public_key_der, Certificate, CertificateParams, Error, Issuer,
PublicKeyData, SignatureAlgorithm,
};
#[cfg(feature = "x509-parser")]
Expand Down Expand Up @@ -201,18 +201,7 @@ 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)?;
Expand Down
109 changes: 109 additions & 0 deletions rcgen/src/issuer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
#[cfg(feature = "x509-parser")]
use pki_types::CertificateDer;

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

/// Holds the information necessary for an issuer of a certificate to sign other certificates. Specifically, it must
/// have the distinguished name, key identifier method, key usages, and access to the private key.
///
/// Optionally, the issuer may also have the entire issuer's certificate, but for root certificates this cannot be
/// available, as the root certificate is self-signed.
pub struct Issuer {
/// The distinguished name of the issuer. Used to construct the issuer field in the issued certificate.
pub(crate) distinguished_name: DistinguishedName,

/// The method used to generate the key identifier for the issuer. Must match the method used to generate the
/// subject key identifier in the issuer's certificate.
pub(crate) key_identifier_method: KeyIdMethod,

/// The key usage purposes associated with the issuer.
pub(crate) key_usages: Vec<KeyUsagePurpose>,

/// The key pair of the issuer which includes the private key, though it may be a RemoteKeyPair allowing for a key
/// held in an HSM or other secure location to sign the certificate.
pub(crate) key_pair: KeyPair,

/// The issuer's certificate, if available. This is typically `None` for root certificates.
pub(crate) certificate: Option<Certificate>,
}

impl Issuer {
/// Creates a new issuer from a certificate in DER format and a key pair. The certificate must be a CA certificate
/// and the key pair must contain the private key associated with the certificate.
#[cfg(feature = "x509-parser")]
pub fn new(der: &CertificateDer, key_pair: &KeyPair) -> Result<Self, crate::Error> {
// TODO: The certificate contains the public key, which must match the public key in the key pair, or this
// issuer is invalid. We should check this error condition.

let params = CertificateParams::from_ca_cert_der(der)?;
let certificate = Certificate {
params: params.clone(),
subject_public_key_info: key_pair.public_key_der(),
der: der.clone().into_owned(),
};

Ok(Self {
distinguished_name: params.distinguished_name,
key_identifier_method: params.key_identifier_method,
key_usages: params.key_usages,
key_pair: key_pair.clone(),
certificate: Some(certificate),
})
}

/// Creates a new issuer from the given parameters and key pair. This is typically used for root certificates, which
/// do not initially have a certificate.
pub fn new_from_params(params: &CertificateParams, key_pair: &KeyPair) -> Self {
Self {
distinguished_name: params.distinguished_name.clone(),
key_identifier_method: params.key_identifier_method.clone(),
key_usages: params.key_usages.clone(),
key_pair: key_pair.clone(),
certificate: None,
}
}

/// Sets the certificate of the issuer.
pub fn set_certificate(&mut self, certificate: Certificate) {
self.certificate = Some(certificate);
}

/// Returns the certificate of the issuer, if available. This is typically `None` for root certificates issuers
pub fn certificate(&self) -> Option<&Certificate> {
self.certificate.as_ref()
}

/// Returns the distinguished name of the issuer.
pub fn distinguished_name(&self) -> &DistinguishedName {
&self.distinguished_name
}

/// Returns the public key of the issuer
pub fn public_key_raw(&self) -> &[u8] {
&self.key_pair.public_key_raw()
}

/// Returns the public key of the issuer in der format
pub fn public_key_der(&self) -> Vec<u8> {
self.key_pair.public_key_der()
}

/// Returns the private key of the issuer. The caller had access to this key when creating the issuer, so it is not
/// an increase in privilege to return it.
pub fn key_pair(&self) -> &KeyPair {
&self.key_pair
}
}

impl PublicKeyData for Issuer {
fn der_bytes(&self) -> &[u8] {
self.key_pair.der_bytes()
}

fn algorithm(&self) -> &SignatureAlgorithm {
self.key_pair.algorithm()
}
}
Loading
Loading