From 8e5d2ef4e4ef905adb186a8453dce747fe939472 Mon Sep 17 00:00:00 2001 From: Dirkjan Ochtman Date: Sat, 5 Aug 2023 21:30:38 +0200 Subject: [PATCH] Start collection of basic data types --- Cargo.toml | 8 +- src/lib.rs | 320 +++++++++++++++++++++++++++++++++++++++++++++++++++-- 2 files changed, 315 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f05ef16..259f886 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,10 @@ [package] name = "rustls-pki-types" -version = "0.1.0" +version = "1.0.0-alpha.1" edition = "2021" rust-version = "1.60" license = "MIT OR Apache-2.0" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - -[dependencies] +[features] +default = ["alloc"] +alloc = [] diff --git a/src/lib.rs b/src/lib.rs index 7d12d9a..0f8df60 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,14 +1,316 @@ -pub fn add(left: usize, right: usize) -> usize { - left + right +#![no_std] +#![warn(unreachable_pub)] +#![warn(clippy::use_self)] + +#[cfg(feature = "alloc")] +extern crate alloc; + +#[cfg(feature = "alloc")] +use alloc::vec::Vec; +use core::fmt; +use core::ops::Deref; + +/// A DER-encoded X.509 private key, in one of several formats +/// +/// See variant inner types for more detailed information. +#[non_exhaustive] +#[derive(Debug, PartialEq)] +pub enum PrivateKeyDer<'a> { + Pkcs1(PrivatePkcs1KeyDer<'a>), + Sec1(PrivateSec1KeyDer<'a>), + Pkcs8(PrivatePkcs8KeyDer<'a>), +} + +impl<'a> PrivateKeyDer<'a> { + pub fn secret_der(&self) -> &[u8] { + match self { + PrivateKeyDer::Pkcs1(key) => key.secret_pkcs1_der(), + PrivateKeyDer::Sec1(key) => key.secret_sec1_der(), + PrivateKeyDer::Pkcs8(key) => key.secret_pkcs8_der(), + } + } +} + +/// A DER-encoded plaintext RSA private key; as specified in PKCS#1/RFC 3447 +/// +/// A common format for storing private keys is +/// [PEM](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail). +/// PEM blocks for RSA (PKCS#1) private keys are commonly stored in files with a `.pem` or `.key` +/// suffix, and look like this: +/// +/// ```txt +/// -----BEGIN RSA PRIVATE KEY----- +/// +/// -----END RSA PRIVATE KEY----- +/// ``` +/// +/// The [`rustls-pemfile`](https://docs.rs/rustls-pemfile/latest/rustls_pemfile/) crate can be used +/// to parse PEM files. The [`rcgen`](https://docs.rs/rcgen/latest/rcgen/) crate can be used to +/// generate certificates and private keys. +#[derive(PartialEq)] +pub struct PrivatePkcs1KeyDer<'a>(Der<'a>); + +impl PrivatePkcs1KeyDer<'_> { + pub fn secret_pkcs1_der(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl<'a> From<&'a [u8]> for PrivatePkcs1KeyDer<'a> { + fn from(slice: &'a [u8]) -> Self { + Self(Der(DerInner::Slice(slice))) + } +} + +#[cfg(feature = "alloc")] +impl<'a> From> for PrivatePkcs1KeyDer<'a> { + fn from(vec: Vec) -> Self { + Self(Der(DerInner::Vec(vec))) + } +} + +impl fmt::Debug for PrivatePkcs1KeyDer<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("PrivatePkcs1KeyDer") + .field(&"[secret key elided]") + .finish() + } +} + +/// A Sec1-encoded plaintext private key; as specified in RFC 5915 +/// +/// A common format for storing private keys is +/// [PEM](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail). +/// PEM blocks for Sec1 private keys are commonly stored in files with a `.pem` or `.key` +/// suffix, and look like this: +/// +/// ```txt +/// -----BEGIN EC PRIVATE KEY----- +/// +/// -----END EC PRIVATE KEY----- +/// ``` +/// +/// The [`rustls-pemfile`](https://docs.rs/rustls-pemfile/latest/rustls_pemfile/) crate can be used +/// to parse PEM files. The [`rcgen`](https://docs.rs/rcgen/latest/rcgen/) crate can be used to +/// generate certificates and private keys. +#[derive(PartialEq)] +pub struct PrivateSec1KeyDer<'a>(Der<'a>); + +impl PrivateSec1KeyDer<'_> { + pub fn secret_sec1_der(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl<'a> From<&'a [u8]> for PrivateSec1KeyDer<'a> { + fn from(slice: &'a [u8]) -> Self { + Self(Der(DerInner::Slice(slice))) + } +} + +#[cfg(feature = "alloc")] +impl<'a> From> for PrivateSec1KeyDer<'a> { + fn from(vec: Vec) -> Self { + Self(Der(DerInner::Vec(vec))) + } +} + +impl fmt::Debug for PrivateSec1KeyDer<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("PrivatePkcs1KeyDer") + .field(&"[secret key elided]") + .finish() + } +} + +/// A DER-encoded plaintext private key; as specified in PKCS#8/RFC 5958 +/// +/// A common format for storing private keys is +/// [PEM](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail). +/// PEM blocks for PKCS#8 private keys are commonly stored in files with a `.pem` or `.key` +/// suffix, and look like this: +/// +/// ```txt +/// -----BEGIN PRIVATE KEY----- +/// +/// -----END PRIVATE KEY----- +/// ``` +/// +/// The [`rustls-pemfile`](https://docs.rs/rustls-pemfile/latest/rustls_pemfile/) crate can be used +/// to parse PEM files. The [`rcgen`](https://docs.rs/rcgen/latest/rcgen/) crate can be used to +/// generate certificates and private keys. +/// ``` +#[derive(PartialEq)] +pub struct PrivatePkcs8KeyDer<'a>(Der<'a>); + +impl PrivatePkcs8KeyDer<'_> { + pub fn secret_pkcs8_der(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl<'a> From<&'a [u8]> for PrivatePkcs8KeyDer<'a> { + fn from(slice: &'a [u8]) -> Self { + Self(Der(DerInner::Slice(slice))) + } +} + +#[cfg(feature = "alloc")] +impl<'a> From> for PrivatePkcs8KeyDer<'a> { + fn from(vec: Vec) -> Self { + Self(Der(DerInner::Vec(vec))) + } +} + +impl fmt::Debug for PrivatePkcs8KeyDer<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("PrivatePkcs1KeyDer") + .field(&"[secret key elided]") + .finish() + } +} + +/// A trust anchor (a.k.a. root CA), represented as a DER-encoded X.509 certificate +/// +/// Traditionally, certificate verification libraries have represented trust anchors as full X.509 +/// root certificates. However, those certificates contain a lot more data than is needed for +/// verifying certificates. The [`TrustAnchor`] representation allows an application to store +/// just the essential elements of trust anchors. +#[derive(Clone, Debug, PartialEq)] +pub struct TrustAnchor<'a> { + pub subject: Der<'a>, + pub subject_public_key_info: Der<'a>, + pub name_constraints: Option>, } -#[cfg(test)] -mod tests { - use super::*; +/// A Certificate Revocation List; as specified in RFC 5280 +#[derive(Debug, PartialEq)] +pub struct CertificateRevocationListDer<'a>(Der<'a>); - #[test] - fn it_works() { - let result = add(2, 2); - assert_eq!(result, 4); +impl AsRef<[u8]> for CertificateRevocationListDer<'_> { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() } } + +impl Deref for CertificateRevocationListDer<'_> { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.as_ref() + } +} + +impl<'a> From<&'a [u8]> for CertificateRevocationListDer<'a> { + fn from(slice: &'a [u8]) -> Self { + Self(Der::from(slice)) + } +} + +#[cfg(feature = "alloc")] +impl<'a> From> for CertificateRevocationListDer<'a> { + fn from(vec: Vec) -> Self { + Self(Der::from(vec)) + } +} + +/// A DER-encoded X.509 certificate; as specified in RFC 5280 +/// +/// A common format for storing certificates is +/// [PEM](https://en.wikipedia.org/wiki/Privacy-Enhanced_Mail). +/// PEM certificates are commonly stored in files with a `.pem`, `.cer` or `.crt` suffix, and look +/// like this: +/// +/// ```txt +/// -----BEGIN BEGIN EC PRIVATE KEY----- +/// +/// -----END CERTIFICATE----- +/// ``` +/// +/// The [`rustls-pemfile`](https://docs.rs/rustls-pemfile/latest/rustls_pemfile/) crate can be used +/// to parse PEM files. The [`rcgen`](https://docs.rs/rcgen/latest/rcgen/) crate can be used to +/// generate certificates and private keys. +/// ``` +#[derive(Clone, Debug, PartialEq)] +pub struct CertificateDer<'a>(Der<'a>); + +impl AsRef<[u8]> for CertificateDer<'_> { + fn as_ref(&self) -> &[u8] { + self.0.as_ref() + } +} + +impl Deref for CertificateDer<'_> { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.as_ref() + } +} + +impl<'a> From<&'a [u8]> for CertificateDer<'a> { + fn from(slice: &'a [u8]) -> Self { + Self(Der::from(slice)) + } +} + +#[cfg(feature = "alloc")] +impl<'a> From> for CertificateDer<'a> { + fn from(vec: Vec) -> Self { + Self(Der::from(vec)) + } +} + +#[derive(Clone, PartialEq)] +pub struct Der<'a>(DerInner<'a>); + +impl<'a> Der<'a> { + // Trait methods cannot be const, so we additionally offer some traditional constructors. + pub const fn from_slice(der: &'a [u8]) -> Self { + Self(DerInner::Slice(der)) + } +} + +impl AsRef<[u8]> for Der<'_> { + fn as_ref(&self) -> &[u8] { + match &self.0 { + #[cfg(feature = "alloc")] + DerInner::Vec(vec) => vec.as_ref(), + DerInner::Slice(slice) => slice, + } + } +} + +impl Deref for Der<'_> { + type Target = [u8]; + + fn deref(&self) -> &Self::Target { + self.as_ref() + } +} + +impl<'a> From<&'a [u8]> for Der<'a> { + fn from(slice: &'a [u8]) -> Self { + Self(DerInner::Slice(slice)) + } +} + +#[cfg(feature = "alloc")] +impl<'a> From> for Der<'a> { + fn from(vec: Vec) -> Self { + Self(DerInner::Vec(vec)) + } +} + +impl fmt::Debug for Der<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Der").field(&self.as_ref()).finish() + } +} + +#[derive(Clone, PartialEq)] +enum DerInner<'a> { + #[cfg(feature = "alloc")] + Vec(Vec), + Slice(&'a [u8]), +}