diff --git a/Cargo.toml b/Cargo.toml index 57ccbb1..023c642 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -3,7 +3,7 @@ name = "rustls-libssl" version = "0.2.1" edition = "2021" build = "build.rs" -rust-version = "1.77" +rust-version = "1.88" [lib] name = "ssl" diff --git a/MATRIX.md b/MATRIX.md index 7520420..417a0fb 100644 --- a/MATRIX.md +++ b/MATRIX.md @@ -384,7 +384,7 @@ | `SSL_get_version` | :white_check_mark: | :white_check_mark: | :white_check_mark: | :white_check_mark: | | `SSL_get_wbio` | | :white_check_mark: | :white_check_mark: | :white_check_mark: | | `SSL_get_wfd` | | | | | -| `SSL_group_to_name` | | | | | +| `SSL_group_to_name` | | | | :white_check_mark: | | `SSL_has_matching_session_id` | | | | | | `SSL_has_pending` | | | | :white_check_mark: | | `SSL_in_before` | | | | :white_check_mark: | diff --git a/build.rs b/build.rs index cf63c1c..ff8b8f6 100644 --- a/build.rs +++ b/build.rs @@ -193,6 +193,7 @@ const ENTRYPOINTS: &[&str] = &[ "SSL_get_verify_result", "SSL_get_version", "SSL_get_wbio", + "SSL_group_to_name", "SSL_has_pending", "SSL_in_before", "SSL_in_init", diff --git a/src/constants.rs b/src/constants.rs index a52dcd3..a9a8bb8 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -123,6 +123,9 @@ pub fn sig_scheme_to_type_nid(scheme: SignatureScheme) -> Option { pub fn named_group_to_nid(group: NamedGroup) -> Option { use NamedGroup::*; + // See TLSEXT_nid_unknown from tls1.h - openssl-sys does not + // have a constant for this to import. + const TLSEXT_NID_UNKNOWN: c_int = 0x1000000; // See NID_ffhdhe* from obj_mac.h - openssl-sys does not have // constants for these to import. const NID_FFDHE2048: c_int = 1126; @@ -130,10 +133,11 @@ pub fn named_group_to_nid(group: NamedGroup) -> Option { const NID_FFDHE4096: c_int = 1128; const NID_FFDHE6144: c_int = 1129; const NID_FFDHE8192: c_int = 1130; - - // See TLSEXT_nid_unknown from tls1.h - openssl-sys does not - // have a constant for this to import. - const TLSEXT_NID_UNKNOWN: c_int = 0x1000000; + // See NID_ML_KEM_* from obj_mac.h - openssl-sys does not have + // constants for these to import. + const NID_ML_KEM_512: c_int = 1454; + const NID_ML_KEM_768: c_int = 1455; + const NID_ML_KEM_1024: c_int = 1456; match group { secp256r1 => Some(NID_X9_62_prime256v1), @@ -146,6 +150,9 @@ pub fn named_group_to_nid(group: NamedGroup) -> Option { FFDHE4096 => Some(NID_FFDHE4096), FFDHE6144 => Some(NID_FFDHE6144), FFDHE8192 => Some(NID_FFDHE8192), + MLKEM512 => Some(NID_ML_KEM_512), + MLKEM768 => Some(NID_ML_KEM_768), + MLKEM1024 => Some(NID_ML_KEM_1024), other => Some(TLSEXT_NID_UNKNOWN | u16::from(other) as c_int), } } diff --git a/src/entry.rs b/src/entry.rs index c751740..712be1b 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -1475,6 +1475,20 @@ entry! { } } +entry! { + pub fn _SSL_group_to_name(ssl: *const SSL, id: c_int) -> *const c_char { + try_clone_arc!(ssl) + .get() + .get_groups() + .iter() + .find(|group| named_group_to_nid(group.name()) == Some(id)) + .map(|group| group.name()) + .and_then(crate::TlsGroupInfo::find_by_id) + .map(|group| group.tls_name.as_ptr()) + .unwrap_or_else(ptr::null) + } +} + entry! { pub fn _SSL_version(ssl: *const SSL) -> c_int { try_clone_arc!(ssl) diff --git a/src/lib.rs b/src/lib.rs index bc381d2..d7b7881 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,13 +11,16 @@ use openssl_sys::{ EVP_PKEY, SSL_ERROR_NONE, SSL_ERROR_SSL, SSL_ERROR_WANT_READ, SSL_ERROR_WANT_WRITE, X509, X509_STORE, X509_V_ERR_UNSPECIFIED, }; + use rustls::client::Resumption; -use rustls::crypto::{aws_lc_rs as provider, SupportedKxGroup}; +use rustls::crypto::aws_lc_rs as provider; +use rustls::crypto::aws_lc_rs::Ticketer; +use rustls::crypto::SupportedKxGroup; use rustls::pki_types::{CertificateDer, ServerName}; use rustls::server::{Accepted, Acceptor, ProducesTickets}; use rustls::{ AlertDescription, CipherSuite, ClientConfig, ClientConnection, Connection, HandshakeKind, - ProtocolVersion, ServerConfig, SignatureScheme, SupportedProtocolVersion, + NamedGroup, ProtocolVersion, ServerConfig, SignatureScheme, SupportedProtocolVersion, }; use not_thread_safe::NotThreadSafe; @@ -100,7 +103,7 @@ pub struct SslCipher { pub standard_name: &'static CStr, pub version: &'static CStr, pub description: &'static CStr, - rustls: &'static rustls::SupportedCipherSuite, + pub rustls: CipherSuite, } impl SslCipher { @@ -132,7 +135,7 @@ impl SslCipher { } pub fn protocol_id(&self) -> u16 { - u16::from(self.rustls.suite()) + u16::from(self.rustls) } pub fn openssl_id(&self) -> u32 { @@ -141,7 +144,6 @@ impl SslCipher { } static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SslCipher = SslCipher { - rustls: &provider::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, auth: constants::NID_AUTH_ECDSA, kx: constants::NID_KX_ECDHE, bits: 128, @@ -149,10 +151,10 @@ static TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: SslCipher = SslCipher { standard_name: c"TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", version: c"TLSv1.2", description: c"ECDHE-ECDSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(128) Mac=AEAD\n", + rustls: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, }; static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SslCipher = SslCipher { - rustls: &provider::cipher_suite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, auth: constants::NID_AUTH_ECDSA, kx: constants::NID_KX_ECDHE, bits: 256, @@ -160,21 +162,21 @@ static TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: SslCipher = SslCipher { standard_name: c"TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", version: c"TLSv1.2", description: c"ECDHE-ECDSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=ECDSA Enc=AESGCM(256) Mac=AEAD\n", + rustls: CipherSuite::TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, }; static TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256: SslCipher = SslCipher { - rustls: &provider::cipher_suite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, auth: constants::NID_AUTH_ECDSA, kx: constants::NID_KX_ECDHE, bits: 256, openssl_name: c"ECDHE-ECDSA-CHACHA20-POLY1305", standard_name: c"TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", + rustls: CipherSuite::TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, version: c"TLSv1.2", description: c"ECDHE-ECDSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=ECDSA Enc=CHACHA20/POLY1305(256) Mac=AEAD\n", }; static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SslCipher = SslCipher { - rustls: &provider::cipher_suite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, auth: constants::NID_AUTH_RSA, kx: constants::NID_KX_ECDHE, bits: 128, @@ -182,10 +184,10 @@ static TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: SslCipher = SslCipher { standard_name: c"TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", version: c"TLSv1.2", description: c"ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(128) Mac=AEAD\n", + rustls: CipherSuite::TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, }; static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SslCipher = SslCipher { - rustls: &provider::cipher_suite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, auth: constants::NID_AUTH_RSA, kx: constants::NID_KX_ECDHE, bits: 256, @@ -193,10 +195,10 @@ static TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: SslCipher = SslCipher { standard_name: c"TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", version: c"TLSv1.2", description: c"ECDHE-RSA-AES256-GCM-SHA384 TLSv1.2 Kx=ECDH Au=RSA Enc=AESGCM(256) Mac=AEAD\n", + rustls: CipherSuite::TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, }; static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SslCipher = SslCipher { - rustls: &provider::cipher_suite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, auth: constants::NID_AUTH_RSA, kx: constants::NID_KX_ECDHE, bits: 256, @@ -204,10 +206,10 @@ static TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256: SslCipher = SslCipher { standard_name: c"TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", version: c"TLSv1.2", description: c"ECDHE-RSA-CHACHA20-POLY1305 TLSv1.2 Kx=ECDH Au=RSA Enc=CHACHA20/POLY1305(256) Mac=AEAD\n", + rustls: CipherSuite::TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, }; static TLS13_AES_128_GCM_SHA256: SslCipher = SslCipher { - rustls: &provider::cipher_suite::TLS13_AES_128_GCM_SHA256, auth: constants::NID_AUTH_ANY, kx: constants::NID_KX_ANY, bits: 128, @@ -215,10 +217,10 @@ static TLS13_AES_128_GCM_SHA256: SslCipher = SslCipher { standard_name: c"TLS_AES_128_GCM_SHA256", version: c"TLSv1.3", description: c"TLS_AES_128_GCM_SHA256 TLSv1.3 Kx=any Au=any Enc=AESGCM(128) Mac=AEAD\n", + rustls: CipherSuite::TLS13_AES_128_GCM_SHA256, }; static TLS13_AES_256_GCM_SHA384: SslCipher = SslCipher { - rustls: &provider::cipher_suite::TLS13_AES_256_GCM_SHA384, auth: constants::NID_AUTH_ANY, kx: constants::NID_KX_ANY, bits: 256, @@ -226,10 +228,10 @@ static TLS13_AES_256_GCM_SHA384: SslCipher = SslCipher { standard_name: c"TLS_AES_256_GCM_SHA384", version: c"TLSv1.3", description: c"TLS_AES_256_GCM_SHA384 TLSv1.3 Kx=any Au=any Enc=AESGCM(256) Mac=AEAD\n", + rustls: CipherSuite::TLS13_AES_256_GCM_SHA384, }; static TLS13_CHACHA20_POLY1305_SHA256: SslCipher = SslCipher { - rustls: &provider::cipher_suite::TLS13_CHACHA20_POLY1305_SHA256, auth: constants::NID_AUTH_ANY, kx: constants::NID_KX_ANY, bits: 256, @@ -237,6 +239,159 @@ static TLS13_CHACHA20_POLY1305_SHA256: SslCipher = SslCipher { standard_name: c"TLS_CHACHA20_POLY1305_SHA256", version: c"TLSv1.3", description: c"TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD\n", + rustls: CipherSuite::TLS13_CHACHA20_POLY1305_SHA256, +}; + +#[allow(dead_code)] +struct TlsGroupInfo { + pub tls_name: &'static CStr, + pub standard_name: &'static CStr, + pub algorithm: &'static CStr, + pub secbits: usize, + pub group_id: NamedGroup, +} + +impl TlsGroupInfo { + pub fn find_by_id(id: NamedGroup) -> Option<&'static Self> { + match id { + NamedGroup::secp256r1 => Some(&SECP256R1), + NamedGroup::secp384r1 => Some(&SECP384R1), + NamedGroup::secp521r1 => Some(&SECP521R1), + NamedGroup::X25519 => Some(&X25519), + NamedGroup::X448 => Some(&X448), + NamedGroup::FFDHE2048 => Some(&FFDHE2048), + NamedGroup::FFDHE3072 => Some(&FFDHE3072), + NamedGroup::FFDHE4096 => Some(&FFDHE4096), + NamedGroup::FFDHE6144 => Some(&FFDHE6144), + NamedGroup::FFDHE8192 => Some(&FFDHE8192), + NamedGroup::MLKEM512 => Some(&MLKEM512), + NamedGroup::MLKEM768 => Some(&MLKEM768), + NamedGroup::MLKEM1024 => Some(&MLKEM1024), + NamedGroup::X25519MLKEM768 => Some(&X25519MLKEM768), + NamedGroup::secp256r1MLKEM768 => Some(&SECP256R1_MLKEM768), + _ => None, + } + } +} + +static SECP256R1: TlsGroupInfo = TlsGroupInfo { + tls_name: c"secp256r1", + standard_name: c"prime256v1", + algorithm: c"EC", + secbits: 128, + group_id: NamedGroup::secp256r1, +}; + +static SECP384R1: TlsGroupInfo = TlsGroupInfo { + tls_name: c"secp384r1", + standard_name: c"secp384r1", + algorithm: c"EC", + secbits: 192, + group_id: NamedGroup::secp384r1, +}; + +static SECP521R1: TlsGroupInfo = TlsGroupInfo { + tls_name: c"secp521r1", + standard_name: c"secp521r1", + algorithm: c"EC", + secbits: 256, + group_id: NamedGroup::secp521r1, +}; + +static X25519: TlsGroupInfo = TlsGroupInfo { + tls_name: c"x25519", + standard_name: c"X25519", + algorithm: c"X25519", + secbits: 128, + group_id: NamedGroup::X25519, +}; + +static X448: TlsGroupInfo = TlsGroupInfo { + tls_name: c"x448", + standard_name: c"X448", + algorithm: c"X448", + secbits: 224, + group_id: NamedGroup::X448, +}; + +static FFDHE2048: TlsGroupInfo = TlsGroupInfo { + tls_name: c"ffdhe2048", + standard_name: c"ffdhe2048", + algorithm: c"DH", + secbits: 112, + group_id: NamedGroup::FFDHE2048, +}; + +static FFDHE3072: TlsGroupInfo = TlsGroupInfo { + tls_name: c"ffdhe3072", + standard_name: c"ffdhe3072", + algorithm: c"DH", + secbits: 128, + group_id: NamedGroup::FFDHE3072, +}; + +static FFDHE4096: TlsGroupInfo = TlsGroupInfo { + tls_name: c"ffdhe4096", + standard_name: c"ffdhe4096", + algorithm: c"DH", + secbits: 128, + group_id: NamedGroup::FFDHE4096, +}; + +static FFDHE6144: TlsGroupInfo = TlsGroupInfo { + tls_name: c"ffdhe6144", + standard_name: c"ffdhe6144", + algorithm: c"DH", + secbits: 128, + group_id: NamedGroup::FFDHE6144, +}; + +static FFDHE8192: TlsGroupInfo = TlsGroupInfo { + tls_name: c"ffdhe8192", + standard_name: c"ffdhe8192", + algorithm: c"DH", + secbits: 192, + group_id: NamedGroup::FFDHE8192, +}; + +static MLKEM512: TlsGroupInfo = TlsGroupInfo { + tls_name: c"MLKEM512", + standard_name: c"", + algorithm: c"ML-KEM-512", + secbits: 128, + group_id: NamedGroup::MLKEM512, +}; + +static MLKEM768: TlsGroupInfo = TlsGroupInfo { + tls_name: c"MLKEM768", + standard_name: c"", + algorithm: c"ML-KEM-768", + secbits: 192, + group_id: NamedGroup::MLKEM768, +}; + +static MLKEM1024: TlsGroupInfo = TlsGroupInfo { + tls_name: c"MLKEM1024", + standard_name: c"", + algorithm: c"ML-KEM-1024", + secbits: 256, + group_id: NamedGroup::MLKEM1024, +}; + +static X25519MLKEM768: TlsGroupInfo = TlsGroupInfo { + tls_name: c"X25519MLKEM768", + standard_name: c"", + algorithm: c"X25519MLKEM768", + secbits: 192, + group_id: NamedGroup::X25519MLKEM768, +}; + +static SECP256R1_MLKEM768: TlsGroupInfo = TlsGroupInfo { + tls_name: c"SecP256r1MLKEM768", + standard_name: c"", + algorithm: c"SecP256r1MLKEM768", + secbits: 192, + group_id: NamedGroup::secp256r1MLKEM768, }; /// Backs a server-side SSL_SESSION object @@ -459,6 +614,7 @@ pub struct SslContext { info_callback: callbacks::InfoCallbackConfig, client_hello_callback: callbacks::ClientHelloCallbackConfig, auth_keys: sign::CertifiedKeySet, + groups: Vec<&'static dyn SupportedKxGroup>, max_early_data: u32, } @@ -468,7 +624,7 @@ impl SslContext { // a ticketer. Doing so is wasteful for a client, and incompatible with miri // (due to calls to a foreign function, `RAND_bytes`). let ticketer = match !method.server_versions.is_empty() && cfg!(not(miri)) { - true => provider::Ticketer::new().ok(), + true => Ticketer::new().ok(), false => None, }; Self { @@ -491,6 +647,7 @@ impl SslContext { info_callback: callbacks::InfoCallbackConfig::default(), client_hello_callback: callbacks::ClientHelloCallbackConfig::default(), auth_keys: sign::CertifiedKeySet::default(), + groups: provider::default_provider().kx_groups.clone(), max_early_data: 0, } } @@ -521,6 +678,10 @@ impl SslContext { self.raw_options } + fn get_groups(&self) -> &Vec<&'static dyn SupportedKxGroup> { + &self.groups + } + fn get_num_tickets(&self) -> usize { self.num_tickets } @@ -880,6 +1041,10 @@ impl Ssl { self.raw_options } + fn get_groups(&self) -> &Vec<&'static dyn SupportedKxGroup> { + self.ctx.get().get_groups() + } + fn get_num_tickets(&self) -> usize { self.num_tickets } @@ -1098,7 +1263,6 @@ impl Ssl { if let ConnMode::Unknown = self.mode { self.set_client_mode(); } - if matches!(self.conn, ConnState::Nothing) { self.init_client_conn()?; }