use std::fmt;
use crate::Error;
#[derive(Clone)]
pub struct Certificate<'a> {
der: CertDer<'a>,
}
#[derive(Clone)]
enum CertDer<'a> {
Borrowed(&'a [u8]),
Owned(Vec<u8>),
Rustls(rustls_pki_types::CertificateDer<'static>),
}
impl<'a> AsRef<[u8]> for CertDer<'a> {
fn as_ref(&self) -> &[u8] {
match self {
CertDer::Borrowed(v) => v,
CertDer::Owned(v) => v,
CertDer::Rustls(v) => v,
}
}
}
impl<'a> Certificate<'a> {
pub fn from_der(der: &'a [u8]) -> Self {
let der = CertDer::Borrowed(der);
Certificate { der }
}
pub fn from_pem(pem: &'a [u8]) -> Result<Certificate<'static>, Error> {
let item = parse_pem(pem)
.find(|p| matches!(p, Err(_) | Ok(PemItem::Certificate(_))))
.ok_or(Error::Tls("No pem encoded cert found"))??;
let PemItem::Certificate(cert) = item else {
unreachable!("matches! above for Certificate");
};
Ok(cert)
}
pub fn der(&self) -> &[u8] {
self.der.as_ref()
}
pub fn to_owned(&self) -> Certificate<'static> {
Certificate {
der: CertDer::Owned(self.der.as_ref().to_vec()),
}
}
}
pub struct PrivateKey<'a> {
kind: KeyKind,
der: PrivateKeyDer<'a>,
}
enum PrivateKeyDer<'a> {
Borrowed(&'a [u8]),
Owned(Vec<u8>),
Rustls(rustls_pki_types::PrivateKeyDer<'static>),
}
impl<'a> AsRef<[u8]> for PrivateKey<'a> {
fn as_ref(&self) -> &[u8] {
match &self.der {
PrivateKeyDer::Borrowed(v) => v,
PrivateKeyDer::Owned(v) => v,
PrivateKeyDer::Rustls(v) => v.secret_der(),
}
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[non_exhaustive]
pub enum KeyKind {
Pkcs1,
Pkcs8,
Sec1,
}
impl<'a> PrivateKey<'a> {
pub fn from_der(kind: KeyKind, der: &'a [u8]) -> Self {
let der = PrivateKeyDer::Borrowed(der);
PrivateKey { kind, der }
}
pub fn from_pem(pem: &'a [u8]) -> Result<PrivateKey<'static>, Error> {
let item = parse_pem(pem)
.find(|p| matches!(p, Err(_) | Ok(PemItem::PrivateKey(_))))
.ok_or(Error::Tls("No pem encoded private key found"))??;
let PemItem::PrivateKey(key) = item else {
unreachable!("matches! above for PrivateKey");
};
Ok(key)
}
pub fn kind(&self) -> KeyKind {
self.kind
}
pub fn der(&self) -> &[u8] {
self.as_ref()
}
pub fn to_owned(&self) -> PrivateKey<'static> {
PrivateKey {
kind: self.kind,
der: match &self.der {
PrivateKeyDer::Borrowed(v) => PrivateKeyDer::Owned(v.to_vec()),
PrivateKeyDer::Owned(v) => PrivateKeyDer::Owned(v.to_vec()),
PrivateKeyDer::Rustls(v) => PrivateKeyDer::Rustls(v.clone_key()),
},
}
}
}
pub fn parse_pem(pem: &[u8]) -> impl Iterator<Item = Result<PemItem<'static>, Error>> + '_ {
PemIter(pem)
}
#[non_exhaustive]
pub enum PemItem<'a> {
Certificate(Certificate<'a>),
PrivateKey(PrivateKey<'a>),
}
struct PemIter<'a>(&'a [u8]);
impl<'a> Iterator for PemIter<'a> {
type Item = Result<PemItem<'static>, Error>;
fn next(&mut self) -> Option<Self::Item> {
loop {
match rustls_pemfile::read_one_from_slice(self.0) {
Ok(Some((cert, rest))) => {
self.0 = rest;
match cert {
rustls_pemfile::Item::X509Certificate(der) => {
return Some(Ok(Certificate {
der: CertDer::Rustls(der),
}
.into()));
}
rustls_pemfile::Item::Pkcs1Key(der) => {
return Some(Ok(PrivateKey {
kind: KeyKind::Pkcs1,
der: PrivateKeyDer::Rustls(der.into()),
}
.into()));
}
rustls_pemfile::Item::Pkcs8Key(der) => {
return Some(Ok(PrivateKey {
kind: KeyKind::Pkcs8,
der: PrivateKeyDer::Rustls(der.into()),
}
.into()));
}
rustls_pemfile::Item::Sec1Key(der) => {
return Some(Ok(PrivateKey {
kind: KeyKind::Sec1,
der: PrivateKeyDer::Rustls(der.into()),
}
.into()));
}
_ => continue,
}
}
Ok(None) => return None,
Err(e) => {
return Some(Err(Error::Pem(e)));
}
}
}
}
}
impl<'a> From<Certificate<'a>> for PemItem<'a> {
fn from(value: Certificate<'a>) -> Self {
PemItem::Certificate(value)
}
}
impl<'a> From<PrivateKey<'a>> for PemItem<'a> {
fn from(value: PrivateKey<'a>) -> Self {
PemItem::PrivateKey(value)
}
}
impl<'a> fmt::Debug for Certificate<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Certificate").finish()
}
}
impl<'a> fmt::Debug for PrivateKey<'a> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("PrivateKey")
.field("kind", &self.kind)
.finish()
}
}