1use alloc::boxed::Box;
2use alloc::vec::Vec;
3use core::ops::Deref;
4use core::{fmt, mem};
5
6use pki_types::FipsStatus;
7
8pub use crate::common_state::Side;
9use crate::common_state::{ConnectionOutputs, Protocol};
10use crate::conn::{
11 Accepted, ClientNext, Connection, MessageIter, MessageIterMode, ServerNext, SideData,
12 Transport, VerifyPeerIdentity, sealed,
13};
14use crate::crypto::cipher::{AeadKey, Iv, Payload};
15use crate::crypto::tls13::{Hkdf, HkdfExpander, OkmBlock};
16use crate::error::{ApiMisuse, Error};
17use crate::msgs::{Message, MessagePayload, ServerExtensionsInput, TransportParameters};
18use crate::server::{ServerConfig, ServerSide};
19use crate::suites::SupportedCipherSuite;
20use crate::sync::Arc;
21use crate::tls13::Tls13CipherSuite;
22use crate::tls13::key_schedule::{
23 hkdf_expand_label, hkdf_expand_label_aead_key, hkdf_expand_label_block,
24};
25use crate::{ClientSide, TlsInputBuffer};
26impl Connection<ServerSide, Quic> {
27 pub fn new_quic(
32 config: Arc<ServerConfig>,
33 version: Version,
34 params: Vec<u8>,
35 ) -> Result<Self, Error> {
36 check_server_config(&config)?;
37 let exts = ServerExtensionsInput {
38 transport_parameters: Some(match version {
39 Version::V1 | Version::V2 => TransportParameters::Quic(Payload::new(params)),
40 }),
41 };
42
43 Self::for_server(
44 config,
45 exts,
46 Quic {
47 version,
48 ..Quic::default()
49 },
50 )
51 }
52}
53
54#[non_exhaustive]
60#[derive(Debug)]
61pub enum ClientHandshake {
62 NeedsInput(NeedsInput<ClientSide>),
64
65 VerifyServerIdentity(VerifyPeerIdentity<ClientSide, Quic>),
69
70 Complete(Connection<ClientSide, Quic>),
72}
73
74impl FromConn<ClientSide> for ClientHandshake {
75 fn from_conn(
76 mut conn: Connection<ClientSide, Quic>,
77 output: &mut Vec<QuicEvent>,
78 ) -> Result<Self, Error> {
79 output.extend(conn.transport.events());
80
81 Ok(match ClientNext::try_from(conn)? {
82 ClientNext::NeedsInput(conn) => Self::NeedsInput(NeedsInput(conn)),
83
84 ClientNext::VerifyServerIdentity(verify) => Self::VerifyServerIdentity(verify),
85
86 ClientNext::Complete(conn) => Self::Complete(conn),
87 })
88 }
89}
90
91#[non_exhaustive]
93#[derive(Debug)]
94pub enum ServerHandshake {
95 NeedsInput(NeedsInput<ServerSide>),
97
98 Accepted(Accepted<Quic>),
103
104 VerifyClientIdentity(VerifyPeerIdentity<ServerSide, Quic>),
108
109 Complete(Connection<ServerSide, Quic>),
111}
112
113impl ServerHandshake {
114 pub fn start(version: Version) -> NeedsInput<ServerSide> {
124 NeedsInput(Connection::for_acceptor(Quic {
125 version,
126 ..Quic::default()
127 }))
128 }
129}
130
131impl FromConn<ServerSide> for ServerHandshake {
132 fn from_conn(
133 mut conn: Connection<ServerSide, Quic>,
134 output: &mut Vec<QuicEvent>,
135 ) -> Result<Self, Error> {
136 output.extend(conn.transport.events());
137
138 Ok(match ServerNext::try_from(conn)? {
139 ServerNext::NeedsInput(conn) => Self::NeedsInput(NeedsInput(conn)),
140
141 ServerNext::ChooseConfig(accepted) => Self::Accepted(accepted),
142
143 ServerNext::VerifyClientIdentity(verify) => Self::VerifyClientIdentity(verify),
144
145 ServerNext::Complete(conn) => Self::Complete(conn),
146 })
147 }
148}
149
150impl Accepted<Quic> {
151 pub fn choose_config(
161 self,
162 config: Arc<ServerConfig>,
163 params: Vec<u8>,
164 output: &mut Vec<QuicEvent>,
165 ) -> Result<ServerHandshake, Error> {
166 check_server_config(&config)?;
167
168 let exts = ServerExtensionsInput {
169 transport_parameters: Some(match self.conn.transport.version {
170 Version::V1 | Version::V2 => TransportParameters::Quic(Payload::new(params)),
171 }),
172 };
173
174 let mut tls = Vec::new();
175 let conn = self.partial_choose_config(config, exts, &mut tls)?;
176
177 debug_assert!(tls.is_empty());
179 ServerHandshake::from_conn(conn, output)
180 }
181}
182
183pub(crate) trait FromConn<Side: SideData> {
184 fn from_conn(
185 conn: Connection<Side, Quic>,
186 output: &mut Vec<QuicEvent>,
187 ) -> Result<Side::QuicHandshake, Error>;
188}
189
190pub struct NeedsInput<Side: SideData>(pub(crate) Connection<Side, Quic>);
197
198impl<Side: SideData> NeedsInput<Side> {
199 pub fn quic_transport_parameters(&self) -> Option<&[u8]> {
205 self.0.transport.transport_parameters()
206 }
207
208 pub fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
210 self.0.transport.zero_rtt_keys(&self.0)
211 }
212
213 pub fn process(
231 mut self,
232 input: &mut dyn TlsInputBuffer,
233 output: &mut Vec<QuicEvent>,
234 ) -> Result<Side::QuicHandshake, Error> {
235 self.0
236 .common
237 .recv
238 .deframer
239 .input_quic(input.slice_mut())?;
240
241 Side::QuicHandshake::from_conn(
242 self.0
243 .process(input, &mut Vec::new())?
244 .into_progress()?,
245 output,
246 )
247 }
248
249 pub fn side(&self) -> &Side {
251 &self.0.side
252 }
253}
254
255impl<Side: SideData> Deref for NeedsInput<Side> {
256 type Target = ConnectionOutputs;
257
258 fn deref(&self) -> &Self::Target {
259 self.0.deref()
260 }
261}
262
263impl<Side: SideData> fmt::Debug for NeedsInput<Side> {
264 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
265 f.debug_struct("quic::NeedsInput")
266 .finish_non_exhaustive()
267 }
268}
269
270fn check_server_config(config: &ServerConfig) -> Result<(), Error> {
271 let suites = &config.provider.tls13_cipher_suites;
272 if suites.is_empty() {
273 return Err(ApiMisuse::QuicRequiresTls13Support.into());
274 }
275
276 if !suites
277 .iter()
278 .any(|scs| scs.quic.is_some())
279 {
280 return Err(ApiMisuse::NoQuicCompatibleCipherSuites.into());
281 }
282
283 if config.max_early_data_size != 0 && config.max_early_data_size != 0xffff_ffff {
284 return Err(ApiMisuse::QuicRestrictsMaxEarlyDataSize.into());
285 }
286
287 Ok(())
288}
289
290#[expect(clippy::large_enum_variant)]
292#[derive(Debug)]
293#[non_exhaustive]
294pub enum QuicEvent {
295 Message(Vec<u8>),
297
298 KeyChange(KeyChange),
300}
301
302impl<Side: SideData> Connection<Side, Quic> {
303 pub fn read_hs(&mut self, input: &mut dyn TlsInputBuffer) -> Result<(), Error> {
310 self.common
311 .recv
312 .deframer
313 .input_quic(input.slice_mut())?;
314
315 let mut tls = Vec::new();
316 let mut iter = MessageIter::new(input, &mut tls, self, MessageIterMode::All);
317
318 let result = match iter.next(false) {
319 Some(Ok(_)) | None => Ok(()),
320 Some(Err(e)) => Err(e),
321 };
322
323 input.discard(self.common.recv.deframer.take_discard());
324 result
325 }
326
327 pub fn events(&mut self) -> impl Iterator<Item = QuicEvent> {
331 self.transport.events()
332 }
333
334 pub fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
336 self.transport.zero_rtt_keys(self)
337 }
338
339 pub fn quic_transport_parameters(&self) -> Option<&[u8]> {
347 self.transport.transport_parameters()
348 }
349}
350
351#[derive(Default)]
353pub struct Quic {
354 pub(crate) version: Version,
355 pub(crate) params: Option<Vec<u8>>,
357 pub(crate) events: Vec<QuicEvent>,
358 pub(crate) early_secret: Option<OkmBlock>,
359}
360
361impl Quic {
362 pub(crate) fn send_msg(&mut self, m: Message<'_>, _must_encrypt: bool) {
363 if let MessagePayload::Alert(_) = m.payload {
364 return;
366 }
367
368 debug_assert!(
369 matches!(
370 m.payload,
371 MessagePayload::Handshake { .. } | MessagePayload::HandshakeFlight(_)
372 ),
373 "QUIC uses TLS for the cryptographic handshake only"
374 );
375 let mut bytes = Vec::new();
376 m.payload.encode(&mut bytes);
377 self.events
378 .push(QuicEvent::Message(bytes));
379 }
380
381 pub(crate) fn events(&mut self) -> impl Iterator<Item = QuicEvent> {
382 mem::take(&mut self.events).into_iter()
383 }
384
385 fn zero_rtt_keys(&self, outputs: &ConnectionOutputs) -> Option<DirectionalKeys> {
386 let suite = outputs
387 .negotiated_cipher_suite()
388 .and_then(|suite| match suite {
389 SupportedCipherSuite::Tls13(suite) => Some(suite),
390 _ => None,
391 })?;
392
393 let suite = Suite {
394 inner: suite,
395 quic: suite.quic?,
396 };
397
398 Some(DirectionalKeys::new(
399 suite,
400 self.early_secret.as_ref()?,
401 self.version,
402 ))
403 }
404
405 fn transport_parameters(&self) -> Option<&[u8]> {
406 self.params.as_ref().map(|v| v.as_ref())
407 }
408}
409
410impl Transport for Quic {}
411
412impl sealed::Transport for Quic {
413 fn protocol(&self) -> Protocol {
414 Protocol::Quic(self.version)
415 }
416
417 fn quic(&mut self) -> Option<&mut dyn QuicOutput> {
418 Some(self)
419 }
420}
421
422impl QuicOutput for Quic {
423 fn transport_parameters(&mut self, params: Vec<u8>) {
424 self.params = Some(params);
425 }
426
427 fn early_secret(&mut self, secret: Option<OkmBlock>) {
428 self.early_secret = secret;
429 }
430
431 fn handshake_secrets(&mut self, secrets: SecretUpdate) {
432 self.events
433 .push(QuicEvent::KeyChange(KeyChange::Handshake {
434 keys: Keys::new(&Secrets::new(secrets, self.version)),
435 }));
436 }
437
438 fn traffic_secrets(&mut self, secrets: SecretUpdate) {
439 let mut secrets = Secrets::new(secrets, self.version);
440 let keys = Keys::new(&secrets);
441 secrets.update();
442 self.events
443 .push(QuicEvent::KeyChange(KeyChange::OneRtt {
444 keys,
445 next: secrets,
446 }));
447 }
448
449 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool) {
450 self.send_msg(m, must_encrypt);
451 }
452}
453
454pub(crate) trait QuicOutput {
455 fn transport_parameters(&mut self, params: Vec<u8>);
456
457 fn early_secret(&mut self, secret: Option<OkmBlock>);
458
459 fn handshake_secrets(&mut self, secrets: SecretUpdate);
460
461 fn traffic_secrets(&mut self, secrets: SecretUpdate);
462
463 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool);
464}
465
466#[derive(Clone)]
468pub struct Secrets {
469 pub(crate) client: OkmBlock,
471 pub(crate) server: OkmBlock,
473 suite: Suite,
475 side: Side,
476 version: Version,
477}
478
479impl Secrets {
480 pub(crate) fn new(update: SecretUpdate, version: Version) -> Self {
481 Self {
482 client: update.client,
483 server: update.server,
484 suite: update.suite,
485 side: update.side,
486 version,
487 }
488 }
489
490 pub fn next_packet_keys(&mut self) -> PacketKeySet {
492 let keys = PacketKeySet::new(self);
493 self.update();
494 keys
495 }
496
497 pub(crate) fn update(&mut self) {
498 self.client = hkdf_expand_label_block(
499 self.suite
500 .inner
501 .hkdf_provider
502 .expander_for_okm(&self.client)
503 .as_ref(),
504 self.version.key_update_label(),
505 &[],
506 );
507 self.server = hkdf_expand_label_block(
508 self.suite
509 .inner
510 .hkdf_provider
511 .expander_for_okm(&self.server)
512 .as_ref(),
513 self.version.key_update_label(),
514 &[],
515 );
516 }
517
518 fn local_remote(&self) -> (&OkmBlock, &OkmBlock) {
519 match self.side {
520 Side::Client => (&self.client, &self.server),
521 Side::Server => (&self.server, &self.client),
522 }
523 }
524}
525
526pub(crate) struct SecretUpdate {
527 pub(crate) client: OkmBlock,
528 pub(crate) server: OkmBlock,
529 pub(crate) suite: Suite,
530 pub(crate) side: Side,
531}
532
533#[expect(clippy::exhaustive_structs)]
535pub struct DirectionalKeys {
536 pub header: Box<dyn HeaderProtectionKey>,
538 pub packet: Box<dyn PacketKey>,
540}
541
542impl DirectionalKeys {
543 pub(crate) fn new(suite: Suite, secret: &OkmBlock, version: Version) -> Self {
544 let builder = KeyBuilder::new(secret, version, suite.quic, suite.inner.hkdf_provider);
545 Self {
546 header: builder.header_protection_key(),
547 packet: builder.packet_key(),
548 }
549 }
550}
551
552const TAG_LEN: usize = 16;
554
555pub struct Tag([u8; TAG_LEN]);
557
558impl From<&[u8]> for Tag {
559 fn from(value: &[u8]) -> Self {
560 let mut array = [0u8; TAG_LEN];
561 array.copy_from_slice(value);
562 Self(array)
563 }
564}
565
566impl AsRef<[u8]> for Tag {
567 fn as_ref(&self) -> &[u8] {
568 &self.0
569 }
570}
571
572pub trait Algorithm: Send + Sync {
574 fn packet_key(&self, key: AeadKey, iv: Iv) -> Box<dyn PacketKey>;
578
579 fn header_protection_key(&self, key: AeadKey) -> Box<dyn HeaderProtectionKey>;
583
584 fn aead_key_len(&self) -> usize;
589
590 fn fips(&self) -> FipsStatus {
592 FipsStatus::Unvalidated
593 }
594}
595
596pub trait HeaderProtectionKey: Send + Sync {
598 fn encrypt_in_place(
619 &self,
620 sample: &[u8],
621 first: &mut u8,
622 packet_number: &mut [u8],
623 ) -> Result<(), Error>;
624
625 fn decrypt_in_place(
647 &self,
648 sample: &[u8],
649 first: &mut u8,
650 packet_number: &mut [u8],
651 ) -> Result<(), Error>;
652
653 fn sample_len(&self) -> usize;
655}
656
657pub trait PacketKey: Send + Sync {
659 fn encrypt_in_place(
670 &self,
671 packet_number: u64,
672 header: &[u8],
673 payload: &mut [u8],
674 path_id: Option<u32>,
675 ) -> Result<Tag, Error>;
676
677 fn decrypt_in_place<'a>(
688 &self,
689 packet_number: u64,
690 header: &[u8],
691 payload: &'a mut [u8],
692 path_id: Option<u32>,
693 ) -> Result<&'a [u8], Error>;
694
695 fn tag_len(&self) -> usize;
697
698 fn confidentiality_limit(&self) -> u64;
709
710 fn integrity_limit(&self) -> u64;
719}
720
721#[expect(clippy::exhaustive_structs)]
723pub struct PacketKeySet {
724 pub local: Box<dyn PacketKey>,
726 pub remote: Box<dyn PacketKey>,
728}
729
730impl PacketKeySet {
731 fn new(secrets: &Secrets) -> Self {
732 let (local, remote) = secrets.local_remote();
733 let (version, alg, hkdf) = (
734 secrets.version,
735 secrets.suite.quic,
736 secrets.suite.inner.hkdf_provider,
737 );
738
739 Self {
740 local: KeyBuilder::new(local, version, alg, hkdf).packet_key(),
741 remote: KeyBuilder::new(remote, version, alg, hkdf).packet_key(),
742 }
743 }
744}
745
746pub struct KeyBuilder<'a> {
748 expander: Box<dyn HkdfExpander>,
749 version: Version,
750 alg: &'a dyn Algorithm,
751}
752
753impl<'a> KeyBuilder<'a> {
754 pub fn new(
756 secret: &OkmBlock,
757 version: Version,
758 alg: &'a dyn Algorithm,
759 hkdf: &'a dyn Hkdf,
760 ) -> Self {
761 Self {
762 expander: hkdf.expander_for_okm(secret),
763 version,
764 alg,
765 }
766 }
767
768 pub fn packet_key(&self) -> Box<dyn PacketKey> {
770 let aead_key_len = self.alg.aead_key_len();
771 let packet_key = hkdf_expand_label_aead_key(
772 self.expander.as_ref(),
773 aead_key_len,
774 self.version.packet_key_label(),
775 &[],
776 );
777
778 let packet_iv =
779 hkdf_expand_label(self.expander.as_ref(), self.version.packet_iv_label(), &[]);
780 self.alg
781 .packet_key(packet_key, packet_iv)
782 }
783
784 pub fn header_protection_key(&self) -> Box<dyn HeaderProtectionKey> {
786 let header_key = hkdf_expand_label_aead_key(
787 self.expander.as_ref(),
788 self.alg.aead_key_len(),
789 self.version.header_key_label(),
790 &[],
791 );
792 self.alg
793 .header_protection_key(header_key)
794 }
795}
796
797#[non_exhaustive]
799#[derive(Clone, Copy)]
800pub struct Suite {
801 pub inner: &'static Tls13CipherSuite,
803 pub quic: &'static dyn Algorithm,
805}
806
807impl Suite {
808 pub fn keys(&self, client_dst_connection_id: &[u8], side: Side, version: Version) -> Keys {
810 Keys::initial(version, *self, client_dst_connection_id, side)
811 }
812}
813
814impl TryFrom<&'static Tls13CipherSuite> for Suite {
815 type Error = ApiMisuse;
816
817 fn try_from(suite: &'static Tls13CipherSuite) -> Result<Self, Self::Error> {
818 Ok(Self {
819 inner: suite,
820 quic: suite
821 .quic
822 .ok_or(ApiMisuse::NoQuicCompatibleCipherSuites)?,
823 })
824 }
825}
826
827impl fmt::Debug for Suite {
828 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
829 f.debug_struct("Suite")
830 .field("inner", &self.inner)
831 .finish_non_exhaustive()
832 }
833}
834
835#[expect(clippy::exhaustive_structs)]
837pub struct Keys {
838 pub local: DirectionalKeys,
840 pub remote: DirectionalKeys,
842}
843
844impl Keys {
845 pub fn initial(
847 version: Version,
848 suite: Suite,
849 client_dst_connection_id: &[u8],
850 side: Side,
851 ) -> Self {
852 const CLIENT_LABEL: &[u8] = b"client in";
853 const SERVER_LABEL: &[u8] = b"server in";
854 let salt = version.initial_salt();
855 let hs_secret = suite
856 .inner
857 .hkdf_provider
858 .extract_from_secret(Some(salt), client_dst_connection_id);
859
860 let secrets = Secrets {
861 client: hkdf_expand_label_block(hs_secret.as_ref(), CLIENT_LABEL, &[]),
862 server: hkdf_expand_label_block(hs_secret.as_ref(), SERVER_LABEL, &[]),
863 suite,
864 side,
865 version,
866 };
867
868 Self::new(&secrets)
869 }
870
871 fn new(secrets: &Secrets) -> Self {
872 let (local, remote) = secrets.local_remote();
873 Self {
874 local: DirectionalKeys::new(secrets.suite, local, secrets.version),
875 remote: DirectionalKeys::new(secrets.suite, remote, secrets.version),
876 }
877 }
878}
879
880#[expect(clippy::exhaustive_enums)]
894pub enum KeyChange {
895 Handshake {
897 keys: Keys,
899 },
900 OneRtt {
902 keys: Keys,
904 next: Secrets,
906 },
907}
908
909impl fmt::Debug for KeyChange {
910 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
911 match self {
912 Self::Handshake { .. } => f
913 .debug_struct("Handshake")
914 .finish_non_exhaustive(),
915 Self::OneRtt { .. } => f
916 .debug_struct("OneRtt")
917 .finish_non_exhaustive(),
918 }
919 }
920}
921
922#[non_exhaustive]
926#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
927pub enum Version {
928 #[default]
930 V1,
931 V2,
933}
934
935impl Version {
936 fn initial_salt(self) -> &'static [u8; 20] {
937 match self {
938 Self::V1 => &[
939 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8,
941 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a,
942 ],
943 Self::V2 => &[
944 0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26,
946 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9,
947 ],
948 }
949 }
950
951 pub(crate) fn packet_key_label(&self) -> &'static [u8] {
953 match self {
954 Self::V1 => b"quic key",
955 Self::V2 => b"quicv2 key",
956 }
957 }
958
959 pub(crate) fn packet_iv_label(&self) -> &'static [u8] {
961 match self {
962 Self::V1 => b"quic iv",
963 Self::V2 => b"quicv2 iv",
964 }
965 }
966
967 pub(crate) fn header_key_label(&self) -> &'static [u8] {
969 match self {
970 Self::V1 => b"quic hp",
971 Self::V2 => b"quicv2 hp",
972 }
973 }
974
975 fn key_update_label(&self) -> &'static [u8] {
976 match self {
977 Self::V1 => b"quic ku",
978 Self::V2 => b"quicv2 ku",
979 }
980 }
981}
982
983#[cfg(all(test, any(target_arch = "aarch64", target_arch = "x86_64")))]
984mod tests {
985 use super::*;
986 use crate::crypto::TLS13_TEST_SUITE;
987 use crate::crypto::tls13::OkmBlock;
988 use crate::quic::{HeaderProtectionKey, Side, Version};
989
990 #[test]
991 fn key_update_test_vector() {
992 fn equal_okm(x: &OkmBlock, y: &OkmBlock) -> bool {
993 x.as_ref() == y.as_ref()
994 }
995
996 let mut secrets = Secrets {
997 client: OkmBlock::new(
999 &[
1000 0xb8, 0x76, 0x77, 0x08, 0xf8, 0x77, 0x23, 0x58, 0xa6, 0xea, 0x9f, 0xc4, 0x3e,
1001 0x4a, 0xdd, 0x2c, 0x96, 0x1b, 0x3f, 0x52, 0x87, 0xa6, 0xd1, 0x46, 0x7e, 0xe0,
1002 0xae, 0xab, 0x33, 0x72, 0x4d, 0xbf,
1003 ][..],
1004 ),
1005 server: OkmBlock::new(
1006 &[
1007 0x42, 0xdc, 0x97, 0x21, 0x40, 0xe0, 0xf2, 0xe3, 0x98, 0x45, 0xb7, 0x67, 0x61,
1008 0x34, 0x39, 0xdc, 0x67, 0x58, 0xca, 0x43, 0x25, 0x9b, 0x87, 0x85, 0x06, 0x82,
1009 0x4e, 0xb1, 0xe4, 0x38, 0xd8, 0x55,
1010 ][..],
1011 ),
1012 suite: Suite {
1013 inner: TLS13_TEST_SUITE,
1014 quic: &FakeAlgorithm,
1015 },
1016 side: Side::Client,
1017 version: Version::V1,
1018 };
1019 secrets.update();
1020
1021 assert!(equal_okm(
1022 &secrets.client,
1023 &OkmBlock::new(
1024 &[
1025 0x42, 0xca, 0xc8, 0xc9, 0x1c, 0xd5, 0xeb, 0x40, 0x68, 0x2e, 0x43, 0x2e, 0xdf,
1026 0x2d, 0x2b, 0xe9, 0xf4, 0x1a, 0x52, 0xca, 0x6b, 0x22, 0xd8, 0xe6, 0xcd, 0xb1,
1027 0xe8, 0xac, 0xa9, 0x6, 0x1f, 0xce
1028 ][..]
1029 )
1030 ));
1031 assert!(equal_okm(
1032 &secrets.server,
1033 &OkmBlock::new(
1034 &[
1035 0xeb, 0x7f, 0x5e, 0x2a, 0x12, 0x3f, 0x40, 0x7d, 0xb4, 0x99, 0xe3, 0x61, 0xca,
1036 0xe5, 0x90, 0xd4, 0xd9, 0x92, 0xe1, 0x4b, 0x7a, 0xce, 0x3, 0xc2, 0x44, 0xe0,
1037 0x42, 0x21, 0x15, 0xb6, 0xd3, 0x8a
1038 ][..]
1039 )
1040 ));
1041 }
1042
1043 struct FakeAlgorithm;
1044
1045 impl Algorithm for FakeAlgorithm {
1046 fn packet_key(&self, _key: AeadKey, _iv: Iv) -> Box<dyn PacketKey> {
1047 unimplemented!()
1048 }
1049
1050 fn header_protection_key(&self, _key: AeadKey) -> Box<dyn HeaderProtectionKey> {
1051 unimplemented!()
1052 }
1053
1054 fn aead_key_len(&self) -> usize {
1055 16
1056 }
1057 }
1058
1059 #[test]
1060 fn auto_traits() {
1061 fn assert_auto<T: Send + Sync>() {}
1062 assert_auto::<Box<dyn PacketKey>>();
1063 assert_auto::<Box<dyn HeaderProtectionKey>>();
1064 }
1065}