work towards decoding serverkx

replace rand crate with existing ring code
This commit is contained in:
Joseph Birr-Pixton 2016-05-19 23:03:04 +01:00
parent b802430174
commit e72f28a584
10 changed files with 263 additions and 35 deletions

46
Cargo.lock generated
View File

@ -3,7 +3,6 @@ name = "rustls"
version = "0.1.0"
dependencies = [
"mio 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"ring 0.1.0 (git+https://github.com/briansmith/ring)",
]
@ -91,7 +90,46 @@ dependencies = [
[[package]]
name = "num"
version = "0.1.31"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-bigint 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-iter 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-bigint"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"rand 0.3.14 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-integer"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-iter"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"num-integer 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"num-traits 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "num-traits"
version = "0.1.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -105,9 +143,9 @@ dependencies = [
[[package]]
name = "ring"
version = "0.1.0"
source = "git+https://github.com/briansmith/ring#b78a8d06d29a3a724b0f2cf857d35acb8d376bd2"
source = "git+https://github.com/briansmith/ring#a3d5424a78b200a92a5fcc06f57c72e03dee90ad"
dependencies = [
"num 0.1.31 (registry+https://github.com/rust-lang/crates.io-index)",
"num 0.1.32 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc-serialize 0.3.19 (registry+https://github.com/rust-lang/crates.io-index)",
]

View File

@ -6,4 +6,3 @@ authors = ["Joseph Birr-Pixton <jpixton@gmail.com>"]
[dependencies]
ring = { version = "0.1.0", git = "https://github.com/briansmith/ring" }
mio = "0.5.1"
rand = "0.3"

View File

@ -1,6 +1,6 @@
use msgs::enums::CipherSuite;
use session::SessionSecrets;
use suites::{SupportedCipherSuite, DEFAULT_CIPHERSUITES};
use suites::{SupportedCipherSuite, DEFAULT_CIPHERSUITES, KeyExchangeData};
use msgs::handshake::{SessionID, CertificatePayload};
use msgs::handshake::{ServerNameRequest, SupportedSignatureAlgorithms};
use msgs::handshake::{ClientExtension};
@ -8,15 +8,13 @@ use msgs::deframer::MessageDeframer;
use msgs::message::Message;
use client_hs;
use handshake::HandshakeError;
use rand;
use std::sync::Arc;
use std::fmt::Debug;
use std::io;
use std::collections::VecDeque;
extern crate rand;
use self::rand::Rng;
pub struct ClientConfig {
/* List of ciphersuites, in preference order. */
pub ciphersuites: Vec<&'static SupportedCipherSuite>
@ -35,6 +33,7 @@ pub struct ClientHandshakeData {
pub ciphersuite: Option<&'static SupportedCipherSuite>,
pub client_random: Vec<u8>,
pub server_random: Vec<u8>,
pub kx_data: KeyExchangeData,
pub secrets: SessionSecrets
}
@ -45,18 +44,13 @@ impl ClientHandshakeData {
ciphersuite: None,
client_random: Vec::new(),
server_random: Vec::new(),
kx_data: KeyExchangeData::Invalid,
secrets: SessionSecrets::for_client()
}
}
pub fn generate_client_random(&mut self) {
let mut rng = rand::thread_rng();
self.client_random.resize(32, 0);
rng.fill_bytes(&mut self.client_random);
}
pub fn init_with_cs(&mut self, cs: &'static SupportedCipherSuite) -> bool {
rand::fill_random_vec(&mut self.client_random, 32);
}
}
@ -108,10 +102,15 @@ impl ClientSession {
ret
}
pub fn find_cipher_suite(&self, suite: &CipherSuite) -> Option<SupportedCipherSuite> {
pub fn find_cipher_suite(&self, suite: &CipherSuite) -> Option<&'static SupportedCipherSuite> {
let got = suite.clone();
self.config.ciphersuites.iter()
.find(|ics| ics.suite == got)
for ref scs in &self.config.ciphersuites {
if scs.suite == got {
return Some(scs);
}
}
None
}
pub fn add_extensions(&self, exts: &mut Vec<ClientExtension>) {

View File

@ -92,11 +92,7 @@ fn ExpectServerHello_handle(sess: &mut ClientSession, m: &Message) -> Result<Con
return Err(HandshakeError::General("server chose non-offered ciphersuite".to_string()));
}
if !sess.handshake_data.init_with_cs(scs.unwrap()) {
return Err(HandshakeError::General("failed to init our ciphersuite data".to_string()));
}
/* TODO: we can send a ClientKeyExchange now */
sess.handshake_data.ciphersuite = scs;
Ok(ConnState::ExpectCertificate)
}
@ -134,9 +130,14 @@ fn ExpectServerKX_expect() -> Expectation {
}
fn ExpectServerKX_handle(sess: &mut ClientSession, m: &Message) -> Result<ConnState, HandshakeError> {
let kx = extract_handshake!(m, HandshakePayload::ServerKeyExchange).unwrap();
let opaque_kx = extract_handshake!(m, HandshakePayload::ServerKeyExchange).unwrap();
let maybe_decoded_kx = opaque_kx.unwrap_given_kxa(&sess.handshake_data.ciphersuite.unwrap().kx);
println!("we have serverkx {:?}", kx);
if maybe_decoded_kx.is_none() {
return Err(HandshakeError::General("cannot decode server's kx".to_string()));
}
println!("we have serverkx {:?}", maybe_decoded_kx);
/* TODO: check signature by subject pubkey on this struct */
Ok(ConnState::ExpectServerHelloDone)
}

View File

@ -2,6 +2,7 @@ pub mod msgs;
use msgs::codec::Reader;
use msgs::message::Message;
mod rand;
mod session;
pub mod server;
pub mod client;

View File

@ -1966,3 +1966,43 @@ impl HeartbeatMode {
}
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
pub enum ECCurveType {
ExplicitPrime,
ExplicitChar2,
NamedCurve,
Unknown(u8)
}
impl Codec for ECCurveType {
fn encode(&self, bytes: &mut Vec<u8>) {
encode_u8(self.get_u8(), bytes);
}
fn read(r: &mut Reader) -> Option<ECCurveType> {
let u = read_u8(r);
if u.is_none() {
return None
}
Some(match u.unwrap() {
0x01 => ECCurveType::ExplicitPrime,
0x02 => ECCurveType::ExplicitChar2,
0x03 => ECCurveType::NamedCurve,
x => ECCurveType::Unknown(x)
})
}
}
impl ECCurveType {
pub fn get_u8(&self) -> u8 {
match *self {
ECCurveType::ExplicitPrime => 0x01,
ECCurveType::ExplicitChar2 => 0x02,
ECCurveType::NamedCurve => 0x03,
ECCurveType::Unknown(v) => v
}
}
}

View File

@ -1,6 +1,7 @@
use msgs::enums::{ProtocolVersion, HandshakeType};
use msgs::enums::{CipherSuite, Compression, ExtensionType, ECPointFormat, NamedCurve};
use msgs::enums::{HashAlgorithm, SignatureAlgorithm, HeartbeatMode, ServerNameType};
use msgs::enums::{ECCurveType};
use msgs::base::{Payload, PayloadU8, PayloadU24};
use msgs::codec;
use msgs::codec::{Codec, Reader};
@ -526,14 +527,100 @@ impl Codec for CertificatePayload {
}
}
#[derive(Debug)]
pub enum KeyExchangeAlgorithm {
DHE_DSS,
DHE_RSA,
DH_ANON,
RSA,
DH_DSS,
DH_RSA,
ECDH_ECDSA,
ECDHE_ECDSA,
ECDH_RSA,
ECDHE_RSA,
ECDH_anon
}
/* We don't support arbitrary curves. It's a terrible
* idea and unnecessary attack surface. Please,
* get a grip. */
#[derive(Debug)]
pub struct ECParameters {
curve_type: ECCurveType,
named_curve: NamedCurve
}
impl Codec for ECParameters {
fn encode(&self, bytes: &mut Vec<u8>) {
self.curve_type.encode(bytes);
self.named_curve.encode(bytes);
}
fn read(r: &mut Reader) -> Option<ECParameters> {
let ct = try_ret!(ECCurveType::read(r));
if ct != ECCurveType::NamedCurve {
return None;
}
let nc = try_ret!(NamedCurve::read(r));
Some(ECParameters { curve_type: ct, named_curve: nc })
}
}
#[derive(Debug)]
pub struct ServerECDHParams {
pub curve_params: ECParameters,
pub public: PayloadU8
}
impl Codec for ServerECDHParams {
fn encode(&self, bytes: &mut Vec<u8>) {
self.curve_params.encode(bytes);
self.public.encode(bytes);
}
fn read(r: &mut Reader) -> Option<ServerECDHParams> {
let cp = try_ret!(ECParameters::read(r));
let pb = try_ret!(PayloadU8::read(r));
Some(ServerECDHParams { curve_params: cp, public: pb })
}
}
#[derive(Debug)]
pub struct ECDHEServerKeyExchange {
pub params: ServerECDHParams,
pub sig: Vec<u8>
}
impl Codec for ECDHEServerKeyExchange {
fn encode(&self, bytes: &mut Vec<u8>) {
self.params.encode(bytes);
bytes.extend(self.sig.iter());
}
fn read(r: &mut Reader) -> Option<ECDHEServerKeyExchange> {
let params = try_ret!(ServerECDHParams::read(r));
let mut sig = Vec::new();
sig.extend_from_slice(r.rest());
Some(ECDHEServerKeyExchange { params: params, sig: sig })
}
}
#[derive(Debug)]
pub enum ServerKeyExchangePayload {
ECDHE(ECDHEServerKeyExchange),
Unknown(Payload)
}
impl Codec for ServerKeyExchangePayload {
fn encode(&self, bytes: &mut Vec<u8>) {
match *self {
ServerKeyExchangePayload::ECDHE(ref x) => x.encode(bytes),
ServerKeyExchangePayload::Unknown(ref x) => x.encode(bytes)
}
}
@ -545,6 +632,22 @@ impl Codec for ServerKeyExchangePayload {
}
}
impl ServerKeyExchangePayload {
pub fn unwrap_given_kxa(&self, kxa: &KeyExchangeAlgorithm) -> Option<ServerKeyExchangePayload> {
if let ServerKeyExchangePayload::Unknown(ref unk) = *self {
let mut rd = Reader::init(&unk.body);
return match *kxa {
KeyExchangeAlgorithm::ECDHE_ECDSA | KeyExchangeAlgorithm::ECDHE_RSA =>
ECDHEServerKeyExchange::read(&mut rd).and_then(|x| Some(ServerKeyExchangePayload::ECDHE(x))),
_ => None
};
}
None
}
}
#[derive(Debug)]
pub enum HandshakePayload {
HelloRequest,

20
src/rand.rs Normal file
View File

@ -0,0 +1,20 @@
/* The single place where we generate random material
* for our own use. These functions never fail,
* they panic on error. */
extern crate ring;
use self::ring::rand::SecureRandom;
/* Fill the whole slice with random material. */
pub fn fill_random(bytes: &mut [u8]) {
ring::rand::SystemRandom::new()
.fill(bytes)
.unwrap();
}
/* Make the vec v contain sz random bytes. */
pub fn fill_random_vec(v: &mut Vec<u8>, sz: usize) {
v.resize(sz, 0u8);
fill_random(v);
}

View File

@ -8,15 +8,13 @@ use msgs::deframer::MessageDeframer;
use msgs::message::Message;
use server_hs;
use handshake::HandshakeError;
use rand;
use std::sync::Arc;
use std::fmt::Debug;
use std::io;
use std::collections::VecDeque;
extern crate rand;
use self::rand::Rng;
pub trait StoresSessions {
/* Generate a session ID. */
fn generate(&self) -> SessionID;
@ -136,9 +134,7 @@ impl ServerHandshakeData {
}
pub fn generate_server_random(&mut self) {
let mut rng = rand::thread_rng();
self.server_random.resize(32, 0);
rng.fill_bytes(&mut self.server_random);
rand::fill_random_vec(&mut self.server_random, 32);
}
}

View File

@ -1,9 +1,28 @@
use msgs::enums::{CipherSuite};
use msgs::enums::{CipherSuite, HashAlgorithm};
use msgs::handshake::KeyExchangeAlgorithm;
use msgs::handshake::CertificatePayload;
extern crate ring;
#[derive(Debug)]
pub enum BulkAlgorithm {
AES_128_GCM,
AES_256_GCM
}
/* This contains the data we need to keep for a connection
* for a particular kind of KX. */
pub enum KeyExchangeData {
ECDHE(ring::agreement::EphemeralKeyPair),
Invalid
}
#[derive(Debug)]
pub struct SupportedCipherSuite {
pub suite: CipherSuite,
pub kx: KeyExchangeAlgorithm,
pub bulk: BulkAlgorithm,
pub hash: HashAlgorithm
}
impl PartialEq for SupportedCipherSuite {
@ -12,14 +31,26 @@ impl PartialEq for SupportedCipherSuite {
}
}
impl SupportedCipherSuite {
pub fn init_kx(&self) -> KeyExchangeData {
KeyExchangeData::Invalid
}
}
pub static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SupportedCipherSuite =
SupportedCipherSuite {
suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
kx: KeyExchangeAlgorithm::ECDHE_RSA,
bulk: BulkAlgorithm::AES_128_GCM,
hash: HashAlgorithm::SHA256
};
pub static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SupportedCipherSuite =
SupportedCipherSuite {
suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
suite: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
kx: KeyExchangeAlgorithm::ECDHE_RSA,
bulk: BulkAlgorithm::AES_256_GCM,
hash: HashAlgorithm::SHA384
};
pub static DEFAULT_CIPHERSUITES: [&'static SupportedCipherSuite; 2] = [