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