tlspuffin/tls/rustls/tls13/
key_schedule.rs

1#![allow(dead_code)]
2
3/// Key schedule maintenance for TLS1.3
4use ring::{
5    aead,
6    digest::{self, Digest},
7    hkdf::{self, KeyType as _, Prk},
8    hmac,
9};
10
11use crate::tls::rustls::cipher::{Iv, IvLen};
12use crate::tls::rustls::error::Error;
13use crate::tls::rustls::key_log::KeyLog;
14use crate::tls::rustls::msgs::base::PayloadU8;
15
16/// The kinds of secret we can extract from `KeySchedule`.
17#[derive(Debug, Clone, Copy, PartialEq)]
18enum SecretKind {
19    ResumptionPskBinderKey,
20    ClientEarlyTrafficSecret,
21    ClientHandshakeTrafficSecret,
22    ServerHandshakeTrafficSecret,
23    ClientApplicationTrafficSecret,
24    ServerApplicationTrafficSecret,
25    ExporterMasterSecret,
26    ResumptionMasterSecret,
27    DerivedSecret,
28}
29
30impl SecretKind {
31    fn to_bytes(self) -> &'static [u8] {
32        use self::SecretKind::*;
33        match self {
34            ResumptionPskBinderKey => b"res binder",
35            ClientEarlyTrafficSecret => b"c e traffic",
36            ClientHandshakeTrafficSecret => b"c hs traffic",
37            ServerHandshakeTrafficSecret => b"s hs traffic",
38            ClientApplicationTrafficSecret => b"c ap traffic",
39            ServerApplicationTrafficSecret => b"s ap traffic",
40            ExporterMasterSecret => b"exp master",
41            ResumptionMasterSecret => b"res master",
42            DerivedSecret => b"derived",
43        }
44    }
45
46    fn log_label(self) -> Option<&'static str> {
47        use self::SecretKind::*;
48        Some(match self {
49            ClientEarlyTrafficSecret => "CLIENT_EARLY_TRAFFIC_SECRET",
50            ClientHandshakeTrafficSecret => "CLIENT_HANDSHAKE_TRAFFIC_SECRET",
51            ServerHandshakeTrafficSecret => "SERVER_HANDSHAKE_TRAFFIC_SECRET",
52            ClientApplicationTrafficSecret => "CLIENT_TRAFFIC_SECRET_0",
53            ServerApplicationTrafficSecret => "SERVER_TRAFFIC_SECRET_0",
54            ExporterMasterSecret => "EXPORTER_SECRET",
55            _ => {
56                return None;
57            }
58        })
59    }
60}
61
62/// This is the TLS1.3 key schedule.  It stores the current secret and
63/// the type of hash.  This isn't used directly; but only through the
64/// typestates.
65pub struct KeySchedule {
66    current: hkdf::Prk,
67    algorithm: ring::hkdf::Algorithm,
68}
69
70// We express the state of a contained KeySchedule using these
71// typestates.  This means we can write code that cannot accidentally
72// (e.g.) encrypt application data using a KeySchedule solely constructed
73// with an empty or trivial secret, or extract the wrong kind of secrets
74// at a given point.
75
76/// KeySchedule for early data stage.
77pub struct KeyScheduleEarly {
78    ks: KeySchedule,
79}
80
81impl KeyScheduleEarly {
82    pub fn new(algorithm: hkdf::Algorithm, secret: &[u8]) -> Self {
83        Self {
84            ks: KeySchedule::new(algorithm, secret),
85        }
86    }
87
88    pub fn client_early_traffic_secret(
89        &self,
90        hs_hash: &Digest,
91        key_log: &dyn KeyLog,
92        client_random: &[u8; 32],
93    ) -> hkdf::Prk {
94        self.ks.derive_logged_secret(
95            SecretKind::ClientEarlyTrafficSecret,
96            hs_hash.as_ref(),
97            key_log,
98            client_random,
99        )
100    }
101
102    pub fn resumption_psk_binder_key_and_sign_verify_data(&self, hs_hash: &Digest) -> hmac::Tag {
103        let resumption_psk_binder_key = self
104            .ks
105            .derive_for_empty_hash(SecretKind::ResumptionPskBinderKey);
106        self.ks
107            .sign_verify_data_raw(&resumption_psk_binder_key, hs_hash.as_ref())
108    }
109}
110
111/// Pre-handshake key schedule
112///
113/// The inner `KeySchedule` is either constructed without any secrets based on ths HKDF algorithm
114/// or is extracted from a `KeyScheduleEarly`. This can then be used to derive the
115/// `KeyScheduleHandshakeStart`.
116pub struct KeySchedulePreHandshake {
117    ks: KeySchedule,
118}
119
120impl KeySchedulePreHandshake {
121    pub fn new(algorithm: hkdf::Algorithm) -> Self {
122        Self {
123            ks: KeySchedule::new_with_empty_secret(algorithm),
124        }
125    }
126
127    pub fn into_handshake(mut self, secret: &[u8]) -> KeyScheduleHandshakeStart {
128        self.ks.input_secret(secret);
129        KeyScheduleHandshakeStart { ks: self.ks }
130    }
131}
132
133impl From<KeyScheduleEarly> for KeySchedulePreHandshake {
134    fn from(KeyScheduleEarly { ks }: KeyScheduleEarly) -> Self {
135        Self { ks }
136    }
137}
138
139/// KeySchedule during handshake.
140pub struct KeyScheduleHandshakeStart {
141    ks: KeySchedule,
142}
143
144impl KeyScheduleHandshakeStart {
145    /// Create a new KeyScheduleHandshakeStart and skip the secret derivation
146    pub fn new_with_secret(algorithm: hkdf::Algorithm, secret: &[u8]) -> Self {
147        let key = Prk::new_less_safe(algorithm, secret);
148        Self {
149            ks: KeySchedule {
150                current: key,
151                algorithm,
152            },
153        }
154    }
155
156    pub fn derive_handshake_secrets(
157        self,
158        hs_hash: &[u8],
159        key_log: &dyn KeyLog,
160        client_random: &[u8; 32],
161    ) -> (KeyScheduleHandshake, hkdf::Prk, hkdf::Prk) {
162        // Use an empty handshake hash for the initial handshake.
163        let client_secret = self.ks.derive_logged_secret(
164            SecretKind::ClientHandshakeTrafficSecret,
165            hs_hash,
166            key_log,
167            client_random,
168        );
169
170        let server_secret = self.ks.derive_logged_secret(
171            SecretKind::ServerHandshakeTrafficSecret,
172            hs_hash,
173            key_log,
174            client_random,
175        );
176
177        let new = KeyScheduleHandshake {
178            ks: self.ks,
179            client_handshake_traffic_secret: client_secret.clone(),
180            server_handshake_traffic_secret: server_secret.clone(),
181        };
182
183        (new, client_secret, server_secret)
184    }
185}
186
187pub struct KeyScheduleHandshake {
188    ks: KeySchedule,
189    client_handshake_traffic_secret: hkdf::Prk,
190    server_handshake_traffic_secret: hkdf::Prk,
191}
192
193impl KeyScheduleHandshake {
194    pub fn sign_server_finish(&self, hs_hash: &Digest) -> hmac::Tag {
195        self.sign_server_finish_raw(hs_hash.as_ref())
196    }
197
198    pub fn sign_server_finish_raw(&self, hs_hash: &[u8]) -> hmac::Tag {
199        self.ks
200            .sign_finish_raw(&self.server_handshake_traffic_secret, hs_hash)
201    }
202
203    pub fn client_key(&self) -> &hkdf::Prk {
204        &self.client_handshake_traffic_secret
205    }
206
207    pub fn into_traffic_with_client_finished_pending(
208        self,
209        hs_hash: Digest,
210        key_log: &dyn KeyLog,
211        client_random: &[u8; 32],
212    ) -> (
213        KeyScheduleTrafficWithClientFinishedPending,
214        hkdf::Prk,
215        hkdf::Prk,
216    ) {
217        self.into_traffic_with_client_finished_pending_raw(hs_hash.as_ref(), key_log, client_random)
218    }
219
220    pub fn into_traffic_with_client_finished_pending_raw(
221        self,
222        hs_hash: &[u8],
223        key_log: &dyn KeyLog,
224        client_random: &[u8; 32],
225    ) -> (
226        KeyScheduleTrafficWithClientFinishedPending,
227        hkdf::Prk,
228        hkdf::Prk,
229    ) {
230        let traffic = KeyScheduleTraffic::new(self.ks, hs_hash, key_log, client_random);
231
232        let client_secret = traffic.current_client_traffic_secret.clone();
233        let server_secret = traffic.current_server_traffic_secret.clone();
234
235        let new = KeyScheduleTrafficWithClientFinishedPending {
236            handshake_client_traffic_secret: self.client_handshake_traffic_secret,
237            traffic,
238        };
239
240        (new, client_secret, server_secret)
241    }
242}
243
244/// KeySchedule during traffic stage.
245///
246/// Note: Retains the ability to calculate the client's finished verify_data. The traffic stage key
247/// schedule can be extracted from it through signing the client finished hash.
248pub struct KeyScheduleTrafficWithClientFinishedPending {
249    handshake_client_traffic_secret: hkdf::Prk,
250    traffic: KeyScheduleTraffic,
251}
252
253impl KeyScheduleTrafficWithClientFinishedPending {
254    pub fn client_key(&self) -> &hkdf::Prk {
255        &self.handshake_client_traffic_secret
256    }
257
258    pub fn sign_client_finish(
259        self,
260        hs_hash: &Digest,
261    ) -> (KeyScheduleTraffic, hmac::Tag, hkdf::Prk) {
262        self.sign_client_finish_raw(hs_hash.as_ref())
263    }
264
265    pub fn sign_client_finish_raw(
266        self,
267        hs_hash: &[u8],
268    ) -> (KeyScheduleTraffic, hmac::Tag, hkdf::Prk) {
269        let tag = self
270            .traffic
271            .ks
272            .sign_finish_raw(&self.handshake_client_traffic_secret, hs_hash);
273
274        let client_secret = self.traffic.current_client_traffic_secret.clone();
275
276        (self.traffic, tag, client_secret)
277    }
278}
279
280/// KeySchedule during traffic stage.  All traffic & exporter keys are guaranteed
281/// to be available.
282pub struct KeyScheduleTraffic {
283    ks: KeySchedule,
284    current_client_traffic_secret: hkdf::Prk,
285    current_server_traffic_secret: hkdf::Prk,
286    current_exporter_secret: hkdf::Prk,
287}
288
289impl KeyScheduleTraffic {
290    fn new(
291        mut ks: KeySchedule,
292        hs_hash: &[u8],
293        key_log: &dyn KeyLog,
294        client_random: &[u8; 32],
295    ) -> Self {
296        ks.input_empty();
297
298        let current_client_traffic_secret = ks.derive_logged_secret(
299            SecretKind::ClientApplicationTrafficSecret,
300            hs_hash,
301            key_log,
302            client_random,
303        );
304
305        let current_server_traffic_secret = ks.derive_logged_secret(
306            SecretKind::ServerApplicationTrafficSecret,
307            hs_hash,
308            key_log,
309            client_random,
310        );
311
312        let current_exporter_secret = ks.derive_logged_secret(
313            SecretKind::ExporterMasterSecret,
314            hs_hash,
315            key_log,
316            client_random,
317        );
318
319        Self {
320            ks,
321            current_client_traffic_secret,
322            current_server_traffic_secret,
323            current_exporter_secret,
324        }
325    }
326
327    pub fn next_server_application_traffic_secret(&mut self) -> hkdf::Prk {
328        let secret = self.ks.derive_next(&self.current_server_traffic_secret);
329        self.current_server_traffic_secret = secret.clone();
330        secret
331    }
332
333    pub fn next_client_application_traffic_secret(&mut self) -> hkdf::Prk {
334        let secret = self.ks.derive_next(&self.current_client_traffic_secret);
335        self.current_client_traffic_secret = secret.clone();
336        secret
337    }
338
339    pub fn resumption_master_secret_and_derive_ticket_psk(
340        &self,
341        hs_hash: &Digest,
342        nonce: &[u8],
343    ) -> Vec<u8> {
344        self.resumption_master_secret_and_derive_ticket_psk_raw(hs_hash.as_ref(), nonce)
345    }
346
347    pub fn resumption_master_secret_and_derive_ticket_psk_raw(
348        &self,
349        hs_hash: &[u8],
350        nonce: &[u8],
351    ) -> Vec<u8> {
352        let resumption_master_secret = self.ks.derive(
353            self.ks.algorithm(),
354            SecretKind::ResumptionMasterSecret,
355            hs_hash,
356        );
357        self.ks.derive_ticket_psk(&resumption_master_secret, nonce)
358    }
359
360    pub fn export_keying_material(
361        &self,
362        out: &mut [u8],
363        label: &[u8],
364        context: Option<&[u8]>,
365    ) -> Result<(), Error> {
366        self.ks
367            .export_keying_material(&self.current_exporter_secret, out, label, context)
368    }
369}
370
371impl KeySchedule {
372    fn new(algorithm: hkdf::Algorithm, secret: &[u8]) -> Self {
373        let zeroes = [0u8; digest::MAX_OUTPUT_LEN];
374        let salt = hkdf::Salt::new(algorithm, &zeroes[..algorithm.len()]);
375        Self {
376            current: salt.extract(secret),
377            algorithm,
378        }
379    }
380
381    #[inline]
382    fn algorithm(&self) -> hkdf::Algorithm {
383        self.algorithm
384    }
385
386    fn new_with_empty_secret(algorithm: hkdf::Algorithm) -> Self {
387        let zeroes = [0u8; digest::MAX_OUTPUT_LEN];
388        Self::new(algorithm, &zeroes[..algorithm.len()])
389    }
390
391    /// Input the empty secret.
392    fn input_empty(&mut self) {
393        let zeroes = [0u8; digest::MAX_OUTPUT_LEN];
394        self.input_secret(&zeroes[..self.algorithm.len()]);
395    }
396
397    /// Input the given secret.
398    fn input_secret(&mut self, secret: &[u8]) {
399        let salt: hkdf::Salt = self.derive_for_empty_hash(SecretKind::DerivedSecret);
400        self.current = salt.extract(secret);
401    }
402
403    /// Derive a secret of given `kind`, using current handshake hash `hs_hash`.
404    fn derive<T, L>(&self, key_type: L, kind: SecretKind, hs_hash: &[u8]) -> T
405    where
406        T: for<'a> From<hkdf::Okm<'a, L>>,
407        L: hkdf::KeyType,
408    {
409        hkdf_expand(&self.current, key_type, kind.to_bytes(), hs_hash)
410    }
411
412    fn derive_logged_secret(
413        &self,
414        kind: SecretKind,
415        hs_hash: &[u8],
416        key_log: &dyn KeyLog,
417        client_random: &[u8; 32],
418    ) -> hkdf::Prk {
419        let log_label = kind.log_label().expect("not a loggable secret");
420        if key_log.will_log(log_label) {
421            let secret = self
422                .derive::<PayloadU8, _>(PayloadU8Len(self.algorithm.len()), kind, hs_hash)
423                .into_inner();
424            key_log.log(log_label, client_random, &secret);
425        }
426        self.derive(self.algorithm, kind, hs_hash)
427    }
428
429    /// Derive a secret of given `kind` using the hash of the empty string
430    /// for the handshake hash.  Useful only for
431    /// `SecretKind::ResumptionPSKBinderKey` and
432    /// `SecretKind::DerivedSecret`.
433    fn derive_for_empty_hash<T>(&self, kind: SecretKind) -> T
434    where
435        T: for<'a> From<hkdf::Okm<'a, hkdf::Algorithm>>,
436    {
437        let digest_alg = self.algorithm.hmac_algorithm().digest_algorithm();
438        let empty_hash = digest::digest(digest_alg, &[]);
439        self.derive(self.algorithm, kind, empty_hash.as_ref())
440    }
441
442    /// Sign the finished message consisting of `hs_hash` using a current
443    /// traffic secret.
444    fn sign_finish(&self, base_key: &hkdf::Prk, hs_hash: &Digest) -> hmac::Tag {
445        self.sign_finish_raw(base_key, hs_hash.as_ref())
446    }
447
448    fn sign_finish_raw(&self, base_key: &hkdf::Prk, hs_hash: &[u8]) -> hmac::Tag {
449        self.sign_verify_data_raw(base_key, hs_hash)
450    }
451
452    /// Sign the finished message consisting of `hs_hash` using the key material
453    /// `base_key`.
454    fn sign_verify_data(&self, base_key: &hkdf::Prk, hs_hash: &Digest) -> hmac::Tag {
455        self.sign_verify_data_raw(base_key, hs_hash.as_ref())
456    }
457
458    fn sign_verify_data_raw(&self, base_key: &hkdf::Prk, hs_hash: &[u8]) -> hmac::Tag {
459        let hmac_alg = self.algorithm.hmac_algorithm();
460        let hmac_key = hkdf_expand(base_key, hmac_alg, b"finished", &[]);
461        hmac::sign(&hmac_key, hs_hash)
462    }
463
464    /// Derive the next application traffic secret, returning it.
465    fn derive_next(&self, base_key: &hkdf::Prk) -> hkdf::Prk {
466        hkdf_expand(base_key, self.algorithm, b"traffic upd", &[])
467    }
468
469    /// Derive the PSK to use given a resumption_master_secret and
470    /// ticket_nonce.
471    fn derive_ticket_psk(&self, rms: &hkdf::Prk, nonce: &[u8]) -> Vec<u8> {
472        let payload: PayloadU8 = hkdf_expand(
473            rms,
474            PayloadU8Len(self.algorithm.len()),
475            b"resumption",
476            nonce,
477        );
478        payload.into_inner()
479    }
480
481    fn export_keying_material(
482        &self,
483        current_exporter_secret: &hkdf::Prk,
484        out: &mut [u8],
485        label: &[u8],
486        context: Option<&[u8]>,
487    ) -> Result<(), Error> {
488        let digest_alg = self.algorithm.hmac_algorithm().digest_algorithm();
489
490        let h_empty = digest::digest(digest_alg, &[]);
491        let secret: hkdf::Prk = hkdf_expand(
492            current_exporter_secret,
493            self.algorithm,
494            label,
495            h_empty.as_ref(),
496        );
497
498        let h_context = digest::digest(digest_alg, context.unwrap_or(&[]));
499
500        // TODO: Test what happens when this fails
501        hkdf_expand_info(
502            &secret,
503            PayloadU8Len(out.len()),
504            b"exporter",
505            h_context.as_ref(),
506            |okm| okm.fill(out),
507        )
508        .map_err(|_| Error::General("exporting too much".to_string()))
509    }
510}
511
512pub fn hkdf_expand<T, L>(secret: &hkdf::Prk, key_type: L, label: &[u8], context: &[u8]) -> T
513where
514    T: for<'a> From<hkdf::Okm<'a, L>>,
515    L: hkdf::KeyType,
516{
517    hkdf_expand_info(secret, key_type, label, context, |okm| okm.into())
518}
519
520fn hkdf_expand_info<F, T, L>(
521    secret: &hkdf::Prk,
522    key_type: L,
523    label: &[u8],
524    context: &[u8],
525    f: F,
526) -> T
527where
528    F: for<'b> FnOnce(hkdf::Okm<'b, L>) -> T,
529    L: hkdf::KeyType,
530{
531    const LABEL_PREFIX: &[u8] = b"tls13 ";
532
533    let output_len = u16::to_be_bytes(key_type.len() as u16);
534    let label_len = u8::to_be_bytes((LABEL_PREFIX.len() + label.len()) as u8);
535    let context_len = u8::to_be_bytes(context.len() as u8);
536
537    let info = &[
538        &output_len[..],
539        &label_len[..],
540        LABEL_PREFIX,
541        label,
542        &context_len[..],
543        context,
544    ];
545    let okm = secret.expand(info, key_type).unwrap();
546
547    f(okm)
548}
549
550pub struct PayloadU8Len(pub usize);
551impl hkdf::KeyType for PayloadU8Len {
552    fn len(&self) -> usize {
553        self.0
554    }
555}
556
557impl From<hkdf::Okm<'_, PayloadU8Len>> for PayloadU8 {
558    fn from(okm: hkdf::Okm<PayloadU8Len>) -> Self {
559        let mut r = vec![0u8; okm.len().0];
560        okm.fill(&mut r[..]).unwrap();
561        Self::new(r)
562    }
563}
564
565pub fn derive_traffic_key(
566    secret: &hkdf::Prk,
567    aead_algorithm: &'static aead::Algorithm,
568) -> aead::UnboundKey {
569    hkdf_expand(secret, aead_algorithm, b"key", &[])
570}
571
572pub fn derive_traffic_iv(secret: &hkdf::Prk) -> Iv {
573    hkdf_expand(secret, IvLen, b"iv", &[])
574}
575
576#[cfg(test)]
577mod tests {
578    use ring::{aead, hkdf};
579
580    use super::{derive_traffic_iv, derive_traffic_key, KeySchedule, SecretKind};
581    use crate::tls::rustls::key_log::KeyLog;
582
583    #[test_log::test]
584    fn test_vectors() {
585        /* These test vectors generated with OpenSSL. */
586        let hs_start_hash = [
587            0xec, 0x14, 0x7a, 0x06, 0xde, 0xa3, 0xc8, 0x84, 0x6c, 0x02, 0xb2, 0x23, 0x8e, 0x41,
588            0xbd, 0xdc, 0x9d, 0x89, 0xf9, 0xae, 0xa1, 0x7b, 0x5e, 0xfd, 0x4d, 0x74, 0x82, 0xaf,
589            0x75, 0x88, 0x1c, 0x0a,
590        ];
591
592        let hs_full_hash = [
593            0x75, 0x1a, 0x3d, 0x4a, 0x14, 0xdf, 0xab, 0xeb, 0x68, 0xe9, 0x2c, 0xa5, 0x91, 0x8e,
594            0x24, 0x08, 0xb9, 0xbc, 0xb0, 0x74, 0x89, 0x82, 0xec, 0x9c, 0x32, 0x30, 0xac, 0x30,
595            0xbb, 0xeb, 0x23, 0xe2,
596        ];
597
598        let ecdhe_secret = [
599            0xe7, 0xb8, 0xfe, 0xf8, 0x90, 0x3b, 0x52, 0x0c, 0xb9, 0xa1, 0x89, 0x71, 0xb6, 0x9d,
600            0xd4, 0x5d, 0xca, 0x53, 0xce, 0x2f, 0x12, 0xbf, 0x3b, 0xef, 0x93, 0x15, 0xe3, 0x12,
601            0x71, 0xdf, 0x4b, 0x40,
602        ];
603
604        let client_hts = [
605            0x61, 0x7b, 0x35, 0x07, 0x6b, 0x9d, 0x0e, 0x08, 0xcf, 0x73, 0x1d, 0x94, 0xa8, 0x66,
606            0x14, 0x78, 0x41, 0x09, 0xef, 0x25, 0x55, 0x51, 0x92, 0x1d, 0xd4, 0x6e, 0x04, 0x01,
607            0x35, 0xcf, 0x46, 0xab,
608        ];
609
610        let client_hts_key = [
611            0x62, 0xd0, 0xdd, 0x00, 0xf6, 0x96, 0x19, 0xd3, 0xb8, 0x19, 0x3a, 0xb4, 0xa0, 0x95,
612            0x85, 0xa7,
613        ];
614
615        let client_hts_iv = [
616            0xff, 0xf7, 0x5d, 0xf5, 0xad, 0x35, 0xd5, 0xcb, 0x3c, 0x53, 0xf3, 0xa9,
617        ];
618
619        let server_hts = [
620            0xfc, 0xf7, 0xdf, 0xe6, 0x4f, 0xa2, 0xc0, 0x4f, 0x62, 0x35, 0x38, 0x7f, 0x43, 0x4e,
621            0x01, 0x42, 0x23, 0x36, 0xd9, 0xc0, 0x39, 0xde, 0x68, 0x47, 0xa0, 0xb9, 0xdd, 0xcf,
622            0x29, 0xa8, 0x87, 0x59,
623        ];
624
625        let server_hts_key = [
626            0x04, 0x67, 0xf3, 0x16, 0xa8, 0x05, 0xb8, 0xc4, 0x97, 0xee, 0x67, 0x04, 0x7b, 0xbc,
627            0xbc, 0x54,
628        ];
629
630        let server_hts_iv = [
631            0xde, 0x83, 0xa7, 0x3e, 0x9d, 0x81, 0x4b, 0x04, 0xc4, 0x8b, 0x78, 0x09,
632        ];
633
634        let client_ats = [
635            0xc1, 0x4a, 0x6d, 0x79, 0x76, 0xd8, 0x10, 0x2b, 0x5a, 0x0c, 0x99, 0x51, 0x49, 0x3f,
636            0xee, 0x87, 0xdc, 0xaf, 0xf8, 0x2c, 0x24, 0xca, 0xb2, 0x14, 0xe8, 0xbe, 0x71, 0xa8,
637            0x20, 0x6d, 0xbd, 0xa5,
638        ];
639
640        let client_ats_key = [
641            0xcc, 0x9f, 0x5f, 0x98, 0x0b, 0x5f, 0x10, 0x30, 0x6c, 0xba, 0xd7, 0xbe, 0x98, 0xd7,
642            0x57, 0x2e,
643        ];
644
645        let client_ats_iv = [
646            0xb8, 0x09, 0x29, 0xe8, 0xd0, 0x2c, 0x70, 0xf6, 0x11, 0x62, 0xed, 0x6b,
647        ];
648
649        let server_ats = [
650            0x2c, 0x90, 0x77, 0x38, 0xd3, 0xf8, 0x37, 0x02, 0xd1, 0xe4, 0x59, 0x8f, 0x48, 0x48,
651            0x53, 0x1d, 0x9f, 0x93, 0x65, 0x49, 0x1b, 0x9f, 0x7f, 0x52, 0xc8, 0x22, 0x29, 0x0d,
652            0x4c, 0x23, 0x21, 0x92,
653        ];
654
655        let server_ats_key = [
656            0x0c, 0xb2, 0x95, 0x62, 0xd8, 0xd8, 0x8f, 0x48, 0xb0, 0x2c, 0xbf, 0xbe, 0xd7, 0xe6,
657            0x2b, 0xb3,
658        ];
659
660        let server_ats_iv = [
661            0x0d, 0xb2, 0x8f, 0x98, 0x85, 0x86, 0xa1, 0xb7, 0xe4, 0xd5, 0xc6, 0x9c,
662        ];
663
664        let hkdf = hkdf::HKDF_SHA256;
665        let mut ks = KeySchedule::new_with_empty_secret(hkdf);
666        ks.input_secret(&ecdhe_secret);
667
668        assert_traffic_secret(
669            &ks,
670            SecretKind::ClientHandshakeTrafficSecret,
671            &hs_start_hash,
672            &client_hts,
673            &client_hts_key,
674            &client_hts_iv,
675        );
676
677        assert_traffic_secret(
678            &ks,
679            SecretKind::ServerHandshakeTrafficSecret,
680            &hs_start_hash,
681            &server_hts,
682            &server_hts_key,
683            &server_hts_iv,
684        );
685
686        ks.input_empty();
687
688        assert_traffic_secret(
689            &ks,
690            SecretKind::ClientApplicationTrafficSecret,
691            &hs_full_hash,
692            &client_ats,
693            &client_ats_key,
694            &client_ats_iv,
695        );
696
697        assert_traffic_secret(
698            &ks,
699            SecretKind::ServerApplicationTrafficSecret,
700            &hs_full_hash,
701            &server_ats,
702            &server_ats_key,
703            &server_ats_iv,
704        );
705    }
706
707    fn assert_traffic_secret(
708        ks: &KeySchedule,
709        kind: SecretKind,
710        hash: &[u8],
711        expected_traffic_secret: &[u8],
712        expected_key: &[u8],
713        expected_iv: &[u8],
714    ) {
715        struct Log<'a>(&'a [u8]);
716        impl KeyLog for Log<'_> {
717            fn log(&self, _label: &str, _client_random: &[u8], secret: &[u8]) {
718                assert_eq!(self.0, secret);
719            }
720        }
721        let log = Log(expected_traffic_secret);
722        let traffic_secret = ks.derive_logged_secret(kind, hash, &log, &[0; 32]);
723
724        // Since we can't test key equality, we test the output of sealing with the key instead.
725        let aead_alg = &aead::AES_128_GCM;
726        let key = derive_traffic_key(&traffic_secret, aead_alg);
727        let seal_output = seal_zeroes(key);
728        let expected_key = aead::UnboundKey::new(aead_alg, expected_key).unwrap();
729        let expected_seal_output = seal_zeroes(expected_key);
730        assert_eq!(seal_output, expected_seal_output);
731        assert!(seal_output.len() >= 48); // Sanity check.
732
733        let iv = derive_traffic_iv(&traffic_secret);
734        assert_eq!(iv.value(), expected_iv);
735    }
736
737    fn seal_zeroes(key: aead::UnboundKey) -> Vec<u8> {
738        let key = aead::LessSafeKey::new(key);
739        let mut seal_output = vec![0; 32];
740        key.seal_in_place_append_tag(
741            aead::Nonce::assume_unique_for_key([0; aead::NONCE_LEN]),
742            aead::Aad::empty(),
743            &mut seal_output,
744        )
745        .unwrap();
746        seal_output
747    }
748}