stochastic-routing-extended 1.0.2

SRX (Stochastic Routing eXtended) — a next-generation VPN protocol with stochastic routing, DPI evasion, post-quantum cryptography, and multi-transport channel splitting
Documentation
//! Certificate pinning helpers for TLS-capable transports.

use rustls::pki_types::CertificateDer;
use sha2::{Digest, Sha256};

use crate::error::{SrxError, TransportError};

/// SHA-256 certificate pin.
pub type CertPin = [u8; 32];

/// Compute SHA-256 over certificate DER bytes.
#[must_use]
pub fn cert_sha256(cert_der: &CertificateDer<'_>) -> CertPin {
    let mut hasher = Sha256::new();
    hasher.update(cert_der.as_ref());
    hasher.finalize().into()
}

/// Validate that at least one certificate in the peer chain matches a pinned hash.
pub fn verify_peer_cert_pins(
    peer_certs: Option<&[CertificateDer<'_>]>,
    pins: &[CertPin],
) -> crate::error::Result<()> {
    if pins.is_empty() {
        return Ok(());
    }

    let certs = peer_certs.ok_or_else(|| {
        SrxError::Transport(TransportError::ConnectionFailed(
            "peer did not present certificates for pin verification".into(),
        ))
    })?;

    let matched = certs
        .iter()
        .map(cert_sha256)
        .any(|peer_pin| pins.contains(&peer_pin));

    if matched {
        return Ok(());
    }

    Err(SrxError::Transport(TransportError::ConnectionFailed(
        "certificate pin verification failed".into(),
    )))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn cert_sha256_is_deterministic() {
        let cert = CertificateDer::from(vec![1, 2, 3, 4, 5, 6]);
        assert_eq!(cert_sha256(&cert), cert_sha256(&cert));
    }

    #[test]
    fn verify_peer_cert_pins_rejects_empty_peer_chain_when_pins_required() {
        let pin = [0x11u8; 32];
        assert!(verify_peer_cert_pins(None, &[pin]).is_err());
    }
}