//
        // Extracts a remote certificate upon request.
        //

        private static X509Certificate2?GetRemoteCertificate(
            SafeDeleteContext?securityContext, bool retrieveChainCertificates, ref X509Chain?chain)
        {
            if (securityContext == null)
            {
                return(null);
            }

            X509Certificate2?   result        = null;
            SafeFreeCertContext?remoteContext = null;

            try
            {
                // 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 (retrieveChainCertificates) // 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)
                {
                    result = new X509Certificate2(remoteContext.DangerousGetHandle());
                }
            }
            finally
            {
                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    if (retrieveChainCertificates)
                    {
                        chain ??= new X509Chain();

                        UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext, chain.ChainPolicy.ExtraStore);
                    }

                    remoteContext.Dispose();
                }
            }

            if (NetEventSource.Log.IsEnabled())
            {
                NetEventSource.Log.RemoteCertificate(result);
            }
            return(result);
        }
Ejemplo n.º 2
0
        private static X509Certificate2?GetRemoteCertificate(
            SafeDeleteContext?securityContext, bool retrieveCollection, out X509Certificate2Collection?remoteCertificateCollection)
        {
            remoteCertificateCollection = null;

            if (securityContext == null)
            {
                return(null);
            }

            X509Certificate2?   result        = null;
            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))
                {
                    SSPIWrapper.QueryContextAttributes_SECPKG_ATTR_REMOTE_CERT_CONTEXT(GlobalSSPI.SSPISecureChannel, securityContext, out remoteContext);
                }

                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    result = new X509Certificate2(remoteContext.DangerousGetHandle());
                }
            }
            finally
            {
                if (remoteContext != null && !remoteContext.IsInvalid)
                {
                    if (retrieveCollection)
                    {
                        remoteCertificateCollection = UnmanagedCertificateContext.GetRemoteCertificatesFromStoreContext(remoteContext);
                    }

                    remoteContext.Dispose();
                }
            }

            if (NetEventSource.Log.IsEnabled())
            {
                NetEventSource.Log.RemoteCertificate(result);
            }
            return(result);
        }