use pki_types::{
CertificateDer, ServerName, SignatureVerificationAlgorithm, SubjectPublicKeyInfoDer, UnixTime,
};
use webpki::ExtendedKeyUsage;
use super::anchors::RootCertStore;
use super::pki_error;
use crate::crypto::WebPkiSupportedAlgorithms;
use crate::error::{ApiMisuse, Error, PeerMisbehaved};
use crate::verify::{HandshakeSignatureValid, SignatureVerificationInput, SignerPublicKey};
pub fn verify_identity_signed_by_trust_anchor(
cert: &ParsedCertificate<'_>,
roots: &RootCertStore,
intermediates: &[CertificateDer<'_>],
now: UnixTime,
supported_algs: &[&dyn SignatureVerificationAlgorithm],
) -> Result<(), Error> {
verify_identity_signed_by_trust_anchor_impl(
cert,
roots,
intermediates,
None, now,
supported_algs,
)
}
pub fn verify_server_name(
cert: &ParsedCertificate<'_>,
server_name: &ServerName<'_>,
) -> Result<(), Error> {
cert.0
.verify_is_valid_for_subject_name(server_name)
.map_err(pki_error)
}
pub struct ParsedCertificate<'a>(pub(crate) webpki::EndEntityCert<'a>);
impl ParsedCertificate<'_> {
pub fn subject_public_key_info(&self) -> SubjectPublicKeyInfoDer<'static> {
self.0.subject_public_key_info()
}
}
impl<'a> TryFrom<&'a CertificateDer<'a>> for ParsedCertificate<'a> {
type Error = Error;
fn try_from(value: &'a CertificateDer<'a>) -> Result<Self, Self::Error> {
webpki::EndEntityCert::try_from(value)
.map_err(pki_error)
.map(ParsedCertificate)
}
}
pub fn verify_tls12_signature(
input: &SignatureVerificationInput<'_>,
supported_schemes: &WebPkiSupportedAlgorithms,
) -> Result<HandshakeSignatureValid, Error> {
let possible_algs = supported_schemes.convert_scheme(input.signature.scheme)?;
let cert = match input.signer {
SignerPublicKey::X509(cert_der) => {
webpki::EndEntityCert::try_from(*cert_der).map_err(pki_error)?
}
SignerPublicKey::RawPublicKey(_) => {
return Err(ApiMisuse::InvalidSignerForProtocolVersion.into());
}
};
let mut error = None;
for alg in possible_algs {
match cert.verify_signature(*alg, input.message, input.signature.signature()) {
Err(err @ webpki::Error::UnsupportedSignatureAlgorithmForPublicKey(_)) => {
error = Some(err);
continue;
}
Err(e) => return Err(pki_error(e)),
Ok(()) => return Ok(HandshakeSignatureValid::assertion()),
}
}
Err(match error {
Some(e) => pki_error(e),
None => Error::ApiMisuse(ApiMisuse::NoSignatureVerificationAlgorithms),
})
}
pub fn verify_tls13_signature(
input: &SignatureVerificationInput<'_>,
supported_schemes: &WebPkiSupportedAlgorithms,
) -> Result<HandshakeSignatureValid, Error> {
if !input
.signature
.scheme
.supported_in_tls13()
{
return Err(PeerMisbehaved::SignedHandshakeWithUnadvertisedSigScheme.into());
}
let &alg = supported_schemes
.convert_scheme(input.signature.scheme)?
.first()
.ok_or(Error::ApiMisuse(
ApiMisuse::NoSignatureVerificationAlgorithms,
))?;
match input.signer {
SignerPublicKey::X509(cert_der) => {
webpki::EndEntityCert::try_from(*cert_der).and_then(|cert| {
cert.verify_signature(alg, input.message, input.signature.signature())
})
}
SignerPublicKey::RawPublicKey(spki) => webpki::RawPublicKeyEntity::try_from(*spki)
.and_then(|rpk| rpk.verify_signature(alg, input.message, input.signature.signature())),
}
.map_err(pki_error)
.map(|_| HandshakeSignatureValid::assertion())
}
pub(crate) fn verify_identity_signed_by_trust_anchor_impl(
cert: &ParsedCertificate<'_>,
roots: &RootCertStore,
intermediates: &[CertificateDer<'_>],
revocation: Option<webpki::RevocationOptions<'_>>,
now: UnixTime,
supported_algs: &[&dyn SignatureVerificationAlgorithm],
) -> Result<(), Error> {
let result = cert.0.verify_for_usage(
supported_algs,
&roots.roots,
intermediates,
now,
&ExtendedKeyUsage::server_auth(),
revocation,
None,
);
match result {
Ok(_) => Ok(()),
Err(e) => Err(pki_error(e)),
}
}
#[cfg(test)]
mod tests {
use alloc::vec;
use std::format;
use super::*;
use crate::crypto::{SignatureScheme, TEST_PROVIDER};
use crate::verify::DigitallySignedStruct;
#[test]
fn tls13_empty_signature_mapping_panics() {
let supported = WebPkiSupportedAlgorithms {
all: TEST_PROVIDER
.signature_verification_algorithms
.all,
mapping: &[(SignatureScheme::ED25519, &[])],
};
let cert = CertificateDer::from(vec![0u8]); let dss = DigitallySignedStruct::new(SignatureScheme::ED25519, vec![]);
let signer = SignerPublicKey::X509(&cert);
let input = SignatureVerificationInput {
message: b"hello",
signer: &signer,
signature: &dss,
};
assert_eq!(
verify_tls13_signature(&input, &supported).unwrap_err(),
Error::ApiMisuse(ApiMisuse::NoSignatureVerificationAlgorithms)
);
}
#[test]
fn certificate_debug() {
assert_eq!(
"CertificateDer(0x6162)",
format!("{:?}", CertificateDer::from(b"ab".to_vec()))
);
}
#[test]
fn webpki_supported_algorithms_is_debug() {
assert_eq!(
"WebPkiSupportedAlgorithms { all: [ .. ], mapping: [] }",
format!(
"{:?}",
WebPkiSupportedAlgorithms {
all: &[],
mapping: &[]
}
)
);
}
}