rcgen/
lib.rs

1/*!
2Rust X.509 certificate generation utility
3
4This crate provides a way to generate self signed X.509 certificates.
5
6The most simple way of using this crate is by calling the
7[`generate_simple_self_signed`] function.
8For more customization abilities, construct a [`CertificateParams`] and
9a key pair to call [`CertificateParams::signed_by()`] or [`CertificateParams::self_signed()`].
10*/
11#![cfg_attr(
12	feature = "pem",
13	doc = r##"
14## Example
15
16```
17use rcgen::{generate_simple_self_signed, CertifiedKey};
18# fn main () {
19// Generate a certificate that's valid for "localhost" and "hello.world.example"
20let subject_alt_names = vec!["hello.world.example".to_string(),
21	"localhost".to_string()];
22
23let CertifiedKey { cert, signing_key } = generate_simple_self_signed(subject_alt_names).unwrap();
24println!("{}", cert.pem());
25println!("{}", signing_key.serialize_pem());
26# }
27```"##
28)]
29#![forbid(unsafe_code)]
30#![forbid(non_ascii_idents)]
31#![deny(missing_docs)]
32#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
33#![warn(unreachable_pub)]
34
35use std::borrow::Cow;
36use std::collections::HashMap;
37use std::fmt;
38use std::hash::Hash;
39use std::net::IpAddr;
40#[cfg(feature = "x509-parser")]
41use std::net::{Ipv4Addr, Ipv6Addr};
42use std::ops::Deref;
43
44#[cfg(feature = "pem")]
45use pem::Pem;
46use pki_types::CertificateDer;
47use time::{OffsetDateTime, Time};
48use yasna::models::ObjectIdentifier;
49use yasna::models::{GeneralizedTime, UTCTime};
50use yasna::tags::{TAG_BMPSTRING, TAG_TELETEXSTRING, TAG_UNIVERSALSTRING};
51use yasna::DERWriter;
52use yasna::Tag;
53
54use crate::string::{BmpString, Ia5String, PrintableString, TeletexString, UniversalString};
55
56pub use certificate::{
57	date_time_ymd, Attribute, BasicConstraints, Certificate, CertificateParams, CidrSubnet,
58	CustomExtension, DnType, ExtendedKeyUsagePurpose, GeneralSubtree, IsCa, NameConstraints,
59};
60pub use crl::{
61	CertificateRevocationList, CertificateRevocationListParams, CrlDistributionPoint,
62	CrlIssuingDistributionPoint, CrlScope, RevocationReason, RevokedCertParams,
63};
64pub use csr::{CertificateSigningRequest, CertificateSigningRequestParams, PublicKey};
65pub use error::{Error, InvalidAsn1String};
66#[cfg(feature = "crypto")]
67pub use key_pair::KeyPair;
68pub use key_pair::PublicKeyData;
69#[cfg(all(feature = "crypto", feature = "aws_lc_rs"))]
70pub use key_pair::RsaKeySize;
71pub use key_pair::{SigningKey, SubjectPublicKeyInfo};
72#[cfg(feature = "crypto")]
73use ring_like::digest;
74pub use sign_algo::algo::*;
75pub use sign_algo::SignatureAlgorithm;
76
77mod certificate;
78mod crl;
79mod csr;
80mod error;
81mod key_pair;
82mod oid;
83mod ring_like;
84mod sign_algo;
85pub mod string;
86
87/// Type-alias for the old name of [`Error`].
88#[deprecated(
89	note = "Renamed to `Error`. We recommend to refer to it by fully-qualifying the crate: `rcgen::Error`."
90)]
91pub type RcgenError = Error;
92
93/// An issued certificate, together with the subject keypair.
94#[derive(PartialEq, Eq)]
95pub struct CertifiedKey<S: SigningKey> {
96	/// An issued certificate.
97	pub cert: Certificate,
98	/// The certificate's subject signing key.
99	pub signing_key: S,
100}
101
102/**
103KISS function to generate a self signed certificate
104
105Given a set of domain names you want your certificate to be valid for,
106this function fills in the other generation parameters with
107reasonable defaults and generates a self signed certificate
108and key pair as output.
109*/
110#[cfg(feature = "crypto")]
111#[cfg_attr(
112	feature = "pem",
113	doc = r##"
114## Example
115
116```
117use rcgen::{generate_simple_self_signed, CertifiedKey};
118# fn main () {
119// Generate a certificate that's valid for "localhost" and "hello.world.example"
120let subject_alt_names = vec!["hello.world.example".to_string(),
121	"localhost".to_string()];
122
123let CertifiedKey { cert, signing_key } = generate_simple_self_signed(subject_alt_names).unwrap();
124
125// The certificate is now valid for localhost and the domain "hello.world.example"
126println!("{}", cert.pem());
127println!("{}", signing_key.serialize_pem());
128# }
129```
130"##
131)]
132pub fn generate_simple_self_signed(
133	subject_alt_names: impl Into<Vec<String>>,
134) -> Result<CertifiedKey<KeyPair>, Error> {
135	let signing_key = KeyPair::generate()?;
136	let cert = CertificateParams::new(subject_alt_names)?.self_signed(&signing_key)?;
137	Ok(CertifiedKey { cert, signing_key })
138}
139
140/// An [`Issuer`] wrapper that also contains the issuer's [`Certificate`].
141#[derive(Debug)]
142pub struct CertifiedIssuer<'a, S> {
143	certificate: Certificate,
144	issuer: Issuer<'a, S>,
145}
146
147impl<'a, S: SigningKey> CertifiedIssuer<'a, S> {
148	/// Create a new issuer from the given parameters and key, with a self-signed certificate.
149	pub fn self_signed(params: CertificateParams, signing_key: S) -> Result<Self, Error> {
150		Ok(Self {
151			certificate: params.self_signed(&signing_key)?,
152			issuer: Issuer::new(params, signing_key),
153		})
154	}
155
156	/// Create a new issuer from the given parameters and key, signed by the given `issuer`.
157	pub fn signed_by(
158		params: CertificateParams,
159		signing_key: S,
160		issuer: &Issuer<'_, impl SigningKey>,
161	) -> Result<Self, Error> {
162		Ok(Self {
163			certificate: params.signed_by(&signing_key, issuer)?,
164			issuer: Issuer::new(params, signing_key),
165		})
166	}
167
168	/// Get the certificate in PEM encoded format.
169	#[cfg(feature = "pem")]
170	pub fn pem(&self) -> String {
171		pem::encode_config(&Pem::new("CERTIFICATE", self.der().to_vec()), ENCODE_CONFIG)
172	}
173
174	/// Get the certificate in DER encoded format.
175	///
176	/// See also [`Certificate::der()`]
177	pub fn der(&self) -> &CertificateDer<'static> {
178		self.certificate.der()
179	}
180}
181
182impl<'a, S> Deref for CertifiedIssuer<'a, S> {
183	type Target = Issuer<'a, S>;
184
185	fn deref(&self) -> &Self::Target {
186		&self.issuer
187	}
188}
189
190impl<'a, S> AsRef<Certificate> for CertifiedIssuer<'a, S> {
191	fn as_ref(&self) -> &Certificate {
192		&self.certificate
193	}
194}
195
196/// An issuer that can sign certificates.
197///
198/// Encapsulates the distinguished name, key identifier method, key usages and signing key
199/// of the issuing certificate.
200pub struct Issuer<'a, S> {
201	distinguished_name: Cow<'a, DistinguishedName>,
202	key_identifier_method: Cow<'a, KeyIdMethod>,
203	key_usages: Cow<'a, [KeyUsagePurpose]>,
204	signing_key: MaybeOwned<'a, S>,
205}
206
207impl<'a, S: SigningKey> Issuer<'a, S> {
208	/// Create a new issuer from the given parameters and signing key.
209	pub fn new(params: CertificateParams, signing_key: S) -> Self {
210		Self {
211			distinguished_name: Cow::Owned(params.distinguished_name),
212			key_identifier_method: Cow::Owned(params.key_identifier_method),
213			key_usages: Cow::Owned(params.key_usages),
214			signing_key: MaybeOwned::Owned(signing_key),
215		}
216	}
217
218	/// Create a new issuer from the given parameters and signing key references.
219	///
220	/// Use [`Issuer::new`] instead if you want to obtain an [`Issuer`] that owns
221	/// its parameters.
222	pub fn from_params(params: &'a CertificateParams, signing_key: &'a S) -> Self {
223		Self {
224			distinguished_name: Cow::Borrowed(&params.distinguished_name),
225			key_identifier_method: Cow::Borrowed(&params.key_identifier_method),
226			key_usages: Cow::Borrowed(&params.key_usages),
227			signing_key: MaybeOwned::Borrowed(signing_key),
228		}
229	}
230
231	/// Parses an existing CA certificate from the ASCII PEM format.
232	///
233	/// See [`from_ca_cert_der`](Self::from_ca_cert_der) for more details.
234	#[cfg(all(feature = "pem", feature = "x509-parser"))]
235	pub fn from_ca_cert_pem(pem_str: &str, signing_key: S) -> Result<Self, Error> {
236		let certificate = pem::parse(pem_str).map_err(|_| Error::CouldNotParseCertificate)?;
237		Self::from_ca_cert_der(&certificate.contents().into(), signing_key)
238	}
239
240	/// Parses an existing CA certificate from the DER format.
241	///
242	/// This function assumes the provided certificate is a CA. It will not check
243	/// for the presence of the `BasicConstraints` extension, or perform any other
244	/// validation.
245	///
246	/// If you already have a byte slice containing DER, it can trivially be converted into
247	/// [`CertificateDer`] using the [`Into`] trait.
248	#[cfg(feature = "x509-parser")]
249	pub fn from_ca_cert_der(ca_cert: &CertificateDer<'_>, signing_key: S) -> Result<Self, Error> {
250		let (_remainder, x509) = x509_parser::parse_x509_certificate(ca_cert)
251			.map_err(|_| Error::CouldNotParseCertificate)?;
252
253		Ok(Self {
254			key_usages: Cow::Owned(KeyUsagePurpose::from_x509(&x509)?),
255			key_identifier_method: Cow::Owned(KeyIdMethod::from_x509(&x509)?),
256			distinguished_name: Cow::Owned(DistinguishedName::from_name(
257				&x509.tbs_certificate.subject,
258			)?),
259			signing_key: MaybeOwned::Owned(signing_key),
260		})
261	}
262
263	/// Allowed key usages for this issuer.
264	pub fn key_usages(&self) -> &[KeyUsagePurpose] {
265		&self.key_usages
266	}
267
268	/// Yield a reference to the signing key.
269	pub fn key(&self) -> &S {
270		&self.signing_key
271	}
272}
273
274impl<'a, S> fmt::Debug for Issuer<'a, S> {
275	/// Formats the issuer information without revealing the key pair.
276	fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
277		// The key pair is omitted from the debug output as it contains secret information.
278		let Issuer {
279			distinguished_name,
280			key_identifier_method,
281			key_usages,
282			signing_key: _,
283		} = self;
284
285		f.debug_struct("Issuer")
286			.field("distinguished_name", distinguished_name)
287			.field("key_identifier_method", key_identifier_method)
288			.field("key_usages", key_usages)
289			.field("signing_key", &"[elided]")
290			.finish()
291	}
292}
293
294enum MaybeOwned<'a, T> {
295	Owned(T),
296	Borrowed(&'a T),
297}
298
299impl<T> Deref for MaybeOwned<'_, T> {
300	type Target = T;
301
302	fn deref(&self) -> &Self::Target {
303		match self {
304			MaybeOwned::Owned(t) => t,
305			MaybeOwned::Borrowed(t) => t,
306		}
307	}
308}
309
310// https://tools.ietf.org/html/rfc5280#section-4.1.1
311
312// Example certs usable as reference:
313// Uses ECDSA: https://crt.sh/?asn1=607203242
314
315#[cfg(feature = "pem")]
316const ENCODE_CONFIG: pem::EncodeConfig = {
317	let line_ending = match cfg!(target_family = "windows") {
318		true => pem::LineEnding::CRLF,
319		false => pem::LineEnding::LF,
320	};
321	pem::EncodeConfig::new().set_line_ending(line_ending)
322};
323
324#[derive(Debug, PartialEq, Eq, Hash, Clone)]
325#[allow(missing_docs)]
326#[non_exhaustive]
327/// The type of subject alt name
328pub enum SanType {
329	/// Also known as E-Mail address
330	Rfc822Name(Ia5String),
331	DnsName(Ia5String),
332	URI(Ia5String),
333	IpAddress(IpAddr),
334	OtherName((Vec<u64>, OtherNameValue)),
335}
336
337impl SanType {
338	#[cfg(all(test, feature = "x509-parser"))]
339	fn from_x509(x509: &x509_parser::certificate::X509Certificate<'_>) -> Result<Vec<Self>, Error> {
340		let sans = x509
341			.subject_alternative_name()
342			.map_err(|_| Error::CouldNotParseCertificate)?
343			.map(|ext| &ext.value.general_names);
344
345		let Some(sans) = sans else {
346			return Ok(Vec::new());
347		};
348
349		let mut subject_alt_names = Vec::with_capacity(sans.len());
350		for san in sans {
351			subject_alt_names.push(Self::try_from_general(san)?);
352		}
353		Ok(subject_alt_names)
354	}
355}
356
357/// An `OtherName` value, defined in [RFC 5280§4.1.2.4].
358///
359/// While the standard specifies this could be any ASN.1 type rcgen limits
360/// the value to a UTF-8 encoded string as this will cover the most common
361/// use cases, for instance smart card user principal names (UPN).
362///
363/// [RFC 5280§4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4
364#[derive(Debug, PartialEq, Eq, Hash, Clone)]
365#[non_exhaustive]
366pub enum OtherNameValue {
367	/// A string encoded using UTF-8
368	Utf8String(String),
369}
370
371impl OtherNameValue {
372	fn write_der(&self, writer: DERWriter) {
373		writer.write_tagged(Tag::context(0), |writer| match self {
374			OtherNameValue::Utf8String(s) => writer.write_utf8_string(s),
375		});
376	}
377}
378
379impl<T> From<T> for OtherNameValue
380where
381	T: Into<String>,
382{
383	fn from(t: T) -> Self {
384		OtherNameValue::Utf8String(t.into())
385	}
386}
387
388#[cfg(feature = "x509-parser")]
389fn ip_addr_from_octets(octets: &[u8]) -> Result<IpAddr, Error> {
390	if let Ok(ipv6_octets) = <&[u8; 16]>::try_from(octets) {
391		Ok(Ipv6Addr::from(*ipv6_octets).into())
392	} else if let Ok(ipv4_octets) = <&[u8; 4]>::try_from(octets) {
393		Ok(Ipv4Addr::from(*ipv4_octets).into())
394	} else {
395		Err(Error::InvalidIpAddressOctetLength(octets.len()))
396	}
397}
398
399impl SanType {
400	#[cfg(feature = "x509-parser")]
401	fn try_from_general(name: &x509_parser::extensions::GeneralName<'_>) -> Result<Self, Error> {
402		use x509_parser::der_parser::asn1_rs::{self, FromDer, Tag, TaggedExplicit};
403		Ok(match name {
404			x509_parser::extensions::GeneralName::RFC822Name(name) => {
405				SanType::Rfc822Name((*name).try_into()?)
406			},
407			x509_parser::extensions::GeneralName::DNSName(name) => {
408				SanType::DnsName((*name).try_into()?)
409			},
410			x509_parser::extensions::GeneralName::URI(name) => SanType::URI((*name).try_into()?),
411			x509_parser::extensions::GeneralName::IPAddress(octets) => {
412				SanType::IpAddress(ip_addr_from_octets(octets)?)
413			},
414			x509_parser::extensions::GeneralName::OtherName(oid, value) => {
415				let oid = oid.iter().ok_or(Error::CouldNotParseCertificate)?;
416				// We first remove the explicit tag ([0] EXPLICIT)
417				let (_, other_name) = TaggedExplicit::<asn1_rs::Any, _, 0>::from_der(value)
418					.map_err(|_| Error::CouldNotParseCertificate)?;
419				let other_name = other_name.into_inner();
420
421				let other_name_value = match other_name.tag() {
422					Tag::Utf8String => OtherNameValue::Utf8String(
423						std::str::from_utf8(other_name.data)
424							.map_err(|_| Error::CouldNotParseCertificate)?
425							.to_owned(),
426					),
427					_ => return Err(Error::CouldNotParseCertificate),
428				};
429				SanType::OtherName((oid.collect(), other_name_value))
430			},
431			_ => return Err(Error::InvalidNameType),
432		})
433	}
434
435	fn tag(&self) -> u64 {
436		// Defined in the GeneralName list in
437		// https://tools.ietf.org/html/rfc5280#page-38
438		const TAG_OTHER_NAME: u64 = 0;
439		const TAG_RFC822_NAME: u64 = 1;
440		const TAG_DNS_NAME: u64 = 2;
441		const TAG_URI: u64 = 6;
442		const TAG_IP_ADDRESS: u64 = 7;
443
444		match self {
445			SanType::Rfc822Name(_name) => TAG_RFC822_NAME,
446			SanType::DnsName(_name) => TAG_DNS_NAME,
447			SanType::URI(_name) => TAG_URI,
448			SanType::IpAddress(_addr) => TAG_IP_ADDRESS,
449			Self::OtherName(_oid) => TAG_OTHER_NAME,
450		}
451	}
452}
453
454/// A distinguished name entry
455#[derive(Debug, PartialEq, Eq, Hash, Clone)]
456#[non_exhaustive]
457pub enum DnValue {
458	/// A string encoded using UCS-2
459	BmpString(BmpString),
460	/// An ASCII string.
461	Ia5String(Ia5String),
462	/// An ASCII string containing only A-Z, a-z, 0-9, '()+,-./:=? and `<SPACE>`
463	PrintableString(PrintableString),
464	/// A string of characters from the T.61 character set
465	TeletexString(TeletexString),
466	/// A string encoded using UTF-32
467	UniversalString(UniversalString),
468	/// A string encoded using UTF-8
469	Utf8String(String),
470}
471
472impl<T> From<T> for DnValue
473where
474	T: Into<String>,
475{
476	fn from(t: T) -> Self {
477		DnValue::Utf8String(t.into())
478	}
479}
480
481#[derive(Debug, Default, PartialEq, Eq, Clone)]
482/**
483Distinguished name used e.g. for the issuer and subject fields of a certificate
484
485A distinguished name is a set of (attribute type, attribute value) tuples.
486
487This datastructure keeps them ordered by insertion order.
488
489See also the RFC 5280 sections on the [issuer](https://tools.ietf.org/html/rfc5280#section-4.1.2.4)
490and [subject](https://tools.ietf.org/html/rfc5280#section-4.1.2.6) fields.
491*/
492pub struct DistinguishedName {
493	entries: HashMap<DnType, DnValue>,
494	order: Vec<DnType>,
495}
496
497impl DistinguishedName {
498	/// Creates a new, empty distinguished name
499	pub fn new() -> Self {
500		Self::default()
501	}
502	/// Obtains the attribute value for the given attribute type
503	pub fn get(&self, ty: &DnType) -> Option<&DnValue> {
504		self.entries.get(ty)
505	}
506	/// Removes the attribute with the specified DnType
507	///
508	/// Returns true when an actual removal happened, false
509	/// when no attribute with the specified DnType was
510	/// found.
511	pub fn remove(&mut self, ty: DnType) -> bool {
512		let removed = self.entries.remove(&ty).is_some();
513		if removed {
514			self.order.retain(|ty_o| &ty != ty_o);
515		}
516		removed
517	}
518	/// Inserts or updates an attribute that consists of type and name
519	///
520	/// ```
521	/// # use rcgen::{DistinguishedName, DnType, DnValue};
522	/// let mut dn = DistinguishedName::new();
523	/// dn.push(DnType::OrganizationName, "Crab widgits SE");
524	/// dn.push(DnType::CommonName, DnValue::PrintableString("Master Cert".try_into().unwrap()));
525	/// assert_eq!(dn.get(&DnType::OrganizationName), Some(&DnValue::Utf8String("Crab widgits SE".to_string())));
526	/// assert_eq!(dn.get(&DnType::CommonName), Some(&DnValue::PrintableString("Master Cert".try_into().unwrap())));
527	/// ```
528	pub fn push(&mut self, ty: DnType, s: impl Into<DnValue>) {
529		if !self.entries.contains_key(&ty) {
530			self.order.push(ty.clone());
531		}
532		self.entries.insert(ty, s.into());
533	}
534	/// Iterate over the entries
535	pub fn iter(&self) -> DistinguishedNameIterator<'_> {
536		DistinguishedNameIterator {
537			distinguished_name: self,
538			iter: self.order.iter(),
539		}
540	}
541
542	#[cfg(feature = "x509-parser")]
543	fn from_name(name: &x509_parser::x509::X509Name) -> Result<Self, Error> {
544		use x509_parser::der_parser::asn1_rs::Tag;
545
546		let mut dn = DistinguishedName::new();
547		for rdn in name.iter() {
548			let mut rdn_iter = rdn.iter();
549			let dn_opt = rdn_iter.next();
550			let attr = if let Some(dn) = dn_opt {
551				if rdn_iter.next().is_some() {
552					// no support for distinguished names with more than one attribute
553					return Err(Error::CouldNotParseCertificate);
554				} else {
555					dn
556				}
557			} else {
558				panic!("x509-parser distinguished name set is empty");
559			};
560
561			let attr_type_oid = attr
562				.attr_type()
563				.iter()
564				.ok_or(Error::CouldNotParseCertificate)?;
565			let dn_type = DnType::from_oid(&attr_type_oid.collect::<Vec<_>>());
566			let data = attr.attr_value().data;
567			let try_str =
568				|data| std::str::from_utf8(data).map_err(|_| Error::CouldNotParseCertificate);
569			let dn_value = match attr.attr_value().header.tag() {
570				Tag::BmpString => DnValue::BmpString(BmpString::from_utf16be(data.to_vec())?),
571				Tag::Ia5String => DnValue::Ia5String(try_str(data)?.try_into()?),
572				Tag::PrintableString => DnValue::PrintableString(try_str(data)?.try_into()?),
573				Tag::T61String => DnValue::TeletexString(try_str(data)?.try_into()?),
574				Tag::UniversalString => {
575					DnValue::UniversalString(UniversalString::from_utf32be(data.to_vec())?)
576				},
577				Tag::Utf8String => DnValue::Utf8String(try_str(data)?.to_owned()),
578				_ => return Err(Error::CouldNotParseCertificate),
579			};
580
581			dn.push(dn_type, dn_value);
582		}
583		Ok(dn)
584	}
585}
586
587/**
588Iterator over [`DistinguishedName`] entries
589*/
590#[derive(Clone, Debug)]
591pub struct DistinguishedNameIterator<'a> {
592	distinguished_name: &'a DistinguishedName,
593	iter: std::slice::Iter<'a, DnType>,
594}
595
596impl<'a> Iterator for DistinguishedNameIterator<'a> {
597	type Item = (&'a DnType, &'a DnValue);
598
599	fn next(&mut self) -> Option<Self::Item> {
600		self.iter
601			.next()
602			.and_then(|ty| self.distinguished_name.entries.get(ty).map(|v| (ty, v)))
603	}
604}
605
606/// One of the purposes contained in the [key usage](https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3) extension
607#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
608pub enum KeyUsagePurpose {
609	/// digitalSignature
610	DigitalSignature,
611	/// contentCommitment / nonRepudiation
612	ContentCommitment,
613	/// keyEncipherment
614	KeyEncipherment,
615	/// dataEncipherment
616	DataEncipherment,
617	/// keyAgreement
618	KeyAgreement,
619	/// keyCertSign
620	KeyCertSign,
621	/// cRLSign
622	CrlSign,
623	/// encipherOnly
624	EncipherOnly,
625	/// decipherOnly
626	DecipherOnly,
627}
628
629impl KeyUsagePurpose {
630	#[cfg(feature = "x509-parser")]
631	fn from_x509(x509: &x509_parser::certificate::X509Certificate<'_>) -> Result<Vec<Self>, Error> {
632		let key_usage = x509
633			.key_usage()
634			.map_err(|_| Error::CouldNotParseCertificate)?
635			.map(|ext| ext.value);
636		// This x509 parser stores flags in reversed bit BIT STRING order
637		let flags = key_usage.map_or(0u16, |k| k.flags).reverse_bits();
638		Ok(Self::from_u16(flags))
639	}
640
641	/// Encode a key usage as the value of a BIT STRING as defined by RFC 5280.
642	/// [`u16`] is sufficient to encode the largest possible key usage value (two bytes).
643	fn to_u16(self) -> u16 {
644		const FLAG: u16 = 0b1000_0000_0000_0000;
645		FLAG >> match self {
646			KeyUsagePurpose::DigitalSignature => 0,
647			KeyUsagePurpose::ContentCommitment => 1,
648			KeyUsagePurpose::KeyEncipherment => 2,
649			KeyUsagePurpose::DataEncipherment => 3,
650			KeyUsagePurpose::KeyAgreement => 4,
651			KeyUsagePurpose::KeyCertSign => 5,
652			KeyUsagePurpose::CrlSign => 6,
653			KeyUsagePurpose::EncipherOnly => 7,
654			KeyUsagePurpose::DecipherOnly => 8,
655		}
656	}
657
658	/// Parse a collection of key usages from a [`u16`] representing the value
659	/// of a KeyUsage BIT STRING as defined by RFC 5280.
660	#[cfg(feature = "x509-parser")]
661	fn from_u16(value: u16) -> Vec<Self> {
662		[
663			KeyUsagePurpose::DigitalSignature,
664			KeyUsagePurpose::ContentCommitment,
665			KeyUsagePurpose::KeyEncipherment,
666			KeyUsagePurpose::DataEncipherment,
667			KeyUsagePurpose::KeyAgreement,
668			KeyUsagePurpose::KeyCertSign,
669			KeyUsagePurpose::CrlSign,
670			KeyUsagePurpose::EncipherOnly,
671			KeyUsagePurpose::DecipherOnly,
672		]
673		.iter()
674		.filter_map(|key_usage| {
675			let present = key_usage.to_u16() & value != 0;
676			present.then_some(*key_usage)
677		})
678		.collect()
679	}
680}
681
682/// Method to generate key identifiers from public keys.
683///
684/// Key identifiers should be derived from the public key data. [RFC 7093] defines
685/// three methods to do so using a choice of SHA256 (method 1), SHA384 (method 2), or SHA512
686/// (method 3). In each case the first 160 bits of the hash are used as the key identifier
687/// to match the output length that would be produced were SHA1 used (a legacy option defined
688/// in RFC 5280).
689///
690/// In addition to the RFC 7093 mechanisms, rcgen supports using a pre-specified key identifier.
691/// This can be helpful when working with an existing `Certificate`.
692///
693/// [RFC 7093]: https://www.rfc-editor.org/rfc/rfc7093
694#[derive(Debug, PartialEq, Eq, Hash, Clone)]
695#[non_exhaustive]
696pub enum KeyIdMethod {
697	/// RFC 7093 method 1 - a truncated SHA256 digest.
698	#[cfg(feature = "crypto")]
699	Sha256,
700	/// RFC 7093 method 2 - a truncated SHA384 digest.
701	#[cfg(feature = "crypto")]
702	Sha384,
703	/// RFC 7093 method 3 - a truncated SHA512 digest.
704	#[cfg(feature = "crypto")]
705	Sha512,
706	/// Pre-specified identifier. The exact given value is used as the key identifier.
707	PreSpecified(Vec<u8>),
708}
709
710impl KeyIdMethod {
711	#[cfg(feature = "x509-parser")]
712	fn from_x509(x509: &x509_parser::certificate::X509Certificate<'_>) -> Result<Self, Error> {
713		let key_identifier_method =
714			x509.iter_extensions()
715				.find_map(|ext| match ext.parsed_extension() {
716					x509_parser::extensions::ParsedExtension::SubjectKeyIdentifier(key_id) => {
717						Some(KeyIdMethod::PreSpecified(key_id.0.into()))
718					},
719					_ => None,
720				});
721
722		Ok(match key_identifier_method {
723			Some(method) => method,
724			None => {
725				#[cfg(not(feature = "crypto"))]
726				return Err(Error::UnsupportedSignatureAlgorithm);
727				#[cfg(feature = "crypto")]
728				KeyIdMethod::Sha256
729			},
730		})
731	}
732
733	/// Derive a key identifier for the provided subject public key info using the key ID method.
734	///
735	/// Typically this is a truncated hash over the raw subject public key info, but may
736	/// be a pre-specified value.
737	///
738	/// This key identifier is used in the SubjectKeyIdentifier and AuthorityKeyIdentifier
739	/// X.509v3 extensions.
740	#[allow(unused_variables)]
741	pub(crate) fn derive(&self, subject_public_key_info: impl AsRef<[u8]>) -> Vec<u8> {
742		#[cfg_attr(not(feature = "crypto"), expect(clippy::let_unit_value))]
743		let digest_method = match &self {
744			#[cfg(feature = "crypto")]
745			Self::Sha256 => &digest::SHA256,
746			#[cfg(feature = "crypto")]
747			Self::Sha384 => &digest::SHA384,
748			#[cfg(feature = "crypto")]
749			Self::Sha512 => &digest::SHA512,
750			Self::PreSpecified(b) => {
751				return b.to_vec();
752			},
753		};
754		#[cfg(feature = "crypto")]
755		{
756			let digest = digest::digest(digest_method, subject_public_key_info.as_ref());
757			digest.as_ref()[0..20].to_vec()
758		}
759	}
760}
761
762fn dt_strip_nanos(dt: OffsetDateTime) -> OffsetDateTime {
763	// Set nanoseconds to zero
764	// This is needed because the GeneralizedTime serializer would otherwise
765	// output fractional values which RFC 5280 explicitly forbode [1].
766	// UTCTime cannot express fractional seconds or leap seconds
767	// therefore, it needs to be stripped of nanoseconds fully.
768	// [1]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
769	// TODO: handle leap seconds if dt becomes leap second aware
770	let time =
771		Time::from_hms(dt.hour(), dt.minute(), dt.second()).expect("invalid or out-of-range time");
772	dt.replace_time(time)
773}
774
775fn dt_to_generalized(dt: OffsetDateTime) -> GeneralizedTime {
776	let date_time = dt_strip_nanos(dt);
777	GeneralizedTime::from_datetime(date_time)
778}
779
780fn write_dt_utc_or_generalized(writer: DERWriter, dt: OffsetDateTime) {
781	// RFC 5280 requires CAs to write certificate validity dates
782	// below 2050 as UTCTime, and anything starting from 2050
783	// as GeneralizedTime [1]. The RFC doesn't say anything
784	// about dates before 1950, but as UTCTime can't represent
785	// them, we have to use GeneralizedTime if we want to or not.
786	// [1]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5
787	if (1950..2050).contains(&dt.year()) {
788		let date_time = dt_strip_nanos(dt);
789		let ut = UTCTime::from_datetime(date_time);
790		writer.write_utctime(&ut);
791	} else {
792		let gt = dt_to_generalized(dt);
793		writer.write_generalized_time(&gt);
794	}
795}
796
797fn write_distinguished_name(writer: DERWriter, dn: &DistinguishedName) {
798	writer.write_sequence(|writer| {
799		for (ty, content) in dn.iter() {
800			writer.next().write_set(|writer| {
801				writer.next().write_sequence(|writer| {
802					writer.next().write_oid(&ty.to_oid());
803					match content {
804						DnValue::BmpString(s) => writer
805							.next()
806							.write_tagged_implicit(TAG_BMPSTRING, |writer| {
807								writer.write_bytes(s.as_bytes())
808							}),
809
810						DnValue::Ia5String(s) => writer.next().write_ia5_string(s.as_str()),
811
812						DnValue::PrintableString(s) => {
813							writer.next().write_printable_string(s.as_str())
814						},
815						DnValue::TeletexString(s) => writer
816							.next()
817							.write_tagged_implicit(TAG_TELETEXSTRING, |writer| {
818								writer.write_bytes(s.as_bytes())
819							}),
820						DnValue::UniversalString(s) => writer
821							.next()
822							.write_tagged_implicit(TAG_UNIVERSALSTRING, |writer| {
823								writer.write_bytes(s.as_bytes())
824							}),
825						DnValue::Utf8String(s) => writer.next().write_utf8_string(s),
826					}
827				});
828			});
829		}
830	});
831}
832
833/// Serializes an X.509v3 extension according to RFC 5280
834fn write_x509_extension(
835	writer: DERWriter,
836	extension_oid: &[u64],
837	is_critical: bool,
838	value_serializer: impl FnOnce(DERWriter),
839) {
840	// Extension specification:
841	//    Extension  ::=  SEQUENCE  {
842	//         extnID      OBJECT IDENTIFIER,
843	//         critical    BOOLEAN DEFAULT FALSE,
844	//         extnValue   OCTET STRING
845	//                     -- contains the DER encoding of an ASN.1 value
846	//                     -- corresponding to the extension type identified
847	//                     -- by extnID
848	//         }
849
850	writer.write_sequence(|writer| {
851		let oid = ObjectIdentifier::from_slice(extension_oid);
852		writer.next().write_oid(&oid);
853		if is_critical {
854			writer.next().write_bool(true);
855		}
856		let bytes = yasna::construct_der(value_serializer);
857		writer.next().write_bytes(&bytes);
858	})
859}
860
861/// Serializes an X.509v3 authority key identifier extension according to RFC 5280.
862fn write_x509_authority_key_identifier(writer: DERWriter, aki: Vec<u8>) {
863	// Write Authority Key Identifier
864	// RFC 5280 states:
865	//   'The keyIdentifier field of the authorityKeyIdentifier extension MUST
866	//    be included in all certificates generated by conforming CAs to
867	//    facilitate certification path construction.  There is one exception;
868	//    where a CA distributes its public key in the form of a "self-signed"
869	//    certificate, the authority key identifier MAY be omitted.'
870	// In addition, for CRLs:
871	//    'Conforming CRL issuers MUST use the key identifier method, and MUST
872	//     include this extension in all CRLs issued.'
873	write_x509_extension(writer, oid::AUTHORITY_KEY_IDENTIFIER, false, |writer| {
874		writer.write_sequence(|writer| {
875			writer
876				.next()
877				.write_tagged_implicit(Tag::context(0), |writer| writer.write_bytes(&aki))
878		});
879	});
880}
881
882#[cfg(feature = "zeroize")]
883impl zeroize::Zeroize for KeyPair {
884	fn zeroize(&mut self) {
885		self.serialized_der.zeroize();
886	}
887}
888
889/// A certificate serial number.
890#[derive(Debug, PartialEq, Eq, Hash, Clone)]
891pub struct SerialNumber {
892	inner: Vec<u8>,
893}
894
895#[allow(clippy::len_without_is_empty)]
896impl SerialNumber {
897	/// Create a serial number from the given byte slice.
898	pub fn from_slice(bytes: &[u8]) -> SerialNumber {
899		let inner = bytes.to_vec();
900		SerialNumber { inner }
901	}
902
903	/// Return the byte representation of the serial number.
904	pub fn to_bytes(&self) -> Vec<u8> {
905		self.inner.clone()
906	}
907
908	/// Return the length of the serial number in bytes.
909	pub fn len(&self) -> usize {
910		self.inner.len()
911	}
912}
913
914impl fmt::Display for SerialNumber {
915	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
916		let hex: Vec<_> = self.inner.iter().map(|b| format!("{b:02x}")).collect();
917		write!(f, "{}", hex.join(":"))
918	}
919}
920
921impl From<Vec<u8>> for SerialNumber {
922	fn from(inner: Vec<u8>) -> SerialNumber {
923		SerialNumber { inner }
924	}
925}
926
927impl From<u64> for SerialNumber {
928	fn from(u: u64) -> SerialNumber {
929		let inner = u.to_be_bytes().into();
930		SerialNumber { inner }
931	}
932}
933
934impl AsRef<[u8]> for SerialNumber {
935	fn as_ref(&self) -> &[u8] {
936		&self.inner
937	}
938}
939
940#[cfg(test)]
941mod tests {
942	use std::panic::catch_unwind;
943
944	use time::{Date, Month, PrimitiveDateTime};
945
946	use super::*;
947
948	fn times() -> [OffsetDateTime; 2] {
949		let dt_nanos = {
950			let date = Date::from_calendar_date(2020, Month::December, 3).unwrap();
951			let time = Time::from_hms_nano(0, 0, 1, 444).unwrap();
952			PrimitiveDateTime::new(date, time).assume_utc()
953		};
954		let dt_zero = {
955			let date = Date::from_calendar_date(2020, Month::December, 3).unwrap();
956			let time = Time::from_hms_nano(0, 0, 1, 0).unwrap();
957			PrimitiveDateTime::new(date, time).assume_utc()
958		};
959		// TODO: include leap seconds if time becomes leap second aware
960		[dt_nanos, dt_zero]
961	}
962
963	#[test]
964	fn test_dt_utc_strip_nanos() {
965		let times = times();
966
967		// No stripping - OffsetDateTime with nanos
968		let res = catch_unwind(|| UTCTime::from_datetime(times[0]));
969		assert!(res.is_err());
970
971		// Stripping
972		for dt in times {
973			let date_time = dt_strip_nanos(dt);
974			assert_eq!(date_time.time().nanosecond(), 0);
975			let _ut = UTCTime::from_datetime(date_time);
976		}
977	}
978
979	#[test]
980	fn test_dt_to_generalized() {
981		let times = times();
982
983		for dt in times {
984			let _gt = dt_to_generalized(dt);
985		}
986	}
987
988	#[test]
989	fn signature_algos_different() {
990		// TODO unify this with test_key_params_mismatch.
991		// Note that that test doesn't have a full list of signature
992		// algorithms, as it has no access to the iter function.
993		for (i, alg_i) in SignatureAlgorithm::iter().enumerate() {
994			for (j, alg_j) in SignatureAlgorithm::iter().enumerate() {
995				assert_eq!(
996					alg_i == alg_j,
997					i == j,
998					"Algorithm relationship mismatch for algorithm index pair {i} and {j}"
999				);
1000			}
1001		}
1002	}
1003
1004	#[cfg(feature = "x509-parser")]
1005	mod test_ip_address_from_octets {
1006		use super::super::ip_addr_from_octets;
1007		use super::super::Error;
1008		use std::net::IpAddr;
1009
1010		#[test]
1011		fn ipv4() {
1012			let octets = [10, 20, 30, 40];
1013
1014			let actual = ip_addr_from_octets(&octets).unwrap();
1015
1016			assert_eq!(IpAddr::from(octets), actual)
1017		}
1018
1019		#[test]
1020		fn ipv6() {
1021			let octets = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
1022
1023			let actual = ip_addr_from_octets(&octets).unwrap();
1024
1025			assert_eq!(IpAddr::from(octets), actual)
1026		}
1027
1028		#[test]
1029		fn mismatch() {
1030			let incorrect = Vec::from_iter(0..10);
1031			let actual = ip_addr_from_octets(&incorrect).unwrap_err();
1032
1033			assert_eq!(Error::InvalidIpAddressOctetLength(10), actual);
1034		}
1035
1036		#[test]
1037		fn none() {
1038			let actual = ip_addr_from_octets(&[]).unwrap_err();
1039
1040			assert_eq!(Error::InvalidIpAddressOctetLength(0), actual);
1041		}
1042
1043		#[test]
1044		fn too_many() {
1045			let incorrect = Vec::from_iter(0..20);
1046			let actual = ip_addr_from_octets(&incorrect).unwrap_err();
1047
1048			assert_eq!(Error::InvalidIpAddressOctetLength(20), actual);
1049		}
1050	}
1051
1052	#[cfg(feature = "x509-parser")]
1053	mod test_san_type_from_general_name {
1054		use crate::SanType;
1055		use std::net::IpAddr;
1056		use x509_parser::extensions::GeneralName;
1057
1058		#[test]
1059		fn with_ipv4() {
1060			let octets = [1, 2, 3, 4];
1061			let value = GeneralName::IPAddress(&octets);
1062			let actual = SanType::try_from_general(&value).unwrap();
1063
1064			assert_eq!(SanType::IpAddress(IpAddr::from(octets)), actual);
1065		}
1066	}
1067}