1- use std:: os:: fd:: { AsFd , AsRawFd } ;
21use std:: os:: unix:: prelude:: RawFd ;
3- use std:: { io, mem} ;
42
53use ktls_sys:: bindings as ktls;
6- use nix:: sys:: socket:: { setsockopt, sockopt} ;
7- use rustls:: crypto:: cipher:: NONCE_LEN ;
84use rustls:: internal:: msgs:: enums:: AlertLevel ;
95use rustls:: internal:: msgs:: message:: Message ;
10- use rustls:: { AlertDescription , ConnectionTrafficSecrets , ExtractedSecrets , SupportedCipherSuite } ;
6+ use rustls:: AlertDescription ;
117
128pub ( crate ) const TLS_1_2_VERSION_NUMBER : u16 = ( ( ( ktls:: TLS_1_2_VERSION_MAJOR & 0xFF ) as u16 ) << 8 )
139 | ( ( ktls:: TLS_1_2_VERSION_MINOR & 0xFF ) as u16 ) ;
@@ -18,236 +14,6 @@ pub(crate) const TLS_1_3_VERSION_NUMBER: u16 = (((ktls::TLS_1_3_VERSION_MAJOR &
1814/// `setsockopt` level constant: TLS
1915const SOL_TLS : libc:: c_int = 282 ;
2016
21- /// Sets the TLS Upper Layer Protocol (ULP).
22- ///
23- /// This should be called before performing any I/O operations on the
24- /// socket.
25- ///
26- /// # Errors
27- ///
28- /// [`SetupUlpError`]. The caller may check if the error is due to the system
29- /// not supporting kTLS (e.g., kernel module `tls` not being enabled or the
30- /// kernel version being too old) with [`SetupUlpError::is_ktls_unsupported`].
31- pub fn setup_ulp < S : AsFd > ( socket : & S ) -> Result < ( ) , SetupUlpError > {
32- setsockopt ( socket, sockopt:: TcpUlp :: default ( ) , b"tls" )
33- . map_err ( io:: Error :: from)
34- . map_err ( SetupUlpError )
35- }
36-
37- #[ derive( Debug , thiserror:: Error ) ]
38- #[ error( "Failed to set TLS ULP, error: {0}" ) ]
39- /// An error that occurred while configuring the ULP.
40- ///
41- /// This error wraps the underlying `io::Error` that caused the failure.
42- /// The caller may check if the error is due to the system not supporting kTLS
43- /// (e.g., kernel module `tls` not being enabled or the kernel version being too
44- /// old).
45- pub struct SetupUlpError ( #[ source] io:: Error ) ;
46-
47- impl SetupUlpError {
48- /// Returns `true` if the error is due to the system not supporting kTLS.
49- pub fn is_ktls_unsupported ( & self ) -> bool {
50- matches ! ( self . 0 . raw_os_error( ) , Some ( libc:: ENOENT ) )
51- }
52- }
53-
54- impl From < SetupUlpError > for io:: Error {
55- fn from ( err : SetupUlpError ) -> Self {
56- io:: Error :: other ( err)
57- }
58- }
59-
60- /// Sets the kTLS parameters on the socket after the TLS handshake is completed.
61- ///
62- /// ## Errors
63- ///
64- /// * Invalid crypto materials.
65- /// * Syscall error.
66- pub ( crate ) fn setup_tls_params < S : AsFd > (
67- socket : & S ,
68- cipher_suite : SupportedCipherSuite ,
69- secrets : ExtractedSecrets ,
70- ) -> io:: Result < ( ) > {
71- TlsCryptoInfo :: extract ( cipher_suite, secrets. tx ) ?. set_tx ( socket) ?;
72- TlsCryptoInfo :: extract ( cipher_suite, secrets. rx ) ?. set_rx ( socket) ?;
73-
74- Ok ( ( ) )
75- }
76-
77- #[ repr( C ) ]
78- #[ allow( unused) ]
79- /// A wrapper around the `libc::tls12_crypto_info_*` structs, use with setting
80- /// up the kTLS r/w parameters on the TCP socket.
81- ///
82- /// This is originated from the `nix` crate, which currently does not support
83- /// `AES-128-CCM` or `SM4-*`, so we implement our own version here.
84- pub ( crate ) enum TlsCryptoInfo {
85- AesGcm128 ( libc:: tls12_crypto_info_aes_gcm_128 ) ,
86- AesGcm256 ( libc:: tls12_crypto_info_aes_gcm_256 ) ,
87- AesCcm128 ( libc:: tls12_crypto_info_aes_ccm_128 ) ,
88- Chacha20Poly1305 ( libc:: tls12_crypto_info_chacha20_poly1305 ) ,
89- Sm4Gcm ( libc:: tls12_crypto_info_sm4_gcm ) ,
90- Sm4Ccm ( libc:: tls12_crypto_info_sm4_ccm ) ,
91- }
92-
93- impl TlsCryptoInfo {
94- /// Sets the kTLS parameters on the given file descriptor, assuming that the
95- /// [`TlsCryptoInfo`] is *extract* from the sequence number and
96- /// secrets for the "tx" (transmit) direction.
97- pub ( crate ) fn set_tx < S : AsFd > ( self , socket : & S ) -> io:: Result < ( ) > {
98- self . set ( socket, libc:: TLS_TX )
99- }
100-
101- /// Sets the kTLS parameters on the given file descriptor, assuming that the
102- /// [`TlsCryptoInfo`] is *extract* from the sequence number and
103- /// secrets for the "rx" (receive) direction.
104- pub ( crate ) fn set_rx < S : AsFd > ( self , socket : & S ) -> io:: Result < ( ) > {
105- self . set ( socket, libc:: TLS_RX )
106- }
107-
108- /// Sets the kTLS parameters on the given file descriptor.
109- fn set < S : AsFd > ( & self , socket : & S , direction : libc:: c_int ) -> io:: Result < ( ) > {
110- let ( ffi_ptr, ffi_len) = match self {
111- Self :: AesGcm128 ( crypto_info) => (
112- <* const _ >:: cast ( crypto_info) ,
113- mem:: size_of_val ( crypto_info) as libc:: socklen_t ,
114- ) ,
115- Self :: AesGcm256 ( crypto_info) => (
116- <* const _ >:: cast ( crypto_info) ,
117- mem:: size_of_val ( crypto_info) as libc:: socklen_t ,
118- ) ,
119- Self :: AesCcm128 ( crypto_info) => (
120- <* const _ >:: cast ( crypto_info) ,
121- mem:: size_of_val ( crypto_info) as libc:: socklen_t ,
122- ) ,
123- Self :: Chacha20Poly1305 ( crypto_info) => (
124- <* const _ >:: cast ( crypto_info) ,
125- mem:: size_of_val ( crypto_info) as libc:: socklen_t ,
126- ) ,
127- Self :: Sm4Gcm ( crypto_info) => (
128- <* const _ >:: cast ( crypto_info) ,
129- mem:: size_of_val ( crypto_info) as libc:: socklen_t ,
130- ) ,
131- Self :: Sm4Ccm ( crypto_info) => (
132- <* const _ >:: cast ( crypto_info) ,
133- mem:: size_of_val ( crypto_info) as libc:: socklen_t ,
134- ) ,
135- } ;
136-
137- // SAFETY: syscall
138- let ret = unsafe {
139- libc:: setsockopt (
140- socket. as_fd ( ) . as_raw_fd ( ) ,
141- libc:: SOL_TLS ,
142- direction,
143- ffi_ptr,
144- ffi_len,
145- )
146- } ;
147-
148- if ret < 0 {
149- return Err ( io:: Error :: last_os_error ( ) ) ;
150- }
151-
152- Ok ( ( ) )
153- }
154- }
155-
156- #[ derive( Debug , thiserror:: Error ) ]
157- /// Crypto material is invalid, e.g., wrong size key or IV.
158- enum InvalidCryptoInfo {
159- #[ error( "Wrong size key" ) ]
160- /// The provided key has an incorrect size (unlikely).
161- WrongSizeKey ,
162-
163- #[ error( "The negotiated cipher suite [{0:?}] is not supported by the current kernel" ) ]
164- /// The negotiated cipher suite is not supported by the current kernel.
165- UnsupportedCipherSuite ( SupportedCipherSuite ) ,
166- }
167-
168- impl From < InvalidCryptoInfo > for io:: Error {
169- fn from ( err : InvalidCryptoInfo ) -> Self {
170- io:: Error :: other ( err)
171- }
172- }
173-
174- impl TlsCryptoInfo {
175- /// Extract the [`TlsCryptoInfo`] from the given
176- /// [`SupportedCipherSuite`] and [`ConnectionTrafficSecrets`].
177- fn extract (
178- cipher_suite : SupportedCipherSuite ,
179- ( seq, secrets) : ( u64 , ConnectionTrafficSecrets ) ,
180- ) -> Result < Self , InvalidCryptoInfo > {
181- let version = match cipher_suite {
182- #[ cfg( feature = "tls12" ) ]
183- SupportedCipherSuite :: Tls12 ( ..) => libc:: TLS_1_2_VERSION ,
184- SupportedCipherSuite :: Tls13 ( ..) => libc:: TLS_1_3_VERSION ,
185- } ;
186-
187- Ok ( match secrets {
188- ConnectionTrafficSecrets :: Aes128Gcm { key, iv } => {
189- // see https://github.com/rustls/rustls/issues/1833, between
190- // rustls 0.21 and 0.22, the extract_keys codepath was changed,
191- // so, for TLS 1.2, both GCM-128 and GCM-256 return the
192- // Aes128Gcm variant.
193- //
194- // This issue is fixed since rustls 0.23.
195-
196- let iv_and_salt: & [ u8 ; NONCE_LEN ] = iv. as_ref ( ) . try_into ( ) . unwrap ( ) ;
197-
198- Self :: AesGcm128 ( libc:: tls12_crypto_info_aes_gcm_128 {
199- info : libc:: tls_crypto_info {
200- version,
201- cipher_type : libc:: TLS_CIPHER_AES_GCM_128 ,
202- } ,
203- iv : iv_and_salt[ 4 ..] . try_into ( ) . unwrap ( ) ,
204- key : key
205- . as_ref ( )
206- . try_into ( )
207- . map_err ( |_| InvalidCryptoInfo :: WrongSizeKey ) ?,
208- salt : iv_and_salt[ ..4 ] . try_into ( ) . unwrap ( ) ,
209- rec_seq : seq. to_be_bytes ( ) ,
210- } )
211- }
212- ConnectionTrafficSecrets :: Aes256Gcm { key, iv } => {
213- let iv_and_salt: & [ u8 ; NONCE_LEN ] = iv. as_ref ( ) . try_into ( ) . unwrap ( ) ;
214-
215- Self :: AesGcm256 ( libc:: tls12_crypto_info_aes_gcm_256 {
216- info : libc:: tls_crypto_info {
217- version,
218- cipher_type : libc:: TLS_CIPHER_AES_GCM_256 ,
219- } ,
220- iv : iv_and_salt[ 4 ..] . try_into ( ) . unwrap ( ) ,
221- key : key
222- . as_ref ( )
223- . try_into ( )
224- . map_err ( |_| InvalidCryptoInfo :: WrongSizeKey ) ?,
225- salt : iv_and_salt[ ..4 ] . try_into ( ) . unwrap ( ) ,
226- rec_seq : seq. to_be_bytes ( ) ,
227- } )
228- }
229- ConnectionTrafficSecrets :: Chacha20Poly1305 { key, iv } => {
230- Self :: Chacha20Poly1305 ( libc:: tls12_crypto_info_chacha20_poly1305 {
231- info : libc:: tls_crypto_info {
232- version,
233- cipher_type : libc:: TLS_CIPHER_CHACHA20_POLY1305 ,
234- } ,
235- iv : iv. as_ref ( ) . try_into ( ) . unwrap ( ) ,
236- key : key
237- . as_ref ( )
238- . try_into ( )
239- . map_err ( |_| InvalidCryptoInfo :: WrongSizeKey ) ?,
240- salt : [ ] ,
241- rec_seq : seq. to_be_bytes ( ) ,
242- } )
243- }
244- _ => {
245- return Err ( InvalidCryptoInfo :: UnsupportedCipherSuite ( cipher_suite) ) ;
246- }
247- } )
248- }
249- }
250-
25117const TLS_SET_RECORD_TYPE : libc:: c_int = 1 ;
25218const ALERT : u8 = 0x15 ;
25319
0 commit comments