| { | ||
| "git": { | ||
| "sha1": "6a188a70a0e1bf4547884a9cdd7710936d653a22" | ||
| "sha1": "b4597ca1f6d386eee64e99b528dd58c8b4e073b5" | ||
| }, | ||
| "path_in_vcs": "rustls" | ||
| } |
+1
-1
@@ -813,3 +813,3 @@ # This file is automatically @generated by Cargo. | ||
| name = "rustls" | ||
| version = "0.23.32" | ||
| version = "0.23.33" | ||
| dependencies = [ | ||
@@ -816,0 +816,0 @@ "aws-lc-rs", |
+1
-1
@@ -16,3 +16,3 @@ # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO | ||
| name = "rustls" | ||
| version = "0.23.32" | ||
| version = "0.23.33" | ||
| build = "build.rs" | ||
@@ -19,0 +19,0 @@ exclude = [ |
+10
-3
@@ -484,2 +484,3 @@ use alloc::boxed::Box; | ||
| pub(crate) fn take_received_plaintext(&mut self, bytes: Payload<'_>) { | ||
| self.temper_counters.received_app_data(); | ||
| self.received_plaintext | ||
@@ -968,2 +969,10 @@ .append(bytes.into_vec()); | ||
| } | ||
| fn received_app_data(&mut self) { | ||
| self.allowed_key_update_requests = Self::INITIAL_KEY_UPDATE_REQUESTS; | ||
| } | ||
| // cf. BoringSSL `kMaxKeyUpdates` | ||
| // <https://github.com/google/boringssl/blob/dec5989b793c56ad4dd32173bd2d8595ca78b398/ssl/tls13_both.cc#L35-L38> | ||
| const INITIAL_KEY_UPDATE_REQUESTS: u8 = 32; | ||
| } | ||
@@ -982,5 +991,3 @@ | ||
| // cf. BoringSSL `kMaxKeyUpdates` | ||
| // <https://github.com/google/boringssl/blob/dec5989b793c56ad4dd32173bd2d8595ca78b398/ssl/tls13_both.cc#L35-L38> | ||
| allowed_key_update_requests: 32, | ||
| allowed_key_update_requests: Self::INITIAL_KEY_UPDATE_REQUESTS, | ||
@@ -987,0 +994,0 @@ // At most two CCS are allowed: one after each ClientHello (recall a second |
+22
-8
@@ -216,14 +216,28 @@ use alloc::boxed::Box; | ||
| pub fn new(iv: &Iv, seq: u64) -> Self { | ||
| let mut nonce = Self([0u8; NONCE_LEN]); | ||
| codec::put_u64(seq, &mut nonce.0[4..]); | ||
| let mut seq_bytes = [0u8; NONCE_LEN]; | ||
| codec::put_u64(seq, &mut seq_bytes[4..]); | ||
| Self::new_from_seq(iv, seq_bytes) | ||
| } | ||
| nonce | ||
| .0 | ||
| .iter_mut() | ||
| /// Creates a unique nonce based on the `iv`, the packet number `pn` and multipath `path_id`. | ||
| /// | ||
| /// The nonce is computed as the XOR between the `iv` and the 96-bit big-ending integer formed | ||
| /// by concatenating `path_id` and `pn`. | ||
| pub fn for_path(path_id: u32, iv: &Iv, pn: u64) -> Self { | ||
| let mut seq_bytes = [0u8; NONCE_LEN]; | ||
| seq_bytes[0..4].copy_from_slice(&path_id.to_be_bytes()); | ||
| codec::put_u64(pn, &mut seq_bytes[4..]); | ||
| Self::new_from_seq(iv, seq_bytes) | ||
| } | ||
| /// Creates a unique nonce based on the `iv` and sequence number `seq`. | ||
| #[inline] | ||
| fn new_from_seq(iv: &Iv, mut seq: [u8; NONCE_LEN]) -> Self { | ||
| seq.iter_mut() | ||
| .zip(iv.0.iter()) | ||
| .for_each(|(nonce, iv)| { | ||
| *nonce ^= *iv; | ||
| .for_each(|(s, iv)| { | ||
| *s ^= *iv; | ||
| }); | ||
| nonce | ||
| Self(seq) | ||
| } | ||
@@ -230,0 +244,0 @@ } |
+117
-0
@@ -143,2 +143,19 @@ #![allow(clippy::duplicate_mod)] | ||
| fn encrypt_in_place_for_path( | ||
| &self, | ||
| path_id: u32, | ||
| packet_number: u64, | ||
| header: &[u8], | ||
| payload: &mut [u8], | ||
| ) -> Result<quic::Tag, Error> { | ||
| let aad = aead::Aad::from(header); | ||
| let nonce = | ||
| aead::Nonce::assume_unique_for_key(Nonce::for_path(path_id, &self.iv, packet_number).0); | ||
| let tag = self | ||
| .key | ||
| .seal_in_place_separate_tag(nonce, aad, payload) | ||
| .map_err(|_| Error::EncryptError)?; | ||
| Ok(quic::Tag::from(tag.as_ref())) | ||
| } | ||
| /// Decrypt a QUIC packet | ||
@@ -168,2 +185,21 @@ /// | ||
| fn decrypt_in_place_for_path<'a>( | ||
| &self, | ||
| path_id: u32, | ||
| packet_number: u64, | ||
| header: &[u8], | ||
| payload: &'a mut [u8], | ||
| ) -> Result<&'a [u8], Error> { | ||
| let payload_len = payload.len(); | ||
| let aad = aead::Aad::from(header); | ||
| let nonce = | ||
| aead::Nonce::assume_unique_for_key(Nonce::for_path(path_id, &self.iv, packet_number).0); | ||
| self.key | ||
| .open_in_place(nonce, aad, payload) | ||
| .map_err(|_| Error::DecryptError)?; | ||
| let plain_len = payload_len - self.key.algorithm().tag_len(); | ||
| Ok(&payload[..plain_len]) | ||
| } | ||
| /// Tag length for the underlying AEAD algorithm | ||
@@ -418,2 +454,83 @@ #[inline] | ||
| } | ||
| // This test is based on picoquic's output for `multipath_aead_test` in | ||
| // `picoquictest/multipath_test.c`. | ||
| // | ||
| // See <https://github.com/private-octopus/picoquic/blob/be0d99e6d4f8759cb7920425351c06a1c6f4a958/picoquictest/multipath_test.c#L1537-L1606> | ||
| #[test] | ||
| fn test_multipath_aead_basic() { | ||
| const SECRET: &[u8; 32] = &[ | ||
| 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, | ||
| 24, 35, 26, 27, 28, 29, 30, 31, | ||
| ]; | ||
| const PN: u64 = 12345; | ||
| const PATH_ID: u32 = 2; | ||
| const PAYLOAD: &[u8] = b"The quick brown fox jumps over the lazy dog"; | ||
| const HEADER: &[u8] = b"This is a test"; | ||
| const EXPECTED: &[u8] = &[ | ||
| 123, 139, 232, 52, 136, 25, 201, 143, 250, 89, 87, 39, 37, 63, 0, 210, 220, 227, 186, | ||
| 140, 183, 251, 13, 203, 6, 116, 204, 100, 166, 64, 43, 185, 174, 85, 212, 163, 242, | ||
| 141, 24, 166, 62, 228, 187, 137, 248, 31, 152, 126, 240, 151, 79, 51, 253, 130, 43, | ||
| 114, 173, 234, 254, | ||
| ]; | ||
| let secret = OkmBlock::new(SECRET); | ||
| let builder = KeyBuilder::new( | ||
| &secret, | ||
| Version::V1, | ||
| TLS13_AES_128_GCM_SHA256_INTERNAL | ||
| .quic | ||
| .unwrap(), | ||
| TLS13_AES_128_GCM_SHA256_INTERNAL.hkdf_provider, | ||
| ); | ||
| let packet = builder.packet_key(); | ||
| let mut buf = PAYLOAD.to_vec(); | ||
| let tag = packet | ||
| .encrypt_in_place_for_path(PATH_ID, PN, HEADER, &mut buf) | ||
| .unwrap(); | ||
| buf.extend_from_slice(tag.as_ref()); | ||
| assert_eq!(buf.as_slice(), EXPECTED); | ||
| } | ||
| // This test is based on `multipath_aead_test` in `picoquictest/multipath_test.c` | ||
| // | ||
| // See <https://github.com/private-octopus/picoquic/blob/be0d99e6d4f8759cb7920425351c06a1c6f4a958/picoquictest/multipath_test.c#L1537-L1606> | ||
| #[test] | ||
| fn test_multipath_aead_roundtrip() { | ||
| const SECRET: &[u8; 32] = &[ | ||
| 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, | ||
| 24, 35, 26, 27, 28, 29, 30, 31, | ||
| ]; | ||
| const PAYLOAD: &[u8] = b"The quick brown fox jumps over the lazy dog"; | ||
| const HEADER: &[u8] = b"This is a test"; | ||
| const PN: u64 = 12345; | ||
| const TEST_PATH_IDS: &[u32] = &[0, 1, 2, 0xaead]; | ||
| let secret = OkmBlock::new(SECRET); | ||
| let builder = KeyBuilder::new( | ||
| &secret, | ||
| Version::V1, | ||
| TLS13_AES_128_GCM_SHA256_INTERNAL | ||
| .quic | ||
| .unwrap(), | ||
| TLS13_AES_128_GCM_SHA256_INTERNAL.hkdf_provider, | ||
| ); | ||
| let packet = builder.packet_key(); | ||
| for &path_id in TEST_PATH_IDS { | ||
| let mut buf = PAYLOAD.to_vec(); | ||
| let tag = packet | ||
| .encrypt_in_place_for_path(path_id, PN, HEADER, &mut buf) | ||
| .unwrap(); | ||
| buf.extend_from_slice(tag.as_ref()); | ||
| let decrypted = packet | ||
| .decrypt_in_place_for_path(path_id, PN, HEADER, &mut buf) | ||
| .unwrap(); | ||
| assert_eq!(decrypted, PAYLOAD); | ||
| } | ||
| } | ||
| } |
+39
-0
@@ -734,2 +734,21 @@ use alloc::boxed::Box; | ||
| /// Encrypts a multipath QUIC packet | ||
| /// | ||
| /// Takes a `path_id` and `packet_number`, used to derive the nonce; the packet `header`, which is used as | ||
| /// the additional authenticated data; and the `payload`. The authentication tag is returned if | ||
| /// encryption succeeds. | ||
| /// | ||
| /// Fails if and only if the payload is longer than allowed by the cipher suite's AEAD algorithm. | ||
| /// | ||
| /// See <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-11.html#name-nonce-calculation>. | ||
| fn encrypt_in_place_for_path( | ||
| &self, | ||
| _path_id: u32, | ||
| _packet_number: u64, | ||
| _header: &[u8], | ||
| _payload: &mut [u8], | ||
| ) -> Result<Tag, Error> { | ||
| Err(Error::EncryptError) | ||
| } | ||
| /// Decrypt a QUIC packet | ||
@@ -749,2 +768,22 @@ /// | ||
| /// Decrypt a multipath QUIC packet | ||
| /// | ||
| /// Takes a `path_id` and `packet_number`, used to derive the nonce; the packet `header`, which is used as | ||
| /// the additional authenticated data; and the `payload`. The authentication tag is returned if | ||
| /// encryption succeeds. | ||
| /// | ||
| /// If the return value is `Ok`, the decrypted payload can be found in `payload`, up to the | ||
| /// length found in the return value. | ||
| /// | ||
| /// See <https://www.ietf.org/archive/id/draft-ietf-quic-multipath-11.html#name-nonce-calculation>. | ||
| fn decrypt_in_place_for_path<'a>( | ||
| &self, | ||
| _path_id: u32, | ||
| _packet_number: u64, | ||
| _header: &[u8], | ||
| _payload: &'a mut [u8], | ||
| ) -> Result<&'a [u8], Error> { | ||
| Err(Error::DecryptError) | ||
| } | ||
| /// Tag length for the underlying AEAD algorithm | ||
@@ -751,0 +790,0 @@ fn tag_len(&self) -> usize; |
Sorry, the diff of this file is not supported yet