@@ -54,6 +54,10 @@ public partial class SessionPool : IDisposable, IPoolDiagnosticReporter
5454 private readonly string _clientCertificatePath ;
5555 private readonly string _clientCertificatePassword ;
5656 private readonly string _rootCertificatePath ;
57+ private X509Certificate2 _clientCertificate ;
58+ private X509Certificate2Collection _rootCertificates ;
59+ private RemoteCertificateValidationCallback _remoteCertificateValidationCallback ;
60+ private LocalCertificateSelectionCallback _localCertificateSelectionCallback ;
5761 private readonly int _fetchSize ;
5862 /// <summary>
5963 /// _timeout is the amount of time a Session will wait for a send operation to complete successfully.
@@ -64,6 +68,9 @@ public partial class SessionPool : IDisposable, IPoolDiagnosticReporter
6468 private string _database ;
6569 private readonly Utils _utilFunctions = new ( ) ;
6670 private const int RetryNum = 3 ;
71+ private const string ServerAuthenticationOid = "1.3.6.1.5.5.7.3.1" ;
72+ private readonly object _tlsConfigurationLock = new ( ) ;
73+ private bool _tlsConfigurationLoaded ;
6774 private bool _debugMode ;
6875 private bool _isClose = true ;
6976 private ConcurrentClientQueue _clients ;
@@ -287,7 +294,7 @@ public async Task Open(CancellationToken cancellationToken = default)
287294 {
288295 try
289296 {
290- _clients . Add ( await CreateAndOpen ( _host , _port , _enableRpcCompression , _timeout , _useSsl , _clientCertificatePath , _clientCertificatePassword , _rootCertificatePath , _sqlDialect , _database , cancellationToken ) ) ;
297+ _clients . Add ( await CreateAndOpen ( _host , _port , _enableRpcCompression , _timeout , _useSsl , _sqlDialect , _database , cancellationToken ) ) ;
291298 }
292299 catch ( Exception e )
293300 {
@@ -307,7 +314,7 @@ public async Task Open(CancellationToken cancellationToken = default)
307314 var endPoint = _endPoints [ endPointIndex ] ;
308315 try
309316 {
310- var client = await CreateAndOpen ( endPoint . Ip , endPoint . Port , _enableRpcCompression , _timeout , _useSsl , _clientCertificatePath , _clientCertificatePassword , _rootCertificatePath , _sqlDialect , _database , cancellationToken ) ;
317+ var client = await CreateAndOpen ( endPoint . Ip , endPoint . Port , _enableRpcCompression , _timeout , _useSsl , _sqlDialect , _database , cancellationToken ) ;
311318 _clients . Add ( client ) ;
312319 isConnected = true ;
313320 startIndex = ( endPointIndex + 1 ) % _endPoints . Count ;
@@ -343,7 +350,7 @@ public async Task<Client> Reconnect(Client originalClient = null, CancellationTo
343350 {
344351 try
345352 {
346- var client = await CreateAndOpen ( _host , _port , _enableRpcCompression , _timeout , _useSsl , _clientCertificatePath , _clientCertificatePassword , _rootCertificatePath , _sqlDialect , _database , cancellationToken ) ;
353+ var client = await CreateAndOpen ( _host , _port , _enableRpcCompression , _timeout , _useSsl , _sqlDialect , _database , cancellationToken ) ;
347354 return client ;
348355 }
349356 catch ( Exception e )
@@ -367,7 +374,7 @@ public async Task<Client> Reconnect(Client originalClient = null, CancellationTo
367374 int j = ( startIndex + i ) % _endPoints . Count ;
368375 try
369376 {
370- var client = await CreateAndOpen ( _endPoints [ j ] . Ip , _endPoints [ j ] . Port , _enableRpcCompression , _timeout , _useSsl , _clientCertificatePath , _clientCertificatePassword , _rootCertificatePath , _sqlDialect , _database , cancellationToken ) ;
377+ var client = await CreateAndOpen ( _endPoints [ j ] . Ip , _endPoints [ j ] . Port , _enableRpcCompression , _timeout , _useSsl , _sqlDialect , _database , cancellationToken ) ;
371378 return client ;
372379 }
373380 catch ( Exception e )
@@ -458,19 +465,16 @@ public async Task<string> GetTimeZone()
458465 }
459466 }
460467
461- private async Task < Client > CreateAndOpen ( string host , int port , bool enableRpcCompression , int timeout , bool useSsl , string clientCertificatePath , string clientCertificatePassword , string rootCertificatePath , string sqlDialect , string database , CancellationToken cancellationToken = default )
468+ private async Task < Client > CreateAndOpen ( string host , int port , bool enableRpcCompression , int timeout , bool useSsl , string sqlDialect , string database , CancellationToken cancellationToken = default )
462469 {
463470 TTransport socket ;
464471
465472 if ( useSsl )
466473 {
467- var clientCertificate = LoadClientCertificate ( clientCertificatePath , clientCertificatePassword ) ;
468- var rootCertificates = LoadRootCertificates ( rootCertificatePath ) ;
469- var remoteCertificateValidationCallback = CreateRemoteCertificateValidationCallback ( rootCertificates ) ;
470- var localCertificateSelectionCallback = CreateLocalCertificateSelectionCallback ( clientCertificate ) ;
474+ EnsureTlsConfigurationLoaded ( ) ;
471475 socket = IPAddress . TryParse ( host , out var ipAddress )
472- ? new TTlsSocketTransport ( ipAddress , port , null , timeout , clientCertificate , remoteCertificateValidationCallback , localCertificateSelectionCallback )
473- : new TTlsSocketTransport ( host , port , null , timeout , clientCertificate , remoteCertificateValidationCallback , localCertificateSelectionCallback ) ;
476+ ? new TTlsSocketTransport ( ipAddress , port , null , timeout , _clientCertificate , _remoteCertificateValidationCallback , _localCertificateSelectionCallback )
477+ : new TTlsSocketTransport ( host , port , null , timeout , _clientCertificate , _remoteCertificateValidationCallback , _localCertificateSelectionCallback ) ;
474478 }
475479 else
476480 {
@@ -538,14 +542,31 @@ private async Task<Client> CreateAndOpen(string host, int port, bool enableRpcCo
538542 }
539543 }
540544
545+ private void EnsureTlsConfigurationLoaded ( )
546+ {
547+ lock ( _tlsConfigurationLock )
548+ {
549+ if ( _tlsConfigurationLoaded )
550+ {
551+ return ;
552+ }
553+
554+ _clientCertificate = LoadClientCertificate ( _clientCertificatePath , _clientCertificatePassword ) ;
555+ _rootCertificates = LoadRootCertificates ( _rootCertificatePath ) ;
556+ _remoteCertificateValidationCallback = CreateRemoteCertificateValidationCallback ( _rootCertificates ) ;
557+ _localCertificateSelectionCallback = CreateLocalCertificateSelectionCallback ( _clientCertificate ) ;
558+ _tlsConfigurationLoaded = true ;
559+ }
560+ }
561+
541562 private static X509Certificate2 LoadClientCertificate ( string clientCertificatePath , string clientCertificatePassword )
542563 {
543564 if ( string . IsNullOrWhiteSpace ( clientCertificatePath ) )
544565 {
545566 return null ;
546567 }
547568
548- return clientCertificatePassword == null
569+ return string . IsNullOrEmpty ( clientCertificatePassword )
549570 ? new X509Certificate2 ( clientCertificatePath )
550571 : new X509Certificate2 ( clientCertificatePath , clientCertificatePassword ) ;
551572 }
@@ -615,6 +636,11 @@ private static RemoteCertificateValidationCallback CreateRemoteCertificateValida
615636 var serverCertificate = certificate as X509Certificate2 ?? new X509Certificate2 ( certificate ) ;
616637 try
617638 {
639+ if ( ! HasServerAuthenticationEku ( serverCertificate ) )
640+ {
641+ return false ;
642+ }
643+
618644 using var customChain = new X509Chain ( ) ;
619645 customChain . ChainPolicy . RevocationMode = X509RevocationMode . NoCheck ;
620646 customChain . ChainPolicy . VerificationFlags = X509VerificationFlags . AllowUnknownCertificateAuthority ;
@@ -647,6 +673,27 @@ private static RemoteCertificateValidationCallback CreateRemoteCertificateValida
647673 } ;
648674 }
649675
676+ private static bool HasServerAuthenticationEku ( X509Certificate2 certificate )
677+ {
678+ var hasEnhancedKeyUsage = false ;
679+ foreach ( var extension in certificate . Extensions )
680+ {
681+ if ( extension is X509EnhancedKeyUsageExtension enhancedKeyUsage )
682+ {
683+ hasEnhancedKeyUsage = true ;
684+ foreach ( var oid in enhancedKeyUsage . EnhancedKeyUsages )
685+ {
686+ if ( string . Equals ( oid . Value , ServerAuthenticationOid , StringComparison . Ordinal ) )
687+ {
688+ return true ;
689+ }
690+ }
691+ }
692+ }
693+
694+ return ! hasEnhancedKeyUsage ;
695+ }
696+
650697 private static bool ChainEndsWithTrustedRoot ( X509Chain chain , X509Certificate2Collection rootCertificates )
651698 {
652699 if ( chain . ChainElements . Count == 0 )
@@ -1977,8 +2024,16 @@ protected virtual void Dispose(bool disposing)
19772024 {
19782025#if NET461_OR_GREATER || NETSTANDARD2_0
19792026#else
1980- _clients . ClientQueue . Clear ( ) ;
2027+ _clients ? . ClientQueue . Clear ( ) ;
19812028#endif
2029+ _clientCertificate ? . Dispose ( ) ;
2030+ if ( _rootCertificates != null )
2031+ {
2032+ foreach ( var rootCertificate in _rootCertificates )
2033+ {
2034+ rootCertificate . Dispose ( ) ;
2035+ }
2036+ }
19822037 }
19832038 _clients = null ;
19842039 disposedValue = true ;
0 commit comments