#[cfg(feature = "alloc")]
use crate::subject_name::GeneralDnsNameRef;
use crate::{
cert, signed_data, subject_name, verify_cert, CertRevocationList, Error, KeyUsage,
SignatureAlgorithm, SubjectNameRef, Time, TrustAnchor,
};
#[allow(deprecated)]
use crate::{TlsClientTrustAnchors, TlsServerTrustAnchors};
pub struct EndEntityCert<'a> {
inner: cert::Cert<'a>,
}
impl<'a> TryFrom<&'a [u8]> for EndEntityCert<'a> {
type Error = Error;
fn try_from(cert_der: &'a [u8]) -> Result<Self, Self::Error> {
Ok(Self {
inner: cert::Cert::from_der(
untrusted::Input::from(cert_der),
cert::EndEntityOrCa::EndEntity,
)?,
})
}
}
impl<'a> EndEntityCert<'a> {
pub(super) fn inner(&self) -> &cert::Cert {
&self.inner
}
fn verify_is_valid_cert(
&self,
supported_sig_algs: &[&SignatureAlgorithm],
trust_anchors: &[TrustAnchor],
intermediate_certs: &[&[u8]],
time: Time,
eku: KeyUsage,
crls: &[&dyn CertRevocationList],
) -> Result<(), Error> {
verify_cert::build_chain(
&verify_cert::ChainOptions {
eku,
supported_sig_algs,
trust_anchors,
intermediate_certs,
crls,
},
&self.inner,
time,
)
}
pub fn verify_for_usage(
&self,
supported_sig_algs: &[&SignatureAlgorithm],
trust_anchors: &[TrustAnchor],
intermediate_certs: &[&[u8]],
time: Time,
usage: KeyUsage,
crls: &[&dyn CertRevocationList],
) -> Result<(), Error> {
self.verify_is_valid_cert(
supported_sig_algs,
trust_anchors,
intermediate_certs,
time,
usage,
crls,
)
}
#[allow(deprecated)]
#[deprecated(
since = "0.101.2",
note = "The per-usage trust anchor representations and verification functions are deprecated in \
favor of the general-purpose `TrustAnchor` type and `EndEntity::verify_for_usage` function. \
The new `verify_for_usage` function expresses trust anchor and end entity purpose with the \
key usage argument."
)]
pub fn verify_is_valid_tls_server_cert(
&self,
supported_sig_algs: &[&SignatureAlgorithm],
&TlsServerTrustAnchors(trust_anchors): &TlsServerTrustAnchors,
intermediate_certs: &[&[u8]],
time: Time,
) -> Result<(), Error> {
self.verify_is_valid_cert(
supported_sig_algs,
trust_anchors,
intermediate_certs,
time,
KeyUsage::server_auth(),
&[],
)
}
#[allow(deprecated)]
#[deprecated(
since = "0.101.2",
note = "The per-usage trust anchor representations and verification functions are deprecated in \
favor of the general-purpose `TrustAnchor` type and `EndEntity::verify_for_usage` function. \
The new `verify_for_usage` function expresses trust anchor and end entity purpose with the \
key usage argument."
)]
pub fn verify_is_valid_tls_client_cert(
&self,
supported_sig_algs: &[&SignatureAlgorithm],
&TlsClientTrustAnchors(trust_anchors): &TlsClientTrustAnchors,
intermediate_certs: &[&[u8]],
time: Time,
crls: &[&dyn CertRevocationList],
) -> Result<(), Error> {
self.verify_is_valid_cert(
supported_sig_algs,
trust_anchors,
intermediate_certs,
time,
KeyUsage::client_auth(),
crls,
)
}
pub fn verify_is_valid_for_subject_name(
&self,
subject_name: SubjectNameRef,
) -> Result<(), Error> {
subject_name::verify_cert_subject_name(self, subject_name)
}
pub fn verify_signature(
&self,
signature_alg: &SignatureAlgorithm,
msg: &[u8],
signature: &[u8],
) -> Result<(), Error> {
signed_data::verify_signature(
signature_alg,
self.inner.spki.value(),
untrusted::Input::from(msg),
untrusted::Input::from(signature),
)
}
#[cfg(feature = "alloc")]
#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))]
pub fn dns_names(&'a self) -> Result<impl Iterator<Item = GeneralDnsNameRef<'a>>, Error> {
subject_name::list_cert_dns_names(self)
}
}
#[cfg(feature = "alloc")]
#[cfg(test)]
mod tests {
use super::*;
use crate::test_utils;
#[test]
fn printable_string_common_name() {
const DNS_NAME: &str = "test.example.com";
let issuer = test_utils::make_issuer("Test", None);
let ee_cert_der = {
let mut params = rcgen::CertificateParams::new(vec![DNS_NAME.to_string()]);
params.distinguished_name.push(
rcgen::DnType::CommonName,
rcgen::DnValue::PrintableString("example.com".to_string()),
);
params.is_ca = rcgen::IsCa::ExplicitNoCa;
params.alg = test_utils::RCGEN_SIGNATURE_ALG;
let cert = rcgen::Certificate::from_params(params)
.expect("failed to make ee cert (this is a test bug)");
cert.serialize_der_with_signer(&issuer)
.expect("failed to serialize signed ee cert (this is a test bug)")
};
expect_dns_name(&ee_cert_der, DNS_NAME);
}
#[test]
fn empty_sequence_common_name() {
let ee_cert_der = include_bytes!("../tests/misc/empty_sequence_common_name.der").as_slice();
expect_dns_name(ee_cert_der, "example.com");
}
fn expect_dns_name(der: &[u8], name: &str) {
let cert =
EndEntityCert::try_from(der).expect("should parse end entity certificate correctly");
let mut names = cert
.dns_names()
.expect("should get all DNS names correctly for end entity cert");
assert_eq!(names.next().map(<&str>::from), Some(name));
assert_eq!(names.next().map(<&str>::from), None);
}
}