Skip to content

Deduplicate issuer usage #331

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

Draft
wants to merge 9 commits into
base: main
Choose a base branch
from
563 changes: 215 additions & 348 deletions rcgen/src/certificate.rs

Large diffs are not rendered by default.

186 changes: 97 additions & 89 deletions rcgen/src/crl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,15 @@ use pem::Pem;
use pki_types::CertificateRevocationListDer;
use time::OffsetDateTime;
use yasna::DERWriter;
use yasna::DERWriterSeq;
use yasna::Tag;

use crate::key_pair::sign_der;
#[cfg(feature = "pem")]
use crate::ENCODE_CONFIG;
use crate::{
oid, write_distinguished_name, write_dt_utc_or_generalized,
write_x509_authority_key_identifier, write_x509_extension, CertificateParams, Error, Issuer,
KeyIdMethod, KeyUsagePurpose, SerialNumber, SigningKey,
KeyIdMethod, KeyUsagePurpose, SerialNumber, SigningKey, ToDer,
};

/// A certificate revocation list (CRL)
Expand Down Expand Up @@ -193,107 +193,115 @@ impl CertificateRevocationListParams {
return Err(Error::InvalidCrlNextUpdate);
}

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

let issuer = Issuer::new(issuer, issuer_key);
if !issuer.key_usages.is_empty() && !issuer.key_usages.contains(&KeyUsagePurpose::CrlSign) {
return Err(Error::IssuerNotCrlSigner);
}

Ok(CertificateRevocationList {
der: self.serialize_der(issuer)?.into(),
der: SignableCrl {
params: self,
issuer: &issuer,
}
.signed(issuer_key)?
.into(),
})
}
}

fn serialize_der(&self, issuer: Issuer<'_, impl SigningKey>) -> Result<Vec<u8>, Error> {
sign_der(issuer.key_pair, |writer| {
// Write CRL version.
// RFC 5280 §5.1.2.1:
// This optional field describes the version of the encoded CRL. When
// extensions are used, as required by this profile, this field MUST be
// present and MUST specify version 2 (the integer value is 1).
// RFC 5280 §5.2:
// Conforming CRL issuers are REQUIRED to include the authority key
// identifier (Section 5.2.1) and the CRL number (Section 5.2.3)
// extensions in all CRLs issued.
writer.next().write_u8(1);

// Write algorithm identifier.
// 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.algorithm().write_alg_ident(writer.next());

// Write issuer.
// RFC 5280 §5.1.2.3:
// The issuer field MUST contain a non-empty X.500 distinguished name (DN).
write_distinguished_name(writer.next(), &issuer.distinguished_name);

// Write thisUpdate date.
// RFC 5280 §5.1.2.4:
// This field indicates the issue date of this CRL. thisUpdate may be
// encoded as UTCTime or GeneralizedTime.
write_dt_utc_or_generalized(writer.next(), self.this_update);

// Write nextUpdate date.
// While OPTIONAL in the ASN.1 module, RFC 5280 §5.1.2.5 says:
// Conforming CRL issuers MUST include the nextUpdate field in all CRLs.
write_dt_utc_or_generalized(writer.next(), self.next_update);

// Write revokedCertificates.
// RFC 5280 §5.1.2.6:
// When there are no revoked certificates, the revoked certificates list
// MUST be absent
if !self.revoked_certs.is_empty() {
writer.next().write_sequence(|writer| {
for revoked_cert in &self.revoked_certs {
revoked_cert.write_der(writer.next());
}
struct SignableCrl<'a, S> {
params: &'a CertificateRevocationListParams,
issuer: &'a Issuer<'a, S>,
}

impl<'a, S: SigningKey> ToDer for SignableCrl<'_, S> {
fn write_der(&self, writer: &mut DERWriterSeq) -> Result<(), Error> {
// Write CRL version.
// RFC 5280 §5.1.2.1:
// This optional field describes the version of the encoded CRL. When
// extensions are used, as required by this profile, this field MUST be
// present and MUST specify version 2 (the integer value is 1).
// RFC 5280 §5.2:
// Conforming CRL issuers are REQUIRED to include the authority key
// identifier (Section 5.2.1) and the CRL number (Section 5.2.3)
// extensions in all CRLs issued.
writer.next().write_u8(1);

// Write algorithm identifier.
// RFC 5280 §5.1.2.2:
// This field MUST contain the same algorithm identifier as the
// signatureAlgorithm field in the sequence CertificateList
self.issuer
.key_pair
.algorithm()
.write_alg_ident(writer.next());

// Write issuer.
// RFC 5280 §5.1.2.3:
// The issuer field MUST contain a non-empty X.500 distinguished name (DN).
write_distinguished_name(writer.next(), &self.issuer.distinguished_name);

// Write thisUpdate date.
// RFC 5280 §5.1.2.4:
// This field indicates the issue date of this CRL. thisUpdate may be
// encoded as UTCTime or GeneralizedTime.
write_dt_utc_or_generalized(writer.next(), self.params.this_update);

// Write nextUpdate date.
// While OPTIONAL in the ASN.1 module, RFC 5280 §5.1.2.5 says:
// Conforming CRL issuers MUST include the nextUpdate field in all CRLs.
write_dt_utc_or_generalized(writer.next(), self.params.next_update);

// Write revokedCertificates.
// RFC 5280 §5.1.2.6:
// When there are no revoked certificates, the revoked certificates list
// MUST be absent
if !self.params.revoked_certs.is_empty() {
writer.next().write_sequence(|writer| {
for revoked_cert in &self.params.revoked_certs {
revoked_cert.write_der(writer.next());
}
});
}

// Write crlExtensions.
// RFC 5280 §5.1.2.7:
// This field may only appear if the version is 2 (Section 5.1.2.1). If
// present, this field is a sequence of one or more CRL extensions.
// RFC 5280 §5.2:
// Conforming CRL issuers are REQUIRED to include the authority key
// identifier (Section 5.2.1) and the CRL number (Section 5.2.3)
// extensions in all CRLs issued.
writer.next().write_tagged(Tag::context(0), |writer| {
writer.write_sequence(|writer| {
// Write authority key identifier.
write_x509_authority_key_identifier(
writer.next(),
self.params
.key_identifier_method
.derive(self.issuer.key_pair.der_bytes()),
);

// Write CRL number.
write_x509_extension(writer.next(), oid::CRL_NUMBER, false, |writer| {
writer.write_bigint_bytes(self.params.crl_number.as_ref(), true);
});
}

// Write crlExtensions.
// RFC 5280 §5.1.2.7:
// This field may only appear if the version is 2 (Section 5.1.2.1). If
// present, this field is a sequence of one or more CRL extensions.
// RFC 5280 §5.2:
// Conforming CRL issuers are REQUIRED to include the authority key
// identifier (Section 5.2.1) and the CRL number (Section 5.2.3)
// extensions in all CRLs issued.
writer.next().write_tagged(Tag::context(0), |writer| {
writer.write_sequence(|writer| {
// Write authority key identifier.
write_x509_authority_key_identifier(
// Write issuing distribution point (if present).
if let Some(issuing_distribution_point) = &self.params.issuing_distribution_point {
write_x509_extension(
writer.next(),
self.key_identifier_method
.derive(issuer.key_pair.subject_public_key_info()),
oid::CRL_ISSUING_DISTRIBUTION_POINT,
true,
|writer| {
issuing_distribution_point.write_der(writer);
},
);

// Write CRL number.
write_x509_extension(writer.next(), oid::CRL_NUMBER, false, |writer| {
writer.write_bigint_bytes(self.crl_number.as_ref(), true);
});

// Write issuing distribution point (if present).
if let Some(issuing_distribution_point) = &self.issuing_distribution_point {
write_x509_extension(
writer.next(),
oid::CRL_ISSUING_DISTRIBUTION_POINT,
true,
|writer| {
issuing_distribution_point.write_der(writer);
},
);
}
});
}
});
});

Ok(())
})
Ok(())
}
}

Expand Down
Loading
Loading