From 4eebe9cd40db750caedcdc43c230c35ec70f050d Mon Sep 17 00:00:00 2001 From: Daniel McCarney Date: Tue, 16 Jul 2024 14:17:31 -0400 Subject: [PATCH] implement SSL_get_negotiated_group Rustls 0.23.11 added a `negotiated_key_exchange_group()` to connections that exposes the `&dyn SupportedKxGroup` used by the connection. This allows us to implement `SSL_get_negotiated_group()`. Our implementation differs slightly from the upstream w.r.t what NID we return for resumed connections. Rustls will return `None` (which we translate to `NID_undef`) for connections that are still handshaking, or for resumed TLS 1.2 handshakes. In contrast, OpenSSL returns the negotiated group of the original connection in that latter case. --- rustls-libssl/src/constants.rs | 35 ++++++++++++++++++++++++++++++++-- rustls-libssl/src/entry.rs | 15 +++++++++++---- rustls-libssl/src/lib.rs | 7 ++++++- rustls-libssl/tests/client.c | 1 + rustls-libssl/tests/server.c | 1 + 5 files changed, 52 insertions(+), 7 deletions(-) diff --git a/rustls-libssl/src/constants.rs b/rustls-libssl/src/constants.rs index d476a3d..f316acf 100644 --- a/rustls-libssl/src/constants.rs +++ b/rustls-libssl/src/constants.rs @@ -1,10 +1,10 @@ use core::ffi::{c_int, CStr}; use openssl_sys::{ NID_X9_62_prime256v1, NID_rsaEncryption, NID_rsassaPss, NID_secp384r1, NID_secp521r1, - NID_ED25519, NID_ED448, + NID_ED25519, NID_ED448, NID_X25519, NID_X448, }; -use rustls::{AlertDescription, SignatureScheme}; +use rustls::{AlertDescription, NamedGroup, SignatureScheme}; pub fn alert_desc_to_long_string(value: c_int) -> &'static CStr { match AlertDescription::from(value as u8) { @@ -102,3 +102,34 @@ pub fn sig_scheme_to_nid(scheme: SignatureScheme) -> Option { _ => None, } } + +pub fn named_group_to_nid(group: NamedGroup) -> Option { + use NamedGroup::*; + + // See NID_ffhdhe* from obj_mac.h - openssl-sys does not have + // constants for these to import. + const NID_FFDHE2048: c_int = 1126; + const NID_FFDHE3072: c_int = 1127; + 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; + + match group { + secp256r1 => Some(NID_X9_62_prime256v1), + secp384r1 => Some(NID_secp384r1), + secp521r1 => Some(NID_secp521r1), + X25519 => Some(NID_X25519), + X448 => Some(NID_X448), + FFDHE2048 => Some(NID_FFDHE2048), + FFDHE3072 => Some(NID_FFDHE3072), + FFDHE4096 => Some(NID_FFDHE4096), + FFDHE6144 => Some(NID_FFDHE6144), + FFDHE8192 => Some(NID_FFDHE8192), + Unknown(id) => Some(TLSEXT_NID_UNKNOWN | id as c_int), + _ => None, + } +} diff --git a/rustls-libssl/src/entry.rs b/rustls-libssl/src/entry.rs index 8c151b7..452cbef 100644 --- a/rustls-libssl/src/entry.rs +++ b/rustls-libssl/src/entry.rs @@ -10,14 +10,14 @@ use std::sync::Arc; use std::{fs, path::PathBuf}; use openssl_sys::{ - stack_st_X509, stack_st_X509_NAME, OPENSSL_malloc, TLSEXT_NAMETYPE_host_name, EVP_PKEY, - OPENSSL_NPN_NEGOTIATED, OPENSSL_NPN_NO_OVERLAP, X509, X509_STORE, X509_STORE_CTX, + stack_st_X509, stack_st_X509_NAME, NID_undef, OPENSSL_malloc, TLSEXT_NAMETYPE_host_name, + EVP_PKEY, OPENSSL_NPN_NEGOTIATED, OPENSSL_NPN_NO_OVERLAP, X509, X509_STORE, X509_STORE_CTX, }; use rustls::pki_types::{CertificateDer, PrivatePkcs8KeyDer}; use crate::bio::{Bio, BIO, BIO_METHOD}; use crate::callbacks::SslCallbackContext; -use crate::constants::sig_scheme_to_nid; +use crate::constants::{named_group_to_nid, sig_scheme_to_nid}; use crate::error::{ffi_panic_boundary, Error, MysteriouslyOppositeReturnValue}; use crate::evp_pkey::EvpPkey; use crate::ex_data::ExData; @@ -221,7 +221,8 @@ entry! { Ok(SslCtrl::GetMaxProtoVersion) => ctx.get().get_max_protocol_version().into(), Ok(SslCtrl::SetTlsExtHostname) | Ok(SslCtrl::SetTlsExtServerNameCallback) - | Ok(SslCtrl::SetTlsExtTicketKeyCallback) => { + | Ok(SslCtrl::SetTlsExtTicketKeyCallback) + | Ok(SslCtrl::GetNegotiatedGroup) => { // not a defined operation in the OpenSSL API 0 } @@ -860,6 +861,11 @@ entry! { ssl.get_mut().stage_certificate_chain(chain); C_INT_SUCCESS as i64 } + Ok(SslCtrl::GetNegotiatedGroup) => ssl + .get() + .get_negotiated_key_exchange_group() + .and_then(|group| named_group_to_nid(group.name())) + .unwrap_or(NID_undef) as c_long, // not a defined operation in the OpenSSL API Ok(SslCtrl::SetTlsExtServerNameCallback) | Ok(SslCtrl::SetTlsExtTicketKeyCallback) @@ -1920,6 +1926,7 @@ num_enum! { SetMaxProtoVersion = 124, GetMinProtoVersion = 130, GetMaxProtoVersion = 131, + GetNegotiatedGroup = 134, } } diff --git a/rustls-libssl/src/lib.rs b/rustls-libssl/src/lib.rs index 257df31..10a97da 100644 --- a/rustls-libssl/src/lib.rs +++ b/rustls-libssl/src/lib.rs @@ -12,7 +12,7 @@ use openssl_sys::{ X509_STORE, X509_V_ERR_UNSPECIFIED, }; use rustls::client::Resumption; -use rustls::crypto::aws_lc_rs as provider; +use rustls::crypto::{aws_lc_rs as provider, SupportedKxGroup}; use rustls::pki_types::{CertificateDer, ServerName}; use rustls::server::{Accepted, Acceptor, ProducesTickets}; use rustls::{ @@ -1378,6 +1378,11 @@ impl Ssl { .map(|suite| suite.suite()) } + fn get_negotiated_key_exchange_group(&self) -> Option<&'static dyn SupportedKxGroup> { + self.conn() + .and_then(|conn| conn.negotiated_key_exchange_group()) + } + fn get_last_verification_result(&self) -> i64 { match &self.conn { ConnState::Client(_, verifier) => verifier.last_result(), diff --git a/rustls-libssl/tests/client.c b/rustls-libssl/tests/client.c index 3d4155a..3daf8b9 100644 --- a/rustls-libssl/tests/client.c +++ b/rustls-libssl/tests/client.c @@ -131,6 +131,7 @@ int main(int argc, char **argv) { TRACE(SSL_get_peer_signature_type_nid(ssl, &cipher_nid)); dump_openssl_error_stack(); printf("cipher NID: %d\n", cipher_nid); + printf("negotiated group NID: %ld\n", SSL_get_negotiated_group(ssl)); show_peer_certificate("server", ssl); diff --git a/rustls-libssl/tests/server.c b/rustls-libssl/tests/server.c index 8d56836..4d05565 100644 --- a/rustls-libssl/tests/server.c +++ b/rustls-libssl/tests/server.c @@ -228,6 +228,7 @@ int main(int argc, char **argv) { TRACE(SSL_get_peer_signature_type_nid(ssl, &cipher_nid)); dump_openssl_error_stack(); printf("cipher NID: %d\n", cipher_nid); + printf("negotiated group NID: %ld\n", SSL_get_negotiated_group(ssl)); printf("SSL_get_servername: %s (%d)\n", SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name),