ktls_core/
probe.rs

1//! See [`Compatibilities::probe`].
2
3use std::io;
4use std::net::{TcpListener, TcpStream};
5
6use bitfield_struct::bitfield;
7
8use crate::setup::{setup_ulp, TlsCryptoInfoTx};
9use crate::tls::{AeadKey, ConnectionTrafficSecrets, ProtocolVersion};
10
11#[non_exhaustive]
12#[derive(Debug, Clone, Copy)]
13/// The current Linux kernel's kTLS cipher suites compatibility.
14pub struct Compatibilities {
15    /// TLS 1.2 cipher suite compatibility.
16    pub tls12: Compatibility,
17
18    /// TLS 1.3 cipher suite compatibility.
19    pub tls13: Compatibility,
20}
21
22impl Compatibilities {
23    /// Probes the current Linux kernel for kTLS cipher suites compatibility.
24    ///
25    /// Returns `Ok(None)` if the running kernel does not support kTLS, e.g.,
26    /// `tls` module is not available. If the kernel is modern enough (at least
27    /// 5.4), it should support kTLS but might not have `tls` module loaded.
28    ///
29    /// The caller can cache the successful result of this method, while the
30    /// supporting cipher suites are unlikely to change during the program's
31    /// lifetime. Note that the attempt to configure TLS ULP still might fail
32    /// due to kTLS being unsupported, while the `tls` module can be loaded
33    /// / unloaded at runtime.
34    ///
35    /// The caller may check the returned `Compatibility`s with
36    /// [`Compatibility::is_unsupported`]  to see whether the desired TLS
37    /// version is totally unsupported.
38    ///
39    /// ## Errors
40    ///
41    /// [`io::Error`].
42    pub fn probe() -> io::Result<Option<Self>> {
43        let listener = TcpListener::bind("127.0.0.1:0")?;
44
45        let local_addr = listener.local_addr()?;
46
47        let mut tls12 = Compatibility::new();
48        let mut tls13 = Compatibility::new();
49
50        macro_rules! test {
51            ($ver:ident, $cipher:ident, $c:ident, $m:ident) => {{
52                let stream = TcpStream::connect(local_addr)?;
53
54                match setup_ulp(&stream) {
55                    Ok(_) => {}
56                    Err(err) if err.is_ktls_unsupported() => return Ok(None),
57                    Err(err) => {
58                        crate::error!(
59                            "Failed to probe compatibility of {} {}",
60                            stringify!($ver),
61                            stringify!($cipher)
62                        );
63
64                        return Err(err.into());
65                    }
66                }
67
68                if TlsCryptoInfoTx::new(
69                    ProtocolVersion::$ver,
70                    ConnectionTrafficSecrets::$cipher {
71                        key: AeadKey::new(Default::default()),
72                        iv: Default::default(),
73                        salt: Default::default(),
74                    },
75                    0,
76                )
77                .unwrap()
78                .set(&stream)
79                .inspect_err(|_err| {
80                    crate::trace!(
81                        "{} {}: Not suitable: {}",
82                        stringify!($ver),
83                        stringify!($cipher),
84                        _err
85                    );
86                })
87                .is_ok()
88                {
89                    $c.$m(true);
90                }
91            }};
92        }
93
94        test!(TLSv1_2, Aes128Gcm, tls12, set_aes_128_gcm);
95        test!(TLSv1_2, Aes256Gcm, tls12, set_aes_256_gcm);
96        test!(TLSv1_2, Chacha20Poly1305, tls12, set_chacha20_poly1305);
97        test!(TLSv1_2, Aes128Ccm, tls12, set_aes_128_ccm);
98        test!(TLSv1_2, Sm4Gcm, tls12, set_sm4_gcm);
99        test!(TLSv1_2, Sm4Ccm, tls12, set_sm4_ccm);
100        test!(TLSv1_2, Aria128Gcm, tls12, set_aria_128_gcm);
101        test!(TLSv1_2, Aria256Gcm, tls12, set_aria_256_gcm);
102
103        test!(TLSv1_3, Aes128Gcm, tls13, set_aes_128_gcm);
104        test!(TLSv1_3, Aes256Gcm, tls13, set_aes_256_gcm);
105        test!(TLSv1_3, Chacha20Poly1305, tls13, set_chacha20_poly1305);
106        test!(TLSv1_3, Aes128Ccm, tls13, set_aes_128_ccm);
107        test!(TLSv1_3, Sm4Gcm, tls13, set_sm4_gcm);
108        test!(TLSv1_3, Sm4Ccm, tls13, set_sm4_ccm);
109        test!(TLSv1_3, Aria128Gcm, tls13, set_aria_128_gcm);
110        test!(TLSv1_3, Aria256Gcm, tls13, set_aria_256_gcm);
111
112        if tls12.is_unsupported() && tls13.is_unsupported() {
113            crate::error!("All cipher suites are unsupported while kTLS seems to be supported");
114
115            return Ok(None);
116        }
117
118        let this = Self { tls12, tls13 };
119
120        crate::trace!("kTLS compatibilities probed: {:#?}", this);
121
122        Ok(Some(this))
123    }
124}
125
126#[bitfield(u8)]
127/// Represents the compatibility of various TLS cipher suites with kernel TLS.
128pub struct Compatibility {
129    /// AES-128-GCM cipher suite support.
130    pub aes_128_gcm: bool,
131
132    /// AES-256-GCM cipher suite support.
133    pub aes_256_gcm: bool,
134
135    /// ChaCha20-Poly1305 cipher suite support.
136    pub chacha20_poly1305: bool,
137
138    /// AES-128-CCM cipher suite support.
139    pub aes_128_ccm: bool,
140
141    /// SM4-GCM cipher suite support.
142    pub sm4_gcm: bool,
143
144    /// SM4-CCM cipher suite support.
145    pub sm4_ccm: bool,
146
147    /// ARIA-128-GCM cipher suite support.
148    pub aria_128_gcm: bool,
149
150    /// ARIA-256-GCM cipher suite support.
151    pub aria_256_gcm: bool,
152}
153
154impl Compatibility {
155    /// Returns whether no cipher suites are supported (the corresponding TLS
156    /// version is unsupported).
157    #[must_use]
158    pub const fn is_unsupported(&self) -> bool {
159        self.0 == 0
160    }
161}