1use alloc::boxed::Box;
2use alloc::vec::Vec;
3use core::ops::{Deref, DerefMut};
4use core::{fmt, mem};
5
6use pki_types::{DnsName, FipsStatus, ServerName};
7
8use crate::TlsInputBuffer;
9use crate::client::{ClientConfig, ClientSide};
10pub use crate::common_state::Side;
11use crate::common_state::{CommonState, ConnectionOutputs, Protocol};
12use crate::conn::{ConnectionCore, KeyingMaterialExporter, MessageIter, SideData, StateMachine};
13use crate::crypto::cipher::{AeadKey, Iv, Payload};
14use crate::crypto::tls13::{Hkdf, HkdfExpander, OkmBlock};
15use crate::enums::ApplicationProtocol;
16use crate::error::{ApiMisuse, Error};
17use crate::msgs::{
18 ClientExtensionsInput, Message, MessagePayload, ServerExtensionsInput, TransportParameters,
19};
20use crate::server::{ChooseConfig, ClientHello, ServerConfig, ServerSide, ServerState};
21use crate::suites::SupportedCipherSuite;
22use crate::sync::Arc;
23use crate::tls13::Tls13CipherSuite;
24use crate::tls13::key_schedule::{
25 hkdf_expand_label, hkdf_expand_label_aead_key, hkdf_expand_label_block,
26};
27
28pub trait Connection: fmt::Debug + Deref<Target = ConnectionOutputs> {
30 fn quic_transport_parameters(&self) -> Option<&[u8]>;
38
39 fn zero_rtt_keys(&self) -> Option<DirectionalKeys>;
41
42 fn read_hs(&mut self, input: &mut dyn TlsInputBuffer) -> Result<(), Error>;
49
50 fn events(&mut self) -> impl Iterator<Item = QuicEvent>;
54
55 fn is_handshaking(&self) -> bool;
57}
58
59pub struct ClientConnection {
61 inner: ConnectionCommon<ClientSide>,
62}
63
64impl ClientConnection {
65 pub fn new(
70 config: Arc<ClientConfig>,
71 quic_version: Version,
72 name: ServerName<'static>,
73 params: Vec<u8>,
74 ) -> Result<Self, Error> {
75 let alpn_protocols = config.alpn_protocols.clone();
76 Self::new_with_alpn(config, quic_version, name, params, alpn_protocols)
77 }
78
79 pub fn new_with_alpn(
81 config: Arc<ClientConfig>,
82 version: Version,
83 name: ServerName<'static>,
84 params: Vec<u8>,
85 alpn_protocols: Vec<ApplicationProtocol<'static>>,
86 ) -> Result<Self, Error> {
87 let suites = &config.provider().tls13_cipher_suites;
88 if suites.is_empty() {
89 return Err(ApiMisuse::QuicRequiresTls13Support.into());
90 }
91
92 if !suites
93 .iter()
94 .any(|scs| scs.quic.is_some())
95 {
96 return Err(ApiMisuse::NoQuicCompatibleCipherSuites.into());
97 }
98
99 let exts = ClientExtensionsInput {
100 transport_parameters: Some(match version {
101 Version::V1 | Version::V2 => TransportParameters::Quic(Payload::new(params)),
102 }),
103
104 ..ClientExtensionsInput::from_alpn(alpn_protocols)
105 };
106
107 let mut quic = Quic {
108 version,
109 ..Quic::default()
110 };
111
112 let inner = ConnectionCore::for_client(
113 config,
114 name,
115 exts,
116 Some(&mut quic),
117 Protocol::Quic(version),
118 )?;
119
120 Ok(Self {
121 inner: ConnectionCommon::new(inner, quic),
122 })
123 }
124
125 pub fn fips(&self) -> FipsStatus {
127 self.inner.fips
128 }
129
130 pub fn is_early_data_accepted(&self) -> bool {
136 self.inner.core.is_early_data_accepted()
137 }
138
139 pub fn tls13_tickets_received(&self) -> u32 {
141 self.inner
142 .core
143 .common
144 .recv
145 .tls13_tickets_received
146 }
147
148 pub fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
162 self.inner.core.exporter()
163 }
164}
165
166impl Connection for ClientConnection {
167 fn quic_transport_parameters(&self) -> Option<&[u8]> {
168 self.inner.quic_transport_parameters()
169 }
170
171 fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
172 self.inner.zero_rtt_keys()
173 }
174
175 fn read_hs(&mut self, input: &mut dyn TlsInputBuffer) -> Result<(), Error> {
176 self.inner.read_hs(input)
177 }
178
179 fn events(&mut self) -> impl Iterator<Item = QuicEvent> {
180 self.inner.events()
181 }
182
183 fn is_handshaking(&self) -> bool {
184 self.inner.is_handshaking()
185 }
186}
187
188impl Deref for ClientConnection {
189 type Target = ConnectionOutputs;
190
191 fn deref(&self) -> &Self::Target {
192 &self.inner
193 }
194}
195
196impl fmt::Debug for ClientConnection {
197 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
198 f.debug_struct("quic::ClientConnection")
199 .finish_non_exhaustive()
200 }
201}
202
203pub struct ServerConnection {
205 inner: ConnectionCommon<ServerSide>,
206}
207
208impl ServerConnection {
209 pub fn new(
214 config: Arc<ServerConfig>,
215 version: Version,
216 params: Vec<u8>,
217 ) -> Result<Self, Error> {
218 check_server_config(&config)?;
219 let exts = ServerExtensionsInput {
220 transport_parameters: Some(match version {
221 Version::V1 | Version::V2 => TransportParameters::Quic(Payload::new(params)),
222 }),
223 };
224
225 let core = ConnectionCore::for_server(config, exts, Protocol::Quic(version))?;
226 let inner = ConnectionCommon::new(
227 core,
228 Quic {
229 version,
230 ..Quic::default()
231 },
232 );
233 Ok(Self { inner })
234 }
235
236 pub fn fips(&self) -> FipsStatus {
238 self.inner.fips
239 }
240
241 pub fn server_name(&self) -> Option<&DnsName<'_>> {
257 self.inner.core.side.server_name()
258 }
259
260 pub fn set_resumption_data(&mut self, resumption_data: &[u8]) -> Result<(), Error> {
269 assert!(resumption_data.len() < 2usize.pow(15));
270 match &mut self.inner.core.state {
271 Ok(st) => st.set_resumption_data(resumption_data),
272 Err(e) => Err(e.clone()),
273 }
274 }
275
276 pub fn received_resumption_data(&self) -> Option<&[u8]> {
280 self.inner
281 .core
282 .side
283 .received_resumption_data()
284 }
285
286 pub fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
300 self.inner.core.exporter()
301 }
302}
303
304impl Connection for ServerConnection {
305 fn quic_transport_parameters(&self) -> Option<&[u8]> {
306 self.inner.quic_transport_parameters()
307 }
308
309 fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
310 self.inner.zero_rtt_keys()
311 }
312
313 fn read_hs(&mut self, input: &mut dyn TlsInputBuffer) -> Result<(), Error> {
314 self.inner.read_hs(input)
315 }
316
317 fn events(&mut self) -> impl Iterator<Item = QuicEvent> {
318 self.inner.events()
319 }
320
321 fn is_handshaking(&self) -> bool {
322 self.inner.is_handshaking()
323 }
324}
325
326impl Deref for ServerConnection {
327 type Target = ConnectionOutputs;
328
329 fn deref(&self) -> &Self::Target {
330 &self.inner
331 }
332}
333
334impl fmt::Debug for ServerConnection {
335 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
336 f.debug_struct("quic::ServerConnection")
337 .finish_non_exhaustive()
338 }
339}
340
341#[non_exhaustive]
343#[derive(Debug)]
344pub enum ServerHandshake {
345 NeedsInput(NeedsInput),
347
348 Accepted(Accepted),
353
354 Complete(ServerConnection),
356}
357
358impl ServerHandshake {
359 pub fn start(version: Version) -> NeedsInput {
369 NeedsInput {
370 inner: ConnectionCommon::new(
371 ConnectionCore::for_acceptor(Protocol::Quic(version)),
372 Quic {
373 version,
374 ..Quic::default()
375 },
376 ),
377 }
378 }
379}
380
381impl TryFrom<ConnectionCommon<ServerSide>> for ServerHandshake {
382 type Error = Error;
383
384 fn try_from(mut inner: ConnectionCommon<ServerSide>) -> Result<Self, Error> {
385 const MISUSED: Error = Error::Unreachable("forgot to restore state");
386
387 Ok(match mem::replace(&mut inner.core.state, Err(MISUSED))? {
388 ServerState::ChooseConfig(choose_config) => Self::Accepted(Accepted {
389 inner,
390 choose_config,
391 }),
392
393 state if state.is_traffic() => {
394 inner.core.state = Ok(state);
395 Self::Complete(ServerConnection { inner })
396 }
397
398 state => {
399 inner.core.state = Ok(state);
400 Self::NeedsInput(NeedsInput { inner })
401 }
402 })
403 }
404}
405
406pub struct NeedsInput {
410 inner: ConnectionCommon<ServerSide>,
411}
412
413impl NeedsInput {
414 pub fn process(
435 mut self,
436 input: &mut dyn TlsInputBuffer,
437 output: &mut Vec<QuicEvent>,
438 ) -> Result<ServerHandshake, Error> {
439 self.inner.read_hs(input)?;
440 output.extend(self.inner.events());
441 ServerHandshake::try_from(self.inner)
442 }
443}
444
445impl fmt::Debug for NeedsInput {
446 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
447 f.debug_struct("quic::NeedsInput")
448 .finish_non_exhaustive()
449 }
450}
451
452pub struct Accepted {
457 inner: ConnectionCommon<ServerSide>,
459 choose_config: Box<ChooseConfig>,
460}
461
462impl Accepted {
463 pub fn client_hello(&self) -> ClientHello<'_> {
465 self.choose_config.client_hello()
466 }
467
468 pub fn choose_config(
478 mut self,
479 config: Arc<ServerConfig>,
480 params: Vec<u8>,
481 output: &mut Vec<QuicEvent>,
482 ) -> Result<ServerHandshake, Error> {
483 check_server_config(&config)?;
484
485 self.inner.core.accepted(
486 self.choose_config,
487 ServerExtensionsInput {
488 transport_parameters: Some(match self.inner.quic.version {
489 Version::V1 | Version::V2 => TransportParameters::Quic(Payload::new(params)),
490 }),
491 },
492 Some(&mut self.inner.quic),
493 config,
494 )?;
495
496 output.extend(self.inner.events());
497
498 ServerHandshake::try_from(self.inner)
499 }
500}
501
502impl fmt::Debug for Accepted {
503 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
504 f.debug_struct("quic::Accepted")
505 .finish_non_exhaustive()
506 }
507}
508
509fn check_server_config(config: &ServerConfig) -> Result<(), Error> {
510 let suites = &config.provider.tls13_cipher_suites;
511 if suites.is_empty() {
512 return Err(ApiMisuse::QuicRequiresTls13Support.into());
513 }
514
515 if !suites
516 .iter()
517 .any(|scs| scs.quic.is_some())
518 {
519 return Err(ApiMisuse::NoQuicCompatibleCipherSuites.into());
520 }
521
522 if config.max_early_data_size != 0 && config.max_early_data_size != 0xffff_ffff {
523 return Err(ApiMisuse::QuicRestrictsMaxEarlyDataSize.into());
524 }
525
526 Ok(())
527}
528
529#[expect(clippy::large_enum_variant)]
531#[derive(Debug)]
532#[non_exhaustive]
533pub enum QuicEvent {
534 Message(Vec<u8>),
536
537 KeyChange(KeyChange),
539}
540
541struct ConnectionCommon<Side: SideData> {
543 core: ConnectionCore<Side>,
544 quic: Quic,
545}
546
547impl<Side: SideData> ConnectionCommon<Side> {
548 fn new(core: ConnectionCore<Side>, quic: Quic) -> Self {
549 Self { core, quic }
550 }
551
552 fn quic_transport_parameters(&self) -> Option<&[u8]> {
553 self.quic
554 .params
555 .as_ref()
556 .map(|v| v.as_ref())
557 }
558
559 fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
560 let suite = self
561 .core
562 .common
563 .negotiated_cipher_suite()
564 .and_then(|suite| match suite {
565 SupportedCipherSuite::Tls13(suite) => Some(suite),
566 _ => None,
567 })?;
568
569 Some(DirectionalKeys::new(
570 suite,
571 suite.quic?,
572 self.quic.early_secret.as_ref()?,
573 self.quic.version,
574 ))
575 }
576
577 fn read_hs(&mut self, input: &mut dyn TlsInputBuffer) -> Result<(), Error> {
578 self.core
579 .common
580 .recv
581 .deframer
582 .input_quic(input.slice_mut())?;
583
584 let mut iter = MessageIter::new(input, Some(&mut self.quic), &mut self.core);
585 let result = match iter.next() {
586 Some(Ok(_)) | None => Ok(()),
587 Some(Err(e)) => Err(e),
588 };
589
590 input.discard(
591 self.core
592 .common
593 .recv
594 .deframer
595 .take_discard(),
596 );
597
598 result
599 }
600
601 fn events(&mut self) -> impl Iterator<Item = QuicEvent> {
602 self.quic.events()
603 }
604}
605
606impl<Side: SideData> Deref for ConnectionCommon<Side> {
607 type Target = CommonState;
608
609 fn deref(&self) -> &Self::Target {
610 &self.core.common
611 }
612}
613
614impl<Side: SideData> DerefMut for ConnectionCommon<Side> {
615 fn deref_mut(&mut self) -> &mut Self::Target {
616 &mut self.core.common
617 }
618}
619
620#[derive(Default)]
621pub(crate) struct Quic {
622 pub(crate) version: Version,
623 pub(crate) params: Option<Vec<u8>>,
625 pub(crate) events: Vec<QuicEvent>,
626 pub(crate) early_secret: Option<OkmBlock>,
627}
628
629impl Quic {
630 pub(crate) fn send_msg(&mut self, m: Message<'_>, _must_encrypt: bool) {
631 if let MessagePayload::Alert(_) = m.payload {
632 return;
634 }
635
636 debug_assert!(
637 matches!(
638 m.payload,
639 MessagePayload::Handshake { .. } | MessagePayload::HandshakeFlight(_)
640 ),
641 "QUIC uses TLS for the cryptographic handshake only"
642 );
643 let mut bytes = Vec::new();
644 m.payload.encode(&mut bytes);
645 self.events
646 .push(QuicEvent::Message(bytes));
647 }
648
649 pub(crate) fn events(&mut self) -> impl Iterator<Item = QuicEvent> {
650 mem::take(&mut self.events).into_iter()
651 }
652}
653
654impl QuicOutput for Quic {
655 fn transport_parameters(&mut self, params: Vec<u8>) {
656 self.params = Some(params);
657 }
658
659 fn early_secret(&mut self, secret: Option<OkmBlock>) {
660 self.early_secret = secret;
661 }
662
663 fn handshake_secrets(
664 &mut self,
665 client_secret: OkmBlock,
666 server_secret: OkmBlock,
667 suite: &'static Tls13CipherSuite,
668 quic: &'static dyn Algorithm,
669 side: Side,
670 ) {
671 self.events
672 .push(QuicEvent::KeyChange(KeyChange::Handshake {
673 keys: Keys::new(&Secrets::new(
674 client_secret,
675 server_secret,
676 suite,
677 quic,
678 side,
679 self.version,
680 )),
681 }));
682 }
683
684 fn traffic_secrets(
685 &mut self,
686 client_secret: OkmBlock,
687 server_secret: OkmBlock,
688 suite: &'static Tls13CipherSuite,
689 quic: &'static dyn Algorithm,
690 side: Side,
691 ) {
692 let mut secrets = Secrets::new(
693 client_secret,
694 server_secret,
695 suite,
696 quic,
697 side,
698 self.version,
699 );
700 let keys = Keys::new(&secrets);
701 secrets.update();
702 self.events
703 .push(QuicEvent::KeyChange(KeyChange::OneRtt {
704 keys,
705 next: secrets,
706 }));
707 }
708
709 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool) {
710 self.send_msg(m, must_encrypt);
711 }
712}
713
714pub(crate) trait QuicOutput {
715 fn transport_parameters(&mut self, params: Vec<u8>);
716
717 fn early_secret(&mut self, secret: Option<OkmBlock>);
718
719 fn handshake_secrets(
720 &mut self,
721 client_secret: OkmBlock,
722 server_secret: OkmBlock,
723 suite: &'static Tls13CipherSuite,
724 quic: &'static dyn Algorithm,
725 side: Side,
726 );
727
728 fn traffic_secrets(
729 &mut self,
730 client_secret: OkmBlock,
731 server_secret: OkmBlock,
732 suite: &'static Tls13CipherSuite,
733 quic: &'static dyn Algorithm,
734 side: Side,
735 );
736
737 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool);
738}
739
740#[derive(Clone)]
742pub struct Secrets {
743 pub(crate) client: OkmBlock,
745 pub(crate) server: OkmBlock,
747 suite: &'static Tls13CipherSuite,
749 quic: &'static dyn Algorithm,
750 side: Side,
751 version: Version,
752}
753
754impl Secrets {
755 pub(crate) fn new(
756 client: OkmBlock,
757 server: OkmBlock,
758 suite: &'static Tls13CipherSuite,
759 quic: &'static dyn Algorithm,
760 side: Side,
761 version: Version,
762 ) -> Self {
763 Self {
764 client,
765 server,
766 suite,
767 quic,
768 side,
769 version,
770 }
771 }
772
773 pub fn next_packet_keys(&mut self) -> PacketKeySet {
775 let keys = PacketKeySet::new(self);
776 self.update();
777 keys
778 }
779
780 pub(crate) fn update(&mut self) {
781 self.client = hkdf_expand_label_block(
782 self.suite
783 .hkdf_provider
784 .expander_for_okm(&self.client)
785 .as_ref(),
786 self.version.key_update_label(),
787 &[],
788 );
789 self.server = hkdf_expand_label_block(
790 self.suite
791 .hkdf_provider
792 .expander_for_okm(&self.server)
793 .as_ref(),
794 self.version.key_update_label(),
795 &[],
796 );
797 }
798
799 fn local_remote(&self) -> (&OkmBlock, &OkmBlock) {
800 match self.side {
801 Side::Client => (&self.client, &self.server),
802 Side::Server => (&self.server, &self.client),
803 }
804 }
805}
806
807#[expect(clippy::exhaustive_structs)]
809pub struct DirectionalKeys {
810 pub header: Box<dyn HeaderProtectionKey>,
812 pub packet: Box<dyn PacketKey>,
814}
815
816impl DirectionalKeys {
817 pub(crate) fn new(
818 suite: &'static Tls13CipherSuite,
819 quic: &'static dyn Algorithm,
820 secret: &OkmBlock,
821 version: Version,
822 ) -> Self {
823 let builder = KeyBuilder::new(secret, version, quic, suite.hkdf_provider);
824 Self {
825 header: builder.header_protection_key(),
826 packet: builder.packet_key(),
827 }
828 }
829}
830
831const TAG_LEN: usize = 16;
833
834pub struct Tag([u8; TAG_LEN]);
836
837impl From<&[u8]> for Tag {
838 fn from(value: &[u8]) -> Self {
839 let mut array = [0u8; TAG_LEN];
840 array.copy_from_slice(value);
841 Self(array)
842 }
843}
844
845impl AsRef<[u8]> for Tag {
846 fn as_ref(&self) -> &[u8] {
847 &self.0
848 }
849}
850
851pub trait Algorithm: Send + Sync {
853 fn packet_key(&self, key: AeadKey, iv: Iv) -> Box<dyn PacketKey>;
858
859 fn header_protection_key(&self, key: AeadKey) -> Box<dyn HeaderProtectionKey>;
863
864 fn aead_key_len(&self) -> usize;
868
869 fn fips(&self) -> FipsStatus {
871 FipsStatus::Unvalidated
872 }
873}
874
875pub trait HeaderProtectionKey: Send + Sync {
877 fn encrypt_in_place(
898 &self,
899 sample: &[u8],
900 first: &mut u8,
901 packet_number: &mut [u8],
902 ) -> Result<(), Error>;
903
904 fn decrypt_in_place(
926 &self,
927 sample: &[u8],
928 first: &mut u8,
929 packet_number: &mut [u8],
930 ) -> Result<(), Error>;
931
932 fn sample_len(&self) -> usize;
934}
935
936pub trait PacketKey: Send + Sync {
938 fn encrypt_in_place(
949 &self,
950 packet_number: u64,
951 header: &[u8],
952 payload: &mut [u8],
953 path_id: Option<u32>,
954 ) -> Result<Tag, Error>;
955
956 fn decrypt_in_place<'a>(
967 &self,
968 packet_number: u64,
969 header: &[u8],
970 payload: &'a mut [u8],
971 path_id: Option<u32>,
972 ) -> Result<&'a [u8], Error>;
973
974 fn tag_len(&self) -> usize;
976
977 fn confidentiality_limit(&self) -> u64;
988
989 fn integrity_limit(&self) -> u64;
998}
999
1000#[expect(clippy::exhaustive_structs)]
1002pub struct PacketKeySet {
1003 pub local: Box<dyn PacketKey>,
1005 pub remote: Box<dyn PacketKey>,
1007}
1008
1009impl PacketKeySet {
1010 fn new(secrets: &Secrets) -> Self {
1011 let (local, remote) = secrets.local_remote();
1012 let (version, alg, hkdf) = (secrets.version, secrets.quic, secrets.suite.hkdf_provider);
1013 Self {
1014 local: KeyBuilder::new(local, version, alg, hkdf).packet_key(),
1015 remote: KeyBuilder::new(remote, version, alg, hkdf).packet_key(),
1016 }
1017 }
1018}
1019
1020pub struct KeyBuilder<'a> {
1022 expander: Box<dyn HkdfExpander>,
1023 version: Version,
1024 alg: &'a dyn Algorithm,
1025}
1026
1027impl<'a> KeyBuilder<'a> {
1028 pub fn new(
1030 secret: &OkmBlock,
1031 version: Version,
1032 alg: &'a dyn Algorithm,
1033 hkdf: &'a dyn Hkdf,
1034 ) -> Self {
1035 Self {
1036 expander: hkdf.expander_for_okm(secret),
1037 version,
1038 alg,
1039 }
1040 }
1041
1042 pub fn packet_key(&self) -> Box<dyn PacketKey> {
1044 let aead_key_len = self.alg.aead_key_len();
1045 let packet_key = hkdf_expand_label_aead_key(
1046 self.expander.as_ref(),
1047 aead_key_len,
1048 self.version.packet_key_label(),
1049 &[],
1050 );
1051
1052 let packet_iv =
1053 hkdf_expand_label(self.expander.as_ref(), self.version.packet_iv_label(), &[]);
1054 self.alg
1055 .packet_key(packet_key, packet_iv)
1056 }
1057
1058 pub fn header_protection_key(&self) -> Box<dyn HeaderProtectionKey> {
1060 let header_key = hkdf_expand_label_aead_key(
1061 self.expander.as_ref(),
1062 self.alg.aead_key_len(),
1063 self.version.header_key_label(),
1064 &[],
1065 );
1066 self.alg
1067 .header_protection_key(header_key)
1068 }
1069}
1070
1071#[non_exhaustive]
1073#[derive(Clone, Copy)]
1074pub struct Suite {
1075 pub suite: &'static Tls13CipherSuite,
1077 pub quic: &'static dyn Algorithm,
1079}
1080
1081impl Suite {
1082 pub fn keys(&self, client_dst_connection_id: &[u8], side: Side, version: Version) -> Keys {
1084 Keys::initial(
1085 version,
1086 self.suite,
1087 self.quic,
1088 client_dst_connection_id,
1089 side,
1090 )
1091 }
1092}
1093
1094#[expect(clippy::exhaustive_structs)]
1096pub struct Keys {
1097 pub local: DirectionalKeys,
1099 pub remote: DirectionalKeys,
1101}
1102
1103impl Keys {
1104 pub fn initial(
1106 version: Version,
1107 suite: &'static Tls13CipherSuite,
1108 quic: &'static dyn Algorithm,
1109 client_dst_connection_id: &[u8],
1110 side: Side,
1111 ) -> Self {
1112 const CLIENT_LABEL: &[u8] = b"client in";
1113 const SERVER_LABEL: &[u8] = b"server in";
1114 let salt = version.initial_salt();
1115 let hs_secret = suite
1116 .hkdf_provider
1117 .extract_from_secret(Some(salt), client_dst_connection_id);
1118
1119 let secrets = Secrets {
1120 client: hkdf_expand_label_block(hs_secret.as_ref(), CLIENT_LABEL, &[]),
1121 server: hkdf_expand_label_block(hs_secret.as_ref(), SERVER_LABEL, &[]),
1122 suite,
1123 quic,
1124 side,
1125 version,
1126 };
1127 Self::new(&secrets)
1128 }
1129
1130 fn new(secrets: &Secrets) -> Self {
1131 let (local, remote) = secrets.local_remote();
1132 Self {
1133 local: DirectionalKeys::new(secrets.suite, secrets.quic, local, secrets.version),
1134 remote: DirectionalKeys::new(secrets.suite, secrets.quic, remote, secrets.version),
1135 }
1136 }
1137}
1138
1139#[expect(clippy::exhaustive_enums)]
1153pub enum KeyChange {
1154 Handshake {
1156 keys: Keys,
1158 },
1159 OneRtt {
1161 keys: Keys,
1163 next: Secrets,
1165 },
1166}
1167
1168impl fmt::Debug for KeyChange {
1169 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1170 match self {
1171 Self::Handshake { .. } => f
1172 .debug_struct("Handshake")
1173 .finish_non_exhaustive(),
1174 Self::OneRtt { .. } => f
1175 .debug_struct("OneRtt")
1176 .finish_non_exhaustive(),
1177 }
1178 }
1179}
1180
1181#[non_exhaustive]
1185#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
1186pub enum Version {
1187 #[default]
1189 V1,
1190 V2,
1192}
1193
1194impl Version {
1195 fn initial_salt(self) -> &'static [u8; 20] {
1196 match self {
1197 Self::V1 => &[
1198 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8,
1200 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a,
1201 ],
1202 Self::V2 => &[
1203 0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26,
1205 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9,
1206 ],
1207 }
1208 }
1209
1210 pub(crate) fn packet_key_label(&self) -> &'static [u8] {
1212 match self {
1213 Self::V1 => b"quic key",
1214 Self::V2 => b"quicv2 key",
1215 }
1216 }
1217
1218 pub(crate) fn packet_iv_label(&self) -> &'static [u8] {
1220 match self {
1221 Self::V1 => b"quic iv",
1222 Self::V2 => b"quicv2 iv",
1223 }
1224 }
1225
1226 pub(crate) fn header_key_label(&self) -> &'static [u8] {
1228 match self {
1229 Self::V1 => b"quic hp",
1230 Self::V2 => b"quicv2 hp",
1231 }
1232 }
1233
1234 fn key_update_label(&self) -> &'static [u8] {
1235 match self {
1236 Self::V1 => b"quic ku",
1237 Self::V2 => b"quicv2 ku",
1238 }
1239 }
1240}
1241
1242#[cfg(all(test, any(target_arch = "aarch64", target_arch = "x86_64")))]
1243mod tests {
1244 use super::*;
1245 use crate::crypto::TLS13_TEST_SUITE;
1246 use crate::crypto::tls13::OkmBlock;
1247 use crate::quic::{HeaderProtectionKey, Secrets, Side, Version};
1248
1249 #[test]
1250 fn key_update_test_vector() {
1251 fn equal_okm(x: &OkmBlock, y: &OkmBlock) -> bool {
1252 x.as_ref() == y.as_ref()
1253 }
1254
1255 let mut secrets = Secrets {
1256 client: OkmBlock::new(
1258 &[
1259 0xb8, 0x76, 0x77, 0x08, 0xf8, 0x77, 0x23, 0x58, 0xa6, 0xea, 0x9f, 0xc4, 0x3e,
1260 0x4a, 0xdd, 0x2c, 0x96, 0x1b, 0x3f, 0x52, 0x87, 0xa6, 0xd1, 0x46, 0x7e, 0xe0,
1261 0xae, 0xab, 0x33, 0x72, 0x4d, 0xbf,
1262 ][..],
1263 ),
1264 server: OkmBlock::new(
1265 &[
1266 0x42, 0xdc, 0x97, 0x21, 0x40, 0xe0, 0xf2, 0xe3, 0x98, 0x45, 0xb7, 0x67, 0x61,
1267 0x34, 0x39, 0xdc, 0x67, 0x58, 0xca, 0x43, 0x25, 0x9b, 0x87, 0x85, 0x06, 0x82,
1268 0x4e, 0xb1, 0xe4, 0x38, 0xd8, 0x55,
1269 ][..],
1270 ),
1271 suite: TLS13_TEST_SUITE,
1272 quic: &FakeAlgorithm,
1273 side: Side::Client,
1274 version: Version::V1,
1275 };
1276 secrets.update();
1277
1278 assert!(equal_okm(
1279 &secrets.client,
1280 &OkmBlock::new(
1281 &[
1282 0x42, 0xca, 0xc8, 0xc9, 0x1c, 0xd5, 0xeb, 0x40, 0x68, 0x2e, 0x43, 0x2e, 0xdf,
1283 0x2d, 0x2b, 0xe9, 0xf4, 0x1a, 0x52, 0xca, 0x6b, 0x22, 0xd8, 0xe6, 0xcd, 0xb1,
1284 0xe8, 0xac, 0xa9, 0x6, 0x1f, 0xce
1285 ][..]
1286 )
1287 ));
1288 assert!(equal_okm(
1289 &secrets.server,
1290 &OkmBlock::new(
1291 &[
1292 0xeb, 0x7f, 0x5e, 0x2a, 0x12, 0x3f, 0x40, 0x7d, 0xb4, 0x99, 0xe3, 0x61, 0xca,
1293 0xe5, 0x90, 0xd4, 0xd9, 0x92, 0xe1, 0x4b, 0x7a, 0xce, 0x3, 0xc2, 0x44, 0xe0,
1294 0x42, 0x21, 0x15, 0xb6, 0xd3, 0x8a
1295 ][..]
1296 )
1297 ));
1298 }
1299
1300 struct FakeAlgorithm;
1301
1302 impl Algorithm for FakeAlgorithm {
1303 fn packet_key(&self, _key: AeadKey, _iv: Iv) -> Box<dyn PacketKey> {
1304 unimplemented!()
1305 }
1306
1307 fn header_protection_key(&self, _key: AeadKey) -> Box<dyn HeaderProtectionKey> {
1308 unimplemented!()
1309 }
1310
1311 fn aead_key_len(&self) -> usize {
1312 16
1313 }
1314 }
1315
1316 #[test]
1317 fn auto_traits() {
1318 fn assert_auto<T: Send + Sync>() {}
1319 assert_auto::<Box<dyn PacketKey>>();
1320 assert_auto::<Box<dyn HeaderProtectionKey>>();
1321 }
1322}