Skip to content

Commit 219e0f0

Browse files
committed
refactor(setup): move setup_* and related stuff to separate module
1 parent ce40fc2 commit 219e0f0

File tree

3 files changed

+262
-243
lines changed

3 files changed

+262
-243
lines changed

ktls/src/ffi.rs

Lines changed: 1 addition & 235 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,9 @@
1-
use std::os::fd::{AsFd, AsRawFd};
21
use std::os::unix::prelude::RawFd;
3-
use std::{io, mem};
42

53
use ktls_sys::bindings as ktls;
6-
use nix::sys::socket::{setsockopt, sockopt};
7-
use rustls::crypto::cipher::NONCE_LEN;
84
use rustls::internal::msgs::enums::AlertLevel;
95
use rustls::internal::msgs::message::Message;
10-
use rustls::{AlertDescription, ConnectionTrafficSecrets, ExtractedSecrets, SupportedCipherSuite};
6+
use rustls::AlertDescription;
117

128
pub(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
1915
const 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-
25117
const TLS_SET_RECORD_TYPE: libc::c_int = 1;
25218
const ALERT: u8 = 0x15;
25319

ktls/src/lib.rs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ mod async_read_ready;
77
mod cork_stream;
88
mod ffi;
99
mod ktls_stream;
10+
mod setup;
1011

1112
use std::future::Future;
1213
use std::io;
@@ -26,8 +27,8 @@ use tokio::net::{TcpListener, TcpStream};
2627

2728
pub use crate::async_read_ready::AsyncReadReady;
2829
pub use crate::cork_stream::CorkStream;
29-
pub use crate::ffi::{setup_ulp, SetupUlpError};
3030
pub use crate::ktls_stream::KtlsStream;
31+
pub use crate::setup::{setup_ulp, SetupUlpError};
3132

3233
#[derive(Debug, Default)]
3334
pub struct CompatibleCiphers {
@@ -174,7 +175,7 @@ fn sample_cipher_setup(
174175

175176
let crypto_info = match kcs.typ {
176177
KtlsCipherType::AesGcm128 => {
177-
ffi::TlsCryptoInfo::AesGcm128(libc::tls12_crypto_info_aes_gcm_128 {
178+
setup::TlsCryptoInfo::AesGcm128(libc::tls12_crypto_info_aes_gcm_128 {
178179
info: libc::tls_crypto_info {
179180
version: ffi_version,
180181
cipher_type: libc::TLS_CIPHER_AES_GCM_128 as _,
@@ -186,7 +187,7 @@ fn sample_cipher_setup(
186187
})
187188
}
188189
KtlsCipherType::AesGcm256 => {
189-
ffi::TlsCryptoInfo::AesGcm256(libc::tls12_crypto_info_aes_gcm_256 {
190+
setup::TlsCryptoInfo::AesGcm256(libc::tls12_crypto_info_aes_gcm_256 {
190191
info: libc::tls_crypto_info {
191192
version: ffi_version,
192193
cipher_type: libc::TLS_CIPHER_AES_GCM_256 as _,
@@ -198,7 +199,7 @@ fn sample_cipher_setup(
198199
})
199200
}
200201
KtlsCipherType::Chacha20Poly1305 => {
201-
ffi::TlsCryptoInfo::Chacha20Poly1305(libc::tls12_crypto_info_chacha20_poly1305 {
202+
setup::TlsCryptoInfo::Chacha20Poly1305(libc::tls12_crypto_info_chacha20_poly1305 {
202203
info: libc::tls_crypto_info {
203204
version: ffi_version,
204205
cipher_type: libc::TLS_CIPHER_CHACHA20_POLY1305 as _,
@@ -211,7 +212,7 @@ fn sample_cipher_setup(
211212
}
212213
};
213214

214-
ffi::setup_ulp(socket).map_err(Error::UlpError)?;
215+
setup::setup_ulp(socket).map_err(Error::UlpError)?;
215216

216217
crypto_info
217218
.set_tx(socket)
@@ -223,7 +224,7 @@ fn sample_cipher_setup(
223224
#[derive(thiserror::Error, Debug)]
224225
pub enum Error {
225226
#[error(transparent)]
226-
UlpError(#[from] ffi::SetupUlpError),
227+
UlpError(#[from] setup::SetupUlpError),
227228

228229
#[error("failed to export secrets")]
229230
ExportSecrets(#[source] rustls::Error),
@@ -340,8 +341,8 @@ fn setup_inner<S: AsFd>(socket: &S, conn: Connection) -> Result<(), Error> {
340341
Err(err) => return Err(Error::ExportSecrets(err)),
341342
};
342343

343-
ffi::setup_ulp(socket).map_err(Error::UlpError)?;
344-
ffi::setup_tls_params(socket, cipher_suite, secrets).map_err(Error::TlsCryptoInfoError)?;
344+
setup::setup_ulp(socket).map_err(Error::UlpError)?;
345+
setup::setup_tls_params(socket, cipher_suite, secrets).map_err(Error::TlsCryptoInfoError)?;
345346

346347
Ok(())
347348
}

0 commit comments

Comments
 (0)