From 95c67b1ccbe1bfde619b121a23feac95c68a2279 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 5 Feb 2024 13:44:59 -0800 Subject: [PATCH 01/49] Initial merge from certValidation and certTest branch from David-Engel repository. --- .../tests/FunctionalTests/localhostcert.pfx | Bin 0 -> 2737 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/tests/FunctionalTests/localhostcert.pfx diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/localhostcert.pfx b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/localhostcert.pfx new file mode 100644 index 0000000000000000000000000000000000000000..739c95fd0537094c204fd298b1650d131b7ca093 GIT binary patch literal 2737 zcmZWqcU05a683NC_kakrp7KFCeHiLAro6U3xPppu`1&V3aDL5Cs%0gen43 zrAUbgN|#76B3+s&O{62d-|pGnciwsDo;fq~&CGZ2{pTAzg|h?-VZl>4{oovOF{fiT zxgczirxZ>n7=_awgl+H?xaj|s;0PE6&JMyb&;a!L~vzZmp~36>hk#Z^`SD~mb#-g|S0PB%77#m4F{aJa-3 zURj!?_Fs@RpS(pmDrF*JyZPK@;FP9mPf(i$^2@YENA}7d({}WA!vo!^>Yfw1ObHA@L?y-Wau24w!U9{K|*5I zINQZ=xYz7*i^ybrbv-s4bzPF1_w#U=iAt{N0h4c>BHVxW$q)lw=jrPM_0L?{s3>{+ zU|g4bwUdTj^N(*%^sppP7OQ+#N{V&KX5-fst7CoV^p$*EO-=oyN7HD8{vEw5DbZUl zo~F`X@)r(gX-Rfc^>4#)#%)%-a`Y=jZr2&>4LTRdLw#$anbX9LmAi#^Z}+6r)^u(P z-R{OyaVtCbjgOXxstJ2ER@hDP_*{E^Gcvdls(O`>`|r z-Wvl60AIaBa36W_s$}ZI9Zn0L$IoXmA`{-wvo^hZ^W9u$j(=o)>!szLua7ubj5=~u zt6c5BAFU?Bkiz*e68+2pSzZPzi;OkjG(Iec^dB6v`_CKnGUw13Ss3_n28IX z84>oyE~wz^L%%|#yF}4toz@{CCi*fvMII;gFp8;lXhwI+bAj_geS?2w4QAVrm8y$g z#eFB*H08>2=xUjEC|+9QyA)EcJ=8jrDkywC>EYZpgpF`eP&mbfJz2$sUtErRuS!k1 zdH4JKV*PID8$nhvS>f4$iN5?crd{GSvQX$xhr)i#Ro#UY3#>s_tI*}#ct-+M+rrh2 zaQeKG*rsNcU3OWLec#Emg(MRFO}S`|f39OCYyGX(_q$B*j*CMUm&?~*#1x;O3{tIr z!-UtmIMhTNJm@zZ_s{O&d?!?(L#w@MD2-dY=$+@Oe1L0Dqtl19MF#M4d-R6}ikQrA zwr zH2I^dW0~kS%k=L_gd0nEE;xrg90G$-GKR63CTfT`Z1L~lpx+u-hpZr2(9K#J6la`kx#Nwc1);Y^QE zkMrSvX%(q15S_Z+Ak=O%qj`zL`9;H+y=aZspiJh&fTulyzfHLAw(xDX&l2}qe}|Ba z9we!#rxGxRf^oXGNGw`@S}`J~%X)x!q5YW^HMUmqM}u;bjuGM2PMnZhg*T@jMJ{Mr zhoh@9gw^MzicOz3G9>Re6UWWw)OpWYLO52b>^UJwXZPX!Tse`c5upybQLWKlh`RCW z>d28pSIs`hr$LRZ>#DvDp{*t(9p0yio0gR(e6qasfvv>IOv`}PkjLwL`xy_GJePoq zLYezDKlE_E4Q67i;c^>n4EeL6X*9(~;xo<1TURA)Ym<&)v`AQ6VoZS-ioNq-(KW|q z9>r-TH#NObyZ5`@>_`D6-rY`{=aiQAMzTbL$@fILu}?kP8S`V~kbKEMSe?K26-WB1 z?D!UCz0|}lxK4~a`#+U2jyD*5-@4CJ5;BBq#nmZER!*M4P&7heG}5qXp}W$8-E_>%A`7KDR3P9 Date: Mon, 5 Feb 2024 13:45:42 -0800 Subject: [PATCH 02/49] Initial merge from certValidation and certTest branch from David-Engel repository. --- .../Microsoft/Data/SqlClient/SNI/SNICommon.cs | 243 ++++++++---------- .../Data/SqlClient/SNI/SNINpHandle.cs | 25 +- .../Microsoft/Data/SqlClient/SNI/SNIProxy.cs | 8 +- .../Data/SqlClient/SNI/SNITcpHandle.cs | 27 +- .../netfx/src/Microsoft.Data.SqlClient.csproj | 7 +- .../src/Resources/Strings.Designer.cs | 9 + .../src/Resources/Strings.resx | 3 + .../Microsoft.Data.SqlClient.Tests.csproj | 10 + .../SqlConnectionBasicTests.cs | 5 +- .../SqlConnectionEncryptionTests.cs | 109 ++++++++ .../tests/FunctionalTests/TestTdsServer.cs | 36 ++- .../tests/FunctionalTests/localhostcert.cer | Bin 0 -> 815 bytes .../CertificateTest.cs | 2 + 13 files changed, 287 insertions(+), 197 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionEncryptionTests.cs create mode 100644 src/Microsoft.Data.SqlClient/tests/FunctionalTests/localhostcert.cer diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs index 964d332ae4..b2f37807b8 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs @@ -13,6 +13,7 @@ using System.Threading; using System.Threading.Tasks; using Microsoft.Data.ProviderBase; +using System.Linq; namespace Microsoft.Data.SqlClient.SNI { @@ -138,196 +139,154 @@ internal class SNICommon internal const int LocalDBBadRuntime = 57; /// - /// We only validate Server name in Certificate to match with "targetServerName". + /// We either validate that the provided validationCert matches the serverCert or validate Server name in the serverCert matches "targetServerName". /// Certificate validation and chain trust validations are done by SSLStream class [System.Net.Security.SecureChannel.VerifyRemoteCertificate method] /// This method is called as a result of callback for SSL Stream Certificate validation. /// + /// Connection ID/GUID for tracing /// Server that client is expecting to connect to - /// X.509 certificate + /// Optional hostname to use for server certificate validation + /// X.509 certificate from the server + /// Path to an X.509 certificate file from the application to compare with the serverCert /// Policy errors /// True if certificate is valid - internal static bool ValidateSslServerCertificate(string targetServerName, X509Certificate cert, SslPolicyErrors policyErrors) + internal static bool ValidateSslServerCertificate(Guid connectionId, string targetServerName, string hostNameInCertificate, X509Certificate serverCert, string validationCertFileName, SslPolicyErrors policyErrors) { using (TrySNIEventScope.Create("SNICommon.ValidateSslServerCertificate | SNI | SCOPE | INFO | Entering Scope {0} ")) { if (policyErrors == SslPolicyErrors.None) { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "targetServerName {0}, SSL Server certificate not validated as PolicyErrors set to None.", args0: targetServerName); + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "Connection Id {0}, targetServerName {1}, SSL Server certificate not validated as PolicyErrors set to None.", args0: connectionId, args1: targetServerName); return true; } - // If we get to this point then there is a ssl policy flag. - StringBuilder messageBuilder = new(); - if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors)) + string serverNameToValidate; + X509Certificate validationCertificate = null; + if (!string.IsNullOrEmpty(hostNameInCertificate)) { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, SslPolicyError {1}, SSL Policy certificate chain has errors.", args0: targetServerName, args1: policyErrors); - - // get the chain status from the certificate - X509Certificate2 cert2 = cert as X509Certificate2; - X509Chain chain = new(); - chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline; - StringBuilder chainStatusInformation = new(); - bool chainIsValid = chain.Build(cert2); - Debug.Assert(!chainIsValid, "RemoteCertificateChainError flag is detected, but certificate chain is valid."); - if (!chainIsValid) - { - foreach (X509ChainStatus chainStatus in chain.ChainStatus) - { - chainStatusInformation.Append($"{chainStatus.StatusInformation}, [Status: {chainStatus.Status}]"); - chainStatusInformation.AppendLine(); - } - } - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, SslPolicyError {1}, SSL Policy certificate chain has errors. ChainStatus {2}", args0: targetServerName, args1: policyErrors, args2: chainStatusInformation); - messageBuilder.AppendFormat(Strings.SQL_RemoteCertificateChainErrors, chainStatusInformation); - messageBuilder.AppendLine(); + serverNameToValidate = hostNameInCertificate; } - - if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNotAvailable)) + else { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, SSL Policy invalidated certificate.", args0: targetServerName); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNotAvailable); + serverNameToValidate = targetServerName; } - if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch)) + if (!string.IsNullOrEmpty(validationCertFileName)) { -#if NET7_0_OR_GREATER - X509Certificate2 cert2 = cert as X509Certificate2; - if (!cert2.MatchesHostname(targetServerName)) + try { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name or HNIC does not match the Subject/SAN in Certificate.", args0: targetServerName); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + validationCertificate = new X509Certificate(validationCertFileName); } -#else - // To Do: include certificate SAN (Subject Alternative Name) check. - string certServerName = cert.Subject.Substring(cert.Subject.IndexOf('=') + 1); - - // Verify that target server name matches subject in the certificate - if (targetServerName.Length > certServerName.Length) + catch (Exception e) { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name is of greater length than Subject in Certificate.", args0: targetServerName); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + // if this fails, then fall back to the HostNameInCertificate or TargetServer validation. + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNITCPHandle), EventType.INFO, "Connection Id {0}, Exception occurred loading specified ServerCertificate: {1}, treating it as if ServerCertificate has not been specified.", args0: connectionId, args1: e.Message); } - else if (targetServerName.Length == certServerName.Length) + } + + if (validationCertificate != null) + { + if (serverCert.GetRawCertData().SequenceEqual(validationCertificate.GetRawCertData())) { - // Both strings have the same length, so targetServerName must be a FQDN - if (!targetServerName.Equals(certServerName, StringComparison.OrdinalIgnoreCase)) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); - } + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "Connection Id {0}, ServerCertificate matches the certificate provided by the server. Certificate validation passed.", args0: connectionId); + return true; } else { - if (string.Compare(targetServerName, 0, certServerName, 0, targetServerName.Length, StringComparison.OrdinalIgnoreCase) != 0) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); - } - - // Server name matches cert name for its whole length, so ensure that the - // character following the server name is a '.'. This will avoid - // having server name "ab" match "abc.corp.company.com" - // (Names have different lengths, so the target server can't be a FQDN.) - if (certServerName[targetServerName.Length] != '.') - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "targetServerName {0}, Target Server name does not match Subject in Certificate.", args0: targetServerName); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); - } + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "Connection Id {0}, ServerCertificate doesn't match the certificate provided by the server. Certificate validation failed.", args0: connectionId); + throw ADP.SSLCertificateAuthenticationException(Strings.SQL_RemoteCertificateDoesNotMatchServerCertificate); } -#endif } - - if (messageBuilder.Length > 0) + else { - throw ADP.SSLCertificateAuthenticationException(messageBuilder.ToString()); - } - - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, " Remote certificate with subject: {0}, validated successfully.", args0: cert.Subject); - return true; - } - } - - /// - /// We validate the provided certificate provided by the client with the one from the server to see if it matches. - /// Certificate validation and chain trust validations are done by SSLStream class [System.Net.Security.SecureChannel.VerifyRemoteCertificate method] - /// This method is called as a result of callback for SSL Stream Certificate validation. - /// - /// X.509 certificate provided by the client - /// X.509 certificate provided by the server - /// Policy errors - /// True if certificate is valid - internal static bool ValidateSslServerCertificate(X509Certificate clientCert, X509Certificate serverCert, SslPolicyErrors policyErrors) - { - using (TrySNIEventScope.Create("SNICommon.ValidateSslServerCertificate | SNI | SCOPE | INFO | Entering Scope {0} ")) - { - if (policyErrors == SslPolicyErrors.None) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "serverCert {0}, SSL Server certificate not validated as PolicyErrors set to None.", args0: clientCert.Subject); - return true; - } - - StringBuilder messageBuilder = new(); - if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNotAvailable)) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "serverCert {0}, SSL Server certificate not validated as PolicyErrors set to RemoteCertificateNotAvailable.", args0: clientCert.Subject); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNotAvailable); - } + // If we get to this point then there is a ssl policy flag. + StringBuilder messageBuilder = new(); + if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNotAvailable)) + { + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, targetServerName {1}, SSL Server certificate not validated as PolicyErrors set to RemoteCertificateNotAvailable.", args0: connectionId, args1: targetServerName); + messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNotAvailable); + } - if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors)) - { - // get the chain status from the server certificate - X509Certificate2 cert2 = serverCert as X509Certificate2; - X509Chain chain = new(); - chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline; - StringBuilder chainStatusInformation = new(); - bool chainIsValid = chain.Build(cert2); - Debug.Assert(!chainIsValid, "RemoteCertificateChainError flag is detected, but certificate chain is valid."); - if (!chainIsValid) + if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateChainErrors)) { - foreach (X509ChainStatus chainStatus in chain.ChainStatus) + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, targetServerName {0}, SslPolicyError {1}, SSL Policy certificate chain has errors.", args0: connectionId, args1: targetServerName, args2: policyErrors); + + // get the chain status from the certificate + X509Certificate2 cert2 = serverCert as X509Certificate2; + X509Chain chain = new(); + chain.ChainPolicy.RevocationMode = X509RevocationMode.Offline; + StringBuilder chainStatusInformation = new(); + bool chainIsValid = chain.Build(cert2); + Debug.Assert(!chainIsValid, "RemoteCertificateChainError flag is detected, but certificate chain is valid."); + if (!chainIsValid) { - chainStatusInformation.Append($"{chainStatus.StatusInformation}, [Status: {chainStatus.Status}]"); - chainStatusInformation.AppendLine(); + foreach (X509ChainStatus chainStatus in chain.ChainStatus) + { + chainStatusInformation.Append($"{chainStatus.StatusInformation}, [Status: {chainStatus.Status}]"); + chainStatusInformation.AppendLine(); + } } + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, targetServerName {1}, SslPolicyError {2}, SSL Policy certificate chain has errors. ChainStatus {3}", args0: connectionId, args1: targetServerName, args2: policyErrors, args3: chainStatusInformation); + messageBuilder.AppendFormat(Strings.SQL_RemoteCertificateChainErrors, chainStatusInformation); + messageBuilder.AppendLine(); } - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "certificate subject from server is {0}, and does not match with the certificate provided client.", args0: cert2.SubjectName.Name); - messageBuilder.AppendFormat(Strings.SQL_RemoteCertificateChainErrors, chainStatusInformation); - messageBuilder.AppendLine(); - } - if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch)) - { + if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch)) + { #if NET7_0_OR_GREATER - X509Certificate2 s_cert = serverCert as X509Certificate2; - X509Certificate2 c_cert = clientCert as X509Certificate2; - - if (!s_cert.MatchesHostname(c_cert.SubjectName.Name)) + X509Certificate2 cert2 = serverCert as X509Certificate2; + if (!cert2.MatchesHostname(serverNameToValidate)) { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "certificate from server does not match with the certificate provided client.", args0: s_cert.Subject); + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, serverNameToValidate {1}, Target Server name or HNIC does not match the Subject/SAN in Certificate.", args0: connectionId, args1: serverNameToValidate); messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); } #else - // Verify that subject name matches - if (serverCert.Subject != clientCert.Subject) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "certificate subject from server is {0}, and does not match with the certificate provided client.", args0: serverCert.Subject); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + // To Do: include certificate SAN (Subject Alternative Name) check. + string certServerName = serverCert.Subject.Substring(serverCert.Subject.IndexOf('=') + 1); + + // Verify that target server name matches subject in the certificate + if (serverNameToValidate.Length > certServerName.Length) + { + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, serverNameToValidate {1}, Target Server name is of greater length than Subject in Certificate.", args0: connectionId, args1: serverNameToValidate); + messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + } + else if (serverNameToValidate.Length == certServerName.Length) + { + // Both strings have the same length, so serverNameToValidate must be a FQDN + if (!serverNameToValidate.Equals(certServerName, StringComparison.OrdinalIgnoreCase)) + { + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, serverNameToValidate {1}, Target Server name does not match Subject in Certificate.", args0: connectionId, args1: serverNameToValidate); + messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + } + } + else + { + if (string.Compare(serverNameToValidate, 0, certServerName, 0, serverNameToValidate.Length, StringComparison.OrdinalIgnoreCase) != 0) + { + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, serverNameToValidate {1}, Target Server name does not match Subject in Certificate.", args0: connectionId, args1: serverNameToValidate); + messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + } + + // Server name matches cert name for its whole length, so ensure that the + // character following the server name is a '.'. This will avoid + // having server name "ab" match "abc.corp.company.com" + // (Names have different lengths, so the target server can't be a FQDN.) + if (certServerName[serverNameToValidate.Length] != '.') + { + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, serverNameToValidate {1}, Target Server name does not match Subject in Certificate.", args0: connectionId, args1: serverNameToValidate); + messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + } + } +#endif } - if (!serverCert.Equals(clientCert)) + if (messageBuilder.Length > 0) { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "certificate from server does not match with the certificate provided client.", args0: serverCert.Subject); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + throw ADP.SSLCertificateAuthenticationException(messageBuilder.ToString()); } -#endif - } - - if (messageBuilder.Length > 0) - { - throw ADP.SSLCertificateAuthenticationException(messageBuilder.ToString()); } - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "certificate subject {0}, Client certificate validated successfully.", args0: clientCert.Subject); + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "Connection Id {0}, certificate with subject: {1}, validated successfully.", args0: connectionId, args1: serverCert.Subject); return true; } } diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs index 2889ce6bb4..09f58833b3 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs @@ -24,6 +24,8 @@ internal sealed class SNINpHandle : SNIPhysicalHandle private readonly string _targetServer; private readonly object _sendSync; + private readonly string _hostNameInCertificate; + private readonly string _serverCertificateFilename; private readonly bool _tlsFirst; private Stream _stream; private NamedPipeClientStream _pipeStream; @@ -38,7 +40,7 @@ internal sealed class SNINpHandle : SNIPhysicalHandle private int _bufferSize = TdsEnums.DEFAULT_LOGIN_PACKET_SIZE; private readonly Guid _connectionId = Guid.NewGuid(); - public SNINpHandle(string serverName, string pipeName, TimeoutTimer timeout, bool tlsFirst) + public SNINpHandle(string serverName, string pipeName, TimeoutTimer timeout, bool tlsFirst, string hostNameInCertificate, string serverCertificateFilename) { using (TrySNIEventScope.Create(nameof(SNINpHandle))) { @@ -47,6 +49,8 @@ public SNINpHandle(string serverName, string pipeName, TimeoutTimer timeout, boo _sendSync = new object(); _targetServer = serverName; _tlsFirst = tlsFirst; + _hostNameInCertificate = hostNameInCertificate; + _serverCertificateFilename = serverCertificateFilename; try { _pipeStream = new NamedPipeClientStream( @@ -369,23 +373,20 @@ public override void DisableSsl() /// Validate server certificate /// /// Sender object - /// X.509 certificate + /// X.509 certificate /// X.509 chain /// Policy errors /// true if valid - private bool ValidateServerCertificate(object sender, X509Certificate cert, X509Chain chain, SslPolicyErrors policyErrors) + private bool ValidateServerCertificate(object sender, X509Certificate serverCertificate, X509Chain chain, SslPolicyErrors policyErrors) { - using (TrySNIEventScope.Create(nameof(SNINpHandle))) + if (!_validateCert) { - if (!_validateCert) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Certificate validation not requested.", args0: ConnectionId); - return true; - } - - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Proceeding to SSL certificate validation.", args0: ConnectionId); - return SNICommon.ValidateSslServerCertificate(_targetServer, cert, policyErrors); + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Certificate validation not requested.", args0: ConnectionId); + return true; } + + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Proceeding to SSL certificate validation.", args0: ConnectionId); + return SNICommon.ValidateSslServerCertificate(_connectionId, _targetServer, _hostNameInCertificate, serverCertificate, _serverCertificateFilename, policyErrors); } /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIProxy.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIProxy.cs index 3df369a2f6..0a463eeb8b 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIProxy.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNIProxy.cs @@ -191,7 +191,7 @@ private static bool IsErrorStatus(SecurityStatusPalErrorCode errorCode) tlsFirst, hostNameInCertificate, serverCertificateFilename); break; case DataSource.Protocol.NP: - sniHandle = CreateNpHandle(details, timeout, parallel, tlsFirst); + sniHandle = CreateNpHandle(details, timeout, parallel, tlsFirst, hostNameInCertificate, serverCertificateFilename); break; default: Debug.Fail($"Unexpected connection protocol: {details._connectionProtocol}"); @@ -347,8 +347,10 @@ private static byte[][] GetSqlServerSPNs(string hostNameOrAddress, string portOr /// Timer expiration /// Should MultiSubnetFailover be used. Only returns an error for named pipes. /// + /// Host name in certificate + /// Used for the path to the Server Certificate /// SNINpHandle - private static SNINpHandle CreateNpHandle(DataSource details, TimeoutTimer timeout, bool parallel, bool tlsFirst) + private static SNINpHandle CreateNpHandle(DataSource details, TimeoutTimer timeout, bool parallel, bool tlsFirst, string hostNameInCertificate, string serverCertificateFilename) { if (parallel) { @@ -356,7 +358,7 @@ private static SNINpHandle CreateNpHandle(DataSource details, TimeoutTimer timeo SNICommon.ReportSNIError(SNIProviders.NP_PROV, 0, SNICommon.MultiSubnetFailoverWithNonTcpProtocol, Strings.SNI_ERROR_49); return null; } - return new SNINpHandle(details.PipeHostName, details.PipeName, timeout, tlsFirst); + return new SNINpHandle(details.PipeHostName, details.PipeName, timeout, tlsFirst, hostNameInCertificate, serverCertificateFilename); } /// diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs index d12e91ad62..ee70ede9a8 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs @@ -698,33 +698,8 @@ private bool ValidateServerCertificate(object sender, X509Certificate serverCert return true; } - string serverNameToValidate; - if (!string.IsNullOrEmpty(_hostNameInCertificate)) - { - serverNameToValidate = _hostNameInCertificate; - } - else - { - serverNameToValidate = _targetServer; - } - - if (!string.IsNullOrEmpty(_serverCertificateFilename)) - { - X509Certificate clientCertificate = null; - try - { - clientCertificate = new X509Certificate(_serverCertificateFilename); - return SNICommon.ValidateSslServerCertificate(clientCertificate, serverCertificate, policyErrors); - } - catch (Exception e) - { - // if this fails, then fall back to the HostNameInCertificate or TargetServer validation. - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNITCPHandle), EventType.INFO, "Connection Id {0}, IOException occurred: {1}", args0: _connectionId, args1: e.Message); - } - } - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNITCPHandle), EventType.INFO, "Connection Id {0}, Certificate will be validated for Target Server name", args0: _connectionId); - return SNICommon.ValidateSslServerCertificate(serverNameToValidate, serverCertificate, policyErrors); + return SNICommon.ValidateSslServerCertificate(_connectionId, _targetServer, _hostNameInCertificate, serverCertificate, _serverCertificateFilename, policyErrors); } /// diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 97feee8bef..1f693be1f3 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -22,14 +22,14 @@ full - + $([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(GeneratedSourceFileName)')) - + True @@ -701,6 +701,7 @@ System ResXFileCodeGenerator Strings.Designer.cs + Designer Resources\%(RecursiveDir)%(Filename)%(Extension) @@ -751,4 +752,4 @@ - + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs b/src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs index 2823830e05..b74b1a4779 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.Designer.cs @@ -10215,6 +10215,15 @@ internal class Strings { } } + /// + /// Looks up a localized string similar to The certificate provided by the server does not match the certificate provided by the ServerCertificate option.. + /// + internal static string SQL_RemoteCertificateDoesNotMatchServerCertificate { + get { + return ResourceManager.GetString("SQL_RemoteCertificateDoesNotMatchServerCertificate", resourceCulture); + } + } + /// /// Looks up a localized string similar to Certificate name mismatch. The provided 'DataSource' or 'HostNameInCertificate' does not match the name in the certificate.. /// diff --git a/src/Microsoft.Data.SqlClient/src/Resources/Strings.resx b/src/Microsoft.Data.SqlClient/src/Resources/Strings.resx index 78bfde6f9a..71a4204fcc 100644 --- a/src/Microsoft.Data.SqlClient/src/Resources/Strings.resx +++ b/src/Microsoft.Data.SqlClient/src/Resources/Strings.resx @@ -4740,4 +4740,7 @@ Certificate not available while validating the certificate. + + The certificate provided by the server does not match the certificate provided by the ServerCertificate option. + \ No newline at end of file diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index 6a874f852b..f79ad9e28a 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -38,6 +38,7 @@ + @@ -120,6 +121,9 @@ + + + @@ -130,5 +134,11 @@ PreserveNewest xunit.runner.json + + PreserveNewest + + + PreserveNewest + diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs index 8f16c09aa3..b4f38f70df 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs @@ -12,6 +12,7 @@ using System.Security; using System.Threading; using System.Threading.Tasks; +using Microsoft.SqlServer.TDS.PreLogin; using Microsoft.SqlServer.TDS.Servers; using Xunit; @@ -46,10 +47,10 @@ public void IntegratedAuthConnectionTest() [Fact] public async Task PreLoginEncryptionExcludedTest() { - using TestTdsServer server = TestTdsServer.StartTestServer(false, false, 5, excludeEncryption: true); + using TestTdsServer server = TestTdsServer.StartTestServer(false, false, 5, encryptionType: TDSPreLoginTokenEncryptionType.None); SqlConnectionStringBuilder builder = new(server.ConnectionString) { - IntegratedSecurity = true + IntegratedSecurity = true, }; using SqlConnection connection = new(builder.ConnectionString); diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionEncryptionTests.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionEncryptionTests.cs new file mode 100644 index 0000000000..74ca8d735c --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionEncryptionTests.cs @@ -0,0 +1,109 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Data; +using System.Diagnostics; +using System.Diagnostics.Tracing; +using System.Linq; +using System.Net; +using System.Net.Sockets; +using System.Security.Cryptography.X509Certificates; +using System.Threading.Tasks; +using Microsoft.SqlServer.TDS.PreLogin; +using Xunit; + +namespace Microsoft.Data.SqlClient.Tests +{ + public class SqlConnectionEncryptionTests + { + [Fact] + public void ConnectionTest() + { + using (SqlClientListener listener = new SqlClientListener()) + { + // Happy path + //AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", true); + + //using TestTdsServer server = TestTdsServer.StartTestServer(false, false, 5, encryptionType: TDSPreLoginTokenEncryptionType.NotSupported); + //SqlConnectionStringBuilder builder = new(server.ConnectionString) + //{ + // IntegratedSecurity = true, + // Encrypt = false, + //}; + + //using SqlConnection connection = new(builder.ConnectionString); + //connection.Open(); + //Assert.Equal(ConnectionState.Open, connection.State); + + AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", true); + + TestTdsServer server = TestTdsServer.StartTestServer(enableFedAuth: false, enableLog: false, connectionTimeout: 15, + methodName: "", + new X509Certificate2("localhostcert.pfx", "nopassword", X509KeyStorageFlags.UserKeySet), + encryptionType: TDSPreLoginTokenEncryptionType.On); + + SqlConnectionStringBuilder builder = new(server.ConnectionString) + { + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = true, + IntegratedSecurity = true, + }; + + using (SqlConnection connection = new(builder.ConnectionString)) + { + connection.Open(); + Assert.Equal(ConnectionState.Open, connection.State); + } + } + } + + [Fact] + public void ConnectionServerCertificateTest() + { + using (SqlClientListener listener = new SqlClientListener()) + { + using (TestTdsServer server = TestTdsServer.StartTestServer(false, false, 60, "", + new X509Certificate2("localhostcert.pfx", "nopassword", X509KeyStorageFlags.UserKeySet), + encryptionType: TDSPreLoginTokenEncryptionType.On)) + { + SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(server.ConnectionString); + builder.Encrypt = SqlConnectionEncryptOption.Mandatory; + builder.TrustServerCertificate = false; + builder.ServerCertificate = "localhostcert.cer"; + using (SqlConnection connection = new(builder.ConnectionString)) + { + connection.Open(); + Assert.Equal(ConnectionState.Open, connection.State); + } + } + } + } + } + public class SqlClientListener : EventListener + { + protected override void OnEventSourceCreated(EventSource eventSource) + { + // Only enable events from SqlClientEventSource. + if (eventSource.Name.Equals("Microsoft.Data.SqlClient.EventSource")) + { + // Use EventKeyWord 2 to capture basic application flow events. + // See the above table for all available keywords. + EnableEvents(eventSource, EventLevel.Verbose, (EventKeywords)2); + //EnableEvents(eventSource, EventLevel.Verbose, EventKeywords.All); + } + } + + // This callback runs whenever an event is written by SqlClientEventSource. + // Event data is accessed through the EventWrittenEventArgs parameter. + protected override void OnEventWritten(EventWrittenEventArgs eventData) + { + // Print event data. + if (eventData != null && eventData.Payload != null && eventData.Payload[0].ToString() != "") + Debug.WriteLine($" {DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss:ff")} {eventData.Payload[0]}"); + } + } + +} + diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs index 1ead74f58d..16117015b5 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs @@ -3,9 +3,13 @@ // See the LICENSE file in the project root for more information. using System; +using System.Linq; using System.Net; +using System.Net.Sockets; using System.Runtime.CompilerServices; +using System.Security.Cryptography.X509Certificates; using Microsoft.SqlServer.TDS.EndPoint; +using Microsoft.SqlServer.TDS.PreLogin; using Microsoft.SqlServer.TDS.Servers; namespace Microsoft.Data.SqlClient.Tests @@ -25,7 +29,9 @@ public TestTdsServer(QueryEngine engine, TDSServerArguments args) : base(args) Engine = engine; } - public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool enableFedAuth = false, bool enableLog = false, int connectionTimeout = DefaultConnectionTimeout, bool excludeEncryption = false, [CallerMemberName] string methodName = "") + public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool enableFedAuth = false, bool enableLog = false, + int connectionTimeout = DefaultConnectionTimeout, [CallerMemberName] string methodName = "", + X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.Off) { TDSServerArguments args = new TDSServerArguments() { @@ -36,12 +42,16 @@ public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool { args.FedAuthRequiredPreLoginOption = SqlServer.TDS.PreLogin.TdsPreLoginFedAuthRequiredOption.FedAuthRequired; } - if (excludeEncryption) + + if (encryptionCertificate != null) { - args.Encryption = SqlServer.TDS.PreLogin.TDSPreLoginTokenEncryptionType.None; + args.EncryptionCertificate = encryptionCertificate; } + args.Encryption = encryptionType; + TestTdsServer server = engine == null ? new TestTdsServer(args) : new TestTdsServer(engine, args); + server._endpoint = new TDSServerEndPoint(server) { ServerEndPoint = new IPEndPoint(IPAddress.Any, 0) }; server._endpoint.EndpointName = methodName; // The server EventLog should be enabled as it logs the exceptions. @@ -49,17 +59,25 @@ public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool server._endpoint.Start(); int port = server._endpoint.ServerEndPoint.Port; - server._connectionStringBuilder = excludeEncryption - // Allow encryption to be set when encryption is to be excluded from pre-login response. - ? new SqlConnectionStringBuilder() { DataSource = "localhost," + port, ConnectTimeout = connectionTimeout, Encrypt = SqlConnectionEncryptOption.Mandatory } - : new SqlConnectionStringBuilder() { DataSource = "localhost," + port, ConnectTimeout = connectionTimeout, Encrypt = SqlConnectionEncryptOption.Optional }; + + String hostName = Dns.GetHostName().ToUpper(); + + server._connectionStringBuilder = new SqlConnectionStringBuilder() + { + DataSource = $"{hostName}," + port, + //DataSource = $"localhost,{port}", + ConnectTimeout = connectionTimeout, + Encrypt = (encryptionType == TDSPreLoginTokenEncryptionType.Off ? SqlConnectionEncryptOption.Optional : SqlConnectionEncryptOption.Mandatory) + }; server.ConnectionString = server._connectionStringBuilder.ConnectionString; return server; } - public static TestTdsServer StartTestServer(bool enableFedAuth = false, bool enableLog = false, int connectionTimeout = DefaultConnectionTimeout, bool excludeEncryption = false, [CallerMemberName] string methodName = "") + public static TestTdsServer StartTestServer(bool enableFedAuth = false, bool enableLog = false, + int connectionTimeout = DefaultConnectionTimeout, [CallerMemberName] string methodName = "", + X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.Off) { - return StartServerWithQueryEngine(null, enableFedAuth, enableLog, connectionTimeout, excludeEncryption, methodName); + return StartServerWithQueryEngine(null, enableFedAuth, enableLog, connectionTimeout, methodName, encryptionCertificate, encryptionType); } public void Dispose() => _endpoint?.Stop(); diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/localhostcert.cer b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/localhostcert.cer new file mode 100644 index 0000000000000000000000000000000000000000..42ed7d48f8d553857be483f690ec6c6e9028ed1d GIT binary patch literal 815 zcmXqLV%9cjViI1!%*4pVB%ma7`m9{$gw_7*8q>=ds#h8CvTs~A}sn41{+84Q{jxtN+585u5=d9tnk>%yqGtW@n;bwkL@U>(C%Mjw(odM6iO z=1Y?d-fVP!k^Qk7YNhP`7jLC%UVeNon5k#2tY6J;o#^&bEt#TKF*@gytgICe|DJSh z#s38?95Pc@8T@7{^J;m&i%$W=Xzgnt5}>I z+QJ>P>EOx*w~I_pyldtQ|LrKKq7!k?Ur8W#-U&-4W=00a#kmIA27JKKm*r<<{LjL| z%*49DKo!InWRWwFX+n>YCeEDv9kRTt6 z7>kI;vKk5T1(hLNY?kMzCN19b@_@4{a)bcm9vC5v44ZpCTQe*$KD5C~po??)N`co6 z*_^`vVj2FazB)OVd(!VacTZi&n6u5{#j@mrr_=bT)ck!iPly7#rE`Q3iK)$p|c;Td)-n4JopSUz5uF10;xW&qP%y-Ar zzdWZErrS5p>@c3vzIMUmUr#k}1>4+szC-KY Date: Mon, 25 Mar 2024 08:47:00 -0700 Subject: [PATCH 03/49] Added unit test in Manual Tests. --- .../Data/SqlClient/SNI/SNITcpHandle.cs | 1 - .../Microsoft.Data.SqlClient.Tests.csproj | 5 +- .../SqlConnectionEncryptionTests.cs | 109 ---------- .../tests/FunctionalTests/TestTdsServer.cs | 5 +- .../tests/FunctionalTests/localhostcert.cer | Bin 815 -> 0 bytes .../tests/FunctionalTests/localhostcert.pfx | Bin 2737 -> 0 bytes .../DataCommon/ConnectionTestParameters.cs | 19 ++ .../ConnectionTestParametersData.cs | 193 ++++++++++++++++++ ....Data.SqlClient.ManualTesting.Tests.csproj | 6 + .../CertificateTestWithTdsServerTest.cs | 151 ++++++++++++++ .../ManualTests/TracingTests/TestTdsServer.cs | 40 +++- .../tests/ManualTests/makepfxcert.ps1 | 115 +++++++++++ .../tools/TDS/TDS.EndPoint/TDSServerParser.cs | 8 +- .../tests/tools/TDS/TDS/TDSStream.cs | 16 ++ 14 files changed, 539 insertions(+), 129 deletions(-) delete mode 100644 src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionEncryptionTests.cs delete mode 100644 src/Microsoft.Data.SqlClient/tests/FunctionalTests/localhostcert.cer delete mode 100644 src/Microsoft.Data.SqlClient/tests/FunctionalTests/localhostcert.pfx create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParameters.cs create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServerTest.cs create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs index ee70ede9a8..52769b0f68 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNITcpHandle.cs @@ -644,7 +644,6 @@ public override uint EnableSsl(uint options) } else { - // TODO: Resolve whether to send _serverNameIndication or _targetServer. _serverNameIndication currently results in error. Why? _sslStream.AuthenticateAsClient(_targetServer, null, s_supportedProtocols, false); } if (_sslOverTdsStream is not null) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index 3615582bcd..02e84e4343 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -38,7 +38,6 @@ - @@ -134,9 +133,7 @@ PreserveNewest xunit.runner.json - - PreserveNewest - + PreserveNewest diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionEncryptionTests.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionEncryptionTests.cs deleted file mode 100644 index 74ca8d735c..0000000000 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionEncryptionTests.cs +++ /dev/null @@ -1,109 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. - -using System; -using System.Data; -using System.Diagnostics; -using System.Diagnostics.Tracing; -using System.Linq; -using System.Net; -using System.Net.Sockets; -using System.Security.Cryptography.X509Certificates; -using System.Threading.Tasks; -using Microsoft.SqlServer.TDS.PreLogin; -using Xunit; - -namespace Microsoft.Data.SqlClient.Tests -{ - public class SqlConnectionEncryptionTests - { - [Fact] - public void ConnectionTest() - { - using (SqlClientListener listener = new SqlClientListener()) - { - // Happy path - //AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", true); - - //using TestTdsServer server = TestTdsServer.StartTestServer(false, false, 5, encryptionType: TDSPreLoginTokenEncryptionType.NotSupported); - //SqlConnectionStringBuilder builder = new(server.ConnectionString) - //{ - // IntegratedSecurity = true, - // Encrypt = false, - //}; - - //using SqlConnection connection = new(builder.ConnectionString); - //connection.Open(); - //Assert.Equal(ConnectionState.Open, connection.State); - - AppContext.SetSwitch("Switch.Microsoft.Data.SqlClient.UseManagedNetworkingOnWindows", true); - - TestTdsServer server = TestTdsServer.StartTestServer(enableFedAuth: false, enableLog: false, connectionTimeout: 15, - methodName: "", - new X509Certificate2("localhostcert.pfx", "nopassword", X509KeyStorageFlags.UserKeySet), - encryptionType: TDSPreLoginTokenEncryptionType.On); - - SqlConnectionStringBuilder builder = new(server.ConnectionString) - { - Encrypt = SqlConnectionEncryptOption.Mandatory, - TrustServerCertificate = true, - IntegratedSecurity = true, - }; - - using (SqlConnection connection = new(builder.ConnectionString)) - { - connection.Open(); - Assert.Equal(ConnectionState.Open, connection.State); - } - } - } - - [Fact] - public void ConnectionServerCertificateTest() - { - using (SqlClientListener listener = new SqlClientListener()) - { - using (TestTdsServer server = TestTdsServer.StartTestServer(false, false, 60, "", - new X509Certificate2("localhostcert.pfx", "nopassword", X509KeyStorageFlags.UserKeySet), - encryptionType: TDSPreLoginTokenEncryptionType.On)) - { - SqlConnectionStringBuilder builder = new SqlConnectionStringBuilder(server.ConnectionString); - builder.Encrypt = SqlConnectionEncryptOption.Mandatory; - builder.TrustServerCertificate = false; - builder.ServerCertificate = "localhostcert.cer"; - using (SqlConnection connection = new(builder.ConnectionString)) - { - connection.Open(); - Assert.Equal(ConnectionState.Open, connection.State); - } - } - } - } - } - public class SqlClientListener : EventListener - { - protected override void OnEventSourceCreated(EventSource eventSource) - { - // Only enable events from SqlClientEventSource. - if (eventSource.Name.Equals("Microsoft.Data.SqlClient.EventSource")) - { - // Use EventKeyWord 2 to capture basic application flow events. - // See the above table for all available keywords. - EnableEvents(eventSource, EventLevel.Verbose, (EventKeywords)2); - //EnableEvents(eventSource, EventLevel.Verbose, EventKeywords.All); - } - } - - // This callback runs whenever an event is written by SqlClientEventSource. - // Event data is accessed through the EventWrittenEventArgs parameter. - protected override void OnEventWritten(EventWrittenEventArgs eventData) - { - // Print event data. - if (eventData != null && eventData.Payload != null && eventData.Payload[0].ToString() != "") - Debug.WriteLine($" {DateTime.Now.ToString("MM/dd/yyyy hh:mm:ss:ff")} {eventData.Payload[0]}"); - } - } - -} - diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs index 16117015b5..4f144cb0f4 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs @@ -60,12 +60,9 @@ public TestTdsServer(QueryEngine engine, TDSServerArguments args) : base(args) int port = server._endpoint.ServerEndPoint.Port; - String hostName = Dns.GetHostName().ToUpper(); - server._connectionStringBuilder = new SqlConnectionStringBuilder() { - DataSource = $"{hostName}," + port, - //DataSource = $"localhost,{port}", + DataSource = "localhost," + port, ConnectTimeout = connectionTimeout, Encrypt = (encryptionType == TDSPreLoginTokenEncryptionType.Off ? SqlConnectionEncryptOption.Optional : SqlConnectionEncryptOption.Mandatory) }; diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/localhostcert.cer b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/localhostcert.cer deleted file mode 100644 index 42ed7d48f8d553857be483f690ec6c6e9028ed1d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 815 zcmXqLV%9cjViI1!%*4pVB%ma7`m9{$gw_7*8q>=ds#h8CvTs~A}sn41{+84Q{jxtN+585u5=d9tnk>%yqGtW@n;bwkL@U>(C%Mjw(odM6iO z=1Y?d-fVP!k^Qk7YNhP`7jLC%UVeNon5k#2tY6J;o#^&bEt#TKF*@gytgICe|DJSh z#s38?95Pc@8T@7{^J;m&i%$W=Xzgnt5}>I z+QJ>P>EOx*w~I_pyldtQ|LrKKq7!k?Ur8W#-U&-4W=00a#kmIA27JKKm*r<<{LjL| z%*49DKo!InWRWwFX+n>YCeEDv9kRTt6 z7>kI;vKk5T1(hLNY?kMzCN19b@_@4{a)bcm9vC5v44ZpCTQe*$KD5C~po??)N`co6 z*_^`vVj2FazB)OVd(!VacTZi&n6u5{#j@mrr_=bT)ck!iPly7#rE`Q3iK)$p|c;Td)-n4JopSUz5uF10;xW&qP%y-Ar zzdWZErrS5p>@c3vzIMUmUr#k}1>4+szC-KY3NC_kakrp7KFCeHiLAro6U3xPppu`1&V3aDL5Cs%0gen43 zrAUbgN|#76B3+s&O{62d-|pGnciwsDo;fq~&CGZ2{pTAzg|h?-VZl>4{oovOF{fiT zxgczirxZ>n7=_awgl+H?xaj|s;0PE6&JMyb&;a!L~vzZmp~36>hk#Z^`SD~mb#-g|S0PB%77#m4F{aJa-3 zURj!?_Fs@RpS(pmDrF*JyZPK@;FP9mPf(i$^2@YENA}7d({}WA!vo!^>Yfw1ObHA@L?y-Wau24w!U9{K|*5I zINQZ=xYz7*i^ybrbv-s4bzPF1_w#U=iAt{N0h4c>BHVxW$q)lw=jrPM_0L?{s3>{+ zU|g4bwUdTj^N(*%^sppP7OQ+#N{V&KX5-fst7CoV^p$*EO-=oyN7HD8{vEw5DbZUl zo~F`X@)r(gX-Rfc^>4#)#%)%-a`Y=jZr2&>4LTRdLw#$anbX9LmAi#^Z}+6r)^u(P z-R{OyaVtCbjgOXxstJ2ER@hDP_*{E^Gcvdls(O`>`|r z-Wvl60AIaBa36W_s$}ZI9Zn0L$IoXmA`{-wvo^hZ^W9u$j(=o)>!szLua7ubj5=~u zt6c5BAFU?Bkiz*e68+2pSzZPzi;OkjG(Iec^dB6v`_CKnGUw13Ss3_n28IX z84>oyE~wz^L%%|#yF}4toz@{CCi*fvMII;gFp8;lXhwI+bAj_geS?2w4QAVrm8y$g z#eFB*H08>2=xUjEC|+9QyA)EcJ=8jrDkywC>EYZpgpF`eP&mbfJz2$sUtErRuS!k1 zdH4JKV*PID8$nhvS>f4$iN5?crd{GSvQX$xhr)i#Ro#UY3#>s_tI*}#ct-+M+rrh2 zaQeKG*rsNcU3OWLec#Emg(MRFO}S`|f39OCYyGX(_q$B*j*CMUm&?~*#1x;O3{tIr z!-UtmIMhTNJm@zZ_s{O&d?!?(L#w@MD2-dY=$+@Oe1L0Dqtl19MF#M4d-R6}ikQrA zwr zH2I^dW0~kS%k=L_gd0nEE;xrg90G$-GKR63CTfT`Z1L~lpx+u-hpZr2(9K#J6la`kx#Nwc1);Y^QE zkMrSvX%(q15S_Z+Ak=O%qj`zL`9;H+y=aZspiJh&fTulyzfHLAw(xDX&l2}qe}|Ba z9we!#rxGxRf^oXGNGw`@S}`J~%X)x!q5YW^HMUmqM}u;bjuGM2PMnZhg*T@jMJ{Mr zhoh@9gw^MzicOz3G9>Re6UWWw)OpWYLO52b>^UJwXZPX!Tse`c5upybQLWKlh`RCW z>d28pSIs`hr$LRZ>#DvDp{*t(9p0yio0gR(e6qasfvv>IOv`}PkjLwL`xy_GJePoq zLYezDKlE_E4Q67i;c^>n4EeL6X*9(~;xo<1TURA)Ym<&)v`AQ6VoZS-ioNq-(KW|q z9>r-TH#NObyZ5`@>_`D6-rY`{=aiQAMzTbL$@fILu}?kP8S`V~kbKEMSe?K26-WB1 z?D!UCz0|}lxK4~a`#+U2jyD*5-@4CJ5;BBq#nmZER!*M4P&7heG}5qXp}W$8-E_>%A`7KDR3P9 ConnectionTestParametersList { get; set; } + + public static IEnumerable GetConnectionTestParameters() + { + yield return new object[] { Data.ConnectionTestParametersList[0] }; + yield return new object[] { Data.ConnectionTestParametersList[1] }; + yield return new object[] { Data.ConnectionTestParametersList[2] }; + yield return new object[] { Data.ConnectionTestParametersList[3] }; + yield return new object[] { Data.ConnectionTestParametersList[4] }; + yield return new object[] { Data.ConnectionTestParametersList[5] }; + yield return new object[] { Data.ConnectionTestParametersList[6] }; + yield return new object[] { Data.ConnectionTestParametersList[7] }; + yield return new object[] { Data.ConnectionTestParametersList[8] }; + yield return new object[] { Data.ConnectionTestParametersList[9] }; + yield return new object[] { Data.ConnectionTestParametersList[10] }; + yield return new object[] { Data.ConnectionTestParametersList[11] }; + yield return new object[] { Data.ConnectionTestParametersList[12] }; + yield return new object[] { Data.ConnectionTestParametersList[13] }; + yield return new object[] { Data.ConnectionTestParametersList[14] }; + yield return new object[] { Data.ConnectionTestParametersList[15] }; + } + + public ConnectionTestParametersData() + { + ConnectionTestParametersList = new List + { + // First batch with TdsEncryptionType = Off + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, + Encrypt = SqlConnectionEncryptOption.Optional, + TrustServerCertificate = false, + Certificate = null, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = false, + Certificate = null, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, + Encrypt = SqlConnectionEncryptOption.Optional, + TrustServerCertificate = true, + Certificate = null, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = true, + Certificate = null, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = false, + Certificate = s_fullPathToCer, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = true, + Certificate = s_fullPathToCer, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = false, + Certificate = null, + HostNameInCertificate = s_hostName, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = true, + Certificate = null, + HostNameInCertificate = s_hostName, + TestResult = true + }, + // Second batch with TdsEncryptionType = On + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, + Encrypt = SqlConnectionEncryptOption.Optional, + TrustServerCertificate = false, + Certificate = null, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = false, + Certificate = null, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, + Encrypt = SqlConnectionEncryptOption.Optional, + TrustServerCertificate = true, + Certificate = null, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = true, + Certificate = null, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = false, + Certificate = s_fullPathToCer, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = true, + Certificate = s_fullPathToCer, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = false, + Certificate = null, + HostNameInCertificate = s_hostName, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = true, + Certificate = null, + HostNameInCertificate = s_hostName, + TestResult = true + }, + }; + } + } +} diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index da3f55dfc1..170ea9588c 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -267,6 +267,8 @@ + + @@ -284,6 +286,7 @@ + @@ -352,6 +355,9 @@ + + Always + Always diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServerTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServerTest.cs new file mode 100644 index 0000000000..ae273188f8 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServerTest.cs @@ -0,0 +1,151 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Data; +using System.Diagnostics; +using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Security.Cryptography.X509Certificates; +using System.Text; +using Microsoft.Data.SqlClient.ManualTesting.Tests.DataCommon; +using Xunit; + +namespace Microsoft.Data.SqlClient.ManualTesting.Tests +{ + public class CertificateTestWithTdsServerTest + { + private static readonly string s_fullPathToPowershellScript = Path.Combine(Directory.GetCurrentDirectory(), "makepfxcert.ps1"); + private static readonly string s_fullPathToPfx = Path.Combine(Directory.GetCurrentDirectory(), "localhostcert.pfx"); + + public CertificateTestWithTdsServerTest() + { + CreatePfxCertificate(s_fullPathToPowershellScript); + } + + [Theory] + [MemberData(nameof(ConnectionTestParametersData.GetConnectionTestParameters), MemberType = typeof(ConnectionTestParametersData))] + public void ConnectionTestTest(ConnectionTestParameters connectionTestParameters) + { + string userId = string.Empty; + string password = string.Empty; + SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString); + userId = builder.UserID; + password = builder.Password; + + using TestTdsServer server = TestTdsServer.StartTestServer(enableFedAuth: false, enableLog: false, connectionTimeout: 15, + methodName: "", new X509Certificate2(s_fullPathToPfx, "nopassword", X509KeyStorageFlags.UserKeySet), + encryptionType: connectionTestParameters.TdsEncryptionType); + + if (userId != string.Empty) + { + builder = new(server.ConnectionString) + { + UserID = userId, + Password = password, + TrustServerCertificate = connectionTestParameters.TrustServerCertificate, + Encrypt = connectionTestParameters.Encrypt, + }; + } + else + { + builder = new(server.ConnectionString) + { + IntegratedSecurity = true, + TrustServerCertificate = connectionTestParameters.TrustServerCertificate, + Encrypt = connectionTestParameters.Encrypt, + }; + } + + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows) && userId == string.Empty) + { + builder.IntegratedSecurity = false; + builder.UserID = "user"; + builder.Password = "password"; + } + + if (connectionTestParameters.Certificate != null) + { + builder.ServerCertificate = connectionTestParameters.Certificate; + } + + if (connectionTestParameters.HostNameInCertificate != null) + { + builder.HostNameInCertificate = connectionTestParameters.HostNameInCertificate; + } + + try + { + using SqlConnection connection = new(builder.ConnectionString); + connection.Open(); + Debug.WriteLine($">>>>>>>>>>>> Connected to {builder.ConnectionString} with encrypt={connectionTestParameters.Encrypt}, trustServerCertificate={connectionTestParameters.TrustServerCertificate} <<<<<<<<<<<<<<<"); + Assert.Equal(connectionTestParameters.TestResult, (connection.State == ConnectionState.Open)); + } + catch (Exception ex) + { + Debug.WriteLine($"{ex.Message} {ex.InnerException?.Message}" ); + Debug.WriteLine($">>>>>>>>>>>> Failed to connect using {builder.ConnectionString} with encrypt={connectionTestParameters.Encrypt}, trustServerCertificate={connectionTestParameters.TrustServerCertificate} <<<<<<<<<<<<<<<"); + } + } + + private static void CreatePfxCertificate(string script) + { + string powerShellCommand = "powershell.exe"; + if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) + { + powerShellCommand = "pwsh"; + } + + if (File.Exists(script)) + { + StringBuilder output = new(); + Process proc = new() + { + StartInfo = + { + FileName = powerShellCommand, + RedirectStandardError = true, + RedirectStandardOutput = true, + UseShellExecute = false, + Arguments = $"{script} > result.txt", + CreateNoWindow = false, + Verb = "runas" + } + }; + + proc.EnableRaisingEvents = true; + + // Use async event handlers to avoid deadlocks + proc.OutputDataReceived += new DataReceivedEventHandler((sender, e) => + { + output.AppendLine(e.Data); + }); + + proc.ErrorDataReceived += new DataReceivedEventHandler((sender, e) => + { + output.AppendLine(e.Data); + }); + + proc.Start(); + + proc.BeginOutputReadLine(); + proc.BeginErrorReadLine(); + + if (!proc.WaitForExit(60000)) + { + proc.Kill(); + // allow async output to process + proc.WaitForExit(2000); + throw new Exception($"Could not generate certificate.Error out put: {output}"); + } + } + else + { + throw new Exception($"Could not find GenerateSelfSignedCertificate.ps1"); + } + } + } +} + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs index 3552204886..e139c8265b 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs @@ -3,27 +3,35 @@ // See the LICENSE file in the project root for more information. using System; +using System.Linq; using System.Net; +using System.Net.Sockets; using System.Runtime.CompilerServices; +using System.Security.Cryptography.X509Certificates; using Microsoft.SqlServer.TDS.EndPoint; +using Microsoft.SqlServer.TDS.PreLogin; using Microsoft.SqlServer.TDS.Servers; namespace Microsoft.Data.SqlClient.ManualTesting.Tests { internal class TestTdsServer : GenericTDSServer, IDisposable { + private const int DefaultConnectionTimeout = 5; + private TDSServerEndPoint _endpoint = null; - private SqlConnectionStringBuilder connectionStringBuilder; + private SqlConnectionStringBuilder _connectionStringBuilder; public TestTdsServer(TDSServerArguments args) : base(args) { } public TestTdsServer(QueryEngine engine, TDSServerArguments args) : base(args) { - this.Engine = engine; + Engine = engine; } - public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool enableFedAuth = false, bool enableLog = false, [CallerMemberName] string methodName = "") + public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool enableFedAuth = false, bool enableLog = false, + int connectionTimeout = DefaultConnectionTimeout, [CallerMemberName] string methodName = "", + X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.Off) { TDSServerArguments args = new TDSServerArguments() { @@ -32,10 +40,18 @@ public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool if (enableFedAuth) { - args.FedAuthRequiredPreLoginOption = Microsoft.SqlServer.TDS.PreLogin.TdsPreLoginFedAuthRequiredOption.FedAuthRequired; + args.FedAuthRequiredPreLoginOption = SqlServer.TDS.PreLogin.TdsPreLoginFedAuthRequiredOption.FedAuthRequired; } + if (encryptionCertificate != null) + { + args.EncryptionCertificate = encryptionCertificate; + } + + args.Encryption = encryptionType; + TestTdsServer server = engine == null ? new TestTdsServer(args) : new TestTdsServer(engine, args); + server._endpoint = new TDSServerEndPoint(server) { ServerEndPoint = new IPEndPoint(IPAddress.Any, 0) }; server._endpoint.EndpointName = methodName; // The server EventLog should be enabled as it logs the exceptions. @@ -43,14 +59,22 @@ public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool server._endpoint.Start(); int port = server._endpoint.ServerEndPoint.Port; - server.connectionStringBuilder = new SqlConnectionStringBuilder() { DataSource = "localhost," + port, ConnectTimeout = 5, Encrypt = SqlConnectionEncryptOption.Optional }; - server.ConnectionString = server.connectionStringBuilder.ConnectionString; + + server._connectionStringBuilder = new SqlConnectionStringBuilder() + { + DataSource = "localhost," + port, + ConnectTimeout = connectionTimeout, + Encrypt = (encryptionType == TDSPreLoginTokenEncryptionType.Off ? SqlConnectionEncryptOption.Optional : SqlConnectionEncryptOption.Mandatory) + }; + server.ConnectionString = server._connectionStringBuilder.ConnectionString; return server; } - public static TestTdsServer StartTestServer(bool enableFedAuth = false, bool enableLog = false, [CallerMemberName] string methodName = "") + public static TestTdsServer StartTestServer(bool enableFedAuth = false, bool enableLog = false, + int connectionTimeout = DefaultConnectionTimeout, [CallerMemberName] string methodName = "", + X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.Off) { - return StartServerWithQueryEngine(null, false, false, methodName); + return StartServerWithQueryEngine(null, enableFedAuth, enableLog, connectionTimeout, methodName, encryptionCertificate, encryptionType); } public void Dispose() => _endpoint?.Stop(); diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 new file mode 100644 index 0000000000..8760d50583 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -0,0 +1,115 @@ +# Licensed to the .NET Foundation under one or more agreements. +# The .NET Foundation licenses this file to you under the MIT license. +# See the LICENSE file in the project root for more information. +# Script: Invoke-SqlServerCertificateCommand# +# Author: SqlClient Team +# Date: March 20, 2024 +# Comments: This scripts creates SQL Server SSL Self-Signed Certificate. +# This script is not intended to be used in production environments. + +function Invoke-SqlServerCertificateCommand { + [CmdletBinding()] + param( + [Parameter(Mandatory = $false)] + [string] $certificateName = ".\localhostcert.cer", + [string] $myCertStoreLocation = "Cert:\LocalMachine\My", + [string] $rootCertStoreLocation = "Cert:\LocalMachine\Root", + [string] $sqlAliasName = "SQLAliasName", + [string] $localhost = "localhost", + [string] $LoopBackIPV4 = "127.0.0.1", + [string] $LoopBackIPV6 = "::1" + ) + Write-Output "Certificate generation started..." + try { + # Get FQDN of the machine + Write-Output "Get FQDN of the machine..." + $fqdn = [System.Net.Dns]::GetHostByName(($env:computerName)).HostName + Write-Output "FQDN = $fqdn..." + + $OS = [System.Environment]::OSVersion.Platform + Write-Output "Operating System is $OS..." + + # Create a self-signed certificate + if ($OS -eq "Unix") { + # Create self signed certificate using openssl + Write-Output "Creating certificate for linux..." + openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout ./localhostcert.key -out ./localhostcert.cer -subj "/CN=$fqdn" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" + # Export the certificate to pfx + Write-Output "Exporting certificate to pfx..." + openssl pkcs12 -export -in ./localhostcert.cer -inkey ./localhostcert.key -out ./localhostcert.pfx -password pass:nopassword + + Write-Output "Converting certificate to pem..." + # Create pem from cer + cp ./localhostcert.cer ./localhostcert.pem + + # Add trust to the pem certificate + Write-Output "Adding trust to pem certificate..." + openssl x509 -trustout -addtrust "serverAuth" -in ./localhostcert.pem + + # Import the certificate to the Root store ------------------------------------------------------------------------------ + # NOTE: The process must have root privileges to add the certificate to the Root store. If not, then use + # "chmod 777 /usr/local/share/ca-certificates" to give read, write and execute privileges to anyone on that folder + # Copy the certificate to /usr/local/share/ca-certificates folder while changing the extension to "crt". + # Only certificates with extension "crt" gets added for some reason. + Write-Output "Copy the pem certificate to /usr/local/share/ca-certificates folder..." + cp ./localhostcert.pem /usr/local/share/ca-certificates/localhostcert.crt + + # Update the certificates store + Write-Output "Updating the certificates store..." + update-ca-certificates -v + } else { + Write-Output "Creating a self-signed certificate..." + $params = @{ + Type = "SSLServerAuthentication" + Subject = "CN=$fqdn" + KeyAlgorithm = "RSA" + KeyLength = 2048 + HashAlgorithm = "SHA256" + TextExtension = "2.5.29.37={text}1.3.6.1.5.5.7.3.1", "2.5.29.17={text}DNS=$fqdn&DNS=$localhost&IPAddress=$LoopBackIPV4&DNS=$sqlAliasName&IPAddress=$LoopBackIPV6" + NotAfter = (Get-Date).AddMonths(36) + KeySpec = "KeyExchange" + Provider = "Microsoft RSA SChannel Cryptographic Provider" + CertStoreLocation = $myCertStoreLocation + FriendlyName = "TestTDSServerCertificate" + } + + $certificate = New-SelfSignedCertificate @params + Write-Output "Certificate created successfully" + Write-Output "Certificate Thumbprint: $($certificate.Thumbprint)" + + # Export the certificate to a file + Write-Output "Exporting the certificate to a file..." + Export-Certificate -Cert $certificate -FilePath "$certificateName" -Type CERT + + # Import the certificate to the Root store + Write-Output "Importing the certificate to the Root store..." + $params = @{ + FilePath = "$certificateName" + CertStoreLocation = $rootCertStoreLocation + } + Import-Certificate @params + + Write-Output "Converting certificate to pfx..." + Write-Output "Cert:\LocalMachine\my\$($certificate.Thumbprint)" + + $pwd = ConvertTo-SecureString -String 'nopassword' -Force -AsPlainText + # Export the certificate to a pfx format + Export-PfxCertificate -Password $pwd -FilePath ".\localhostcert.pfx" -Cert "Cert:\LocalMachine\my\$($certificate.Thumbprint)" + } + + Write-Output "Done creating pfx certificate..." + } + catch { + $e = $_.Exception + $msg = $e.Message + while ($e.InnerException) { + $e = $e.InnerException + $msg += "`n" + $e.Message + } + Write-Output "Certificate generation was not successfull. $msg" + } + + Write-Output "Certificate generation task completed." +} + +Invoke-SqlServerCertificateCommand diff --git a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/TDSServerParser.cs b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/TDSServerParser.cs index 019fefd907..8a95553344 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/TDSServerParser.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/TDSServerParser.cs @@ -69,15 +69,17 @@ public void Run() { case TDSMessageType.PreLogin: { - if (Session.Encryption == TDSEncryptionType.None) + if ((Session.Encryption == TDSEncryptionType.None || Session.Encryption == TDSEncryptionType.Off) && + (MessageBeingReceived[0] as TDSPreLoginToken).Encryption != TDSPreLoginTokenEncryptionType.On) + //if (Session.Encryption == TDSEncryptionType.None) { (MessageBeingReceived[0] as TDSPreLoginToken).Encryption = TDSPreLoginTokenEncryptionType.None; } // Call into the subscriber to process the packet responseMessages = Server.OnPreLoginRequest(Session, MessageBeingReceived); - - if (Session.Encryption == TDSEncryptionType.None) + + if (Session.Encryption == TDSEncryptionType.None || Session.Encryption == TDSEncryptionType.Off) { DisableTransportEncryption(); } diff --git a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs index 94abbf5818..6922530523 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +//using System.Diagnostics; using System.IO; using System.Threading; @@ -264,6 +265,21 @@ public override int Read(byte[] buffer, int offset, int count) // Calculate how much data can be read until the end of the packet is reached long packetDataAvailable = IncomingPacketHeader.Length - IncomingPacketPosition; + // set count to actual size of data to be read from the buffer + if (packetDataAvailable < count) + count = (int)packetDataAvailable; + + //if (packetDataAvailable < count) + //{ + // Debug.WriteLine($"packetDataAvailable is only {packetDataAvailable} bytes but was expecting to get {count} bytes."); + // Debug.WriteLine($"Changing expected data size to {packetDataAvailable} bytes only."); + // count = (int)packetDataAvailable; + //} + //else + //{ + // Debug.WriteLine($"packetDataAvailable is {packetDataAvailable} bytes and expecting to get {count} bytes."); + //} + // Check how much data we should give back in the current iteration int packetDataToRead = Math.Min((int)packetDataAvailable, count - bufferReadPosition); From e8d3e5413944cb7b723188a84c25ee30197e8361 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 25 Mar 2024 09:03:33 -0700 Subject: [PATCH 04/49] Merged latest project files from upstream. --- src/Microsoft.Data.SqlClient.sln | 73 ------------------- .../Microsoft.Data.SqlClient.Tests.csproj | 10 --- ....Data.SqlClient.ManualTesting.Tests.csproj | 16 +--- 3 files changed, 1 insertion(+), 98 deletions(-) diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln index b09409f828..f8f65b8ae2 100644 --- a/src/Microsoft.Data.SqlClient.sln +++ b/src/Microsoft.Data.SqlClient.sln @@ -23,32 +23,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "netcore", "netcore", "{28E5 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "netfx", "netfx", "{3FDD425C-FE01-4B56-863E-1FCDD0677CF5}" EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Address", "Microsoft.Data.SqlClient\tests\ManualTests\SQL\UdtTest\UDTs\Address\Address.csproj", "{D1392B54-998A-4F27-BC17-4CE149117BCC}" - ProjectSection(ProjectDependencies) = postProject - {37431336-5307-4184-9356-C4B7E47DC714} = {37431336-5307-4184-9356-C4B7E47DC714} - {407890AC-9876-4FEF-A6F1-F36A876BAADE} = {407890AC-9876-4FEF-A6F1-F36A876BAADE} - EndProjectSection -EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Data.SqlClient.ManualTesting.Tests", "Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj", "{45DB5F86-7AE3-45C6-870D-F9357B66BDB5}" ProjectSection(ProjectDependencies) = postProject {37431336-5307-4184-9356-C4B7E47DC714} = {37431336-5307-4184-9356-C4B7E47DC714} EndProjectSection EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Circle", "Microsoft.Data.SqlClient\tests\ManualTests\SQL\UdtTest\UDTs\Circle\Circle.csproj", "{6C88F00F-9597-43AD-9E5F-9B344DA3B16F}" - ProjectSection(ProjectDependencies) = postProject - {37431336-5307-4184-9356-C4B7E47DC714} = {37431336-5307-4184-9356-C4B7E47DC714} - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shapes", "Microsoft.Data.SqlClient\tests\ManualTests\SQL\UdtTest\UDTs\Shapes\Shapes.csproj", "{B73A7063-37C3-415D-AD53-BB3DA20ABD6E}" - ProjectSection(ProjectDependencies) = postProject - {37431336-5307-4184-9356-C4B7E47DC714} = {37431336-5307-4184-9356-C4B7E47DC714} - EndProjectSection -EndProject -Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utf8String", "Microsoft.Data.SqlClient\tests\ManualTests\SQL\UdtTest\UDTs\Utf8String\Utf8String.csproj", "{E0A6BB21-574B-43D9-890D-6E1144F2EE9E}" - ProjectSection(ProjectDependencies) = postProject - {37431336-5307-4184-9356-C4B7E47DC714} = {37431336-5307-4184-9356-C4B7E47DC714} - EndProjectSection -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{A2E7E470-5EFF-4828-B55E-FCBA3650F51C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Data.SqlClient", "Microsoft.Data.SqlClient\netcore\ref\Microsoft.Data.SqlClient.csproj", "{1C9FC4B8-54BC-4B6C-BB3A-F5CD59D80A9B}" @@ -282,18 +261,6 @@ Global {37431336-5307-4184-9356-C4B7E47DC714}.Release|x64.Build.0 = Release|Any CPU {37431336-5307-4184-9356-C4B7E47DC714}.Release|x86.ActiveCfg = Release|Any CPU {37431336-5307-4184-9356-C4B7E47DC714}.Release|x86.Build.0 = Release|Any CPU - {D1392B54-998A-4F27-BC17-4CE149117BCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {D1392B54-998A-4F27-BC17-4CE149117BCC}.Debug|Any CPU.Build.0 = Debug|Any CPU - {D1392B54-998A-4F27-BC17-4CE149117BCC}.Debug|x64.ActiveCfg = Debug|Any CPU - {D1392B54-998A-4F27-BC17-4CE149117BCC}.Debug|x64.Build.0 = Debug|Any CPU - {D1392B54-998A-4F27-BC17-4CE149117BCC}.Debug|x86.ActiveCfg = Debug|Any CPU - {D1392B54-998A-4F27-BC17-4CE149117BCC}.Debug|x86.Build.0 = Debug|Any CPU - {D1392B54-998A-4F27-BC17-4CE149117BCC}.Release|Any CPU.ActiveCfg = Release|Any CPU - {D1392B54-998A-4F27-BC17-4CE149117BCC}.Release|Any CPU.Build.0 = Release|Any CPU - {D1392B54-998A-4F27-BC17-4CE149117BCC}.Release|x64.ActiveCfg = Release|Any CPU - {D1392B54-998A-4F27-BC17-4CE149117BCC}.Release|x64.Build.0 = Release|Any CPU - {D1392B54-998A-4F27-BC17-4CE149117BCC}.Release|x86.ActiveCfg = Release|Any CPU - {D1392B54-998A-4F27-BC17-4CE149117BCC}.Release|x86.Build.0 = Release|Any CPU {45DB5F86-7AE3-45C6-870D-F9357B66BDB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {45DB5F86-7AE3-45C6-870D-F9357B66BDB5}.Debug|Any CPU.Build.0 = Debug|Any CPU {45DB5F86-7AE3-45C6-870D-F9357B66BDB5}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -306,42 +273,6 @@ Global {45DB5F86-7AE3-45C6-870D-F9357B66BDB5}.Release|x64.Build.0 = Release|Any CPU {45DB5F86-7AE3-45C6-870D-F9357B66BDB5}.Release|x86.ActiveCfg = Release|Any CPU {45DB5F86-7AE3-45C6-870D-F9357B66BDB5}.Release|x86.Build.0 = Release|Any CPU - {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Debug|Any CPU.Build.0 = Debug|Any CPU - {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Debug|x64.ActiveCfg = Debug|Any CPU - {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Debug|x64.Build.0 = Debug|Any CPU - {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Debug|x86.ActiveCfg = Debug|Any CPU - {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Debug|x86.Build.0 = Debug|Any CPU - {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Release|Any CPU.ActiveCfg = Release|Any CPU - {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Release|Any CPU.Build.0 = Release|Any CPU - {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Release|x64.ActiveCfg = Release|Any CPU - {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Release|x64.Build.0 = Release|Any CPU - {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Release|x86.ActiveCfg = Release|Any CPU - {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Release|x86.Build.0 = Release|Any CPU - {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Debug|x64.ActiveCfg = Debug|Any CPU - {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Debug|x64.Build.0 = Debug|Any CPU - {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Debug|x86.ActiveCfg = Debug|Any CPU - {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Debug|x86.Build.0 = Debug|Any CPU - {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Release|Any CPU.Build.0 = Release|Any CPU - {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Release|x64.ActiveCfg = Release|Any CPU - {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Release|x64.Build.0 = Release|Any CPU - {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Release|x86.ActiveCfg = Release|Any CPU - {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Release|x86.Build.0 = Release|Any CPU - {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU - {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Debug|Any CPU.Build.0 = Debug|Any CPU - {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Debug|x64.ActiveCfg = Debug|Any CPU - {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Debug|x64.Build.0 = Debug|Any CPU - {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Debug|x86.ActiveCfg = Debug|Any CPU - {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Debug|x86.Build.0 = Debug|Any CPU - {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Release|Any CPU.ActiveCfg = Release|Any CPU - {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Release|Any CPU.Build.0 = Release|Any CPU - {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Release|x64.ActiveCfg = Release|Any CPU - {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Release|x64.Build.0 = Release|Any CPU - {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Release|x86.ActiveCfg = Release|Any CPU - {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Release|x86.Build.0 = Release|Any CPU {1C9FC4B8-54BC-4B6C-BB3A-F5CD59D80A9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1C9FC4B8-54BC-4B6C-BB3A-F5CD59D80A9B}.Debug|Any CPU.Build.0 = Debug|Any CPU {1C9FC4B8-54BC-4B6C-BB3A-F5CD59D80A9B}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -483,11 +414,7 @@ Global {8DC9D1A0-351B-47BC-A90F-B9DA542550E9} = {0CC4817A-12F3-4357-912C-09315FAAD008} {D2D1E2D1-B6E0-489F-A36D-1F3047AB87B9} = {0CC4817A-12F3-4357-912C-09315FAAD008} {37431336-5307-4184-9356-C4B7E47DC714} = {28E5EFE6-C9DD-4FF9-9FEC-532F72DFFA6E} - {D1392B54-998A-4F27-BC17-4CE149117BCC} = {0CC4817A-12F3-4357-912C-09315FAAD008} {45DB5F86-7AE3-45C6-870D-F9357B66BDB5} = {0CC4817A-12F3-4357-912C-09315FAAD008} - {6C88F00F-9597-43AD-9E5F-9B344DA3B16F} = {0CC4817A-12F3-4357-912C-09315FAAD008} - {B73A7063-37C3-415D-AD53-BB3DA20ABD6E} = {0CC4817A-12F3-4357-912C-09315FAAD008} - {E0A6BB21-574B-43D9-890D-6E1144F2EE9E} = {0CC4817A-12F3-4357-912C-09315FAAD008} {A2E7E470-5EFF-4828-B55E-FCBA3650F51C} = {28E5EFE6-C9DD-4FF9-9FEC-532F72DFFA6E} {1C9FC4B8-54BC-4B6C-BB3A-F5CD59D80A9B} = {A2E7E470-5EFF-4828-B55E-FCBA3650F51C} {771F3F1E-7A68-4A9D-ADA8-A24F1D5BE71D} = {3FDD425C-FE01-4B56-863E-1FCDD0677CF5} diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index 02e84e4343..a8bde637a5 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -102,9 +102,6 @@ - - Address - TDS.Servers @@ -120,9 +117,6 @@ - - - @@ -133,9 +127,5 @@ PreserveNewest xunit.runner.json - - - PreserveNewest - diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index 170ea9588c..d54747180e 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -163,6 +163,7 @@ + @@ -292,18 +293,6 @@ - - Address - - - Circle - - - Shapes - - - Utf8String - @@ -335,17 +324,14 @@ - - - From cf5739cbb4d82c774d990b5ecce96faeae9e234c Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 25 Mar 2024 09:22:26 -0700 Subject: [PATCH 05/49] Fixed project files. --- .../Microsoft.Data.SqlClient.Tests.csproj | 3 +++ ...crosoft.Data.SqlClient.ManualTesting.Tests.csproj | 12 ++++++++++++ 2 files changed, 15 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj index a8bde637a5..7724f4c58e 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/Microsoft.Data.SqlClient.Tests.csproj @@ -102,6 +102,9 @@ + + Address + TDS.Servers diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index d54747180e..7525d7d91c 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -293,6 +293,18 @@ + + Address + + + Circle + + + Shapes + + + Utf8String + From 267acdd3437f3f5f42de24305a7c338e0c4a50fe Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 27 Mar 2024 11:12:32 -0700 Subject: [PATCH 06/49] Fix script for linux to install openssl first. --- ...Microsoft.Data.SqlClient.ManualTesting.Tests.csproj | 2 +- ...dsServerTest.cs => CertificateTestWithTdsServer.cs} | 6 +++--- .../tests/ManualTests/makepfxcert.ps1 | 10 ++++++++++ 3 files changed, 14 insertions(+), 4 deletions(-) rename src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/{CertificateTestWithTdsServerTest.cs => CertificateTestWithTdsServer.cs} (96%) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index 7525d7d91c..231f354ac2 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -287,7 +287,7 @@ - + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServerTest.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs similarity index 96% rename from src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServerTest.cs rename to src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs index ae273188f8..a1da664f96 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServerTest.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs @@ -15,19 +15,19 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests { - public class CertificateTestWithTdsServerTest + public class CertificateTestWithTdsServer { private static readonly string s_fullPathToPowershellScript = Path.Combine(Directory.GetCurrentDirectory(), "makepfxcert.ps1"); private static readonly string s_fullPathToPfx = Path.Combine(Directory.GetCurrentDirectory(), "localhostcert.pfx"); - public CertificateTestWithTdsServerTest() + public CertificateTestWithTdsServer() { CreatePfxCertificate(s_fullPathToPowershellScript); } [Theory] [MemberData(nameof(ConnectionTestParametersData.GetConnectionTestParameters), MemberType = typeof(ConnectionTestParametersData))] - public void ConnectionTestTest(ConnectionTestParameters connectionTestParameters) + public void ConnectionTest(ConnectionTestParameters connectionTestParameters) { string userId = string.Empty; string password = string.Empty; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index 8760d50583..dacf0a30a7 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -31,6 +31,11 @@ function Invoke-SqlServerCertificateCommand { # Create a self-signed certificate if ($OS -eq "Unix") { + # Install OpenSSL module + Install-Module -Name OpenSSL + # Show version of OpenSSL just to make sure it is installed + openssl --version + # Create self signed certificate using openssl Write-Output "Creating certificate for linux..." openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout ./localhostcert.key -out ./localhostcert.cer -subj "/CN=$fqdn" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" @@ -106,6 +111,11 @@ function Invoke-SqlServerCertificateCommand { $e = $e.InnerException $msg += "`n" + $e.Message } + + if ($OS -eq "Unix") { + # Display the contents of result.txt for debugging + cat result.txt + } Write-Output "Certificate generation was not successfull. $msg" } From af9a1ff30ab3437bc9b217917410c0eb2c269d3a Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 27 Mar 2024 12:11:31 -0700 Subject: [PATCH 07/49] Add force installation of openssl from PSGallery. --- src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index dacf0a30a7..2b660c51b0 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -32,7 +32,7 @@ function Invoke-SqlServerCertificateCommand { # Create a self-signed certificate if ($OS -eq "Unix") { # Install OpenSSL module - Install-Module -Name OpenSSL + Install-Module -Name OpenSSL -Repository PSGallery -Force # Show version of OpenSSL just to make sure it is installed openssl --version From 3c682cc4e16ec936a594e274130d3a87c6757c1d Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 27 Mar 2024 12:29:20 -0700 Subject: [PATCH 08/49] Removed OpenSsl installation. --- .../tests/ManualTests/makepfxcert.ps1 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index 2b660c51b0..483dadeb85 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -31,11 +31,6 @@ function Invoke-SqlServerCertificateCommand { # Create a self-signed certificate if ($OS -eq "Unix") { - # Install OpenSSL module - Install-Module -Name OpenSSL -Repository PSGallery -Force - # Show version of OpenSSL just to make sure it is installed - openssl --version - # Create self signed certificate using openssl Write-Output "Creating certificate for linux..." openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout ./localhostcert.key -out ./localhostcert.cer -subj "/CN=$fqdn" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" From 45ad5f8e3b0349ad2544728f444490114197971b Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 27 Mar 2024 13:18:01 -0700 Subject: [PATCH 09/49] Add 1 second delay for the certificate to be created. --- .../CertificateTestWithTdsServer.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs index a1da664f96..24bf331d16 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs @@ -140,6 +140,12 @@ private static void CreatePfxCertificate(string script) proc.WaitForExit(2000); throw new Exception($"Could not generate certificate.Error out put: {output}"); } + + System.Threading.Thread.Sleep(1000); + if (!File.Exists(s_fullPathToPfx)) + { + System.Threading.Thread.Sleep(1000); + } } else { From 35222002f5e5a1d3407019aeb6f72587af31c87d Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 27 Mar 2024 14:59:23 -0700 Subject: [PATCH 10/49] Add debug to display certificate location. --- .../ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs index 24bf331d16..46265a84f6 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs @@ -29,6 +29,9 @@ public CertificateTestWithTdsServer() [MemberData(nameof(ConnectionTestParametersData.GetConnectionTestParameters), MemberType = typeof(ConnectionTestParametersData))] public void ConnectionTest(ConnectionTestParameters connectionTestParameters) { + + Debug.WriteLine($"Certificate is at {s_fullPathToPfx}"); + string userId = string.Empty; string password = string.Empty; SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString); From 78f75e4ed41776bc450e03b7a9897fadf38f419c Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 27 Mar 2024 15:26:59 -0700 Subject: [PATCH 11/49] Add print working directory to script. --- .../tests/ManualTests/makepfxcert.ps1 | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index 483dadeb85..5d681ab45d 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -31,6 +31,13 @@ function Invoke-SqlServerCertificateCommand { # Create a self-signed certificate if ($OS -eq "Unix") { + # Where is this executing, print working directory + Write-Output "print working directory..." + pwd + # What folder is this executing in, list the contents + Write-Output "list the contents of working directory..." + ls -l + # Create self signed certificate using openssl Write-Output "Creating certificate for linux..." openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout ./localhostcert.key -out ./localhostcert.cer -subj "/CN=$fqdn" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" From 9d417da074c98182d6de264b0b2f1d2ee91b2d82 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 27 Mar 2024 15:45:24 -0700 Subject: [PATCH 12/49] Add cat to display content of result.txt. --- src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index 5d681ab45d..a4b393ad12 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -114,11 +114,11 @@ function Invoke-SqlServerCertificateCommand { $msg += "`n" + $e.Message } + Write-Output "Certificate generation was not successfull. $msg" if ($OS -eq "Unix") { # Display the contents of result.txt for debugging cat result.txt } - Write-Output "Certificate generation was not successfull. $msg" } Write-Output "Certificate generation task completed." From 60768f09b3e5e7922409d0a35938e7f017faf9d3 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 27 Mar 2024 16:05:39 -0700 Subject: [PATCH 13/49] Add parameter for the location of certificate. --- .../CertificateTestWithTdsServer.cs | 2 +- .../tests/ManualTests/makepfxcert.ps1 | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs index 46265a84f6..ed1bf0a7af 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs @@ -112,7 +112,7 @@ private static void CreatePfxCertificate(string script) RedirectStandardError = true, RedirectStandardOutput = true, UseShellExecute = false, - Arguments = $"{script} > result.txt", + Arguments = $"{script} -OutDir {Directory.GetCurrentDirectory()}> result.txt", CreateNoWindow = false, Verb = "runas" } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index a4b393ad12..96b1be4bcb 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -7,11 +7,13 @@ # Comments: This scripts creates SQL Server SSL Self-Signed Certificate. # This script is not intended to be used in production environments. +param ($OutDir) + function Invoke-SqlServerCertificateCommand { [CmdletBinding()] param( [Parameter(Mandatory = $false)] - [string] $certificateName = ".\localhostcert.cer", + [string] $certificateName = "$OutDir\localhostcert.cer", [string] $myCertStoreLocation = "Cert:\LocalMachine\My", [string] $rootCertStoreLocation = "Cert:\LocalMachine\Root", [string] $sqlAliasName = "SQLAliasName", @@ -40,18 +42,18 @@ function Invoke-SqlServerCertificateCommand { # Create self signed certificate using openssl Write-Output "Creating certificate for linux..." - openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout ./localhostcert.key -out ./localhostcert.cer -subj "/CN=$fqdn" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" + openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout $OutDir/localhostcert.key -out $OutDir/localhostcert.cer -subj "/CN=$fqdn" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" # Export the certificate to pfx Write-Output "Exporting certificate to pfx..." - openssl pkcs12 -export -in ./localhostcert.cer -inkey ./localhostcert.key -out ./localhostcert.pfx -password pass:nopassword + openssl pkcs12 -export -in $OutDir/localhostcert.cer -inkey $OutDir/localhostcert.key -out $OutDir/localhostcert.pfx -password pass:nopassword Write-Output "Converting certificate to pem..." # Create pem from cer - cp ./localhostcert.cer ./localhostcert.pem + cp $OutDir/localhostcert.cer $OutDir/localhostcert.pem # Add trust to the pem certificate Write-Output "Adding trust to pem certificate..." - openssl x509 -trustout -addtrust "serverAuth" -in ./localhostcert.pem + openssl x509 -trustout -addtrust "serverAuth" -in $OutDir/localhostcert.pem # Import the certificate to the Root store ------------------------------------------------------------------------------ # NOTE: The process must have root privileges to add the certificate to the Root store. If not, then use @@ -59,7 +61,7 @@ function Invoke-SqlServerCertificateCommand { # Copy the certificate to /usr/local/share/ca-certificates folder while changing the extension to "crt". # Only certificates with extension "crt" gets added for some reason. Write-Output "Copy the pem certificate to /usr/local/share/ca-certificates folder..." - cp ./localhostcert.pem /usr/local/share/ca-certificates/localhostcert.crt + cp $OutDir/localhostcert.pem /usr/local/share/ca-certificates/localhostcert.crt # Update the certificates store Write-Output "Updating the certificates store..." @@ -101,7 +103,7 @@ function Invoke-SqlServerCertificateCommand { $pwd = ConvertTo-SecureString -String 'nopassword' -Force -AsPlainText # Export the certificate to a pfx format - Export-PfxCertificate -Password $pwd -FilePath ".\localhostcert.pfx" -Cert "Cert:\LocalMachine\my\$($certificate.Thumbprint)" + Export-PfxCertificate -Password $pwd -FilePath "$OutDir\localhostcert.pfx" -Cert "Cert:\LocalMachine\my\$($certificate.Thumbprint)" } Write-Output "Done creating pfx certificate..." From 7136a3358e16cfce2d0ccd06482bb4417dd91219 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 27 Mar 2024 17:47:19 -0700 Subject: [PATCH 14/49] Fix script parameters. --- .../CertificateTestWithTdsServer.cs | 3 ++- .../tests/ManualTests/makepfxcert.ps1 | 12 +++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs index ed1bf0a7af..4a3663f224 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs @@ -95,6 +95,7 @@ public void ConnectionTest(ConnectionTestParameters connectionTestParameters) private static void CreatePfxCertificate(string script) { + string currentDirectory = Directory.GetCurrentDirectory(); string powerShellCommand = "powershell.exe"; if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -112,7 +113,7 @@ private static void CreatePfxCertificate(string script) RedirectStandardError = true, RedirectStandardOutput = true, UseShellExecute = false, - Arguments = $"{script} -OutDir {Directory.GetCurrentDirectory()}> result.txt", + Arguments = $"{script} -OutDir {currentDirectory} > result.txt", CreateNoWindow = false, Verb = "runas" } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index 96b1be4bcb..20bf02d3f8 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -13,7 +13,7 @@ function Invoke-SqlServerCertificateCommand { [CmdletBinding()] param( [Parameter(Mandatory = $false)] - [string] $certificateName = "$OutDir\localhostcert.cer", + [string] $certificateName = "localhostcert.cer", [string] $myCertStoreLocation = "Cert:\LocalMachine\My", [string] $rootCertStoreLocation = "Cert:\LocalMachine\Root", [string] $sqlAliasName = "SQLAliasName", @@ -22,6 +22,12 @@ function Invoke-SqlServerCertificateCommand { [string] $LoopBackIPV6 = "::1" ) Write-Output "Certificate generation started..." + + # Change directory to where the tests are + Write-Output "Change directory to $OutDir ..." + cd $OutDir + pwd + try { # Get FQDN of the machine Write-Output "Get FQDN of the machine..." @@ -88,12 +94,12 @@ function Invoke-SqlServerCertificateCommand { # Export the certificate to a file Write-Output "Exporting the certificate to a file..." - Export-Certificate -Cert $certificate -FilePath "$certificateName" -Type CERT + Export-Certificate -Cert $certificate -FilePath "$OutDir/$certificateName" -Type CERT # Import the certificate to the Root store Write-Output "Importing the certificate to the Root store..." $params = @{ - FilePath = "$certificateName" + FilePath = "$OutDir/$certificateName" CertStoreLocation = $rootCertStoreLocation } Import-Certificate @params From d7423ed2e27aa268ad04388a0e694e858b538568 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 1 Apr 2024 11:01:52 -0700 Subject: [PATCH 15/49] Fix script so that if FQDN is over 64 characters then don't use it as CN in certificate. --- .../tests/ManualTests/makepfxcert.ps1 | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index 20bf02d3f8..6cfb8307fc 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -48,7 +48,12 @@ function Invoke-SqlServerCertificateCommand { # Create self signed certificate using openssl Write-Output "Creating certificate for linux..." - openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout $OutDir/localhostcert.key -out $OutDir/localhostcert.cer -subj "/CN=$fqdn" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" + if ($fqdn.length -gt 64) { + openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout $OutDir/localhostcert.key -out $OutDir/localhostcert.cer -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" + } + else { + openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout $OutDir/localhostcert.key -out $OutDir/localhostcert.cer -subj "/CN=$fqdn" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" + } # Export the certificate to pfx Write-Output "Exporting certificate to pfx..." openssl pkcs12 -export -in $OutDir/localhostcert.cer -inkey $OutDir/localhostcert.key -out $OutDir/localhostcert.pfx -password pass:nopassword From 07a2332697331d0ec91a09ebb9d8b3a3e540a878 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 1 Apr 2024 11:52:28 -0700 Subject: [PATCH 16/49] Without specifiying CN, the openssl command becomes interactive. Thus, use hostname as CN in certificate instead. --- .../tests/ManualTests/makepfxcert.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index 6cfb8307fc..cdf229eae8 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -48,8 +48,9 @@ function Invoke-SqlServerCertificateCommand { # Create self signed certificate using openssl Write-Output "Creating certificate for linux..." - if ($fqdn.length -gt 64) { - openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout $OutDir/localhostcert.key -out $OutDir/localhostcert.cer -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" + if ($fqdn.length -gt 1) { + $machineId = $fqdn.Substring(0,15) + openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout $OutDir/localhostcert.key -out $OutDir/localhostcert.cer -subj "/CN=$machineId" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" } else { openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout $OutDir/localhostcert.key -out $OutDir/localhostcert.cer -subj "/CN=$fqdn" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" From aa13fb196055acb9ce41ca01543ac12a9a7277c0 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 1 Apr 2024 11:55:33 -0700 Subject: [PATCH 17/49] Fix string length test to -gt 64. --- src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index cdf229eae8..2b3a33890f 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -48,7 +48,7 @@ function Invoke-SqlServerCertificateCommand { # Create self signed certificate using openssl Write-Output "Creating certificate for linux..." - if ($fqdn.length -gt 1) { + if ($fqdn.length -gt 64) { $machineId = $fqdn.Substring(0,15) openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout $OutDir/localhostcert.key -out $OutDir/localhostcert.cer -subj "/CN=$machineId" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" } From 4369b9eac5464283c446c4f6b0e810a4d3bdff3d Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 1 Apr 2024 12:13:07 -0700 Subject: [PATCH 18/49] Add the installation of openssl for linux. --- .../tests/ManualTests/makepfxcert.ps1 | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index 2b3a33890f..42a3e07eb0 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -39,6 +39,11 @@ function Invoke-SqlServerCertificateCommand { # Create a self-signed certificate if ($OS -eq "Unix") { + # Install OpenSSL module + Install-Module -Name OpenSSL -Repository PSGallery -Force + # Show version of OpenSSL just to make sure it is installed + openssl version + # Where is this executing, print working directory Write-Output "print working directory..." pwd From 1c3982313960cc3c092ab308b342d119ebb20afd Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 1 Apr 2024 15:30:34 -0700 Subject: [PATCH 19/49] Clean-up unwanted comments from scripts and unit test. --- .../ConnectionTestParametersData.cs | 3 --- .../CertificateTestWithTdsServer.cs | 26 +++++-------------- .../tests/ManualTests/makepfxcert.ps1 | 15 ++--------- .../tests/tools/TDS/TDS/TDSStream.cs | 13 +--------- 4 files changed, 9 insertions(+), 48 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs index f57f05c852..db8349cfa1 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs @@ -13,7 +13,6 @@ public class ConnectionTestParametersData { private static readonly string s_fullPathToCer = Path.Combine(Directory.GetCurrentDirectory(), "localhostcert.cer"); private static string s_hostName = System.Net.Dns.GetHostName(); - public static ConnectionTestParametersData Data { get; } = new ConnectionTestParametersData(); public List ConnectionTestParametersList { get; set; } @@ -41,7 +40,6 @@ public ConnectionTestParametersData() { ConnectionTestParametersList = new List { - // First batch with TdsEncryptionType = Off new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -114,7 +112,6 @@ public ConnectionTestParametersData() HostNameInCertificate = s_hostName, TestResult = true }, - // Second batch with TdsEncryptionType = On new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs index 4a3663f224..6c8e439877 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs @@ -29,9 +29,6 @@ public CertificateTestWithTdsServer() [MemberData(nameof(ConnectionTestParametersData.GetConnectionTestParameters), MemberType = typeof(ConnectionTestParametersData))] public void ConnectionTest(ConnectionTestParameters connectionTestParameters) { - - Debug.WriteLine($"Certificate is at {s_fullPathToPfx}"); - string userId = string.Empty; string password = string.Empty; SqlConnectionStringBuilder builder = new(DataTestUtility.TCPConnectionString); @@ -79,23 +76,14 @@ public void ConnectionTest(ConnectionTestParameters connectionTestParameters) builder.HostNameInCertificate = connectionTestParameters.HostNameInCertificate; } - try - { - using SqlConnection connection = new(builder.ConnectionString); - connection.Open(); - Debug.WriteLine($">>>>>>>>>>>> Connected to {builder.ConnectionString} with encrypt={connectionTestParameters.Encrypt}, trustServerCertificate={connectionTestParameters.TrustServerCertificate} <<<<<<<<<<<<<<<"); - Assert.Equal(connectionTestParameters.TestResult, (connection.State == ConnectionState.Open)); - } - catch (Exception ex) - { - Debug.WriteLine($"{ex.Message} {ex.InnerException?.Message}" ); - Debug.WriteLine($">>>>>>>>>>>> Failed to connect using {builder.ConnectionString} with encrypt={connectionTestParameters.Encrypt}, trustServerCertificate={connectionTestParameters.TrustServerCertificate} <<<<<<<<<<<<<<<"); - } + using SqlConnection connection = new(builder.ConnectionString); + connection.Open(); + Assert.Equal(connectionTestParameters.TestResult, (connection.State == ConnectionState.Open)); } private static void CreatePfxCertificate(string script) { - string currentDirectory = Directory.GetCurrentDirectory(); + string currentDirectory = Directory.GetCurrentDirectory(); string powerShellCommand = "powershell.exe"; if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) { @@ -121,7 +109,6 @@ private static void CreatePfxCertificate(string script) proc.EnableRaisingEvents = true; - // Use async event handlers to avoid deadlocks proc.OutputDataReceived += new DataReceivedEventHandler((sender, e) => { output.AppendLine(e.Data); @@ -140,15 +127,14 @@ private static void CreatePfxCertificate(string script) if (!proc.WaitForExit(60000)) { proc.Kill(); - // allow async output to process proc.WaitForExit(2000); throw new Exception($"Could not generate certificate.Error out put: {output}"); } System.Threading.Thread.Sleep(1000); - if (!File.Exists(s_fullPathToPfx)) + if (!File.Exists(s_fullPathToPfx)) { - System.Threading.Thread.Sleep(1000); + System.Threading.Thread.Sleep(1000); } } else diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index 42a3e07eb0..ee0a87e33f 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -32,10 +32,10 @@ function Invoke-SqlServerCertificateCommand { # Get FQDN of the machine Write-Output "Get FQDN of the machine..." $fqdn = [System.Net.Dns]::GetHostByName(($env:computerName)).HostName - Write-Output "FQDN = $fqdn..." + Write-Output "FQDN = $fqdn" $OS = [System.Environment]::OSVersion.Platform - Write-Output "Operating System is $OS..." + Write-Output "Operating System is $OS" # Create a self-signed certificate if ($OS -eq "Unix") { @@ -44,13 +44,6 @@ function Invoke-SqlServerCertificateCommand { # Show version of OpenSSL just to make sure it is installed openssl version - # Where is this executing, print working directory - Write-Output "print working directory..." - pwd - # What folder is this executing in, list the contents - Write-Output "list the contents of working directory..." - ls -l - # Create self signed certificate using openssl Write-Output "Creating certificate for linux..." if ($fqdn.length -gt 64) { @@ -134,10 +127,6 @@ function Invoke-SqlServerCertificateCommand { } Write-Output "Certificate generation was not successfull. $msg" - if ($OS -eq "Unix") { - # Display the contents of result.txt for debugging - cat result.txt - } } Write-Output "Certificate generation task completed." diff --git a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs index 6922530523..8a20a10cae 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs @@ -265,21 +265,10 @@ public override int Read(byte[] buffer, int offset, int count) // Calculate how much data can be read until the end of the packet is reached long packetDataAvailable = IncomingPacketHeader.Length - IncomingPacketPosition; - // set count to actual size of data to be read from the buffer + // Set count to actual size of data to be read from the buffer so this loop can exit if (packetDataAvailable < count) count = (int)packetDataAvailable; - //if (packetDataAvailable < count) - //{ - // Debug.WriteLine($"packetDataAvailable is only {packetDataAvailable} bytes but was expecting to get {count} bytes."); - // Debug.WriteLine($"Changing expected data size to {packetDataAvailable} bytes only."); - // count = (int)packetDataAvailable; - //} - //else - //{ - // Debug.WriteLine($"packetDataAvailable is {packetDataAvailable} bytes and expecting to get {count} bytes."); - //} - // Check how much data we should give back in the current iteration int packetDataToRead = Math.Min((int)packetDataAvailable, count - bufferReadPosition); From aa0dfc23ab4565d4b1e8ef9fbe0f006ed39b9f27 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 1 Apr 2024 16:29:38 -0700 Subject: [PATCH 20/49] Removed unnecessary using. --- .../ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs | 1 - src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs index 6c8e439877..8cf6dd0e5d 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs @@ -6,7 +6,6 @@ using System.Data; using System.Diagnostics; using System.IO; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; using System.Text; diff --git a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs index 8a20a10cae..80d8633501 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS/TDSStream.cs @@ -3,7 +3,6 @@ // See the LICENSE file in the project root for more information. using System; -//using System.Diagnostics; using System.IO; using System.Threading; From 2a4d8311f5445571b35e46e1e069afd78559f452 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Tue, 2 Apr 2024 13:26:08 -0700 Subject: [PATCH 21/49] Added byte array comparer function. Added mismatched certificate tests. --- .../Microsoft/Data/SqlClient/SNI/SNICommon.cs | 47 ++++++++++++++---- .../ConnectionTestParametersData.cs | 42 ++++++++++++++++ ....Data.SqlClient.ManualTesting.Tests.csproj | 3 ++ .../CertificateTestWithTdsServer.cs | 11 +++- .../tests/ManualTests/makepfxcert.ps1 | 7 ++- .../tests/ManualTests/mismatchedcert.cer | Bin 0 -> 919 bytes 6 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/tests/ManualTests/mismatchedcert.cer diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs index b2f37807b8..660199bf00 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs @@ -9,11 +9,10 @@ using System.Net.Security; using System.Security.Cryptography.X509Certificates; using System.Text; -using Microsoft.Data.Common; using System.Threading; using System.Threading.Tasks; +using Microsoft.Data.Common; using Microsoft.Data.ProviderBase; -using System.Linq; namespace Microsoft.Data.SqlClient.SNI { @@ -186,7 +185,7 @@ internal static bool ValidateSslServerCertificate(Guid connectionId, string targ if (validationCertificate != null) { - if (serverCert.GetRawCertData().SequenceEqual(validationCertificate.GetRawCertData())) + if (ByteArrayCompare(serverCert.GetRawCertData(), validationCertificate.GetRawCertData())) { SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "Connection Id {0}, ServerCertificate matches the certificate provided by the server. Certificate validation passed.", args0: connectionId); return true; @@ -234,12 +233,12 @@ internal static bool ValidateSslServerCertificate(Guid connectionId, string targ if (policyErrors.HasFlag(SslPolicyErrors.RemoteCertificateNameMismatch)) { #if NET7_0_OR_GREATER - X509Certificate2 cert2 = serverCert as X509Certificate2; - if (!cert2.MatchesHostname(serverNameToValidate)) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, serverNameToValidate {1}, Target Server name or HNIC does not match the Subject/SAN in Certificate.", args0: connectionId, args1: serverNameToValidate); - messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); - } + X509Certificate2 cert2 = serverCert as X509Certificate2; + if (!cert2.MatchesHostname(serverNameToValidate)) + { + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.ERR, "Connection Id {0}, serverNameToValidate {1}, Target Server name or HNIC does not match the Subject/SAN in Certificate.", args0: connectionId, args1: serverNameToValidate); + messageBuilder.AppendLine(Strings.SQL_RemoteCertificateNameMismatch); + } #else // To Do: include certificate SAN (Subject Alternative Name) check. string certServerName = serverCert.Subject.Substring(serverCert.Subject.IndexOf('=') + 1); @@ -356,5 +355,35 @@ internal static uint ReportSNIError(SNIError error) SNILoadHandle.SingletonInstance.LastError = error; return TdsEnums.SNI_ERROR; } + + internal static unsafe bool ByteArrayCompare(byte[] original, byte[] variant) + { + unchecked + { + if (original == variant) + return true; + + if (original == null || variant == null || original.Length != variant.Length) + return false; + + fixed (byte* originalStartPosition = original, variantStartPosition = variant) + { + byte* originalCurrentPosition = originalStartPosition, variantCurrentPosition = variantStartPosition; + int originalLength = original.Length; + for (int i = 0; i < originalLength / 8; i++, originalCurrentPosition += 8, variantCurrentPosition += 8) + if (*((long*)originalCurrentPosition) != *((long*)variantCurrentPosition)) + return false; + if ((originalLength & 4) != 0) + { if (*((int*)originalCurrentPosition) != *((int*)variantCurrentPosition)) return false; originalCurrentPosition += 4; variantCurrentPosition += 4; } + if ((originalLength & 2) != 0) + { if (*((short*)originalCurrentPosition) != *((short*)variantCurrentPosition)) return false; originalCurrentPosition += 2; variantCurrentPosition += 2; } + if ((originalLength & 1) != 0) + if (*((byte*)originalCurrentPosition) != *((byte*)variantCurrentPosition)) + return false; + return true; + } + } + } + } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs index db8349cfa1..d13453af5f 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs @@ -12,6 +12,8 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests.DataCommon public class ConnectionTestParametersData { private static readonly string s_fullPathToCer = Path.Combine(Directory.GetCurrentDirectory(), "localhostcert.cer"); + private static readonly string s_mismatchedcert = Path.Combine(Directory.GetCurrentDirectory(), "mismatchedcert.cer"); + private static string s_hostName = System.Net.Dns.GetHostName(); public static ConnectionTestParametersData Data { get; } = new ConnectionTestParametersData(); public List ConnectionTestParametersList { get; set; } @@ -34,6 +36,10 @@ public static IEnumerable GetConnectionTestParameters() yield return new object[] { Data.ConnectionTestParametersList[13] }; yield return new object[] { Data.ConnectionTestParametersList[14] }; yield return new object[] { Data.ConnectionTestParametersList[15] }; + yield return new object[] { Data.ConnectionTestParametersList[16] }; + yield return new object[] { Data.ConnectionTestParametersList[17] }; + yield return new object[] { Data.ConnectionTestParametersList[18] }; + yield return new object[] { Data.ConnectionTestParametersList[19] }; } public ConnectionTestParametersData() @@ -184,6 +190,42 @@ public ConnectionTestParametersData() HostNameInCertificate = s_hostName, TestResult = true }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = false, + Certificate = s_mismatchedcert, + HostNameInCertificate = null, + TestResult = false, + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = true, + Certificate = s_mismatchedcert, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = false, + Certificate = s_mismatchedcert, + HostNameInCertificate = null, + TestResult = false, + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = true, + Certificate = s_mismatchedcert, + HostNameInCertificate = null, + TestResult = true + }, }; } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index 231f354ac2..67116e91da 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -356,6 +356,9 @@ Always + + Always + Always diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs index 8cf6dd0e5d..ad959c0d43 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs @@ -76,8 +76,15 @@ public void ConnectionTest(ConnectionTestParameters connectionTestParameters) } using SqlConnection connection = new(builder.ConnectionString); - connection.Open(); - Assert.Equal(connectionTestParameters.TestResult, (connection.State == ConnectionState.Open)); + try + { + connection.Open(); + Assert.Equal(connectionTestParameters.TestResult, (connection.State == ConnectionState.Open)); + } + catch(Exception) + { + Assert.False(connectionTestParameters.TestResult); + } } private static void CreatePfxCertificate(string script) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index ee0a87e33f..911affc9db 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -64,7 +64,7 @@ function Invoke-SqlServerCertificateCommand { # Add trust to the pem certificate Write-Output "Adding trust to pem certificate..." openssl x509 -trustout -addtrust "serverAuth" -in $OutDir/localhostcert.pem - + # Import the certificate to the Root store ------------------------------------------------------------------------------ # NOTE: The process must have root privileges to add the certificate to the Root store. If not, then use # "chmod 777 /usr/local/share/ca-certificates" to give read, write and execute privileges to anyone on that folder @@ -73,6 +73,11 @@ function Invoke-SqlServerCertificateCommand { Write-Output "Copy the pem certificate to /usr/local/share/ca-certificates folder..." cp $OutDir/localhostcert.pem /usr/local/share/ca-certificates/localhostcert.crt + # Add trust to the mismatched certificate as well + $ openssl x509 -in $OutDir/mismatchedcert.cer -inform der -out $OutDir/mismatchedcert.pem + openssl x509 -trustout -addtrust "serverAuth" -in $OutDir/mismatchedcert.pem + cp $OutDir/mismatchedcert.pem /usr/local/share/ca-certificates/mismatchedcert.crt + # Update the certificates store Write-Output "Updating the certificates store..." update-ca-certificates -v diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/mismatchedcert.cer b/src/Microsoft.Data.SqlClient/tests/ManualTests/mismatchedcert.cer new file mode 100644 index 0000000000000000000000000000000000000000..6b35e97a5534ea4c218c4df7c8874906248ae967 GIT binary patch literal 919 zcmXqLVxDZ!#8kb2nTe5!Ngy^P*GyUZ-a7B}EvW(eTUiWv**LY@JlekVGBR?rG8h;d z>Ko{?F^94+^Qak_8JJiZrx;jRS)`h$SfwT#SQ(m_8e18r7@1flCmUN>85@~f7|4n9 z8kqn!8X6cFTN)We0lB6St|^F1j*(4_O2`glWMyD(V&rEqXkz4IYGPz$SbOK-j9&TV zEgRNvuu-@i@;fWtudU~!iqntVJ}2GYS=8;|itsC3$D4V?#`L7UfI4%*`2waxd(+vv zwAKfR|GZieThy9zBSOKIcfrM1o{y6F51ib|vG?(Dm`V_WUN%W?Dgiha#mwg;~^ExIkpuww6)OtVU-e`1>ssRvbcEU%ki z6UxNQ$iTR`ahXBmVgo*4Y{~L7GX7^_VP;}oU?2JvoW%=vNJQmS&Rn3 zAZbAs9|Nx@ejmqx5dQ$(0ArtEcRw%7c9wbu2F7*)22{YfK%R{YXc7x!leq{J^8!I0 zbd3-@`B=nQL^y+2NAGaD968U_Qe$GxadoS&C635Z2~1O`5AbNofAd?B{41$IBVlICa^LjYly7sGdwi`9u_UiCKQD5n`kU%biB%6K zG7HaTx-9W^-7y(^MURXQ0RwqnQJ!|eUA)t#967$F!8L8O@b3I|J?9b_clWAgr!M-u zvew4PMd)Fq!`f(_%*i70JT=lsrmwd=D9=~Kc&=09-9cv0ywC0J+{> literal 0 HcmV?d00001 From e7c1e4820efdbbfd1eca51debb79baa2285fa5a8 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Tue, 2 Apr 2024 14:18:56 -0700 Subject: [PATCH 22/49] Change tests expected results. --- .../ConnectionTestParametersData.cs | 28 ++++++++++++++++--- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs index d13453af5f..4cca0bdafd 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs @@ -46,6 +46,7 @@ public ConnectionTestParametersData() { ConnectionTestParametersList = new List { + // 1 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -55,6 +56,7 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, + // 2 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -62,8 +64,9 @@ public ConnectionTestParametersData() TrustServerCertificate = false, Certificate = null, HostNameInCertificate = null, - TestResult = true + TestResult = false }, + // 3 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -73,6 +76,7 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, + // 4 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -82,6 +86,7 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, + // 5 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -91,6 +96,7 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, + // 6 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -100,6 +106,7 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, + // 7 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -107,8 +114,9 @@ public ConnectionTestParametersData() TrustServerCertificate = false, Certificate = null, HostNameInCertificate = s_hostName, - TestResult = true + TestResult = false }, + // 8 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -118,6 +126,7 @@ public ConnectionTestParametersData() HostNameInCertificate = s_hostName, TestResult = true }, + // 9 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -127,6 +136,7 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, + // 10 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -134,8 +144,9 @@ public ConnectionTestParametersData() TrustServerCertificate = false, Certificate = null, HostNameInCertificate = null, - TestResult = true + TestResult = false }, + // 11 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -145,6 +156,7 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, + // 12 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -154,6 +166,7 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, + // 13 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -163,6 +176,7 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, + // 14 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -172,6 +186,7 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, + // 15 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -179,8 +194,9 @@ public ConnectionTestParametersData() TrustServerCertificate = false, Certificate = null, HostNameInCertificate = s_hostName, - TestResult = true + TestResult = false }, + // 16 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -190,6 +206,7 @@ public ConnectionTestParametersData() HostNameInCertificate = s_hostName, TestResult = true }, + // 17 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -199,6 +216,7 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = false, }, + // 18 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -208,6 +226,7 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, + // 19 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -217,6 +236,7 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = false, }, + // 20 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, From d1a1bab335bd066e74f32a3a7c1ad8c772855d6a Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Tue, 2 Apr 2024 14:59:23 -0700 Subject: [PATCH 23/49] Use AsSpan().SequenceEqual in ByteArrayCompare function. --- .../Microsoft/Data/SqlClient/SNI/SNICommon.cs | 29 ++----------------- .../ConnectionTestParametersData.cs | 20 ------------- 2 files changed, 2 insertions(+), 47 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs index 660199bf00..3463465176 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs @@ -356,34 +356,9 @@ internal static uint ReportSNIError(SNIError error) return TdsEnums.SNI_ERROR; } - internal static unsafe bool ByteArrayCompare(byte[] original, byte[] variant) + internal static bool ByteArrayCompare(byte[] original, byte[] variant) { - unchecked - { - if (original == variant) - return true; - - if (original == null || variant == null || original.Length != variant.Length) - return false; - - fixed (byte* originalStartPosition = original, variantStartPosition = variant) - { - byte* originalCurrentPosition = originalStartPosition, variantCurrentPosition = variantStartPosition; - int originalLength = original.Length; - for (int i = 0; i < originalLength / 8; i++, originalCurrentPosition += 8, variantCurrentPosition += 8) - if (*((long*)originalCurrentPosition) != *((long*)variantCurrentPosition)) - return false; - if ((originalLength & 4) != 0) - { if (*((int*)originalCurrentPosition) != *((int*)variantCurrentPosition)) return false; originalCurrentPosition += 4; variantCurrentPosition += 4; } - if ((originalLength & 2) != 0) - { if (*((short*)originalCurrentPosition) != *((short*)variantCurrentPosition)) return false; originalCurrentPosition += 2; variantCurrentPosition += 2; } - if ((originalLength & 1) != 0) - if (*((byte*)originalCurrentPosition) != *((byte*)variantCurrentPosition)) - return false; - return true; - } - } + return original.AsSpan().SequenceEqual(variant.AsSpan()); } - } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs index 4cca0bdafd..5997f6be9d 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs @@ -46,7 +46,6 @@ public ConnectionTestParametersData() { ConnectionTestParametersList = new List { - // 1 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -56,7 +55,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, - // 2 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -66,7 +64,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = false }, - // 3 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -76,7 +73,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, - // 4 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -86,7 +82,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, - // 5 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -96,7 +91,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, - // 6 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -106,7 +100,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, - // 7 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -116,7 +109,6 @@ public ConnectionTestParametersData() HostNameInCertificate = s_hostName, TestResult = false }, - // 8 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -126,7 +118,6 @@ public ConnectionTestParametersData() HostNameInCertificate = s_hostName, TestResult = true }, - // 9 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -136,7 +127,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, - // 10 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -146,7 +136,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = false }, - // 11 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -156,7 +145,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, - // 12 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -166,7 +154,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, - // 13 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -176,7 +163,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, - // 14 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -186,7 +172,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, - // 15 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -196,7 +181,6 @@ public ConnectionTestParametersData() HostNameInCertificate = s_hostName, TestResult = false }, - // 16 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -206,7 +190,6 @@ public ConnectionTestParametersData() HostNameInCertificate = s_hostName, TestResult = true }, - // 17 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -216,7 +199,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = false, }, - // 18 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, @@ -226,7 +208,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, - // 19 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, @@ -236,7 +217,6 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = false, }, - // 20 new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, From 7f1806af6cef006379e445716ce07153767caed7 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Tue, 2 Apr 2024 15:52:57 -0700 Subject: [PATCH 24/49] Drop ByteArrayCompare function and use inline .AsSpan().SequenceEqual instead. --- .../netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs index 3463465176..512b63e86a 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs @@ -185,7 +185,7 @@ internal static bool ValidateSslServerCertificate(Guid connectionId, string targ if (validationCertificate != null) { - if (ByteArrayCompare(serverCert.GetRawCertData(), validationCertificate.GetRawCertData())) + if (serverCert.GetRawCertData().AsSpan().SequenceEqual(validationCertificate.GetRawCertData().AsSpan())) { SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNICommon), EventType.INFO, "Connection Id {0}, ServerCertificate matches the certificate provided by the server. Certificate validation passed.", args0: connectionId); return true; @@ -355,10 +355,5 @@ internal static uint ReportSNIError(SNIError error) SNILoadHandle.SingletonInstance.LastError = error; return TdsEnums.SNI_ERROR; } - - internal static bool ByteArrayCompare(byte[] original, byte[] variant) - { - return original.AsSpan().SequenceEqual(variant.AsSpan()); - } } } From 523b9219e354b810105e17f834c764745147c5fd Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 3 Apr 2024 08:18:29 -0700 Subject: [PATCH 25/49] Merged upstream MDS solution file. --- src/Microsoft.Data.SqlClient.sln | 69 ++++++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/src/Microsoft.Data.SqlClient.sln b/src/Microsoft.Data.SqlClient.sln index 0657cab9d7..d47f0a450e 100644 --- a/src/Microsoft.Data.SqlClient.sln +++ b/src/Microsoft.Data.SqlClient.sln @@ -23,11 +23,32 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "netcore", "netcore", "{28E5 EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "netfx", "netfx", "{3FDD425C-FE01-4B56-863E-1FCDD0677CF5}" EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Address", "Microsoft.Data.SqlClient\tests\ManualTests\SQL\UdtTest\UDTs\Address\Address.csproj", "{D1392B54-998A-4F27-BC17-4CE149117BCC}" + ProjectSection(ProjectDependencies) = postProject + {37431336-5307-4184-9356-C4B7E47DC714} = {37431336-5307-4184-9356-C4B7E47DC714} + {407890AC-9876-4FEF-A6F1-F36A876BAADE} = {407890AC-9876-4FEF-A6F1-F36A876BAADE} + EndProjectSection +EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Data.SqlClient.ManualTesting.Tests", "Microsoft.Data.SqlClient\tests\ManualTests\Microsoft.Data.SqlClient.ManualTesting.Tests.csproj", "{45DB5F86-7AE3-45C6-870D-F9357B66BDB5}" ProjectSection(ProjectDependencies) = postProject {37431336-5307-4184-9356-C4B7E47DC714} = {37431336-5307-4184-9356-C4B7E47DC714} EndProjectSection EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Circle", "Microsoft.Data.SqlClient\tests\ManualTests\SQL\UdtTest\UDTs\Circle\Circle.csproj", "{6C88F00F-9597-43AD-9E5F-9B344DA3B16F}" + ProjectSection(ProjectDependencies) = postProject + {37431336-5307-4184-9356-C4B7E47DC714} = {37431336-5307-4184-9356-C4B7E47DC714} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Shapes", "Microsoft.Data.SqlClient\tests\ManualTests\SQL\UdtTest\UDTs\Shapes\Shapes.csproj", "{B73A7063-37C3-415D-AD53-BB3DA20ABD6E}" + ProjectSection(ProjectDependencies) = postProject + {37431336-5307-4184-9356-C4B7E47DC714} = {37431336-5307-4184-9356-C4B7E47DC714} + EndProjectSection +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Utf8String", "Microsoft.Data.SqlClient\tests\ManualTests\SQL\UdtTest\UDTs\Utf8String\Utf8String.csproj", "{E0A6BB21-574B-43D9-890D-6E1144F2EE9E}" + ProjectSection(ProjectDependencies) = postProject + {37431336-5307-4184-9356-C4B7E47DC714} = {37431336-5307-4184-9356-C4B7E47DC714} + EndProjectSection +EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "ref", "ref", "{A2E7E470-5EFF-4828-B55E-FCBA3650F51C}" EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Microsoft.Data.SqlClient", "Microsoft.Data.SqlClient\netcore\ref\Microsoft.Data.SqlClient.csproj", "{1C9FC4B8-54BC-4B6C-BB3A-F5CD59D80A9B}" @@ -283,6 +304,18 @@ Global {37431336-5307-4184-9356-C4B7E47DC714}.Release|x64.Build.0 = Release|Any CPU {37431336-5307-4184-9356-C4B7E47DC714}.Release|x86.ActiveCfg = Release|Any CPU {37431336-5307-4184-9356-C4B7E47DC714}.Release|x86.Build.0 = Release|Any CPU + {D1392B54-998A-4F27-BC17-4CE149117BCC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {D1392B54-998A-4F27-BC17-4CE149117BCC}.Debug|Any CPU.Build.0 = Debug|Any CPU + {D1392B54-998A-4F27-BC17-4CE149117BCC}.Debug|x64.ActiveCfg = Debug|Any CPU + {D1392B54-998A-4F27-BC17-4CE149117BCC}.Debug|x64.Build.0 = Debug|Any CPU + {D1392B54-998A-4F27-BC17-4CE149117BCC}.Debug|x86.ActiveCfg = Debug|Any CPU + {D1392B54-998A-4F27-BC17-4CE149117BCC}.Debug|x86.Build.0 = Debug|Any CPU + {D1392B54-998A-4F27-BC17-4CE149117BCC}.Release|Any CPU.ActiveCfg = Release|Any CPU + {D1392B54-998A-4F27-BC17-4CE149117BCC}.Release|Any CPU.Build.0 = Release|Any CPU + {D1392B54-998A-4F27-BC17-4CE149117BCC}.Release|x64.ActiveCfg = Release|Any CPU + {D1392B54-998A-4F27-BC17-4CE149117BCC}.Release|x64.Build.0 = Release|Any CPU + {D1392B54-998A-4F27-BC17-4CE149117BCC}.Release|x86.ActiveCfg = Release|Any CPU + {D1392B54-998A-4F27-BC17-4CE149117BCC}.Release|x86.Build.0 = Release|Any CPU {45DB5F86-7AE3-45C6-870D-F9357B66BDB5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {45DB5F86-7AE3-45C6-870D-F9357B66BDB5}.Debug|Any CPU.Build.0 = Debug|Any CPU {45DB5F86-7AE3-45C6-870D-F9357B66BDB5}.Debug|x64.ActiveCfg = Debug|Any CPU @@ -295,6 +328,42 @@ Global {45DB5F86-7AE3-45C6-870D-F9357B66BDB5}.Release|x64.Build.0 = Release|Any CPU {45DB5F86-7AE3-45C6-870D-F9357B66BDB5}.Release|x86.ActiveCfg = Release|Any CPU {45DB5F86-7AE3-45C6-870D-F9357B66BDB5}.Release|x86.Build.0 = Release|Any CPU + {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Debug|Any CPU.Build.0 = Debug|Any CPU + {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Debug|x64.ActiveCfg = Debug|Any CPU + {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Debug|x64.Build.0 = Debug|Any CPU + {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Debug|x86.ActiveCfg = Debug|Any CPU + {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Debug|x86.Build.0 = Debug|Any CPU + {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Release|Any CPU.ActiveCfg = Release|Any CPU + {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Release|Any CPU.Build.0 = Release|Any CPU + {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Release|x64.ActiveCfg = Release|Any CPU + {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Release|x64.Build.0 = Release|Any CPU + {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Release|x86.ActiveCfg = Release|Any CPU + {6C88F00F-9597-43AD-9E5F-9B344DA3B16F}.Release|x86.Build.0 = Release|Any CPU + {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Debug|x64.ActiveCfg = Debug|Any CPU + {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Debug|x64.Build.0 = Debug|Any CPU + {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Debug|x86.ActiveCfg = Debug|Any CPU + {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Debug|x86.Build.0 = Debug|Any CPU + {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Release|Any CPU.Build.0 = Release|Any CPU + {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Release|x64.ActiveCfg = Release|Any CPU + {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Release|x64.Build.0 = Release|Any CPU + {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Release|x86.ActiveCfg = Release|Any CPU + {B73A7063-37C3-415D-AD53-BB3DA20ABD6E}.Release|x86.Build.0 = Release|Any CPU + {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Debug|x64.ActiveCfg = Debug|Any CPU + {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Debug|x64.Build.0 = Debug|Any CPU + {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Debug|x86.ActiveCfg = Debug|Any CPU + {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Debug|x86.Build.0 = Debug|Any CPU + {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Release|Any CPU.Build.0 = Release|Any CPU + {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Release|x64.ActiveCfg = Release|Any CPU + {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Release|x64.Build.0 = Release|Any CPU + {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Release|x86.ActiveCfg = Release|Any CPU + {E0A6BB21-574B-43D9-890D-6E1144F2EE9E}.Release|x86.Build.0 = Release|Any CPU {1C9FC4B8-54BC-4B6C-BB3A-F5CD59D80A9B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {1C9FC4B8-54BC-4B6C-BB3A-F5CD59D80A9B}.Debug|Any CPU.Build.0 = Debug|Any CPU {1C9FC4B8-54BC-4B6C-BB3A-F5CD59D80A9B}.Debug|x64.ActiveCfg = Debug|Any CPU From 131450ec21ddb5e0faf9fd3c17fc78acb8e98938 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 3 Apr 2024 08:33:07 -0700 Subject: [PATCH 26/49] Bring back TrySNIEventScope.Create inside ValidateServerCertificate in SNINpHandel.cs. --- .../Microsoft/Data/SqlClient/SNI/SNINpHandle.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs index 09f58833b3..8f8af57f58 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNINpHandle.cs @@ -379,14 +379,17 @@ public override void DisableSsl() /// true if valid private bool ValidateServerCertificate(object sender, X509Certificate serverCertificate, X509Chain chain, SslPolicyErrors policyErrors) { - if (!_validateCert) - { - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Certificate validation not requested.", args0: ConnectionId); - return true; - } + using (TrySNIEventScope.Create(nameof(SNINpHandle))) + { + if (!_validateCert) + { + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Certificate validation not requested.", args0: ConnectionId); + return true; + } - SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Proceeding to SSL certificate validation.", args0: ConnectionId); - return SNICommon.ValidateSslServerCertificate(_connectionId, _targetServer, _hostNameInCertificate, serverCertificate, _serverCertificateFilename, policyErrors); + SqlClientEventSource.Log.TrySNITraceEvent(nameof(SNINpHandle), EventType.INFO, "Connection Id {0}, Proceeding to SSL certificate validation.", args0: ConnectionId); + return SNICommon.ValidateSslServerCertificate(_connectionId, _targetServer, _hostNameInCertificate, serverCertificate, _serverCertificateFilename, policyErrors); + } } /// From 2c5b5fd5577e1c629006229b8cafdca7aa9830d5 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 3 Apr 2024 08:56:35 -0700 Subject: [PATCH 27/49] Merge netfx MDS project file. Added DbReferenceCollection.cs --- .../netfx/src/Microsoft.Data.SqlClient.csproj | 19 +- .../ProviderBase/DbReferenceCollection.cs | 279 ++++++++++++++++++ 2 files changed, 288 insertions(+), 10 deletions(-) create mode 100644 src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbReferenceCollection.cs diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 931a48f65c..2ce5e824e0 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -1,10 +1,8 @@ - - - + {407890AC-9876-4FEF-A6F1-F36A876BAADE} Microsoft.Data.SqlClient - v4.6.2 + net462 true Microsoft.Data.SqlClient AnyCPU @@ -17,19 +15,20 @@ True + false $(DefineConstants);NETFRAMEWORK; full - + - $([System.IO.Path]::Combine('$(IntermediateOutputPath)','$(GeneratedSourceFileName)')) + $([System.IO.Path]::Combine('$(IntermediateOutputPath)\$(TargetFramework)','$(GeneratedSourceFileName)')) - + True @@ -610,6 +609,9 @@ Resources\ResDescriptionAttribute.cs + + Microsoft\Data\ProviderBase\DbReferenceCollection.cs + @@ -631,7 +633,6 @@ - @@ -701,7 +702,6 @@ System ResXFileCodeGenerator Strings.Designer.cs - Designer Resources\%(RecursiveDir)%(Filename)%(Extension) @@ -747,7 +747,6 @@ $(SystemBuffersVersion) - diff --git a/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbReferenceCollection.cs b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbReferenceCollection.cs new file mode 100644 index 0000000000..35356bfa12 --- /dev/null +++ b/src/Microsoft.Data.SqlClient/src/Microsoft/Data/ProviderBase/DbReferenceCollection.cs @@ -0,0 +1,279 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Diagnostics; +using System.Threading; + +namespace Microsoft.Data.ProviderBase +{ + internal abstract class DbReferenceCollection + { + #region Constants + // Time to wait (in ms) between attempting to get the _itemLock + private const int LockPollTime = 100; + + // Default size for the collection, and the amount to grow every time the collection is full + private const int DefaultCollectionSize = 20; + #endregion + + #region Fields + // The collection of items we are keeping track of + private CollectionEntry[] _items; + + // Used to synchronize access to the _items collection + private readonly object _itemLock; + + // (#ItemsAdded - #ItemsRemoved) - This estimates the number of items that we should have + // (but doesn't take into account item targets being GC'd) + private int _estimatedCount; + + // Location of the last item in _items + private int _lastItemIndex; + + // Indicates that the collection is currently being notified (and, therefore, about to be cleared) + private volatile bool _isNotifying; + #endregion + + private struct CollectionEntry + { + private int _refInfo; // information about the reference + private WeakReference _weakReference; // the reference itself. + + public void SetNewTarget(int refInfo, object target) + { + Debug.Assert(!TryGetTarget(out object _), "Entry already has a valid target"); + Debug.Assert(refInfo != 0, "Bad reference info"); + Debug.Assert(target != null, "Invalid target"); + + if (_weakReference == null) + { + _weakReference = new WeakReference(target, false); + } + else + { + _weakReference.SetTarget(target); + } + _refInfo = refInfo; + } + + public void RemoveTarget() + { + _refInfo = 0; + _weakReference.SetTarget(null); + } + + public readonly int RefInfo => _refInfo; + + public readonly bool TryGetTarget(out object target) + { + target = null; + return _refInfo != 0 && _weakReference.TryGetTarget(out target); + } + } + + protected DbReferenceCollection() + { + _items = new CollectionEntry[DefaultCollectionSize]; + _itemLock = new object(); + _estimatedCount = 0; + _lastItemIndex = 0; + } + + abstract public void Add(object value, int refInfo); + + protected void AddItem(object value, int refInfo) + { + Debug.Assert(value != null && 0 != refInfo, "AddItem with null value or 0 reference info"); + bool itemAdded = false; + + lock (_itemLock) + { + // Try to find a free spot + for (int i = 0; i <= _lastItemIndex; ++i) + { + if (_items[i].RefInfo == 0) + { + _items[i].SetNewTarget(refInfo, value); + Debug.Assert(_items[i].TryGetTarget(out object _), "missing expected target"); + itemAdded = true; + break; + } + } + + // No free spots, can we just add on to the end? + if ((!itemAdded) && (_lastItemIndex + 1 < _items.Length)) + { + _lastItemIndex++; + _items[_lastItemIndex].SetNewTarget(refInfo, value); + itemAdded = true; + } + + // If no free spots and no space at the end, try to find a dead item + if (!itemAdded) + { + for (int i = 0; i <= _lastItemIndex; ++i) + { + if (!_items[i].TryGetTarget(out object _)) + { + _items[i].SetNewTarget(refInfo, value); + Debug.Assert(_items[i].TryGetTarget(out object _), "missing expected target"); + itemAdded = true; + break; + } + } + } + + // If nothing was free, then resize and add to the end + if (!itemAdded) + { + Array.Resize(ref _items, _items.Length * 2); + _lastItemIndex++; + _items[_lastItemIndex].SetNewTarget(refInfo, value); + } + + _estimatedCount++; + } + } + + internal T FindItem(int refInfo, Func filterMethod) where T : class + { + bool lockObtained = false; + try + { + TryEnterItemLock(ref lockObtained); + if (lockObtained) + { + if (_estimatedCount > 0) + { + for (int counter = 0; counter <= _lastItemIndex; counter++) + { + // Check reference info (should be easiest and quickest) + if (_items[counter].RefInfo == refInfo) + { + if (_items[counter].TryGetTarget(out object value)) + { + // Make sure the item has the correct type and passes the filtering + if (value is T tempItem && filterMethod(tempItem)) + { + return tempItem; + } + } + } + } + } + } + } + finally + { + ExitItemLockIfNeeded(lockObtained); + } + + // If we got to here, then no item was found, so return null + return null; + } + + public void Notify(int message) + { + bool lockObtained = false; + try + { + TryEnterItemLock(ref lockObtained); + if (lockObtained) + { + try + { + _isNotifying = true; + + // Loop through each live item and notify it + if (_estimatedCount > 0) + { + for (int index = 0; index <= _lastItemIndex; ++index) + { + if (_items[index].TryGetTarget(out object value)) + { + NotifyItem(message, _items[index].RefInfo, value); + _items[index].RemoveTarget(); + } + Debug.Assert(!_items[index].TryGetTarget(out object _), "Unexpected target after notifying"); + } + _estimatedCount = 0; + } + + // Shrink collection (if needed) + if (_items.Length > 100) + { + _lastItemIndex = 0; + _items = new CollectionEntry[DefaultCollectionSize]; + } + } + finally + { + _isNotifying = false; + } + } + } + finally + { + ExitItemLockIfNeeded(lockObtained); + } + } + + abstract protected void NotifyItem(int message, int refInfo, object value); + + abstract public void Remove(object value); + + protected void RemoveItem(object value) + { + Debug.Assert(null != value, "RemoveItem with null"); + + bool lockObtained = false; + try + { + TryEnterItemLock(ref lockObtained); + + if (lockObtained) + { + // Find the value, and then remove the target from our collection + if (_estimatedCount > 0) + { + for (int index = 0; index <= _lastItemIndex; ++index) + { + if (_items[index].TryGetTarget(out object target) && value == target) + { + _items[index].RemoveTarget(); + _estimatedCount--; + break; + } + } + } + } + } + finally + { + ExitItemLockIfNeeded(lockObtained); + } + } + + // This is polling lock that will abandon getting the lock if _isNotifying is set to true + private void TryEnterItemLock(ref bool lockObtained) + { + // Assume that we couldn't take the lock + lockObtained = false; + // Keep trying to take the lock until either we've taken it, or the collection is being notified + while ((!_isNotifying) && (!lockObtained)) + { + Monitor.TryEnter(_itemLock, LockPollTime, ref lockObtained); + } + } + + private void ExitItemLockIfNeeded(bool lockObtained) + { + if (lockObtained) + { + Monitor.Exit(_itemLock); + } + } + } +} From 1b6371ab659aaa180fb49b049cc56d3dea624002 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 3 Apr 2024 09:06:56 -0700 Subject: [PATCH 28/49] Removed one second delay to wait for the creation of certificate to complete. --- .../CertificateTestWithTdsServer.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs index ad959c0d43..09fcfb79c7 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs @@ -136,12 +136,6 @@ private static void CreatePfxCertificate(string script) proc.WaitForExit(2000); throw new Exception($"Could not generate certificate.Error out put: {output}"); } - - System.Threading.Thread.Sleep(1000); - if (!File.Exists(s_fullPathToPfx)) - { - System.Threading.Thread.Sleep(1000); - } } else { From d1a988026729440c715be3fae596fcabd43bd4ba Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 3 Apr 2024 09:08:58 -0700 Subject: [PATCH 29/49] Added license information to new class files. --- .../ManualTests/DataCommon/ConnectionTestParameters.cs | 6 +++++- .../ManualTests/DataCommon/ConnectionTestParametersData.cs | 6 +++++- .../CertificateTestWithTdsServer.cs | 1 - 3 files changed, 10 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParameters.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParameters.cs index 2ae7cdc377..b2b8b96179 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParameters.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParameters.cs @@ -1,4 +1,8 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using System.Collections.Generic; using System.Linq; using System.Text; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs index 5997f6be9d..0575d56fb2 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs @@ -1,4 +1,8 @@ -using System; +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; using System.Collections; using System.Collections.Generic; using System.IO; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs index 09fcfb79c7..41a5527bf5 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs @@ -144,4 +144,3 @@ private static void CreatePfxCertificate(string script) } } } - From 6f198e7cc644bd9c8f68171a32461a6d5fead797 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 3 Apr 2024 10:01:20 -0700 Subject: [PATCH 30/49] Re-merge Manual Tests project file. --- .../Microsoft.Data.SqlClient.ManualTesting.Tests.csproj | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj index 67116e91da..4a83f8738b 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/Microsoft.Data.SqlClient.ManualTesting.Tests.csproj @@ -350,7 +350,10 @@ - + + PreserveNewest + %(Filename)%(Extension) + From cb7cc8edfb23b4428c859f22da2dbdd78a7b136e Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 8 Apr 2024 11:44:59 -0700 Subject: [PATCH 31/49] Change parameter names. Added more set of parameters. --- .../DataCommon/ConnectionTestParameters.cs | 2 +- .../ConnectionTestParametersData.cs | 100 ++++++++++++++++++ .../tools/TDS/TDS.EndPoint/TDSServerParser.cs | 8 +- 3 files changed, 106 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParameters.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParameters.cs index b2b8b96179..10aa2f5c15 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParameters.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParameters.cs @@ -13,11 +13,11 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests.DataCommon { public class ConnectionTestParameters { - public TDSPreLoginTokenEncryptionType TdsEncryptionType { get; set; } public SqlConnectionEncryptOption Encrypt { get; set; } public bool TrustServerCertificate { get; set; } public string Certificate { get; set; } public string HostNameInCertificate { get; set; } public bool TestResult { get; set; } + public TDSPreLoginTokenEncryptionType TdsEncryptionType { get; set; } } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs index 0575d56fb2..1ecf679de7 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs @@ -44,6 +44,16 @@ public static IEnumerable GetConnectionTestParameters() yield return new object[] { Data.ConnectionTestParametersList[17] }; yield return new object[] { Data.ConnectionTestParametersList[18] }; yield return new object[] { Data.ConnectionTestParametersList[19] }; + yield return new object[] { Data.ConnectionTestParametersList[20] }; + yield return new object[] { Data.ConnectionTestParametersList[21] }; + yield return new object[] { Data.ConnectionTestParametersList[22] }; + yield return new object[] { Data.ConnectionTestParametersList[23] }; + yield return new object[] { Data.ConnectionTestParametersList[24] }; + yield return new object[] { Data.ConnectionTestParametersList[25] }; + yield return new object[] { Data.ConnectionTestParametersList[26] }; + yield return new object[] { Data.ConnectionTestParametersList[27] }; + yield return new object[] { Data.ConnectionTestParametersList[28] }; + yield return new object[] { Data.ConnectionTestParametersList[29] }; } public ConnectionTestParametersData() @@ -195,6 +205,78 @@ public ConnectionTestParametersData() TestResult = true }, new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, + Encrypt = SqlConnectionEncryptOption.Optional, + TrustServerCertificate = false, + Certificate = null, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = false, + Certificate = null, + HostNameInCertificate = null, + TestResult = false + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, + Encrypt = SqlConnectionEncryptOption.Optional, + TrustServerCertificate = true, + Certificate = null, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = true, + Certificate = null, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = false, + Certificate = s_fullPathToCer, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = true, + Certificate = s_fullPathToCer, + HostNameInCertificate = null, + TestResult = true + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = false, + Certificate = null, + HostNameInCertificate = s_hostName, + TestResult = false + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = true, + Certificate = null, + HostNameInCertificate = s_hostName, + TestResult = true + }, + new ConnectionTestParameters { TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, Encrypt = SqlConnectionEncryptOption.Mandatory, @@ -230,6 +312,24 @@ public ConnectionTestParametersData() HostNameInCertificate = null, TestResult = true }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = false, + Certificate = s_mismatchedcert, + HostNameInCertificate = null, + TestResult = false, + }, + new ConnectionTestParameters + { + TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, + Encrypt = SqlConnectionEncryptOption.Mandatory, + TrustServerCertificate = true, + Certificate = s_mismatchedcert, + HostNameInCertificate = null, + TestResult = true + }, }; } } diff --git a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/TDSServerParser.cs b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/TDSServerParser.cs index 8a95553344..58ae749a29 100644 --- a/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/TDSServerParser.cs +++ b/src/Microsoft.Data.SqlClient/tests/tools/TDS/TDS.EndPoint/TDSServerParser.cs @@ -71,14 +71,16 @@ public void Run() { if ((Session.Encryption == TDSEncryptionType.None || Session.Encryption == TDSEncryptionType.Off) && (MessageBeingReceived[0] as TDSPreLoginToken).Encryption != TDSPreLoginTokenEncryptionType.On) - //if (Session.Encryption == TDSEncryptionType.None) { - (MessageBeingReceived[0] as TDSPreLoginToken).Encryption = TDSPreLoginTokenEncryptionType.None; + if (Session.Encryption == TDSEncryptionType.None) + (MessageBeingReceived[0] as TDSPreLoginToken).Encryption = TDSPreLoginTokenEncryptionType.None; + else + (MessageBeingReceived[0] as TDSPreLoginToken).Encryption = TDSPreLoginTokenEncryptionType.Off; } // Call into the subscriber to process the packet responseMessages = Server.OnPreLoginRequest(Session, MessageBeingReceived); - + if (Session.Encryption == TDSEncryptionType.None || Session.Encryption == TDSEncryptionType.Off) { DisableTransportEncryption(); From c065a90967130a142fb3a0c7c8c4d8026840b7c8 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 8 Apr 2024 12:11:20 -0700 Subject: [PATCH 32/49] Fix some wrong expecated result in the set of parameters. --- .../ManualTests/DataCommon/ConnectionTestParametersData.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs index 1ecf679de7..17672a68ef 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs @@ -139,7 +139,7 @@ public ConnectionTestParametersData() TrustServerCertificate = false, Certificate = null, HostNameInCertificate = null, - TestResult = true + TestResult = false }, new ConnectionTestParameters { @@ -211,7 +211,7 @@ public ConnectionTestParametersData() TrustServerCertificate = false, Certificate = null, HostNameInCertificate = null, - TestResult = true + TestResult = false }, new ConnectionTestParameters { From 0f1d82f3a6d64fc78efde9d02b2877927e72c183 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 8 Apr 2024 13:09:30 -0700 Subject: [PATCH 33/49] Ammend makepfxcert.ps1 desciption. --- src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index 911affc9db..9f28bb584a 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -4,7 +4,7 @@ # Script: Invoke-SqlServerCertificateCommand# # Author: SqlClient Team # Date: March 20, 2024 -# Comments: This scripts creates SQL Server SSL Self-Signed Certificate. +# Comments: This scripts creates SSL Self-Signed Certificate for TestTdsServer in pfx format. # This script is not intended to be used in production environments. param ($OutDir) From dfbc84720cedf742f5f008766b930e39d771af97 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Thu, 18 Apr 2024 12:06:09 -0700 Subject: [PATCH 34/49] Applied suggested change in the comment at line 141 of SNICommon.cs. --- .../netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs index 512b63e86a..ad9ebebbfe 100644 --- a/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs +++ b/src/Microsoft.Data.SqlClient/netcore/src/Microsoft/Data/SqlClient/SNI/SNICommon.cs @@ -138,7 +138,7 @@ internal class SNICommon internal const int LocalDBBadRuntime = 57; /// - /// We either validate that the provided validationCert matches the serverCert or validate Server name in the serverCert matches "targetServerName". + /// We either validate that the provided 'validationCert' matches the 'serverCert', or we validate that the server name in the 'serverCert' matches 'targetServerName'. /// Certificate validation and chain trust validations are done by SSLStream class [System.Net.Security.SecureChannel.VerifyRemoteCertificate method] /// This method is called as a result of callback for SSL Stream Certificate validation. /// From 9d8c7d9a67a7c301e09f3de0e5caa45d1e9c591a Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Thu, 18 Apr 2024 12:16:21 -0700 Subject: [PATCH 35/49] Added extra line as suggested. --- .../netfx/src/Microsoft.Data.SqlClient.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj index 2ce5e824e0..4dc1ae6393 100644 --- a/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj +++ b/src/Microsoft.Data.SqlClient/netfx/src/Microsoft.Data.SqlClient.csproj @@ -751,4 +751,4 @@ - \ No newline at end of file + From f30151502260837934ff88996664a498f6992492 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Fri, 19 Apr 2024 09:22:31 -0700 Subject: [PATCH 36/49] Applied suggested changes. --- NuGet.config | 2 + .../ConnectionTestParametersData.cs | 128 ++++++++---------- .../CertificateTestWithTdsServer.cs | 4 +- 3 files changed, 60 insertions(+), 74 deletions(-) diff --git a/NuGet.config b/NuGet.config index 3233e60161..a1bb4d4085 100644 --- a/NuGet.config +++ b/NuGet.config @@ -3,5 +3,7 @@ + + diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs index 17672a68ef..36d9b5cc82 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs @@ -15,6 +15,8 @@ namespace Microsoft.Data.SqlClient.ManualTesting.Tests.DataCommon { public class ConnectionTestParametersData { + private const int CASES = 30; + private string _empty = string.Empty; private static readonly string s_fullPathToCer = Path.Combine(Directory.GetCurrentDirectory(), "localhostcert.cer"); private static readonly string s_mismatchedcert = Path.Combine(Directory.GetCurrentDirectory(), "mismatchedcert.cer"); @@ -24,40 +26,22 @@ public class ConnectionTestParametersData public static IEnumerable GetConnectionTestParameters() { - yield return new object[] { Data.ConnectionTestParametersList[0] }; - yield return new object[] { Data.ConnectionTestParametersList[1] }; - yield return new object[] { Data.ConnectionTestParametersList[2] }; - yield return new object[] { Data.ConnectionTestParametersList[3] }; - yield return new object[] { Data.ConnectionTestParametersList[4] }; - yield return new object[] { Data.ConnectionTestParametersList[5] }; - yield return new object[] { Data.ConnectionTestParametersList[6] }; - yield return new object[] { Data.ConnectionTestParametersList[7] }; - yield return new object[] { Data.ConnectionTestParametersList[8] }; - yield return new object[] { Data.ConnectionTestParametersList[9] }; - yield return new object[] { Data.ConnectionTestParametersList[10] }; - yield return new object[] { Data.ConnectionTestParametersList[11] }; - yield return new object[] { Data.ConnectionTestParametersList[12] }; - yield return new object[] { Data.ConnectionTestParametersList[13] }; - yield return new object[] { Data.ConnectionTestParametersList[14] }; - yield return new object[] { Data.ConnectionTestParametersList[15] }; - yield return new object[] { Data.ConnectionTestParametersList[16] }; - yield return new object[] { Data.ConnectionTestParametersList[17] }; - yield return new object[] { Data.ConnectionTestParametersList[18] }; - yield return new object[] { Data.ConnectionTestParametersList[19] }; - yield return new object[] { Data.ConnectionTestParametersList[20] }; - yield return new object[] { Data.ConnectionTestParametersList[21] }; - yield return new object[] { Data.ConnectionTestParametersList[22] }; - yield return new object[] { Data.ConnectionTestParametersList[23] }; - yield return new object[] { Data.ConnectionTestParametersList[24] }; - yield return new object[] { Data.ConnectionTestParametersList[25] }; - yield return new object[] { Data.ConnectionTestParametersList[26] }; - yield return new object[] { Data.ConnectionTestParametersList[27] }; - yield return new object[] { Data.ConnectionTestParametersList[28] }; - yield return new object[] { Data.ConnectionTestParametersList[29] }; + for(int i=0; i < CASES; i++) + { + yield return new object[] { Data.ConnectionTestParametersList[i] }; + } } public ConnectionTestParametersData() { + // Test cases possible field values for connection parameters: + // Possible values for TdsEncryptionType are Off, On, Required + // Possible values for Encrypt are Optional, Mandatory + // Possible values for TrustServerCertificate are true, false + // Possible values for Certificate are valid path to certificate, empty + // Possible values for HostNameInCertificate are valid hostname, empty + // TestResult is the expected result of the connection test + // These combinations are based on the possible values of Encrypt, TrustServerCertificate, Certificate, HostNameInCertificate ConnectionTestParametersList = new List { new ConnectionTestParameters @@ -65,8 +49,8 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, Encrypt = SqlConnectionEncryptOption.Optional, TrustServerCertificate = false, - Certificate = null, - HostNameInCertificate = null, + Certificate = _empty, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -74,8 +58,8 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = false, - Certificate = null, - HostNameInCertificate = null, + Certificate = _empty, + HostNameInCertificate = _empty, TestResult = false }, new ConnectionTestParameters @@ -83,8 +67,8 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, Encrypt = SqlConnectionEncryptOption.Optional, TrustServerCertificate = true, - Certificate = null, - HostNameInCertificate = null, + Certificate = _empty, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -92,8 +76,8 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = true, - Certificate = null, - HostNameInCertificate = null, + Certificate = _empty, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -102,7 +86,7 @@ public ConnectionTestParametersData() Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = false, Certificate = s_fullPathToCer, - HostNameInCertificate = null, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -111,7 +95,7 @@ public ConnectionTestParametersData() Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = true, Certificate = s_fullPathToCer, - HostNameInCertificate = null, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -119,7 +103,7 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = false, - Certificate = null, + Certificate = _empty, HostNameInCertificate = s_hostName, TestResult = false }, @@ -128,7 +112,7 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.Off, Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = true, - Certificate = null, + Certificate = _empty, HostNameInCertificate = s_hostName, TestResult = true }, @@ -137,8 +121,8 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, Encrypt = SqlConnectionEncryptOption.Optional, TrustServerCertificate = false, - Certificate = null, - HostNameInCertificate = null, + Certificate = _empty, + HostNameInCertificate = _empty, TestResult = false }, new ConnectionTestParameters @@ -146,8 +130,8 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = false, - Certificate = null, - HostNameInCertificate = null, + Certificate = _empty, + HostNameInCertificate = _empty, TestResult = false }, new ConnectionTestParameters @@ -155,8 +139,8 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, Encrypt = SqlConnectionEncryptOption.Optional, TrustServerCertificate = true, - Certificate = null, - HostNameInCertificate = null, + Certificate = _empty, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -164,8 +148,8 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = true, - Certificate = null, - HostNameInCertificate = null, + Certificate = _empty, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -174,7 +158,7 @@ public ConnectionTestParametersData() Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = false, Certificate = s_fullPathToCer, - HostNameInCertificate = null, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -183,7 +167,7 @@ public ConnectionTestParametersData() Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = true, Certificate = s_fullPathToCer, - HostNameInCertificate = null, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -191,7 +175,7 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = false, - Certificate = null, + Certificate = _empty, HostNameInCertificate = s_hostName, TestResult = false }, @@ -200,7 +184,7 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.On, Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = true, - Certificate = null, + Certificate = _empty, HostNameInCertificate = s_hostName, TestResult = true }, @@ -209,8 +193,8 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, Encrypt = SqlConnectionEncryptOption.Optional, TrustServerCertificate = false, - Certificate = null, - HostNameInCertificate = null, + Certificate = _empty, + HostNameInCertificate = _empty, TestResult = false }, new ConnectionTestParameters @@ -218,8 +202,8 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = false, - Certificate = null, - HostNameInCertificate = null, + Certificate = _empty, + HostNameInCertificate = _empty, TestResult = false }, new ConnectionTestParameters @@ -227,8 +211,8 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, Encrypt = SqlConnectionEncryptOption.Optional, TrustServerCertificate = true, - Certificate = null, - HostNameInCertificate = null, + Certificate = _empty, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -236,8 +220,8 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = true, - Certificate = null, - HostNameInCertificate = null, + Certificate = _empty, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -246,7 +230,7 @@ public ConnectionTestParametersData() Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = false, Certificate = s_fullPathToCer, - HostNameInCertificate = null, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -255,7 +239,7 @@ public ConnectionTestParametersData() Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = true, Certificate = s_fullPathToCer, - HostNameInCertificate = null, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -263,7 +247,7 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = false, - Certificate = null, + Certificate = _empty, HostNameInCertificate = s_hostName, TestResult = false }, @@ -272,7 +256,7 @@ public ConnectionTestParametersData() TdsEncryptionType = TDSPreLoginTokenEncryptionType.Required, Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = true, - Certificate = null, + Certificate = _empty, HostNameInCertificate = s_hostName, TestResult = true }, @@ -282,7 +266,7 @@ public ConnectionTestParametersData() Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = false, Certificate = s_mismatchedcert, - HostNameInCertificate = null, + HostNameInCertificate = _empty, TestResult = false, }, new ConnectionTestParameters @@ -291,7 +275,7 @@ public ConnectionTestParametersData() Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = true, Certificate = s_mismatchedcert, - HostNameInCertificate = null, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -300,7 +284,7 @@ public ConnectionTestParametersData() Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = false, Certificate = s_mismatchedcert, - HostNameInCertificate = null, + HostNameInCertificate = _empty, TestResult = false, }, new ConnectionTestParameters @@ -309,7 +293,7 @@ public ConnectionTestParametersData() Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = true, Certificate = s_mismatchedcert, - HostNameInCertificate = null, + HostNameInCertificate = _empty, TestResult = true }, new ConnectionTestParameters @@ -318,7 +302,7 @@ public ConnectionTestParametersData() Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = false, Certificate = s_mismatchedcert, - HostNameInCertificate = null, + HostNameInCertificate = _empty, TestResult = false, }, new ConnectionTestParameters @@ -327,7 +311,7 @@ public ConnectionTestParametersData() Encrypt = SqlConnectionEncryptOption.Mandatory, TrustServerCertificate = true, Certificate = s_mismatchedcert, - HostNameInCertificate = null, + HostNameInCertificate = _empty, TestResult = true }, }; diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs index 41a5527bf5..eecb513cb6 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs @@ -65,12 +65,12 @@ public void ConnectionTest(ConnectionTestParameters connectionTestParameters) builder.Password = "password"; } - if (connectionTestParameters.Certificate != null) + if (connectionTestParameters.Certificate != string.Empty) { builder.ServerCertificate = connectionTestParameters.Certificate; } - if (connectionTestParameters.HostNameInCertificate != null) + if (connectionTestParameters.HostNameInCertificate != string.Empty) { builder.HostNameInCertificate = connectionTestParameters.HostNameInCertificate; } From e413d9c3ca3a5044a1fae3457a03d59a89b6162c Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Fri, 19 Apr 2024 11:06:29 -0700 Subject: [PATCH 37/49] No change just trigerring pipeline run for this PR. --- src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index 9f28bb584a..397db5c6cf 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -5,7 +5,7 @@ # Author: SqlClient Team # Date: March 20, 2024 # Comments: This scripts creates SSL Self-Signed Certificate for TestTdsServer in pfx format. -# This script is not intended to be used in production environments. +# This script is not intended to be used in any production environments. param ($OutDir) From db6656de760057ccc2c1ef237ad45dd8aa633ab4 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Wed, 24 Apr 2024 08:56:31 -0700 Subject: [PATCH 38/49] Revert Nuget.config changes. --- NuGet.config | 2 -- 1 file changed, 2 deletions(-) diff --git a/NuGet.config b/NuGet.config index a1bb4d4085..3233e60161 100644 --- a/NuGet.config +++ b/NuGet.config @@ -3,7 +3,5 @@ - - From 3341d76d1b08f184a150798514689cb5a6d51451 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 29 Apr 2024 08:54:19 -0700 Subject: [PATCH 39/49] Change default Tds Server encryption to not supported in Functional Tests. --- .../tests/FunctionalTests/TestTdsServer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs index 4f144cb0f4..d1f373f516 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs @@ -31,7 +31,7 @@ public TestTdsServer(QueryEngine engine, TDSServerArguments args) : base(args) public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool enableFedAuth = false, bool enableLog = false, int connectionTimeout = DefaultConnectionTimeout, [CallerMemberName] string methodName = "", - X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.Off) + X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.NotSupported) { TDSServerArguments args = new TDSServerArguments() { From 5e8bd990e26003c0fd5f5b1c7f4882955fa814c0 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 29 Apr 2024 09:20:59 -0700 Subject: [PATCH 40/49] Restore original TestTdsServer.cs in Functional Test. --- .../SqlConnectionBasicTests.cs | 2 +- .../tests/FunctionalTests/TestTdsServer.cs | 33 +++++-------------- 2 files changed, 10 insertions(+), 25 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs index b4f38f70df..35ceee3f76 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/SqlConnectionBasicTests.cs @@ -47,7 +47,7 @@ public void IntegratedAuthConnectionTest() [Fact] public async Task PreLoginEncryptionExcludedTest() { - using TestTdsServer server = TestTdsServer.StartTestServer(false, false, 5, encryptionType: TDSPreLoginTokenEncryptionType.None); + using TestTdsServer server = TestTdsServer.StartTestServer(false, false, 5, excludeEncryption: true); SqlConnectionStringBuilder builder = new(server.ConnectionString) { IntegratedSecurity = true, diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs index d1f373f516..1ead74f58d 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs @@ -3,13 +3,9 @@ // See the LICENSE file in the project root for more information. using System; -using System.Linq; using System.Net; -using System.Net.Sockets; using System.Runtime.CompilerServices; -using System.Security.Cryptography.X509Certificates; using Microsoft.SqlServer.TDS.EndPoint; -using Microsoft.SqlServer.TDS.PreLogin; using Microsoft.SqlServer.TDS.Servers; namespace Microsoft.Data.SqlClient.Tests @@ -29,9 +25,7 @@ public TestTdsServer(QueryEngine engine, TDSServerArguments args) : base(args) Engine = engine; } - public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool enableFedAuth = false, bool enableLog = false, - int connectionTimeout = DefaultConnectionTimeout, [CallerMemberName] string methodName = "", - X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.NotSupported) + public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool enableFedAuth = false, bool enableLog = false, int connectionTimeout = DefaultConnectionTimeout, bool excludeEncryption = false, [CallerMemberName] string methodName = "") { TDSServerArguments args = new TDSServerArguments() { @@ -42,16 +36,12 @@ public TestTdsServer(QueryEngine engine, TDSServerArguments args) : base(args) { args.FedAuthRequiredPreLoginOption = SqlServer.TDS.PreLogin.TdsPreLoginFedAuthRequiredOption.FedAuthRequired; } - - if (encryptionCertificate != null) + if (excludeEncryption) { - args.EncryptionCertificate = encryptionCertificate; + args.Encryption = SqlServer.TDS.PreLogin.TDSPreLoginTokenEncryptionType.None; } - args.Encryption = encryptionType; - TestTdsServer server = engine == null ? new TestTdsServer(args) : new TestTdsServer(engine, args); - server._endpoint = new TDSServerEndPoint(server) { ServerEndPoint = new IPEndPoint(IPAddress.Any, 0) }; server._endpoint.EndpointName = methodName; // The server EventLog should be enabled as it logs the exceptions. @@ -59,22 +49,17 @@ public TestTdsServer(QueryEngine engine, TDSServerArguments args) : base(args) server._endpoint.Start(); int port = server._endpoint.ServerEndPoint.Port; - - server._connectionStringBuilder = new SqlConnectionStringBuilder() - { - DataSource = "localhost," + port, - ConnectTimeout = connectionTimeout, - Encrypt = (encryptionType == TDSPreLoginTokenEncryptionType.Off ? SqlConnectionEncryptOption.Optional : SqlConnectionEncryptOption.Mandatory) - }; + server._connectionStringBuilder = excludeEncryption + // Allow encryption to be set when encryption is to be excluded from pre-login response. + ? new SqlConnectionStringBuilder() { DataSource = "localhost," + port, ConnectTimeout = connectionTimeout, Encrypt = SqlConnectionEncryptOption.Mandatory } + : new SqlConnectionStringBuilder() { DataSource = "localhost," + port, ConnectTimeout = connectionTimeout, Encrypt = SqlConnectionEncryptOption.Optional }; server.ConnectionString = server._connectionStringBuilder.ConnectionString; return server; } - public static TestTdsServer StartTestServer(bool enableFedAuth = false, bool enableLog = false, - int connectionTimeout = DefaultConnectionTimeout, [CallerMemberName] string methodName = "", - X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.Off) + public static TestTdsServer StartTestServer(bool enableFedAuth = false, bool enableLog = false, int connectionTimeout = DefaultConnectionTimeout, bool excludeEncryption = false, [CallerMemberName] string methodName = "") { - return StartServerWithQueryEngine(null, enableFedAuth, enableLog, connectionTimeout, methodName, encryptionCertificate, encryptionType); + return StartServerWithQueryEngine(null, enableFedAuth, enableLog, connectionTimeout, excludeEncryption, methodName); } public void Dispose() => _endpoint?.Stop(); From 7ee63c2c5fe3f38807204b9fdb9f03a2bbaa8d76 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 29 Apr 2024 10:53:44 -0700 Subject: [PATCH 41/49] Changed TdsServer default encryption to None in Manual Tests. --- .../tests/ManualTests/TracingTests/TestTdsServer.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs index e139c8265b..ef4010a3bc 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs @@ -31,7 +31,7 @@ public TestTdsServer(QueryEngine engine, TDSServerArguments args) : base(args) public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool enableFedAuth = false, bool enableLog = false, int connectionTimeout = DefaultConnectionTimeout, [CallerMemberName] string methodName = "", - X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.Off) + X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.None) { TDSServerArguments args = new TDSServerArguments() { @@ -64,8 +64,17 @@ public TestTdsServer(QueryEngine engine, TDSServerArguments args) : base(args) { DataSource = "localhost," + port, ConnectTimeout = connectionTimeout, - Encrypt = (encryptionType == TDSPreLoginTokenEncryptionType.Off ? SqlConnectionEncryptOption.Optional : SqlConnectionEncryptOption.Mandatory) }; + + if ((encryptionType == TDSPreLoginTokenEncryptionType.Off) || (encryptionType == TDSPreLoginTokenEncryptionType.None)) + { + server._connectionStringBuilder.Encrypt = SqlConnectionEncryptOption.Optional; + } + else + { + server._connectionStringBuilder.Encrypt = SqlConnectionEncryptOption.Mandatory; + } + server.ConnectionString = server._connectionStringBuilder.ConnectionString; return server; } From b5539d1f1b83b840c319b651cd0e936055f07c7c Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 29 Apr 2024 12:57:21 -0700 Subject: [PATCH 42/49] Actually, make the test TdsServer default Encryption to NotSupported in Manual Tests. --- .../tests/ManualTests/TracingTests/TestTdsServer.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs index ef4010a3bc..af97f0a80c 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs @@ -31,7 +31,7 @@ public TestTdsServer(QueryEngine engine, TDSServerArguments args) : base(args) public static TestTdsServer StartServerWithQueryEngine(QueryEngine engine, bool enableFedAuth = false, bool enableLog = false, int connectionTimeout = DefaultConnectionTimeout, [CallerMemberName] string methodName = "", - X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.None) + X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.NotSupported) { TDSServerArguments args = new TDSServerArguments() { @@ -66,7 +66,9 @@ public TestTdsServer(QueryEngine engine, TDSServerArguments args) : base(args) ConnectTimeout = connectionTimeout, }; - if ((encryptionType == TDSPreLoginTokenEncryptionType.Off) || (encryptionType == TDSPreLoginTokenEncryptionType.None)) + if (encryptionType == TDSPreLoginTokenEncryptionType.Off || + encryptionType == TDSPreLoginTokenEncryptionType.None || + encryptionType == TDSPreLoginTokenEncryptionType.NotSupported) { server._connectionStringBuilder.Encrypt = SqlConnectionEncryptOption.Optional; } @@ -81,7 +83,7 @@ public TestTdsServer(QueryEngine engine, TDSServerArguments args) : base(args) public static TestTdsServer StartTestServer(bool enableFedAuth = false, bool enableLog = false, int connectionTimeout = DefaultConnectionTimeout, [CallerMemberName] string methodName = "", - X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.Off) + X509Certificate2 encryptionCertificate = null, TDSPreLoginTokenEncryptionType encryptionType = TDSPreLoginTokenEncryptionType.NotSupported) { return StartServerWithQueryEngine(null, enableFedAuth, enableLog, connectionTimeout, methodName, encryptionCertificate, encryptionType); } From 2dd6fb13b7547e1ace1438faa422670b20745938 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Mon, 29 Apr 2024 13:52:35 -0700 Subject: [PATCH 43/49] Removed blank line from TestTdsServer.cs. --- .../tests/FunctionalTests/TestTdsServer.cs | 1 - .../tests/ManualTests/TracingTests/TestTdsServer.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs index 1ead74f58d..ef45bdbc7a 100644 --- a/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/FunctionalTests/TestTdsServer.cs @@ -65,6 +65,5 @@ public static TestTdsServer StartTestServer(bool enableFedAuth = false, bool ena public void Dispose() => _endpoint?.Stop(); public string ConnectionString { get; private set; } - } } diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs index af97f0a80c..a4557d72b6 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/TracingTests/TestTdsServer.cs @@ -91,6 +91,5 @@ public TestTdsServer(QueryEngine engine, TDSServerArguments args) : base(args) public void Dispose() => _endpoint?.Stop(); public string ConnectionString { get; private set; } - } } From b6770d3f067056d7183e423b3d44dd5e109678c1 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Tue, 30 Apr 2024 08:57:10 -0700 Subject: [PATCH 44/49] Make Windows and Linux certificate key length to be 4096. Enable Linux certificate as CA certificate. --- .../tests/ManualTests/makepfxcert.ps1 | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index 397db5c6cf..c7075cf9c7 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -78,6 +78,9 @@ function Invoke-SqlServerCertificateCommand { openssl x509 -trustout -addtrust "serverAuth" -in $OutDir/mismatchedcert.pem cp $OutDir/mismatchedcert.pem /usr/local/share/ca-certificates/mismatchedcert.crt + # enable certificate as CA certificate + dpkg-reconfigure ca-certificates + # Update the certificates store Write-Output "Updating the certificates store..." update-ca-certificates -v @@ -87,7 +90,7 @@ function Invoke-SqlServerCertificateCommand { Type = "SSLServerAuthentication" Subject = "CN=$fqdn" KeyAlgorithm = "RSA" - KeyLength = 2048 + KeyLength = 4096 HashAlgorithm = "SHA256" TextExtension = "2.5.29.37={text}1.3.6.1.5.5.7.3.1", "2.5.29.17={text}DNS=$fqdn&DNS=$localhost&IPAddress=$LoopBackIPV4&DNS=$sqlAliasName&IPAddress=$LoopBackIPV6" NotAfter = (Get-Date).AddMonths(36) From 43b940be4825e2d0c75efcd4fab2103af35836c9 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Tue, 30 Apr 2024 17:06:18 -0700 Subject: [PATCH 45/49] Commenbt out dpkg-reconfigure in the certificate maker script. --- .../tests/ManualTests/makepfxcert.ps1 | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index c7075cf9c7..8cdf57a204 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -53,13 +53,16 @@ function Invoke-SqlServerCertificateCommand { else { openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout $OutDir/localhostcert.key -out $OutDir/localhostcert.cer -subj "/CN=$fqdn" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" } + sudo chmod 777 $OutDir/localhostcert.key $OutDir/localhostcert.cer # Export the certificate to pfx Write-Output "Exporting certificate to pfx..." openssl pkcs12 -export -in $OutDir/localhostcert.cer -inkey $OutDir/localhostcert.key -out $OutDir/localhostcert.pfx -password pass:nopassword + sudo chmod 777 $OutDir/localhostcert.pfx Write-Output "Converting certificate to pem..." # Create pem from cer cp $OutDir/localhostcert.cer $OutDir/localhostcert.pem + sudo chmod 777 $OutDir/localhostcert.pem # Add trust to the pem certificate Write-Output "Adding trust to pem certificate..." @@ -79,7 +82,8 @@ function Invoke-SqlServerCertificateCommand { cp $OutDir/mismatchedcert.pem /usr/local/share/ca-certificates/mismatchedcert.crt # enable certificate as CA certificate - dpkg-reconfigure ca-certificates + # ---- this causes it to fail in Mac ---- + #dpkg-reconfigure ca-certificates # Update the certificates store Write-Output "Updating the certificates store..." From df87444bdd75938dc5aa16d73ac7fd12d069ba13 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Thu, 2 May 2024 10:08:35 -0700 Subject: [PATCH 46/49] Update script that creates certificate. --- .../tests/ManualTests/makepfxcert.ps1 | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index 8cdf57a204..9dcbb098f0 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -39,6 +39,7 @@ function Invoke-SqlServerCertificateCommand { # Create a self-signed certificate if ($OS -eq "Unix") { + chmod 777 $OutDir # Install OpenSSL module Install-Module -Name OpenSSL -Repository PSGallery -Force # Show version of OpenSSL just to make sure it is installed @@ -53,16 +54,16 @@ function Invoke-SqlServerCertificateCommand { else { openssl req -x509 -newkey rsa:4096 -sha256 -days 1095 -nodes -keyout $OutDir/localhostcert.key -out $OutDir/localhostcert.cer -subj "/CN=$fqdn" -addext "subjectAltName=DNS:$fqdn,DNS:localhost,IP:127.0.0.1,IP:::1" } - sudo chmod 777 $OutDir/localhostcert.key $OutDir/localhostcert.cer + chmod 777 $OutDir/localhostcert.key $OutDir/localhostcert.cer # Export the certificate to pfx Write-Output "Exporting certificate to pfx..." openssl pkcs12 -export -in $OutDir/localhostcert.cer -inkey $OutDir/localhostcert.key -out $OutDir/localhostcert.pfx -password pass:nopassword - sudo chmod 777 $OutDir/localhostcert.pfx + chmod 777 $OutDir/localhostcert.pfx Write-Output "Converting certificate to pem..." # Create pem from cer cp $OutDir/localhostcert.cer $OutDir/localhostcert.pem - sudo chmod 777 $OutDir/localhostcert.pem + chmod 777 $OutDir/localhostcert.pem # Add trust to the pem certificate Write-Output "Adding trust to pem certificate..." @@ -83,7 +84,7 @@ function Invoke-SqlServerCertificateCommand { # enable certificate as CA certificate # ---- this causes it to fail in Mac ---- - #dpkg-reconfigure ca-certificates + dpkg-reconfigure ca-certificates # Update the certificates store Write-Output "Updating the certificates store..." From 81b5a09fcffbdff3dfd986cdf312c6e3fa018310 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Thu, 2 May 2024 10:42:27 -0700 Subject: [PATCH 47/49] Added unit test wrapper for Windows and Unix. MaxOS will be excluded. --- .../CertificateTestWithTdsServer.cs | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs index eecb513cb6..9577772003 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/SQL/ConnectionTestWithSSLCert/CertificateTestWithTdsServer.cs @@ -26,7 +26,21 @@ public CertificateTestWithTdsServer() [Theory] [MemberData(nameof(ConnectionTestParametersData.GetConnectionTestParameters), MemberType = typeof(ConnectionTestParametersData))] - public void ConnectionTest(ConnectionTestParameters connectionTestParameters) + [PlatformSpecific(TestPlatforms.Windows)] + public void BeginWindowsConnectionTest(ConnectionTestParameters connectionTestParameters) + { + ConnectionTest(connectionTestParameters); + } + + [Theory] + [MemberData(nameof(ConnectionTestParametersData.GetConnectionTestParameters), MemberType = typeof(ConnectionTestParametersData))] + [PlatformSpecific(TestPlatforms.Linux)] + public void BeginLinuxConnectionTest(ConnectionTestParameters connectionTestParameters) + { + ConnectionTest(connectionTestParameters); + } + + private void ConnectionTest(ConnectionTestParameters connectionTestParameters) { string userId = string.Empty; string password = string.Empty; From faf2b14ea64a5dfa2444f1f902a0eb7611cffc1f Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Thu, 2 May 2024 10:56:46 -0700 Subject: [PATCH 48/49] Updated script so that the dpkg-reconfigure is noninteractive. --- src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 index 9dcbb098f0..a647ca9ca2 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/makepfxcert.ps1 @@ -83,8 +83,7 @@ function Invoke-SqlServerCertificateCommand { cp $OutDir/mismatchedcert.pem /usr/local/share/ca-certificates/mismatchedcert.crt # enable certificate as CA certificate - # ---- this causes it to fail in Mac ---- - dpkg-reconfigure ca-certificates + dpkg-reconfigure ca-certificates -f noninteractive -p critical # Update the certificates store Write-Output "Updating the certificates store..." From e9adb8295bee27b169355fff77814a6ae4295b26 Mon Sep 17 00:00:00 2001 From: v-arellegue Date: Thu, 2 May 2024 12:09:09 -0700 Subject: [PATCH 49/49] Add comment that possible value for certificate includes a mismatched certificate for negative test. --- .../ManualTests/DataCommon/ConnectionTestParametersData.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs index 36d9b5cc82..b95ceec88f 100644 --- a/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs +++ b/src/Microsoft.Data.SqlClient/tests/ManualTests/DataCommon/ConnectionTestParametersData.cs @@ -38,8 +38,8 @@ public ConnectionTestParametersData() // Possible values for TdsEncryptionType are Off, On, Required // Possible values for Encrypt are Optional, Mandatory // Possible values for TrustServerCertificate are true, false - // Possible values for Certificate are valid path to certificate, empty - // Possible values for HostNameInCertificate are valid hostname, empty + // Possible values for Certificate are valid path to certificate, mismatched certificate, or empty + // Possible values for HostNameInCertificate are valid hostname, or empty // TestResult is the expected result of the connection test // These combinations are based on the possible values of Encrypt, TrustServerCertificate, Certificate, HostNameInCertificate ConnectionTestParametersList = new List