diff --git a/rustls-libssl/MATRIX.md b/rustls-libssl/MATRIX.md index 65c90e1..fe699f3 100644 --- a/rustls-libssl/MATRIX.md +++ b/rustls-libssl/MATRIX.md @@ -136,7 +136,7 @@ | `SSL_CTX_set_async_callback_arg` | | | | | `SSL_CTX_set_block_padding` | | | | | `SSL_CTX_set_cert_cb` | | :white_check_mark: | :white_check_mark: | -| `SSL_CTX_set_cert_store` | | | | +| `SSL_CTX_set_cert_store` | | | :white_check_mark: | | `SSL_CTX_set_cert_verify_callback` | | | | | `SSL_CTX_set_cipher_list` | :white_check_mark: | :white_check_mark: | :white_check_mark: | | `SSL_CTX_set_ciphersuites` | :white_check_mark: | | :exclamation: [^stub] | @@ -347,7 +347,7 @@ | `SSL_get_options` | | :white_check_mark: | :white_check_mark: | | `SSL_get_peer_cert_chain` | :white_check_mark: | | :white_check_mark: | | `SSL_get_peer_finished` | | | | -| `SSL_get_peer_signature_type_nid` | | | | +| `SSL_get_peer_signature_type_nid` | | | :white_check_mark: | | `SSL_get_pending_cipher` | | | | | `SSL_get_privatekey` | :white_check_mark: | | :white_check_mark: | | `SSL_get_psk_identity` [^psk] | | | | diff --git a/rustls-libssl/build.rs b/rustls-libssl/build.rs index 58f1f8f..56a905a 100644 --- a/rustls-libssl/build.rs +++ b/rustls-libssl/build.rs @@ -96,6 +96,7 @@ const ENTRYPOINTS: &[&str] = &[ "SSL_CTX_set_alpn_protos", "SSL_CTX_set_alpn_select_cb", "SSL_CTX_set_cert_cb", + "SSL_CTX_set_cert_store", "SSL_CTX_set_cipher_list", "SSL_CTX_set_ciphersuites", "SSL_CTX_set_client_CA_list", @@ -142,6 +143,7 @@ const ENTRYPOINTS: &[&str] = &[ "SSL_get_ex_data_X509_STORE_CTX_idx", "SSL_get_options", "SSL_get_peer_cert_chain", + "SSL_get_peer_signature_type_nid", "SSL_get_privatekey", "SSL_get_rbio", "SSL_get_servername", diff --git a/rustls-libssl/src/constants.rs b/rustls-libssl/src/constants.rs index 9ec539e..d476a3d 100644 --- a/rustls-libssl/src/constants.rs +++ b/rustls-libssl/src/constants.rs @@ -1,6 +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, +}; -use rustls::AlertDescription; +use rustls::{AlertDescription, SignatureScheme}; pub fn alert_desc_to_long_string(value: c_int) -> &'static CStr { match AlertDescription::from(value as u8) { @@ -83,3 +87,18 @@ pub fn alert_desc_to_short_string(value: c_int) -> &'static CStr { _ => c"UK", } } + +pub fn sig_scheme_to_nid(scheme: SignatureScheme) -> Option { + use SignatureScheme::*; + match scheme { + RSA_PKCS1_SHA256 | RSA_PKCS1_SHA384 | RSA_PKCS1_SHA512 => Some(NID_rsaEncryption), + RSA_PSS_SHA256 | RSA_PSS_SHA384 | RSA_PSS_SHA512 => Some(NID_rsassaPss), + ECDSA_NISTP256_SHA256 => Some(NID_X9_62_prime256v1), + ECDSA_NISTP384_SHA384 => Some(NID_secp384r1), + ECDSA_NISTP521_SHA512 => Some(NID_secp521r1), + ED25519 => Some(NID_ED25519), + ED448 => Some(NID_ED448), + // Omitted: SHA1 legacy schemes. + _ => None, + } +} diff --git a/rustls-libssl/src/entry.rs b/rustls-libssl/src/entry.rs index bfa4c47..9ff195a 100644 --- a/rustls-libssl/src/entry.rs +++ b/rustls-libssl/src/entry.rs @@ -17,6 +17,7 @@ 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::error::{ffi_panic_boundary, Error, MysteriouslyOppositeReturnValue}; use crate::evp_pkey::EvpPkey; use crate::ex_data::ExData; @@ -297,6 +298,12 @@ entry! { } } +entry! { + pub fn _SSL_CTX_set_cert_store(ctx: *mut SSL_CTX, store: *mut X509_STORE) { + try_clone_arc!(ctx).get_mut().set_x509_store(store); + } +} + fn load_verify_files( ctx: &NotThreadSafe, file_names: impl Iterator, @@ -1124,6 +1131,27 @@ entry! { } } +entry! { + pub fn _SSL_get_peer_signature_type_nid(ssl: *const SSL, psigtype_nid: *mut c_int) -> c_int { + if psigtype_nid.is_null() { + return 0; + } + + let sigalg_nid = try_clone_arc!(ssl) + .get() + .get_last_verification_sig_scheme() + .and_then(sig_scheme_to_nid); + + match sigalg_nid { + Some(nid) => { + unsafe { ptr::write(psigtype_nid, nid) }; + C_INT_SUCCESS + } + None => 0, + } + } +} + entry! { pub fn _SSL_get0_verified_chain(ssl: *const SSL) -> *mut stack_st_X509 { _SSL_get_peer_cert_chain(ssl) diff --git a/rustls-libssl/src/lib.rs b/rustls-libssl/src/lib.rs index ceec0be..041e573 100644 --- a/rustls-libssl/src/lib.rs +++ b/rustls-libssl/src/lib.rs @@ -17,10 +17,11 @@ use rustls::pki_types::{CertificateDer, ServerName}; use rustls::server::{Accepted, Acceptor}; use rustls::{ CipherSuite, ClientConfig, ClientConnection, Connection, HandshakeKind, ProtocolVersion, - RootCertStore, ServerConfig, SupportedProtocolVersion, + RootCertStore, ServerConfig, SignatureScheme, SupportedProtocolVersion, }; use not_thread_safe::NotThreadSafe; +use x509::OwnedX509Store; mod bio; mod cache; @@ -435,7 +436,7 @@ impl SslContext { verify_mode: VerifyMode::default(), verify_depth: -1, verify_roots: RootCertStore::empty(), - verify_x509_store: x509::OwnedX509Store::new(), + verify_x509_store: OwnedX509Store::default(), alpn: vec![], default_cert_file: None, default_cert_dir: None, @@ -615,6 +616,13 @@ impl SslContext { self.verify_x509_store.pointer() } + fn set_x509_store(&mut self, store: *mut X509_STORE) { + self.verify_x509_store = match store.is_null() { + true => OwnedX509Store::default(), + false => OwnedX509Store::new(store), + }; + } + fn set_alpn_offer(&mut self, alpn: Vec>) { self.alpn = alpn; } @@ -1337,6 +1345,14 @@ impl Ssl { } } + fn get_last_verification_sig_scheme(&self) -> Option { + match &self.conn { + ConnState::Client(_, verifier) => verifier.last_sig_scheme(), + ConnState::Server(_, verifier, _) => verifier.last_sig_scheme(), + _ => None, + } + } + fn get_error(&mut self) -> c_int { match self.conn_mut() { Some(conn) => { diff --git a/rustls-libssl/src/verifier.rs b/rustls-libssl/src/verifier.rs index 6dd72d1..641d583 100644 --- a/rustls-libssl/src/verifier.rs +++ b/rustls-libssl/src/verifier.rs @@ -1,5 +1,5 @@ use core::sync::atomic::{AtomicI64, Ordering}; -use std::sync::Arc; +use std::sync::{Arc, RwLock}; use openssl_sys::{ X509_V_ERR_CERT_HAS_EXPIRED, X509_V_ERR_CERT_NOT_YET_VALID, X509_V_ERR_CERT_REVOKED, @@ -41,6 +41,8 @@ pub struct ServerVerifier { mode: VerifyMode, last_result: AtomicI64, + + last_sig_scheme: RwLock>, } impl ServerVerifier { @@ -56,6 +58,7 @@ impl ServerVerifier { verify_hostname: hostname.clone(), mode, last_result: AtomicI64::new(X509_V_ERR_UNSPECIFIED as i64), + last_sig_scheme: RwLock::new(None), } } @@ -63,6 +66,10 @@ impl ServerVerifier { self.last_result.load(Ordering::Acquire) } + pub fn last_sig_scheme(&self) -> Option { + self.last_sig_scheme.read().ok().map(|scheme| *scheme)? + } + fn verify_server_cert_inner( &self, end_entity: &CertificateDer<'_>, @@ -85,6 +92,12 @@ impl ServerVerifier { Ok(()) } + + fn update_sig_scheme(&self, scheme: SignatureScheme) { + if let Ok(mut last_scheme) = self.last_sig_scheme.write() { + *last_scheme = Some(scheme); + } + } } impl ServerCertVerifier for ServerVerifier { @@ -115,6 +128,7 @@ impl ServerCertVerifier for ServerVerifier { cert: &CertificateDer<'_>, dss: &DigitallySignedStruct, ) -> Result { + self.update_sig_scheme(dss.scheme); verify_tls12_signature( message, cert, @@ -129,6 +143,7 @@ impl ServerCertVerifier for ServerVerifier { cert: &CertificateDer<'_>, dss: &DigitallySignedStruct, ) -> Result { + self.update_sig_scheme(dss.scheme); verify_tls13_signature( message, cert, @@ -149,6 +164,7 @@ pub struct ClientVerifier { parent: Arc, mode: VerifyMode, last_result: AtomicI64, + last_sig_scheme: RwLock>, } impl ClientVerifier { @@ -178,12 +194,23 @@ impl ClientVerifier { parent, mode, last_result: AtomicI64::new(initial_result as i64), + last_sig_scheme: RwLock::new(None), }) } pub fn last_result(&self) -> i64 { self.last_result.load(Ordering::Acquire) } + + pub fn last_sig_scheme(&self) -> Option { + self.last_sig_scheme.read().ok().map(|scheme| *scheme)? + } + + fn update_sig_scheme(&self, scheme: SignatureScheme) { + if let Ok(mut last_scheme) = self.last_sig_scheme.write() { + *last_scheme = Some(scheme); + } + } } impl ClientCertVerifier for ClientVerifier { @@ -223,6 +250,7 @@ impl ClientCertVerifier for ClientVerifier { cert: &CertificateDer<'_>, dss: &DigitallySignedStruct, ) -> Result { + self.update_sig_scheme(dss.scheme); self.parent.verify_tls12_signature(message, cert, dss) } @@ -232,6 +260,7 @@ impl ClientCertVerifier for ClientVerifier { cert: &CertificateDer<'_>, dss: &DigitallySignedStruct, ) -> Result { + self.update_sig_scheme(dss.scheme); self.parent.verify_tls13_signature(message, cert, dss) } diff --git a/rustls-libssl/src/x509.rs b/rustls-libssl/src/x509.rs index 10d96e2..3e48aa2 100644 --- a/rustls-libssl/src/x509.rs +++ b/rustls-libssl/src/x509.rs @@ -237,10 +237,9 @@ pub struct OwnedX509Store { } impl OwnedX509Store { - pub fn new() -> Self { - Self { - raw: unsafe { X509_STORE_new() }, - } + /// Create a new one, from a (donated) existing ref. + pub fn new(store: *mut X509_STORE) -> Self { + Self { raw: store } } pub fn pointer(&self) -> *mut X509_STORE { @@ -248,6 +247,14 @@ impl OwnedX509Store { } } +impl Default for OwnedX509Store { + fn default() -> Self { + Self { + raw: unsafe { X509_STORE_new() }, + } + } +} + impl Drop for OwnedX509Store { fn drop(&mut self) { unsafe { diff --git a/rustls-libssl/tests/client.c b/rustls-libssl/tests/client.c index 2d16e30..1537b03 100644 --- a/rustls-libssl/tests/client.c +++ b/rustls-libssl/tests/client.c @@ -126,6 +126,10 @@ int main(int argc, char **argv) { printf("numeric version: %d\n", SSL_version(ssl)); printf("verify-result: %ld\n", SSL_get_verify_result(ssl)); printf("cipher: %s\n", SSL_CIPHER_standard_name(SSL_get_current_cipher(ssl))); + int cipher_nid = 0; + TRACE(SSL_get_peer_signature_type_nid(ssl, &cipher_nid)); + dump_openssl_error_stack(); + printf("cipher NID: %d\n", cipher_nid); show_peer_certificate("server", ssl); diff --git a/rustls-libssl/tests/server.c b/rustls-libssl/tests/server.c index 9e80647..36a6f50 100644 --- a/rustls-libssl/tests/server.c +++ b/rustls-libssl/tests/server.c @@ -202,6 +202,11 @@ int main(int argc, char **argv) { printf("numeric version: %d\n", SSL_version(ssl)); printf("verify-result: %ld\n", SSL_get_verify_result(ssl)); printf("cipher: %s\n", SSL_CIPHER_standard_name(SSL_get_current_cipher(ssl))); + int cipher_nid = 0; + TRACE(SSL_get_peer_signature_type_nid(ssl, &cipher_nid)); + dump_openssl_error_stack(); + printf("cipher NID: %d\n", cipher_nid); + printf("SSL_get_servername: %s (%d)\n", SSL_get_servername(ssl, TLSEXT_NAMETYPE_host_name), SSL_get_servername_type(ssl));