summaryrefslogtreecommitdiff
path: root/packet-detector/src/tls_util.rs
blob: 456991ba3c8ac5ca81b88dfc881fdf3f88d0308e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
use rcgen::{DistinguishedName, DnType};
use rustls::client::danger::{HandshakeSignatureValid, ServerCertVerified, ServerCertVerifier};
use rustls::pki_types::{CertificateDer, ServerName, UnixTime};
use rustls::{DigitallySignedStruct, Error, SignatureScheme};
use sha2::{Digest, Sha256};
use x509_parser::prelude::*;

/// SHA256 fingerprint (truncated to 16 bytes by default)
pub fn fingerprint(cert: &CertificateDer<'_>, full: bool) -> String {
    let hash = Sha256::digest(cert.as_ref());
    if full { hex::encode(hash) } else { hex::encode(&hash[..16]) }
}

pub fn dn(cn: &str, org: &str) -> DistinguishedName {
    let mut d = DistinguishedName::new();
    d.push(DnType::CommonName, cn);
    d.push(DnType::OrganizationName, org);
    d.push(DnType::CountryName, "US");
    d
}

/// Parse certs from PEM
pub fn parse_pem(pem: &str) -> Result<Vec<CertificateDer<'static>>, std::io::Error> {
    rustls_pemfile::certs(&mut pem.as_bytes()).collect()
}

fn schemes() -> Vec<SignatureScheme> {
    rustls::crypto::ring::default_provider()
        .signature_verification_algorithms
        .supported_schemes()
}

/// Macro to implement the boilerplate verifier methods
macro_rules! impl_verifier_base {
    () => {
        fn verify_tls12_signature(&self, _: &[u8], _: &CertificateDer<'_>, _: &DigitallySignedStruct) -> Result<HandshakeSignatureValid, Error> {
            Ok(HandshakeSignatureValid::assertion())
        }
        fn verify_tls13_signature(&self, _: &[u8], _: &CertificateDer<'_>, _: &DigitallySignedStruct) -> Result<HandshakeSignatureValid, Error> {
            Ok(HandshakeSignatureValid::assertion())
        }
        fn supported_verify_schemes(&self) -> Vec<SignatureScheme> {
            schemes()
        }
    };
}

/// Accepts all certificates, logs info
#[derive(Debug)]
pub struct LoggingVerifier;

impl ServerCertVerifier for LoggingVerifier {
    fn verify_server_cert(&self, cert: &CertificateDer<'_>, intermediates: &[CertificateDer<'_>], _: &ServerName<'_>, _: &[u8], _: UnixTime) -> Result<ServerCertVerified, Error> {
        println!("\n=== Server Certificate ===");
        match X509Certificate::from_der(cert.as_ref()) {
            Ok((_, x)) => {
                println!("Subject: {}", x.subject());
                println!("Issuer:  {}", x.issuer());
                println!("SHA256:  {}", fingerprint(cert, true));
                if x.subject() == x.issuer() { println!("Type:    Self-Signed"); }
            }
            Err(e) => println!("Parse failed: {}", e),
        }
        for (i, c) in intermediates.iter().enumerate() {
            if let Ok((_, x)) = X509Certificate::from_der(c.as_ref()) {
                println!("Intermediate #{}: {}", i + 1, x.subject());
            }
        }
        println!("Chain length: {}\n", 1 + intermediates.len());
        Ok(ServerCertVerified::assertion())
    }
    impl_verifier_base!();
}