Skip to content
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
6 changes: 3 additions & 3 deletions rcgen/examples/simple.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
use std::fs;

use rcgen::{date_time_ymd, CertificateParams, DistinguishedName, DnType, KeyPair, SanType};
use rcgen::{date_time_ymd, CertificateParams, DistinguishedName, DnType, GeneralName, KeyPair};

fn main() -> Result<(), Box<dyn std::error::Error>> {
let mut params: CertificateParams = Default::default();
Expand All @@ -14,8 +14,8 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
.distinguished_name
.push(DnType::CommonName, "Master Cert");
params.subject_alt_names = vec![
SanType::DnsName("crabs.crabs".try_into()?),
SanType::DnsName("localhost".try_into()?),
GeneralName::DnsName("crabs.crabs".try_into()?),
GeneralName::DnsName("localhost".try_into()?),
];

let key_pair = KeyPair::generate()?;
Expand Down
44 changes: 25 additions & 19 deletions rcgen/src/certificate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ use crate::ring_like::digest;
use crate::ENCODE_CONFIG;
use crate::{
oid, write_distinguished_name, write_dt_utc_or_generalized,
write_x509_authority_key_identifier, write_x509_extension, DistinguishedName, Error, Issuer,
KeyIdMethod, KeyUsagePurpose, SanType, SerialNumber, SigningKey,
write_x509_authority_key_identifier, write_x509_extension, DistinguishedName, Error,
GeneralName, Issuer, KeyIdMethod, KeyUsagePurpose, SerialNumber, SigningKey,
};

/// An issued certificate
Expand Down Expand Up @@ -57,7 +57,7 @@ pub struct CertificateParams {
pub not_before: OffsetDateTime,
pub not_after: OffsetDateTime,
pub serial_number: Option<SerialNumber>,
pub subject_alt_names: Vec<SanType>,
pub subject_alt_names: Vec<GeneralName>,
pub distinguished_name: DistinguishedName,
pub is_ca: IsCa,
pub key_usages: Vec<KeyUsagePurpose>,
Expand Down Expand Up @@ -114,8 +114,8 @@ impl CertificateParams {
.into_iter()
.map(|s| {
Ok(match IpAddr::from_str(&s) {
Ok(ip) => SanType::IpAddress(ip),
Err(_) => SanType::DnsName(s.try_into()?),
Ok(ip) => GeneralName::IpAddress(ip),
Err(_) => GeneralName::DnsName(s.try_into()?),
})
})
.collect::<Result<Vec<_>, _>>()?;
Expand Down Expand Up @@ -172,7 +172,7 @@ impl CertificateParams {

Ok(CertificateParams {
is_ca: IsCa::from_x509(&x509)?,
subject_alt_names: SanType::from_x509(&x509)?,
subject_alt_names: GeneralName::from_x509(&x509)?,
key_usages: KeyUsagePurpose::from_x509(&x509)?,
extended_key_usages: ExtendedKeyUsagePurpose::from_x509(&x509)?,
name_constraints: NameConstraints::from_x509(&x509)?,
Expand Down Expand Up @@ -265,16 +265,16 @@ impl CertificateParams {
writer.next().write_tagged_implicit(
Tag::context(san.tag()),
|writer| match san {
SanType::Rfc822Name(name)
| SanType::DnsName(name)
| SanType::URI(name) => writer.write_ia5_string(name.as_str()),
SanType::IpAddress(IpAddr::V4(addr)) => {
GeneralName::Rfc822Name(name)
| GeneralName::DnsName(name)
| GeneralName::URI(name) => writer.write_ia5_string(name.as_str()),
GeneralName::IpAddress(IpAddr::V4(addr)) => {
writer.write_bytes(&addr.octets())
},
SanType::IpAddress(IpAddr::V6(addr)) => {
GeneralName::IpAddress(IpAddr::V6(addr)) => {
writer.write_bytes(&addr.octets())
},
SanType::OtherName((oid, value)) => {
GeneralName::OtherName((oid, value)) => {
// otherName SEQUENCE { OID, [0] explicit any defined by oid }
// https://datatracker.ietf.org/doc/html/rfc5280#page-38
writer.write_sequence(|writer| {
Expand Down Expand Up @@ -640,6 +640,7 @@ fn write_general_subtrees(writer: DERWriter, tag: u64, general_subtrees: &[Gener
///
/// [RFC 5280]: <https://datatracker.ietf.org/doc/html/rfc5280#appendix-A.1>
/// [RFC 2986]: <https://datatracker.ietf.org/doc/html/rfc2986#section-4>
#[allow(clippy::exhaustive_structs)]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub struct Attribute {
/// `AttributeType` of the `Attribute`, defined as an `OBJECT IDENTIFIER`.
Expand Down Expand Up @@ -755,8 +756,9 @@ impl DnType {
}
}

#[derive(Debug, PartialEq, Eq, Hash, Clone)]
/// One of the purposes contained in the [extended key usage extension](https://tools.ietf.org/html/rfc5280#section-4.2.1.12)
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq, Hash, Clone)]
pub enum ExtendedKeyUsagePurpose {
/// anyExtendedKeyUsage
Any,
Expand Down Expand Up @@ -831,6 +833,7 @@ impl ExtendedKeyUsagePurpose {

/// The [NameConstraints extension](https://tools.ietf.org/html/rfc5280#section-4.2.1.10)
/// (only relevant for CA certificates)
#[allow(clippy::exhaustive_structs)]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct NameConstraints {
/// A list of subtrees that the domain has to match.
Expand Down Expand Up @@ -883,9 +886,9 @@ impl NameConstraints {
#[non_exhaustive]
/// General Subtree type.
///
/// This type has similarities to the [`SanType`] enum but is not equal.
/// This type has similarities to the [`GeneralName`] enum but is not equal.
/// For example, `GeneralSubtree` has CIDR subnets for ip addresses
/// while [`SanType`] has IP addresses.
/// while [`GeneralName`] has IP addresses.
pub enum GeneralSubtree {
/// Also known as E-Mail address
Rfc822Name(String),
Expand Down Expand Up @@ -944,8 +947,6 @@ impl GeneralSubtree {
}
}

#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
/// CIDR subnet, as per [RFC 4632](https://tools.ietf.org/html/rfc4632)
///
/// You might know CIDR subnets better by their textual representation
Expand All @@ -954,6 +955,9 @@ impl GeneralSubtree {
///
/// The first field in the enum is the address, the second is the mask.
/// Both are specified in network byte order.
#[allow(clippy::exhaustive_enums)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub enum CidrSubnet {
V4([u8; 4], [u8; 4]),
V6([u8; 16], [u8; 16]),
Expand Down Expand Up @@ -1056,6 +1060,7 @@ pub fn date_time_ymd(year: i32, month: u8, day: u8) -> OffsetDateTime {
}

/// Whether the certificate is allowed to sign other certificates
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum IsCa {
/// The certificate can only sign itself
Expand Down Expand Up @@ -1099,6 +1104,7 @@ impl IsCa {
///
/// Sets an optional upper limit on the length of the intermediate certificate chain
/// length allowed for this CA certificate (not including the end entity certificate).
#[non_exhaustive]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
pub enum BasicConstraints {
/// No constraint
Expand Down Expand Up @@ -1282,7 +1288,7 @@ mod tests {
fn parse_other_name_alt_name() {
// Create and serialize a certificate with an alternative name containing an "OtherName".
let mut params = CertificateParams::default();
let other_name = SanType::OtherName((vec![1, 2, 3, 4], "Foo".into()));
let other_name = GeneralName::OtherName((vec![1, 2, 3, 4], "Foo".into()));
params.subject_alt_names.push(other_name.clone());
let key_pair = KeyPair::generate().unwrap();
let cert = params.self_signed(&key_pair).unwrap();
Expand Down Expand Up @@ -1336,7 +1342,7 @@ mod tests {
#[test]
fn converts_from_ip() {
let ip = Ipv4Addr::new(2, 4, 6, 8);
let ip_san = SanType::IpAddress(IpAddr::V4(ip));
let ip_san = GeneralName::IpAddress(IpAddr::V4(ip));

let mut params = CertificateParams::new(vec!["crabs".to_owned()]).unwrap();
let ca_key = KeyPair::generate().unwrap();
Expand Down
77 changes: 60 additions & 17 deletions rcgen/src/crl.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,24 +45,21 @@ use crate::{
/// let issuer = Issuer::new(issuer_params, key_pair);
///
/// // Describe a revoked certificate.
/// let revoked_cert = RevokedCertParams{
/// serial_number: SerialNumber::from(9999),
/// revocation_time: date_time_ymd(2024, 06, 17),
/// reason_code: Some(RevocationReason::KeyCompromise),
/// invalidity_date: None,
/// };
/// let mut revoked_cert = RevokedCertParams::new(SerialNumber::from(9999), date_time_ymd(2024, 06, 17));
/// revoked_cert.reason_code = Some(RevocationReason::KeyCompromise);
///
/// // Create a CRL signed by the issuer, revoking revoked_cert.
/// let crl = CertificateRevocationListParams{
/// this_update: date_time_ymd(2023, 06, 17),
/// next_update: date_time_ymd(2024, 06, 17),
/// crl_number: SerialNumber::from(1234),
/// issuing_distribution_point: None,
/// revoked_certs: vec![revoked_cert],
/// #[cfg(feature = "crypto")]
/// key_identifier_method: KeyIdMethod::Sha256,
/// #[cfg(not(feature = "crypto"))]
/// key_identifier_method: KeyIdMethod::PreSpecified(vec![]),
/// }.signed_by(&issuer).unwrap();
/// #[cfg(feature = "crypto")]
/// let mut crl = CertificateRevocationListParams::new(
/// date_time_ymd(2023, 06, 17),
/// date_time_ymd(2024, 06, 17),
/// SerialNumber::from(1234),
/// KeyIdMethod::Sha256,
/// );
/// #[cfg(feature = "crypto")]
/// crl.revoked_certs.push(revoked_cert);
/// #[cfg(feature = "crypto")]
/// crl.signed_by(&issuer).unwrap();
///# }
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CertificateRevocationList {
Expand Down Expand Up @@ -95,6 +92,7 @@ impl From<CertificateRevocationList> for CertificateRevocationListDer<'static> {
/// A certificate revocation list (CRL) distribution point, to be included in a certificate's
/// [distribution points extension](https://www.rfc-editor.org/rfc/rfc5280#section-4.2.1.13) or
/// a CRL's [issuing distribution point extension](https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.5)
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct CrlDistributionPoint {
/// One or more URI distribution point names, indicating a place the current CRL can
Expand All @@ -103,6 +101,11 @@ pub struct CrlDistributionPoint {
}

impl CrlDistributionPoint {
/// Construct a new `CrlDistributionPoint` with the given URIs.
pub fn new(uris: Vec<String>) -> Self {
Self { uris }
}

pub(crate) fn write_der(&self, writer: DERWriter) {
// DistributionPoint SEQUENCE
writer.write_sequence(|writer| {
Expand Down Expand Up @@ -142,6 +145,7 @@ fn write_distribution_point_name_uris<'a>(
/// See [RFC 5280 §5.3.1][1]
///
/// [1]: <https://www.rfc-editor.org/rfc/rfc5280#section-5.3.1>
#[non_exhaustive]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
#[allow(missing_docs)] // Not much to add above the code name.
pub enum RevocationReason {
Expand All @@ -159,6 +163,7 @@ pub enum RevocationReason {
}

/// Parameters used for certificate revocation list (CRL) generation
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CertificateRevocationListParams {
/// Issue date of the CRL.
Expand All @@ -181,6 +186,23 @@ pub struct CertificateRevocationListParams {
}

impl CertificateRevocationListParams {
/// Construct a new `CertificateRevocationListParams` with the given parameters.
pub fn new(
this_update: OffsetDateTime,
next_update: OffsetDateTime,
crl_number: SerialNumber,
key_identifier_method: KeyIdMethod,
) -> Self {
Self {
this_update,
next_update,
crl_number,
issuing_distribution_point: None,
revoked_certs: Vec::new(),
key_identifier_method,
}
}

/// Serializes the certificate revocation list (CRL).
///
/// Including a signature from the issuing certificate authority's key.
Expand Down Expand Up @@ -294,6 +316,7 @@ impl CertificateRevocationListParams {

/// A certificate revocation list (CRL) issuing distribution point, to be included in a CRL's
/// [issuing distribution point extension](https://datatracker.ietf.org/doc/html/rfc5280#section-5.2.5).
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CrlIssuingDistributionPoint {
/// The CRL's distribution point, containing a sequence of URIs the CRL can be retrieved from.
Expand All @@ -304,6 +327,14 @@ pub struct CrlIssuingDistributionPoint {
}

impl CrlIssuingDistributionPoint {
/// Construct a new `CrlIssuingDistributionPoint` with the given distribution point.
pub fn new(distribution_point: CrlDistributionPoint) -> Self {
Self {
distribution_point,
scope: None,
}
}

fn write_der(&self, writer: DERWriter) {
// IssuingDistributionPoint SEQUENCE
writer.write_sequence(|writer| {
Expand All @@ -328,6 +359,7 @@ impl CrlIssuingDistributionPoint {
}

/// Describes the scope of a CRL for an issuing distribution point extension.
#[non_exhaustive]
#[derive(Debug, Clone, Copy, Eq, PartialEq)]
pub enum CrlScope {
/// The CRL contains only end-entity user certificates.
Expand All @@ -337,6 +369,7 @@ pub enum CrlScope {
}

/// Parameters used for describing a revoked certificate included in a [`CertificateRevocationList`].
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct RevokedCertParams {
/// Serial number identifying the revoked certificate.
Expand All @@ -352,6 +385,16 @@ pub struct RevokedCertParams {
}

impl RevokedCertParams {
/// Construct a new `RevokedCertParams` with the given serial number and revocation time.
pub fn new(serial_number: SerialNumber, revocation_time: OffsetDateTime) -> Self {
Self {
serial_number,
revocation_time,
reason_code: None,
invalidity_date: None,
}
}

fn write_der(&self, writer: DERWriter) {
writer.write_sequence(|writer| {
// Write serial number.
Expand Down
7 changes: 4 additions & 3 deletions rcgen/src/csr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ use crate::{
Certificate, CertificateParams, Error, Issuer, PublicKeyData, SignatureAlgorithm, SigningKey,
};
#[cfg(feature = "x509-parser")]
use crate::{DistinguishedName, ExtendedKeyUsagePurpose, KeyUsagePurpose, SanType};
use crate::{DistinguishedName, ExtendedKeyUsagePurpose, GeneralName, KeyUsagePurpose};

/// A public key, extracted from a CSR
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
Expand Down Expand Up @@ -66,6 +66,7 @@ impl From<CertificateSigningRequest> for CertificateSigningRequestDer<'static> {
}

/// Parameters for a certificate signing request
#[non_exhaustive]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CertificateSigningRequestParams {
/// Parameters for the certificate to be signed.
Expand All @@ -87,7 +88,7 @@ impl CertificateSigningRequestParams {
/// Parse and verify a certificate signing request from DER-encoded bytes
///
/// Currently, this supports the following extensions:
/// - `Subject Alternative Name` (see [`SanType`])
/// - `Subject Alternative Name` (see [`GeneralName`])
/// - `Key Usage` (see [`KeyUsagePurpose`])
/// - `Extended Key Usage` (see [`ExtendedKeyUsagePurpose`])
///
Expand Down Expand Up @@ -136,7 +137,7 @@ impl CertificateSigningRequestParams {
for name in &san.general_names {
params
.subject_alt_names
.push(SanType::try_from_general(name)?);
.push(GeneralName::try_from_general(name)?);
}
},
x509_parser::extensions::ParsedExtension::ExtendedKeyUsage(eku) => {
Expand Down
Loading
Loading