// // 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); }
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); }