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 self.0.process(input, &mut Vec::new())?;
242 Side::QuicHandshake::from_conn(self.0, output)
243 }
244
245 pub fn side(&self) -> &Side {
247 &self.0.side
248 }
249}
250
251impl<Side: SideData> Deref for NeedsInput<Side> {
252 type Target = ConnectionOutputs;
253
254 fn deref(&self) -> &Self::Target {
255 self.0.deref()
256 }
257}
258
259impl<Side: SideData> fmt::Debug for NeedsInput<Side> {
260 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
261 f.debug_struct("quic::NeedsInput")
262 .finish_non_exhaustive()
263 }
264}
265
266fn check_server_config(config: &ServerConfig) -> Result<(), Error> {
267 let suites = &config.provider.tls13_cipher_suites;
268 if suites.is_empty() {
269 return Err(ApiMisuse::QuicRequiresTls13Support.into());
270 }
271
272 if !suites
273 .iter()
274 .any(|scs| scs.quic.is_some())
275 {
276 return Err(ApiMisuse::NoQuicCompatibleCipherSuites.into());
277 }
278
279 if config.max_early_data_size != 0 && config.max_early_data_size != 0xffff_ffff {
280 return Err(ApiMisuse::QuicRestrictsMaxEarlyDataSize.into());
281 }
282
283 Ok(())
284}
285
286#[expect(clippy::large_enum_variant)]
288#[derive(Debug)]
289#[non_exhaustive]
290pub enum QuicEvent {
291 Message(Vec<u8>),
293
294 KeyChange(KeyChange),
296}
297
298impl<Side: SideData> Connection<Side, Quic> {
299 pub fn read_hs(&mut self, input: &mut dyn TlsInputBuffer) -> Result<(), Error> {
306 self.common
307 .recv
308 .deframer
309 .input_quic(input.slice_mut())?;
310
311 let mut tls = Vec::new();
312 let mut iter = MessageIter::new(input, &mut tls, self, MessageIterMode::All);
313
314 let result = match iter.next(false) {
315 Some(Ok(_)) | None => Ok(()),
316 Some(Err(e)) => Err(e),
317 };
318
319 input.discard(self.common.recv.deframer.take_discard());
320 result
321 }
322
323 pub fn events(&mut self) -> impl Iterator<Item = QuicEvent> {
327 self.transport.events()
328 }
329
330 pub fn zero_rtt_keys(&self) -> Option<DirectionalKeys> {
332 self.transport.zero_rtt_keys(self)
333 }
334
335 pub fn quic_transport_parameters(&self) -> Option<&[u8]> {
343 self.transport.transport_parameters()
344 }
345}
346
347#[derive(Default)]
349pub struct Quic {
350 pub(crate) version: Version,
351 pub(crate) params: Option<Vec<u8>>,
353 pub(crate) events: Vec<QuicEvent>,
354 pub(crate) early_secret: Option<OkmBlock>,
355}
356
357impl Quic {
358 pub(crate) fn send_msg(&mut self, m: Message<'_>, _must_encrypt: bool) {
359 if let MessagePayload::Alert(_) = m.payload {
360 return;
362 }
363
364 debug_assert!(
365 matches!(
366 m.payload,
367 MessagePayload::Handshake { .. } | MessagePayload::HandshakeFlight(_)
368 ),
369 "QUIC uses TLS for the cryptographic handshake only"
370 );
371 let mut bytes = Vec::new();
372 m.payload.encode(&mut bytes);
373 self.events
374 .push(QuicEvent::Message(bytes));
375 }
376
377 pub(crate) fn events(&mut self) -> impl Iterator<Item = QuicEvent> {
378 mem::take(&mut self.events).into_iter()
379 }
380
381 fn zero_rtt_keys(&self, outputs: &ConnectionOutputs) -> Option<DirectionalKeys> {
382 let suite = outputs
383 .negotiated_cipher_suite()
384 .and_then(|suite| match suite {
385 SupportedCipherSuite::Tls13(suite) => Some(suite),
386 _ => None,
387 })?;
388
389 let suite = Suite {
390 inner: suite,
391 quic: suite.quic?,
392 };
393
394 Some(DirectionalKeys::new(
395 suite,
396 self.early_secret.as_ref()?,
397 self.version,
398 ))
399 }
400
401 fn transport_parameters(&self) -> Option<&[u8]> {
402 self.params.as_ref().map(|v| v.as_ref())
403 }
404}
405
406impl Transport for Quic {}
407
408impl sealed::Transport for Quic {
409 fn protocol(&self) -> Protocol {
410 Protocol::Quic(self.version)
411 }
412
413 fn quic(&mut self) -> Option<&mut dyn QuicOutput> {
414 Some(self)
415 }
416}
417
418impl QuicOutput for Quic {
419 fn transport_parameters(&mut self, params: Vec<u8>) {
420 self.params = Some(params);
421 }
422
423 fn early_secret(&mut self, secret: Option<OkmBlock>) {
424 self.early_secret = secret;
425 }
426
427 fn handshake_secrets(&mut self, secrets: SecretUpdate) {
428 self.events
429 .push(QuicEvent::KeyChange(KeyChange::Handshake {
430 keys: Keys::new(&Secrets::new(secrets, self.version)),
431 }));
432 }
433
434 fn traffic_secrets(&mut self, secrets: SecretUpdate) {
435 let mut secrets = Secrets::new(secrets, self.version);
436 let keys = Keys::new(&secrets);
437 secrets.update();
438 self.events
439 .push(QuicEvent::KeyChange(KeyChange::OneRtt {
440 keys,
441 next: secrets,
442 }));
443 }
444
445 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool) {
446 self.send_msg(m, must_encrypt);
447 }
448}
449
450pub(crate) trait QuicOutput {
451 fn transport_parameters(&mut self, params: Vec<u8>);
452
453 fn early_secret(&mut self, secret: Option<OkmBlock>);
454
455 fn handshake_secrets(&mut self, secrets: SecretUpdate);
456
457 fn traffic_secrets(&mut self, secrets: SecretUpdate);
458
459 fn send_msg(&mut self, m: Message<'_>, must_encrypt: bool);
460}
461
462#[derive(Clone)]
464pub struct Secrets {
465 pub(crate) client: OkmBlock,
467 pub(crate) server: OkmBlock,
469 suite: Suite,
471 side: Side,
472 version: Version,
473}
474
475impl Secrets {
476 pub(crate) fn new(update: SecretUpdate, version: Version) -> Self {
477 Self {
478 client: update.client,
479 server: update.server,
480 suite: update.suite,
481 side: update.side,
482 version,
483 }
484 }
485
486 pub fn next_packet_keys(&mut self) -> PacketKeySet {
488 let keys = PacketKeySet::new(self);
489 self.update();
490 keys
491 }
492
493 pub(crate) fn update(&mut self) {
494 self.client = hkdf_expand_label_block(
495 self.suite
496 .inner
497 .hkdf_provider
498 .expander_for_okm(&self.client)
499 .as_ref(),
500 self.version.key_update_label(),
501 &[],
502 );
503 self.server = hkdf_expand_label_block(
504 self.suite
505 .inner
506 .hkdf_provider
507 .expander_for_okm(&self.server)
508 .as_ref(),
509 self.version.key_update_label(),
510 &[],
511 );
512 }
513
514 fn local_remote(&self) -> (&OkmBlock, &OkmBlock) {
515 match self.side {
516 Side::Client => (&self.client, &self.server),
517 Side::Server => (&self.server, &self.client),
518 }
519 }
520}
521
522pub(crate) struct SecretUpdate {
523 pub(crate) client: OkmBlock,
524 pub(crate) server: OkmBlock,
525 pub(crate) suite: Suite,
526 pub(crate) side: Side,
527}
528
529#[expect(clippy::exhaustive_structs)]
531pub struct DirectionalKeys {
532 pub header: Box<dyn HeaderProtectionKey>,
534 pub packet: Box<dyn PacketKey>,
536}
537
538impl DirectionalKeys {
539 pub(crate) fn new(suite: Suite, secret: &OkmBlock, version: Version) -> Self {
540 let builder = KeyBuilder::new(secret, version, suite.quic, suite.inner.hkdf_provider);
541 Self {
542 header: builder.header_protection_key(),
543 packet: builder.packet_key(),
544 }
545 }
546}
547
548const TAG_LEN: usize = 16;
550
551pub struct Tag([u8; TAG_LEN]);
553
554impl From<&[u8]> for Tag {
555 fn from(value: &[u8]) -> Self {
556 let mut array = [0u8; TAG_LEN];
557 array.copy_from_slice(value);
558 Self(array)
559 }
560}
561
562impl AsRef<[u8]> for Tag {
563 fn as_ref(&self) -> &[u8] {
564 &self.0
565 }
566}
567
568pub trait Algorithm: Send + Sync {
570 fn packet_key(&self, key: AeadKey, iv: Iv) -> Box<dyn PacketKey>;
574
575 fn header_protection_key(&self, key: AeadKey) -> Box<dyn HeaderProtectionKey>;
579
580 fn aead_key_len(&self) -> usize;
585
586 fn fips(&self) -> FipsStatus {
588 FipsStatus::Unvalidated
589 }
590}
591
592pub trait HeaderProtectionKey: Send + Sync {
594 fn encrypt_in_place(
615 &self,
616 sample: &[u8],
617 first: &mut u8,
618 packet_number: &mut [u8],
619 ) -> Result<(), Error>;
620
621 fn decrypt_in_place(
643 &self,
644 sample: &[u8],
645 first: &mut u8,
646 packet_number: &mut [u8],
647 ) -> Result<(), Error>;
648
649 fn sample_len(&self) -> usize;
651}
652
653pub trait PacketKey: Send + Sync {
655 fn encrypt_in_place(
666 &self,
667 packet_number: u64,
668 header: &[u8],
669 payload: &mut [u8],
670 path_id: Option<u32>,
671 ) -> Result<Tag, Error>;
672
673 fn decrypt_in_place<'a>(
684 &self,
685 packet_number: u64,
686 header: &[u8],
687 payload: &'a mut [u8],
688 path_id: Option<u32>,
689 ) -> Result<&'a [u8], Error>;
690
691 fn tag_len(&self) -> usize;
693
694 fn confidentiality_limit(&self) -> u64;
705
706 fn integrity_limit(&self) -> u64;
715}
716
717#[expect(clippy::exhaustive_structs)]
719pub struct PacketKeySet {
720 pub local: Box<dyn PacketKey>,
722 pub remote: Box<dyn PacketKey>,
724}
725
726impl PacketKeySet {
727 fn new(secrets: &Secrets) -> Self {
728 let (local, remote) = secrets.local_remote();
729 let (version, alg, hkdf) = (
730 secrets.version,
731 secrets.suite.quic,
732 secrets.suite.inner.hkdf_provider,
733 );
734
735 Self {
736 local: KeyBuilder::new(local, version, alg, hkdf).packet_key(),
737 remote: KeyBuilder::new(remote, version, alg, hkdf).packet_key(),
738 }
739 }
740}
741
742pub struct KeyBuilder<'a> {
744 expander: Box<dyn HkdfExpander>,
745 version: Version,
746 alg: &'a dyn Algorithm,
747}
748
749impl<'a> KeyBuilder<'a> {
750 pub fn new(
752 secret: &OkmBlock,
753 version: Version,
754 alg: &'a dyn Algorithm,
755 hkdf: &'a dyn Hkdf,
756 ) -> Self {
757 Self {
758 expander: hkdf.expander_for_okm(secret),
759 version,
760 alg,
761 }
762 }
763
764 pub fn packet_key(&self) -> Box<dyn PacketKey> {
766 let aead_key_len = self.alg.aead_key_len();
767 let packet_key = hkdf_expand_label_aead_key(
768 self.expander.as_ref(),
769 aead_key_len,
770 self.version.packet_key_label(),
771 &[],
772 );
773
774 let packet_iv =
775 hkdf_expand_label(self.expander.as_ref(), self.version.packet_iv_label(), &[]);
776 self.alg
777 .packet_key(packet_key, packet_iv)
778 }
779
780 pub fn header_protection_key(&self) -> Box<dyn HeaderProtectionKey> {
782 let header_key = hkdf_expand_label_aead_key(
783 self.expander.as_ref(),
784 self.alg.aead_key_len(),
785 self.version.header_key_label(),
786 &[],
787 );
788 self.alg
789 .header_protection_key(header_key)
790 }
791}
792
793#[non_exhaustive]
795#[derive(Clone, Copy)]
796pub struct Suite {
797 pub inner: &'static Tls13CipherSuite,
799 pub quic: &'static dyn Algorithm,
801}
802
803impl Suite {
804 pub fn keys(&self, client_dst_connection_id: &[u8], side: Side, version: Version) -> Keys {
806 Keys::initial(version, *self, client_dst_connection_id, side)
807 }
808}
809
810impl TryFrom<&'static Tls13CipherSuite> for Suite {
811 type Error = ApiMisuse;
812
813 fn try_from(suite: &'static Tls13CipherSuite) -> Result<Self, Self::Error> {
814 Ok(Self {
815 inner: suite,
816 quic: suite
817 .quic
818 .ok_or(ApiMisuse::NoQuicCompatibleCipherSuites)?,
819 })
820 }
821}
822
823impl fmt::Debug for Suite {
824 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
825 f.debug_struct("Suite")
826 .field("inner", &self.inner)
827 .finish_non_exhaustive()
828 }
829}
830
831#[expect(clippy::exhaustive_structs)]
833pub struct Keys {
834 pub local: DirectionalKeys,
836 pub remote: DirectionalKeys,
838}
839
840impl Keys {
841 pub fn initial(
843 version: Version,
844 suite: Suite,
845 client_dst_connection_id: &[u8],
846 side: Side,
847 ) -> Self {
848 const CLIENT_LABEL: &[u8] = b"client in";
849 const SERVER_LABEL: &[u8] = b"server in";
850 let salt = version.initial_salt();
851 let hs_secret = suite
852 .inner
853 .hkdf_provider
854 .extract_from_secret(Some(salt), client_dst_connection_id);
855
856 let secrets = Secrets {
857 client: hkdf_expand_label_block(hs_secret.as_ref(), CLIENT_LABEL, &[]),
858 server: hkdf_expand_label_block(hs_secret.as_ref(), SERVER_LABEL, &[]),
859 suite,
860 side,
861 version,
862 };
863
864 Self::new(&secrets)
865 }
866
867 fn new(secrets: &Secrets) -> Self {
868 let (local, remote) = secrets.local_remote();
869 Self {
870 local: DirectionalKeys::new(secrets.suite, local, secrets.version),
871 remote: DirectionalKeys::new(secrets.suite, remote, secrets.version),
872 }
873 }
874}
875
876#[expect(clippy::exhaustive_enums)]
890pub enum KeyChange {
891 Handshake {
893 keys: Keys,
895 },
896 OneRtt {
898 keys: Keys,
900 next: Secrets,
902 },
903}
904
905impl fmt::Debug for KeyChange {
906 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
907 match self {
908 Self::Handshake { .. } => f
909 .debug_struct("Handshake")
910 .finish_non_exhaustive(),
911 Self::OneRtt { .. } => f
912 .debug_struct("OneRtt")
913 .finish_non_exhaustive(),
914 }
915 }
916}
917
918#[non_exhaustive]
922#[derive(Clone, Copy, Debug, Default, Eq, PartialEq)]
923pub enum Version {
924 #[default]
926 V1,
927 V2,
929}
930
931impl Version {
932 fn initial_salt(self) -> &'static [u8; 20] {
933 match self {
934 Self::V1 => &[
935 0x38, 0x76, 0x2c, 0xf7, 0xf5, 0x59, 0x34, 0xb3, 0x4d, 0x17, 0x9a, 0xe6, 0xa4, 0xc8,
937 0x0c, 0xad, 0xcc, 0xbb, 0x7f, 0x0a,
938 ],
939 Self::V2 => &[
940 0x0d, 0xed, 0xe3, 0xde, 0xf7, 0x00, 0xa6, 0xdb, 0x81, 0x93, 0x81, 0xbe, 0x6e, 0x26,
942 0x9d, 0xcb, 0xf9, 0xbd, 0x2e, 0xd9,
943 ],
944 }
945 }
946
947 pub(crate) fn packet_key_label(&self) -> &'static [u8] {
949 match self {
950 Self::V1 => b"quic key",
951 Self::V2 => b"quicv2 key",
952 }
953 }
954
955 pub(crate) fn packet_iv_label(&self) -> &'static [u8] {
957 match self {
958 Self::V1 => b"quic iv",
959 Self::V2 => b"quicv2 iv",
960 }
961 }
962
963 pub(crate) fn header_key_label(&self) -> &'static [u8] {
965 match self {
966 Self::V1 => b"quic hp",
967 Self::V2 => b"quicv2 hp",
968 }
969 }
970
971 fn key_update_label(&self) -> &'static [u8] {
972 match self {
973 Self::V1 => b"quic ku",
974 Self::V2 => b"quicv2 ku",
975 }
976 }
977}
978
979#[cfg(all(test, any(target_arch = "aarch64", target_arch = "x86_64")))]
980mod tests {
981 use super::*;
982 use crate::crypto::TLS13_TEST_SUITE;
983 use crate::crypto::tls13::OkmBlock;
984 use crate::quic::{HeaderProtectionKey, Side, Version};
985
986 #[test]
987 fn key_update_test_vector() {
988 fn equal_okm(x: &OkmBlock, y: &OkmBlock) -> bool {
989 x.as_ref() == y.as_ref()
990 }
991
992 let mut secrets = Secrets {
993 client: OkmBlock::new(
995 &[
996 0xb8, 0x76, 0x77, 0x08, 0xf8, 0x77, 0x23, 0x58, 0xa6, 0xea, 0x9f, 0xc4, 0x3e,
997 0x4a, 0xdd, 0x2c, 0x96, 0x1b, 0x3f, 0x52, 0x87, 0xa6, 0xd1, 0x46, 0x7e, 0xe0,
998 0xae, 0xab, 0x33, 0x72, 0x4d, 0xbf,
999 ][..],
1000 ),
1001 server: OkmBlock::new(
1002 &[
1003 0x42, 0xdc, 0x97, 0x21, 0x40, 0xe0, 0xf2, 0xe3, 0x98, 0x45, 0xb7, 0x67, 0x61,
1004 0x34, 0x39, 0xdc, 0x67, 0x58, 0xca, 0x43, 0x25, 0x9b, 0x87, 0x85, 0x06, 0x82,
1005 0x4e, 0xb1, 0xe4, 0x38, 0xd8, 0x55,
1006 ][..],
1007 ),
1008 suite: Suite {
1009 inner: TLS13_TEST_SUITE,
1010 quic: &FakeAlgorithm,
1011 },
1012 side: Side::Client,
1013 version: Version::V1,
1014 };
1015 secrets.update();
1016
1017 assert!(equal_okm(
1018 &secrets.client,
1019 &OkmBlock::new(
1020 &[
1021 0x42, 0xca, 0xc8, 0xc9, 0x1c, 0xd5, 0xeb, 0x40, 0x68, 0x2e, 0x43, 0x2e, 0xdf,
1022 0x2d, 0x2b, 0xe9, 0xf4, 0x1a, 0x52, 0xca, 0x6b, 0x22, 0xd8, 0xe6, 0xcd, 0xb1,
1023 0xe8, 0xac, 0xa9, 0x6, 0x1f, 0xce
1024 ][..]
1025 )
1026 ));
1027 assert!(equal_okm(
1028 &secrets.server,
1029 &OkmBlock::new(
1030 &[
1031 0xeb, 0x7f, 0x5e, 0x2a, 0x12, 0x3f, 0x40, 0x7d, 0xb4, 0x99, 0xe3, 0x61, 0xca,
1032 0xe5, 0x90, 0xd4, 0xd9, 0x92, 0xe1, 0x4b, 0x7a, 0xce, 0x3, 0xc2, 0x44, 0xe0,
1033 0x42, 0x21, 0x15, 0xb6, 0xd3, 0x8a
1034 ][..]
1035 )
1036 ));
1037 }
1038
1039 struct FakeAlgorithm;
1040
1041 impl Algorithm for FakeAlgorithm {
1042 fn packet_key(&self, _key: AeadKey, _iv: Iv) -> Box<dyn PacketKey> {
1043 unimplemented!()
1044 }
1045
1046 fn header_protection_key(&self, _key: AeadKey) -> Box<dyn HeaderProtectionKey> {
1047 unimplemented!()
1048 }
1049
1050 fn aead_key_len(&self) -> usize {
1051 16
1052 }
1053 }
1054
1055 #[test]
1056 fn auto_traits() {
1057 fn assert_auto<T: Send + Sync>() {}
1058 assert_auto::<Box<dyn PacketKey>>();
1059 assert_auto::<Box<dyn HeaderProtectionKey>>();
1060 }
1061}