diff --git a/src/crypto.rs b/src/crypto.rs index 852a20232..299ba7124 100644 --- a/src/crypto.rs +++ b/src/crypto.rs @@ -8,10 +8,10 @@ pub use ring::aead::AES_128_GCM; pub use ring::digest::SHA256; pub use ring::hmac::SigningKey; -use types::Side; +use types::{ConnectionId, Side}; pub enum Secret { - Handshake(u64), + Handshake(ConnectionId), For1Rtt( &'static aead::Algorithm, &'static digest::Algorithm, @@ -20,6 +20,13 @@ pub enum Secret { } impl Secret { + pub fn tag_len(&self) -> usize { + match *self { + Secret::Handshake(_) => AES_128_GCM.tag_len(), + Secret::For1Rtt(aead_alg, _, _) => aead_alg.tag_len(), + } + } + pub fn build_key(&self, side: Side) -> PacketKey { match *self { Secret::Handshake(cid) => { @@ -106,7 +113,7 @@ impl PacketKey { } } -pub fn expanded_handshake_secret(conn_id: u64, label: &[u8]) -> Vec { +pub fn expanded_handshake_secret(conn_id: ConnectionId, label: &[u8]) -> Vec { let prk = handshake_secret(conn_id); let mut out = vec![0u8; SHA256.output_len]; qhkdf_expand(&prk, label, &mut out); @@ -122,10 +129,10 @@ pub fn qhkdf_expand(key: &SigningKey, label: &[u8], out: &mut [u8]) { hkdf::expand(key, &info, out); } -fn handshake_secret(conn_id: u64) -> SigningKey { +fn handshake_secret(conn_id: ConnectionId) -> SigningKey { let key = SigningKey::new(&SHA256, HANDSHAKE_SALT); let mut buf = Vec::with_capacity(8); - buf.put_u64::(conn_id); + buf.put_slice(&conn_id); hkdf::extract(&key, &buf) } @@ -134,10 +141,15 @@ const HANDSHAKE_SALT: &[u8; 20] = #[cfg(test)] mod tests { + use types::ConnectionId; + #[test] fn test_handshake_client() { - let conn_id = 0x8394c8f03e515708; - let client_handshake_secret = super::expanded_handshake_secret(conn_id, b"client hs"); + let hs_cid = ConnectionId { + len: 8, + bytes: [0x83, 0x94, 0xc8, 0xf0, 0x3e, 0x51, 0x57, 0x08, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + }; + let client_handshake_secret = super::expanded_handshake_secret(hs_cid, b"client hs"); let expected = b"\x83\x55\xf2\x1a\x3d\x8f\x83\xec\xb3\xd0\xf9\x71\x08\xd3\xf9\x5e\ \x0f\x65\xb4\xd8\xae\x88\xa0\x61\x1e\xe4\x9d\xb0\xb5\x23\x59\x1d"; assert_eq!(&client_handshake_secret, expected); diff --git a/src/packet.rs b/src/packet.rs index 67f918c1f..ab87d0397 100644 --- a/src/packet.rs +++ b/src/packet.rs @@ -1,8 +1,9 @@ use bytes::{BigEndian, Buf, BufMut}; -use codec::{BufLen, Codec}; +use codec::{BufLen, Codec, VarLen}; use frame::{Frame, PaddingFrame}; use crypto::PacketKey; +use types::ConnectionId; use std::io::Cursor; @@ -17,8 +18,8 @@ impl Packet { self.header.ptype() } - pub fn conn_id(&self) -> Option { - self.header.conn_id() + pub fn dst_cid(&self) -> ConnectionId { + self.header.dst_cid() } pub fn number(&self) -> u32 { @@ -93,8 +94,8 @@ pub struct PartialDecode<'a> { } impl<'a> PartialDecode<'a> { - pub fn conn_id(&self) -> Option { - self.header.conn_id() + pub fn dst_cid(&self) -> ConnectionId { + self.header.dst_cid() } pub fn finish(self, key: &PacketKey) -> Packet { @@ -127,8 +128,10 @@ impl BufLen for Packet { pub enum Header { Long { ptype: LongType, - conn_id: u64, version: u32, + dst_cid: ConnectionId, + src_cid: ConnectionId, + len: u64, number: u32, }, } @@ -140,9 +143,9 @@ impl Header { } } - fn conn_id(&self) -> Option { + fn dst_cid(&self) -> ConnectionId { match *self { - Header::Long { conn_id, .. } => Some(conn_id), + Header::Long { dst_cid, .. } => dst_cid, } } @@ -156,7 +159,9 @@ impl Header { impl BufLen for Header { fn buf_len(&self) -> usize { match *self { - Header::Long { .. } => 17, + Header::Long { dst_cid, src_cid, len, .. } => { + 10 + (dst_cid.len as usize + src_cid.len as usize) + VarLen(len).buf_len() + } } } } @@ -166,13 +171,18 @@ impl Codec for Header { match *self { Header::Long { ptype, - conn_id, version, + dst_cid, + src_cid, + len, number, } => { buf.put_u8(128 | ptype.to_byte()); - buf.put_u64::(conn_id); buf.put_u32::(version); + buf.put_u8(dst_cid.len << 4 | src_cid.len); + buf.put_slice(&dst_cid); + buf.put_slice(&src_cid); + VarLen(len).encode(buf); buf.put_u32::(number); } } @@ -181,10 +191,24 @@ impl Codec for Header { fn decode(buf: &mut T) -> Self { let first = buf.get_u8(); if first & 128 == 128 { + let version = buf.get_u32::(); + let cils = buf.get_u8(); + + let (dst_cid, src_cid, used) = { + let (dcil, scil) = ((cils >> 4) as usize, (cils & 15) as usize); + let bytes = buf.bytes(); + let dst_cid = ConnectionId::new(&bytes[..dcil]); + let src_cid = ConnectionId::new(&bytes[dcil..dcil + scil]); + (dst_cid, src_cid, dcil + scil) + }; + + buf.advance(used); Header::Long { ptype: LongType::from_byte(first ^ 128), - conn_id: buf.get_u64::(), - version: buf.get_u32::(), + version, + dst_cid, + src_cid, + len: VarLen::decode(buf).0, number: buf.get_u32::(), } } else { @@ -268,33 +292,45 @@ impl ShortType { #[cfg(test)] mod tests { use super::{Header, LongType, Packet}; - use types::{DRAFT_10, Side}; + use types::{ConnectionId, DRAFT_11, Side}; use frame::{Frame, StreamFrame}; use crypto::Secret; + use codec::BufLen; #[test] fn test_roundtrip() { + let hs_cid = ConnectionId { + len: 9, + bytes: [1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0], + }; + let mut buf = vec![0u8; 65536]; let bytes = b"\x00\x01\x02\x03"; + let payload = vec![ + Frame::Stream(StreamFrame { + id: 0, + fin: false, + offset: 0, + len: Some(bytes.len() as u64), + data: bytes.to_vec(), + }), + ]; + + let secret = Secret::Handshake(hs_cid); + let len = (payload.buf_len() + secret.tag_len()) as u64; let packet = Packet { header: Header::Long { ptype: LongType::Initial, - conn_id: 123456789, - version: DRAFT_10, + version: DRAFT_11, + dst_cid: hs_cid, + src_cid: hs_cid, + len, number: 987654321, }, - payload: vec![ - Frame::Stream(StreamFrame { - id: 0, - fin: false, - offset: 0, - len: Some(bytes.len() as u64), - data: bytes.to_vec(), - }), - ], + payload, }; - let key = Secret::Handshake(123456789).build_key(Side::Client); + let key = secret.build_key(Side::Client); packet.encode(&key, &mut buf); let mut decoded = Packet::start_decode(&mut buf).finish(&key); diff --git a/src/server.rs b/src/server.rs index 67f169adb..8e5db529b 100644 --- a/src/server.rs +++ b/src/server.rs @@ -2,7 +2,7 @@ use futures::{Future, Poll}; use crypto::Secret; use packet::{LongType, Packet}; -use types::{Endpoint, Side}; +use types::{ConnectionId, Endpoint, Side}; use tls::{self, ServerTls}; use std::collections::{HashMap, hash_map::Entry}; @@ -17,7 +17,7 @@ pub struct Server { tls_config: Arc, in_buf: Vec, out_buf: Vec, - connections: HashMap)>, + connections: HashMap)>, } impl Server { @@ -45,16 +45,16 @@ impl Future for Server { loop { let (len, addr) = try_ready!(self.socket.poll_recv_from(&mut self.in_buf)); let partial = Packet::start_decode(&mut self.in_buf[..len]); - let conn_id = partial.conn_id().unwrap(); - match self.connections.entry(conn_id) { + let dst_cid = partial.dst_cid(); + match self.connections.entry(dst_cid) { Entry::Occupied(_) => { - println!("connection found for {}", conn_id); + println!("connection found for {:?}", dst_cid); } Entry::Vacant(entry) => { let endpoint = Endpoint::new( ServerTls::with_config(&self.tls_config), Side::Server, - Some(Secret::Handshake(conn_id)) + Some(Secret::Handshake(dst_cid)) ); let &mut (addr, ref mut endpoint) = entry.insert((addr, endpoint)); let key = endpoint.decode_key(&partial.header); @@ -75,4 +75,3 @@ impl Future for Server { } } } - diff --git a/src/tests.rs b/src/tests.rs index aa7804442..d757e870f 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -7,7 +7,7 @@ use std::sync::Arc; use crypto::Secret; use tls::{ClientTls, ServerTls}; -use types::{Endpoint, Side}; +use types::{ConnectionId, Endpoint, Side}; use self::untrusted::Input; @@ -18,12 +18,12 @@ fn test_handshake() { let mut c = client_endpoint(); let initial = c.initial("example.com"); - let mut s = server_endpoint(initial.conn_id().unwrap()); + let mut s = server_endpoint(initial.dst_cid()); let server_hello = s.handle_handshake(&initial).unwrap(); assert!(c.handle_handshake(&server_hello).is_some()); } -fn server_endpoint(hs_cid: u64) -> Endpoint { +fn server_endpoint(hs_cid: ConnectionId) -> Endpoint { let certs = { let f = File::open("certs/server.chain").expect("cannot open 'certs/server.chain'"); let mut reader = BufReader::new(f); diff --git a/src/tls.rs b/src/tls.rs index ccb22ee29..854f64816 100644 --- a/src/tls.rs +++ b/src/tls.rs @@ -7,7 +7,7 @@ use rustls::quic::{ClientSession, QuicSecret, ServerSession, TLSResult}; use std::sync::Arc; use crypto::Secret; -use types::{DRAFT_10, TransportParameter}; +use types::{DRAFT_11, TransportParameter}; use webpki::{DNSNameRef, TLSServerTrustAnchors}; use webpki_roots; @@ -71,8 +71,8 @@ impl ServerTls { session: ServerSession::new( config, ServerTransportParameters { - negotiated_version: DRAFT_10, - supported_versions: vec![DRAFT_10], + negotiated_version: DRAFT_11, + supported_versions: vec![DRAFT_11], parameters: encode_transport_parameters(&vec![ TransportParameter::InitialMaxStreamData(131072), TransportParameter::InitialMaxData(1048576), diff --git a/src/types.rs b/src/types.rs index 8ea067b36..7614a93df 100644 --- a/src/types.rs +++ b/src/types.rs @@ -11,7 +11,8 @@ use tls::{ClientTls, QuicTls}; pub struct Endpoint { side: Side, - pub dst_cid: u64, + pub dst_cid: ConnectionId, + pub src_cid: ConnectionId, pub src_pn: u32, secret: Secret, prev_secret: Option, @@ -39,6 +40,7 @@ where tls, side, dst_cid, + src_cid: rng.gen(), src_pn: rng.gen(), secret, prev_secret: None, @@ -69,8 +71,10 @@ where Packet { header: Header::Long { ptype: LongType::Initial, - conn_id: self.dst_cid, - version: DRAFT_10, + version: DRAFT_11, + dst_cid: self.dst_cid, + src_cid: self.src_cid, + len: (payload.buf_len() + self.secret.tag_len()) as u64, number, }, payload, @@ -83,8 +87,10 @@ where Packet { header: Header::Long { ptype: LongType::Handshake, - conn_id: self.dst_cid, - version: DRAFT_10, + version: DRAFT_11, + dst_cid: self.dst_cid, + src_cid: self.src_cid, + len: (payload.buf_len() + self.secret.tag_len()) as u64, number, }, payload, @@ -92,7 +98,7 @@ where } pub(crate) fn handle_handshake(&mut self, rsp: &Packet) -> Option { - self.dst_cid = rsp.conn_id().unwrap(); + self.dst_cid = rsp.dst_cid(); let tls_frame = rsp.payload .iter() .filter_map(|f| match *f { @@ -203,4 +209,4 @@ pub enum Side { impl Copy for Side {} -pub const DRAFT_10: u32 = 0xff00000a; +pub const DRAFT_11: u32 = 0xff00000b;