packet: support Retry with older versions too
I realized that until other implementations update to draft-29 we will
fail the Retry tests, so we might as well do this now.
It's mostly just a matter of propagating the version from the public API
exposed to applications, down to where the retry integrity tag is
generated.
diff --git a/examples/http3-server.c b/examples/http3-server.c
index fbef6f5..9ca1a7f 100644
--- a/examples/http3-server.c
+++ b/examples/http3-server.c
@@ -290,7 +290,7 @@
dcid, dcid_len,
dcid, dcid_len,
token, token_len,
- out, sizeof(out));
+ version, out, sizeof(out));
if (written < 0) {
fprintf(stderr, "failed to create retry packet: %zd\n",
diff --git a/examples/http3-server.rs b/examples/http3-server.rs
index 194ca00..2cd0e62 100644
--- a/examples/http3-server.rs
+++ b/examples/http3-server.rs
@@ -219,9 +219,15 @@
let new_token = mint_token(&hdr, &src);
let len = quiche::retry(
- &hdr.scid, &hdr.dcid, &scid, &new_token, &mut out,
+ &hdr.scid,
+ &hdr.dcid,
+ &scid,
+ &new_token,
+ hdr.version,
+ &mut out,
)
.unwrap();
+
let out = &out[..len];
if let Err(e) = socket.send_to(out, &src) {
diff --git a/examples/server.c b/examples/server.c
index 7068824..71a52d7 100644
--- a/examples/server.c
+++ b/examples/server.c
@@ -278,7 +278,7 @@
dcid, dcid_len,
dcid, dcid_len,
token, token_len,
- out, sizeof(out));
+ version, out, sizeof(out));
if (written < 0) {
fprintf(stderr, "failed to create retry packet: %zd\n",
diff --git a/examples/server.rs b/examples/server.rs
index abe16ca..8213d95 100644
--- a/examples/server.rs
+++ b/examples/server.rs
@@ -213,7 +213,12 @@
let new_token = mint_token(&hdr, &src);
let len = quiche::retry(
- &hdr.scid, &hdr.dcid, &scid, &new_token, &mut out,
+ &hdr.scid,
+ &hdr.dcid,
+ &scid,
+ &new_token,
+ hdr.version,
+ &mut out,
)
.unwrap();
diff --git a/include/quiche.h b/include/quiche.h
index 0eb3117..b63fc2e 100644
--- a/include/quiche.h
+++ b/include/quiche.h
@@ -216,7 +216,7 @@
const uint8_t *dcid, size_t dcid_len,
const uint8_t *new_scid, size_t new_scid_len,
const uint8_t *token, size_t token_len,
- uint8_t *out, size_t out_len);
+ uint32_t version, uint8_t *out, size_t out_len);
// Returns true if the given protocol version is supported.
bool quiche_version_is_supported(uint32_t version);
diff --git a/src/ffi.rs b/src/ffi.rs
index 42376f9..362c6f7 100644
--- a/src/ffi.rs
+++ b/src/ffi.rs
@@ -376,7 +376,7 @@
pub extern fn quiche_retry(
scid: *const u8, scid_len: size_t, dcid: *const u8, dcid_len: size_t,
new_scid: *const u8, new_scid_len: size_t, token: *const u8,
- token_len: size_t, out: *mut u8, out_len: size_t,
+ token_len: size_t, version: u32, out: *mut u8, out_len: size_t,
) -> ssize_t {
let scid = unsafe { slice::from_raw_parts(scid, scid_len) };
let dcid = unsafe { slice::from_raw_parts(dcid, dcid_len) };
@@ -384,7 +384,7 @@
let token = unsafe { slice::from_raw_parts(token, token_len) };
let out = unsafe { slice::from_raw_parts_mut(out, out_len) };
- match retry(scid, dcid, new_scid, token, out) {
+ match retry(scid, dcid, new_scid, token, version, out) {
Ok(v) => v as ssize_t,
Err(e) => e.to_c(),
diff --git a/src/lib.rs b/src/lib.rs
index 84177ef..28c8646 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -1004,7 +1004,7 @@
/// let new_token = mint_token(&hdr, &src);
///
/// let len = quiche::retry(
-/// &hdr.scid, &hdr.dcid, &scid, &new_token, &mut out,
+/// &hdr.scid, &hdr.dcid, &scid, &new_token, hdr.version, &mut out,
/// )?;
///
/// socket.send_to(&out[..len], &src).unwrap();
@@ -1023,9 +1023,10 @@
/// # Ok::<(), quiche::Error>(())
/// ```
pub fn retry(
- scid: &[u8], dcid: &[u8], new_scid: &[u8], token: &[u8], out: &mut [u8],
+ scid: &[u8], dcid: &[u8], new_scid: &[u8], token: &[u8], version: u32,
+ out: &mut [u8],
) -> Result<usize> {
- packet::retry(scid, dcid, new_scid, token, out)
+ packet::retry(scid, dcid, new_scid, token, version, out)
}
/// Returns true if the given protocol version is supported.
@@ -1497,7 +1498,9 @@
}
// Check if Retry packet is valid.
- if packet::verify_retry_integrity(&b, &self.dcid).is_err() {
+ if packet::verify_retry_integrity(&b, &self.dcid, self.version)
+ .is_err()
+ {
return Err(Error::Done);
}
@@ -6021,8 +6024,15 @@
let token = b"quiche test retry token";
- len =
- packet::retry(&hdr.scid, &hdr.dcid, &scid, token, &mut buf).unwrap();
+ len = packet::retry(
+ &hdr.scid,
+ &hdr.dcid,
+ &scid,
+ token,
+ hdr.version,
+ &mut buf,
+ )
+ .unwrap();
// Client receives Retry and sends new Initial.
assert_eq!(pipe.client.recv(&mut buf[..len]), Ok(len));
@@ -6071,8 +6081,15 @@
let token = b"quiche test retry token";
- len =
- packet::retry(&hdr.scid, &hdr.dcid, &scid, token, &mut buf).unwrap();
+ len = packet::retry(
+ &hdr.scid,
+ &hdr.dcid,
+ &scid,
+ token,
+ hdr.version,
+ &mut buf,
+ )
+ .unwrap();
// Client receives Retry and sends new Initial.
assert_eq!(pipe.client.recv(&mut buf[..len]), Ok(len));
@@ -6119,8 +6136,15 @@
let token = b"quiche test retry token";
- len =
- packet::retry(&hdr.scid, &hdr.dcid, &scid, token, &mut buf).unwrap();
+ len = packet::retry(
+ &hdr.scid,
+ &hdr.dcid,
+ &scid,
+ token,
+ hdr.version,
+ &mut buf,
+ )
+ .unwrap();
// Client receives Retry and sends new Initial.
assert_eq!(pipe.client.recv(&mut buf[..len]), Ok(len));
diff --git a/src/packet.rs b/src/packet.rs
index 3ef3661..e21bc2d 100644
--- a/src/packet.rs
+++ b/src/packet.rs
@@ -596,13 +596,18 @@
}
pub fn retry(
- scid: &[u8], dcid: &[u8], new_scid: &[u8], token: &[u8], out: &mut [u8],
+ scid: &[u8], dcid: &[u8], new_scid: &[u8], token: &[u8], version: u32,
+ out: &mut [u8],
) -> Result<usize> {
let mut b = octets::OctetsMut::with_slice(out);
+ if !crate::version_is_supported(version) {
+ return Err(Error::UnknownVersion);
+ }
+
let hdr = Header {
ty: Type::Retry,
- version: crate::PROTOCOL_VERSION,
+ version,
dcid: scid.to_vec(),
scid: new_scid.to_vec(),
pkt_num: 0,
@@ -614,15 +619,17 @@
hdr.to_bytes(&mut b)?;
- let tag = compute_retry_integrity_tag(&b, dcid)?;
+ let tag = compute_retry_integrity_tag(&b, dcid, version)?;
b.put_bytes(tag.as_ref())?;
Ok(b.off())
}
-pub fn verify_retry_integrity(b: &octets::OctetsMut, odcid: &[u8]) -> Result<()> {
- let tag = compute_retry_integrity_tag(b, odcid)?;
+pub fn verify_retry_integrity(
+ b: &octets::OctetsMut, odcid: &[u8], version: u32,
+) -> Result<()> {
+ let tag = compute_retry_integrity_tag(b, odcid, version)?;
ring::constant_time::verify_slices_are_equal(
&b.as_ref()[..aead::AES_128_GCM.tag_len()],
@@ -634,7 +641,7 @@
}
fn compute_retry_integrity_tag(
- b: &octets::OctetsMut, odcid: &[u8],
+ b: &octets::OctetsMut, odcid: &[u8], version: u32,
) -> Result<aead::Tag> {
const RETRY_INTEGRITY_KEY: [u8; 16] = [
0xcc, 0xce, 0x18, 0x7e, 0xd0, 0x9a, 0x09, 0xd0, 0x57, 0x28, 0x15, 0x5a,
@@ -645,6 +652,22 @@
0xe5, 0x49, 0x30, 0xf9, 0x7f, 0x21, 0x36, 0xf0, 0x53, 0x0a, 0x8c, 0x1c,
];
+ const RETRY_INTEGRITY_KEY_OLD: [u8; 16] = [
+ 0x4d, 0x32, 0xec, 0xdb, 0x2a, 0x21, 0x33, 0xc8, 0x41, 0xe4, 0x04, 0x3d,
+ 0xf2, 0x7d, 0x44, 0x30,
+ ];
+
+ const RETRY_INTEGRITY_NONCE_OLD: [u8; aead::NONCE_LEN] = [
+ 0x4d, 0x16, 0x11, 0xd0, 0x55, 0x13, 0xa5, 0x52, 0xc5, 0x87, 0xd5, 0x75,
+ ];
+
+ let (key, nonce) = match version {
+ crate::PROTOCOL_VERSION_DRAFT27 | crate::PROTOCOL_VERSION_DRAFT28 =>
+ (&RETRY_INTEGRITY_KEY_OLD, RETRY_INTEGRITY_NONCE_OLD),
+
+ _ => (&RETRY_INTEGRITY_KEY, RETRY_INTEGRITY_NONCE),
+ };
+
let hdr_len = b.off();
let mut pseudo = vec![0; 1 + odcid.len() + hdr_len];
@@ -656,11 +679,11 @@
pb.put_bytes(&b.buf()[..hdr_len])?;
let key = aead::LessSafeKey::new(
- aead::UnboundKey::new(&aead::AES_128_GCM, &RETRY_INTEGRITY_KEY)
+ aead::UnboundKey::new(&aead::AES_128_GCM, key)
.map_err(|_| Error::CryptoFail)?,
);
- let nonce = aead::Nonce::assume_unique_for_key(RETRY_INTEGRITY_NONCE);
+ let nonce = aead::Nonce::assume_unique_for_key(nonce);
let aad = aead::Aad::from(&pseudo);
diff --git a/tools/apps/src/bin/quiche-server.rs b/tools/apps/src/bin/quiche-server.rs
index 49f944c..54d6dab 100644
--- a/tools/apps/src/bin/quiche-server.rs
+++ b/tools/apps/src/bin/quiche-server.rs
@@ -266,9 +266,15 @@
let new_token = mint_token(&hdr, &src);
let len = quiche::retry(
- &hdr.scid, &hdr.dcid, &scid, &new_token, &mut out,
+ &hdr.scid,
+ &hdr.dcid,
+ &scid,
+ &new_token,
+ hdr.version,
+ &mut out,
)
.unwrap();
+
let out = &out[..len];
if let Err(e) = socket.send_to(out, &src) {