1use alloc::boxed::Box;
2use alloc::collections::VecDeque;
3use alloc::vec::Vec;
4use core::fmt::{self, Debug};
5use core::mem;
6use core::ops::{Deref, DerefMut};
7
8use pki_types::{DnsName, FipsStatus, ServerName};
9
10use crate::client::{ClientConfig, ClientSide};
11pub use crate::common_state::Side;
12use crate::common_state::{CommonState, ConnectionOutputs, Protocol};
13use crate::conn::{ConnectionCore, KeyingMaterialExporter, SideCommonOutput, SideData};
14use crate::crypto::cipher::{AeadKey, EncodedMessage, Iv, Payload};
15use crate::crypto::tls13::{Hkdf, HkdfExpander, OkmBlock};
16use crate::enums::{ApplicationProtocol, ContentType, ProtocolVersion};
17use crate::error::{ApiMisuse, Error};
18use crate::msgs::{
19 ClientExtensionsInput, Message, MessagePayload, ServerExtensionsInput, TransportParameters,
20 VecInput,
21};
22use crate::server::{ChooseConfig, ClientHello, ServerConfig, ServerSide, ServerState};
23use crate::suites::SupportedCipherSuite;
24use crate::sync::Arc;
25use crate::tls13::Tls13CipherSuite;
26use crate::tls13::key_schedule::{
27 hkdf_expand_label, hkdf_expand_label_aead_key, hkdf_expand_label_block,
28};
29
30pub trait Connection: Debug + Deref<Target = ConnectionOutputs> {
32 fn quic_transport_parameters(&self) -> Option<&[u8]>;
40
41 fn zero_rtt_keys(&self) -> Option<DirectionalKeys>;
43
44 fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error>;
48
49 fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange>;
53
54 fn is_handshaking(&self) -> bool;
56}
57
58pub struct ClientConnection {
60 inner: ConnectionCommon<ClientSide>,
61}
62
63impl ClientConnection {
64 pub fn new(
69 config: Arc<ClientConfig>,
70 quic_version: Version,
71 name: ServerName<'static>,
72 params: Vec<u8>,
73 ) -> Result<Self, Error> {
74 Self::new_with_alpn(
75 config.clone(),
76 quic_version,
77 name,
78 params,
79 config.alpn_protocols.clone(),
80 )
81 }
82
83 pub fn new_with_alpn(
85 config: Arc<ClientConfig>,
86 version: Version,
87 name: ServerName<'static>,
88 params: Vec<u8>,
89 alpn_protocols: Vec<ApplicationProtocol<'static>>,
90 ) -> Result<Self, Error> {
91 let fips = config.fips();
92 let suites = &config.provider().tls13_cipher_suites;
93 if suites.is_empty() {
94 return Err(ApiMisuse::QuicRequiresTls13Support.into());
95 }
96
97 if !suites
98 .iter()
99 .any(|scs| scs.quic.is_some())
100 {
101 return Err(ApiMisuse::NoQuicCompatibleCipherSuites.into());
102 }
103
104 let exts = ClientExtensionsInput {
105 transport_parameters: Some(match version {
106 Version::V1 | Version::V2 => TransportParameters::Quic(Payload::new(params)),
107 }),
108
109 ..ClientExtensionsInput::from_alpn(alpn_protocols)
110 };
111
112 let mut quic = Quic {
113 version,
114 ..Quic::default()
115 };
116
117 let inner = ConnectionCore::for_client(
118 config,
119 name,
120 exts,
121 Some(&mut quic),
122 Protocol::Quic(version),
123 )?;
124
125 Ok(Self {
126 inner: ConnectionCommon::new(inner, fips, quic),
127 })
128 }
129
130 pub fn fips(&self) -> FipsStatus {
132 self.inner.fips
133 }
134
135 pub fn is_early_data_accepted(&self) -> bool {
141 self.inner.core.is_early_data_accepted()
142 }
143
144 pub fn tls13_tickets_received(&self) -> u32 {
146 self.inner
147 .core
148 .common
149 .recv
150 .tls13_tickets_received
151 }
152
153 pub fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
167 self.inner.core.exporter()
168 }
169}
170
171impl Connection for ClientConnection {
172 fn quic_transport_parameters(&self) -> Option<&[u8]> {
173 self.inner.quic_transport_parameters()
174 }
175
176 fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
177 self.inner.zero_rtt_keys()
178 }
179
180 fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> {
181 self.inner.read_hs(plaintext)
182 }
183
184 fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange> {
185 self.inner.write_hs(buf)
186 }
187
188 fn is_handshaking(&self) -> bool {
189 self.inner.is_handshaking()
190 }
191}
192
193impl Deref for ClientConnection {
194 type Target = ConnectionOutputs;
195
196 fn deref(&self) -> &Self::Target {
197 &self.inner
198 }
199}
200
201impl Debug for ClientConnection {
202 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
203 f.debug_struct("quic::ClientConnection")
204 .finish_non_exhaustive()
205 }
206}
207
208pub struct ServerConnection {
210 inner: ConnectionCommon<ServerSide>,
211}
212
213impl ServerConnection {
214 pub fn new(
219 config: Arc<ServerConfig>,
220 version: Version,
221 params: Vec<u8>,
222 ) -> Result<Self, Error> {
223 check_server_config(&config)?;
224 let fips = config.fips();
225
226 let exts = ServerExtensionsInput {
227 transport_parameters: Some(match version {
228 Version::V1 | Version::V2 => TransportParameters::Quic(Payload::new(params)),
229 }),
230 };
231
232 let core = ConnectionCore::for_server(config, exts, Protocol::Quic(version))?;
233 let inner = ConnectionCommon::new(
234 core,
235 fips,
236 Quic {
237 version,
238 ..Quic::default()
239 },
240 );
241 Ok(Self { inner })
242 }
243
244 pub fn fips(&self) -> FipsStatus {
246 self.inner.fips
247 }
248
249 pub fn server_name(&self) -> Option<&DnsName<'_>> {
265 self.inner.core.side.server_name()
266 }
267
268 pub fn set_resumption_data(&mut self, resumption_data: &[u8]) -> Result<(), Error> {
277 assert!(resumption_data.len() < 2usize.pow(15));
278 match &mut self.inner.core.state {
279 Ok(st) => st.set_resumption_data(resumption_data),
280 Err(e) => Err(e.clone()),
281 }
282 }
283
284 pub fn received_resumption_data(&self) -> Option<&[u8]> {
288 self.inner
289 .core
290 .side
291 .received_resumption_data()
292 }
293
294 pub fn exporter(&mut self) -> Result<KeyingMaterialExporter, Error> {
308 self.inner.core.exporter()
309 }
310}
311
312impl Connection for ServerConnection {
313 fn quic_transport_parameters(&self) -> Option<&[u8]> {
314 self.inner.quic_transport_parameters()
315 }
316
317 fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
318 self.inner.zero_rtt_keys()
319 }
320
321 fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> {
322 self.inner.read_hs(plaintext)
323 }
324
325 fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange> {
326 self.inner.write_hs(buf)
327 }
328
329 fn is_handshaking(&self) -> bool {
330 self.inner.is_handshaking()
331 }
332}
333
334impl Deref for ServerConnection {
335 type Target = ConnectionOutputs;
336
337 fn deref(&self) -> &Self::Target {
338 &self.inner
339 }
340}
341
342impl Debug for ServerConnection {
343 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
344 f.debug_struct("quic::ServerConnection")
345 .finish_non_exhaustive()
346 }
347}
348
349pub struct Acceptor {
354 inner: Option<ConnectionCommon<ServerSide>>,
355}
356
357impl Acceptor {
358 pub fn new(version: Version) -> Self {
360 Self {
361 inner: Some(ConnectionCommon::new(
362 ConnectionCore::for_acceptor(Protocol::Quic(version)),
363 FipsStatus::Unvalidated,
364 Quic {
365 version,
366 ..Quic::default()
367 },
368 )),
369 }
370 }
371
372 pub fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> {
378 match &mut self.inner {
379 Some(conn) => conn.read_hs(plaintext),
380 None => Err(ApiMisuse::AcceptorPolledAfterCompletion.into()),
381 }
382 }
383
384 pub fn accept(&mut self) -> Result<Option<Accepted>, Error> {
392 let Some(mut connection) = self.inner.take() else {
393 return Err(ApiMisuse::AcceptorPolledAfterCompletion.into());
394 };
395
396 const MISUSED: Error = Error::Unreachable("Accepted misused state");
397 let state = mem::replace(&mut connection.core.state, Err(MISUSED))?;
398
399 Ok(match state {
400 ServerState::ChooseConfig(choose_config) => Some(Accepted {
401 connection,
402 choose_config,
403 }),
404 state => {
405 connection.core.state = Ok(state);
406 self.inner = Some(connection);
407 None
408 }
409 })
410 }
411}
412
413pub struct Accepted {
418 connection: ConnectionCommon<ServerSide>,
420 choose_config: Box<ChooseConfig>,
421}
422
423impl Accepted {
424 pub fn client_hello(&self) -> ClientHello<'_> {
426 self.choose_config.client_hello()
427 }
428
429 pub fn into_connection(
436 mut self,
437 config: Arc<ServerConfig>,
438 params: Vec<u8>,
439 ) -> Result<ServerConnection, Error> {
440 check_server_config(&config)?;
441 self.connection
442 .core
443 .common
444 .send
445 .set_max_fragment_size(config.max_fragment_size)?;
446 self.connection.fips = config.fips();
447
448 let exts = ServerExtensionsInput {
449 transport_parameters: Some(match self.connection.quic.version {
450 Version::V1 | Version::V2 => TransportParameters::Quic(Payload::new(params)),
451 }),
452 };
453 let mut output = SideCommonOutput {
454 side: &mut self.connection.core.side,
455 quic: Some(&mut self.connection.quic),
456 common: &mut self.connection.core.common,
457 };
458
459 self.connection.core.state =
460 Ok(self
461 .choose_config
462 .use_config(config, exts, &mut output)?);
463
464 Ok(ServerConnection {
465 inner: self.connection,
466 })
467 }
468}
469
470impl Debug for Accepted {
471 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
472 f.debug_struct("quic::Accepted")
473 .finish_non_exhaustive()
474 }
475}
476
477fn check_server_config(config: &ServerConfig) -> Result<(), Error> {
478 let suites = &config.provider.tls13_cipher_suites;
479 if suites.is_empty() {
480 return Err(ApiMisuse::QuicRequiresTls13Support.into());
481 }
482
483 if !suites
484 .iter()
485 .any(|scs| scs.quic.is_some())
486 {
487 return Err(ApiMisuse::NoQuicCompatibleCipherSuites.into());
488 }
489
490 if config.max_early_data_size != 0 && config.max_early_data_size != 0xffff_ffff {
491 return Err(ApiMisuse::QuicRestrictsMaxEarlyDataSize.into());
492 }
493
494 Ok(())
495}
496
497struct ConnectionCommon<Side: SideData> {
499 core: ConnectionCore<Side>,
500 fips: FipsStatus,
501 deframer_buffer: VecInput,
502 quic: Quic,
503}
504
505impl<Side: SideData> ConnectionCommon<Side> {
506 fn new(core: ConnectionCore<Side>, fips: FipsStatus, quic: Quic) -> Self {
507 Self {
508 core,
509 fips,
510 deframer_buffer: VecInput::default(),
511 quic,
512 }
513 }
514
515 fn quic_transport_parameters(&self) -> Option<&[u8]> {
516 self.quic
517 .params
518 .as_ref()
519 .map(|v| v.as_ref())
520 }
521
522 fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
523 let suite = self
524 .core
525 .common
526 .negotiated_cipher_suite()
527 .and_then(|suite| match suite {
528 SupportedCipherSuite::Tls13(suite) => Some(suite),
529 _ => None,
530 })?;
531
532 Some(DirectionalKeys::new(
533 suite,
534 suite.quic?,
535 self.quic.early_secret.as_ref()?,
536 self.quic.version,
537 ))
538 }
539
540 fn read_hs(&mut self, plaintext: &[u8]) -> Result<(), Error> {
541 let range = self.deframer_buffer.extend(plaintext);
542
543 let deframer = &mut self.core.common.recv.deframer;
544 deframer.add_processed(range.len());
545 deframer.input_message(
546 EncodedMessage {
547 typ: ContentType::Handshake,
548 version: ProtocolVersion::TLSv1_3,
549 payload: &self.deframer_buffer.filled()[range.start..range.end],
550 },
551 range,
552 );
553
554 self.core
555 .common
556 .recv
557 .deframer
558 .coalesce(self.deframer_buffer.filled_mut())?;
559
560 self.core
561 .process_new_packets(&mut self.deframer_buffer, Some(&mut self.quic))?;
562
563 Ok(())
564 }
565
566 fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange> {
567 self.quic.write_hs(buf)
568 }
569}
570
571impl<Side: SideData> Deref for ConnectionCommon<Side> {
572 type Target = CommonState;
573
574 fn deref(&self) -> &Self::Target {
575 &self.core.common
576 }
577}
578
579impl<Side: SideData> DerefMut for ConnectionCommon<Side> {
580 fn deref_mut(&mut self) -> &mut Self::Target {
581 &mut self.core.common
582 }
583}
584
585#[derive(Default)]
586pub(crate) struct Quic {
587 pub(crate) version: Version,
588 pub(crate) params: Option<Vec<u8>>,
590 pub(crate) hs_queue: VecDeque<(bool, Vec<u8>)>,
591 pub(crate) early_secret: Option<OkmBlock>,
592 pub(crate) hs_secrets: Option<Secrets>,
593 pub(crate) traffic_secrets: Option<Secrets>,
594 pub(crate) returned_traffic_keys: bool,
596}
597
598impl Quic {
599 pub(crate) fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool) {
600 if let MessagePayload::Alert(_) = m.payload {
601 return;
603 }
604
605 debug_assert!(
606 matches!(
607 m.payload,
608 MessagePayload::Handshake { .. } | MessagePayload::HandshakeFlight(_)
609 ),
610 "QUIC uses TLS for the cryptographic handshake only"
611 );
612 let mut bytes = Vec::new();
613 m.payload.encode(&mut bytes);
614 self.hs_queue
615 .push_back((must_encrypt, bytes));
616 }
617
618 pub(crate) fn write_hs(&mut self, buf: &mut Vec<u8>) -> Option<KeyChange> {
619 while let Some((_, msg)) = self.hs_queue.pop_front() {
620 buf.extend_from_slice(&msg);
621 if let Some(&(true, _)) = self.hs_queue.front() {
622 if self.hs_secrets.is_some() {
623 break;
625 }
626 }
627 }
628
629 if let Some(secrets) = self.hs_secrets.take() {
630 return Some(KeyChange::Handshake {
631 keys: Keys::new(&secrets),
632 });
633 }
634
635 if let Some(mut secrets) = self.traffic_secrets.take() {
636 if !self.returned_traffic_keys {
637 self.returned_traffic_keys = true;
638 let keys = Keys::new(&secrets);
639 secrets.update();
640 return Some(KeyChange::OneRtt {
641 keys,
642 next: secrets,
643 });
644 }
645 }
646
647 None
648 }
649}
650
651impl QuicOutput for Quic {
652 fn transport_parameters(&mut self, params: Vec<u8>) {
653 self.params = Some(params);
654 }
655
656 fn early_secret(&mut self, secret: Option<OkmBlock>) {
657 self.early_secret = secret;
658 }
659
660 fn handshake_secrets(
661 &mut self,
662 client_secret: OkmBlock,
663 server_secret: OkmBlock,
664 suite: &'static Tls13CipherSuite,
665 quic: &'static dyn Algorithm,
666 side: Side,
667 ) {
668 self.hs_secrets = Some(Secrets::new(
669 client_secret,
670 server_secret,
671 suite,
672 quic,
673 side,
674 self.version,
675 ));
676 }
677
678 fn traffic_secrets(
679 &mut self,
680 client_secret: OkmBlock,
681 server_secret: OkmBlock,
682 suite: &'static Tls13CipherSuite,
683 quic: &'static dyn Algorithm,
684 side: Side,
685 ) {
686 self.traffic_secrets = Some(Secrets::new(
687 client_secret,
688 server_secret,
689 suite,
690 quic,
691 side,
692 self.version,
693 ));
694 }
695
696 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool) {
697 self.send_msg(m, must_encrypt);
698 }
699}
700
701pub(crate) trait QuicOutput {
702 fn transport_parameters(&mut self, params: Vec<u8>);
703
704 fn early_secret(&mut self, secret: Option<OkmBlock>);
705
706 fn handshake_secrets(
707 &mut self,
708 client_secret: OkmBlock,
709 server_secret: OkmBlock,
710 suite: &'static Tls13CipherSuite,
711 quic: &'static dyn Algorithm,
712 side: Side,
713 );
714
715 fn traffic_secrets(
716 &mut self,
717 client_secret: OkmBlock,
718 server_secret: OkmBlock,
719 suite: &'static Tls13CipherSuite,
720 quic: &'static dyn Algorithm,
721 side: Side,
722 );
723
724 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool);
725}
726
727#[derive(Clone)]
729pub struct Secrets {
730 pub(crate) client: OkmBlock,
732 pub(crate) server: OkmBlock,
734 suite: &'static Tls13CipherSuite,
736 quic: &'static dyn Algorithm,
737 side: Side,
738 version: Version,
739}
740
741impl Secrets {
742 pub(crate) fn new(
743 client: OkmBlock,
744 server: OkmBlock,
745 suite: &'static Tls13CipherSuite,
746 quic: &'static dyn Algorithm,
747 side: Side,
748 version: Version,
749 ) -> Self {
750 Self {
751 client,
752 server,
753 suite,
754 quic,
755 side,
756 version,
757 }
758 }
759
760 pub fn next_packet_keys(&mut self) -> PacketKeySet {
762 let keys = PacketKeySet::new(self);
763 self.update();
764 keys
765 }
766
767 pub(crate) fn update(&mut self) {
768 self.client = hkdf_expand_label_block(
769 self.suite
770 .hkdf_provider
771 .expander_for_okm(&self.client)
772 .as_ref(),
773 self.version.key_update_label(),
774 &[],
775 );
776 self.server = hkdf_expand_label_block(
777 self.suite
778 .hkdf_provider
779 .expander_for_okm(&self.server)
780 .as_ref(),
781 self.version.key_update_label(),
782 &[],
783 );
784 }
785
786 fn local_remote(&self) -> (&OkmBlock, &OkmBlock) {
787 match self.side {
788 Side::Client => (&self.client, &self.server),
789 Side::Server => (&self.server, &self.client),
790 }
791 }
792}
793
794#[expect(clippy::exhaustive_structs)]
796pub struct DirectionalKeys {
797 pub header: Box<dyn HeaderProtectionKey>,
799 pub packet: Box<dyn PacketKey>,
801}
802
803impl DirectionalKeys {
804 pub(crate) fn new(
805 suite: &'static Tls13CipherSuite,
806 quic: &'static dyn Algorithm,
807 secret: &OkmBlock,
808 version: Version,
809 ) -> Self {
810 let builder = KeyBuilder::new(secret, version, quic, suite.hkdf_provider);
811 Self {
812 header: builder.header_protection_key(),
813 packet: builder.packet_key(),
814 }
815 }
816}
817
818const TAG_LEN: usize = 16;
820
821pub struct Tag([u8; TAG_LEN]);
823
824impl From<&[u8]> for Tag {
825 fn from(value: &[u8]) -> Self {
826 let mut array = [0u8; TAG_LEN];
827 array.copy_from_slice(value);
828 Self(array)
829 }
830}
831
832impl AsRef<[u8]> for Tag {
833 fn as_ref(&self) -> &[u8] {
834 &self.0
835 }
836}
837
838pub trait Algorithm: Send + Sync {
840 fn packet_key(&self, key: AeadKey, iv: Iv) -> Box<dyn PacketKey>;
845
846 fn header_protection_key(&self, key: AeadKey) -> Box<dyn HeaderProtectionKey>;
850
851 fn aead_key_len(&self) -> usize;
855
856 fn fips(&self) -> FipsStatus {
858 FipsStatus::Unvalidated
859 }
860}
861
862pub trait HeaderProtectionKey: Send + Sync {
864 fn encrypt_in_place(
885 &self,
886 sample: &[u8],
887 first: &mut u8,
888 packet_number: &mut [u8],
889 ) -> Result<(), Error>;
890
891 fn decrypt_in_place(
913 &self,
914 sample: &[u8],
915 first: &mut u8,
916 packet_number: &mut [u8],
917 ) -> Result<(), Error>;
918
919 fn sample_len(&self) -> usize;
921}
922
923pub trait PacketKey: Send + Sync {
925 fn encrypt_in_place(
936 &self,
937 packet_number: u64,
938 header: &[u8],
939 payload: &mut [u8],
940 path_id: Option<u32>,
941 ) -> Result<Tag, Error>;
942
943 fn decrypt_in_place<'a>(
954 &self,
955 packet_number: u64,
956 header: &[u8],
957 payload: &'a mut [u8],
958 path_id: Option<u32>,
959 ) -> Result<&'a [u8], Error>;
960
961 fn tag_len(&self) -> usize;
963
964 fn confidentiality_limit(&self) -> u64;
975
976 fn integrity_limit(&self) -> u64;
985}
986
987#[expect(clippy::exhaustive_structs)]
989pub struct PacketKeySet {
990 pub local: Box<dyn PacketKey>,
992 pub remote: Box<dyn PacketKey>,
994}
995
996impl PacketKeySet {
997 fn new(secrets: &Secrets) -> Self {
998 let (local, remote) = secrets.local_remote();
999 let (version, alg, hkdf) = (secrets.version, secrets.quic, secrets.suite.hkdf_provider);
1000 Self {
1001 local: KeyBuilder::new(local, version, alg, hkdf).packet_key(),
1002 remote: KeyBuilder::new(remote, version, alg, hkdf).packet_key(),
1003 }
1004 }
1005}
1006
1007pub struct KeyBuilder<'a> {
1009 expander: Box<dyn HkdfExpander>,
1010 version: Version,
1011 alg: &'a dyn Algorithm,
1012}
1013
1014impl<'a> KeyBuilder<'a> {
1015 pub fn new(
1017 secret: &OkmBlock,
1018 version: Version,
1019 alg: &'a dyn Algorithm,
1020 hkdf: &'a dyn Hkdf,
1021 ) -> Self {
1022 Self {
1023 expander: hkdf.expander_for_okm(secret),
1024 version,
1025 alg,
1026 }
1027 }
1028
1029 pub fn packet_key(&self) -> Box<dyn PacketKey> {
1031 let aead_key_len = self.alg.aead_key_len();
1032 let packet_key = hkdf_expand_label_aead_key(
1033 self.expander.as_ref(),
1034 aead_key_len,
1035 self.version.packet_key_label(),
1036 &[],
1037 );
1038
1039 let packet_iv =
1040 hkdf_expand_label(self.expander.as_ref(), self.version.packet_iv_label(), &[]);
1041 self.alg
1042 .packet_key(packet_key, packet_iv)
1043 }
1044
1045 pub fn header_protection_key(&self) -> Box<dyn HeaderProtectionKey> {
1047 let header_key = hkdf_expand_label_aead_key(
1048 self.expander.as_ref(),
1049 self.alg.aead_key_len(),
1050 self.version.header_key_label(),
1051 &[],
1052 );
1053 self.alg
1054 .header_protection_key(header_key)
1055 }
1056}
1057
1058#[non_exhaustive]
1060#[derive(Clone, Copy)]
1061pub struct Suite {
1062 pub suite: &'static Tls13CipherSuite,
1064 pub quic: &'static dyn Algorithm,
1066}
1067
1068impl Suite {
1069 pub fn keys(&self, client_dst_connection_id: &[u8], side: Side, version: Version) -> Keys {
1071 Keys::initial(
1072 version,
1073 self.suite,
1074 self.quic,
1075 client_dst_connection_id,
1076 side,
1077 )
1078 }
1079}
1080
1081#[expect(clippy::exhaustive_structs)]
1083pub struct Keys {
1084 pub local: DirectionalKeys,
1086 pub remote: DirectionalKeys,
1088}
1089
1090impl Keys {
1091 pub fn initial(
1093 version: Version,
1094 suite: &'static Tls13CipherSuite,
1095 quic: &'static dyn Algorithm,
1096 client_dst_connection_id: &[u8],
1097 side: Side,
1098 ) -> Self {
1099 const CLIENT_LABEL: &[u8] = b"client in";
1100 const SERVER_LABEL: &[u8] = b"server in";
1101 let salt = version.initial_salt();
1102 let hs_secret = suite
1103 .hkdf_provider
1104 .extract_from_secret(Some(salt), client_dst_connection_id);
1105
1106 let secrets = Secrets {
1107 client: hkdf_expand_label_block(hs_secret.as_ref(), CLIENT_LABEL, &[]),
1108 server: hkdf_expand_label_block(hs_secret.as_ref(), SERVER_LABEL, &[]),
1109 suite,
1110 quic,
1111 side,
1112 version,
1113 };
1114 Self::new(&secrets)
1115 }
1116
1117 fn new(secrets: &Secrets) -> Self {
1118 let (local, remote) = secrets.local_remote();
1119 Self {
1120 local: DirectionalKeys::new(secrets.suite, secrets.quic, local, secrets.version),
1121 remote: DirectionalKeys::new(secrets.suite, secrets.quic, remote, secrets.version),
1122 }
1123 }
1124}
1125
1126#[expect(clippy::exhaustive_enums)]
1140pub enum KeyChange {
1141 Handshake {
1143 keys: Keys,
1145 },
1146 OneRtt {
1148 keys: Keys,
1150 next: Secrets,
1152 },
1153}
1154
1155#[non_exhaustive]
1159#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
1160pub enum Version {
1161 #[default]
1163 V1,
1164 V2,
1166}
1167
1168impl Version {
1169 fn initial_salt(self) -> &'static [u8; 20] {
1170 match self {
1171 Self::V1 => &[
1172 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8,
1174 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a,
1175 ],
1176 Self::V2 => &[
1177 0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26,
1179 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9,
1180 ],
1181 }
1182 }
1183
1184 pub(crate) fn packet_key_label(&self) -> &'static [u8] {
1186 match self {
1187 Self::V1 => b"quic key",
1188 Self::V2 => b"quicv2 key",
1189 }
1190 }
1191
1192 pub(crate) fn packet_iv_label(&self) -> &'static [u8] {
1194 match self {
1195 Self::V1 => b"quic iv",
1196 Self::V2 => b"quicv2 iv",
1197 }
1198 }
1199
1200 pub(crate) fn header_key_label(&self) -> &'static [u8] {
1202 match self {
1203 Self::V1 => b"quic hp",
1204 Self::V2 => b"quicv2 hp",
1205 }
1206 }
1207
1208 fn key_update_label(&self) -> &'static [u8] {
1209 match self {
1210 Self::V1 => b"quic ku",
1211 Self::V2 => b"quicv2 ku",
1212 }
1213 }
1214}
1215
1216#[cfg(all(test, any(target_arch = "aarch64", target_arch = "x86_64")))]
1217mod tests {
1218 use super::*;
1219 use crate::crypto::TLS13_TEST_SUITE;
1220 use crate::crypto::tls13::OkmBlock;
1221 use crate::quic::{HeaderProtectionKey, Secrets, Side, Version};
1222
1223 #[test]
1224 fn key_update_test_vector() {
1225 fn equal_okm(x: &OkmBlock, y: &OkmBlock) -> bool {
1226 x.as_ref() == y.as_ref()
1227 }
1228
1229 let mut secrets = Secrets {
1230 client: OkmBlock::new(
1232 &[
1233 0xb8, 0x76, 0x77, 0x08, 0xf8, 0x77, 0x23, 0x58, 0xa6, 0xea, 0x9f, 0xc4, 0x3e,
1234 0x4a, 0xdd, 0x2c, 0x96, 0x1b, 0x3f, 0x52, 0x87, 0xa6, 0xd1, 0x46, 0x7e, 0xe0,
1235 0xae, 0xab, 0x33, 0x72, 0x4d, 0xbf,
1236 ][..],
1237 ),
1238 server: OkmBlock::new(
1239 &[
1240 0x42, 0xdc, 0x97, 0x21, 0x40, 0xe0, 0xf2, 0xe3, 0x98, 0x45, 0xb7, 0x67, 0x61,
1241 0x34, 0x39, 0xdc, 0x67, 0x58, 0xca, 0x43, 0x25, 0x9b, 0x87, 0x85, 0x06, 0x82,
1242 0x4e, 0xb1, 0xe4, 0x38, 0xd8, 0x55,
1243 ][..],
1244 ),
1245 suite: TLS13_TEST_SUITE,
1246 quic: &FakeAlgorithm,
1247 side: Side::Client,
1248 version: Version::V1,
1249 };
1250 secrets.update();
1251
1252 assert!(equal_okm(
1253 &secrets.client,
1254 &OkmBlock::new(
1255 &[
1256 0x42, 0xca, 0xc8, 0xc9, 0x1c, 0xd5, 0xeb, 0x40, 0x68, 0x2e, 0x43, 0x2e, 0xdf,
1257 0x2d, 0x2b, 0xe9, 0xf4, 0x1a, 0x52, 0xca, 0x6b, 0x22, 0xd8, 0xe6, 0xcd, 0xb1,
1258 0xe8, 0xac, 0xa9, 0x6, 0x1f, 0xce
1259 ][..]
1260 )
1261 ));
1262 assert!(equal_okm(
1263 &secrets.server,
1264 &OkmBlock::new(
1265 &[
1266 0xeb, 0x7f, 0x5e, 0x2a, 0x12, 0x3f, 0x40, 0x7d, 0xb4, 0x99, 0xe3, 0x61, 0xca,
1267 0xe5, 0x90, 0xd4, 0xd9, 0x92, 0xe1, 0x4b, 0x7a, 0xce, 0x3, 0xc2, 0x44, 0xe0,
1268 0x42, 0x21, 0x15, 0xb6, 0xd3, 0x8a
1269 ][..]
1270 )
1271 ));
1272 }
1273
1274 struct FakeAlgorithm;
1275
1276 impl Algorithm for FakeAlgorithm {
1277 fn packet_key(&self, _key: AeadKey, _iv: Iv) -> Box<dyn PacketKey> {
1278 unimplemented!()
1279 }
1280
1281 fn header_protection_key(&self, _key: AeadKey) -> Box<dyn HeaderProtectionKey> {
1282 unimplemented!()
1283 }
1284
1285 fn aead_key_len(&self) -> usize {
1286 16
1287 }
1288 }
1289
1290 #[test]
1291 fn auto_traits() {
1292 fn assert_auto<T: Send + Sync>() {}
1293 assert_auto::<Box<dyn PacketKey>>();
1294 assert_auto::<Box<dyn HeaderProtectionKey>>();
1295 }
1296}