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::{ConnectionCommon, 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: QuicCommon<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 mut tls = Vec::new();
113 let inner = ConnectionCommon::for_client(
114 config,
115 name,
116 exts,
117 Some(&mut quic),
118 Protocol::Quic(version),
119 &mut tls,
120 )?;
121
122 debug_assert!(tls.is_empty());
124 Ok(Self {
125 inner: QuicCommon::new(inner, quic),
126 })
127 }
128
129 pub fn fips(&self) -> FipsStatus {
131 self.inner.fips
132 }
133
134 pub fn is_early_data_accepted(&self) -> bool {
140 self.inner
141 .common
142 .is_early_data_accepted()
143 }
144
145 pub fn tls13_tickets_received(&self) -> u32 {
147 self.inner
148 .common
149 .common
150 .recv
151 .tls13_tickets_received
152 }
153
154 pub fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
168 self.inner.common.exporter()
169 }
170}
171
172impl Connection for ClientConnection {
173 fn quic_transport_parameters(&self) -> Option<&[u8]> {
174 self.inner.quic_transport_parameters()
175 }
176
177 fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
178 self.inner.zero_rtt_keys()
179 }
180
181 fn read_hs(&mut self, input: &mut dyn TlsInputBuffer) -> Result<(), Error> {
182 self.inner.read_hs(input)
183 }
184
185 fn events(&mut self) -> impl Iterator<Item = QuicEvent> {
186 self.inner.events()
187 }
188
189 fn is_handshaking(&self) -> bool {
190 self.inner.is_handshaking()
191 }
192}
193
194impl Deref for ClientConnection {
195 type Target = ConnectionOutputs;
196
197 fn deref(&self) -> &Self::Target {
198 &self.inner
199 }
200}
201
202impl fmt::Debug for ClientConnection {
203 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
204 f.debug_struct("quic::ClientConnection")
205 .finish_non_exhaustive()
206 }
207}
208
209pub struct ServerConnection {
211 inner: QuicCommon<ServerSide>,
212}
213
214impl ServerConnection {
215 pub fn new(
220 config: Arc<ServerConfig>,
221 version: Version,
222 params: Vec<u8>,
223 ) -> Result<Self, Error> {
224 check_server_config(&config)?;
225 let exts = ServerExtensionsInput {
226 transport_parameters: Some(match version {
227 Version::V1 | Version::V2 => TransportParameters::Quic(Payload::new(params)),
228 }),
229 };
230
231 let core = ConnectionCommon::for_server(config, exts, Protocol::Quic(version))?;
232 let inner = QuicCommon::new(
233 core,
234 Quic {
235 version,
236 ..Quic::default()
237 },
238 );
239 Ok(Self { inner })
240 }
241
242 pub fn fips(&self) -> FipsStatus {
244 self.inner.fips
245 }
246
247 pub fn server_name(&self) -> Option<&DnsName<'_>> {
263 self.inner.common.side.server_name()
264 }
265
266 pub fn set_resumption_data(&mut self, resumption_data: &[u8]) -> Result<(), Error> {
275 assert!(resumption_data.len() < 2usize.pow(15));
276 match &mut self.inner.common.state {
277 Ok(st) => st.set_resumption_data(resumption_data),
278 Err(e) => Err(e.clone()),
279 }
280 }
281
282 pub fn received_resumption_data(&self) -> Option<&[u8]> {
286 self.inner
287 .common
288 .side
289 .received_resumption_data()
290 }
291
292 pub fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
306 self.inner.common.exporter()
307 }
308}
309
310impl Connection for ServerConnection {
311 fn quic_transport_parameters(&self) -> Option<&[u8]> {
312 self.inner.quic_transport_parameters()
313 }
314
315 fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
316 self.inner.zero_rtt_keys()
317 }
318
319 fn read_hs(&mut self, input: &mut dyn TlsInputBuffer) -> Result<(), Error> {
320 self.inner.read_hs(input)
321 }
322
323 fn events(&mut self) -> impl Iterator<Item = QuicEvent> {
324 self.inner.events()
325 }
326
327 fn is_handshaking(&self) -> bool {
328 self.inner.is_handshaking()
329 }
330}
331
332impl Deref for ServerConnection {
333 type Target = ConnectionOutputs;
334
335 fn deref(&self) -> &Self::Target {
336 &self.inner
337 }
338}
339
340impl fmt::Debug for ServerConnection {
341 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
342 f.debug_struct("quic::ServerConnection")
343 .finish_non_exhaustive()
344 }
345}
346
347#[non_exhaustive]
349#[derive(Debug)]
350pub enum ServerHandshake {
351 NeedsInput(NeedsInput),
353
354 Accepted(Accepted),
359
360 Complete(ServerConnection),
362}
363
364impl ServerHandshake {
365 pub fn start(version: Version) -> NeedsInput {
375 NeedsInput {
376 inner: QuicCommon::new(
377 ConnectionCommon::for_acceptor(Protocol::Quic(version)),
378 Quic {
379 version,
380 ..Quic::default()
381 },
382 ),
383 }
384 }
385}
386
387impl TryFrom<QuicCommon<ServerSide>> for ServerHandshake {
388 type Error = Error;
389
390 fn try_from(mut inner: QuicCommon<ServerSide>) -> Result<Self, Error> {
391 const MISUSED: Error = Error::Unreachable("forgot to restore state");
392
393 Ok(match mem::replace(&mut inner.common.state, Err(MISUSED))? {
394 ServerState::ChooseConfig(choose_config) => Self::Accepted(Accepted {
395 inner,
396 choose_config,
397 }),
398
399 state if state.is_traffic() => {
400 inner.common.state = Ok(state);
401 Self::Complete(ServerConnection { inner })
402 }
403
404 state => {
405 inner.common.state = Ok(state);
406 Self::NeedsInput(NeedsInput { inner })
407 }
408 })
409 }
410}
411
412pub struct NeedsInput {
416 inner: QuicCommon<ServerSide>,
417}
418
419impl NeedsInput {
420 pub fn process(
441 mut self,
442 input: &mut dyn TlsInputBuffer,
443 output: &mut Vec<QuicEvent>,
444 ) -> Result<ServerHandshake, Error> {
445 self.inner.read_hs(input)?;
446 output.extend(self.inner.events());
447 ServerHandshake::try_from(self.inner)
448 }
449}
450
451impl fmt::Debug for NeedsInput {
452 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
453 f.debug_struct("quic::NeedsInput")
454 .finish_non_exhaustive()
455 }
456}
457
458pub struct Accepted {
463 inner: QuicCommon<ServerSide>,
465 choose_config: Box<ChooseConfig>,
466}
467
468impl Accepted {
469 pub fn client_hello(&self) -> ClientHello<'_> {
471 self.choose_config.client_hello()
472 }
473
474 pub fn choose_config(
484 mut self,
485 config: Arc<ServerConfig>,
486 params: Vec<u8>,
487 output: &mut Vec<QuicEvent>,
488 ) -> Result<ServerHandshake, Error> {
489 check_server_config(&config)?;
490
491 let mut tls = Vec::new();
492 self.inner.common.accepted(
493 self.choose_config,
494 ServerExtensionsInput {
495 transport_parameters: Some(match self.inner.quic.version {
496 Version::V1 | Version::V2 => TransportParameters::Quic(Payload::new(params)),
497 }),
498 },
499 Some(&mut self.inner.quic),
500 config,
501 &mut tls,
502 )?;
503
504 debug_assert!(tls.is_empty());
506 output.extend(self.inner.events());
507
508 ServerHandshake::try_from(self.inner)
509 }
510}
511
512impl fmt::Debug for Accepted {
513 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
514 f.debug_struct("quic::Accepted")
515 .finish_non_exhaustive()
516 }
517}
518
519fn check_server_config(config: &ServerConfig) -> Result<(), Error> {
520 let suites = &config.provider.tls13_cipher_suites;
521 if suites.is_empty() {
522 return Err(ApiMisuse::QuicRequiresTls13Support.into());
523 }
524
525 if !suites
526 .iter()
527 .any(|scs| scs.quic.is_some())
528 {
529 return Err(ApiMisuse::NoQuicCompatibleCipherSuites.into());
530 }
531
532 if config.max_early_data_size != 0 && config.max_early_data_size != 0xffff_ffff {
533 return Err(ApiMisuse::QuicRestrictsMaxEarlyDataSize.into());
534 }
535
536 Ok(())
537}
538
539#[expect(clippy::large_enum_variant)]
541#[derive(Debug)]
542#[non_exhaustive]
543pub enum QuicEvent {
544 Message(Vec<u8>),
546
547 KeyChange(KeyChange),
549}
550
551struct QuicCommon<Side: SideData> {
553 common: ConnectionCommon<Side>,
554 quic: Quic,
555}
556
557impl<Side: SideData> QuicCommon<Side> {
558 fn new(common: ConnectionCommon<Side>, quic: Quic) -> Self {
559 Self { common, quic }
560 }
561
562 fn quic_transport_parameters(&self) -> Option<&[u8]> {
563 self.quic
564 .params
565 .as_ref()
566 .map(|v| v.as_ref())
567 }
568
569 fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
570 let suite = self
571 .common
572 .common
573 .negotiated_cipher_suite()
574 .and_then(|suite| match suite {
575 SupportedCipherSuite::Tls13(suite) => Some(suite),
576 _ => None,
577 })?;
578
579 let suite = Suite {
580 inner: suite,
581 quic: suite.quic?,
582 };
583
584 Some(DirectionalKeys::new(
585 suite,
586 self.quic.early_secret.as_ref()?,
587 self.quic.version,
588 ))
589 }
590
591 fn read_hs(&mut self, input: &mut dyn TlsInputBuffer) -> Result<(), Error> {
592 self.common
593 .common
594 .recv
595 .deframer
596 .input_quic(input.slice_mut())?;
597
598 let mut tls = Vec::new();
599 let mut iter = MessageIter::new(input, &mut tls, Some(&mut self.quic), &mut self.common);
600 let result = match iter.next() {
601 Some(Ok(_)) | None => Ok(()),
602 Some(Err(e)) => Err(e),
603 };
604
605 input.discard(
606 self.common
607 .common
608 .recv
609 .deframer
610 .take_discard(),
611 );
612
613 result
614 }
615
616 fn events(&mut self) -> impl Iterator<Item = QuicEvent> {
617 self.quic.events()
618 }
619}
620
621impl<Side: SideData> Deref for QuicCommon<Side> {
622 type Target = CommonState;
623
624 fn deref(&self) -> &Self::Target {
625 &self.common.common
626 }
627}
628
629impl<Side: SideData> DerefMut for QuicCommon<Side> {
630 fn deref_mut(&mut self) -> &mut Self::Target {
631 &mut self.common.common
632 }
633}
634
635#[derive(Default)]
636pub(crate) struct Quic {
637 pub(crate) version: Version,
638 pub(crate) params: Option<Vec<u8>>,
640 pub(crate) events: Vec<QuicEvent>,
641 pub(crate) early_secret: Option<OkmBlock>,
642}
643
644impl Quic {
645 pub(crate) fn send_msg(&mut self, m: Message<'_>, _must_encrypt: bool) {
646 if let MessagePayload::Alert(_) = m.payload {
647 return;
649 }
650
651 debug_assert!(
652 matches!(
653 m.payload,
654 MessagePayload::Handshake { .. } | MessagePayload::HandshakeFlight(_)
655 ),
656 "QUIC uses TLS for the cryptographic handshake only"
657 );
658 let mut bytes = Vec::new();
659 m.payload.encode(&mut bytes);
660 self.events
661 .push(QuicEvent::Message(bytes));
662 }
663
664 pub(crate) fn events(&mut self) -> impl Iterator<Item = QuicEvent> {
665 mem::take(&mut self.events).into_iter()
666 }
667}
668
669impl QuicOutput for Quic {
670 fn transport_parameters(&mut self, params: Vec<u8>) {
671 self.params = Some(params);
672 }
673
674 fn early_secret(&mut self, secret: Option<OkmBlock>) {
675 self.early_secret = secret;
676 }
677
678 fn handshake_secrets(
679 &mut self,
680 client_secret: OkmBlock,
681 server_secret: OkmBlock,
682 suite: Suite,
683 side: Side,
684 ) {
685 self.events
686 .push(QuicEvent::KeyChange(KeyChange::Handshake {
687 keys: Keys::new(&Secrets::new(
688 client_secret,
689 server_secret,
690 suite,
691 side,
692 self.version,
693 )),
694 }));
695 }
696
697 fn traffic_secrets(
698 &mut self,
699 client_secret: OkmBlock,
700 server_secret: OkmBlock,
701 suite: Suite,
702 side: Side,
703 ) {
704 let mut secrets = Secrets::new(client_secret, server_secret, suite, side, self.version);
705 let keys = Keys::new(&secrets);
706 secrets.update();
707 self.events
708 .push(QuicEvent::KeyChange(KeyChange::OneRtt {
709 keys,
710 next: secrets,
711 }));
712 }
713
714 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool) {
715 self.send_msg(m, must_encrypt);
716 }
717}
718
719pub(crate) trait QuicOutput {
720 fn transport_parameters(&mut self, params: Vec<u8>);
721
722 fn early_secret(&mut self, secret: Option<OkmBlock>);
723
724 fn handshake_secrets(
725 &mut self,
726 client_secret: OkmBlock,
727 server_secret: OkmBlock,
728 suite: Suite,
729 side: Side,
730 );
731
732 fn traffic_secrets(
733 &mut self,
734 client_secret: OkmBlock,
735 server_secret: OkmBlock,
736 suite: Suite,
737 side: Side,
738 );
739
740 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool);
741}
742
743#[derive(Clone)]
745pub struct Secrets {
746 pub(crate) client: OkmBlock,
748 pub(crate) server: OkmBlock,
750 suite: Suite,
752 side: Side,
753 version: Version,
754}
755
756impl Secrets {
757 pub(crate) fn new(
758 client: OkmBlock,
759 server: OkmBlock,
760 suite: Suite,
761 side: Side,
762 version: Version,
763 ) -> Self {
764 Self {
765 client,
766 server,
767 suite,
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 .inner
784 .hkdf_provider
785 .expander_for_okm(&self.client)
786 .as_ref(),
787 self.version.key_update_label(),
788 &[],
789 );
790 self.server = hkdf_expand_label_block(
791 self.suite
792 .inner
793 .hkdf_provider
794 .expander_for_okm(&self.server)
795 .as_ref(),
796 self.version.key_update_label(),
797 &[],
798 );
799 }
800
801 fn local_remote(&self) -> (&OkmBlock, &OkmBlock) {
802 match self.side {
803 Side::Client => (&self.client, &self.server),
804 Side::Server => (&self.server, &self.client),
805 }
806 }
807}
808
809#[expect(clippy::exhaustive_structs)]
811pub struct DirectionalKeys {
812 pub header: Box<dyn HeaderProtectionKey>,
814 pub packet: Box<dyn PacketKey>,
816}
817
818impl DirectionalKeys {
819 pub(crate) fn new(suite: Suite, secret: &OkmBlock, version: Version) -> Self {
820 let builder = KeyBuilder::new(secret, version, suite.quic, suite.inner.hkdf_provider);
821 Self {
822 header: builder.header_protection_key(),
823 packet: builder.packet_key(),
824 }
825 }
826}
827
828const TAG_LEN: usize = 16;
830
831pub struct Tag([u8; TAG_LEN]);
833
834impl From<&[u8]> for Tag {
835 fn from(value: &[u8]) -> Self {
836 let mut array = [0u8; TAG_LEN];
837 array.copy_from_slice(value);
838 Self(array)
839 }
840}
841
842impl AsRef<[u8]> for Tag {
843 fn as_ref(&self) -> &[u8] {
844 &self.0
845 }
846}
847
848pub trait Algorithm: Send + Sync {
850 fn packet_key(&self, key: AeadKey, iv: Iv) -> Box<dyn PacketKey>;
855
856 fn header_protection_key(&self, key: AeadKey) -> Box<dyn HeaderProtectionKey>;
860
861 fn aead_key_len(&self) -> usize;
865
866 fn fips(&self) -> FipsStatus {
868 FipsStatus::Unvalidated
869 }
870}
871
872pub trait HeaderProtectionKey: Send + Sync {
874 fn encrypt_in_place(
895 &self,
896 sample: &[u8],
897 first: &mut u8,
898 packet_number: &mut [u8],
899 ) -> Result<(), Error>;
900
901 fn decrypt_in_place(
923 &self,
924 sample: &[u8],
925 first: &mut u8,
926 packet_number: &mut [u8],
927 ) -> Result<(), Error>;
928
929 fn sample_len(&self) -> usize;
931}
932
933pub trait PacketKey: Send + Sync {
935 fn encrypt_in_place(
946 &self,
947 packet_number: u64,
948 header: &[u8],
949 payload: &mut [u8],
950 path_id: Option<u32>,
951 ) -> Result<Tag, Error>;
952
953 fn decrypt_in_place<'a>(
964 &self,
965 packet_number: u64,
966 header: &[u8],
967 payload: &'a mut [u8],
968 path_id: Option<u32>,
969 ) -> Result<&'a [u8], Error>;
970
971 fn tag_len(&self) -> usize;
973
974 fn confidentiality_limit(&self) -> u64;
985
986 fn integrity_limit(&self) -> u64;
995}
996
997#[expect(clippy::exhaustive_structs)]
999pub struct PacketKeySet {
1000 pub local: Box<dyn PacketKey>,
1002 pub remote: Box<dyn PacketKey>,
1004}
1005
1006impl PacketKeySet {
1007 fn new(secrets: &Secrets) -> Self {
1008 let (local, remote) = secrets.local_remote();
1009 let (version, alg, hkdf) = (
1010 secrets.version,
1011 secrets.suite.quic,
1012 secrets.suite.inner.hkdf_provider,
1013 );
1014
1015 Self {
1016 local: KeyBuilder::new(local, version, alg, hkdf).packet_key(),
1017 remote: KeyBuilder::new(remote, version, alg, hkdf).packet_key(),
1018 }
1019 }
1020}
1021
1022pub struct KeyBuilder<'a> {
1024 expander: Box<dyn HkdfExpander>,
1025 version: Version,
1026 alg: &'a dyn Algorithm,
1027}
1028
1029impl<'a> KeyBuilder<'a> {
1030 pub fn new(
1032 secret: &OkmBlock,
1033 version: Version,
1034 alg: &'a dyn Algorithm,
1035 hkdf: &'a dyn Hkdf,
1036 ) -> Self {
1037 Self {
1038 expander: hkdf.expander_for_okm(secret),
1039 version,
1040 alg,
1041 }
1042 }
1043
1044 pub fn packet_key(&self) -> Box<dyn PacketKey> {
1046 let aead_key_len = self.alg.aead_key_len();
1047 let packet_key = hkdf_expand_label_aead_key(
1048 self.expander.as_ref(),
1049 aead_key_len,
1050 self.version.packet_key_label(),
1051 &[],
1052 );
1053
1054 let packet_iv =
1055 hkdf_expand_label(self.expander.as_ref(), self.version.packet_iv_label(), &[]);
1056 self.alg
1057 .packet_key(packet_key, packet_iv)
1058 }
1059
1060 pub fn header_protection_key(&self) -> Box<dyn HeaderProtectionKey> {
1062 let header_key = hkdf_expand_label_aead_key(
1063 self.expander.as_ref(),
1064 self.alg.aead_key_len(),
1065 self.version.header_key_label(),
1066 &[],
1067 );
1068 self.alg
1069 .header_protection_key(header_key)
1070 }
1071}
1072
1073#[non_exhaustive]
1075#[derive(Clone, Copy)]
1076pub struct Suite {
1077 pub inner: &'static Tls13CipherSuite,
1079 pub quic: &'static dyn Algorithm,
1081}
1082
1083impl Suite {
1084 pub fn keys(&self, client_dst_connection_id: &[u8], side: Side, version: Version) -> Keys {
1086 Keys::initial(version, *self, client_dst_connection_id, side)
1087 }
1088}
1089
1090impl TryFrom<&'static Tls13CipherSuite> for Suite {
1091 type Error = ApiMisuse;
1092
1093 fn try_from(suite: &'static Tls13CipherSuite) -> Result<Self, Self::Error> {
1094 Ok(Self {
1095 inner: suite,
1096 quic: suite
1097 .quic
1098 .ok_or(ApiMisuse::NoQuicCompatibleCipherSuites)?,
1099 })
1100 }
1101}
1102
1103impl fmt::Debug for Suite {
1104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1105 f.debug_struct("Suite")
1106 .field("inner", &self.inner)
1107 .finish_non_exhaustive()
1108 }
1109}
1110
1111#[expect(clippy::exhaustive_structs)]
1113pub struct Keys {
1114 pub local: DirectionalKeys,
1116 pub remote: DirectionalKeys,
1118}
1119
1120impl Keys {
1121 pub fn initial(
1123 version: Version,
1124 suite: Suite,
1125 client_dst_connection_id: &[u8],
1126 side: Side,
1127 ) -> Self {
1128 const CLIENT_LABEL: &[u8] = b"client in";
1129 const SERVER_LABEL: &[u8] = b"server in";
1130 let salt = version.initial_salt();
1131 let hs_secret = suite
1132 .inner
1133 .hkdf_provider
1134 .extract_from_secret(Some(salt), client_dst_connection_id);
1135
1136 let secrets = Secrets {
1137 client: hkdf_expand_label_block(hs_secret.as_ref(), CLIENT_LABEL, &[]),
1138 server: hkdf_expand_label_block(hs_secret.as_ref(), SERVER_LABEL, &[]),
1139 suite,
1140 side,
1141 version,
1142 };
1143
1144 Self::new(&secrets)
1145 }
1146
1147 fn new(secrets: &Secrets) -> Self {
1148 let (local, remote) = secrets.local_remote();
1149 Self {
1150 local: DirectionalKeys::new(secrets.suite, local, secrets.version),
1151 remote: DirectionalKeys::new(secrets.suite, remote, secrets.version),
1152 }
1153 }
1154}
1155
1156#[expect(clippy::exhaustive_enums)]
1170pub enum KeyChange {
1171 Handshake {
1173 keys: Keys,
1175 },
1176 OneRtt {
1178 keys: Keys,
1180 next: Secrets,
1182 },
1183}
1184
1185impl fmt::Debug for KeyChange {
1186 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
1187 match self {
1188 Self::Handshake { .. } => f
1189 .debug_struct("Handshake")
1190 .finish_non_exhaustive(),
1191 Self::OneRtt { .. } => f
1192 .debug_struct("OneRtt")
1193 .finish_non_exhaustive(),
1194 }
1195 }
1196}
1197
1198#[non_exhaustive]
1202#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
1203pub enum Version {
1204 #[default]
1206 V1,
1207 V2,
1209}
1210
1211impl Version {
1212 fn initial_salt(self) -> &'static [u8; 20] {
1213 match self {
1214 Self::V1 => &[
1215 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8,
1217 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a,
1218 ],
1219 Self::V2 => &[
1220 0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26,
1222 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9,
1223 ],
1224 }
1225 }
1226
1227 pub(crate) fn packet_key_label(&self) -> &'static [u8] {
1229 match self {
1230 Self::V1 => b"quic key",
1231 Self::V2 => b"quicv2 key",
1232 }
1233 }
1234
1235 pub(crate) fn packet_iv_label(&self) -> &'static [u8] {
1237 match self {
1238 Self::V1 => b"quic iv",
1239 Self::V2 => b"quicv2 iv",
1240 }
1241 }
1242
1243 pub(crate) fn header_key_label(&self) -> &'static [u8] {
1245 match self {
1246 Self::V1 => b"quic hp",
1247 Self::V2 => b"quicv2 hp",
1248 }
1249 }
1250
1251 fn key_update_label(&self) -> &'static [u8] {
1252 match self {
1253 Self::V1 => b"quic ku",
1254 Self::V2 => b"quicv2 ku",
1255 }
1256 }
1257}
1258
1259#[cfg(all(test, any(target_arch = "aarch64", target_arch = "x86_64")))]
1260mod tests {
1261 use super::*;
1262 use crate::crypto::TLS13_TEST_SUITE;
1263 use crate::crypto::tls13::OkmBlock;
1264 use crate::quic::{HeaderProtectionKey, Secrets, Side, Version};
1265
1266 #[test]
1267 fn key_update_test_vector() {
1268 fn equal_okm(x: &OkmBlock, y: &OkmBlock) -> bool {
1269 x.as_ref() == y.as_ref()
1270 }
1271
1272 let mut secrets = Secrets {
1273 client: OkmBlock::new(
1275 &[
1276 0xb8, 0x76, 0x77, 0x08, 0xf8, 0x77, 0x23, 0x58, 0xa6, 0xea, 0x9f, 0xc4, 0x3e,
1277 0x4a, 0xdd, 0x2c, 0x96, 0x1b, 0x3f, 0x52, 0x87, 0xa6, 0xd1, 0x46, 0x7e, 0xe0,
1278 0xae, 0xab, 0x33, 0x72, 0x4d, 0xbf,
1279 ][..],
1280 ),
1281 server: OkmBlock::new(
1282 &[
1283 0x42, 0xdc, 0x97, 0x21, 0x40, 0xe0, 0xf2, 0xe3, 0x98, 0x45, 0xb7, 0x67, 0x61,
1284 0x34, 0x39, 0xdc, 0x67, 0x58, 0xca, 0x43, 0x25, 0x9b, 0x87, 0x85, 0x06, 0x82,
1285 0x4e, 0xb1, 0xe4, 0x38, 0xd8, 0x55,
1286 ][..],
1287 ),
1288 suite: Suite {
1289 inner: TLS13_TEST_SUITE,
1290 quic: &FakeAlgorithm,
1291 },
1292 side: Side::Client,
1293 version: Version::V1,
1294 };
1295 secrets.update();
1296
1297 assert!(equal_okm(
1298 &secrets.client,
1299 &OkmBlock::new(
1300 &[
1301 0x42, 0xca, 0xc8, 0xc9, 0x1c, 0xd5, 0xeb, 0x40, 0x68, 0x2e, 0x43, 0x2e, 0xdf,
1302 0x2d, 0x2b, 0xe9, 0xf4, 0x1a, 0x52, 0xca, 0x6b, 0x22, 0xd8, 0xe6, 0xcd, 0xb1,
1303 0xe8, 0xac, 0xa9, 0x6, 0x1f, 0xce
1304 ][..]
1305 )
1306 ));
1307 assert!(equal_okm(
1308 &secrets.server,
1309 &OkmBlock::new(
1310 &[
1311 0xeb, 0x7f, 0x5e, 0x2a, 0x12, 0x3f, 0x40, 0x7d, 0xb4, 0x99, 0xe3, 0x61, 0xca,
1312 0xe5, 0x90, 0xd4, 0xd9, 0x92, 0xe1, 0x4b, 0x7a, 0xce, 0x3, 0xc2, 0x44, 0xe0,
1313 0x42, 0x21, 0x15, 0xb6, 0xd3, 0x8a
1314 ][..]
1315 )
1316 ));
1317 }
1318
1319 struct FakeAlgorithm;
1320
1321 impl Algorithm for FakeAlgorithm {
1322 fn packet_key(&self, _key: AeadKey, _iv: Iv) -> Box<dyn PacketKey> {
1323 unimplemented!()
1324 }
1325
1326 fn header_protection_key(&self, _key: AeadKey) -> Box<dyn HeaderProtectionKey> {
1327 unimplemented!()
1328 }
1329
1330 fn aead_key_len(&self) -> usize {
1331 16
1332 }
1333 }
1334
1335 #[test]
1336 fn auto_traits() {
1337 fn assert_auto<T: Send + Sync>() {}
1338 assert_auto::<Box<dyn PacketKey>>();
1339 assert_auto::<Box<dyn HeaderProtectionKey>>();
1340 }
1341}