Created
December 5, 2015 21:33
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
extern crate tls; | |
extern crate byteorder; | |
extern crate openssl; | |
extern crate crypto; | |
use std::fs::File; | |
use std::io::{Read,Write,Cursor}; | |
use std::net::TcpListener; | |
use tls::record::{TLSCiphertext,TLSPlaintext,ConnectionState}; | |
use tls::handshake; | |
use byteorder::{WriteBytesExt,BigEndian}; | |
use openssl::crypto::pkey::{PKey,EncryptionPadding}; | |
const TLS_RSA_WITH_AES_128_CBC_SHA: u16 = 0x002f; | |
#[derive(Debug)] | |
struct AlertType; | |
#[derive(Debug)] | |
enum Subprotocol { | |
Handshake(handshake::Message), | |
Alert(AlertType), | |
ChangeCipherSpec, | |
ApplicationData, | |
} | |
trait ProtocolChooser { | |
fn subprotocol(self: Self) -> Option<Subprotocol>; | |
} | |
impl ProtocolChooser for TLSPlaintext { | |
fn subprotocol(self: TLSPlaintext) -> Option<Subprotocol> { | |
match self.content_type { | |
22 => match handshake::Message::parse(self.body) { | |
Some(x) => Some(Subprotocol::Handshake(x)), | |
_ => None, | |
}, | |
_ => None, | |
} | |
} | |
} | |
use openssl::crypto::hash::Type; | |
//use openssl::crypto::hmac::hmac; | |
use crypto::hmac::Hmac; | |
use crypto::sha2::Sha256; | |
use crypto::mac::Mac; | |
fn prf(secret: &[u8], seed: &[u8], dest: &mut [u8]) { | |
let mut hmac = Hmac::new(Sha256::new(), secret); | |
let mut n: usize = 0; | |
let mut a = [0 as u8; 32]; | |
hmac.input(seed); | |
hmac.raw_result(&mut a); | |
hmac.reset(); | |
while n < dest.len() { | |
hmac.input(&a); | |
hmac.input(seed); | |
let mut buf = [0 as u8; 32]; | |
hmac.raw_result(&mut buf); | |
hmac.reset(); | |
let mut i=0; | |
while i < 32 && n+i < dest.len() { | |
dest[n+i] = buf[i]; | |
i+=1; | |
} | |
n+=32; | |
hmac.input(&a); | |
hmac.raw_result(&mut a); | |
hmac.reset(); | |
} | |
} | |
fn main() { | |
let listener = TcpListener::bind("0.0.0.0:9123").unwrap(); | |
println!("listening started, ready to accept"); | |
for stream in listener.incoming() { | |
let mut stream = stream.unwrap(); | |
let mut bytes = Vec::<u8>::with_capacity(1000); | |
unsafe { | |
bytes.set_len(1000); | |
} | |
let n = stream.read(&mut bytes[..]).unwrap(); | |
bytes.split_off(n); | |
println!("read {}: {:?}",n,bytes); | |
let ct = TLSCiphertext::from_wire_bytes(bytes); | |
let pt = ct.decipher(ConnectionState::initial()); | |
println!("plaintext packet: {:?}",pt); | |
let client_random; | |
match pt.subprotocol() { | |
Some(Subprotocol::Handshake(handshake::Message::TypeClientHello(helo))) => | |
{ | |
let mut found = false; | |
for suite in helo.offered_suites { | |
if suite == TLS_RSA_WITH_AES_128_CBC_SHA { | |
found = true; | |
break | |
} | |
} | |
if !found { | |
panic!("client didn't offer TLS_RSA_WITH_AES_128_CBC_SHA"); | |
} | |
client_random = helo.client_random; | |
}, | |
_ => | |
panic!("client didn't send a valid ClientHello"), | |
} | |
let mut repbuf = [0 as u8; 1000]; | |
let server_random = [1 as u8; 32]; | |
let n; | |
{ | |
let mut replyc = Cursor::new(&mut repbuf[..]); | |
replyc.write_u8(22).unwrap(); | |
replyc.write_u8(3).unwrap(); | |
replyc.write_u8(3).unwrap(); | |
replyc.write_u16::<BigEndian>(42).unwrap(); // len | |
//lenpos = replyc.position(); | |
replyc.write_u8(2).unwrap(); // serverhello | |
replyc.write_u8(0).unwrap(); // high length | |
replyc.write_u16::<BigEndian>(38).unwrap(); // inner length | |
println!("start of inner at {}", replyc.position()); | |
replyc.write_u8(3).unwrap(); // ver | |
replyc.write_u8(3).unwrap(); // ver | |
for i in 0..32 { | |
replyc.write_u8(1).unwrap(); // our rand | |
} | |
replyc.write_u8(0).unwrap(); // sessid length | |
//replyc.write_u8(32).unwrap(); // sessid | |
replyc.write_u16::<BigEndian>(TLS_RSA_WITH_AES_128_CBC_SHA).unwrap(); | |
replyc.write_u8(0).unwrap(); // chosen compression | |
//replyc.write_u16::<BigEndian>(0).unwrap(); // extension length | |
// for i in 0..15 { | |
// replyc.write_u8(0).unwrap(); // dummy ext | |
// } | |
n = replyc.position(); | |
} | |
println!("constructed {} bytes",n); | |
{ | |
let to_send = &repbuf[0..(n as usize)]; | |
println!("sending: {}, {:?}",to_send.len(),to_send); | |
let sent = stream.write(to_send).unwrap(); | |
println!("sent {}",sent); | |
} | |
let mut certbuf = [0 as u8; 4096]; | |
let mut f = File::open("keys/server.crt.der").unwrap(); | |
let certlen = f.read(&mut certbuf).unwrap(); | |
let cert: &[u8] = &certbuf[0..certlen]; | |
let certlen_u16 = certlen as u16; | |
println!("cert is {} bytes long", certlen); | |
let n2; | |
{ | |
let mut replyc = Cursor::new(&mut repbuf[..]); | |
replyc.write_u8(22).unwrap(); | |
replyc.write_u8(3).unwrap(); | |
replyc.write_u8(3).unwrap(); | |
replyc.write_u16::<BigEndian>(certlen_u16+3+3+4).unwrap(); // outer len | |
// certificate message | |
replyc.write_u8(11).unwrap(); // certificate | |
replyc.write_u8(0).unwrap(); // high length | |
replyc.write_u16::<BigEndian>(certlen_u16+3+3).unwrap(); // inner length | |
// certificate_list | |
replyc.write_u8(0).unwrap(); | |
replyc.write_u16::<BigEndian>(certlen_u16+3).unwrap(); | |
replyc.write_u8(0).unwrap(); | |
replyc.write_u16::<BigEndian>(certlen_u16).unwrap(); | |
replyc.write(cert); | |
n2 = replyc.position(); | |
} | |
{ | |
let to_send = &repbuf[0..(n2 as usize)]; | |
println!("sending: {}, {:?}",to_send.len(),to_send); | |
let sent = stream.write(to_send).unwrap(); | |
println!("sent {}",sent); | |
} | |
let n3; | |
{ | |
let mut replyc = Cursor::new(&mut repbuf[..]); | |
replyc.write_u8(22).unwrap(); | |
replyc.write_u8(3).unwrap(); | |
replyc.write_u8(3).unwrap(); | |
replyc.write_u16::<BigEndian>(4).unwrap(); // outer len | |
replyc.write_u8(14).unwrap(); // server_hello_done | |
replyc.write_u8(0).unwrap(); // high length | |
replyc.write_u16::<BigEndian>(0).unwrap(); // inner length | |
n3 = replyc.position(); | |
} | |
{ | |
let to_send = &repbuf[0..(n3 as usize)]; | |
println!("sending: {}, {:?}",to_send.len(),to_send); | |
let sent = stream.write(to_send).unwrap(); | |
println!("sent {}",sent); | |
} | |
stream.write(b"Hello World\r\n").unwrap(); | |
let mut f = File::open("keys/server.key").unwrap(); | |
let pk = openssl::crypto::pkey::PKey::private_key_from_pem(&mut f).unwrap(); | |
println!("pk: {}, {:?}", pk.size(), pk.max_data()); | |
let mut pmsbuf = [0 as u8; 4096]; | |
let clientkexlen = stream.read(&mut pmsbuf[..]).unwrap(); | |
println!("kexlen: {}, {:?}", clientkexlen, &pmsbuf[0..clientkexlen]); | |
let premastersecret = pk.private_decrypt_with_padding(&pmsbuf[11..(11+128)], EncryptionPadding::PKCS1v15); | |
assert!(48 == premastersecret.len()); | |
println!("client random: {:?}", client_random); | |
println!("server random: {:?}", server_random); | |
let mut master_secret: [u8; 48] = [0 as u8; 48]; | |
let mut seed = Vec::new(); | |
seed.extend(b"master secret"); | |
seed.extend(&client_random); | |
seed.extend(&server_random); | |
//assert!(64 == seed.len()); | |
println!("{:?}", seed); | |
prf(&premastersecret[..], &seed[..], &mut master_secret); | |
for b in master_secret.into_iter() { | |
print!("{:02X}", b); | |
} | |
println!(""); | |
// let strs: String = master_secret.into_iter() | |
// .map(|b| format!("{:02X}", b)) | |
// .collect().connect(""); | |
// println!("master key: {}", strs); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment