1 | use crate::common_state::{CommonState, Side}; |
2 | use crate::crypto::cipher::{AeadKey, Iv, MessageDecrypter}; |
3 | use crate::crypto::tls13::{expand, Hkdf, HkdfExpander, OkmBlock, OutputLengthError}; |
4 | use crate::crypto::{hash, hmac, ActiveKeyExchange}; |
5 | use crate::error::Error; |
6 | use crate::quic; |
7 | use crate::suites::PartiallyExtractedSecrets; |
8 | use crate::{KeyLog, Tls13CipherSuite}; |
9 | |
10 | use alloc::boxed::Box; |
11 | use alloc::string::ToString; |
12 | |
13 | /// Key schedule maintenance for TLS1.3 |
14 | |
15 | /// The kinds of secret we can extract from `KeySchedule`. |
16 | #[derive (Debug, Clone, Copy, PartialEq)] |
17 | enum SecretKind { |
18 | ResumptionPskBinderKey, |
19 | ClientEarlyTrafficSecret, |
20 | ClientHandshakeTrafficSecret, |
21 | ServerHandshakeTrafficSecret, |
22 | ClientApplicationTrafficSecret, |
23 | ServerApplicationTrafficSecret, |
24 | ExporterMasterSecret, |
25 | ResumptionMasterSecret, |
26 | DerivedSecret, |
27 | } |
28 | |
29 | impl SecretKind { |
30 | fn to_bytes(self) -> &'static [u8] { |
31 | use self::SecretKind::*; |
32 | match self { |
33 | ResumptionPskBinderKey => b"res binder" , |
34 | ClientEarlyTrafficSecret => b"c e traffic" , |
35 | ClientHandshakeTrafficSecret => b"c hs traffic" , |
36 | ServerHandshakeTrafficSecret => b"s hs traffic" , |
37 | ClientApplicationTrafficSecret => b"c ap traffic" , |
38 | ServerApplicationTrafficSecret => b"s ap traffic" , |
39 | ExporterMasterSecret => b"exp master" , |
40 | ResumptionMasterSecret => b"res master" , |
41 | DerivedSecret => b"derived" , |
42 | } |
43 | } |
44 | |
45 | fn log_label(self) -> Option<&'static str> { |
46 | use self::SecretKind::*; |
47 | Some(match self { |
48 | ClientEarlyTrafficSecret => "CLIENT_EARLY_TRAFFIC_SECRET" , |
49 | ClientHandshakeTrafficSecret => "CLIENT_HANDSHAKE_TRAFFIC_SECRET" , |
50 | ServerHandshakeTrafficSecret => "SERVER_HANDSHAKE_TRAFFIC_SECRET" , |
51 | ClientApplicationTrafficSecret => "CLIENT_TRAFFIC_SECRET_0" , |
52 | ServerApplicationTrafficSecret => "SERVER_TRAFFIC_SECRET_0" , |
53 | ExporterMasterSecret => "EXPORTER_SECRET" , |
54 | _ => { |
55 | return None; |
56 | } |
57 | }) |
58 | } |
59 | } |
60 | |
61 | /// This is the TLS1.3 key schedule. It stores the current secret and |
62 | /// the type of hash. This isn't used directly; but only through the |
63 | /// typestates. |
64 | struct KeySchedule { |
65 | current: Box<dyn HkdfExpander>, |
66 | suite: &'static Tls13CipherSuite, |
67 | } |
68 | |
69 | // We express the state of a contained KeySchedule using these |
70 | // typestates. This means we can write code that cannot accidentally |
71 | // (e.g.) encrypt application data using a KeySchedule solely constructed |
72 | // with an empty or trivial secret, or extract the wrong kind of secrets |
73 | // at a given point. |
74 | |
75 | /// KeySchedule for early data stage. |
76 | pub(crate) struct KeyScheduleEarly { |
77 | ks: KeySchedule, |
78 | } |
79 | |
80 | impl KeyScheduleEarly { |
81 | pub(crate) fn new(suite: &'static Tls13CipherSuite, secret: &[u8]) -> Self { |
82 | Self { |
83 | ks: KeySchedule::new(suite, secret), |
84 | } |
85 | } |
86 | |
87 | pub(crate) fn client_early_traffic_secret( |
88 | &self, |
89 | hs_hash: &hash::Output, |
90 | key_log: &dyn KeyLog, |
91 | client_random: &[u8; 32], |
92 | common: &mut CommonState, |
93 | ) { |
94 | let client_early_traffic_secret = self.ks.derive_logged_secret( |
95 | SecretKind::ClientEarlyTrafficSecret, |
96 | hs_hash.as_ref(), |
97 | key_log, |
98 | client_random, |
99 | ); |
100 | |
101 | match common.side { |
102 | Side::Client => self |
103 | .ks |
104 | .set_encrypter(&client_early_traffic_secret, common), |
105 | Side::Server => self |
106 | .ks |
107 | .set_decrypter(&client_early_traffic_secret, common), |
108 | } |
109 | |
110 | if common.is_quic() { |
111 | // If 0-RTT should be rejected, this will be clobbered by ExtensionProcessing |
112 | // before the application can see. |
113 | common.quic.early_secret = Some(client_early_traffic_secret); |
114 | } |
115 | } |
116 | |
117 | pub(crate) fn resumption_psk_binder_key_and_sign_verify_data( |
118 | &self, |
119 | hs_hash: &hash::Output, |
120 | ) -> hmac::Tag { |
121 | let resumption_psk_binder_key = self |
122 | .ks |
123 | .derive_for_empty_hash(SecretKind::ResumptionPskBinderKey); |
124 | self.ks |
125 | .sign_verify_data(&resumption_psk_binder_key, hs_hash) |
126 | } |
127 | } |
128 | |
129 | /// Pre-handshake key schedule |
130 | /// |
131 | /// The inner `KeySchedule` is either constructed without any secrets based on ths HKDF algorithm |
132 | /// or is extracted from a `KeyScheduleEarly`. This can then be used to derive the `KeyScheduleHandshakeStart`. |
133 | pub(crate) struct KeySchedulePreHandshake { |
134 | ks: KeySchedule, |
135 | } |
136 | |
137 | impl KeySchedulePreHandshake { |
138 | pub(crate) fn new(suite: &'static Tls13CipherSuite) -> Self { |
139 | Self { |
140 | ks: KeySchedule::new_with_empty_secret(suite), |
141 | } |
142 | } |
143 | |
144 | pub(crate) fn into_handshake( |
145 | mut self, |
146 | kx: Box<dyn ActiveKeyExchange>, |
147 | peer_public_key: &[u8], |
148 | ) -> Result<KeyScheduleHandshakeStart, Error> { |
149 | self.ks |
150 | .input_from_key_exchange(kx, peer_public_key)?; |
151 | Ok(KeyScheduleHandshakeStart { ks: self.ks }) |
152 | } |
153 | } |
154 | |
155 | impl From<KeyScheduleEarly> for KeySchedulePreHandshake { |
156 | fn from(KeyScheduleEarly { ks: KeySchedule }: KeyScheduleEarly) -> Self { |
157 | Self { ks } |
158 | } |
159 | } |
160 | |
161 | /// KeySchedule during handshake. |
162 | pub(crate) struct KeyScheduleHandshakeStart { |
163 | ks: KeySchedule, |
164 | } |
165 | |
166 | impl KeyScheduleHandshakeStart { |
167 | pub(crate) fn derive_client_handshake_secrets( |
168 | mut self, |
169 | early_data_enabled: bool, |
170 | hs_hash: hash::Output, |
171 | suite: &'static Tls13CipherSuite, |
172 | key_log: &dyn KeyLog, |
173 | client_random: &[u8; 32], |
174 | common: &mut CommonState, |
175 | ) -> KeyScheduleHandshake { |
176 | debug_assert_eq!(common.side, Side::Client); |
177 | // Suite might have changed due to resumption |
178 | self.ks.suite = suite; |
179 | let new = self.into_handshake(hs_hash, key_log, client_random, common); |
180 | |
181 | // Decrypt with the peer's key, encrypt with our own key |
182 | new.ks |
183 | .set_decrypter(&new.server_handshake_traffic_secret, common); |
184 | |
185 | if !early_data_enabled { |
186 | // Set the client encryption key for handshakes if early data is not used |
187 | new.ks |
188 | .set_encrypter(&new.client_handshake_traffic_secret, common); |
189 | } |
190 | |
191 | new |
192 | } |
193 | |
194 | pub(crate) fn derive_server_handshake_secrets( |
195 | self, |
196 | hs_hash: hash::Output, |
197 | key_log: &dyn KeyLog, |
198 | client_random: &[u8; 32], |
199 | common: &mut CommonState, |
200 | ) -> KeyScheduleHandshake { |
201 | debug_assert_eq!(common.side, Side::Server); |
202 | let new = self.into_handshake(hs_hash, key_log, client_random, common); |
203 | |
204 | // Set up to encrypt with handshake secrets, but decrypt with early_data keys. |
205 | // If not doing early_data after all, this is corrected later to the handshake |
206 | // keys (now stored in key_schedule). |
207 | new.ks |
208 | .set_encrypter(&new.server_handshake_traffic_secret, common); |
209 | new |
210 | } |
211 | |
212 | fn into_handshake( |
213 | self, |
214 | hs_hash: hash::Output, |
215 | key_log: &dyn KeyLog, |
216 | client_random: &[u8; 32], |
217 | common: &mut CommonState, |
218 | ) -> KeyScheduleHandshake { |
219 | // Use an empty handshake hash for the initial handshake. |
220 | let client_secret = self.ks.derive_logged_secret( |
221 | SecretKind::ClientHandshakeTrafficSecret, |
222 | hs_hash.as_ref(), |
223 | key_log, |
224 | client_random, |
225 | ); |
226 | |
227 | let server_secret = self.ks.derive_logged_secret( |
228 | SecretKind::ServerHandshakeTrafficSecret, |
229 | hs_hash.as_ref(), |
230 | key_log, |
231 | client_random, |
232 | ); |
233 | |
234 | if common.is_quic() { |
235 | common.quic.hs_secrets = Some(quic::Secrets::new( |
236 | client_secret.clone(), |
237 | server_secret.clone(), |
238 | self.ks.suite, |
239 | self.ks.suite.quic.unwrap(), |
240 | common.side, |
241 | common.quic.version, |
242 | )); |
243 | } |
244 | |
245 | KeyScheduleHandshake { |
246 | ks: self.ks, |
247 | client_handshake_traffic_secret: client_secret, |
248 | server_handshake_traffic_secret: server_secret, |
249 | } |
250 | } |
251 | } |
252 | |
253 | pub(crate) struct KeyScheduleHandshake { |
254 | ks: KeySchedule, |
255 | client_handshake_traffic_secret: OkmBlock, |
256 | server_handshake_traffic_secret: OkmBlock, |
257 | } |
258 | |
259 | impl KeyScheduleHandshake { |
260 | pub(crate) fn sign_server_finish(&self, hs_hash: &hash::Output) -> hmac::Tag { |
261 | self.ks |
262 | .sign_finish(&self.server_handshake_traffic_secret, hs_hash) |
263 | } |
264 | |
265 | pub(crate) fn set_handshake_encrypter(&self, common: &mut CommonState) { |
266 | debug_assert_eq!(common.side, Side::Client); |
267 | self.ks |
268 | .set_encrypter(&self.client_handshake_traffic_secret, common); |
269 | } |
270 | |
271 | pub(crate) fn set_handshake_decrypter( |
272 | &self, |
273 | skip_requested: Option<usize>, |
274 | common: &mut CommonState, |
275 | ) { |
276 | debug_assert_eq!(common.side, Side::Server); |
277 | let secret = &self.client_handshake_traffic_secret; |
278 | match skip_requested { |
279 | None => self.ks.set_decrypter(secret, common), |
280 | Some(max_early_data_size) => common |
281 | .record_layer |
282 | .set_message_decrypter_with_trial_decryption( |
283 | self.ks |
284 | .derive_decrypter(&self.client_handshake_traffic_secret), |
285 | max_early_data_size, |
286 | ), |
287 | } |
288 | } |
289 | |
290 | pub(crate) fn into_traffic_with_client_finished_pending( |
291 | self, |
292 | hs_hash: hash::Output, |
293 | key_log: &dyn KeyLog, |
294 | client_random: &[u8; 32], |
295 | common: &mut CommonState, |
296 | ) -> KeyScheduleTrafficWithClientFinishedPending { |
297 | debug_assert_eq!(common.side, Side::Server); |
298 | |
299 | let traffic = KeyScheduleTraffic::new(self.ks, hs_hash, key_log, client_random); |
300 | let (_client_secret, server_secret) = ( |
301 | &traffic.current_client_traffic_secret, |
302 | &traffic.current_server_traffic_secret, |
303 | ); |
304 | |
305 | traffic |
306 | .ks |
307 | .set_encrypter(server_secret, common); |
308 | |
309 | if common.is_quic() { |
310 | common.quic.traffic_secrets = Some(quic::Secrets::new( |
311 | _client_secret.clone(), |
312 | server_secret.clone(), |
313 | traffic.ks.suite, |
314 | traffic.ks.suite.quic.unwrap(), |
315 | common.side, |
316 | common.quic.version, |
317 | )); |
318 | } |
319 | |
320 | KeyScheduleTrafficWithClientFinishedPending { |
321 | handshake_client_traffic_secret: self.client_handshake_traffic_secret, |
322 | traffic, |
323 | } |
324 | } |
325 | |
326 | pub(crate) fn into_pre_finished_client_traffic( |
327 | self, |
328 | pre_finished_hash: hash::Output, |
329 | handshake_hash: hash::Output, |
330 | key_log: &dyn KeyLog, |
331 | client_random: &[u8; 32], |
332 | ) -> (KeyScheduleClientBeforeFinished, hmac::Tag) { |
333 | let traffic = KeyScheduleTraffic::new(self.ks, pre_finished_hash, key_log, client_random); |
334 | let tag = traffic |
335 | .ks |
336 | .sign_finish(&self.client_handshake_traffic_secret, &handshake_hash); |
337 | (KeyScheduleClientBeforeFinished { traffic }, tag) |
338 | } |
339 | } |
340 | |
341 | pub(crate) struct KeyScheduleClientBeforeFinished { |
342 | traffic: KeyScheduleTraffic, |
343 | } |
344 | |
345 | impl KeyScheduleClientBeforeFinished { |
346 | pub(crate) fn into_traffic(self, common: &mut CommonState) -> KeyScheduleTraffic { |
347 | debug_assert_eq!(common.side, Side::Client); |
348 | let (client_secret, server_secret) = ( |
349 | &self |
350 | .traffic |
351 | .current_client_traffic_secret, |
352 | &self |
353 | .traffic |
354 | .current_server_traffic_secret, |
355 | ); |
356 | |
357 | self.traffic |
358 | .ks |
359 | .set_decrypter(server_secret, common); |
360 | self.traffic |
361 | .ks |
362 | .set_encrypter(client_secret, common); |
363 | |
364 | if common.is_quic() { |
365 | common.quic.traffic_secrets = Some(quic::Secrets::new( |
366 | client_secret.clone(), |
367 | server_secret.clone(), |
368 | self.traffic.ks.suite, |
369 | self.traffic.ks.suite.quic.unwrap(), |
370 | common.side, |
371 | common.quic.version, |
372 | )); |
373 | } |
374 | |
375 | self.traffic |
376 | } |
377 | } |
378 | |
379 | /// KeySchedule during traffic stage, retaining the ability to calculate the client's |
380 | /// finished verify_data. The traffic stage key schedule can be extracted from it |
381 | /// through signing the client finished hash. |
382 | pub(crate) struct KeyScheduleTrafficWithClientFinishedPending { |
383 | handshake_client_traffic_secret: OkmBlock, |
384 | traffic: KeyScheduleTraffic, |
385 | } |
386 | |
387 | impl KeyScheduleTrafficWithClientFinishedPending { |
388 | pub(crate) fn update_decrypter(&self, common: &mut CommonState) { |
389 | debug_assert_eq!(common.side, Side::Server); |
390 | self.traffic |
391 | .ks |
392 | .set_decrypter(&self.handshake_client_traffic_secret, common); |
393 | } |
394 | |
395 | pub(crate) fn sign_client_finish( |
396 | self, |
397 | hs_hash: &hash::Output, |
398 | common: &mut CommonState, |
399 | ) -> (KeyScheduleTraffic, hmac::Tag) { |
400 | debug_assert_eq!(common.side, Side::Server); |
401 | let tag = self |
402 | .traffic |
403 | .ks |
404 | .sign_finish(&self.handshake_client_traffic_secret, hs_hash); |
405 | |
406 | // Install keying to read future messages. |
407 | self.traffic.ks.set_decrypter( |
408 | &self |
409 | .traffic |
410 | .current_client_traffic_secret, |
411 | common, |
412 | ); |
413 | |
414 | (self.traffic, tag) |
415 | } |
416 | } |
417 | |
418 | /// KeySchedule during traffic stage. All traffic & exporter keys are guaranteed |
419 | /// to be available. |
420 | pub(crate) struct KeyScheduleTraffic { |
421 | ks: KeySchedule, |
422 | current_client_traffic_secret: OkmBlock, |
423 | current_server_traffic_secret: OkmBlock, |
424 | current_exporter_secret: OkmBlock, |
425 | } |
426 | |
427 | impl KeyScheduleTraffic { |
428 | fn new( |
429 | mut ks: KeySchedule, |
430 | hs_hash: hash::Output, |
431 | key_log: &dyn KeyLog, |
432 | client_random: &[u8; 32], |
433 | ) -> Self { |
434 | ks.input_empty(); |
435 | |
436 | let current_client_traffic_secret = ks.derive_logged_secret( |
437 | SecretKind::ClientApplicationTrafficSecret, |
438 | hs_hash.as_ref(), |
439 | key_log, |
440 | client_random, |
441 | ); |
442 | |
443 | let current_server_traffic_secret = ks.derive_logged_secret( |
444 | SecretKind::ServerApplicationTrafficSecret, |
445 | hs_hash.as_ref(), |
446 | key_log, |
447 | client_random, |
448 | ); |
449 | |
450 | let current_exporter_secret = ks.derive_logged_secret( |
451 | SecretKind::ExporterMasterSecret, |
452 | hs_hash.as_ref(), |
453 | key_log, |
454 | client_random, |
455 | ); |
456 | |
457 | Self { |
458 | ks, |
459 | current_client_traffic_secret, |
460 | current_server_traffic_secret, |
461 | current_exporter_secret, |
462 | } |
463 | } |
464 | |
465 | pub(crate) fn update_encrypter_and_notify(&mut self, common: &mut CommonState) { |
466 | let secret = self.next_application_traffic_secret(common.side); |
467 | common.enqueue_key_update_notification(); |
468 | self.ks.set_encrypter(&secret, common); |
469 | } |
470 | |
471 | pub(crate) fn update_decrypter(&mut self, common: &mut CommonState) { |
472 | let secret = self.next_application_traffic_secret(common.side.peer()); |
473 | self.ks.set_decrypter(&secret, common); |
474 | } |
475 | |
476 | pub(crate) fn next_application_traffic_secret(&mut self, side: Side) -> OkmBlock { |
477 | let current = match side { |
478 | Side::Client => &mut self.current_client_traffic_secret, |
479 | Side::Server => &mut self.current_server_traffic_secret, |
480 | }; |
481 | |
482 | let secret = self.ks.derive_next(current); |
483 | *current = secret.clone(); |
484 | secret |
485 | } |
486 | |
487 | pub(crate) fn resumption_master_secret_and_derive_ticket_psk( |
488 | &self, |
489 | hs_hash: &hash::Output, |
490 | nonce: &[u8], |
491 | ) -> OkmBlock { |
492 | let resumption_master_secret = self |
493 | .ks |
494 | .derive(SecretKind::ResumptionMasterSecret, hs_hash.as_ref()); |
495 | self.ks |
496 | .derive_ticket_psk(&resumption_master_secret, nonce) |
497 | } |
498 | |
499 | pub(crate) fn export_keying_material( |
500 | &self, |
501 | out: &mut [u8], |
502 | label: &[u8], |
503 | context: Option<&[u8]>, |
504 | ) -> Result<(), Error> { |
505 | self.ks |
506 | .export_keying_material(&self.current_exporter_secret, out, label, context) |
507 | } |
508 | |
509 | pub(crate) fn extract_secrets(&self, side: Side) -> Result<PartiallyExtractedSecrets, Error> { |
510 | fn expand( |
511 | secret: &OkmBlock, |
512 | hkdf: &'static dyn Hkdf, |
513 | aead_key_len: usize, |
514 | ) -> (AeadKey, Iv) { |
515 | let expander = hkdf.expander_for_okm(secret); |
516 | |
517 | ( |
518 | hkdf_expand_label_aead_key(expander.as_ref(), aead_key_len, b"key" , &[]), |
519 | hkdf_expand_label(expander.as_ref(), b"iv" , &[]), |
520 | ) |
521 | } |
522 | |
523 | let (client_key, client_iv) = expand( |
524 | &self.current_client_traffic_secret, |
525 | self.ks.suite.hkdf_provider, |
526 | self.ks.suite.aead_alg.key_len(), |
527 | ); |
528 | let (server_key, server_iv) = expand( |
529 | &self.current_server_traffic_secret, |
530 | self.ks.suite.hkdf_provider, |
531 | self.ks.suite.aead_alg.key_len(), |
532 | ); |
533 | let client_secrets = self |
534 | .ks |
535 | .suite |
536 | .aead_alg |
537 | .extract_keys(client_key, client_iv)?; |
538 | let server_secrets = self |
539 | .ks |
540 | .suite |
541 | .aead_alg |
542 | .extract_keys(server_key, server_iv)?; |
543 | |
544 | let (tx, rx) = match side { |
545 | Side::Client => (client_secrets, server_secrets), |
546 | Side::Server => (server_secrets, client_secrets), |
547 | }; |
548 | Ok(PartiallyExtractedSecrets { tx, rx }) |
549 | } |
550 | } |
551 | |
552 | impl KeySchedule { |
553 | fn new(suite: &'static Tls13CipherSuite, secret: &[u8]) -> Self { |
554 | Self { |
555 | current: suite |
556 | .hkdf_provider |
557 | .extract_from_secret(None, secret), |
558 | suite, |
559 | } |
560 | } |
561 | |
562 | fn set_encrypter(&self, secret: &OkmBlock, common: &mut CommonState) { |
563 | let expander = self |
564 | .suite |
565 | .hkdf_provider |
566 | .expander_for_okm(secret); |
567 | let key = derive_traffic_key(expander.as_ref(), self.suite.aead_alg.key_len()); |
568 | let iv = derive_traffic_iv(expander.as_ref()); |
569 | |
570 | common |
571 | .record_layer |
572 | .set_message_encrypter(self.suite.aead_alg.encrypter(key, iv)); |
573 | } |
574 | |
575 | fn set_decrypter(&self, secret: &OkmBlock, common: &mut CommonState) { |
576 | common |
577 | .record_layer |
578 | .set_message_decrypter(self.derive_decrypter(secret)); |
579 | } |
580 | |
581 | fn derive_decrypter(&self, secret: &OkmBlock) -> Box<dyn MessageDecrypter> { |
582 | let expander = self |
583 | .suite |
584 | .hkdf_provider |
585 | .expander_for_okm(secret); |
586 | let key = derive_traffic_key(expander.as_ref(), self.suite.aead_alg.key_len()); |
587 | let iv = derive_traffic_iv(expander.as_ref()); |
588 | self.suite.aead_alg.decrypter(key, iv) |
589 | } |
590 | |
591 | fn new_with_empty_secret(suite: &'static Tls13CipherSuite) -> Self { |
592 | Self { |
593 | current: suite |
594 | .hkdf_provider |
595 | .extract_from_zero_ikm(None), |
596 | suite, |
597 | } |
598 | } |
599 | |
600 | /// Input the empty secret. |
601 | fn input_empty(&mut self) { |
602 | let salt = self.derive_for_empty_hash(SecretKind::DerivedSecret); |
603 | self.current = self |
604 | .suite |
605 | .hkdf_provider |
606 | .extract_from_zero_ikm(Some(salt.as_ref())); |
607 | } |
608 | |
609 | /// Input the given secret. |
610 | #[cfg (all(test, any(feature = "ring" , feature = "aws_lc_rs" )))] |
611 | fn input_secret(&mut self, secret: &[u8]) { |
612 | let salt = self.derive_for_empty_hash(SecretKind::DerivedSecret); |
613 | self.current = self |
614 | .suite |
615 | .hkdf_provider |
616 | .extract_from_secret(Some(salt.as_ref()), secret); |
617 | } |
618 | |
619 | /// Input the shared secret resulting from completing the given key exchange. |
620 | fn input_from_key_exchange( |
621 | &mut self, |
622 | kx: Box<dyn ActiveKeyExchange>, |
623 | peer_public_key: &[u8], |
624 | ) -> Result<(), Error> { |
625 | let salt = self.derive_for_empty_hash(SecretKind::DerivedSecret); |
626 | self.current = self |
627 | .suite |
628 | .hkdf_provider |
629 | .extract_from_kx_shared_secret(Some(salt.as_ref()), kx, peer_public_key)?; |
630 | Ok(()) |
631 | } |
632 | |
633 | /// Derive a secret of given `kind`, using current handshake hash `hs_hash`. |
634 | fn derive(&self, kind: SecretKind, hs_hash: &[u8]) -> OkmBlock { |
635 | hkdf_expand_label_block(self.current.as_ref(), kind.to_bytes(), hs_hash) |
636 | } |
637 | |
638 | fn derive_logged_secret( |
639 | &self, |
640 | kind: SecretKind, |
641 | hs_hash: &[u8], |
642 | key_log: &dyn KeyLog, |
643 | client_random: &[u8; 32], |
644 | ) -> OkmBlock { |
645 | let output = self.derive(kind, hs_hash); |
646 | |
647 | let log_label = kind |
648 | .log_label() |
649 | .expect("not a loggable secret" ); |
650 | if key_log.will_log(log_label) { |
651 | key_log.log(log_label, client_random, output.as_ref()); |
652 | } |
653 | output |
654 | } |
655 | |
656 | /// Derive a secret of given `kind` using the hash of the empty string |
657 | /// for the handshake hash. Useful only for |
658 | /// `SecretKind::ResumptionPSKBinderKey` and |
659 | /// `SecretKind::DerivedSecret`. |
660 | fn derive_for_empty_hash(&self, kind: SecretKind) -> OkmBlock { |
661 | let empty_hash = self |
662 | .suite |
663 | .common |
664 | .hash_provider |
665 | .start() |
666 | .finish(); |
667 | self.derive(kind, empty_hash.as_ref()) |
668 | } |
669 | |
670 | /// Sign the finished message consisting of `hs_hash` using a current |
671 | /// traffic secret. |
672 | fn sign_finish(&self, base_key: &OkmBlock, hs_hash: &hash::Output) -> hmac::Tag { |
673 | self.sign_verify_data(base_key, hs_hash) |
674 | } |
675 | |
676 | /// Sign the finished message consisting of `hs_hash` using the key material |
677 | /// `base_key`. |
678 | fn sign_verify_data(&self, base_key: &OkmBlock, hs_hash: &hash::Output) -> hmac::Tag { |
679 | let expander = self |
680 | .suite |
681 | .hkdf_provider |
682 | .expander_for_okm(base_key); |
683 | let hmac_key = hkdf_expand_label_block(expander.as_ref(), b"finished" , &[]); |
684 | |
685 | self.suite |
686 | .hkdf_provider |
687 | .hmac_sign(&hmac_key, hs_hash.as_ref()) |
688 | } |
689 | |
690 | /// Derive the next application traffic secret, returning it. |
691 | fn derive_next(&self, base_key: &OkmBlock) -> OkmBlock { |
692 | let expander = self |
693 | .suite |
694 | .hkdf_provider |
695 | .expander_for_okm(base_key); |
696 | hkdf_expand_label_block(expander.as_ref(), b"traffic upd" , &[]) |
697 | } |
698 | |
699 | /// Derive the PSK to use given a resumption_master_secret and |
700 | /// ticket_nonce. |
701 | fn derive_ticket_psk(&self, rms: &OkmBlock, nonce: &[u8]) -> OkmBlock { |
702 | let expander = self |
703 | .suite |
704 | .hkdf_provider |
705 | .expander_for_okm(rms); |
706 | hkdf_expand_label_block(expander.as_ref(), b"resumption" , nonce) |
707 | } |
708 | |
709 | fn export_keying_material( |
710 | &self, |
711 | current_exporter_secret: &OkmBlock, |
712 | out: &mut [u8], |
713 | label: &[u8], |
714 | context: Option<&[u8]>, |
715 | ) -> Result<(), Error> { |
716 | let secret = { |
717 | let h_empty = self |
718 | .suite |
719 | .common |
720 | .hash_provider |
721 | .hash(&[]); |
722 | |
723 | let expander = self |
724 | .suite |
725 | .hkdf_provider |
726 | .expander_for_okm(current_exporter_secret); |
727 | hkdf_expand_label_block(expander.as_ref(), label, h_empty.as_ref()) |
728 | }; |
729 | |
730 | let h_context = self |
731 | .suite |
732 | .common |
733 | .hash_provider |
734 | .hash(context.unwrap_or(&[])); |
735 | |
736 | let expander = self |
737 | .suite |
738 | .hkdf_provider |
739 | .expander_for_okm(&secret); |
740 | hkdf_expand_label_slice(expander.as_ref(), b"exporter" , h_context.as_ref(), out) |
741 | .map_err(|_| Error::General("exporting too much" .to_string())) |
742 | } |
743 | } |
744 | |
745 | /// [HKDF-Expand-Label] where the output length is a compile-time constant, and therefore |
746 | /// it is infallible. |
747 | /// |
748 | /// [HKDF-Expand-Label]: <https://www.rfc-editor.org/rfc/rfc8446#section-7.1> |
749 | pub(crate) fn hkdf_expand_label<T: From<[u8; N]>, const N: usize>( |
750 | expander: &dyn HkdfExpander, |
751 | label: &[u8], |
752 | context: &[u8], |
753 | ) -> T { |
754 | hkdf_expand_label_inner(expander, label, context, N, |e: &dyn HkdfExpander, info: &[&[u8]]| expand(expander:e, info)) |
755 | } |
756 | |
757 | /// [HKDF-Expand-Label] where the output is one block in size. |
758 | pub(crate) fn hkdf_expand_label_block( |
759 | expander: &dyn HkdfExpander, |
760 | label: &[u8], |
761 | context: &[u8], |
762 | ) -> OkmBlock { |
763 | hkdf_expand_label_inner(expander, label, context, n:expander.hash_len(), |e: &dyn HkdfExpander, info: &[&[u8]]| { |
764 | e.expand_block(info) |
765 | }) |
766 | } |
767 | |
768 | /// [HKDF-Expand-Label] where the output is an AEAD key. |
769 | pub(crate) fn hkdf_expand_label_aead_key( |
770 | expander: &dyn HkdfExpander, |
771 | key_len: usize, |
772 | label: &[u8], |
773 | context: &[u8], |
774 | ) -> AeadKey { |
775 | hkdf_expand_label_inner(expander, label, context, n:key_len, |e: &dyn HkdfExpander, info: &[&[u8]]| { |
776 | let key: AeadKey = expand(expander:e, info); |
777 | key.with_length(key_len) |
778 | }) |
779 | } |
780 | |
781 | /// [HKDF-Expand-Label] where the output is a slice. |
782 | /// |
783 | /// This can fail because HKDF-Expand is limited in its maximum output length. |
784 | fn hkdf_expand_label_slice( |
785 | expander: &dyn HkdfExpander, |
786 | label: &[u8], |
787 | context: &[u8], |
788 | output: &mut [u8], |
789 | ) -> Result<(), OutputLengthError> { |
790 | hkdf_expand_label_inner(expander, label, context, n:output.len(), |e: &dyn HkdfExpander, info: &[&[u8]]| { |
791 | e.expand_slice(info, output) |
792 | }) |
793 | } |
794 | |
795 | pub(crate) fn derive_traffic_key(expander: &dyn HkdfExpander, aead_key_len: usize) -> AeadKey { |
796 | hkdf_expand_label_aead_key(expander, aead_key_len, label:b"key" , &[]) |
797 | } |
798 | |
799 | pub(crate) fn derive_traffic_iv(expander: &dyn HkdfExpander) -> Iv { |
800 | hkdf_expand_label(expander, label:b"iv" , &[]) |
801 | } |
802 | |
803 | fn hkdf_expand_label_inner<F, T>( |
804 | expander: &dyn HkdfExpander, |
805 | label: &[u8], |
806 | context: &[u8], |
807 | n: usize, |
808 | f: F, |
809 | ) -> T |
810 | where |
811 | F: FnOnce(&dyn HkdfExpander, &[&[u8]]) -> T, |
812 | { |
813 | const LABEL_PREFIX: &[u8] = b"tls13 " ; |
814 | |
815 | let output_len: [u8; 2] = u16::to_be_bytes(self:n as u16); |
816 | let label_len: [u8; 1] = u8::to_be_bytes((LABEL_PREFIX.len() + label.len()) as u8); |
817 | let context_len: [u8; 1] = u8::to_be_bytes(self:context.len() as u8); |
818 | |
819 | let info: &[&[u8]; 6] = &[ |
820 | &output_len[..], |
821 | &label_len[..], |
822 | LABEL_PREFIX, |
823 | label, |
824 | &context_len[..], |
825 | context, |
826 | ]; |
827 | |
828 | f(expander, info) |
829 | } |
830 | |
831 | #[cfg (all(test, any(feature = "ring" , feature = "aws_lc_rs" )))] |
832 | mod tests { |
833 | use core::fmt::Debug; |
834 | |
835 | use super::{derive_traffic_iv, derive_traffic_key, KeySchedule, SecretKind}; |
836 | use crate::test_provider::ring_like::aead; |
837 | use crate::test_provider::tls13::{ |
838 | TLS13_AES_128_GCM_SHA256_INTERNAL, TLS13_CHACHA20_POLY1305_SHA256_INTERNAL, |
839 | }; |
840 | use crate::KeyLog; |
841 | |
842 | #[test ] |
843 | fn test_vectors() { |
844 | /* These test vectors generated with OpenSSL. */ |
845 | let hs_start_hash = [ |
846 | 0xec, 0x14, 0x7a, 0x06, 0xde, 0xa3, 0xc8, 0x84, 0x6c, 0x02, 0xb2, 0x23, 0x8e, 0x41, |
847 | 0xbd, 0xdc, 0x9d, 0x89, 0xf9, 0xae, 0xa1, 0x7b, 0x5e, 0xfd, 0x4d, 0x74, 0x82, 0xaf, |
848 | 0x75, 0x88, 0x1c, 0x0a, |
849 | ]; |
850 | |
851 | let hs_full_hash = [ |
852 | 0x75, 0x1a, 0x3d, 0x4a, 0x14, 0xdf, 0xab, 0xeb, 0x68, 0xe9, 0x2c, 0xa5, 0x91, 0x8e, |
853 | 0x24, 0x08, 0xb9, 0xbc, 0xb0, 0x74, 0x89, 0x82, 0xec, 0x9c, 0x32, 0x30, 0xac, 0x30, |
854 | 0xbb, 0xeb, 0x23, 0xe2, |
855 | ]; |
856 | |
857 | let ecdhe_secret = [ |
858 | 0xe7, 0xb8, 0xfe, 0xf8, 0x90, 0x3b, 0x52, 0x0c, 0xb9, 0xa1, 0x89, 0x71, 0xb6, 0x9d, |
859 | 0xd4, 0x5d, 0xca, 0x53, 0xce, 0x2f, 0x12, 0xbf, 0x3b, 0xef, 0x93, 0x15, 0xe3, 0x12, |
860 | 0x71, 0xdf, 0x4b, 0x40, |
861 | ]; |
862 | |
863 | let client_hts = [ |
864 | 0x61, 0x7b, 0x35, 0x07, 0x6b, 0x9d, 0x0e, 0x08, 0xcf, 0x73, 0x1d, 0x94, 0xa8, 0x66, |
865 | 0x14, 0x78, 0x41, 0x09, 0xef, 0x25, 0x55, 0x51, 0x92, 0x1d, 0xd4, 0x6e, 0x04, 0x01, |
866 | 0x35, 0xcf, 0x46, 0xab, |
867 | ]; |
868 | |
869 | let client_hts_key = [ |
870 | 0x62, 0xd0, 0xdd, 0x00, 0xf6, 0x96, 0x19, 0xd3, 0xb8, 0x19, 0x3a, 0xb4, 0xa0, 0x95, |
871 | 0x85, 0xa7, |
872 | ]; |
873 | |
874 | let client_hts_iv = [ |
875 | 0xff, 0xf7, 0x5d, 0xf5, 0xad, 0x35, 0xd5, 0xcb, 0x3c, 0x53, 0xf3, 0xa9, |
876 | ]; |
877 | |
878 | let server_hts = [ |
879 | 0xfc, 0xf7, 0xdf, 0xe6, 0x4f, 0xa2, 0xc0, 0x4f, 0x62, 0x35, 0x38, 0x7f, 0x43, 0x4e, |
880 | 0x01, 0x42, 0x23, 0x36, 0xd9, 0xc0, 0x39, 0xde, 0x68, 0x47, 0xa0, 0xb9, 0xdd, 0xcf, |
881 | 0x29, 0xa8, 0x87, 0x59, |
882 | ]; |
883 | |
884 | let server_hts_key = [ |
885 | 0x04, 0x67, 0xf3, 0x16, 0xa8, 0x05, 0xb8, 0xc4, 0x97, 0xee, 0x67, 0x04, 0x7b, 0xbc, |
886 | 0xbc, 0x54, |
887 | ]; |
888 | |
889 | let server_hts_iv = [ |
890 | 0xde, 0x83, 0xa7, 0x3e, 0x9d, 0x81, 0x4b, 0x04, 0xc4, 0x8b, 0x78, 0x09, |
891 | ]; |
892 | |
893 | let client_ats = [ |
894 | 0xc1, 0x4a, 0x6d, 0x79, 0x76, 0xd8, 0x10, 0x2b, 0x5a, 0x0c, 0x99, 0x51, 0x49, 0x3f, |
895 | 0xee, 0x87, 0xdc, 0xaf, 0xf8, 0x2c, 0x24, 0xca, 0xb2, 0x14, 0xe8, 0xbe, 0x71, 0xa8, |
896 | 0x20, 0x6d, 0xbd, 0xa5, |
897 | ]; |
898 | |
899 | let client_ats_key = [ |
900 | 0xcc, 0x9f, 0x5f, 0x98, 0x0b, 0x5f, 0x10, 0x30, 0x6c, 0xba, 0xd7, 0xbe, 0x98, 0xd7, |
901 | 0x57, 0x2e, |
902 | ]; |
903 | |
904 | let client_ats_iv = [ |
905 | 0xb8, 0x09, 0x29, 0xe8, 0xd0, 0x2c, 0x70, 0xf6, 0x11, 0x62, 0xed, 0x6b, |
906 | ]; |
907 | |
908 | let server_ats = [ |
909 | 0x2c, 0x90, 0x77, 0x38, 0xd3, 0xf8, 0x37, 0x02, 0xd1, 0xe4, 0x59, 0x8f, 0x48, 0x48, |
910 | 0x53, 0x1d, 0x9f, 0x93, 0x65, 0x49, 0x1b, 0x9f, 0x7f, 0x52, 0xc8, 0x22, 0x29, 0x0d, |
911 | 0x4c, 0x23, 0x21, 0x92, |
912 | ]; |
913 | |
914 | let server_ats_key = [ |
915 | 0x0c, 0xb2, 0x95, 0x62, 0xd8, 0xd8, 0x8f, 0x48, 0xb0, 0x2c, 0xbf, 0xbe, 0xd7, 0xe6, |
916 | 0x2b, 0xb3, |
917 | ]; |
918 | |
919 | let server_ats_iv = [ |
920 | 0x0d, 0xb2, 0x8f, 0x98, 0x85, 0x86, 0xa1, 0xb7, 0xe4, 0xd5, 0xc6, 0x9c, |
921 | ]; |
922 | |
923 | let mut ks = KeySchedule::new_with_empty_secret(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL); |
924 | ks.input_secret(&ecdhe_secret); |
925 | |
926 | assert_traffic_secret( |
927 | &ks, |
928 | SecretKind::ClientHandshakeTrafficSecret, |
929 | &hs_start_hash, |
930 | &client_hts, |
931 | &client_hts_key, |
932 | &client_hts_iv, |
933 | ); |
934 | |
935 | assert_traffic_secret( |
936 | &ks, |
937 | SecretKind::ServerHandshakeTrafficSecret, |
938 | &hs_start_hash, |
939 | &server_hts, |
940 | &server_hts_key, |
941 | &server_hts_iv, |
942 | ); |
943 | |
944 | ks.input_empty(); |
945 | |
946 | assert_traffic_secret( |
947 | &ks, |
948 | SecretKind::ClientApplicationTrafficSecret, |
949 | &hs_full_hash, |
950 | &client_ats, |
951 | &client_ats_key, |
952 | &client_ats_iv, |
953 | ); |
954 | |
955 | assert_traffic_secret( |
956 | &ks, |
957 | SecretKind::ServerApplicationTrafficSecret, |
958 | &hs_full_hash, |
959 | &server_ats, |
960 | &server_ats_key, |
961 | &server_ats_iv, |
962 | ); |
963 | } |
964 | |
965 | fn assert_traffic_secret( |
966 | ks: &KeySchedule, |
967 | kind: SecretKind, |
968 | hash: &[u8], |
969 | expected_traffic_secret: &[u8], |
970 | expected_key: &[u8], |
971 | expected_iv: &[u8], |
972 | ) { |
973 | #[derive (Debug)] |
974 | struct Log<'a>(&'a [u8]); |
975 | impl KeyLog for Log<'_> { |
976 | fn log(&self, _label: &str, _client_random: &[u8], secret: &[u8]) { |
977 | assert_eq!(self.0, secret); |
978 | } |
979 | } |
980 | let log = Log(expected_traffic_secret); |
981 | let traffic_secret = ks.derive_logged_secret(kind, hash, &log, &[0; 32]); |
982 | |
983 | // Since we can't test key equality, we test the output of sealing with the key instead. |
984 | let aead_alg = &aead::AES_128_GCM; |
985 | let expander = TLS13_AES_128_GCM_SHA256_INTERNAL |
986 | .hkdf_provider |
987 | .expander_for_okm(&traffic_secret); |
988 | let key = derive_traffic_key(expander.as_ref(), aead_alg.key_len()); |
989 | let key = aead::UnboundKey::new(aead_alg, key.as_ref()).unwrap(); |
990 | let seal_output = seal_zeroes(key); |
991 | let expected_key = aead::UnboundKey::new(aead_alg, expected_key).unwrap(); |
992 | let expected_seal_output = seal_zeroes(expected_key); |
993 | assert_eq!(seal_output, expected_seal_output); |
994 | assert!(seal_output.len() >= 48); // Sanity check. |
995 | |
996 | let iv = derive_traffic_iv(expander.as_ref()); |
997 | assert_eq!(iv.as_ref(), expected_iv); |
998 | } |
999 | |
1000 | fn seal_zeroes(key: aead::UnboundKey) -> Vec<u8> { |
1001 | let key = aead::LessSafeKey::new(key); |
1002 | let mut seal_output = vec![0; 32]; |
1003 | key.seal_in_place_append_tag( |
1004 | aead::Nonce::assume_unique_for_key([0; aead::NONCE_LEN]), |
1005 | aead::Aad::empty(), |
1006 | &mut seal_output, |
1007 | ) |
1008 | .unwrap(); |
1009 | seal_output |
1010 | } |
1011 | } |
1012 | |
1013 | #[cfg (bench)] |
1014 | mod benchmarks { |
1015 | #[cfg (any(feature = "ring" , feature = "aws_lc_rs" ))] |
1016 | #[bench ] |
1017 | fn bench_sha256(b: &mut test::Bencher) { |
1018 | use core::fmt::Debug; |
1019 | |
1020 | use super::{derive_traffic_iv, derive_traffic_key, KeySchedule, SecretKind}; |
1021 | use crate::test_provider::tls13::TLS13_CHACHA20_POLY1305_SHA256_INTERNAL; |
1022 | use crate::KeyLog; |
1023 | |
1024 | fn extract_traffic_secret(ks: &KeySchedule, kind: SecretKind) { |
1025 | #[derive (Debug)] |
1026 | struct Log; |
1027 | |
1028 | impl KeyLog for Log { |
1029 | fn log(&self, _label: &str, _client_random: &[u8], _secret: &[u8]) {} |
1030 | } |
1031 | |
1032 | let hash = [0u8; 32]; |
1033 | let traffic_secret = ks.derive_logged_secret(kind, &hash, &Log, &[0u8; 32]); |
1034 | let traffic_secret_expander = TLS13_CHACHA20_POLY1305_SHA256_INTERNAL |
1035 | .hkdf_provider |
1036 | .expander_for_okm(&traffic_secret); |
1037 | test::black_box(derive_traffic_key( |
1038 | traffic_secret_expander.as_ref(), |
1039 | TLS13_CHACHA20_POLY1305_SHA256_INTERNAL |
1040 | .aead_alg |
1041 | .key_len(), |
1042 | )); |
1043 | test::black_box(derive_traffic_iv(traffic_secret_expander.as_ref())); |
1044 | } |
1045 | |
1046 | b.iter(|| { |
1047 | let mut ks = |
1048 | KeySchedule::new_with_empty_secret(TLS13_CHACHA20_POLY1305_SHA256_INTERNAL); |
1049 | ks.input_secret(&[0u8; 32]); |
1050 | |
1051 | extract_traffic_secret(&ks, SecretKind::ClientHandshakeTrafficSecret); |
1052 | extract_traffic_secret(&ks, SecretKind::ServerHandshakeTrafficSecret); |
1053 | |
1054 | ks.input_empty(); |
1055 | |
1056 | extract_traffic_secret(&ks, SecretKind::ClientApplicationTrafficSecret); |
1057 | extract_traffic_secret(&ks, SecretKind::ServerApplicationTrafficSecret); |
1058 | }); |
1059 | } |
1060 | } |
1061 | |