From c4d758575c612af57401d063912953771eb214c0 Mon Sep 17 00:00:00 2001 From: Vincent Date: Tue, 4 Nov 2025 17:31:44 +0100 Subject: [PATCH 1/2] Added: TLSGroupInfo Added: New Entrypoint to build Added: New NIDs --- MATRIX.md | 2 +- build.rs | 1 + src/constants.rs | 15 +++-- src/entry.rs | 14 ++++ src/lib.rs | 166 ++++++++++++++++++++++++++++++++++++++++++++++- 5 files changed, 191 insertions(+), 7 deletions(-) diff --git a/MATRIX.md b/MATRIX.md index 75204204..417a0fb8 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 cf63c1c7..ff8b8f69 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 a52dcd30..a9a8bb8a 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 c7517400..712be1b0 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 bc381d20..d3f9a06e 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -11,13 +11,14 @@ 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::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; @@ -239,6 +240,158 @@ static TLS13_CHACHA20_POLY1305_SHA256: SslCipher = SslCipher { description: c"TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD\n", }; +#[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 /// /// Note that this has equality and ordering entirely based on the `id` field. @@ -459,6 +612,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, } @@ -491,6 +645,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 +676,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 +1039,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 +1261,6 @@ impl Ssl { if let ConnMode::Unknown = self.mode { self.set_client_mode(); } - if matches!(self.conn, ConnState::Nothing) { self.init_client_conn()?; } From 6343a4aa83fd1e2d3f74e76e18fd8c1417b9d642 Mon Sep 17 00:00:00 2001 From: Vincent Date: Mon, 10 Nov 2025 17:50:42 +0100 Subject: [PATCH 2/2] Refactored: Moved TLSGroupNames to constants Added: Test group_to_name in tests/constants.c Refactored: Moved tests in separate functions in tests/constants.c --- src/constants.rs | 21 +++++++ src/entry.rs | 12 ++-- src/lib.rs | 155 +--------------------------------------------- tests/constants.c | 33 +++++++++- 4 files changed, 62 insertions(+), 159 deletions(-) diff --git a/src/constants.rs b/src/constants.rs index a9a8bb8a..8aabec8d 100644 --- a/src/constants.rs +++ b/src/constants.rs @@ -120,6 +120,27 @@ pub fn sig_scheme_to_type_nid(scheme: SignatureScheme) -> Option { } } +pub fn named_group_to_tls_name(id: NamedGroup) -> Option<&'static CStr> { + match id { + NamedGroup::secp256r1 => Some(c"secp256r1"), + NamedGroup::secp384r1 => Some(c"secp384r1"), + NamedGroup::secp521r1 => Some(c"secp521r1"), + NamedGroup::X25519 => Some(c"x25519"), + NamedGroup::X448 => Some(c"x448"), + NamedGroup::FFDHE2048 => Some(c"ffdhe2048"), + NamedGroup::FFDHE3072 => Some(c"ffdhe3072"), + NamedGroup::FFDHE4096 => Some(c"ffdhe4096"), + NamedGroup::FFDHE6144 => Some(c"ffdhe6144"), + NamedGroup::FFDHE8192 => Some(c"ffdhe8192"), + NamedGroup::MLKEM512 => Some(c"MLKEM512"), + NamedGroup::MLKEM768 => Some(c"MLKEM768"), + NamedGroup::MLKEM1024 => Some(c"MLKEM1024"), + NamedGroup::X25519MLKEM768 => Some(c"X25519MLKEM768"), + NamedGroup::secp256r1MLKEM768 => Some(c"SecP256r1MLKEM768"), + _ => None, + } +} + pub fn named_group_to_nid(group: NamedGroup) -> Option { use NamedGroup::*; diff --git a/src/entry.rs b/src/entry.rs index 712be1b0..9394e925 100644 --- a/src/entry.rs +++ b/src/entry.rs @@ -22,7 +22,7 @@ use rustls::pki_types::{CertificateDer, PrivateKeyDer, PrivatePkcs8KeyDer}; use crate::bio::{Bio, BIO, BIO_METHOD}; use crate::callbacks::SslCallbackContext; -use crate::constants::{named_group_to_nid, sig_scheme_to_type_nid}; +use crate::constants::{named_group_to_nid, named_group_to_tls_name, sig_scheme_to_type_nid}; use crate::error::{ffi_panic_boundary, Error, MysteriouslyOppositeReturnValue}; use crate::evp_pkey::EvpPkey; use crate::ex_data::ExData; @@ -1481,10 +1481,12 @@ entry! { .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()) + .find_map(|group| match named_group_to_nid(group.name()) { + Some(nid) if nid == id => { + named_group_to_tls_name(group.name()).map(|info| info.as_ptr()) + } + _ => None, + }) .unwrap_or_else(ptr::null) } } diff --git a/src/lib.rs b/src/lib.rs index d3f9a06e..63075d04 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,7 +18,7 @@ use rustls::pki_types::{CertificateDer, ServerName}; use rustls::server::{Accepted, Acceptor, ProducesTickets}; use rustls::{ AlertDescription, CipherSuite, ClientConfig, ClientConnection, Connection, HandshakeKind, - NamedGroup, ProtocolVersion, ServerConfig, SignatureScheme, SupportedProtocolVersion, + ProtocolVersion, ServerConfig, SignatureScheme, SupportedProtocolVersion, }; use not_thread_safe::NotThreadSafe; @@ -240,158 +240,6 @@ static TLS13_CHACHA20_POLY1305_SHA256: SslCipher = SslCipher { description: c"TLS_CHACHA20_POLY1305_SHA256 TLSv1.3 Kx=any Au=any Enc=CHACHA20/POLY1305(256) Mac=AEAD\n", }; -#[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 /// /// Note that this has equality and ordering entirely based on the `id` field. @@ -1261,6 +1109,7 @@ impl Ssl { if let ConnMode::Unknown = self.mode { self.set_client_mode(); } + if matches!(self.conn, ConnState::Nothing) { self.init_client_conn()?; } diff --git a/tests/constants.c b/tests/constants.c index df088678..97c278c3 100644 --- a/tests/constants.c +++ b/tests/constants.c @@ -6,10 +6,41 @@ #include -int main(void) { +void print_group_to_name() { + // secp{256, 384}r1, x25519 + int supported_nids[] = {415, 715, 1034}; + SSL_CTX *ctx = SSL_CTX_new(TLS_method()); + if (!ctx) { + printf("Failed allocating SSL context\n"); + return; + } + SSL *ssl_inst = SSL_new(ctx); + if (!ssl_inst) { + printf("Failed allocating SSL struct\n"); + return; + } + + for (size_t i = 0; i < sizeof(supported_nids) / sizeof(int); i += 1) { + const char *group_name = SSL_group_to_name(ssl_inst, supported_nids[i]); + if (group_name) + printf("%d: '%s'\n", supported_nids[i], group_name); + else + printf("Unknown: %d\n", supported_nids[i]); + } + + SSL_free(ssl_inst); + SSL_CTX_free(ctx); +} + +void print_alert_desc_string() { for (int i = -1; i < 260; i++) { printf("%d: '%s' '%s'\n", i, SSL_alert_desc_string(i), SSL_alert_desc_string_long(i)); } +} + +int main(void) { + print_alert_desc_string(); + print_group_to_name(); return 0; }