s2n_quic_crypto/
one_rtt.rs

1// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4use s2n_quic_core::crypto;
5
6header_key!(OneRttHeaderKey);
7negotiated_crypto!(OneRttKey, OneRttHeaderKey);
8
9impl crypto::OneRttKey for OneRttKey {
10    #[inline]
11    fn derive_next_key(&self) -> Self {
12        Self(self.0.update())
13    }
14}
15
16impl crypto::OneRttHeaderKey for OneRttHeaderKey {}
17
18#[cfg(test)]
19mod tests {
20    use crate::{cipher_suite::TLS_CHACHA20_POLY1305_SHA256, hkdf};
21    use hex_literal::hex;
22    use s2n_codec::{encoder::scatter, EncoderBuffer};
23    use s2n_quic_core::crypto::Key;
24
25    //= https://www.rfc-editor.org/rfc/rfc9001#appendix-A.5
26    //# In this example, TLS produces an application write secret from which
27    //# a server uses HKDF-Expand-Label to produce four values: a key, an IV,
28    //# a header protection key, and the secret that will be used after keys
29    //# are updated (this last value is not used further in this example).
30    //#
31    //# secret
32    //#     = 9ac312a7f877468ebe69422748ad00a1
33    //#       5443f18203a07d6060f688f30f21632b
34    //#
35    //# key = HKDF-Expand-Label(secret, "quic key", "", 32)
36    //#     = c6d98ff3441c3fe1b2182094f69caa2e
37    //#       d4b716b65488960a7a984979fb23e1c8
38    //#
39    //# iv  = HKDF-Expand-Label(secret, "quic iv", "", 12)
40    //#     = e0459b3474bdd0e44a41c144
41    //#
42    //# hp  = HKDF-Expand-Label(secret, "quic hp", "", 32)
43    //#     = 25a282b9e82f06f21f488917a4fc8f1b
44    //#       73573685608597d0efcb076b0ab7a7a4
45    //#
46    //# ku  = HKDF-Expand-Label(secret, "quic ku", "", 32)
47    //#     = 1223504755036d556342ee9361d25342
48    //#       1a826c9ecdf3c7148684b36b714881f9
49    const SECRET: [u8; 32] =
50        hex!("9ac312a7f877468ebe69422748ad00a15443f18203a07d6060f688f30f21632b");
51    const KU_SECRET: [u8; 32] =
52        hex!("1223504755036d556342ee9361d253421a826c9ecdf3c7148684b36b714881f9");
53
54    // Prevent trivial success
55    const INVALID_SECRET: [u8; 32] =
56        hex!("0000000000000000000000000000000000000000000000000000000000000000");
57
58    /// Return ChaCha20 ciphers because these are the ciphers given in the RFC. The other cipher
59    /// implementations don't have RFC values we can test.
60    /// This is not exhaustive, but it does show that we are using the KDF and label correctly.
61    fn generate_ciphers(
62        secret: &[u8],
63        next_secret: &[u8],
64    ) -> (TLS_CHACHA20_POLY1305_SHA256, TLS_CHACHA20_POLY1305_SHA256) {
65        // Create a cipher based on the initial secret
66        let key = hkdf::Prk::new_less_safe(hkdf::HKDF_SHA256, secret);
67        let cipher = TLS_CHACHA20_POLY1305_SHA256::new(key);
68
69        // Create the cipher after a Key Update has occurred
70        let next_cipher = cipher.0.update();
71
72        // Create a cipher based on the expected post-update secret
73        let next_key = hkdf::Prk::new_less_safe(hkdf::HKDF_SHA256, next_secret);
74        let expected_next_cipher = TLS_CHACHA20_POLY1305_SHA256::new(next_key);
75
76        (next_cipher, expected_next_cipher.0)
77    }
78
79    #[test]
80    fn test_key_update() {
81        let tests = [
82            (&SECRET, &KU_SECRET, true),
83            (&INVALID_SECRET, &KU_SECRET, false),
84        ];
85
86        for (secret, ku_secret, should_match) in tests {
87            let (mut next_cipher, mut expected_next_cipher) = generate_ciphers(secret, ku_secret);
88
89            // Encrypt two empty blocks to verify the ciphers are the same
90            let mut next_cipher_output = [0; 32];
91            let mut expected_cipher_output = [0; 32];
92
93            {
94                let next_cipher_output = EncoderBuffer::new(&mut next_cipher_output);
95                let mut next_cipher_output = scatter::Buffer::new(next_cipher_output);
96
97                let expected_cipher_output = EncoderBuffer::new(&mut expected_cipher_output);
98                let mut expected_cipher_output = scatter::Buffer::new(expected_cipher_output);
99
100                next_cipher
101                    .encrypt(0, &[], &mut next_cipher_output)
102                    .unwrap();
103                expected_next_cipher
104                    .encrypt(0, &[], &mut expected_cipher_output)
105                    .unwrap();
106            }
107
108            if should_match {
109                assert_eq!(next_cipher_output, expected_cipher_output);
110            } else {
111                assert_ne!(next_cipher_output, expected_cipher_output);
112            }
113        }
114    }
115}