use std::os::raw::c_int;
use crate::ffi::Ssl;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum KtlsCipher {
Tls13Aes128Gcm,
Tls13Aes256Gcm,
Tls13Chacha20Poly1305,
Tls12Aes128Gcm,
Tls12Aes256Gcm,
Tls12Chacha20Poly1305,
}
impl KtlsCipher {
pub(crate) fn detect(ssl: &Ssl) -> Option<Self> {
let version = unsafe { aws_lc_sys::SSL_version(ssl.as_ptr()) };
let cipher = unsafe { aws_lc_sys::SSL_get_current_cipher(ssl.as_ptr()) };
if cipher.is_null() {
return None;
}
let id = unsafe { aws_lc_sys::SSL_CIPHER_get_protocol_id(cipher) };
Self::from_ids(version, id)
}
fn from_ids(tls_version: c_int, cipher_id: u16) -> Option<Self> {
const TLS_AES_128_GCM_SHA256: u16 = 0x1301;
const TLS_AES_256_GCM_SHA384: u16 = 0x1302;
const TLS_CHACHA20_POLY1305_SHA256: u16 = 0x1303;
const ECDHE_ECDSA_AES128_GCM_SHA256: u16 = 0xC02B;
const ECDHE_RSA_AES128_GCM_SHA256: u16 = 0xC02F;
const ECDHE_ECDSA_AES256_GCM_SHA384: u16 = 0xC02C;
const ECDHE_RSA_AES256_GCM_SHA384: u16 = 0xC030;
const ECDHE_ECDSA_CHACHA20_POLY1305: u16 = 0xCCA9;
const ECDHE_RSA_CHACHA20_POLY1305: u16 = 0xCCA8;
if tls_version == aws_lc_sys::TLS1_3_VERSION {
match cipher_id {
TLS_AES_128_GCM_SHA256 => Some(Self::Tls13Aes128Gcm),
TLS_AES_256_GCM_SHA384 => Some(Self::Tls13Aes256Gcm),
TLS_CHACHA20_POLY1305_SHA256 => Some(Self::Tls13Chacha20Poly1305),
_ => None,
}
} else if tls_version == aws_lc_sys::TLS1_2_VERSION {
match cipher_id {
ECDHE_ECDSA_AES128_GCM_SHA256 | ECDHE_RSA_AES128_GCM_SHA256 => {
Some(Self::Tls12Aes128Gcm)
}
ECDHE_ECDSA_AES256_GCM_SHA384 | ECDHE_RSA_AES256_GCM_SHA384 => {
Some(Self::Tls12Aes256Gcm)
}
ECDHE_ECDSA_CHACHA20_POLY1305 | ECDHE_RSA_CHACHA20_POLY1305 => {
Some(Self::Tls12Chacha20Poly1305)
}
_ => None,
}
} else {
None
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn tls13_aead_suites_recognised() {
assert_eq!(
KtlsCipher::from_ids(aws_lc_sys::TLS1_3_VERSION, 0x1301),
Some(KtlsCipher::Tls13Aes128Gcm)
);
assert_eq!(
KtlsCipher::from_ids(aws_lc_sys::TLS1_3_VERSION, 0x1302),
Some(KtlsCipher::Tls13Aes256Gcm)
);
assert_eq!(
KtlsCipher::from_ids(aws_lc_sys::TLS1_3_VERSION, 0x1303),
Some(KtlsCipher::Tls13Chacha20Poly1305)
);
}
#[test]
fn tls12_aead_suites_recognised() {
for id in [0xC02Bu16, 0xC02F] {
assert_eq!(
KtlsCipher::from_ids(aws_lc_sys::TLS1_2_VERSION, id),
Some(KtlsCipher::Tls12Aes128Gcm),
"id 0x{id:04X}"
);
}
for id in [0xC02Cu16, 0xC030] {
assert_eq!(
KtlsCipher::from_ids(aws_lc_sys::TLS1_2_VERSION, id),
Some(KtlsCipher::Tls12Aes256Gcm),
"id 0x{id:04X}"
);
}
for id in [0xCCA8u16, 0xCCA9] {
assert_eq!(
KtlsCipher::from_ids(aws_lc_sys::TLS1_2_VERSION, id),
Some(KtlsCipher::Tls12Chacha20Poly1305),
"id 0x{id:04X}"
);
}
}
#[test]
fn non_aead_tls12_rejected() {
assert!(KtlsCipher::from_ids(aws_lc_sys::TLS1_2_VERSION, 0xC013).is_none());
}
#[test]
fn tls13_with_tls12_cipher_rejected() {
assert!(KtlsCipher::from_ids(aws_lc_sys::TLS1_3_VERSION, 0xC02F).is_none());
}
#[test]
fn pre_tls12_rejected() {
assert!(KtlsCipher::from_ids(0x0301, 0x1301).is_none());
assert!(KtlsCipher::from_ids(0x0302, 0xC02F).is_none());
}
}