Fix performance regression in SSL handshake (#66077)
authorRadek Zikmund <32671551+rzikm@users.noreply.github.com>
Mon, 7 Mar 2022 08:16:45 +0000 (09:16 +0100)
committerGitHub <noreply@github.com>
Mon, 7 Mar 2022 08:16:45 +0000 (09:16 +0100)
src/libraries/System.Net.Security/src/System/Net/CertificateValidationPal.Windows.cs

index 99c71a9..1d9f69c 100644 (file)
@@ -48,13 +48,20 @@ namespace System.Net
             SafeFreeCertContext? remoteContext = null;
             try
             {
-                // SECPKG_ATTR_REMOTE_CERT_CHAIN can be used even before the TLS handshake completes, which is necessary
-                // in order to supply the certificate to the client cert selection callback. However, it is not available on
-                // windows 7, so use the SECPKG_ATTR_REMOTE_CERT_CONTEXT as a fallback option.
-                if (!SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CHAIN(GlobalSSPI.SSPISecureChannel, securityContext, out remoteContext))
+                // SECPKG_ATTR_REMOTE_CERT_CONTEXT will not succeed before TLS handshake completes. Inside the handshake,
+                // we need to use (more expensive) SECPKG_ATTR_REMOTE_CERT_CHAIN. That one may be unsupported on older
+                // versions of windows. In that case, we have no option than to return null.
+                //
+                // We can use retrieveCollection to distinguish between in-handshake and after-handshake calls, because
+                // the collection is retrieved for cert validation purposes after the handshake completes.
+                if (retrieveCollection) // handshake completed
                 {
                     SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, securityContext, out remoteContext);
                 }
+                else // in handshake
+                {
+                    SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CHAIN(GlobalSSPI.SSPISecureChannel, securityContext, out remoteContext);
+                }
 
                 if (remoteContext != null && !remoteContext.IsInvalid)
                 {