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: 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,
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: 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,
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,
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
294// https://tools.ietf.org/html/rfc5280#section-4.1.1
295
296// Example certs usable as reference:
297// Uses ECDSA: https://crt.sh/?asn1=607203242
298
299#[cfg(feature = "pem")]
300const ENCODE_CONFIG: pem::EncodeConfig = {
301	let line_ending = match cfg!(target_family = "windows") {
302		true => pem::LineEnding::CRLF,
303		false => pem::LineEnding::LF,
304	};
305	pem::EncodeConfig::new().set_line_ending(line_ending)
306};
307
308#[derive(Debug, PartialEq, Eq, Hash, Clone)]
309#[allow(missing_docs)]
310#[non_exhaustive]
311/// The type of subject alt name
312pub enum SanType {
313	/// Also known as E-Mail address
314	Rfc822Name(Ia5String),
315	DnsName(Ia5String),
316	URI(Ia5String),
317	IpAddress(IpAddr),
318	OtherName((Vec<u64>, OtherNameValue)),
319}
320
321impl SanType {
322	#[cfg(all(test, feature = "x509-parser"))]
323	fn from_x509(x509: &x509_parser::certificate::X509Certificate<'_>) -> Result<Vec<Self>, Error> {
324		let sans = x509
325			.subject_alternative_name()
326			.map_err(|_| Error::CouldNotParseCertificate)?
327			.map(|ext| &ext.value.general_names);
328
329		let Some(sans) = sans else {
330			return Ok(Vec::new());
331		};
332
333		let mut subject_alt_names = Vec::with_capacity(sans.len());
334		for san in sans {
335			subject_alt_names.push(Self::try_from_general(san)?);
336		}
337		Ok(subject_alt_names)
338	}
339}
340
341/// An `OtherName` value, defined in [RFC 5280§4.1.2.4].
342///
343/// While the standard specifies this could be any ASN.1 type rcgen limits
344/// the value to a UTF-8 encoded string as this will cover the most common
345/// use cases, for instance smart card user principal names (UPN).
346///
347/// [RFC 5280§4.1.2.4]: https://datatracker.ietf.org/doc/html/rfc5280#section-4.1.2.4
348#[derive(Debug, PartialEq, Eq, Hash, Clone)]
349#[non_exhaustive]
350pub enum OtherNameValue {
351	/// A string encoded using UTF-8
352	Utf8String(String),
353}
354
355impl OtherNameValue {
356	fn write_der(&self, writer: DERWriter) {
357		writer.write_tagged(Tag::context(0), |writer| match self {
358			OtherNameValue::Utf8String(s) => writer.write_utf8_string(s),
359		});
360	}
361}
362
363impl<T> From<T> for OtherNameValue
364where
365	T: Into<String>,
366{
367	fn from(t: T) -> Self {
368		OtherNameValue::Utf8String(t.into())
369	}
370}
371
372#[cfg(feature = "x509-parser")]
373fn ip_addr_from_octets(octets: &[u8]) -> Result<IpAddr, Error> {
374	if let Ok(ipv6_octets) = <&[u8; 16]>::try_from(octets) {
375		Ok(Ipv6Addr::from(*ipv6_octets).into())
376	} else if let Ok(ipv4_octets) = <&[u8; 4]>::try_from(octets) {
377		Ok(Ipv4Addr::from(*ipv4_octets).into())
378	} else {
379		Err(Error::InvalidIpAddressOctetLength(octets.len()))
380	}
381}
382
383impl SanType {
384	#[cfg(feature = "x509-parser")]
385	fn try_from_general(name: &x509_parser::extensions::GeneralName<'_>) -> Result<Self, Error> {
386		use x509_parser::der_parser::asn1_rs::{self, FromDer, Tag, TaggedExplicit};
387		Ok(match name {
388			x509_parser::extensions::GeneralName::RFC822Name(name) => {
389				SanType::Rfc822Name((*name).try_into()?)
390			},
391			x509_parser::extensions::GeneralName::DNSName(name) => {
392				SanType::DnsName((*name).try_into()?)
393			},
394			x509_parser::extensions::GeneralName::URI(name) => SanType::URI((*name).try_into()?),
395			x509_parser::extensions::GeneralName::IPAddress(octets) => {
396				SanType::IpAddress(ip_addr_from_octets(octets)?)
397			},
398			x509_parser::extensions::GeneralName::OtherName(oid, value) => {
399				let oid = oid.iter().ok_or(Error::CouldNotParseCertificate)?;
400				// We first remove the explicit tag ([0] EXPLICIT)
401				let (_, other_name) = TaggedExplicit::<asn1_rs::Any, _, 0>::from_der(value)
402					.map_err(|_| Error::CouldNotParseCertificate)?;
403				let other_name = other_name.into_inner();
404
405				let other_name_value = match other_name.tag() {
406					Tag::Utf8String => OtherNameValue::Utf8String(
407						std::str::from_utf8(other_name.data)
408							.map_err(|_| Error::CouldNotParseCertificate)?
409							.to_owned(),
410					),
411					_ => return Err(Error::CouldNotParseCertificate),
412				};
413				SanType::OtherName((oid.collect(), other_name_value))
414			},
415			_ => return Err(Error::InvalidNameType),
416		})
417	}
418
419	fn tag(&self) -> u64 {
420		// Defined in the GeneralName list in
421		// https://tools.ietf.org/html/rfc5280#page-38
422		const TAG_OTHER_NAME: u64 = 0;
423		const TAG_RFC822_NAME: u64 = 1;
424		const TAG_DNS_NAME: u64 = 2;
425		const TAG_URI: u64 = 6;
426		const TAG_IP_ADDRESS: u64 = 7;
427
428		match self {
429			SanType::Rfc822Name(_name) => TAG_RFC822_NAME,
430			SanType::DnsName(_name) => TAG_DNS_NAME,
431			SanType::URI(_name) => TAG_URI,
432			SanType::IpAddress(_addr) => TAG_IP_ADDRESS,
433			Self::OtherName(_oid) => TAG_OTHER_NAME,
434		}
435	}
436}
437
438/// A distinguished name entry
439#[derive(Debug, PartialEq, Eq, Hash, Clone)]
440#[non_exhaustive]
441pub enum DnValue {
442	/// A string encoded using UCS-2
443	BmpString(BmpString),
444	/// An ASCII string.
445	Ia5String(Ia5String),
446	/// An ASCII string containing only A-Z, a-z, 0-9, '()+,-./:=? and `<SPACE>`
447	PrintableString(PrintableString),
448	/// A string of characters from the T.61 character set
449	TeletexString(TeletexString),
450	/// A string encoded using UTF-32
451	UniversalString(UniversalString),
452	/// A string encoded using UTF-8
453	Utf8String(String),
454}
455
456impl<T> From<T> for DnValue
457where
458	T: Into<String>,
459{
460	fn from(t: T) -> Self {
461		DnValue::Utf8String(t.into())
462	}
463}
464
465#[derive(Debug, Default, PartialEq, Eq, Clone)]
466/**
467Distinguished name used e.g. for the issuer and subject fields of a certificate
468
469A distinguished name is a set of (attribute type, attribute value) tuples.
470
471This datastructure keeps them ordered by insertion order.
472
473See also the RFC 5280 sections on the [issuer](https://tools.ietf.org/html/rfc5280#section-4.1.2.4)
474and [subject](https://tools.ietf.org/html/rfc5280#section-4.1.2.6) fields.
475*/
476pub struct DistinguishedName {
477	entries: HashMap<DnType, DnValue>,
478	order: Vec<DnType>,
479}
480
481impl DistinguishedName {
482	/// Creates a new, empty distinguished name
483	pub fn new() -> Self {
484		Self::default()
485	}
486	/// Obtains the attribute value for the given attribute type
487	pub fn get(&self, ty: &DnType) -> Option<&DnValue> {
488		self.entries.get(ty)
489	}
490	/// Removes the attribute with the specified DnType
491	///
492	/// Returns true when an actual removal happened, false
493	/// when no attribute with the specified DnType was
494	/// found.
495	pub fn remove(&mut self, ty: DnType) -> bool {
496		let removed = self.entries.remove(&ty).is_some();
497		if removed {
498			self.order.retain(|ty_o| &ty != ty_o);
499		}
500		removed
501	}
502	/// Inserts or updates an attribute that consists of type and name
503	///
504	/// ```
505	/// # use rcgen::{DistinguishedName, DnType, DnValue};
506	/// let mut dn = DistinguishedName::new();
507	/// dn.push(DnType::OrganizationName, "Crab widgits SE");
508	/// dn.push(DnType::CommonName, DnValue::PrintableString("Master Cert".try_into().unwrap()));
509	/// assert_eq!(dn.get(&DnType::OrganizationName), Some(&DnValue::Utf8String("Crab widgits SE".to_string())));
510	/// assert_eq!(dn.get(&DnType::CommonName), Some(&DnValue::PrintableString("Master Cert".try_into().unwrap())));
511	/// ```
512	pub fn push(&mut self, ty: DnType, s: impl Into<DnValue>) {
513		if !self.entries.contains_key(&ty) {
514			self.order.push(ty.clone());
515		}
516		self.entries.insert(ty, s.into());
517	}
518	/// Iterate over the entries
519	pub fn iter(&self) -> DistinguishedNameIterator<'_> {
520		DistinguishedNameIterator {
521			distinguished_name: self,
522			iter: self.order.iter(),
523		}
524	}
525
526	#[cfg(feature = "x509-parser")]
527	fn from_name(name: &x509_parser::x509::X509Name) -> Result<Self, Error> {
528		use x509_parser::der_parser::asn1_rs::Tag;
529
530		let mut dn = DistinguishedName::new();
531		for rdn in name.iter() {
532			let mut rdn_iter = rdn.iter();
533			let dn_opt = rdn_iter.next();
534			let attr = if let Some(dn) = dn_opt {
535				if rdn_iter.next().is_some() {
536					// no support for distinguished names with more than one attribute
537					return Err(Error::CouldNotParseCertificate);
538				} else {
539					dn
540				}
541			} else {
542				panic!("x509-parser distinguished name set is empty");
543			};
544
545			let attr_type_oid = attr
546				.attr_type()
547				.iter()
548				.ok_or(Error::CouldNotParseCertificate)?;
549			let dn_type = DnType::from_oid(&attr_type_oid.collect::<Vec<_>>());
550			let data = attr.attr_value().data;
551			let try_str =
552				|data| std::str::from_utf8(data).map_err(|_| Error::CouldNotParseCertificate);
553			let dn_value = match attr.attr_value().header.tag() {
554				Tag::BmpString => DnValue::BmpString(BmpString::from_utf16be(data.to_vec())?),
555				Tag::Ia5String => DnValue::Ia5String(try_str(data)?.try_into()?),
556				Tag::PrintableString => DnValue::PrintableString(try_str(data)?.try_into()?),
557				Tag::T61String => DnValue::TeletexString(try_str(data)?.try_into()?),
558				Tag::UniversalString => {
559					DnValue::UniversalString(UniversalString::from_utf32be(data.to_vec())?)
560				},
561				Tag::Utf8String => DnValue::Utf8String(try_str(data)?.to_owned()),
562				_ => return Err(Error::CouldNotParseCertificate),
563			};
564
565			dn.push(dn_type, dn_value);
566		}
567		Ok(dn)
568	}
569}
570
571/**
572Iterator over [`DistinguishedName`] entries
573*/
574#[derive(Clone, Debug)]
575pub struct DistinguishedNameIterator<'a> {
576	distinguished_name: &'a DistinguishedName,
577	iter: std::slice::Iter<'a, DnType>,
578}
579
580impl<'a> Iterator for DistinguishedNameIterator<'a> {
581	type Item = (&'a DnType, &'a DnValue);
582
583	fn next(&mut self) -> Option<Self::Item> {
584		self.iter
585			.next()
586			.and_then(|ty| self.distinguished_name.entries.get(ty).map(|v| (ty, v)))
587	}
588}
589
590/// One of the purposes contained in the [key usage](https://datatracker.ietf.org/doc/html/rfc5280#section-4.2.1.3) extension
591#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
592pub enum KeyUsagePurpose {
593	/// digitalSignature
594	DigitalSignature,
595	/// contentCommitment / nonRepudiation
596	ContentCommitment,
597	/// keyEncipherment
598	KeyEncipherment,
599	/// dataEncipherment
600	DataEncipherment,
601	/// keyAgreement
602	KeyAgreement,
603	/// keyCertSign
604	KeyCertSign,
605	/// cRLSign
606	CrlSign,
607	/// encipherOnly
608	EncipherOnly,
609	/// decipherOnly
610	DecipherOnly,
611}
612
613impl KeyUsagePurpose {
614	#[cfg(feature = "x509-parser")]
615	fn from_x509(x509: &x509_parser::certificate::X509Certificate<'_>) -> Result<Vec<Self>, Error> {
616		let key_usage = x509
617			.key_usage()
618			.map_err(|_| Error::CouldNotParseCertificate)?
619			.map(|ext| ext.value);
620		// This x509 parser stores flags in reversed bit BIT STRING order
621		let flags = key_usage.map_or(0u16, |k| k.flags).reverse_bits();
622		Ok(Self::from_u16(flags))
623	}
624
625	/// Encode a key usage as the value of a BIT STRING as defined by RFC 5280.
626	/// [`u16`] is sufficient to encode the largest possible key usage value (two bytes).
627	fn to_u16(self) -> u16 {
628		const FLAG: u16 = 0b1000_0000_0000_0000;
629		FLAG >> match self {
630			KeyUsagePurpose::DigitalSignature => 0,
631			KeyUsagePurpose::ContentCommitment => 1,
632			KeyUsagePurpose::KeyEncipherment => 2,
633			KeyUsagePurpose::DataEncipherment => 3,
634			KeyUsagePurpose::KeyAgreement => 4,
635			KeyUsagePurpose::KeyCertSign => 5,
636			KeyUsagePurpose::CrlSign => 6,
637			KeyUsagePurpose::EncipherOnly => 7,
638			KeyUsagePurpose::DecipherOnly => 8,
639		}
640	}
641
642	/// Parse a collection of key usages from a [`u16`] representing the value
643	/// of a KeyUsage BIT STRING as defined by RFC 5280.
644	#[cfg(feature = "x509-parser")]
645	fn from_u16(value: u16) -> Vec<Self> {
646		[
647			KeyUsagePurpose::DigitalSignature,
648			KeyUsagePurpose::ContentCommitment,
649			KeyUsagePurpose::KeyEncipherment,
650			KeyUsagePurpose::DataEncipherment,
651			KeyUsagePurpose::KeyAgreement,
652			KeyUsagePurpose::KeyCertSign,
653			KeyUsagePurpose::CrlSign,
654			KeyUsagePurpose::EncipherOnly,
655			KeyUsagePurpose::DecipherOnly,
656		]
657		.iter()
658		.filter_map(|key_usage| {
659			let present = key_usage.to_u16() & value != 0;
660			present.then_some(*key_usage)
661		})
662		.collect()
663	}
664}
665
666/// Method to generate key identifiers from public keys.
667///
668/// Key identifiers should be derived from the public key data. [RFC 7093] defines
669/// three methods to do so using a choice of SHA256 (method 1), SHA384 (method 2), or SHA512
670/// (method 3). In each case the first 160 bits of the hash are used as the key identifier
671/// to match the output length that would be produced were SHA1 used (a legacy option defined
672/// in RFC 5280).
673///
674/// In addition to the RFC 7093 mechanisms, rcgen supports using a pre-specified key identifier.
675/// This can be helpful when working with an existing `Certificate`.
676///
677/// [RFC 7093]: https://www.rfc-editor.org/rfc/rfc7093
678#[derive(Debug, PartialEq, Eq, Hash, Clone)]
679#[non_exhaustive]
680pub enum KeyIdMethod {
681	/// RFC 7093 method 1 - a truncated SHA256 digest.
682	#[cfg(feature = "crypto")]
683	Sha256,
684	/// RFC 7093 method 2 - a truncated SHA384 digest.
685	#[cfg(feature = "crypto")]
686	Sha384,
687	/// RFC 7093 method 3 - a truncated SHA512 digest.
688	#[cfg(feature = "crypto")]
689	Sha512,
690	/// Pre-specified identifier. The exact given value is used as the key identifier.
691	PreSpecified(Vec<u8>),
692}
693
694impl KeyIdMethod {
695	#[cfg(feature = "x509-parser")]
696	fn from_x509(x509: &x509_parser::certificate::X509Certificate<'_>) -> Result<Self, Error> {
697		let key_identifier_method =
698			x509.iter_extensions()
699				.find_map(|ext| match ext.parsed_extension() {
700					x509_parser::extensions::ParsedExtension::SubjectKeyIdentifier(key_id) => {
701						Some(KeyIdMethod::PreSpecified(key_id.0.into()))
702					},
703					_ => None,
704				});
705
706		Ok(match key_identifier_method {
707			Some(method) => method,
708			None => {
709				#[cfg(not(feature = "crypto"))]
710				return Err(Error::UnsupportedSignatureAlgorithm);
711				#[cfg(feature = "crypto")]
712				KeyIdMethod::Sha256
713			},
714		})
715	}
716
717	/// Derive a key identifier for the provided subject public key info using the key ID method.
718	///
719	/// Typically this is a truncated hash over the raw subject public key info, but may
720	/// be a pre-specified value.
721	///
722	/// This key identifier is used in the SubjectKeyIdentifier and AuthorityKeyIdentifier
723	/// X.509v3 extensions.
724	#[allow(unused_variables)]
725	pub(crate) fn derive(&self, subject_public_key_info: impl AsRef<[u8]>) -> Vec<u8> {
726		#[cfg_attr(not(feature = "crypto"), expect(clippy::let_unit_value))]
727		let digest_method = match &self {
728			#[cfg(feature = "crypto")]
729			Self::Sha256 => &digest::SHA256,
730			#[cfg(feature = "crypto")]
731			Self::Sha384 => &digest::SHA384,
732			#[cfg(feature = "crypto")]
733			Self::Sha512 => &digest::SHA512,
734			Self::PreSpecified(b) => {
735				return b.to_vec();
736			},
737		};
738		#[cfg(feature = "crypto")]
739		{
740			let digest = digest::digest(digest_method, subject_public_key_info.as_ref());
741			digest.as_ref()[0..20].to_vec()
742		}
743	}
744}
745
746fn dt_strip_nanos(dt: OffsetDateTime) -> OffsetDateTime {
747	// Set nanoseconds to zero
748	// This is needed because the GeneralizedTime serializer would otherwise
749	// output fractional values which RFC 5280 explicitly forbode [1].
750	// UTCTime cannot express fractional seconds or leap seconds
751	// therefore, it needs to be stripped of nanoseconds fully.
752	// [1]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5.2
753	// TODO: handle leap seconds if dt becomes leap second aware
754	let time =
755		Time::from_hms(dt.hour(), dt.minute(), dt.second()).expect("invalid or out-of-range time");
756	dt.replace_time(time)
757}
758
759fn dt_to_generalized(dt: OffsetDateTime) -> GeneralizedTime {
760	let date_time = dt_strip_nanos(dt);
761	GeneralizedTime::from_datetime(date_time)
762}
763
764fn write_dt_utc_or_generalized(writer: DERWriter, dt: OffsetDateTime) {
765	// RFC 5280 requires CAs to write certificate validity dates
766	// below 2050 as UTCTime, and anything starting from 2050
767	// as GeneralizedTime [1]. The RFC doesn't say anything
768	// about dates before 1950, but as UTCTime can't represent
769	// them, we have to use GeneralizedTime if we want to or not.
770	// [1]: https://tools.ietf.org/html/rfc5280#section-4.1.2.5
771	if (1950..2050).contains(&dt.year()) {
772		let date_time = dt_strip_nanos(dt);
773		let ut = UTCTime::from_datetime(date_time);
774		writer.write_utctime(&ut);
775	} else {
776		let gt = dt_to_generalized(dt);
777		writer.write_generalized_time(&gt);
778	}
779}
780
781fn write_distinguished_name(writer: DERWriter, dn: &DistinguishedName) {
782	writer.write_sequence(|writer| {
783		for (ty, content) in dn.iter() {
784			writer.next().write_set(|writer| {
785				writer.next().write_sequence(|writer| {
786					writer.next().write_oid(&ty.to_oid());
787					match content {
788						DnValue::BmpString(s) => writer
789							.next()
790							.write_tagged_implicit(TAG_BMPSTRING, |writer| {
791								writer.write_bytes(s.as_bytes())
792							}),
793
794						DnValue::Ia5String(s) => writer.next().write_ia5_string(s.as_str()),
795
796						DnValue::PrintableString(s) => {
797							writer.next().write_printable_string(s.as_str())
798						},
799						DnValue::TeletexString(s) => writer
800							.next()
801							.write_tagged_implicit(TAG_TELETEXSTRING, |writer| {
802								writer.write_bytes(s.as_bytes())
803							}),
804						DnValue::UniversalString(s) => writer
805							.next()
806							.write_tagged_implicit(TAG_UNIVERSALSTRING, |writer| {
807								writer.write_bytes(s.as_bytes())
808							}),
809						DnValue::Utf8String(s) => writer.next().write_utf8_string(s),
810					}
811				});
812			});
813		}
814	});
815}
816
817/// Serializes an X.509v3 extension according to RFC 5280
818fn write_x509_extension(
819	writer: DERWriter,
820	extension_oid: &[u64],
821	is_critical: bool,
822	value_serializer: impl FnOnce(DERWriter),
823) {
824	// Extension specification:
825	//    Extension  ::=  SEQUENCE  {
826	//         extnID      OBJECT IDENTIFIER,
827	//         critical    BOOLEAN DEFAULT FALSE,
828	//         extnValue   OCTET STRING
829	//                     -- contains the DER encoding of an ASN.1 value
830	//                     -- corresponding to the extension type identified
831	//                     -- by extnID
832	//         }
833
834	writer.write_sequence(|writer| {
835		let oid = ObjectIdentifier::from_slice(extension_oid);
836		writer.next().write_oid(&oid);
837		if is_critical {
838			writer.next().write_bool(true);
839		}
840		let bytes = yasna::construct_der(value_serializer);
841		writer.next().write_bytes(&bytes);
842	})
843}
844
845/// Serializes an X.509v3 authority key identifier extension according to RFC 5280.
846fn write_x509_authority_key_identifier(writer: DERWriter, aki: Vec<u8>) {
847	// Write Authority Key Identifier
848	// RFC 5280 states:
849	//   'The keyIdentifier field of the authorityKeyIdentifier extension MUST
850	//    be included in all certificates generated by conforming CAs to
851	//    facilitate certification path construction.  There is one exception;
852	//    where a CA distributes its public key in the form of a "self-signed"
853	//    certificate, the authority key identifier MAY be omitted.'
854	// In addition, for CRLs:
855	//    'Conforming CRL issuers MUST use the key identifier method, and MUST
856	//     include this extension in all CRLs issued.'
857	write_x509_extension(writer, oid::AUTHORITY_KEY_IDENTIFIER, false, |writer| {
858		writer.write_sequence(|writer| {
859			writer
860				.next()
861				.write_tagged_implicit(Tag::context(0), |writer| writer.write_bytes(&aki))
862		});
863	});
864}
865
866#[cfg(feature = "zeroize")]
867impl zeroize::Zeroize for KeyPair {
868	fn zeroize(&mut self) {
869		self.serialized_der.zeroize();
870	}
871}
872
873/// A certificate serial number.
874#[derive(Debug, PartialEq, Eq, Hash, Clone)]
875pub struct SerialNumber {
876	inner: Vec<u8>,
877}
878
879#[allow(clippy::len_without_is_empty)]
880impl SerialNumber {
881	/// Create a serial number from the given byte slice.
882	pub fn from_slice(bytes: &[u8]) -> SerialNumber {
883		let inner = bytes.to_vec();
884		SerialNumber { inner }
885	}
886
887	/// Return the byte representation of the serial number.
888	pub fn to_bytes(&self) -> Vec<u8> {
889		self.inner.clone()
890	}
891
892	/// Return the length of the serial number in bytes.
893	pub fn len(&self) -> usize {
894		self.inner.len()
895	}
896}
897
898impl fmt::Display for SerialNumber {
899	fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
900		let hex: Vec<_> = self.inner.iter().map(|b| format!("{b:02x}")).collect();
901		write!(f, "{}", hex.join(":"))
902	}
903}
904
905impl From<Vec<u8>> for SerialNumber {
906	fn from(inner: Vec<u8>) -> SerialNumber {
907		SerialNumber { inner }
908	}
909}
910
911impl From<u64> for SerialNumber {
912	fn from(u: u64) -> SerialNumber {
913		let inner = u.to_be_bytes().into();
914		SerialNumber { inner }
915	}
916}
917
918impl AsRef<[u8]> for SerialNumber {
919	fn as_ref(&self) -> &[u8] {
920		&self.inner
921	}
922}
923
924#[cfg(test)]
925mod tests {
926	use std::panic::catch_unwind;
927
928	use time::{Date, Month, PrimitiveDateTime};
929
930	use super::*;
931
932	fn times() -> [OffsetDateTime; 2] {
933		let dt_nanos = {
934			let date = Date::from_calendar_date(2020, Month::December, 3).unwrap();
935			let time = Time::from_hms_nano(0, 0, 1, 444).unwrap();
936			PrimitiveDateTime::new(date, time).assume_utc()
937		};
938		let dt_zero = {
939			let date = Date::from_calendar_date(2020, Month::December, 3).unwrap();
940			let time = Time::from_hms_nano(0, 0, 1, 0).unwrap();
941			PrimitiveDateTime::new(date, time).assume_utc()
942		};
943		// TODO: include leap seconds if time becomes leap second aware
944		[dt_nanos, dt_zero]
945	}
946
947	#[test]
948	fn test_dt_utc_strip_nanos() {
949		let times = times();
950
951		// No stripping - OffsetDateTime with nanos
952		let res = catch_unwind(|| UTCTime::from_datetime(times[0]));
953		assert!(res.is_err());
954
955		// Stripping
956		for dt in times {
957			let date_time = dt_strip_nanos(dt);
958			assert_eq!(date_time.time().nanosecond(), 0);
959			let _ut = UTCTime::from_datetime(date_time);
960		}
961	}
962
963	#[test]
964	fn test_dt_to_generalized() {
965		let times = times();
966
967		for dt in times {
968			let _gt = dt_to_generalized(dt);
969		}
970	}
971
972	#[test]
973	fn signature_algos_different() {
974		// TODO unify this with test_key_params_mismatch.
975		// Note that that test doesn't have a full list of signature
976		// algorithms, as it has no access to the iter function.
977		for (i, alg_i) in SignatureAlgorithm::iter().enumerate() {
978			for (j, alg_j) in SignatureAlgorithm::iter().enumerate() {
979				assert_eq!(
980					alg_i == alg_j,
981					i == j,
982					"Algorithm relationship mismatch for algorithm index pair {i} and {j}"
983				);
984			}
985		}
986	}
987
988	#[cfg(feature = "x509-parser")]
989	mod test_ip_address_from_octets {
990		use super::super::ip_addr_from_octets;
991		use super::super::Error;
992		use std::net::IpAddr;
993
994		#[test]
995		fn ipv4() {
996			let octets = [10, 20, 30, 40];
997
998			let actual = ip_addr_from_octets(&octets).unwrap();
999
1000			assert_eq!(IpAddr::from(octets), actual)
1001		}
1002
1003		#[test]
1004		fn ipv6() {
1005			let octets = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16];
1006
1007			let actual = ip_addr_from_octets(&octets).unwrap();
1008
1009			assert_eq!(IpAddr::from(octets), actual)
1010		}
1011
1012		#[test]
1013		fn mismatch() {
1014			let incorrect = Vec::from_iter(0..10);
1015			let actual = ip_addr_from_octets(&incorrect).unwrap_err();
1016
1017			assert_eq!(Error::InvalidIpAddressOctetLength(10), actual);
1018		}
1019
1020		#[test]
1021		fn none() {
1022			let actual = ip_addr_from_octets(&[]).unwrap_err();
1023
1024			assert_eq!(Error::InvalidIpAddressOctetLength(0), actual);
1025		}
1026
1027		#[test]
1028		fn too_many() {
1029			let incorrect = Vec::from_iter(0..20);
1030			let actual = ip_addr_from_octets(&incorrect).unwrap_err();
1031
1032			assert_eq!(Error::InvalidIpAddressOctetLength(20), actual);
1033		}
1034	}
1035
1036	#[cfg(feature = "x509-parser")]
1037	mod test_san_type_from_general_name {
1038		use crate::SanType;
1039		use std::net::IpAddr;
1040		use x509_parser::extensions::GeneralName;
1041
1042		#[test]
1043		fn with_ipv4() {
1044			let octets = [1, 2, 3, 4];
1045			let value = GeneralName::IPAddress(&octets);
1046			let actual = SanType::try_from_general(&value).unwrap();
1047
1048			assert_eq!(SanType::IpAddress(IpAddr::from(octets)), actual);
1049		}
1050	}
1051}