mirror of https://github.com/ctz/rustls
101 lines
2.8 KiB
Rust
101 lines
2.8 KiB
Rust
// A Rustls stub for TryTLS
|
|
//
|
|
// Author: Joachim Viide
|
|
// See: https://github.com/HowNetWorks/trytls-rustls-stub
|
|
//
|
|
|
|
|
|
use webpki;
|
|
use webpki_roots;
|
|
|
|
use std::io::{Read, Write, BufReader};
|
|
use std::net::TcpStream;
|
|
use std::sync::Arc;
|
|
use std::fs::File;
|
|
use std::error::Error;
|
|
use std::process;
|
|
use std::env;
|
|
use rustls::{ClientConfig, ClientSession, Session, TLSError};
|
|
|
|
enum Verdict {
|
|
Accept,
|
|
Reject(TLSError),
|
|
}
|
|
|
|
fn parse_args(args: &[String]) -> Result<(String, u16, ClientConfig), Box<dyn Error>> {
|
|
let mut config = ClientConfig::new();
|
|
match args.len() {
|
|
3 => {
|
|
config.root_store.add_server_trust_anchors(&webpki_roots::TLS_SERVER_ROOTS);
|
|
}
|
|
4 => {
|
|
let f = File::open(&args[3])?;
|
|
let mut f = BufReader::new(f);
|
|
if config.root_store.add_pem_file(&mut f).is_err() {
|
|
return Err(From::from("Could not load PEM data"));
|
|
}
|
|
}
|
|
_ => {
|
|
return Err(From::from("Incorrect number of arguments"));
|
|
}
|
|
};
|
|
let port = args[2].parse()?;
|
|
Ok((args[1].clone(), port, config))
|
|
}
|
|
|
|
fn communicate(host: String, port: u16, config: ClientConfig) -> Result<Verdict, Box<dyn Error>> {
|
|
let dns_name = webpki::DNSNameRef::try_from_ascii_str(&host).unwrap();
|
|
let rc_config = Arc::new(config);
|
|
let mut client = ClientSession::new(&rc_config, dns_name);
|
|
let mut stream = TcpStream::connect((&*host, port))?;
|
|
|
|
client.write_all(b"GET / HTTP/1.0\r\nConnection: close\r\nContent-Length: 0\r\n\r\n")?;
|
|
loop {
|
|
while client.wants_write() {
|
|
client.write_tls(&mut stream)?;
|
|
}
|
|
|
|
if client.wants_read() {
|
|
if client.read_tls(&mut stream)? == 0 {
|
|
return Err(From::from("Connection closed"));
|
|
}
|
|
|
|
if let Err(err) = client.process_new_packets() {
|
|
return match err {
|
|
TLSError::WebPKIError(_) |
|
|
TLSError::AlertReceived(_) => Ok(Verdict::Reject(err)),
|
|
_ => Err(From::from(format!("{:?}", err))),
|
|
};
|
|
}
|
|
|
|
if client.read(&mut [0])? > 0 {
|
|
return Ok(Verdict::Accept);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn main() {
|
|
let args: Vec<String> = env::args().collect();
|
|
let (host, port, config) = parse_args(&args).unwrap_or_else(|err| {
|
|
println!("Argument error: {}", err);
|
|
process::exit(2);
|
|
});
|
|
|
|
match communicate(host, port, config) {
|
|
Ok(Verdict::Accept) => {
|
|
println!("ACCEPT");
|
|
process::exit(0);
|
|
}
|
|
Ok(Verdict::Reject(reason)) => {
|
|
println!("{:?}", reason);
|
|
println!("REJECT");
|
|
process::exit(0);
|
|
}
|
|
Err(err) => {
|
|
println!("{}", err);
|
|
process::exit(1);
|
|
}
|
|
}
|
|
}
|