rustls/
key_schedule.rs

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