mirror of
https://github.com/n0-computer/noq.git
synced 2026-09-20 02:04:07 +00:00
Implement draft 11 packet header
This commit is contained in:
+19
-7
@@ -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<u8> {
|
||||
pub fn expanded_handshake_secret(conn_id: ConnectionId, label: &[u8]) -> Vec<u8> {
|
||||
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::<BigEndian>(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);
|
||||
|
||||
+62
-26
@@ -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<u64> {
|
||||
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<u64> {
|
||||
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<u64> {
|
||||
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::<BigEndian>(conn_id);
|
||||
buf.put_u32::<BigEndian>(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::<BigEndian>(number);
|
||||
}
|
||||
}
|
||||
@@ -181,10 +191,24 @@ impl Codec for Header {
|
||||
fn decode<T: Buf>(buf: &mut T) -> Self {
|
||||
let first = buf.get_u8();
|
||||
if first & 128 == 128 {
|
||||
let version = buf.get_u32::<BigEndian>();
|
||||
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::<BigEndian>(),
|
||||
version: buf.get_u32::<BigEndian>(),
|
||||
version,
|
||||
dst_cid,
|
||||
src_cid,
|
||||
len: VarLen::decode(buf).0,
|
||||
number: buf.get_u32::<BigEndian>(),
|
||||
}
|
||||
} 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);
|
||||
|
||||
|
||||
+6
-7
@@ -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<tls::ServerConfig>,
|
||||
in_buf: Vec<u8>,
|
||||
out_buf: Vec<u8>,
|
||||
connections: HashMap<u64, (SocketAddr, Endpoint<ServerTls>)>,
|
||||
connections: HashMap<ConnectionId, (SocketAddr, Endpoint<ServerTls>)>,
|
||||
}
|
||||
|
||||
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 {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -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<ServerTls> {
|
||||
fn server_endpoint(hs_cid: ConnectionId) -> Endpoint<ServerTls> {
|
||||
let certs = {
|
||||
let f = File::open("certs/server.chain").expect("cannot open 'certs/server.chain'");
|
||||
let mut reader = BufReader::new(f);
|
||||
|
||||
+3
-3
@@ -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),
|
||||
|
||||
+13
-7
@@ -11,7 +11,8 @@ use tls::{ClientTls, QuicTls};
|
||||
|
||||
pub struct Endpoint<T> {
|
||||
side: Side,
|
||||
pub dst_cid: u64,
|
||||
pub dst_cid: ConnectionId,
|
||||
pub src_cid: ConnectionId,
|
||||
pub src_pn: u32,
|
||||
secret: Secret,
|
||||
prev_secret: Option<Secret>,
|
||||
@@ -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<Packet> {
|
||||
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;
|
||||
|
||||
Reference in New Issue
Block a user