#![cfg_attr(not(feature = "std"), no_std)]
#![warn(unreachable_pub, clippy::use_self)]
#![deny(missing_docs)]
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
#[cfg(feature = "alloc")]
extern crate alloc;
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
use core::fmt;
use core::ops::Deref;
use core::time::Duration;
#[cfg(all(
feature = "std",
not(all(target_family = "wasm", target_os = "unknown"))
))]
use std::time::SystemTime;
#[cfg(all(target_family = "wasm", target_os = "unknown", feature = "web"))]
use web_time::SystemTime;
mod server_name;
pub use server_name::{
AddrParseError, DnsName, InvalidDnsNameError, IpAddr, Ipv4Addr, Ipv6Addr, ServerName,
};
#[non_exhaustive]
#[derive(Debug, PartialEq, Eq)]
pub enum PrivateKeyDer<'a> {
Pkcs1(PrivatePkcs1KeyDer<'a>),
Sec1(PrivateSec1KeyDer<'a>),
Pkcs8(PrivatePkcs8KeyDer<'a>),
}
impl<'a> PrivateKeyDer<'a> {
#[cfg(feature = "alloc")]
pub fn clone_key(&self) -> PrivateKeyDer<'static> {
use PrivateKeyDer::*;
match self {
Pkcs1(key) => Pkcs1(key.clone_key()),
Sec1(key) => Sec1(key.clone_key()),
Pkcs8(key) => Pkcs8(key.clone_key()),
}
}
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(),
}
}
}
impl<'a> From<PrivatePkcs1KeyDer<'a>> for PrivateKeyDer<'a> {
fn from(key: PrivatePkcs1KeyDer<'a>) -> Self {
Self::Pkcs1(key)
}
}
impl<'a> From<PrivateSec1KeyDer<'a>> for PrivateKeyDer<'a> {
fn from(key: PrivateSec1KeyDer<'a>) -> Self {
Self::Sec1(key)
}
}
impl<'a> From<PrivatePkcs8KeyDer<'a>> for PrivateKeyDer<'a> {
fn from(key: PrivatePkcs8KeyDer<'a>) -> Self {
Self::Pkcs8(key)
}
}
impl<'a> TryFrom<&'a [u8]> for PrivateKeyDer<'a> {
type Error = &'static str;
fn try_from(key: &'a [u8]) -> Result<Self, Self::Error> {
const SHORT_FORM_LEN_MAX: u8 = 128;
const TAG_SEQUENCE: u8 = 0x30;
const TAG_INTEGER: u8 = 0x02;
if key.first() != Some(&TAG_SEQUENCE) || key.len() < 2 {
return Err(INVALID_KEY_DER_ERR);
}
let skip_len = match key[1] >= SHORT_FORM_LEN_MAX {
false => 2,
true => 2 + (key[1] - SHORT_FORM_LEN_MAX) as usize,
};
let key_bytes = key.get(skip_len..).ok_or(INVALID_KEY_DER_ERR)?;
if matches!(key_bytes, [TAG_INTEGER, 0x01, _, TAG_SEQUENCE, ..]) {
return Ok(Self::Pkcs8(key.into()));
}
if key_bytes.starts_with(&[TAG_INTEGER, 0x01, 0x00]) {
return Ok(Self::Pkcs1(key.into()));
}
if key_bytes.starts_with(&[TAG_INTEGER, 0x01, 0x01]) {
return Ok(Self::Sec1(key.into()));
}
Err(INVALID_KEY_DER_ERR)
}
}
static INVALID_KEY_DER_ERR: &str = "unknown or invalid key format";
#[cfg(feature = "alloc")]
impl<'a> TryFrom<Vec<u8>> for PrivateKeyDer<'a> {
type Error = &'static str;
fn try_from(key: Vec<u8>) -> Result<Self, Self::Error> {
Ok(match PrivateKeyDer::try_from(&key[..])? {
PrivateKeyDer::Pkcs1(_) => Self::Pkcs1(key.into()),
PrivateKeyDer::Sec1(_) => Self::Sec1(key.into()),
PrivateKeyDer::Pkcs8(_) => Self::Pkcs8(key.into()),
})
}
}
#[derive(PartialEq, Eq)]
pub struct PrivatePkcs1KeyDer<'a>(Der<'a>);
impl PrivatePkcs1KeyDer<'_> {
#[cfg(feature = "alloc")]
pub fn clone_key(&self) -> PrivatePkcs1KeyDer<'static> {
PrivatePkcs1KeyDer::from(self.0.as_ref().to_vec())
}
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(BytesInner::Borrowed(slice)))
}
}
#[cfg(feature = "alloc")]
impl<'a> From<Vec<u8>> for PrivatePkcs1KeyDer<'a> {
fn from(vec: Vec<u8>) -> Self {
Self(Der(BytesInner::Owned(vec)))
}
}
impl fmt::Debug for PrivatePkcs1KeyDer<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("PrivatePkcs1KeyDer")
.field(&"[secret key elided]")
.finish()
}
}
#[derive(PartialEq, Eq)]
pub struct PrivateSec1KeyDer<'a>(Der<'a>);
impl PrivateSec1KeyDer<'_> {
#[cfg(feature = "alloc")]
pub fn clone_key(&self) -> PrivateSec1KeyDer<'static> {
PrivateSec1KeyDer::from(self.0.as_ref().to_vec())
}
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(BytesInner::Borrowed(slice)))
}
}
#[cfg(feature = "alloc")]
impl<'a> From<Vec<u8>> for PrivateSec1KeyDer<'a> {
fn from(vec: Vec<u8>) -> Self {
Self(Der(BytesInner::Owned(vec)))
}
}
impl fmt::Debug for PrivateSec1KeyDer<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("PrivateSec1KeyDer")
.field(&"[secret key elided]")
.finish()
}
}
#[derive(PartialEq, Eq)]
pub struct PrivatePkcs8KeyDer<'a>(Der<'a>);
impl PrivatePkcs8KeyDer<'_> {
#[cfg(feature = "alloc")]
pub fn clone_key(&self) -> PrivatePkcs8KeyDer<'static> {
PrivatePkcs8KeyDer::from(self.0.as_ref().to_vec())
}
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(BytesInner::Borrowed(slice)))
}
}
#[cfg(feature = "alloc")]
impl<'a> From<Vec<u8>> for PrivatePkcs8KeyDer<'a> {
fn from(vec: Vec<u8>) -> Self {
Self(Der(BytesInner::Owned(vec)))
}
}
impl fmt::Debug for PrivatePkcs8KeyDer<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("PrivatePkcs8KeyDer")
.field(&"[secret key elided]")
.finish()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct TrustAnchor<'a> {
pub subject: Der<'a>,
pub subject_public_key_info: Der<'a>,
pub name_constraints: Option<Der<'a>>,
}
impl TrustAnchor<'_> {
#[cfg(feature = "alloc")]
pub fn to_owned(&self) -> TrustAnchor<'static> {
#[cfg(not(feature = "std"))]
use alloc::borrow::ToOwned;
TrustAnchor {
subject: self.subject.as_ref().to_owned().into(),
subject_public_key_info: self.subject_public_key_info.as_ref().to_owned().into(),
name_constraints: self
.name_constraints
.as_ref()
.map(|nc| nc.as_ref().to_owned().into()),
}
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CertificateRevocationListDer<'a>(Der<'a>);
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<Vec<u8>> for CertificateRevocationListDer<'a> {
fn from(vec: Vec<u8>) -> Self {
Self(Der::from(vec))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct CertificateSigningRequestDer<'a>(Der<'a>);
impl AsRef<[u8]> for CertificateSigningRequestDer<'_> {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl Deref for CertificateSigningRequestDer<'_> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
impl<'a> From<&'a [u8]> for CertificateSigningRequestDer<'a> {
fn from(slice: &'a [u8]) -> Self {
Self(Der::from(slice))
}
}
#[cfg(feature = "alloc")]
impl<'a> From<Vec<u8>> for CertificateSigningRequestDer<'a> {
fn from(vec: Vec<u8>) -> Self {
Self(Der::from(vec))
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
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<Vec<u8>> for CertificateDer<'a> {
fn from(vec: Vec<u8>) -> Self {
Self(Der::from(vec))
}
}
impl CertificateDer<'_> {
#[cfg(feature = "alloc")]
pub fn into_owned(self) -> CertificateDer<'static> {
CertificateDer(Der(self.0 .0.into_owned()))
}
}
#[derive(Clone, Eq, PartialEq)]
pub struct EchConfigListBytes<'a>(BytesInner<'a>);
impl EchConfigListBytes<'_> {
#[cfg(feature = "alloc")]
pub fn into_owned(self) -> EchConfigListBytes<'static> {
EchConfigListBytes(self.0.into_owned())
}
}
impl fmt::Debug for EchConfigListBytes<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
hex(f, self.as_ref())
}
}
impl AsRef<[u8]> for EchConfigListBytes<'_> {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
impl Deref for EchConfigListBytes<'_> {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
impl<'a> From<&'a [u8]> for EchConfigListBytes<'a> {
fn from(slice: &'a [u8]) -> Self {
Self(BytesInner::Borrowed(slice))
}
}
#[cfg(feature = "alloc")]
impl<'a> From<Vec<u8>> for EchConfigListBytes<'a> {
fn from(vec: Vec<u8>) -> Self {
Self(BytesInner::Owned(vec))
}
}
pub trait SignatureVerificationAlgorithm: Send + Sync + fmt::Debug {
fn verify_signature(
&self,
public_key: &[u8],
message: &[u8],
signature: &[u8],
) -> Result<(), InvalidSignature>;
fn public_key_alg_id(&self) -> AlgorithmIdentifier;
fn signature_alg_id(&self) -> AlgorithmIdentifier;
fn fips(&self) -> bool {
false
}
}
#[derive(Debug, Copy, Clone)]
pub struct InvalidSignature;
#[derive(Clone, Copy, PartialEq, Eq)]
pub struct AlgorithmIdentifier(&'static [u8]);
impl AlgorithmIdentifier {
pub const fn from_slice(bytes: &'static [u8]) -> Self {
Self(bytes)
}
}
impl AsRef<[u8]> for AlgorithmIdentifier {
fn as_ref(&self) -> &[u8] {
self.0
}
}
impl fmt::Debug for AlgorithmIdentifier {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
hex(f, self.0)
}
}
impl Deref for AlgorithmIdentifier {
type Target = [u8];
fn deref(&self) -> &Self::Target {
self.as_ref()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd)]
pub struct UnixTime(u64);
impl UnixTime {
#[cfg(any(
all(
feature = "std",
not(all(target_family = "wasm", target_os = "unknown"))
),
all(target_family = "wasm", target_os = "unknown", feature = "web")
))]
pub fn now() -> Self {
Self::since_unix_epoch(
SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.unwrap(), )
}
pub fn since_unix_epoch(duration: Duration) -> Self {
Self(duration.as_secs())
}
pub fn as_secs(&self) -> u64 {
self.0
}
}
#[derive(Clone, Eq, PartialEq)]
pub struct Der<'a>(BytesInner<'a>);
impl<'a> Der<'a> {
pub const fn from_slice(der: &'a [u8]) -> Self {
Self(BytesInner::Borrowed(der))
}
}
impl AsRef<[u8]> for Der<'_> {
fn as_ref(&self) -> &[u8] {
self.0.as_ref()
}
}
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(BytesInner::Borrowed(slice))
}
}
#[cfg(feature = "alloc")]
impl From<Vec<u8>> for Der<'static> {
fn from(vec: Vec<u8>) -> Self {
Self(BytesInner::Owned(vec))
}
}
impl fmt::Debug for Der<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
hex(f, self.as_ref())
}
}
#[derive(Debug, Clone)]
enum BytesInner<'a> {
#[cfg(feature = "alloc")]
Owned(Vec<u8>),
Borrowed(&'a [u8]),
}
#[cfg(feature = "alloc")]
impl BytesInner<'_> {
fn into_owned(self) -> BytesInner<'static> {
BytesInner::Owned(match self {
Self::Owned(vec) => vec,
Self::Borrowed(slice) => slice.to_vec(),
})
}
}
impl AsRef<[u8]> for BytesInner<'_> {
fn as_ref(&self) -> &[u8] {
match &self {
#[cfg(feature = "alloc")]
BytesInner::Owned(vec) => vec.as_ref(),
BytesInner::Borrowed(slice) => slice,
}
}
}
impl PartialEq for BytesInner<'_> {
fn eq(&self, other: &Self) -> bool {
self.as_ref() == other.as_ref()
}
}
impl Eq for BytesInner<'_> {}
fn hex<'a>(f: &mut fmt::Formatter<'_>, payload: impl IntoIterator<Item = &'a u8>) -> fmt::Result {
for (i, b) in payload.into_iter().enumerate() {
if i == 0 {
write!(f, "0x")?;
}
write!(f, "{:02x}", b)?;
}
Ok(())
}
#[cfg(all(test, feature = "std"))]
mod tests {
use super::*;
#[test]
fn der_debug() {
let der = Der::from_slice(&[0x01, 0x02, 0x03]);
assert_eq!(format!("{:?}", der), "0x010203");
}
#[test]
fn alg_id_debug() {
let alg_id = AlgorithmIdentifier::from_slice(&[0x01, 0x02, 0x03]);
assert_eq!(format!("{:?}", alg_id), "0x010203");
}
#[test]
fn bytes_inner_equality() {
let owned_a = BytesInner::Owned(vec![1, 2, 3]);
let owned_b = BytesInner::Owned(vec![4, 5]);
let borrowed_a = BytesInner::Borrowed(&[1, 2, 3]);
let borrowed_b = BytesInner::Borrowed(&[99]);
assert_eq!(owned_a, owned_a);
assert_eq!(owned_b, owned_b);
assert_eq!(borrowed_a, borrowed_a);
assert_eq!(borrowed_b, borrowed_b);
assert_eq!(owned_a, borrowed_a);
assert_eq!(borrowed_a, owned_a);
assert_ne!(owned_a, owned_b);
assert_ne!(owned_b, owned_a);
assert_ne!(borrowed_a, borrowed_b);
assert_ne!(borrowed_b, borrowed_a);
assert_ne!(owned_a, borrowed_b);
assert_ne!(borrowed_b, owned_a);
}
}