rustls_pki_types/lib.rs
1//! This crate provides types for representing X.509 certificates, keys and other types as
2//! commonly used in the rustls ecosystem. It is intended to be used by crates that need to work
3//! with such X.509 types, such as [rustls](https://crates.io/crates/rustls),
4//! [rustls-webpki](https://crates.io/crates/rustls-webpki),
5//! [rustls-pemfile](https://crates.io/crates/rustls-pemfile), and others.
6//!
7//! Some of these crates used to define their own trivial wrappers around DER-encoded bytes.
8//! However, in order to avoid inconvenient dependency edges, these were all disconnected. By
9//! using a common low-level crate of types with long-term stable API, we hope to avoid the
10//! downsides of unnecessary dependency edges while providing good interoperability between crates.
11//!
12//! ## DER and PEM
13//!
14//! Many of the types defined in this crate represent DER-encoded data. DER is a binary encoding of
15//! the ASN.1 format commonly used in web PKI specifications. It is a binary encoding, so it is
16//! relatively compact when stored in memory. However, as a binary format, it is not very easy to
17//! work with for humans and in contexts where binary data is inconvenient. For this reason,
18//! many tools and protocols use a ASCII-based encoding of DER, called PEM. In addition to the
19//! base64-encoded DER, PEM objects are delimited by header and footer lines which indicate the type
20//! of object contained in the PEM blob.
21//!
22//! Types here can be created from:
23//!
24//! - DER using (for example) [`PrivatePkcs8KeyDer::from()`].
25//! - PEM using (for example) [`pem::PemObject::from_pem_slice()`].
26//!
27//! The [`pem::PemObject`] trait contains the full selection of ways to construct
28//! these types from PEM encodings. That includes ways to open and read from a file,
29//! from a slice, or from an `std::io` stream.
30//!
31//! There is also a lower-level API that allows a given PEM file to be fully consumed
32//! in one pass, even if it contains different data types: see the implementation of
33//! the [`pem::PemObject`] trait on the `(pem::SectionKind, Vec<u8>)` tuple.
34//!
35//! ## Creating new certificates and keys
36//!
37//! This crate does not provide any functionality for creating new certificates or keys. However,
38//! the [rcgen](https://docs.rs/rcgen) crate can be used to create new certificates and keys.
39//!
40//! ## Cloning private keys
41//!
42//! This crate intentionally **does not** implement `Clone` on private key types in
43//! order to minimize the exposure of private key data in memory.
44//!
45//! If you want to extend the lifetime of a `PrivateKeyDer<'_>`, consider [`PrivateKeyDer::clone_key()`].
46//! Alternatively since these types are immutable, consider wrapping the `PrivateKeyDer<'_>` in a [`Rc`]
47//! or an [`Arc`].
48//!
49//! [`Rc`]: https://doc.rust-lang.org/std/rc/struct.Rc.html
50//! [`Arc`]: https://doc.rust-lang.org/std/sync/struct.Arc.html
51//! [`PrivateKeyDer::clone_key()`]: https://docs.rs/rustls-pki-types/latest/rustls_pki_types/enum.PrivateKeyDer.html#method.clone_key
52//!
53//! ## Target `wasm32-unknown-unknown` with the `web` feature
54//!
55//! [`std::time::SystemTime`](https://doc.rust-lang.org/std/time/struct.SystemTime.html)
56//! is unavailable in `wasm32-unknown-unknown` targets, so calls to
57//! [`UnixTime::now()`](https://docs.rs/rustls-pki-types/latest/rustls_pki_types/struct.UnixTime.html#method.now),
58//! otherwise enabled by the [`std`](https://docs.rs/crate/rustls-pki-types/latest/features#std) feature,
59//! require building instead with the [`web`](https://docs.rs/crate/rustls-pki-types/latest/features#web)
60//! feature. It gets time by calling [`Date.now()`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/now)
61//! in the browser.
62
63#![cfg_attr(not(feature = "std"), no_std)]
64#![warn(
65 missing_docs,
66 clippy::exhaustive_enums,
67 clippy::exhaustive_structs,
68 clippy::use_self
69)]
70#![cfg_attr(rustls_pki_types_docsrs, feature(doc_cfg))]
71
72#[cfg(feature = "alloc")]
73extern crate alloc;
74
75#[cfg(feature = "alloc")]
76use alloc::vec::Vec;
77use core::fmt;
78use core::ops::Deref;
79use core::time::Duration;
80#[cfg(feature = "alloc")]
81use pem::{PemObject, PemObjectFilter, SectionKind};
82#[cfg(all(
83 feature = "std",
84 not(all(target_family = "wasm", target_os = "unknown"))
85))]
86use std::time::SystemTime;
87#[cfg(all(target_family = "wasm", target_os = "unknown", feature = "web"))]
88use web_time::SystemTime;
89
90pub mod alg_id;
91mod base64;
92mod server_name;
93
94/// Low-level PEM decoding APIs.
95///
96/// These APIs allow decoding PEM format in an iterator, which means you
97/// can load multiple different types of PEM section from a file in a single
98/// pass.
99#[cfg(feature = "alloc")]
100pub mod pem;
101
102pub use alg_id::AlgorithmIdentifier;
103pub use server_name::{
104 AddrParseError, DnsName, InvalidDnsNameError, IpAddr, Ipv4Addr, Ipv6Addr, ServerName,
105};
106
107/// A DER-encoded X.509 private key, in one of several formats
108///
109/// See variant inner types for more detailed information.
110///
111/// This can load several types of PEM-encoded private key, and then reveal
112/// which types were found:
113///
114/// ```rust
115/// # #[cfg(all(feature = "alloc", feature = "std"))] {
116/// use rustls_pki_types::{PrivateKeyDer, pem::PemObject};
117///
118/// // load from a PEM file
119/// let pkcs8 = PrivateKeyDer::from_pem_file("tests/data/nistp256key.pkcs8.pem").unwrap();
120/// let pkcs1 = PrivateKeyDer::from_pem_file("tests/data/rsa1024.pkcs1.pem").unwrap();
121/// let sec1 = PrivateKeyDer::from_pem_file("tests/data/nistp256key.pem").unwrap();
122/// assert!(matches!(pkcs8, PrivateKeyDer::Pkcs8(_)));
123/// assert!(matches!(pkcs1, PrivateKeyDer::Pkcs1(_)));
124/// assert!(matches!(sec1, PrivateKeyDer::Sec1(_)));
125/// # }
126/// ```
127#[non_exhaustive]
128#[derive(Debug, PartialEq, Eq)]
129pub enum PrivateKeyDer<'a> {
130 /// An RSA private key
131 Pkcs1(PrivatePkcs1KeyDer<'a>),
132 /// A Sec1 private key
133 Sec1(PrivateSec1KeyDer<'a>),
134 /// A PKCS#8 private key
135 Pkcs8(PrivatePkcs8KeyDer<'a>),
136}
137
138#[cfg(feature = "alloc")]
139impl zeroize::Zeroize for PrivateKeyDer<'static> {
140 fn zeroize(&mut self) {
141 match self {
142 Self::Pkcs1(key) => key.zeroize(),
143 Self::Sec1(key) => key.zeroize(),
144 Self::Pkcs8(key) => key.zeroize(),
145 }
146 }
147}
148
149impl PrivateKeyDer<'_> {
150 /// Clone the private key to a `'static` value
151 #[cfg(feature = "alloc")]
152 pub fn clone_key(&self) -> PrivateKeyDer<'static> {
153 use PrivateKeyDer::*;
154 match self {
155 Pkcs1(key) => Pkcs1(key.clone_key()),
156 Sec1(key) => Sec1(key.clone_key()),
157 Pkcs8(key) => Pkcs8(key.clone_key()),
158 }
159 }
160
161 /// Yield the DER-encoded bytes of the private key
162 pub fn secret_der(&self) -> &[u8] {
163 match self {
164 PrivateKeyDer::Pkcs1(key) => key.secret_pkcs1_der(),
165 PrivateKeyDer::Sec1(key) => key.secret_sec1_der(),
166 PrivateKeyDer::Pkcs8(key) => key.secret_pkcs8_der(),
167 }
168 }
169}
170
171#[cfg(feature = "alloc")]
172impl PemObject for PrivateKeyDer<'static> {
173 fn from_pem(kind: SectionKind, value: Vec<u8>) -> Option<Self> {
174 match kind {
175 SectionKind::RsaPrivateKey => Some(Self::Pkcs1(value.into())),
176 SectionKind::EcPrivateKey => Some(Self::Sec1(value.into())),
177 SectionKind::PrivateKey => Some(Self::Pkcs8(value.into())),
178 _ => None,
179 }
180 }
181}
182
183impl<'a> From<PrivatePkcs1KeyDer<'a>> for PrivateKeyDer<'a> {
184 fn from(key: PrivatePkcs1KeyDer<'a>) -> Self {
185 Self::Pkcs1(key)
186 }
187}
188
189impl<'a> From<PrivateSec1KeyDer<'a>> for PrivateKeyDer<'a> {
190 fn from(key: PrivateSec1KeyDer<'a>) -> Self {
191 Self::Sec1(key)
192 }
193}
194
195impl<'a> From<PrivatePkcs8KeyDer<'a>> for PrivateKeyDer<'a> {
196 fn from(key: PrivatePkcs8KeyDer<'a>) -> Self {
197 Self::Pkcs8(key)
198 }
199}
200
201impl<'a> TryFrom<&'a [u8]> for PrivateKeyDer<'a> {
202 type Error = &'static str;
203
204 fn try_from(key: &'a [u8]) -> Result<Self, Self::Error> {
205 const SHORT_FORM_LEN_MAX: u8 = 128;
206 const TAG_SEQUENCE: u8 = 0x30;
207 const TAG_INTEGER: u8 = 0x02;
208
209 // We expect all key formats to begin with a SEQUENCE, which requires at least 2 bytes
210 // in the short length encoding.
211 if key.first() != Some(&TAG_SEQUENCE) || key.len() < 2 {
212 return Err(INVALID_KEY_DER_ERR);
213 }
214
215 // The length of the SEQUENCE is encoded in the second byte. We must skip this many bytes.
216 let skip_len = match key[1] >= SHORT_FORM_LEN_MAX {
217 // 1 byte for SEQUENCE tag, 1 byte for short-form len
218 false => 2,
219 // 1 byte for SEQUENCE tag, 1 byte for start of len, remaining bytes encoded
220 // in key[1].
221 true => 2 + (key[1] - SHORT_FORM_LEN_MAX) as usize,
222 };
223 let key_bytes = key.get(skip_len..).ok_or(INVALID_KEY_DER_ERR)?;
224
225 // PKCS#8 (https://www.rfc-editor.org/rfc/rfc5208) describes the PrivateKeyInfo
226 // structure as:
227 // PrivateKeyInfo ::= SEQUENCE {
228 // version Version,
229 // privateKeyAlgorithm AlgorithmIdentifier {{PrivateKeyAlgorithms}},
230 // privateKey PrivateKey,
231 // attributes [0] Attributes OPTIONAL
232 // }
233 // PKCS#5 (https://www.rfc-editor.org/rfc/rfc8018) describes the AlgorithmIdentifier
234 // as a SEQUENCE.
235 //
236 // Therefore, we consider the outer SEQUENCE, a version number, and the start of
237 // an AlgorithmIdentifier to be enough to identify a PKCS#8 key. If it were PKCS#1 or SEC1
238 // the version would not be followed by a SEQUENCE.
239 if matches!(key_bytes, [TAG_INTEGER, 0x01, _, TAG_SEQUENCE, ..]) {
240 return Ok(Self::Pkcs8(key.into()));
241 }
242
243 // PKCS#1 (https://www.rfc-editor.org/rfc/rfc8017) describes the RSAPrivateKey structure
244 // as:
245 // RSAPrivateKey ::= SEQUENCE {
246 // version Version,
247 // modulus INTEGER, -- n
248 // publicExponent INTEGER, -- e
249 // privateExponent INTEGER, -- d
250 // prime1 INTEGER, -- p
251 // prime2 INTEGER, -- q
252 // exponent1 INTEGER, -- d mod (p-1)
253 // exponent2 INTEGER, -- d mod (q-1)
254 // coefficient INTEGER, -- (inverse of q) mod p
255 // otherPrimeInfos OtherPrimeInfos OPTIONAL
256 // }
257 //
258 // Therefore, we consider the outer SEQUENCE and a Version of 0 to be enough to identify
259 // a PKCS#1 key. If it were PKCS#8, the version would be followed by a SEQUENCE. If it
260 // were SEC1, the VERSION would have been 1.
261 if key_bytes.starts_with(&[TAG_INTEGER, 0x01, 0x00]) {
262 return Ok(Self::Pkcs1(key.into()));
263 }
264
265 // SEC1 (https://www.rfc-editor.org/rfc/rfc5915) describes the ECPrivateKey structure as:
266 // ECPrivateKey ::= SEQUENCE {
267 // version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
268 // privateKey OCTET STRING,
269 // parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
270 // publicKey [1] BIT STRING OPTIONAL
271 // }
272 //
273 // Therefore, we consider the outer SEQUENCE and an INTEGER of 1 to be enough to
274 // identify a SEC1 key. If it were PKCS#8 or PKCS#1, the version would have been 0.
275 if key_bytes.starts_with(&[TAG_INTEGER, 0x01, 0x01]) {
276 return Ok(Self::Sec1(key.into()));
277 }
278
279 Err(INVALID_KEY_DER_ERR)
280 }
281}
282
283static INVALID_KEY_DER_ERR: &str = "unknown or invalid key format";
284
285#[cfg(feature = "alloc")]
286impl TryFrom<Vec<u8>> for PrivateKeyDer<'_> {
287 type Error = &'static str;
288
289 fn try_from(key: Vec<u8>) -> Result<Self, Self::Error> {
290 Ok(match PrivateKeyDer::try_from(&key[..])? {
291 PrivateKeyDer::Pkcs1(_) => Self::Pkcs1(key.into()),
292 PrivateKeyDer::Sec1(_) => Self::Sec1(key.into()),
293 PrivateKeyDer::Pkcs8(_) => Self::Pkcs8(key.into()),
294 })
295 }
296}
297
298/// A DER-encoded plaintext RSA private key; as specified in PKCS#1/RFC 3447
299///
300/// RSA private keys are identified in PEM context as `RSA PRIVATE KEY` and when stored in a
301/// file usually use a `.pem` or `.key` extension.
302///
303/// ```rust
304/// # #[cfg(all(feature = "alloc", feature = "std"))] {
305/// use rustls_pki_types::{PrivatePkcs1KeyDer, pem::PemObject};
306///
307/// // load from a PEM file
308/// PrivatePkcs1KeyDer::from_pem_file("tests/data/rsa1024.pkcs1.pem").unwrap();
309///
310/// // or from a PEM byte slice...
311/// # let byte_slice = include_bytes!("../tests/data/rsa1024.pkcs1.pem");
312/// PrivatePkcs1KeyDer::from_pem_slice(byte_slice).unwrap();
313/// # }
314/// ```
315#[derive(PartialEq, Eq)]
316pub struct PrivatePkcs1KeyDer<'a>(Der<'a>);
317
318impl PrivatePkcs1KeyDer<'_> {
319 /// Clone the private key to a `'static` value
320 #[cfg(feature = "alloc")]
321 pub fn clone_key(&self) -> PrivatePkcs1KeyDer<'static> {
322 PrivatePkcs1KeyDer::from(self.0.as_ref().to_vec())
323 }
324
325 /// Yield the DER-encoded bytes of the private key
326 pub fn secret_pkcs1_der(&self) -> &[u8] {
327 self.0.as_ref()
328 }
329}
330
331#[cfg(feature = "alloc")]
332impl zeroize::Zeroize for PrivatePkcs1KeyDer<'static> {
333 fn zeroize(&mut self) {
334 self.0.0.zeroize()
335 }
336}
337
338#[cfg(feature = "alloc")]
339impl PemObjectFilter for PrivatePkcs1KeyDer<'static> {
340 const KIND: SectionKind = SectionKind::RsaPrivateKey;
341}
342
343impl<'a> From<&'a [u8]> for PrivatePkcs1KeyDer<'a> {
344 fn from(slice: &'a [u8]) -> Self {
345 Self(Der(BytesInner::Borrowed(slice)))
346 }
347}
348
349#[cfg(feature = "alloc")]
350impl From<Vec<u8>> for PrivatePkcs1KeyDer<'_> {
351 fn from(vec: Vec<u8>) -> Self {
352 Self(Der(BytesInner::Owned(vec)))
353 }
354}
355
356impl fmt::Debug for PrivatePkcs1KeyDer<'_> {
357 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
358 f.debug_tuple("PrivatePkcs1KeyDer")
359 .field(&"[secret key elided]")
360 .finish()
361 }
362}
363
364/// A Sec1-encoded plaintext private key; as specified in RFC 5915
365///
366/// Sec1 private keys are identified in PEM context as `EC PRIVATE KEY` and when stored in a
367/// file usually use a `.pem` or `.key` extension. For more on PEM files, refer to the crate
368/// documentation.
369///
370/// ```rust
371/// # #[cfg(all(feature = "alloc", feature = "std"))] {
372/// use rustls_pki_types::{PrivateSec1KeyDer, pem::PemObject};
373///
374/// // load from a PEM file
375/// PrivateSec1KeyDer::from_pem_file("tests/data/nistp256key.pem").unwrap();
376///
377/// // or from a PEM byte slice...
378/// # let byte_slice = include_bytes!("../tests/data/nistp256key.pem");
379/// PrivateSec1KeyDer::from_pem_slice(byte_slice).unwrap();
380/// # }
381/// ```
382#[derive(PartialEq, Eq)]
383pub struct PrivateSec1KeyDer<'a>(Der<'a>);
384
385impl PrivateSec1KeyDer<'_> {
386 /// Clone the private key to a `'static` value
387 #[cfg(feature = "alloc")]
388 pub fn clone_key(&self) -> PrivateSec1KeyDer<'static> {
389 PrivateSec1KeyDer::from(self.0.as_ref().to_vec())
390 }
391
392 /// Yield the DER-encoded bytes of the private key
393 pub fn secret_sec1_der(&self) -> &[u8] {
394 self.0.as_ref()
395 }
396}
397
398#[cfg(feature = "alloc")]
399impl zeroize::Zeroize for PrivateSec1KeyDer<'static> {
400 fn zeroize(&mut self) {
401 self.0.0.zeroize()
402 }
403}
404
405#[cfg(feature = "alloc")]
406impl PemObjectFilter for PrivateSec1KeyDer<'static> {
407 const KIND: SectionKind = SectionKind::EcPrivateKey;
408}
409
410impl<'a> From<&'a [u8]> for PrivateSec1KeyDer<'a> {
411 fn from(slice: &'a [u8]) -> Self {
412 Self(Der(BytesInner::Borrowed(slice)))
413 }
414}
415
416#[cfg(feature = "alloc")]
417impl From<Vec<u8>> for PrivateSec1KeyDer<'_> {
418 fn from(vec: Vec<u8>) -> Self {
419 Self(Der(BytesInner::Owned(vec)))
420 }
421}
422
423impl fmt::Debug for PrivateSec1KeyDer<'_> {
424 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
425 f.debug_tuple("PrivateSec1KeyDer")
426 .field(&"[secret key elided]")
427 .finish()
428 }
429}
430
431/// A DER-encoded plaintext private key; as specified in PKCS#8/RFC 5958
432///
433/// PKCS#8 private keys are identified in PEM context as `PRIVATE KEY` and when stored in a
434/// file usually use a `.pem` or `.key` extension. For more on PEM files, refer to the crate
435/// documentation.
436///
437/// ```rust
438/// # #[cfg(all(feature = "alloc", feature = "std"))] {
439/// use rustls_pki_types::{PrivatePkcs8KeyDer, pem::PemObject};
440///
441/// // load from a PEM file
442/// PrivatePkcs8KeyDer::from_pem_file("tests/data/nistp256key.pkcs8.pem").unwrap();
443/// PrivatePkcs8KeyDer::from_pem_file("tests/data/rsa1024.pkcs8.pem").unwrap();
444///
445/// // or from a PEM byte slice...
446/// # let byte_slice = include_bytes!("../tests/data/nistp256key.pkcs8.pem");
447/// PrivatePkcs8KeyDer::from_pem_slice(byte_slice).unwrap();
448/// # }
449/// ```
450#[derive(PartialEq, Eq)]
451pub struct PrivatePkcs8KeyDer<'a>(Der<'a>);
452
453impl PrivatePkcs8KeyDer<'_> {
454 /// Clone the private key to a `'static` value
455 #[cfg(feature = "alloc")]
456 pub fn clone_key(&self) -> PrivatePkcs8KeyDer<'static> {
457 PrivatePkcs8KeyDer::from(self.0.as_ref().to_vec())
458 }
459
460 /// Yield the DER-encoded bytes of the private key
461 pub fn secret_pkcs8_der(&self) -> &[u8] {
462 self.0.as_ref()
463 }
464}
465
466#[cfg(feature = "alloc")]
467impl zeroize::Zeroize for PrivatePkcs8KeyDer<'static> {
468 fn zeroize(&mut self) {
469 self.0.0.zeroize()
470 }
471}
472
473#[cfg(feature = "alloc")]
474impl PemObjectFilter for PrivatePkcs8KeyDer<'static> {
475 const KIND: SectionKind = SectionKind::PrivateKey;
476}
477
478impl<'a> From<&'a [u8]> for PrivatePkcs8KeyDer<'a> {
479 fn from(slice: &'a [u8]) -> Self {
480 Self(Der(BytesInner::Borrowed(slice)))
481 }
482}
483
484#[cfg(feature = "alloc")]
485impl From<Vec<u8>> for PrivatePkcs8KeyDer<'_> {
486 fn from(vec: Vec<u8>) -> Self {
487 Self(Der(BytesInner::Owned(vec)))
488 }
489}
490
491impl fmt::Debug for PrivatePkcs8KeyDer<'_> {
492 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
493 f.debug_tuple("PrivatePkcs8KeyDer")
494 .field(&"[secret key elided]")
495 .finish()
496 }
497}
498
499/// A trust anchor (a.k.a. root CA)
500///
501/// Traditionally, certificate verification libraries have represented trust anchors as full X.509
502/// root certificates. However, those certificates contain a lot more data than is needed for
503/// verifying certificates. The [`TrustAnchor`] representation allows an application to store
504/// just the essential elements of trust anchors.
505///
506/// The most common way to get one of these is to call [`rustls_webpki::anchor_from_trusted_cert()`].
507///
508/// [`rustls_webpki::anchor_from_trusted_cert()`]: https://docs.rs/rustls-webpki/latest/webpki/fn.anchor_from_trusted_cert.html
509#[allow(clippy::exhaustive_structs)]
510#[derive(Clone, Debug, Hash, PartialEq, Eq)]
511pub struct TrustAnchor<'a> {
512 /// Value of the `subject` field of the trust anchor
513 pub subject: Der<'a>,
514 /// Value of the `subjectPublicKeyInfo` field of the trust anchor
515 pub subject_public_key_info: Der<'a>,
516 /// Value of DER-encoded `NameConstraints`, containing name constraints to the trust anchor, if any
517 pub name_constraints: Option<Der<'a>>,
518}
519
520impl TrustAnchor<'_> {
521 /// Yield a `'static` lifetime of the `TrustAnchor` by allocating owned `Der` variants
522 #[cfg(feature = "alloc")]
523 pub fn to_owned(&self) -> TrustAnchor<'static> {
524 #[cfg(not(feature = "std"))]
525 use alloc::borrow::ToOwned;
526 TrustAnchor {
527 subject: self.subject.as_ref().to_owned().into(),
528 subject_public_key_info: self.subject_public_key_info.as_ref().to_owned().into(),
529 name_constraints: self
530 .name_constraints
531 .as_ref()
532 .map(|nc| nc.as_ref().to_owned().into()),
533 }
534 }
535}
536
537/// A Certificate Revocation List; as specified in RFC 5280
538///
539/// Certificate revocation lists are identified in PEM context as `X509 CRL` and when stored in a
540/// file usually use a `.crl` extension. For more on PEM files, refer to the crate documentation.
541///
542/// ```rust
543/// # #[cfg(all(feature = "alloc", feature = "std"))] {
544/// use rustls_pki_types::{CertificateRevocationListDer, pem::PemObject};
545///
546/// // load several from a PEM file
547/// let crls: Vec<_> = CertificateRevocationListDer::pem_file_iter("tests/data/crl.pem")
548/// .unwrap()
549/// .collect();
550/// assert!(crls.len() >= 1);
551///
552/// // or one from a PEM byte slice...
553/// # let byte_slice = include_bytes!("../tests/data/crl.pem");
554/// CertificateRevocationListDer::from_pem_slice(byte_slice).unwrap();
555///
556/// // or several from a PEM byte slice
557/// let crls: Vec<_> = CertificateRevocationListDer::pem_slice_iter(byte_slice)
558/// .collect();
559/// assert!(crls.len() >= 1);
560/// # }
561/// ```
562
563#[derive(Clone, Debug, Hash, PartialEq, Eq)]
564pub struct CertificateRevocationListDer<'a>(Der<'a>);
565
566#[cfg(feature = "alloc")]
567impl PemObjectFilter for CertificateRevocationListDer<'static> {
568 const KIND: SectionKind = SectionKind::Crl;
569}
570
571impl AsRef<[u8]> for CertificateRevocationListDer<'_> {
572 fn as_ref(&self) -> &[u8] {
573 self.0.as_ref()
574 }
575}
576
577impl Deref for CertificateRevocationListDer<'_> {
578 type Target = [u8];
579
580 fn deref(&self) -> &Self::Target {
581 self.as_ref()
582 }
583}
584
585impl<'a> From<&'a [u8]> for CertificateRevocationListDer<'a> {
586 fn from(slice: &'a [u8]) -> Self {
587 Self(Der::from(slice))
588 }
589}
590
591#[cfg(feature = "alloc")]
592impl From<Vec<u8>> for CertificateRevocationListDer<'_> {
593 fn from(vec: Vec<u8>) -> Self {
594 Self(Der::from(vec))
595 }
596}
597
598/// A Certificate Signing Request; as specified in RFC 2986
599///
600/// Certificate signing requests are identified in PEM context as `CERTIFICATE REQUEST` and when stored in a
601/// file usually use a `.csr` extension. For more on PEM files, refer to the crate documentation.
602///
603/// ```rust
604/// # #[cfg(all(feature = "alloc", feature = "std"))] {
605/// use rustls_pki_types::{CertificateSigningRequestDer, pem::PemObject};
606///
607/// // load from a PEM file
608/// CertificateSigningRequestDer::from_pem_file("tests/data/csr.pem").unwrap();
609///
610/// // or from a PEM byte slice...
611/// # let byte_slice = include_bytes!("../tests/data/csr.pem");
612/// CertificateSigningRequestDer::from_pem_slice(byte_slice).unwrap();
613/// # }
614/// ```
615#[derive(Clone, Debug, Hash, PartialEq, Eq)]
616pub struct CertificateSigningRequestDer<'a>(Der<'a>);
617
618#[cfg(feature = "alloc")]
619impl PemObjectFilter for CertificateSigningRequestDer<'static> {
620 const KIND: SectionKind = SectionKind::Csr;
621}
622
623impl AsRef<[u8]> for CertificateSigningRequestDer<'_> {
624 fn as_ref(&self) -> &[u8] {
625 self.0.as_ref()
626 }
627}
628
629impl Deref for CertificateSigningRequestDer<'_> {
630 type Target = [u8];
631
632 fn deref(&self) -> &Self::Target {
633 self.as_ref()
634 }
635}
636
637impl<'a> From<&'a [u8]> for CertificateSigningRequestDer<'a> {
638 fn from(slice: &'a [u8]) -> Self {
639 Self(Der::from(slice))
640 }
641}
642
643#[cfg(feature = "alloc")]
644impl From<Vec<u8>> for CertificateSigningRequestDer<'_> {
645 fn from(vec: Vec<u8>) -> Self {
646 Self(Der::from(vec))
647 }
648}
649
650/// A DER-encoded X.509 certificate; as specified in RFC 5280
651///
652/// Certificates are identified in PEM context as `CERTIFICATE` and when stored in a
653/// file usually use a `.pem`, `.cer` or `.crt` extension. For more on PEM files, refer to the
654/// crate documentation.
655///
656/// ```rust
657/// # #[cfg(all(feature = "alloc", feature = "std"))] {
658/// use rustls_pki_types::{CertificateDer, pem::PemObject};
659///
660/// // load several from a PEM file
661/// let certs: Vec<_> = CertificateDer::pem_file_iter("tests/data/certificate.chain.pem")
662/// .unwrap()
663/// .collect();
664/// assert_eq!(certs.len(), 3);
665///
666/// // or one from a PEM byte slice...
667/// # let byte_slice = include_bytes!("../tests/data/certificate.chain.pem");
668/// CertificateDer::from_pem_slice(byte_slice).unwrap();
669///
670/// // or several from a PEM byte slice
671/// let certs: Vec<_> = CertificateDer::pem_slice_iter(byte_slice)
672/// .collect();
673/// assert_eq!(certs.len(), 3);
674/// # }
675/// ```
676#[derive(Clone, Debug, Hash, PartialEq, Eq)]
677pub struct CertificateDer<'a>(Der<'a>);
678
679impl<'a> CertificateDer<'a> {
680 /// A const constructor to create a `CertificateDer` from a slice of DER.
681 pub const fn from_slice(bytes: &'a [u8]) -> Self {
682 Self(Der::from_slice(bytes))
683 }
684}
685
686#[cfg(feature = "alloc")]
687impl PemObjectFilter for CertificateDer<'static> {
688 const KIND: SectionKind = SectionKind::Certificate;
689}
690
691impl AsRef<[u8]> for CertificateDer<'_> {
692 fn as_ref(&self) -> &[u8] {
693 self.0.as_ref()
694 }
695}
696
697impl Deref for CertificateDer<'_> {
698 type Target = [u8];
699
700 fn deref(&self) -> &Self::Target {
701 self.as_ref()
702 }
703}
704
705impl<'a> From<&'a [u8]> for CertificateDer<'a> {
706 fn from(slice: &'a [u8]) -> Self {
707 Self(Der::from(slice))
708 }
709}
710
711#[cfg(feature = "alloc")]
712impl From<Vec<u8>> for CertificateDer<'_> {
713 fn from(vec: Vec<u8>) -> Self {
714 Self(Der::from(vec))
715 }
716}
717
718impl CertificateDer<'_> {
719 /// Converts this certificate into its owned variant, unfreezing borrowed content (if any)
720 #[cfg(feature = "alloc")]
721 pub fn into_owned(self) -> CertificateDer<'static> {
722 CertificateDer(Der(self.0.0.into_owned()))
723 }
724}
725
726/// A DER-encoded SubjectPublicKeyInfo (SPKI), as specified in RFC 5280.
727#[deprecated(since = "1.7.0", note = "Prefer `SubjectPublicKeyInfoDer` instead")]
728pub type SubjectPublicKeyInfo<'a> = SubjectPublicKeyInfoDer<'a>;
729
730/// A DER-encoded SubjectPublicKeyInfo (SPKI), as specified in RFC 5280.
731///
732/// Public keys are identified in PEM context as a `PUBLIC KEY`.
733///
734/// ```rust
735/// # #[cfg(all(feature = "alloc", feature = "std"))] {
736/// use rustls_pki_types::{SubjectPublicKeyInfoDer, pem::PemObject};
737///
738/// // load from a PEM file
739/// SubjectPublicKeyInfoDer::from_pem_file("tests/data/spki.pem").unwrap();
740///
741/// // or from a PEM byte slice...
742/// # let byte_slice = include_bytes!("../tests/data/spki.pem");
743/// SubjectPublicKeyInfoDer::from_pem_slice(byte_slice).unwrap();
744/// # }
745/// ```
746#[derive(Clone, Debug, Hash, PartialEq, Eq)]
747pub struct SubjectPublicKeyInfoDer<'a>(Der<'a>);
748
749#[cfg(feature = "alloc")]
750impl PemObjectFilter for SubjectPublicKeyInfoDer<'static> {
751 const KIND: SectionKind = SectionKind::PublicKey;
752}
753
754impl AsRef<[u8]> for SubjectPublicKeyInfoDer<'_> {
755 fn as_ref(&self) -> &[u8] {
756 self.0.as_ref()
757 }
758}
759
760impl Deref for SubjectPublicKeyInfoDer<'_> {
761 type Target = [u8];
762
763 fn deref(&self) -> &Self::Target {
764 self.as_ref()
765 }
766}
767
768impl<'a> From<&'a [u8]> for SubjectPublicKeyInfoDer<'a> {
769 fn from(slice: &'a [u8]) -> Self {
770 Self(Der::from(slice))
771 }
772}
773
774#[cfg(feature = "alloc")]
775impl From<Vec<u8>> for SubjectPublicKeyInfoDer<'_> {
776 fn from(vec: Vec<u8>) -> Self {
777 Self(Der::from(vec))
778 }
779}
780
781impl SubjectPublicKeyInfoDer<'_> {
782 /// Converts this SubjectPublicKeyInfo into its owned variant, unfreezing borrowed content (if any)
783 #[cfg(feature = "alloc")]
784 pub fn into_owned(self) -> SubjectPublicKeyInfoDer<'static> {
785 SubjectPublicKeyInfoDer(Der(self.0.0.into_owned()))
786 }
787}
788
789/// A TLS-encoded Encrypted Client Hello (ECH) configuration list (`ECHConfigList`); as specified in
790/// [draft-ietf-tls-esni-18 ยง4](https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-4)
791#[derive(Clone, Eq, Hash, PartialEq)]
792pub struct EchConfigListBytes<'a>(BytesInner<'a>);
793
794impl EchConfigListBytes<'_> {
795 /// Converts this config into its owned variant, unfreezing borrowed content (if any)
796 #[cfg(feature = "alloc")]
797 pub fn into_owned(self) -> EchConfigListBytes<'static> {
798 EchConfigListBytes(self.0.into_owned())
799 }
800}
801
802#[cfg(feature = "alloc")]
803impl EchConfigListBytes<'static> {
804 /// Convert an iterator over PEM items into an `EchConfigListBytes` and private key.
805 ///
806 /// This handles the "ECHConfig file" format specified in
807 /// <https://www.ietf.org/archive/id/draft-farrell-tls-pemesni-05.html#name-echconfig-file>
808 ///
809 /// Use it like:
810 ///
811 /// ```rust
812 /// # #[cfg(all(feature = "alloc", feature = "std"))] {
813 /// # use rustls_pki_types::{EchConfigListBytes, pem::PemObject};
814 /// let (config, key) = EchConfigListBytes::config_and_key_from_iter(
815 /// PemObject::pem_file_iter("tests/data/ech.pem").unwrap()
816 /// ).unwrap();
817 /// # }
818 /// ```
819 pub fn config_and_key_from_iter(
820 iter: impl Iterator<Item = Result<(SectionKind, Vec<u8>), pem::Error>>,
821 ) -> Result<(Self, PrivatePkcs8KeyDer<'static>), pem::Error> {
822 let mut key = None;
823 let mut config = None;
824
825 for item in iter {
826 let (kind, data) = item?;
827 match kind {
828 SectionKind::PrivateKey => {
829 key = PrivatePkcs8KeyDer::from_pem(kind, data);
830 }
831 SectionKind::EchConfigList => {
832 config = Self::from_pem(kind, data);
833 }
834 _ => continue,
835 };
836
837 if let (Some(_key), Some(_config)) = (&key, &config) {
838 return Ok((config.take().unwrap(), key.take().unwrap()));
839 }
840 }
841
842 Err(pem::Error::NoItemsFound)
843 }
844}
845
846#[cfg(feature = "alloc")]
847impl PemObjectFilter for EchConfigListBytes<'static> {
848 const KIND: SectionKind = SectionKind::EchConfigList;
849}
850
851impl fmt::Debug for EchConfigListBytes<'_> {
852 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
853 hex(f, self.as_ref())
854 }
855}
856
857impl AsRef<[u8]> for EchConfigListBytes<'_> {
858 fn as_ref(&self) -> &[u8] {
859 self.0.as_ref()
860 }
861}
862
863impl Deref for EchConfigListBytes<'_> {
864 type Target = [u8];
865
866 fn deref(&self) -> &Self::Target {
867 self.as_ref()
868 }
869}
870
871impl<'a> From<&'a [u8]> for EchConfigListBytes<'a> {
872 fn from(slice: &'a [u8]) -> Self {
873 Self(BytesInner::Borrowed(slice))
874 }
875}
876
877#[cfg(feature = "alloc")]
878impl From<Vec<u8>> for EchConfigListBytes<'_> {
879 fn from(vec: Vec<u8>) -> Self {
880 Self(BytesInner::Owned(vec))
881 }
882}
883
884/// An abstract signature verification algorithm.
885///
886/// One of these is needed per supported pair of public key type (identified
887/// with `public_key_alg_id()`) and `signatureAlgorithm` (identified with
888/// `signature_alg_id()`). Note that both of these `AlgorithmIdentifier`s include
889/// the parameters encoding, so separate `SignatureVerificationAlgorithm`s are needed
890/// for each possible public key or signature parameters.
891///
892/// Debug implementations should list the public key algorithm identifier and
893/// signature algorithm identifier in human friendly form (i.e. not encoded bytes),
894/// along with the name of the implementing library (to distinguish different
895/// implementations of the same algorithms).
896pub trait SignatureVerificationAlgorithm: Send + Sync + fmt::Debug {
897 /// Verify a signature.
898 ///
899 /// `public_key` is the `subjectPublicKey` value from a `SubjectPublicKeyInfo` encoding
900 /// and is untrusted. The key's `subjectPublicKeyInfo` matches the [`AlgorithmIdentifier`]
901 /// returned by `public_key_alg_id()`.
902 ///
903 /// `message` is the data over which the signature was allegedly computed.
904 /// It is not hashed; implementations of this trait function must do hashing
905 /// if that is required by the algorithm they implement.
906 ///
907 /// `signature` is the signature allegedly over `message`.
908 ///
909 /// Return `Ok(())` only if `signature` is a valid signature on `message`.
910 ///
911 /// Return `Err(InvalidSignature)` if the signature is invalid, including if the `public_key`
912 /// encoding is invalid. There is no need or opportunity to produce errors
913 /// that are more specific than this.
914 fn verify_signature(
915 &self,
916 public_key: &[u8],
917 message: &[u8],
918 signature: &[u8],
919 ) -> Result<(), InvalidSignature>;
920
921 /// Return the `AlgorithmIdentifier` that must equal a public key's
922 /// `subjectPublicKeyInfo` value for this `SignatureVerificationAlgorithm`
923 /// to be used for signature verification.
924 fn public_key_alg_id(&self) -> AlgorithmIdentifier;
925
926 /// Return the `AlgorithmIdentifier` that must equal the `signatureAlgorithm` value
927 /// on the data to be verified for this `SignatureVerificationAlgorithm` to be used
928 /// for signature verification.
929 fn signature_alg_id(&self) -> AlgorithmIdentifier;
930
931 /// Return the FIPS status of this algorithm or implementation.
932 fn fips_status(&self) -> FipsStatus {
933 match self.fips() {
934 true => FipsStatus::Pending,
935 false => FipsStatus::Unvalidated,
936 }
937 }
938
939 /// Return `true` if this is backed by a FIPS-approved implementation.
940 fn fips(&self) -> bool {
941 false
942 }
943}
944
945/// A detail-less error when a signature is not valid.
946#[allow(clippy::exhaustive_structs)]
947#[derive(Debug, Copy, Clone)]
948pub struct InvalidSignature;
949
950/// A timestamp, tracking the number of non-leap seconds since the Unix epoch.
951///
952/// The Unix epoch is defined January 1, 1970 00:00:00 UTC.
953#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
954pub struct UnixTime(u64);
955
956impl UnixTime {
957 /// The current time, as a `UnixTime`
958 #[cfg(any(
959 all(
960 feature = "std",
961 not(all(target_family = "wasm", target_os = "unknown"))
962 ),
963 all(target_family = "wasm", target_os = "unknown", feature = "web")
964 ))]
965 pub fn now() -> Self {
966 Self::since_unix_epoch(
967 SystemTime::now()
968 .duration_since(SystemTime::UNIX_EPOCH)
969 .unwrap(), // Safe: this code did not exist before 1970.
970 )
971 }
972
973 /// Convert a `Duration` since the start of 1970 to a `UnixTime`
974 ///
975 /// The `duration` must be relative to the Unix epoch.
976 pub const fn since_unix_epoch(duration: Duration) -> Self {
977 Self(duration.as_secs())
978 }
979
980 /// Number of seconds since the Unix epoch
981 pub const fn as_secs(&self) -> u64 {
982 self.0
983 }
984}
985
986/// DER-encoded data, either owned or borrowed
987///
988/// This wrapper type is used to represent DER-encoded data in a way that is agnostic to whether
989/// the data is owned (by a `Vec<u8>`) or borrowed (by a `&[u8]`). Support for the owned
990/// variant is only available when the `alloc` feature is enabled.
991#[derive(Clone, Eq, Hash, PartialEq)]
992pub struct Der<'a>(BytesInner<'a>);
993
994impl<'a> Der<'a> {
995 /// A const constructor to create a `Der` from a borrowed slice
996 pub const fn from_slice(der: &'a [u8]) -> Self {
997 Self(BytesInner::Borrowed(der))
998 }
999}
1000
1001impl AsRef<[u8]> for Der<'_> {
1002 fn as_ref(&self) -> &[u8] {
1003 self.0.as_ref()
1004 }
1005}
1006
1007impl Deref for Der<'_> {
1008 type Target = [u8];
1009
1010 fn deref(&self) -> &Self::Target {
1011 self.as_ref()
1012 }
1013}
1014
1015impl<'a> From<&'a [u8]> for Der<'a> {
1016 fn from(slice: &'a [u8]) -> Self {
1017 Self(BytesInner::Borrowed(slice))
1018 }
1019}
1020
1021#[cfg(feature = "alloc")]
1022impl From<Vec<u8>> for Der<'static> {
1023 fn from(vec: Vec<u8>) -> Self {
1024 Self(BytesInner::Owned(vec))
1025 }
1026}
1027
1028impl fmt::Debug for Der<'_> {
1029 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1030 hex(f, self.as_ref())
1031 }
1032}
1033
1034#[derive(Debug, Clone)]
1035enum BytesInner<'a> {
1036 #[cfg(feature = "alloc")]
1037 Owned(Vec<u8>),
1038 Borrowed(&'a [u8]),
1039}
1040
1041#[cfg(feature = "alloc")]
1042impl BytesInner<'_> {
1043 fn into_owned(self) -> BytesInner<'static> {
1044 BytesInner::Owned(match self {
1045 Self::Owned(vec) => vec,
1046 Self::Borrowed(slice) => slice.to_vec(),
1047 })
1048 }
1049}
1050
1051#[cfg(feature = "alloc")]
1052impl zeroize::Zeroize for BytesInner<'static> {
1053 fn zeroize(&mut self) {
1054 match self {
1055 BytesInner::Owned(vec) => vec.zeroize(),
1056 BytesInner::Borrowed(_) => (),
1057 }
1058 }
1059}
1060
1061impl AsRef<[u8]> for BytesInner<'_> {
1062 fn as_ref(&self) -> &[u8] {
1063 match &self {
1064 #[cfg(feature = "alloc")]
1065 BytesInner::Owned(vec) => vec.as_ref(),
1066 BytesInner::Borrowed(slice) => slice,
1067 }
1068 }
1069}
1070
1071impl core::hash::Hash for BytesInner<'_> {
1072 fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
1073 state.write(self.as_ref());
1074 }
1075}
1076
1077impl PartialEq for BytesInner<'_> {
1078 fn eq(&self, other: &Self) -> bool {
1079 self.as_ref() == other.as_ref()
1080 }
1081}
1082
1083impl Eq for BytesInner<'_> {}
1084
1085/// FIPS validation status of an algorithm or implementation.
1086#[allow(clippy::exhaustive_enums)]
1087#[derive(Clone, Copy, Debug, Eq, Ord, PartialEq, PartialOrd)]
1088pub enum FipsStatus {
1089 /// Not FIPS tested, or unapproved algorithm.
1090 Unvalidated,
1091 /// In queue for FIPS validation.
1092 Pending,
1093 /// FIPS certified, with named certificate.
1094 #[non_exhaustive]
1095 Certified {
1096 /// A name, number or URL referencing the FIPS certificate.
1097 certificate: &'static str,
1098 },
1099}
1100
1101// Format an iterator of u8 into a hex string
1102fn hex<'a>(f: &mut fmt::Formatter<'_>, payload: impl IntoIterator<Item = &'a u8>) -> fmt::Result {
1103 for (i, b) in payload.into_iter().enumerate() {
1104 if i == 0 {
1105 write!(f, "0x")?;
1106 }
1107 write!(f, "{b:02x}")?;
1108 }
1109 Ok(())
1110}
1111
1112#[cfg(all(test, feature = "std"))]
1113mod tests {
1114 use super::*;
1115
1116 #[test]
1117 fn der_debug() {
1118 let der = Der::from_slice(&[0x01, 0x02, 0x03]);
1119 assert_eq!(format!("{der:?}"), "0x010203");
1120 }
1121
1122 #[test]
1123 fn alg_id_debug() {
1124 let alg_id = AlgorithmIdentifier::from_slice(&[0x01, 0x02, 0x03]);
1125 assert_eq!(format!("{alg_id:?}"), "0x010203");
1126 }
1127
1128 #[test]
1129 fn bytes_inner_equality() {
1130 let owned_a = BytesInner::Owned(vec![1, 2, 3]);
1131 let owned_b = BytesInner::Owned(vec![4, 5]);
1132 let borrowed_a = BytesInner::Borrowed(&[1, 2, 3]);
1133 let borrowed_b = BytesInner::Borrowed(&[99]);
1134
1135 // Self-equality.
1136 assert_eq!(owned_a, owned_a);
1137 assert_eq!(owned_b, owned_b);
1138 assert_eq!(borrowed_a, borrowed_a);
1139 assert_eq!(borrowed_b, borrowed_b);
1140
1141 // Borrowed vs Owned equality
1142 assert_eq!(owned_a, borrowed_a);
1143 assert_eq!(borrowed_a, owned_a);
1144
1145 // Owned inequality
1146 assert_ne!(owned_a, owned_b);
1147 assert_ne!(owned_b, owned_a);
1148
1149 // Borrowed inequality
1150 assert_ne!(borrowed_a, borrowed_b);
1151 assert_ne!(borrowed_b, borrowed_a);
1152
1153 // Borrowed vs Owned inequality
1154 assert_ne!(owned_a, borrowed_b);
1155 assert_ne!(borrowed_b, owned_a);
1156 }
1157}