Skip to content

Commit

Permalink
WIP: rustls 0.22 support
Browse files Browse the repository at this point in the history
  • Loading branch information
fasterthanlime committed Mar 11, 2024
1 parent 3283fbd commit 03855c0
Show file tree
Hide file tree
Showing 6 changed files with 215 additions and 99 deletions.
46 changes: 29 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ Configures kTLS for tokio-rustls client and server connections.
libc = { version = "0.2.148", features = ["const-extern-fn"] }
thiserror = "1.0.49"
tracing = "0.1.37"
tokio-rustls = "0.24.1"
rustls = { version = "0.21.7", features = ["secret_extraction"] }
tokio-rustls = "0.25.0"
rustls = { version = "0.22" }
smallvec = "1.11.1"
memoffset = "0.9.0"
pin-project-lite = "0.2.13"
Expand Down
5 changes: 4 additions & 1 deletion Justfile
Original file line number Diff line number Diff line change
Expand Up @@ -15,4 +15,7 @@ cov:

# Run all tests
test *args:
RUST_BACKTRACE=1 cargo nextest run {{args}}
RUST_BACKTRACE=1 cargo nextest run {{args}}

check:
cargo clippy --all-features --all-targets
89 changes: 65 additions & 24 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,38 +138,79 @@ impl CryptoInfo {
};

Ok(match secrets {
ConnectionTrafficSecrets::Aes128Gcm { key, salt, iv } => {
CryptoInfo::AesGcm128(ktls::tls12_crypto_info_aes_gcm_128 {
info: ktls::tls_crypto_info {
version,
cipher_type: ktls::TLS_CIPHER_AES_GCM_128 as _,
},
iv,
key,
salt,
rec_seq: seq.to_be_bytes(),
})
ConnectionTrafficSecrets::Aes128Gcm { key, iv } => {
// see https://github.com/rustls/rustls/issues/1833,
// between rustls 0.21 and 0.22, the extract_keys codepath
// was changed, so it always returns AesGcm128, even if
// the cipher suite is Aes256Gcm.

match key.as_ref().len() {
16 => CryptoInfo::AesGcm128(ktls::tls12_crypto_info_aes_gcm_128 {
info: ktls::tls_crypto_info {
version,
cipher_type: ktls::TLS_CIPHER_AES_GCM_128 as _,
},
iv: iv
.as_ref()
.get(4..)
.expect("AES-GCM-128 iv is 8 bytes")
.try_into()
.expect("AES-GCM-128 iv is 8 bytes"),
key: key
.as_ref()
.try_into()
.expect("AES-GCM-128 key is 16 bytes"),
salt: iv
.as_ref()
.get(..4)
.expect("AES-GCM-128 salt is 4 bytes")
.try_into()
.expect("AES-GCM-128 salt is 4 bytes"),
rec_seq: seq.to_be_bytes(),
}),
32 => CryptoInfo::AesGcm256(ktls::tls12_crypto_info_aes_gcm_256 {
info: ktls::tls_crypto_info {
version,
cipher_type: ktls::TLS_CIPHER_AES_GCM_256 as _,
},
iv: iv
.as_ref()
.get(4..)
.expect("AES-GCM-256 iv is 8 bytes")
.try_into()
.expect("AES-GCM-256 iv is 8 bytes"),
key: key
.as_ref()
.try_into()
.expect("AES-GCM-256 key is 32 bytes"),
salt: iv
.as_ref()
.get(..4)
.expect("AES-GCM-256 salt is 4 bytes")
.try_into()
.expect("AES-GCM-256 salt is 4 bytes"),
rec_seq: seq.to_be_bytes(),
}),
_ => unreachable!("GCM key length is not 16 or 32"),
}
}
ConnectionTrafficSecrets::Aes256Gcm { key, salt, iv } => {
CryptoInfo::AesGcm256(ktls::tls12_crypto_info_aes_gcm_256 {
info: ktls::tls_crypto_info {
version,
cipher_type: ktls::TLS_CIPHER_AES_GCM_256 as _,
},
iv,
key,
salt,
rec_seq: seq.to_be_bytes(),
})
ConnectionTrafficSecrets::Aes256Gcm { .. } => {
unreachable!("a bug in rustls 0.22 means this codepath is dead. when we can upgrade to 0.23, we should fix this. see https://github.com/rustls/rustls/issues/1833")
}
ConnectionTrafficSecrets::Chacha20Poly1305 { key, iv } => {
CryptoInfo::Chacha20Poly1305(ktls::tls12_crypto_info_chacha20_poly1305 {
info: ktls::tls_crypto_info {
version,
cipher_type: ktls::TLS_CIPHER_CHACHA20_POLY1305 as _,
},
iv,
key,
iv: iv
.as_ref()
.try_into()
.expect("Chacha20-Poly1305 iv is 12 bytes"),
key: key
.as_ref()
.try_into()
.expect("Chacha20-Poly1305 key is 32 bytes"),
salt: ktls::__IncompleteArrayField::new(),
rec_seq: seq.to_be_bytes(),
})
Expand Down
116 changes: 84 additions & 32 deletions src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use ffi::{setup_tls_info, setup_ulp, KtlsCompatibilityError};
use futures::future::try_join_all;
use rustls::{Connection, ConnectionTrafficSecrets, SupportedCipherSuite};
use ktls_sys::bindings as sys;
use rustls::{crypto::ring::cipher_suite, Connection, SupportedCipherSuite};
use smallvec::SmallVec;
use std::{
io,
Expand Down Expand Up @@ -90,27 +91,27 @@ impl CompatibleCiphers {
fn test_ciphers(&mut self, socks: &[TcpStream; Self::CIPHERS_COUNT]) {
let ciphers = [
(
rustls::cipher_suite::TLS13_AES_128_GCM_SHA256,
cipher_suite::TLS13_AES_128_GCM_SHA256,
&mut self.tls13.aes_gcm_128,
),
(
rustls::cipher_suite::TLS13_AES_256_GCM_SHA384,
cipher_suite::TLS13_AES_256_GCM_SHA384,
&mut self.tls13.aes_gcm_256,
),
(
rustls::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256,
cipher_suite::TLS13_CHACHA20_POLY1305_SHA256,
&mut self.tls13.chacha20_poly1305,
),
(
rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
&mut self.tls12.aes_gcm_128,
),
(
rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
&mut self.tls12.aes_gcm_256,
),
(
rustls::cipher_suite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
cipher_suite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
&mut self.tls12.chacha20_poly1305,
),
];
Expand All @@ -128,48 +129,99 @@ impl CompatibleCiphers {
/// Returns true if we're reasonably confident that functions like
/// [config_ktls_client] and [config_ktls_server] will succeed.
pub fn is_compatible(&self, suite: &SupportedCipherSuite) -> bool {
let (fields, bulk) = match suite {
SupportedCipherSuite::Tls12(suite) => (&self.tls12, &suite.common.bulk),
SupportedCipherSuite::Tls13(suite) => (&self.tls13, &suite.common.bulk),
};
match bulk {
rustls::BulkAlgorithm::Aes128Gcm => fields.aes_gcm_128,
rustls::BulkAlgorithm::Aes256Gcm => fields.aes_gcm_256,
rustls::BulkAlgorithm::Chacha20Poly1305 => fields.chacha20_poly1305,
if suite == &cipher_suite::TLS13_AES_128_GCM_SHA256 {
self.tls13.aes_gcm_128
} else if suite == &cipher_suite::TLS13_AES_256_GCM_SHA384 {
self.tls13.aes_gcm_256
} else if suite == &cipher_suite::TLS13_CHACHA20_POLY1305_SHA256 {
self.tls13.chacha20_poly1305
} else if suite == &cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 {
self.tls12.aes_gcm_128
} else if suite == &cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 {
self.tls12.aes_gcm_256
} else if suite == &cipher_suite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 {
self.tls12.chacha20_poly1305
} else {
false
}
}
}

fn sample_cipher_setup(sock: &TcpStream, cipher_suite: SupportedCipherSuite) -> Result<(), Error> {
let bulk_algo = match cipher_suite {
SupportedCipherSuite::Tls12(suite) => &suite.common.bulk,
SupportedCipherSuite::Tls13(suite) => &suite.common.bulk,
};
let zero_secrets = match bulk_algo {
rustls::BulkAlgorithm::Aes128Gcm => ConnectionTrafficSecrets::Aes128Gcm {
let crypto_info = if cipher_suite == cipher_suite::TLS13_AES_128_GCM_SHA256 {
CryptoInfo::AesGcm128(sys::tls12_crypto_info_aes_gcm_128 {
info: sys::tls_crypto_info {
version: ffi::TLS_1_3_VERSION_NUMBER,
cipher_type: sys::TLS_CIPHER_AES_GCM_128 as _,
},
iv: Default::default(),
key: Default::default(),
salt: Default::default(),
rec_seq: Default::default(),
})
} else if cipher_suite == cipher_suite::TLS13_AES_256_GCM_SHA384 {
CryptoInfo::AesGcm256(sys::tls12_crypto_info_aes_gcm_256 {
info: sys::tls_crypto_info {
version: ffi::TLS_1_3_VERSION_NUMBER,
cipher_type: sys::TLS_CIPHER_AES_GCM_256 as _,
},
iv: Default::default(),
key: Default::default(),
salt: Default::default(),
rec_seq: Default::default(),
})
} else if cipher_suite == cipher_suite::TLS13_CHACHA20_POLY1305_SHA256 {
CryptoInfo::Chacha20Poly1305(sys::tls12_crypto_info_chacha20_poly1305 {
info: sys::tls_crypto_info {
version: ffi::TLS_1_3_VERSION_NUMBER,
cipher_type: sys::TLS_CIPHER_CHACHA20_POLY1305 as _,
},
iv: Default::default(),
},
rustls::BulkAlgorithm::Aes256Gcm => ConnectionTrafficSecrets::Aes256Gcm {
key: Default::default(),
salt: Default::default(),
rec_seq: Default::default(),
})
} else if cipher_suite == cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 {
CryptoInfo::AesGcm128(sys::tls12_crypto_info_aes_gcm_128 {
info: sys::tls_crypto_info {
version: ffi::TLS_1_2_VERSION_NUMBER,
cipher_type: sys::TLS_CIPHER_AES_GCM_128 as _,
},
iv: Default::default(),
},
rustls::BulkAlgorithm::Chacha20Poly1305 => ConnectionTrafficSecrets::Chacha20Poly1305 {
key: Default::default(),
salt: Default::default(),
rec_seq: Default::default(),
})
} else if cipher_suite == cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 {
CryptoInfo::AesGcm256(sys::tls12_crypto_info_aes_gcm_256 {
info: sys::tls_crypto_info {
version: ffi::TLS_1_2_VERSION_NUMBER,
cipher_type: sys::TLS_CIPHER_AES_GCM_256 as _,
},
iv: Default::default(),
},
key: Default::default(),
salt: Default::default(),
rec_seq: Default::default(),
})
} else if cipher_suite == cipher_suite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 {
CryptoInfo::Chacha20Poly1305(sys::tls12_crypto_info_chacha20_poly1305 {
info: sys::tls_crypto_info {
version: ffi::TLS_1_2_VERSION_NUMBER,
cipher_type: sys::TLS_CIPHER_CHACHA20_POLY1305 as _,
},
iv: Default::default(),
key: Default::default(),
salt: Default::default(),
rec_seq: Default::default(),
})
} else {
panic!("unsupported cipher suite")
};

let seq_secrets = (0, zero_secrets);
let info = CryptoInfo::from_rustls(cipher_suite, seq_secrets).unwrap();

let fd = sock.as_raw_fd();

setup_ulp(fd).map_err(Error::UlpError)?;

setup_tls_info(fd, ffi::Direction::Tx, info)?;
setup_tls_info(fd, ffi::Direction::Tx, crypto_info)?;

Ok(())
}
Expand Down Expand Up @@ -285,7 +337,7 @@ fn setup_inner(fd: RawFd, conn: Connection) -> Result<(), Error> {
}
};

let secrets = match conn.extract_secrets() {
let secrets = match conn.dangerous_extract_secrets() {
Ok(secrets) => secrets,
Err(err) => return Err(Error::ExportSecrets(err)),
};
Expand Down
Loading

0 comments on commit 03855c0

Please sign in to comment.