ktls_core/
tls.rs

1//! Shim layer for TLS protocol implementations.
2
3use std::io;
4
5use crate::error::{Error, InvalidMessage, Result};
6use crate::setup::{TlsCryptoInfoRx, TlsCryptoInfoTx};
7
8#[derive(zeroize_derive::ZeroizeOnDrop)]
9/// An AEAD key with fixed size.
10///
11/// This is a low-level structure, usually you don't need to use it directly
12/// unless you are implementing a higher-level abstraction.
13pub struct AeadKey<const N: usize>(pub(crate) [u8; N]);
14
15impl<const N: usize> core::fmt::Debug for AeadKey<N> {
16    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
17        f.debug_struct("AeadKey").finish()
18    }
19}
20
21impl<const N: usize> AeadKey<N> {
22    /// Create a new AEAD key from a byte array.
23    #[must_use]
24    pub const fn new(inner: [u8; N]) -> Self {
25        Self(inner)
26    }
27}
28
29impl<const N: usize> From<[u8; N]> for AeadKey<N> {
30    fn from(arr: [u8; N]) -> Self {
31        Self::new(arr)
32    }
33}
34
35#[non_exhaustive]
36/// Secrets used to encrypt/decrypt data in a TLS session.
37///
38/// This is a low-level structure, usually you don't need to use it directly
39/// unless you are implementing a higher-level abstraction.
40pub enum ConnectionTrafficSecrets {
41    /// Secrets for the `AES_128_GCM` AEAD algorithm
42    Aes128Gcm {
43        /// AEAD Key
44        key: AeadKey<{ libc::TLS_CIPHER_AES_GCM_128_KEY_SIZE }>,
45
46        /// Initialization vector
47        iv: [u8; libc::TLS_CIPHER_AES_GCM_128_IV_SIZE],
48
49        /// Salt
50        salt: [u8; libc::TLS_CIPHER_AES_GCM_128_SALT_SIZE],
51    },
52
53    /// Secrets for the `AES_256_GCM` AEAD algorithm
54    Aes256Gcm {
55        /// AEAD Key
56        key: AeadKey<{ libc::TLS_CIPHER_AES_GCM_256_KEY_SIZE }>,
57
58        /// Initialization vector
59        iv: [u8; libc::TLS_CIPHER_AES_GCM_256_IV_SIZE],
60
61        /// Salt
62        salt: [u8; libc::TLS_CIPHER_AES_GCM_256_SALT_SIZE],
63    },
64
65    /// Secrets for the `CHACHA20_POLY1305` AEAD algorithm
66    Chacha20Poly1305 {
67        /// AEAD Key
68        key: AeadKey<{ libc::TLS_CIPHER_CHACHA20_POLY1305_KEY_SIZE }>,
69
70        /// Initialization vector
71        iv: [u8; libc::TLS_CIPHER_CHACHA20_POLY1305_IV_SIZE],
72
73        /// Salt (not used)
74        salt: [u8; libc::TLS_CIPHER_CHACHA20_POLY1305_SALT_SIZE],
75    },
76
77    /// Secrets for the `AES_128_CCM` AEAD algorithm
78    Aes128Ccm {
79        /// AEAD Key
80        key: AeadKey<{ libc::TLS_CIPHER_AES_CCM_128_KEY_SIZE }>,
81
82        /// Initialization vector
83        iv: [u8; libc::TLS_CIPHER_AES_CCM_128_IV_SIZE],
84
85        /// Salt
86        salt: [u8; libc::TLS_CIPHER_AES_CCM_128_SALT_SIZE],
87    },
88
89    /// Secrets for the `SM4_GCM` AEAD algorithm
90    Sm4Gcm {
91        /// AEAD Key
92        key: AeadKey<{ libc::TLS_CIPHER_SM4_GCM_KEY_SIZE }>,
93
94        /// Initialization vector
95        iv: [u8; libc::TLS_CIPHER_SM4_GCM_IV_SIZE],
96
97        /// Salt
98        salt: [u8; libc::TLS_CIPHER_SM4_GCM_SALT_SIZE],
99    },
100
101    /// Secrets for the `SM4_CCM` AEAD algorithm
102    Sm4Ccm {
103        /// AEAD Key
104        key: AeadKey<{ libc::TLS_CIPHER_SM4_CCM_KEY_SIZE }>,
105
106        /// Initialization vector
107        iv: [u8; libc::TLS_CIPHER_SM4_CCM_IV_SIZE],
108
109        /// Salt
110        salt: [u8; libc::TLS_CIPHER_SM4_CCM_SALT_SIZE],
111    },
112
113    /// Secrets for the `ARIA_GCM_128` AEAD algorithm
114    Aria128Gcm {
115        /// AEAD Key
116        key: AeadKey<{ libc::TLS_CIPHER_ARIA_GCM_128_KEY_SIZE }>,
117
118        /// Initialization vector
119        iv: [u8; libc::TLS_CIPHER_ARIA_GCM_128_IV_SIZE],
120
121        /// Salt
122        salt: [u8; libc::TLS_CIPHER_ARIA_GCM_128_SALT_SIZE],
123    },
124
125    /// Secrets for the `ARIA_GCM_256` AEAD algorithm
126    Aria256Gcm {
127        /// AEAD Key
128        key: AeadKey<{ libc::TLS_CIPHER_ARIA_GCM_256_KEY_SIZE }>,
129
130        /// Initialization vector
131        iv: [u8; libc::TLS_CIPHER_ARIA_GCM_256_IV_SIZE],
132
133        /// Salt
134        salt: [u8; libc::TLS_CIPHER_ARIA_GCM_256_SALT_SIZE],
135    },
136}
137
138#[allow(clippy::exhaustive_structs)]
139/// Secrets for transmitting/receiving data over a TLS session.
140///
141/// After performing a handshake with rustls, these secrets can be extracted
142/// to configure kTLS for a socket, and have the kernel take over encryption
143/// and/or decryption.
144///
145/// This is a low-level structure, usually you don't need to use it directly
146/// unless you are implementing a higher-level abstraction.
147///
148/// This is copied from rustls.
149pub struct ExtractedSecrets {
150    /// sequence number and secrets for the "tx" (transmit) direction
151    pub tx: (u64, ConnectionTrafficSecrets),
152
153    /// sequence number and secrets for the "rx" (receive) direction
154    pub rx: (u64, ConnectionTrafficSecrets),
155}
156
157/// A macro which defines an enum type.
158///
159/// This is copied from rustls.
160macro_rules! enum_builder {
161    (
162        $(#[doc = $comment:literal])*
163        #[repr($uint:ty)]
164        $enum_vis:vis enum $enum_name:ident
165        {
166          $(
167              $(#[doc = $enum_comment:literal])*
168              $enum_var:ident => $enum_val:literal
169          ),*
170          $(,)?
171          $(
172              !Debug:
173              $(
174                  $(#[doc = $enum_comment_no_debug:literal])*
175                  $enum_var_no_debug:ident => $enum_val_no_debug:literal
176              ),*
177              $(,)?
178          )?
179        }
180    ) => {
181        $(#[doc = $comment])*
182        #[non_exhaustive]
183        #[allow(missing_docs)]
184        #[derive(PartialEq, Eq, Clone, Copy)]
185        $enum_vis enum $enum_name {
186            $(
187                $(#[doc = $enum_comment])*
188                $enum_var
189            ),*
190            $(
191                ,
192                $(
193                    $(#[doc = $enum_comment_no_debug])*
194                    $enum_var_no_debug
195                ),*
196            )?
197            ,Unknown($uint)
198        }
199
200        impl $enum_name {
201            // NOTE(allow) generated irrespective if there are callers
202            #[allow(dead_code)]
203            pub(crate) const fn to_array(self) -> [u8; core::mem::size_of::<$uint>()] {
204                self.to_int().to_be_bytes()
205            }
206
207            // NOTE(allow) generated irrespective if there are callers
208            #[allow(dead_code)]
209            pub(crate) const fn as_str(&self) -> Option<&'static str> {
210                match self {
211                    $( $enum_name::$enum_var => Some(stringify!($enum_var))),*
212                    $(, $( $enum_name::$enum_var_no_debug => Some(stringify!($enum_var_no_debug))),* )?
213                    ,$enum_name::Unknown(_) => None,
214                }
215            }
216
217            #[allow(dead_code)]
218            pub(crate) const fn from_int(x: $uint) -> Self {
219                match x {
220                    $($enum_val => $enum_name::$enum_var),*
221                    $(, $($enum_val_no_debug => $enum_name::$enum_var_no_debug),* )?
222                    , x => $enum_name::Unknown(x),
223                }
224            }
225
226            #[allow(dead_code)]
227            pub(crate) const fn to_int(self) -> $uint {
228                match self {
229                    $( $enum_name::$enum_var => $enum_val),*
230                    $(, $( $enum_name::$enum_var_no_debug => $enum_val_no_debug),* )?
231                    ,$enum_name::Unknown(x) => x
232                }
233            }
234        }
235
236        impl From<$uint> for $enum_name {
237            fn from(x: $uint) -> Self {
238                Self::from_int(x)
239            }
240        }
241
242        impl From<$enum_name> for $uint {
243            fn from(value: $enum_name) -> Self {
244                value.to_int()
245            }
246        }
247
248        impl core::fmt::Debug for $enum_name {
249            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
250                match self {
251                    $( $enum_name::$enum_var => f.write_str(stringify!($enum_var)), )*
252                    _ => write!(f, "{}(0x{:x?})", stringify!($enum_name), <$uint>::from(*self)),
253                }
254            }
255        }
256    };
257}
258
259enum_builder! {
260    /// The `AlertLevel` TLS protocol enum.  Values in this enum are taken
261    /// from the various RFCs covering TLS, and are listed by IANA.
262    /// The `Unknown` item is used when processing unrecognized ordinals.
263    #[repr(u8)]
264    pub(crate) enum AlertLevel {
265        Warning => 0x01,
266        Fatal => 0x02,
267    }
268}
269
270enum_builder! {
271    /// The `AlertDescription` TLS protocol enum.  Values in this enum are taken
272    /// from the various RFCs covering TLS, and are listed by IANA.
273    /// The `Unknown` item is used when processing unrecognized ordinals.
274    #[repr(u8)]
275    pub enum AlertDescription {
276        CloseNotify => 0x00,
277        UnexpectedMessage => 0x0a,
278        BadRecordMac => 0x14,
279        DecryptionFailed => 0x15,
280        RecordOverflow => 0x16,
281        DecompressionFailure => 0x1e,
282        HandshakeFailure => 0x28,
283        NoCertificate => 0x29,
284        BadCertificate => 0x2a,
285        UnsupportedCertificate => 0x2b,
286        CertificateRevoked => 0x2c,
287        CertificateExpired => 0x2d,
288        CertificateUnknown => 0x2e,
289        IllegalParameter => 0x2f,
290        UnknownCa => 0x30,
291        AccessDenied => 0x31,
292        DecodeError => 0x32,
293        DecryptError => 0x33,
294        ExportRestriction => 0x3c,
295        ProtocolVersion => 0x46,
296        InsufficientSecurity => 0x47,
297        InternalError => 0x50,
298        InappropriateFallback => 0x56,
299        UserCanceled => 0x5a,
300        NoRenegotiation => 0x64,
301        MissingExtension => 0x6d,
302        UnsupportedExtension => 0x6e,
303        CertificateUnobtainable => 0x6f,
304        UnrecognizedName => 0x70,
305        BadCertificateStatusResponse => 0x71,
306        BadCertificateHashValue => 0x72,
307        UnknownPskIdentity => 0x73,
308        CertificateRequired => 0x74,
309        NoApplicationProtocol => 0x78,
310        EncryptedClientHelloRequired => 0x79, // https://datatracker.ietf.org/doc/html/draft-ietf-tls-esni-18#section-11.2
311    }
312}
313
314enum_builder! {
315    /// The `ContentType` TLS protocol enum.  Values in this enum are taken
316    /// from the various RFCs covering TLS, and are listed by IANA.
317    /// The `Unknown` item is used when processing unrecognized ordinals.
318    #[repr(u8)]
319    pub enum ContentType {
320        ChangeCipherSpec => 0x14,
321        Alert => 0x15,
322        Handshake => 0x16,
323        ApplicationData => 0x17,
324        Heartbeat => 0x18,
325    }
326}
327
328enum_builder! {
329    /// The `KeyUpdateRequest` TLS protocol enum.  Values in this enum are taken
330    /// from the various RFCs covering TLS, and are listed by IANA.
331    /// The `Unknown` item is used when processing unrecognized ordinals.
332    #[repr(u8)]
333    pub(crate) enum KeyUpdateRequest {
334        UpdateNotRequested => 0x00,
335        UpdateRequested => 0x01,
336    }
337}
338
339enum_builder! {
340    /// The `HandshakeType` TLS protocol enum.  Values in this enum are taken
341    /// from the various RFCs covering TLS, and are listed by IANA.
342    /// The `Unknown` item is used when processing unrecognized ordinals.
343    #[repr(u8)]
344    pub(crate) enum HandshakeType {
345        HelloRequest => 0x00,
346        ClientHello => 0x01,
347        ServerHello => 0x02,
348        HelloVerifyRequest => 0x03,
349        NewSessionTicket => 0x04,
350        EndOfEarlyData => 0x05,
351        HelloRetryRequest => 0x06,
352        EncryptedExtensions => 0x08,
353        Certificate => 0x0b,
354        ServerKeyExchange => 0x0c,
355        CertificateRequest => 0x0d,
356        ServerHelloDone => 0x0e,
357        CertificateVerify => 0x0f,
358        ClientKeyExchange => 0x10,
359        Finished => 0x14,
360        CertificateURL => 0x15,
361        CertificateStatus => 0x16,
362        KeyUpdate => 0x18,
363        CompressedCertificate => 0x19,
364        MessageHash => 0xfe,
365    }
366}
367
368enum_builder! {
369    /// The `ProtocolVersion` TLS protocol enum.  Values in this enum are taken
370    /// from the various RFCs covering TLS, and are listed by IANA.
371    /// The `Unknown` item is used when processing unrecognized ordinals.
372    #[repr(u16)]
373    pub enum ProtocolVersion {
374        SSLv2 => 0x0002,
375        SSLv3 => 0x0300,
376        TLSv1_0 => 0x0301,
377        TLSv1_1 => 0x0302,
378        TLSv1_2 => 0x0303,
379        TLSv1_3 => 0x0304,
380        DTLSv1_0 => 0xFEFF,
381        DTLSv1_2 => 0xFEFD,
382        DTLSv1_3 => 0xFEFC,
383    }
384}
385
386#[allow(clippy::exhaustive_enums)]
387#[derive(Debug, Clone, Copy, PartialEq, Eq)]
388/// The peer in a TLS connection: client or server.
389pub enum Peer {
390    /// The client.
391    Client,
392
393    /// The server.
394    Server,
395}
396
397/// TLS session context abstraction.
398///
399/// The kernel only handles TLS encryption and decryption, while the TLS
400/// implementation should provide the necessary TLS session context management,
401/// including key updates and handling of `NewSessionTicket` messages.
402pub trait TlsSession {
403    /// Retrieves which peer this session represents (client or server).
404    fn peer(&self) -> Peer;
405
406    /// Retrieves the protocol version agreed with the peer.
407    fn protocol_version(&self) -> ProtocolVersion;
408
409    /// Update the traffic secret used for encrypting messages sent to the peer.
410    ///
411    /// Returns the new traffic secret and initial sequence number to use.
412    ///
413    /// This method is called once we send a TLS 1.3 key update message to the
414    /// peer.
415    ///
416    /// # Errors
417    ///
418    /// Various errors may be returned depending on the implementation.
419    fn update_tx_secret(&mut self) -> Result<TlsCryptoInfoTx>;
420
421    /// Update the traffic secret used for decrypting messages received from the
422    /// peer.
423    ///
424    /// Returns the new traffic secret and initial sequence number to use.
425    ///
426    /// This method is called once we receive a TLS 1.3 key update message from
427    /// the peer.
428    ///
429    /// # Errors
430    ///
431    /// Various errors may be returned depending on the implementation.
432    fn update_rx_secret(&mut self) -> Result<TlsCryptoInfoRx>;
433
434    /// Handles a `NewSessionTicket` message received from the peer.
435    ///
436    /// This method expects to be passed the inner payload of the handshake
437    /// message. This means that you will need to parse the header of the
438    /// handshake message in order to determine the correct payload to pass in.
439    /// The message format is described in [RFC 8446 section 4]. `payload`
440    /// should not include the `msg_type` or `length` fields.
441    ///
442    /// [RFC 8446 section 4]: https://datatracker.ietf.org/doc/html/rfc8446#section-4
443    ///
444    /// # Errors
445    ///
446    /// Various errors may be returned depending on the implementation.
447    fn handle_new_session_ticket(&mut self, _payload: &[u8]) -> Result<()>;
448
449    #[inline]
450    /// Handles the message with unknown content type received from the peer.
451    ///
452    /// By default, this method returns an
453    /// [`InvalidContentType`](InvalidMessage::InvalidContentType) error.
454    ///
455    /// # Errors
456    ///
457    /// Various errors may be returned depending on the implementation.
458    fn handle_unknown_message(&mut self, _content_type: u8, _payload: &[u8]) -> Result<()> {
459        Err(Error::InvalidMessage(InvalidMessage::InvalidContentType))
460    }
461}
462
463#[derive(Debug, Clone, Copy)]
464/// A dummy TLS session implementation which does nothing.
465pub struct DummyTlsSession {
466    peer: Peer,
467    protocol_version: ProtocolVersion,
468}
469
470/// See [`DummyTlsSession`].
471pub static DUMMY_TLS_13_SESSION_CLIENT: DummyTlsSession = DummyTlsSession {
472    peer: Peer::Client,
473    protocol_version: ProtocolVersion::TLSv1_3,
474};
475
476/// See [`DummyTlsSession`].
477pub static DUMMY_TLS_13_SESSION_SERVER: DummyTlsSession = DummyTlsSession {
478    peer: Peer::Server,
479    protocol_version: ProtocolVersion::TLSv1_3,
480};
481
482/// See [`DummyTlsSession`].
483pub static DUMMY_TLS_12_SESSION_CLIENT: DummyTlsSession = DummyTlsSession {
484    peer: Peer::Client,
485    protocol_version: ProtocolVersion::TLSv1_2,
486};
487
488/// See [`DummyTlsSession`].
489pub static DUMMY_TLS_12_SESSION_SERVER: DummyTlsSession = DummyTlsSession {
490    peer: Peer::Server,
491    protocol_version: ProtocolVersion::TLSv1_2,
492};
493
494impl TlsSession for DummyTlsSession {
495    fn peer(&self) -> Peer {
496        self.peer
497    }
498
499    fn protocol_version(&self) -> ProtocolVersion {
500        self.protocol_version
501    }
502
503    fn update_tx_secret(&mut self) -> Result<TlsCryptoInfoTx> {
504        Err(Error::KeyUpdateFailed(io::Error::other(
505            "Dummy TLS session does not support key updates",
506        )))
507    }
508
509    fn update_rx_secret(&mut self) -> Result<TlsCryptoInfoRx> {
510        Err(Error::KeyUpdateFailed(io::Error::other(
511            "Dummy TLS session does not support key updates",
512        )))
513    }
514
515    fn handle_new_session_ticket(&mut self, _payload: &[u8]) -> Result<()> {
516        Err(Error::HandleNewSessionTicketFailed(io::Error::other(
517            "Dummy TLS session does not support new session tickets",
518        )))
519    }
520}
521
522#[cfg(feature = "_shim")]
523mod shim {
524    #[allow(clippy::wildcard_imports)]
525    use super::*;
526
527    #[cfg(feature = "shim-rustls")]
528    impl TlsSession for rustls::kernel::KernelConnection<rustls::client::ClientConnectionData> {
529        fn peer(&self) -> Peer {
530            Peer::Client
531        }
532
533        fn protocol_version(&self) -> ProtocolVersion {
534            self.protocol_version().into()
535        }
536
537        #[track_caller]
538        fn update_tx_secret(&mut self) -> Result<TlsCryptoInfoTx> {
539            let (seq, secrets) = self
540                .update_tx_secret()
541                .map_err(|e| Error::KeyUpdateFailed(io::Error::other(e)))?;
542
543            TlsCryptoInfoTx::new(
544                self.protocol_version().into(),
545                ConnectionTrafficSecrets::try_from(secrets)?,
546                seq,
547            )
548        }
549
550        #[track_caller]
551        fn update_rx_secret(&mut self) -> Result<TlsCryptoInfoRx> {
552            let (seq, secrets) = self
553                .update_rx_secret()
554                .map_err(|e| Error::KeyUpdateFailed(io::Error::other(e)))?;
555
556            TlsCryptoInfoRx::new(
557                self.protocol_version().into(),
558                ConnectionTrafficSecrets::try_from(secrets)?,
559                seq,
560            )
561        }
562
563        #[track_caller]
564        fn handle_new_session_ticket(&mut self, payload: &[u8]) -> Result<()> {
565            self.handle_new_session_ticket(payload)
566                .map_err(|e| Error::HandleNewSessionTicketFailed(io::Error::other(e)))
567        }
568    }
569
570    #[cfg(feature = "shim-rustls")]
571    impl TlsSession for rustls::kernel::KernelConnection<rustls::server::ServerConnectionData> {
572        fn peer(&self) -> Peer {
573            Peer::Server
574        }
575
576        fn protocol_version(&self) -> ProtocolVersion {
577            self.protocol_version().into()
578        }
579
580        #[track_caller]
581        fn update_tx_secret(&mut self) -> Result<TlsCryptoInfoTx> {
582            let (seq, secrets) = self
583                .update_tx_secret()
584                .map_err(|e| Error::KeyUpdateFailed(io::Error::other(e)))?;
585
586            TlsCryptoInfoTx::new(
587                self.protocol_version().into(),
588                ConnectionTrafficSecrets::try_from(secrets)?,
589                seq,
590            )
591        }
592
593        #[track_caller]
594        fn update_rx_secret(&mut self) -> Result<TlsCryptoInfoRx> {
595            let (seq, secrets) = self
596                .update_rx_secret()
597                .map_err(|e| Error::KeyUpdateFailed(io::Error::other(e)))?;
598
599            TlsCryptoInfoRx::new(
600                self.protocol_version().into(),
601                ConnectionTrafficSecrets::try_from(secrets)?,
602                seq,
603            )
604        }
605
606        fn handle_new_session_ticket(&mut self, _payload: &[u8]) -> Result<()> {
607            Err(Error::HandleNewSessionTicketFailed(io::Error::other(
608                "Server should not receive new session ticket",
609            )))
610        }
611    }
612
613    #[cfg(feature = "shim-rustls")]
614    impl From<rustls::ProtocolVersion> for ProtocolVersion {
615        fn from(value: rustls::ProtocolVersion) -> Self {
616            Self::from_int(value.into())
617        }
618    }
619
620    #[cfg(feature = "shim-rustls")]
621    impl TryFrom<rustls::ExtractedSecrets> for ExtractedSecrets {
622        type Error = Error;
623
624        /// The secrets and context must be extracted from a
625        /// [`rustls::client::UnbufferedClientConnection`] or
626        /// [`rustls::client::UnbufferedClientConnection`]. See
627        /// [`rustls::kernel`] module documentation for more details.
628        fn try_from(secrets: rustls::ExtractedSecrets) -> Result<Self, Self::Error> {
629            let rustls::ExtractedSecrets {
630                tx: (seq_tx, secrets_tx),
631                rx: (seq_rx, secrets_rx),
632            } = secrets;
633
634            Ok(Self {
635                tx: (seq_tx, ConnectionTrafficSecrets::try_from(secrets_tx)?),
636                rx: (seq_rx, ConnectionTrafficSecrets::try_from(secrets_rx)?),
637            })
638        }
639    }
640
641    #[cfg(feature = "shim-rustls")]
642    impl TryFrom<rustls::ConnectionTrafficSecrets> for ConnectionTrafficSecrets {
643        type Error = Error;
644
645        #[track_caller]
646        fn try_from(value: rustls::ConnectionTrafficSecrets) -> Result<Self, Self::Error> {
647            match value {
648                rustls::ConnectionTrafficSecrets::Aes128Gcm { key, iv } => Ok(Self::Aes128Gcm {
649                    key: AeadKey::new(
650                        key.as_ref()
651                            .try_into()
652                            .expect("key length mismatch"),
653                    ),
654                    iv: iv.as_ref()[4..]
655                        .try_into()
656                        .expect("iv length mismatch"),
657                    salt: iv.as_ref()[..4]
658                        .try_into()
659                        .expect("salt length mismatch"),
660                }),
661                rustls::ConnectionTrafficSecrets::Aes256Gcm { key, iv } => Ok(Self::Aes256Gcm {
662                    key: AeadKey::new(
663                        key.as_ref()
664                            .try_into()
665                            .expect("key length mismatch"),
666                    ),
667                    iv: iv.as_ref()[4..]
668                        .try_into()
669                        .expect("iv length mismatch"),
670                    salt: iv.as_ref()[..4]
671                        .try_into()
672                        .expect("salt length mismatch"),
673                }),
674                rustls::ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv } => {
675                    Ok(Self::Chacha20Poly1305 {
676                        key: AeadKey::new(
677                            key.as_ref()
678                                .try_into()
679                                .expect("key length mismatch"),
680                        ),
681                        iv: iv
682                            .as_ref()
683                            .try_into()
684                            .expect("iv length mismatch"),
685                        salt: [],
686                    })
687                }
688                secrets => Err(Error::CryptoMaterial(io::Error::other(format!(
689                    "The given crypto material is not supported by the running kernel: {}",
690                    std::any::type_name_of_val(&secrets)
691                )))),
692            }
693        }
694    }
695}