Procházet zdrojové kódy

Organize some of the duplicated TLS code into a separate crate (#3835)

* Add a place to store common TLS-related code that has no other home
* remove SkipServerVerification from tpu-client-next
* move TLS manipulation stuff from streamer to solana-tls-utils
* move SkipServerVerification, SkipClientVerification and ClientCertificate to solana-tls-utils to avoid duplication. 

---------

Co-authored-by: Alex Pyattaev <alex.pyattaev@anza.xyz>
Alex Pyattaev před 11 měsíci
rodič
revize
1d3c961289

+ 17 - 0
Cargo.lock

@@ -6734,6 +6734,7 @@ dependencies = [
  "solana-svm",
  "solana-svm-transaction",
  "solana-timings",
+ "solana-tls-utils",
  "solana-tpu-client",
  "solana-transaction-status",
  "solana-turbine",
@@ -8095,6 +8096,7 @@ dependencies = [
  "solana-sdk",
  "solana-signer",
  "solana-streamer",
+ "solana-tls-utils",
  "solana-transaction-error",
  "thiserror 2.0.3",
  "tokio",
@@ -8935,6 +8937,7 @@ dependencies = [
  "solana-signer",
  "solana-streamer",
  "solana-time-utils",
+ "solana-tls-utils",
  "solana-transaction-error",
  "solana-transaction-metrics-tracker",
  "thiserror 2.0.3",
@@ -9161,6 +9164,18 @@ dependencies = [
  "solana-sdk",
 ]
 
+[[package]]
+name = "solana-tls-utils"
+version = "2.2.0"
+dependencies = [
+ "rustls 0.23.19",
+ "solana-keypair",
+ "solana-pubkey",
+ "solana-sdk",
+ "solana-signer",
+ "x509-parser",
+]
+
 [[package]]
 name = "solana-tokens"
 version = "2.2.0"
@@ -9256,6 +9271,7 @@ dependencies = [
  "solana-rpc-client",
  "solana-sdk",
  "solana-streamer",
+ "solana-tls-utils",
  "solana-tpu-client",
  "thiserror 2.0.3",
  "tokio",
@@ -9415,6 +9431,7 @@ dependencies = [
  "solana-runtime",
  "solana-sdk",
  "solana-streamer",
+ "solana-tls-utils",
  "static_assertions",
  "test-case",
  "thiserror 2.0.3",

+ 3 - 1
Cargo.toml

@@ -191,6 +191,7 @@ members = [
     "test-validator",
     "thin-client",
     "timings",
+    "tls-utils",
     "tokens",
     "tps-client",
     "tpu-client",
@@ -527,8 +528,8 @@ solana-rent = { path = "sdk/rent", version = "=2.2.0", default-features = false
 solana-rent-debits = { path = "sdk/rent-debits", version = "=2.2.0" }
 solana-reserved-account-keys = { path = "sdk/reserved-account-keys", version = "=2.2.0", default-features = false }
 solana-reward-info = { path = "sdk/reward-info", version = "=2.2.0" }
-solana-secp256r1-program = { path = "sdk/secp256r1-program", version = "=2.2.0", default-features = false }
 solana-sanitize = { path = "sdk/sanitize", version = "=2.2.0" }
+solana-secp256r1-program = { path = "sdk/secp256r1-program", version = "=2.2.0", default-features = false }
 solana-seed-derivable = { path = "sdk/seed-derivable", version = "=2.2.0" }
 solana-seed-phrase = { path = "sdk/seed-phrase", version = "=2.2.0" }
 solana-serde = { path = "sdk/serde", version = "=2.2.0" }
@@ -541,6 +542,7 @@ solana-slot-hashes = { path = "sdk/slot-hashes", version = "=2.2.0" }
 solana-slot-history = { path = "sdk/slot-history", version = "=2.2.0" }
 solana-time-utils = { path = "sdk/time-utils", version = "=2.2.0" }
 solana-timings = { path = "timings", version = "=2.2.0" }
+solana-tls-utils = { path = "tls-utils", version = "=2.2.0" }
 solana-unified-scheduler-logic = { path = "unified-scheduler-logic", version = "=2.2.0" }
 solana-unified-scheduler-pool = { path = "unified-scheduler-pool", version = "=2.2.0" }
 solana-rpc = { path = "rpc", version = "=2.2.0" }

+ 1 - 0
core/Cargo.toml

@@ -83,6 +83,7 @@ solana-streamer = { workspace = true }
 solana-svm = { workspace = true }
 solana-svm-transaction = { workspace = true }
 solana-timings = { workspace = true }
+solana-tls-utils = { workspace = true }
 solana-tpu-client = { workspace = true }
 solana-transaction-status = { workspace = true }
 solana-turbine = { workspace = true }

+ 3 - 2
core/src/repair/quic_endpoint.rs

@@ -14,10 +14,11 @@ use {
         CertificateError, KeyLogFile,
     },
     solana_gossip::contact_info::Protocol,
-    solana_quic_client::nonblocking::quic_client::SkipServerVerification,
     solana_runtime::bank_forks::BankForks,
     solana_sdk::{pubkey::Pubkey, signature::Keypair},
-    solana_streamer::{quic::SkipClientVerification, tls_certificates::new_dummy_x509_certificate},
+    solana_tls_utils::{
+        new_dummy_x509_certificate, SkipClientVerification, SkipServerVerification,
+    },
     std::{
         cmp::Reverse,
         collections::{hash_map::Entry, HashMap},

+ 17 - 0
programs/sbf/Cargo.lock

@@ -5427,6 +5427,7 @@ dependencies = [
  "solana-svm",
  "solana-svm-transaction",
  "solana-timings",
+ "solana-tls-utils",
  "solana-tpu-client",
  "solana-transaction-status",
  "solana-turbine",
@@ -6385,6 +6386,7 @@ dependencies = [
  "solana-rpc-client-api",
  "solana-signer",
  "solana-streamer",
+ "solana-tls-utils",
  "solana-transaction-error",
  "thiserror 2.0.3",
  "tokio",
@@ -7545,6 +7547,7 @@ dependencies = [
  "solana-signature",
  "solana-signer",
  "solana-time-utils",
+ "solana-tls-utils",
  "solana-transaction-error",
  "solana-transaction-metrics-tracker",
  "thiserror 2.0.3",
@@ -7726,6 +7729,18 @@ dependencies = [
  "solana-sdk",
 ]
 
+[[package]]
+name = "solana-tls-utils"
+version = "2.2.0"
+dependencies = [
+ "rustls 0.23.19",
+ "solana-keypair",
+ "solana-pubkey",
+ "solana-sdk",
+ "solana-signer",
+ "x509-parser",
+]
+
 [[package]]
 name = "solana-tpu-client"
 version = "2.2.0"
@@ -7763,6 +7778,7 @@ dependencies = [
  "solana-rpc-client",
  "solana-sdk",
  "solana-streamer",
+ "solana-tls-utils",
  "solana-tpu-client",
  "thiserror 2.0.3",
  "tokio",
@@ -7884,6 +7900,7 @@ dependencies = [
  "solana-runtime",
  "solana-sdk",
  "solana-streamer",
+ "solana-tls-utils",
  "static_assertions",
  "thiserror 2.0.3",
  "tokio",

+ 1 - 0
quic-client/Cargo.toml

@@ -29,6 +29,7 @@ solana-quic-definitions = { workspace = true }
 solana-rpc-client-api = { workspace = true }
 solana-signer = { workspace = true }
 solana-streamer = { workspace = true }
+solana-tls-utils = { workspace = true }
 solana-transaction-error = { workspace = true }
 thiserror = { workspace = true }
 tokio = { workspace = true, features = ["full"] }

+ 4 - 3
quic-client/src/lib.rs

@@ -9,8 +9,8 @@ extern crate solana_metrics;
 use {
     crate::{
         nonblocking::quic_client::{
-            QuicClient, QuicClientCertificate,
-            QuicClientConnection as NonblockingQuicClientConnection, QuicLazyInitializedEndpoint,
+            QuicClient, QuicClientConnection as NonblockingQuicClientConnection,
+            QuicLazyInitializedEndpoint,
         },
         quic_client::QuicClientConnection as BlockingQuicClientConnection,
     },
@@ -25,7 +25,8 @@ use {
     solana_keypair::Keypair,
     solana_pubkey::Pubkey,
     solana_signer::Signer,
-    solana_streamer::{streamer::StakedNodes, tls_certificates::new_dummy_x509_certificate},
+    solana_streamer::streamer::StakedNodes,
+    solana_tls_utils::{new_dummy_x509_certificate, QuicClientCertificate},
     std::{
         net::{IpAddr, SocketAddr},
         sync::{Arc, RwLock},

+ 2 - 62
quic-client/src/nonblocking/quic_client.rs

@@ -22,9 +22,8 @@ use {
         QUIC_CONNECTION_HANDSHAKE_TIMEOUT, QUIC_KEEP_ALIVE, QUIC_MAX_TIMEOUT,
     },
     solana_rpc_client_api::client_error::ErrorKind as ClientErrorKind,
-    solana_streamer::{
-        nonblocking::quic::ALPN_TPU_PROTOCOL_ID, tls_certificates::new_dummy_x509_certificate,
-    },
+    solana_streamer::nonblocking::quic::ALPN_TPU_PROTOCOL_ID,
+    solana_tls_utils::{new_dummy_x509_certificate, QuicClientCertificate, SkipServerVerification},
     solana_transaction_error::TransportResult,
     std::{
         net::{IpAddr, Ipv4Addr, SocketAddr, UdpSocket},
@@ -35,65 +34,6 @@ use {
     tokio::{sync::OnceCell, time::timeout},
 };
 
-#[derive(Debug)]
-pub struct SkipServerVerification(Arc<rustls::crypto::CryptoProvider>);
-
-impl SkipServerVerification {
-    pub fn new() -> Arc<Self> {
-        Arc::new(Self(Arc::new(rustls::crypto::ring::default_provider())))
-    }
-}
-
-impl rustls::client::danger::ServerCertVerifier for SkipServerVerification {
-    fn verify_tls12_signature(
-        &self,
-        message: &[u8],
-        cert: &rustls::pki_types::CertificateDer<'_>,
-        dss: &rustls::DigitallySignedStruct,
-    ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
-        rustls::crypto::verify_tls12_signature(
-            message,
-            cert,
-            dss,
-            &self.0.signature_verification_algorithms,
-        )
-    }
-
-    fn verify_tls13_signature(
-        &self,
-        message: &[u8],
-        cert: &rustls::pki_types::CertificateDer<'_>,
-        dss: &rustls::DigitallySignedStruct,
-    ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
-        rustls::crypto::verify_tls13_signature(
-            message,
-            cert,
-            dss,
-            &self.0.signature_verification_algorithms,
-        )
-    }
-
-    fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
-        self.0.signature_verification_algorithms.supported_schemes()
-    }
-
-    fn verify_server_cert(
-        &self,
-        _end_entity: &rustls::pki_types::CertificateDer<'_>,
-        _intermediates: &[rustls::pki_types::CertificateDer<'_>],
-        _server_name: &rustls::pki_types::ServerName<'_>,
-        _ocsp_response: &[u8],
-        _now: rustls::pki_types::UnixTime,
-    ) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
-        Ok(rustls::client::danger::ServerCertVerified::assertion())
-    }
-}
-
-pub struct QuicClientCertificate {
-    pub certificate: rustls::pki_types::CertificateDer<'static>,
-    pub key: rustls::pki_types::PrivateKeyDer<'static>,
-}
-
 /// A lazy-initialized Quic Endpoint
 pub struct QuicLazyInitializedEndpoint {
     endpoint: OnceCell<Arc<Endpoint>>,

+ 2 - 4
quic-client/tests/quic_client.rs

@@ -6,15 +6,13 @@ mod tests {
         solana_connection_cache::connection_cache_stats::ConnectionCacheStats,
         solana_net_utils::bind_to_localhost,
         solana_perf::packet::PacketBatch,
-        solana_quic_client::nonblocking::quic_client::{
-            QuicClientCertificate, QuicLazyInitializedEndpoint,
-        },
+        solana_quic_client::nonblocking::quic_client::QuicLazyInitializedEndpoint,
         solana_sdk::{packet::PACKET_DATA_SIZE, signature::Keypair},
         solana_streamer::{
             quic::{QuicServerParams, SpawnServerResult},
             streamer::StakedNodes,
-            tls_certificates::new_dummy_x509_certificate,
         },
+        solana_tls_utils::{new_dummy_x509_certificate, QuicClientCertificate},
         std::{
             net::{SocketAddr, UdpSocket},
             sync::{

+ 1 - 0
streamer/Cargo.toml

@@ -42,6 +42,7 @@ solana-quic-definitions = { workspace = true }
 solana-signature = { workspace = true }
 solana-signer = { workspace = true }
 solana-time-utils = { workspace = true }
+solana-tls-utils = { workspace = true }
 solana-transaction-error = { workspace = true }
 solana-transaction-metrics-tracker = { workspace = true }
 thiserror = { workspace = true }

+ 0 - 1
streamer/src/lib.rs

@@ -6,7 +6,6 @@ pub mod recvmmsg;
 pub mod sendmmsg;
 pub mod socket;
 pub mod streamer;
-pub mod tls_certificates;
 
 #[macro_use]
 extern crate log;

+ 1 - 1
streamer/src/nonblocking/quic.rs

@@ -9,7 +9,6 @@ use {
         },
         quic::{configure_server, QuicServerError, QuicServerParams, StreamerStats},
         streamer::StakedNodes,
-        tls_certificates::get_pubkey_from_tls_certificate,
     },
     async_channel::{
         unbounded as async_unbounded, Receiver as AsyncReceiver, Sender as AsyncSender,
@@ -36,6 +35,7 @@ use {
     },
     solana_signature::Signature,
     solana_time_utils as timing,
+    solana_tls_utils::get_pubkey_from_tls_certificate,
     solana_transaction_metrics_tracker::signature_if_should_track_packet,
     std::{
         array,

+ 1 - 55
streamer/src/nonblocking/testing_utilities.rs

@@ -11,7 +11,6 @@ use {
             MAX_UNSTAKED_CONNECTIONS,
         },
         streamer::StakedNodes,
-        tls_certificates::new_dummy_x509_certificate,
     },
     crossbeam_channel::unbounded,
     quinn::{
@@ -22,6 +21,7 @@ use {
     solana_net_utils::bind_to_localhost,
     solana_perf::packet::PacketBatch,
     solana_quic_definitions::{QUIC_KEEP_ALIVE, QUIC_MAX_TIMEOUT},
+    solana_tls_utils::{new_dummy_x509_certificate, SkipServerVerification},
     std::{
         net::{SocketAddr, UdpSocket},
         sync::{atomic::AtomicBool, Arc, RwLock},
@@ -29,60 +29,6 @@ use {
     tokio::task::JoinHandle,
 };
 
-#[derive(Debug)]
-pub struct SkipServerVerification(Arc<rustls::crypto::CryptoProvider>);
-
-impl SkipServerVerification {
-    pub fn new() -> Arc<Self> {
-        Arc::new(Self(Arc::new(rustls::crypto::ring::default_provider())))
-    }
-}
-
-impl rustls::client::danger::ServerCertVerifier for SkipServerVerification {
-    fn verify_tls12_signature(
-        &self,
-        message: &[u8],
-        cert: &rustls::pki_types::CertificateDer<'_>,
-        dss: &rustls::DigitallySignedStruct,
-    ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
-        rustls::crypto::verify_tls12_signature(
-            message,
-            cert,
-            dss,
-            &self.0.signature_verification_algorithms,
-        )
-    }
-
-    fn verify_tls13_signature(
-        &self,
-        message: &[u8],
-        cert: &rustls::pki_types::CertificateDer<'_>,
-        dss: &rustls::DigitallySignedStruct,
-    ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
-        rustls::crypto::verify_tls13_signature(
-            message,
-            cert,
-            dss,
-            &self.0.signature_verification_algorithms,
-        )
-    }
-
-    fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
-        self.0.signature_verification_algorithms.supported_schemes()
-    }
-
-    fn verify_server_cert(
-        &self,
-        _end_entity: &rustls::pki_types::CertificateDer<'_>,
-        _intermediates: &[rustls::pki_types::CertificateDer<'_>],
-        _server_name: &rustls::pki_types::ServerName<'_>,
-        _ocsp_response: &[u8],
-        _now: rustls::pki_types::UnixTime,
-    ) -> Result<rustls::client::danger::ServerCertVerified, rustls::Error> {
-        Ok(rustls::client::danger::ServerCertVerified::assertion())
-    }
-}
-
 pub fn get_client_config(keypair: &Keypair) -> ClientConfig {
     let (cert, key) = new_dummy_x509_certificate(keypair);
 

+ 2 - 70
streamer/src/quic.rs

@@ -5,7 +5,6 @@ use {
             DEFAULT_MAX_STREAMS_PER_MS, DEFAULT_WAIT_FOR_CHUNK_TIMEOUT,
         },
         streamer::StakedNodes,
-        tls_certificates::new_dummy_x509_certificate,
     },
     crossbeam_channel::Sender,
     pem::Pem,
@@ -13,17 +12,14 @@ use {
         crypto::rustls::{NoInitialCipherSuite, QuicServerConfig},
         Endpoint, IdleTimeout, ServerConfig,
     },
-    rustls::{
-        pki_types::{CertificateDer, UnixTime},
-        server::danger::ClientCertVerified,
-        DistinguishedName, KeyLogFile,
-    },
+    rustls::KeyLogFile,
     solana_keypair::Keypair,
     solana_packet::PACKET_DATA_SIZE,
     solana_perf::packet::PacketBatch,
     solana_quic_definitions::{
         NotifyKeyUpdate, QUIC_MAX_TIMEOUT, QUIC_MAX_UNSTAKED_CONCURRENT_STREAMS,
     },
+    solana_tls_utils::{new_dummy_x509_certificate, SkipClientVerification},
     std::{
         net::UdpSocket,
         sync::{
@@ -44,76 +40,12 @@ pub const DEFAULT_QUIC_ENDPOINTS: usize = 1;
 // inlined to avoid solana-sdk dep
 pub(crate) const DEFAULT_TPU_COALESCE: Duration = Duration::from_millis(5);
 
-#[derive(Debug)]
-pub struct SkipClientVerification(Arc<rustls::crypto::CryptoProvider>);
-
-impl SkipClientVerification {
-    pub fn new() -> Arc<Self> {
-        Arc::new(Self(Arc::new(rustls::crypto::ring::default_provider())))
-    }
-}
-
 pub struct SpawnServerResult {
     pub endpoints: Vec<Endpoint>,
     pub thread: thread::JoinHandle<()>,
     pub key_updater: Arc<EndpointKeyUpdater>,
 }
 
-impl rustls::server::danger::ClientCertVerifier for SkipClientVerification {
-    fn verify_client_cert(
-        &self,
-        _end_entity: &CertificateDer,
-        _intermediates: &[CertificateDer],
-        _now: UnixTime,
-    ) -> Result<ClientCertVerified, rustls::Error> {
-        Ok(rustls::server::danger::ClientCertVerified::assertion())
-    }
-
-    fn root_hint_subjects(&self) -> &[DistinguishedName] {
-        &[]
-    }
-
-    fn verify_tls12_signature(
-        &self,
-        message: &[u8],
-        cert: &rustls::pki_types::CertificateDer<'_>,
-        dss: &rustls::DigitallySignedStruct,
-    ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
-        rustls::crypto::verify_tls12_signature(
-            message,
-            cert,
-            dss,
-            &self.0.signature_verification_algorithms,
-        )
-    }
-
-    fn verify_tls13_signature(
-        &self,
-        message: &[u8],
-        cert: &rustls::pki_types::CertificateDer<'_>,
-        dss: &rustls::DigitallySignedStruct,
-    ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
-        rustls::crypto::verify_tls13_signature(
-            message,
-            cert,
-            dss,
-            &self.0.signature_verification_algorithms,
-        )
-    }
-
-    fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
-        self.0.signature_verification_algorithms.supported_schemes()
-    }
-
-    fn offer_client_auth(&self) -> bool {
-        true
-    }
-
-    fn client_auth_mandatory(&self) -> bool {
-        self.offer_client_auth()
-    }
-}
-
 /// Returns default server configuration along with its PEM certificate chain.
 #[allow(clippy::field_reassign_with_default)] // https://github.com/rust-lang/rust-clippy/issues/6527
 pub(crate) fn configure_server(

+ 17 - 0
svm/examples/Cargo.lock

@@ -5278,6 +5278,7 @@ dependencies = [
  "solana-svm",
  "solana-svm-transaction",
  "solana-timings",
+ "solana-tls-utils",
  "solana-tpu-client",
  "solana-transaction-status",
  "solana-turbine",
@@ -6205,6 +6206,7 @@ dependencies = [
  "solana-rpc-client-api",
  "solana-signer",
  "solana-streamer",
+ "solana-tls-utils",
  "solana-transaction-error",
  "thiserror 2.0.3",
  "tokio",
@@ -6873,6 +6875,7 @@ dependencies = [
  "solana-signature",
  "solana-signer",
  "solana-time-utils",
+ "solana-tls-utils",
  "solana-transaction-error",
  "solana-transaction-metrics-tracker",
  "thiserror 2.0.3",
@@ -7071,6 +7074,18 @@ dependencies = [
  "solana-sdk",
 ]
 
+[[package]]
+name = "solana-tls-utils"
+version = "2.2.0"
+dependencies = [
+ "rustls 0.23.19",
+ "solana-keypair",
+ "solana-pubkey",
+ "solana-sdk",
+ "solana-signer",
+ "x509-parser",
+]
+
 [[package]]
 name = "solana-tpu-client"
 version = "2.2.0"
@@ -7108,6 +7123,7 @@ dependencies = [
  "solana-rpc-client",
  "solana-sdk",
  "solana-streamer",
+ "solana-tls-utils",
  "solana-tpu-client",
  "thiserror 2.0.3",
  "tokio",
@@ -7229,6 +7245,7 @@ dependencies = [
  "solana-runtime",
  "solana-sdk",
  "solana-streamer",
+ "solana-tls-utils",
  "static_assertions",
  "thiserror 2.0.3",
  "tokio",

+ 22 - 0
tls-utils/Cargo.toml

@@ -0,0 +1,22 @@
+[package]
+name = "solana-tls-utils"
+description = "Solana TLS utilities"
+documentation = "https://docs.rs/solana-tls-utils"
+publish = false
+version = { workspace = true }
+authors = { workspace = true }
+repository = { workspace = true }
+homepage = { workspace = true }
+license = { workspace = true }
+edition = { workspace = true }
+
+[dependencies]
+rustls = { workspace = true, features = ["ring"] }
+solana-keypair = { workspace = true }
+solana-pubkey = { workspace = true }
+solana-sdk = { workspace = true }
+solana-signer = { workspace = true }
+x509-parser = { workspace = true }
+
+[lints]
+workspace = true

+ 1 - 0
tls-utils/README

@@ -0,0 +1 @@
+A collection of utility functions and structures needed to bridge the conceptual gap between conventional TLS security models in protocols like QUIC and Agave use cases

+ 14 - 0
tls-utils/src/lib.rs

@@ -0,0 +1,14 @@
+//! Collection of TLS related code fragments that end up popping up everywhere where quic is used.
+//! Aggregated here to avoid bugs due to conflicting implementations of the same functionality.
+
+mod tls_certificates;
+pub use tls_certificates::*;
+
+mod quic_client_certificate;
+pub use quic_client_certificate::*;
+
+mod skip_server_verification;
+pub use skip_server_verification::SkipServerVerification;
+
+mod skip_client_verification;
+pub use skip_client_verification::SkipClientVerification;

+ 1 - 1
tpu-client-next/src/quic_networking/quic_client_certificate.rs → tls-utils/src/quic_client_certificate.rs

@@ -1,7 +1,7 @@
 use {
+    crate::new_dummy_x509_certificate,
     rustls::pki_types::{CertificateDer, PrivateKeyDer},
     solana_sdk::signature::Keypair,
-    solana_streamer::tls_certificates::new_dummy_x509_certificate,
 };
 
 pub struct QuicClientCertificate {

+ 73 - 0
tls-utils/src/skip_client_verification.rs

@@ -0,0 +1,73 @@
+use {
+    rustls::{
+        pki_types::{CertificateDer, UnixTime},
+        server::danger::ClientCertVerified,
+        DistinguishedName,
+    },
+    std::{fmt::Debug, sync::Arc},
+};
+
+/// Implementation of [`ClientCertVerifier`] that ignores the server
+/// certificate. Yet still checks the TLS signatures.
+#[derive(Debug)]
+pub struct SkipClientVerification(Arc<rustls::crypto::CryptoProvider>);
+
+impl SkipClientVerification {
+    pub fn new() -> Arc<Self> {
+        Arc::new(Self(Arc::new(rustls::crypto::ring::default_provider())))
+    }
+}
+impl rustls::server::danger::ClientCertVerifier for SkipClientVerification {
+    fn verify_client_cert(
+        &self,
+        _end_entity: &CertificateDer,
+        _intermediates: &[CertificateDer],
+        _now: UnixTime,
+    ) -> Result<ClientCertVerified, rustls::Error> {
+        Ok(rustls::server::danger::ClientCertVerified::assertion())
+    }
+
+    fn root_hint_subjects(&self) -> &[DistinguishedName] {
+        &[]
+    }
+
+    fn verify_tls12_signature(
+        &self,
+        message: &[u8],
+        cert: &rustls::pki_types::CertificateDer<'_>,
+        dss: &rustls::DigitallySignedStruct,
+    ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
+        rustls::crypto::verify_tls12_signature(
+            message,
+            cert,
+            dss,
+            &self.0.signature_verification_algorithms,
+        )
+    }
+
+    fn verify_tls13_signature(
+        &self,
+        message: &[u8],
+        cert: &rustls::pki_types::CertificateDer<'_>,
+        dss: &rustls::DigitallySignedStruct,
+    ) -> Result<rustls::client::danger::HandshakeSignatureValid, rustls::Error> {
+        rustls::crypto::verify_tls13_signature(
+            message,
+            cert,
+            dss,
+            &self.0.signature_verification_algorithms,
+        )
+    }
+
+    fn supported_verify_schemes(&self) -> Vec<rustls::SignatureScheme> {
+        self.0.signature_verification_algorithms.supported_schemes()
+    }
+
+    fn offer_client_auth(&self) -> bool {
+        true
+    }
+
+    fn client_auth_mandatory(&self) -> bool {
+        self.offer_client_auth()
+    }
+}

+ 3 - 1
tpu-client-next/src/quic_networking/skip_server_verification.rs → tls-utils/src/skip_server_verification.rs

@@ -13,7 +13,9 @@ use {
 
 /// Implementation of [`ServerCertVerifier`] that ignores the server
 /// certificate. Yet still checks the TLS signatures.
-pub(crate) struct SkipServerVerification(Arc<CryptoProvider>);
+/// This is useful for turbine (where server verification is not feasible) and for tests
+/// Logic mostly copied from rustls examples.
+pub struct SkipServerVerification(Arc<CryptoProvider>);
 
 impl SkipServerVerification {
     pub fn new() -> Arc<Self> {

+ 16 - 3
streamer/src/tls_certificates.rs → tls-utils/src/tls_certificates.rs

@@ -29,9 +29,22 @@ pub fn new_dummy_x509_certificate(
         0x30, 0x2e, 0x02, 0x01, 0x00, 0x30, 0x05, 0x06, 0x03, 0x2b, 0x65, 0x70, 0x04, 0x22, 0x04,
         0x20,
     ];
-    let mut key_pkcs8_der = Vec::<u8>::with_capacity(PKCS8_PREFIX.len() + 32);
-    key_pkcs8_der.extend_from_slice(&PKCS8_PREFIX);
-    key_pkcs8_der.extend_from_slice(keypair.secret().as_bytes());
+
+    let key_pkcs8_der = {
+        let keypair_secret_bytes = keypair.secret().as_bytes();
+        let keypair_secret_len = keypair_secret_bytes.len();
+        if keypair_secret_len != 32 {
+            panic!("Unexpected secret key length!");
+        }
+        let buffer_size = PKCS8_PREFIX
+            .len()
+            .checked_add(keypair_secret_len) //clippy being overly guarded here but optimizer will elide checked_add
+            .expect("Unexpected secret key length!");
+        let mut key_pkcs8_der = Vec::<u8>::with_capacity(buffer_size);
+        key_pkcs8_der.extend_from_slice(&PKCS8_PREFIX);
+        key_pkcs8_der.extend_from_slice(keypair_secret_bytes);
+        key_pkcs8_der
+    };
 
     // Create a dummy certificate. Only the SubjectPublicKeyInfo field
     // is relevant to the peer-to-peer protocols. The signature of the

+ 1 - 0
tpu-client-next/Cargo.toml

@@ -20,6 +20,7 @@ solana-measure = { workspace = true }
 solana-rpc-client = { workspace = true }
 solana-sdk = { workspace = true }
 solana-streamer = { workspace = true }
+solana-tls-utils = { workspace = true }
 solana-tpu-client = { workspace = true }
 thiserror = { workspace = true }
 tokio = { workspace = true }

+ 2 - 4
tpu-client-next/src/quic_networking.rs

@@ -5,19 +5,17 @@ use {
         crypto::rustls::QuicClientConfig, ClientConfig, Connection, Endpoint, IdleTimeout,
         TransportConfig,
     },
-    skip_server_verification::SkipServerVerification,
     solana_sdk::quic::{QUIC_KEEP_ALIVE, QUIC_MAX_TIMEOUT},
     solana_streamer::nonblocking::quic::ALPN_TPU_PROTOCOL_ID,
+    solana_tls_utils::SkipServerVerification,
     std::{net::SocketAddr, sync::Arc},
 };
 
 pub mod error;
-pub mod quic_client_certificate;
-pub mod skip_server_verification;
 
 pub use {
     error::{IoErrorWithPartialEq, QuicError},
-    quic_client_certificate::QuicClientCertificate,
+    solana_tls_utils::QuicClientCertificate,
 };
 
 pub(crate) fn create_client_config(client_certificate: QuicClientCertificate) -> ClientConfig {

+ 1 - 0
turbine/Cargo.toml

@@ -40,6 +40,7 @@ solana-rpc-client-api = { workspace = true }
 solana-runtime = { workspace = true }
 solana-sdk = { workspace = true }
 solana-streamer = { workspace = true }
+solana-tls-utils = { workspace = true }
 static_assertions = { workspace = true }
 thiserror = { workspace = true }
 tokio = { workspace = true }

+ 3 - 2
turbine/src/quic_endpoint.rs

@@ -13,10 +13,11 @@ use {
         pki_types::{CertificateDer, PrivateKeyDer},
         CertificateError, KeyLogFile,
     },
-    solana_quic_client::nonblocking::quic_client::SkipServerVerification,
     solana_runtime::bank_forks::BankForks,
     solana_sdk::{pubkey::Pubkey, signature::Keypair},
-    solana_streamer::{quic::SkipClientVerification, tls_certificates::new_dummy_x509_certificate},
+    solana_tls_utils::{
+        new_dummy_x509_certificate, SkipClientVerification, SkipServerVerification,
+    },
     std::{
         cmp::Reverse,
         collections::{hash_map::Entry, HashMap},