Skip to content

Instantly share code, notes, and snippets.

@wafflespeanut
Last active January 16, 2019 14:25
Show Gist options
  • Save wafflespeanut/ab91e404f0132cadf1945b54d829273b to your computer and use it in GitHub Desktop.
Save wafflespeanut/ab91e404f0132cadf1945b54d829273b to your computer and use it in GitHub Desktop.
TLS Certificate check
[package]
name = "cert-check"
version = "0.1.0"
authors = ["Ravi Shankar <[email protected]>"]
edition = "2018"
[dependencies]
futures = "0.1"
rustls = "0.14"
tokio-core = "0.1"
webpki = "0.18"
webpki-roots = "0.15"
x509-parser = "0.4"
use futures::{Async, Future, Poll};
use rustls::{Certificate, ClientConfig, ClientSession, Session};
use tokio_core::reactor::Core;
use webpki::DNSNameRef;
use webpki_roots::TLS_SERVER_ROOTS;
use std::net::{TcpStream, ToSocketAddrs};
use std::sync::Arc;
struct CertificateViewer {
eof: bool,
stream: TcpStream,
session: ClientSession,
}
impl CertificateViewer {
fn for_host(host: &str, port: u16) -> Self { // should be result after error check
let mut config = ClientConfig::new();
config.root_store.add_server_trust_anchors(&TLS_SERVER_ROOTS);
let config = Arc::new(config);
let name = DNSNameRef::try_from_ascii_str(host).unwrap(); // error check
let session = ClientSession::new(&config, name);
let mut addrs = (host, port).to_socket_addrs().unwrap(); // lookup error check
let addr = addrs.next().unwrap();
CertificateViewer {
eof: false,
stream: TcpStream::connect(&addr).unwrap(),
session,
}
}
}
impl Future for CertificateViewer {
type Item = Vec<Certificate>;
type Error = (); // wrong, handle error
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
let mut wlen = 0;
let mut rlen = 0;
while self.session.wants_write() {
wlen += self.session.write_tls(&mut self.stream).unwrap();
}
if !self.eof && self.session.wants_read() {
match self.session.read_tls(&mut self.stream).unwrap() {
0 => self.eof = true,
n => rlen += n,
}
}
if self.eof {
return Err(())
}
println!("Wrote {} bytes, Read {} bytes", wlen, rlen);
self.session.process_new_packets().unwrap();
// Certificates can be obtained only after handshake.
if let Some(certs) = self.session.get_peer_certificates() {
return Ok(Async::Ready(certs))
}
Ok(Async::NotReady)
}
}
impl Drop for CertificateViewer {
fn drop(&mut self) {
self.session.send_close_notify();
}
}
fn main() {
let viewer = CertificateViewer::for_host("naamio.cloud", 443);
let mut core = Core::new().unwrap();
let certs = core.run(viewer).unwrap();
for cert in certs {
let (_, cert) = x509_parser::parse_x509_der(&cert.0).unwrap();
let validity = &cert.tbs_certificate.validity;
let (not_before, not_after) = (validity.not_before.to_utc(), validity.not_after.to_utc());
println!("Subject {}: (Not before: {}, Not after: {})",
cert.tbs_certificate.subject, not_before.rfc822(), not_after.rfc822());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment