#[cfg(feature = "ws")]
use crate::ws::WsStream;
use rmqtt_codec::cert::CertInfo;
pub trait TlsCertExtractor {
fn extract_cert_info(&self) -> Option<CertInfo>;
}
#[cfg(feature = "tls")]
impl<S> TlsCertExtractor for tokio_rustls::server::TlsStream<S>
where
S: tokio::io::AsyncRead + tokio::io::AsyncWrite + Unpin,
{
fn extract_cert_info(&self) -> Option<CertInfo> {
use x509_parser::parse_x509_certificate;
let (_, session) = self.get_ref();
let certs = session.peer_certificates()?;
let cert = certs.first()?;
let (_, parsed) = parse_x509_certificate(cert.as_ref()).ok()?;
let common_name =
parsed.subject().iter_common_name().next().and_then(|cn| cn.as_str().ok()).map(|s| s.to_string());
let organization = parsed
.subject()
.iter_organization()
.next()
.and_then(|org| org.as_str().ok())
.map(|s| s.to_string());
let subject = parsed.subject().to_string();
let serial = parsed.serial.to_str_radix(16);
Some(CertInfo { common_name, subject, serial: Some(serial), organization })
}
}
impl TlsCertExtractor for tokio::net::TcpStream {
fn extract_cert_info(&self) -> Option<CertInfo> {
None
}
}
#[cfg(feature = "ws")]
impl TlsCertExtractor for WsStream<tokio::net::TcpStream> {
fn extract_cert_info(&self) -> Option<CertInfo> {
None
}
}
#[cfg(feature = "ws")]
#[cfg(feature = "tls")]
impl TlsCertExtractor for WsStream<tokio_rustls::server::TlsStream<tokio::net::TcpStream>> {
fn extract_cert_info(&self) -> Option<CertInfo> {
self.get_inner().get_ref().extract_cert_info()
}
}