Last active
January 16, 2019 14:25
-
-
Save wafflespeanut/ab91e404f0132cadf1945b54d829273b to your computer and use it in GitHub Desktop.
TLS Certificate check
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[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" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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