# webpki.rs - source
Source of the Rust file `crates/core/src/webpki.rs`.

Skip to main content

#
tlsn_core/
webpki.rs

    1//! Web PKI types.
    2
    3use std::time::Duration;
    4
    5use rustls_pki_types::{self as webpki_types, pem::PemObject};
    6use serde::{Deserialize, Serialize};
    7
    8use crate::connection::ServerName;
    9
    10/// X.509 certificate, DER encoded.
    11#[derive(Debug, Clone, Serialize, Deserialize)]
    12pub struct CertificateDer(pub Vec<u8>);
    13
    14impl CertificateDer {
    15    /// Creates a DER-encoded certificate from a PEM-encoded certificate.
    16    pub fn from_pem_slice(pem: &[u8]) -> Result<Self, PemError> {
    17        let der = webpki_types::CertificateDer::from_pem_slice(pem).map_err(|_| PemError {})?;
    18
    19        Ok(Self(der.to_vec()))
    20    }
    21}
    22
    23/// Private key, DER encoded.
    24#[derive(Debug, Clone, zeroize::ZeroizeOnDrop, Serialize, Deserialize)]
    25pub struct PrivateKeyDer(pub Vec<u8>);
    26
    27impl PrivateKeyDer {
    28    /// Creates a DER-encoded private key from a PEM-encoded private key.
    29    pub fn from_pem_slice(pem: &[u8]) -> Result<Self, PemError> {
    30        let der = webpki_types::PrivateKeyDer::from_pem_slice(pem).map_err(|_| PemError {})?;
    31
    32        Ok(Self(der.secret_der().to_vec()))
    33    }
    34}
    35
    36/// PEM parsing error.
    37#[derive(Debug, thiserror::Error)]
    38#[error("failed to parse PEM object")]
    39pub struct PemError {}
    40
    41/// Root certificate store.
    42///
    43/// This stores root certificates which are used to verify end-entity
    44/// certificates presented by a TLS server.
    45#[derive(Debug, Clone, Serialize, Deserialize)]
    46pub struct RootCertStore {
    47    /// Unvalidated DER-encoded X.509 root certificates.
    48    pub roots: Vec<CertificateDer>,
    49}
    50
    51impl RootCertStore {
    52    /// Creates an empty root certificate store.
    53    pub fn empty() -> Self {
    54        Self { roots: Vec::new() }
    55    }
    56
    57    /// Creates a root certificate store with Mozilla root certificates.
    58    ///
    59    /// These certificates are sourced from [`webpki-root-certs`](https://docs.rs/webpki-root-certs/latest/webpki_root_certs/). It is not recommended to use these unless the
    60    /// application binary can be recompiled and deployed on-demand in the case
    61    /// that the root certificates need to be updated.
    62    #[cfg(feature = "mozilla-certs")]
    63    pub fn mozilla() -> Self {
    64        Self {
    65            roots: webpki_root_certs::TLS_SERVER_ROOT_CERTS
    66                .iter()
    67                .map(|cert| CertificateDer(cert.to_vec()))
    68                .collect(),
    69        }
    70    }
    71}
    72
    73/// Server certificate verifier.
    74#[derive(Debug)]
    75pub struct ServerCertVerifier {
    76    roots: Vec<webpki_types::TrustAnchor<'static>>,
    77}
    78
    79impl ServerCertVerifier {
    80    /// Creates a new server certificate verifier.
    81    pub fn new(roots: &RootCertStore) -> Result<Self, ServerCertVerifierError> {
    82        let roots = roots
    83            .roots
    84            .iter()
    85            .map(|cert| {
    86                webpki::anchor_from_trusted_cert(&webpki_types::CertificateDer::from(
    87                    cert.0.as_slice(),
    88                ))
    89                .map(|anchor| anchor.to_owned())
    90                .map_err(|err| ServerCertVerifierError::InvalidRootCertificate {
    91                    cert: cert.clone(),
    92                    reason: err.to_string(),
    93                })
    94            })
    95            .collect::<Result<Vec<_>, _>>()?;
    96
    97        Ok(Self { roots })
    98    }
    99
    100    /// Creates a server certificate verifier with Mozilla root certificates.
    101    ///
    102    /// These certificates are sourced from [`webpki-root-certs`](https://docs.rs/webpki-root-certs/latest/webpki_root_certs/). It is not recommended to use these unless the
    103    /// application binary can be recompiled and deployed on-demand in the case
    104    /// that the root certificates need to be updated.
    105    #[cfg(feature = "mozilla-certs")]
    106    pub fn mozilla() -> Self {
    107        Self {
    108            roots: webpki_roots::TLS_SERVER_ROOTS.to_vec(),
    109        }
    110    }
    111
    112    /// Verifies the server certificate was valid at the given time of
    113    /// presentation.
    114    ///
    115    /// # Arguments
    116    ///
    117    /// * `end_entity` - End-entity certificate to verify.
    118    /// * `intermediates` - Intermediate certificates to a trust anchor.
    119    /// * `server_name` - Server DNS name.
    120    /// * `time` - Unix time the certificate was presented.
    121    pub fn verify_server_cert(
    122        &self,
    123        end_entity: &CertificateDer,
    124        intermediates: &[CertificateDer],
    125        server_name: &ServerName,
    126        time: u64,
    127    ) -> Result<(), ServerCertVerifierError> {
    128        let cert = webpki_types::CertificateDer::from(end_entity.0.as_slice());
    129        let cert = webpki::EndEntityCert::try_from(&cert).map_err(|e| {
    130            ServerCertVerifierError::InvalidEndEntityCertificate {
    131                cert: end_entity.clone(),
    132                reason: e.to_string(),
    133            }
    134        })?;
    135        let intermediates = intermediates
    136            .iter()
    137            .map(|c| webpki_types::CertificateDer::from(c.0.as_slice()))
    138            .collect::<Vec<_>>();
    139        let server_name = server_name.to_webpki();
    140        let time = webpki_types::UnixTime::since_unix_epoch(Duration::from_secs(time));
    141
    142        cert.verify_for_usage(
    143            webpki::ALL_VERIFICATION_ALGS,
    144            &self.roots,
    145            &intermediates,
    146            time,
    147            webpki::KeyUsage::server_auth(),
    148            None,
    149            None,
    150        )
    151        .map(|_| ())
    152        .map_err(|_| ServerCertVerifierError::InvalidPath)?;
    153
    154        cert.verify_is_valid_for_subject_name(&server_name)
    155            .map_err(|_| ServerCertVerifierError::InvalidServerName)?;
    156
    157        Ok(())
    158    }
    159}
    160
    161/// Error for [`ServerCertVerifier`].
    162#[derive(Debug, thiserror::Error)]
    163#[error("server certificate verification failed: {0}")]
    164pub enum ServerCertVerifierError {
    165    /// Root certificate store contains invalid certificate.
    166    #[error("root certificate store contains invalid certificate: {reason}")]
    167    InvalidRootCertificate {
    168        /// Invalid certificate.
    169        cert: CertificateDer,
    170        /// Reason for invalidity.
    171        reason: String,
    172    },
    173    /// End-entity certificate is invalid.
    174    #[error("end-entity certificate is invalid: {reason}")]
    175    InvalidEndEntityCertificate {
    176        /// Invalid certificate.
    177        cert: CertificateDer,
    178        /// Reason for invalidity.
    179        reason: String,
    180    },
    181    /// Failed to verify certificate path to provided trust anchors.
    182    #[error("failed to verify certificate path to provided trust anchors")]
    183    InvalidPath,
    184    /// Failed to verify certificate is valid for provided server name.
    185    #[error("failed to verify certificate is valid for provided server name")]
    186    InvalidServerName,
    187}