1#[cfg(feature = "ws")]
2use crate::ws::WsStream;
3use std::fmt;
4
5#[derive(Debug, Clone, Default)]
7pub struct CertInfo {
8 pub common_name: Option<String>,
10 pub subject: String,
12 pub serial: Option<String>,
14 pub organization: Option<String>,
16}
17
18impl CertInfo {
19 pub fn new() -> Self {
20 Self::default()
21 }
22}
23
24impl fmt::Display for CertInfo {
25 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
26 write!(f, "CN: {:?}, Subject: {}, Org: {:?}", self.common_name, self.subject, self.organization)
27 }
28}
29
30pub trait TlsCertExtractor {
32 fn extract_cert_info(&self) -> Option<CertInfo>;
33}
34
35#[cfg(feature = "tls")]
37impl<S> TlsCertExtractor for tokio_rustls::server::TlsStream<S>
38where
39 S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin,
40{
41 fn extract_cert_info(&self) -> Option<CertInfo> {
42 use x509_parser::parse_x509_certificate;
43
44 let (_, session) = self.get_ref();
45 let certs = session.peer_certificates()?;
46 let cert = certs.first()?;
47
48 let (_, parsed) = parse_x509_certificate(cert.as_ref()).ok()?;
49
50 let common_name =
51 parsed.subject().iter_common_name().next().and_then(|cn| cn.as_str().ok()).map(|s| s.to_string());
52
53 let organization = parsed
54 .subject()
55 .iter_organization()
56 .next()
57 .and_then(|org| org.as_str().ok())
58 .map(|s| s.to_string());
59
60 let subject = parsed.subject().to_string();
61
62 let serial = parsed.serial.to_str_radix(16);
63
64 Some(CertInfo { common_name, subject, serial: Some(serial), organization })
65 }
66}
67
68impl TlsCertExtractor for tokio::net::TcpStream {
70 fn extract_cert_info(&self) -> Option<CertInfo> {
71 None
72 }
73}
74
75#[cfg(feature = "ws")]
76impl TlsCertExtractor for WsStream<tokio::net::TcpStream> {
77 fn extract_cert_info(&self) -> Option<CertInfo> {
78 None
79 }
80}
81
82#[cfg(feature = "ws")]
83#[cfg(feature = "tls")]
84impl TlsCertExtractor for WsStream<tokio_rustls::server::TlsStream<tokio::net::TcpStream>> {
85 fn extract_cert_info(&self) -> Option<CertInfo> {
86 self.get_inner().get_ref().extract_cert_info()
87 }
88}