use alloc::boxed::Box;
use alloc::vec::Vec;
use core::fmt::Debug;
use core::hash::{Hash, Hasher};
use core::iter;
#[cfg(feature = "webpki")]
use pki_types::PrivateKeyDer;
use pki_types::{AlgorithmIdentifier, CertificateDer, SubjectPublicKeyInfoDer};
#[cfg(feature = "webpki")]
use super::CryptoProvider;
use crate::client::{ClientCredentialResolver, CredentialRequest};
use crate::crypto::SignatureScheme;
use crate::enums::CertificateType;
use crate::error::{ApiMisuse, Error, InvalidMessage, PeerIncompatible};
use crate::msgs::{Codec, Reader};
use crate::server::{ClientHello, ServerCredentialResolver};
use crate::sync::Arc;
#[cfg(feature = "webpki")]
use crate::webpki::ParsedCertificate;
use crate::{DynHasher, SignerPublicKey, x509};
#[derive(Debug, Hash)]
pub struct SingleCredential {
credentials: Credentials,
types: &'static [CertificateType],
}
impl From<Credentials> for SingleCredential {
fn from(credentials: Credentials) -> Self {
match &*credentials.identity {
Identity::X509(_) => Self {
credentials,
types: &[CertificateType::X509],
},
Identity::RawPublicKey(_) => Self {
credentials,
types: &[CertificateType::RawPublicKey],
},
}
}
}
impl ClientCredentialResolver for SingleCredential {
fn resolve(&self, request: &CredentialRequest<'_>) -> Option<SelectedCredential> {
match (&*self.credentials.identity, request.negotiated_type()) {
(Identity::X509(_), CertificateType::X509)
| (Identity::RawPublicKey(_), CertificateType::RawPublicKey) => self
.credentials
.signer(request.signature_schemes()),
_ => None,
}
}
fn supported_certificate_types(&self) -> &'static [CertificateType] {
self.types
}
fn hash_config(&self, h: &mut dyn Hasher) {
self.hash(&mut DynHasher(h));
}
}
impl ServerCredentialResolver for SingleCredential {
fn resolve(&self, client_hello: &ClientHello<'_>) -> Result<SelectedCredential, Error> {
self.credentials
.signer(client_hello.signature_schemes())
.ok_or(Error::PeerIncompatible(
PeerIncompatible::NoSignatureSchemesInCommon,
))
}
fn supported_certificate_types(&self) -> &'static [CertificateType] {
self.types
}
}
#[non_exhaustive]
#[derive(Debug)]
pub struct Credentials {
pub identity: Arc<Identity<'static>>,
pub key: Box<dyn SigningKey>,
pub ocsp: Option<Arc<[u8]>>,
}
impl Credentials {
#[cfg(feature = "webpki")]
pub fn from_der(
identity: Arc<Identity<'static>>,
key: PrivateKeyDer<'static>,
provider: &CryptoProvider,
) -> Result<Self, Error> {
Self::new(
identity,
provider
.key_provider
.load_private_key(key)?,
)
}
#[cfg(feature = "webpki")]
pub fn new(identity: Arc<Identity<'static>>, key: Box<dyn SigningKey>) -> Result<Self, Error> {
if let Identity::X509(CertificateIdentity { end_entity, .. }) = &*identity {
let parsed = ParsedCertificate::try_from(end_entity)?;
match (key.public_key(), parsed.subject_public_key_info()) {
(None, _) => return Err(Error::InconsistentKeys(InconsistentKeys::Unknown)),
(Some(key_spki), cert_spki) if key_spki != cert_spki => {
return Err(Error::InconsistentKeys(InconsistentKeys::KeyMismatch));
}
_ => {}
}
};
Ok(Self {
identity,
key,
ocsp: None,
})
}
pub fn new_unchecked(identity: Arc<Identity<'static>>, key: Box<dyn SigningKey>) -> Self {
Self {
identity,
key,
ocsp: None,
}
}
pub fn signer(&self, sig_schemes: &[SignatureScheme]) -> Option<SelectedCredential> {
Some(SelectedCredential {
identity: self.identity.clone(),
signer: self.key.choose_scheme(sig_schemes)?,
ocsp: self.ocsp.clone(),
})
}
}
impl Hash for Credentials {
fn hash<H: Hasher>(&self, state: &mut H) {
self.identity.hash(state);
self.ocsp.hash(state);
}
}
#[non_exhaustive]
#[derive(Debug)]
pub struct SelectedCredential {
pub identity: Arc<Identity<'static>>,
pub signer: Box<dyn Signer>,
pub ocsp: Option<Arc<[u8]>>,
}
#[non_exhaustive]
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub enum Identity<'a> {
X509(CertificateIdentity<'a>),
RawPublicKey(SubjectPublicKeyInfoDer<'a>),
}
impl<'a> Identity<'a> {
pub fn from_cert_chain(mut cert_chain: Vec<CertificateDer<'a>>) -> Result<Self, ApiMisuse> {
let mut iter = cert_chain.drain(..);
let Some(first) = iter.next() else {
return Err(ApiMisuse::EmptyCertificateChain);
};
Ok(Self::X509(CertificateIdentity {
end_entity: first,
intermediates: iter.collect(),
}))
}
pub(crate) fn from_peer(
mut cert_chain: Vec<CertificateDer<'a>>,
expected: CertificateType,
) -> Result<Option<Self>, Error> {
let mut iter = cert_chain.drain(..);
let Some(first) = iter.next() else {
return Ok(None);
};
match expected {
CertificateType::X509 => Ok(Some(Self::X509(CertificateIdentity {
end_entity: first,
intermediates: iter.collect(),
}))),
CertificateType::RawPublicKey => match iter.count() {
0 => Ok(Some(Self::RawPublicKey(
SubjectPublicKeyInfoDer::from(first.as_ref()).into_owned(),
))),
_ => Err(PeerIncompatible::MultipleRawKeys.into()),
},
CertificateType(ty) => Err(PeerIncompatible::UnknownCertificateType(ty).into()),
}
}
pub fn into_owned(self) -> Identity<'static> {
match self {
Self::X509(id) => Identity::X509(id.into_owned()),
Self::RawPublicKey(spki) => Identity::RawPublicKey(spki.into_owned()),
}
}
pub(crate) fn as_certificates(&'a self) -> impl Iterator<Item = CertificateDer<'a>> + 'a {
match self {
Self::X509(cert) => IdentityCertificateIterator::X509(
iter::once(CertificateDer::from(cert.end_entity.as_ref())).chain(
cert.intermediates
.iter()
.map(|c| CertificateDer::from(c.as_ref())),
),
),
Self::RawPublicKey(spki) => IdentityCertificateIterator::RawPublicKey(iter::once(
CertificateDer::from(spki.as_ref()),
)),
}
}
pub fn as_signer(&self) -> SignerPublicKey<'_> {
match self {
Self::X509(cert) => SignerPublicKey::X509(&cert.end_entity),
Self::RawPublicKey(spki) => SignerPublicKey::RawPublicKey(spki),
}
}
}
impl<'a> Codec<'a> for Identity<'a> {
fn encode(&self, bytes: &mut Vec<u8>) {
match self {
Self::X509(certificates) => {
0u8.encode(bytes);
certificates.end_entity.encode(bytes);
certificates.intermediates.encode(bytes);
}
Self::RawPublicKey(spki) => {
1u8.encode(bytes);
spki.encode(bytes);
}
}
}
fn read(reader: &mut Reader<'a>) -> Result<Self, InvalidMessage> {
match u8::read(reader)? {
0 => Ok(Self::X509(CertificateIdentity {
end_entity: CertificateDer::read(reader)?.into_owned(),
intermediates: Vec::<CertificateDer<'_>>::read(reader)?
.into_iter()
.collect(),
})),
1 => Ok(Self::RawPublicKey(
SubjectPublicKeyInfoDer::read(reader)?.into_owned(),
)),
_ => Err(InvalidMessage::UnexpectedMessage(
"invalid PeerIdentity discriminant",
)),
}
}
}
enum IdentityCertificateIterator<C, R> {
X509(C),
RawPublicKey(R),
}
impl<'a, C, R> Iterator for IdentityCertificateIterator<C, R>
where
C: Iterator<Item = CertificateDer<'a>>,
R: Iterator<Item = CertificateDer<'a>>,
{
type Item = CertificateDer<'a>;
fn next(&mut self) -> Option<Self::Item> {
match self {
Self::X509(iter) => iter.next(),
Self::RawPublicKey(iter) => iter.next(),
}
}
}
#[non_exhaustive]
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct CertificateIdentity<'a> {
pub end_entity: CertificateDer<'a>,
pub intermediates: Vec<CertificateDer<'a>>,
}
impl<'a> CertificateIdentity<'a> {
pub fn new(end_entity: CertificateDer<'a>, intermediates: Vec<CertificateDer<'a>>) -> Self {
Self {
end_entity,
intermediates,
}
}
pub fn into_owned(self) -> CertificateIdentity<'static> {
CertificateIdentity {
end_entity: self.end_entity.into_owned(),
intermediates: self
.intermediates
.into_iter()
.map(|cert| cert.into_owned())
.collect(),
}
}
}
pub trait SigningKey: Debug + Send + Sync {
fn choose_scheme(&self, offered: &[SignatureScheme]) -> Option<Box<dyn Signer>>;
fn public_key(&self) -> Option<SubjectPublicKeyInfoDer<'_>>;
}
pub trait Signer: Debug + Send + Sync {
fn sign(self: Box<Self>, message: &[u8]) -> Result<Vec<u8>, Error>;
fn scheme(&self) -> SignatureScheme;
}
pub fn public_key_to_spki(
alg_id: &AlgorithmIdentifier,
public_key: impl AsRef<[u8]>,
) -> SubjectPublicKeyInfoDer<'static> {
let mut spki_inner = x509::wrap_in_sequence(alg_id.as_ref());
spki_inner.extend(&x509::wrap_in_bit_string(public_key.as_ref()));
let spki = x509::wrap_in_sequence(&spki_inner);
SubjectPublicKeyInfoDer::from(spki)
}
#[non_exhaustive]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum InconsistentKeys {
KeyMismatch,
Unknown,
}