internal static extern bool CertGetCertificateChain( [In] SafeChainEngineHandle hChainEngine, [In] SafeCertContextHandle pCertContext, [In] ref FILETIME pTime, [In] SafeCertStoreHandle hAdditionalStore, [In] ref CERT_CHAIN_PARA pChainPara, [In] uint dwFlags, [In] IntPtr pvReserved, [In, Out] ref SafeX509ChainHandle ppChainContext);
/// <summary> /// Builds and validates a certificate chain, similar to <see cref="X509Chain.Build" />. /// </summary> /// <param name="certificate">The certificate to validate.</param> /// <param name="chainPolicy">The chain policy to apply.</param> /// <param name="chain">The resulting chain, whose <see cref="X509Chain.ChainStatus"/> and <see cref="X509Chain.ChainElements"/> properties are populated.</param> /// <returns>Whether the certificate is valid accoring to the given <paramref name="chainPolicy"/></returns> /// <exception cref="System.Security.Cryptography.CryptographicException"> /// When any of the underlying Windows CryptoAPI calls fail. /// </exception> public unsafe bool BuildChain(X509Certificate2 certificate, X509ChainPolicy chainPolicy, out X509Chain chain) { SafeX509ChainHandle ppChainContext = SafeX509ChainHandle.InvalidHandle; SafeCertStoreHandle hCertStore = SafeCertStoreHandle.InvalidHandle; if (chainPolicy.ExtraStore != null && chainPolicy.ExtraStore.Count > 0) { hCertStore = ExportToMemoryStore(chainPolicy.ExtraStore); } NativeMethods.CERT_CHAIN_PARA chainPara = new NativeMethods.CERT_CHAIN_PARA(); // Initialize the structure size. chainPara.cbSize = (uint)Marshal.SizeOf(chainPara); SafeLocalAllocHandle applicationPolicyHandle = SafeLocalAllocHandle.InvalidHandle; SafeLocalAllocHandle certificatePolicyHandle = SafeLocalAllocHandle.InvalidHandle; try { // Application policy if (chainPolicy.ApplicationPolicy != null && chainPolicy.ApplicationPolicy.Count > 0) { chainPara.RequestedUsage.dwType = NativeMethods.USAGE_MATCH_TYPE_AND; chainPara.RequestedUsage.Usage.cUsageIdentifier = (uint)chainPolicy.ApplicationPolicy.Count; applicationPolicyHandle = CopyOidsToUnmanagedMemory(chainPolicy.ApplicationPolicy); chainPara.RequestedUsage.Usage.rgpszUsageIdentifier = applicationPolicyHandle.DangerousGetHandle(); } // Certificate policy if (chainPolicy.CertificatePolicy != null && chainPolicy.CertificatePolicy.Count > 0) { chainPara.RequestedIssuancePolicy.dwType = NativeMethods.USAGE_MATCH_TYPE_AND; chainPara.RequestedIssuancePolicy.Usage.cUsageIdentifier = (uint)chainPolicy.CertificatePolicy.Count; certificatePolicyHandle = CopyOidsToUnmanagedMemory(chainPolicy.CertificatePolicy); chainPara.RequestedIssuancePolicy.Usage.rgpszUsageIdentifier = certificatePolicyHandle.DangerousGetHandle(); } chainPara.dwUrlRetrievalTimeout = (uint)Math.Floor(chainPolicy.UrlRetrievalTimeout.TotalMilliseconds); FILETIME ft = new FILETIME(); *(long *)&ft = chainPolicy.VerificationTime.ToFileTime(); uint flags = MapRevocationFlags(chainPolicy.RevocationMode, chainPolicy.RevocationFlag); using (SafeCertContextHandle certContextHandle = NativeMethods.CertDuplicateCertificateContext(certificate.Handle)) { // Build the chain. if (!NativeMethods.CertGetCertificateChain(hChainEngine: this.safeChainEngineHandle, pCertContext: certContextHandle, pTime: ref ft, hAdditionalStore: hCertStore, pChainPara: ref chainPara, dwFlags: flags, pvReserved: IntPtr.Zero, ppChainContext: ref ppChainContext)) { throw new CryptographicException(Marshal.GetHRForLastWin32Error()); } chain = new X509Chain(ppChainContext.DangerousGetHandle()) { ChainPolicy = chainPolicy }; // Verify the chain using the specified policy. NativeMethods.CERT_CHAIN_POLICY_PARA policyPara = new NativeMethods.CERT_CHAIN_POLICY_PARA(Marshal.SizeOf(typeof(NativeMethods.CERT_CHAIN_POLICY_PARA))); NativeMethods.CERT_CHAIN_POLICY_STATUS policyStatus = new NativeMethods.CERT_CHAIN_POLICY_STATUS(Marshal.SizeOf(typeof(NativeMethods.CERT_CHAIN_POLICY_STATUS))); policyPara.dwFlags = (uint)chainPolicy.VerificationFlags; if (!NativeMethods.CertVerifyCertificateChainPolicy( pszPolicyOID: new IntPtr(NativeMethods.CERT_CHAIN_POLICY_BASE), pChainContext: ppChainContext, pPolicyPara: ref policyPara, pPolicyStatus: ref policyStatus)) { throw new CryptographicException(Marshal.GetLastWin32Error()); } NativeMethods.SetLastError(policyStatus.dwError); return(policyStatus.dwError == 0); } } finally { applicationPolicyHandle.Dispose(); certificatePolicyHandle.Dispose(); } }
internal static extern bool CertVerifyCertificateChainPolicy( [In] IntPtr pszPolicyOID, [In] SafeX509ChainHandle pChainContext, [In] ref CERT_CHAIN_POLICY_PARA pPolicyPara, [In, Out] ref CERT_CHAIN_POLICY_STATUS pPolicyStatus);