@@ -828,13 +828,11 @@ private async Task InitSslAsync(ProtocolCapabilities serverCapabilities, Connect
828
828
{
829
829
m_logArguments [ 1 ] = cs . CertificateFile ;
830
830
Log . Error ( "Session{0} no private key included with CertificateFile '{1}'" , m_logArguments ) ;
831
- throw new MySqlException ( "CertificateFile does not contain a private key. " +
832
- "CertificateFile should be in PKCS #12 (.pfx) format and contain both a Certificate and Private Key" ) ;
831
+ throw new MySqlException ( "CertificateFile does not contain a private key. " +
832
+ "CertificateFile should be in PKCS #12 (.pfx) format and contain both a Certificate and Private Key" ) ;
833
833
}
834
- #if ! NET45
835
834
m_clientCertificate = certificate ;
836
- #endif
837
- clientCertificates = new X509CertificateCollection { certificate } ;
835
+ clientCertificates = new X509CertificateCollection { certificate } ;
838
836
}
839
837
catch ( CryptographicException ex )
840
838
{
@@ -849,29 +847,64 @@ private async Task InitSslAsync(ProtocolCapabilities serverCapabilities, Connect
849
847
X509Chain caCertificateChain = null ;
850
848
if ( cs . CACertificateFile != null )
851
849
{
852
- try
850
+ var certificateChain = new X509Chain
853
851
{
854
- var caCertificate = new X509Certificate2 ( cs . CACertificateFile ) ;
855
- #if ! NET45
856
- m_serverCertificate = caCertificate ;
857
- #endif
858
- caCertificateChain = new X509Chain
859
- {
860
- ChainPolicy =
852
+ ChainPolicy =
861
853
{
862
854
RevocationMode = X509RevocationMode . NoCheck ,
863
855
VerificationFlags = X509VerificationFlags . AllowUnknownCertificateAuthority
864
856
}
865
- } ;
866
- caCertificateChain . ChainPolicy . ExtraStore . Add ( caCertificate ) ;
867
- }
868
- catch ( CryptographicException ex )
857
+ } ;
858
+
859
+ try
869
860
{
861
+ // read the CA Certificate File
870
862
m_logArguments [ 1 ] = cs . CACertificateFile ;
871
- Log . Error ( ex , "Session{0} couldn't load CA certificate from CertificateFile '{1}'" , m_logArguments ) ;
872
- if ( ! File . Exists ( cs . CACertificateFile ) )
873
- throw new MySqlException ( "Cannot find CA Certificate File" , ex ) ;
874
- throw new MySqlException ( "The CA Certificate File is invalid" , ex ) ;
863
+ Log . Debug ( "Session{0} loading CA certificate(s) from CertificateFile '{1}'" , m_logArguments ) ;
864
+ byte [ ] certificateBytes ;
865
+ try
866
+ {
867
+ certificateBytes = File . ReadAllBytes ( cs . CACertificateFile ) ;
868
+ }
869
+ catch ( Exception ex )
870
+ {
871
+ Log . Error ( ex , "Session{0} couldn't load CA certificate from CertificateFile '{1}'" , m_logArguments ) ;
872
+ throw new MySqlException ( "Could not load CA Certificate File: " + cs . CACertificateFile , ex ) ;
873
+ }
874
+
875
+ // find the index of each individual certificate in the file (assuming there may be multiple certificates concatenated together)
876
+ for ( var index = 0 ; index != - 1 ; index = Utility . FindNextIndex ( certificateBytes , index + 1 , s_beginCertificateBytes ) )
877
+ {
878
+ try
879
+ {
880
+ // load the certificate at this index; note that 'new X509Certificate' stops at the end of the first certificate it loads
881
+ m_logArguments [ 1 ] = index ;
882
+ Log . Debug ( "Session{0} loading certificate at Index {1} in the CA certificate file." , m_logArguments ) ;
883
+ var caCertificate = new X509Certificate2 ( Utility . ArraySlice ( certificateBytes , index ) ) ;
884
+ certificateChain . ChainPolicy . ExtraStore . Add ( caCertificate ) ;
885
+ }
886
+ catch ( CryptographicException ex )
887
+ {
888
+ m_logArguments [ 1 ] = cs . CACertificateFile ;
889
+ Log . Error ( ex , "Session{0} couldn't load CA certificate from CertificateFile '{1}'" , m_logArguments ) ;
890
+ if ( ! File . Exists ( cs . CACertificateFile ) )
891
+ throw new MySqlException ( "The CA Certificate File is invalid" , ex ) ;
892
+ }
893
+ }
894
+
895
+ // success
896
+ if ( Log . IsInfoEnabled ( ) )
897
+ Log . Info ( "Session{0} loaded certificates from CertificateFile '{1}'; CertificateCount: {2}" , m_logArguments [ 0 ] , cs . CACertificateFile , certificateChain . ChainPolicy . ExtraStore . Count ) ;
898
+ caCertificateChain = certificateChain ;
899
+ certificateChain = null ;
900
+ }
901
+ finally
902
+ {
903
+ #if NET45
904
+ certificateChain ? . Reset ( ) ;
905
+ #else
906
+ certificateChain ? . Dispose ( ) ;
907
+ #endif
875
908
}
876
909
}
877
910
@@ -944,6 +977,14 @@ bool ValidateRemoteCertificate(object rcbSender, X509Certificate rcbCertificate,
944
977
throw new MySqlException ( "MySQL Server rejected client certificate" , ex ) ;
945
978
throw ;
946
979
}
980
+ finally
981
+ {
982
+ #if NET45
983
+ caCertificateChain ? . Reset ( ) ;
984
+ #else
985
+ caCertificateChain ? . Dispose ( ) ;
986
+ #endif
987
+ }
947
988
}
948
989
949
990
// Some servers are exposed through a proxy, which handles the initial handshake and gives the proxy's
@@ -1015,9 +1056,11 @@ private void ShutdownSocket()
1015
1056
Utility . Dispose ( ref m_networkStream ) ;
1016
1057
SafeDispose ( ref m_tcpClient ) ;
1017
1058
SafeDispose ( ref m_socket ) ;
1018
- #if ! NET45
1059
+ #if NET45
1060
+ m_clientCertificate ? . Reset ( ) ;
1061
+ m_clientCertificate = null ;
1062
+ #else
1019
1063
Utility . Dispose ( ref m_clientCertificate ) ;
1020
- Utility . Dispose ( ref m_serverCertificate ) ;
1021
1064
#endif
1022
1065
}
1023
1066
@@ -1198,6 +1241,7 @@ private enum State
1198
1241
Failed ,
1199
1242
}
1200
1243
1244
+ static readonly byte [ ] s_beginCertificateBytes = new byte [ ] { 45 , 45 , 45 , 45 , 45 , 66 , 69 , 71 , 73 , 78 , 32 , 67 , 69 , 82 , 84 , 73 , 70 , 73 , 67 , 65 , 84 , 69 , 45 , 45 , 45 , 45 , 45 } ; // -----BEGIN CERTIFICATE-----
1201
1245
static int s_lastId ;
1202
1246
static byte [ ] s_connectionAttributes ;
1203
1247
static readonly IMySqlConnectorLogger Log = MySqlConnectorLogManager . CreateLogger ( nameof ( ServerSession ) ) ;
@@ -1211,10 +1255,7 @@ private enum State
1211
1255
Socket m_socket ;
1212
1256
NetworkStream m_networkStream ;
1213
1257
SslStream m_sslStream ;
1214
- #if ! NET45
1215
- IDisposable m_clientCertificate ;
1216
- IDisposable m_serverCertificate ;
1217
- #endif
1258
+ X509Certificate2 m_clientCertificate ;
1218
1259
IPayloadHandler m_payloadHandler ;
1219
1260
int m_activeCommandId ;
1220
1261
bool m_useCompression ;
0 commit comments