using System;
using System.Runtime.InteropServices;
using Vanara.Extensions;
using Vanara.InteropServices;
using FILETIME = System.Runtime.InteropServices.ComTypes.FILETIME;

namespace Vanara.PInvoke
{
	/// <summary>Methods and data types found in Crypt32.dll.</summary>
	public static partial class Crypt32
	{
		/// <summary>Flags used by <see cref="CERT_CHAIN_ENGINE_CONFIG"/>.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "9e010eb9-2cbb-4fca-ba5c-4a5a50f23786")]
		[Flags]
		public enum CertChainEngineExclusiveFlags
		{
			/// <summary>
			/// Indicates that a non-self-signed intermediate CA certificate in the hExclusiveRoot store should be treated as a trust anchor
			/// during certificate validation. If a certificate chains up to this CA, chain building is terminated and the certificate is
			/// considered trusted. No signature verification or revocation checking is performed on the CA certificate.
			/// <para>
			/// By default, if this flag is not set, only self-signed certificates in the hExclusiveRoot store are treated as trust anchors.
			/// </para>
			/// <para>See also the CERT_TRUST_IS_CA_TRUSTED value in the CERT_TRUST_STATUS structure.</para>
			/// </summary>
			CERT_CHAIN_EXCLUSIVE_ENABLE_CA_FLAG = 0x00000001,
		}

		/// <summary>Flags used by <see cref="CERT_CHAIN_ENGINE_CONFIG"/>.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "9e010eb9-2cbb-4fca-ba5c-4a5a50f23786")]
		[Flags]
		public enum CertChainEngineFlags
		{
			/// <summary>
			/// Information in the end certificate is cached. By default, information in all certificates except the end certificate is
			/// cached as a chain is built. Setting this flag extends the caching to the end certificate.
			/// </summary>
			CERT_CHAIN_CACHE_END_CERT = 0x00000001,

			/// <summary/>
			CERT_CHAIN_THREAD_STORE_SYNC = 0x00000002,

			/// <summary>
			/// Use only cached URLs in building a certificate chain. The Internet and intranet are not searched for URL-based objects.
			/// </summary>
			CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL = 0x00000004,

			/// <summary>Build the chain using the LocalMachine registry location as opposed to the CurrentUser location.</summary>
			CERT_CHAIN_USE_LOCAL_MACHINE_STORE = 0x00000008,

			/// <summary>Enable automatic updating of the cache as a chain is being built.</summary>
			CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE = 0x00000010,

			/// <summary>Allow certificate stores used to build the chain to be shared.</summary>
			CERT_CHAIN_ENABLE_SHARE_STORE = 0x00000020,

			/// <summary>Turn off Authority Information Access (AIA) retrievals explicitly.</summary>
			CERT_CHAIN_DISABLE_AIA = 0x00002000,
		}

		/// <summary>Flags used by <see cref="CertGetCertificateChain(HCERTCHAINENGINE, PCCERT_CONTEXT, in FILETIME, HCERTSTORE, in CERT_CHAIN_PARA, CertChainFlags, IntPtr, out SafePCCERT_CHAIN_CONTEXT)"/>.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "8c93036c-0b93-40d4-b0e3-ba1f2fc72db1")]
		[Flags]
		public enum CertChainFlags : uint
		{
			/// <summary>
			/// When this flag is set, the end certificate is cached, which might speed up the chain-building process. By default, the end
			/// certificate is not cached, and it would need to be verified each time a chain is built for it.
			/// </summary>
			CERT_CHAIN_CACHE_END_CERT = 0x00000001,

			/// <summary>Revocation checking only accesses cached URLs.</summary>
			CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY = 0x80000000,

			/// <summary>
			/// This flag is used internally during chain building for an online certificate status protocol (OCSP) signer certificate to
			/// prevent cyclic revocation checks. During chain building, if the OCSP response is signed by an independent OCSP signer, then,
			/// in addition to the original chain build, there is a second chain built for the OCSP signer certificate itself. This flag is
			/// used during this second chain build to inhibit a recursive independent OCSP signer certificate. If the signer certificate
			/// contains the szOID_PKIX_OCSP_NOCHECK extension, revocation checking is skipped for the leaf signer certificate. Both OCSP
			/// and CRL checking are allowed.
			/// <para>Windows Server 2003 and Windows XP: This value is not supported.</para>
			/// </summary>
			CERT_CHAIN_REVOCATION_CHECK_OCSP_CERT = 0x04000000,

			/// <summary>
			/// Uses only cached URLs in building a certificate chain. The Internet and intranet are not searched for URL-based objects.
			/// <para>
			/// Note This flag is not applicable to revocation checking. Set CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY to use only cached URLs
			/// for revocation checking.
			/// </para>
			/// </summary>
			CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL = 0x00000004,

			/// <summary>
			/// For performance reasons, the second pass of chain building only considers potential chain paths that have quality greater
			/// than or equal to the highest quality determined during the first pass. The first pass only considers valid signature,
			/// complete chain, and trusted roots to calculate chain quality. This flag can be set to disable this optimization and consider
			/// all potential chain paths during the second pass.
			/// </summary>
			CERT_CHAIN_DISABLE_PASS1_QUALITY_FILTERING = 0x00000040,

			/// <summary>This flag is not supported. Certificates in the "My" store are never considered for peer trust.</summary>
			CERT_CHAIN_DISABLE_MY_PEER_TRUST = 0x00000800,

			/// <summary>
			/// End entity certificates in the "TrustedPeople" store are trusted without performing any chain building. This function does
			/// not set the CERT_TRUST_IS_PARTIAL_CHAIN or CERT_TRUST_IS_UNTRUSTED_ROOT dwErrorStatus member bits of the ppChainContext
			/// parameter. Windows Server 2003 Windows XP : This flag is not supported.
			/// </summary>
			CERT_CHAIN_ENABLE_PEER_TRUST = 0x00000400,

			/// <summary>
			/// Setting this flag indicates the caller wishes to opt into weak signature checks.
			/// <para>This flag is available in the rollup update for each OS starting with Windows 7 and Windows Server 2008 R2.</para>
			/// </summary>
			CERT_CHAIN_OPT_IN_WEAK_SIGNATURE = 0x00010000,

			/// <summary>
			/// The default is to return only the highest quality chain path. Setting this flag will return the lower quality chains. These
			/// are returned in the cLowerQualityChainContext and rgpLowerQualityChainContext fields of the chain context.
			/// </summary>
			CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS = 0x00000080,

			/// <summary>Setting this flag inhibits the auto update of third-party roots from the Windows Update Web Server.</summary>
			CERT_CHAIN_DISABLE_AUTH_ROOT_AUTO_UPDATE = 0x00000100,

			/// <summary>
			/// When you set CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT and you also specify a value for the dwUrlRetrievalTimeout member of
			/// the CERT_CHAIN_PARA structure, the value you specify in dwUrlRetrievalTimeout represents the cumulative timeout across all
			/// revocation URL retrievals.
			/// <para>
			/// If you set CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT but do not specify a dwUrlRetrievalTimeout value, the maximum
			/// cumulative timeout is set, by default, to 20 seconds. Each URL tested will timeout after half of the remaining cumulative
			/// balance has passed. That is, the first URL times out after 10 seconds, the second after 5 seconds, the third after 2.5
			/// seconds and so on until a URL succeeds, 20 seconds has passed, or there are no more URLs to test.
			/// </para>
			/// <para>
			/// If you do not set CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT, each revocation URL in the chain is assigned a maximum timeout
			/// equal to the value specified in dwUrlRetrievalTimeout. If you do not specify a value for the dwUrlRetrievalTimeout member,
			/// each revocation URL is assigned a maximum default timeout of 15 seconds. If no URL succeeds, the maximum cumulative timeout
			/// value is 15 seconds multiplied by the number of URLs in the chain.
			/// </para>
			/// <para>You can set the default values by using Group Policy.</para>
			/// </summary>
			CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT = 0x08000000,

			/// <summary>
			/// When this flag is set, pTime is used as the time stamp time to determine whether the end certificate was time valid. Current
			/// time can also be used to determine whether the end certificate remains time valid. All other certification authority (CA)
			/// and root certificates in the chain are checked by using current time and not pTime.
			/// </summary>
			CERT_CHAIN_TIMESTAMP_TIME = 0x00000200,

			/// <summary>Setting this flag explicitly turns off Authority Information Access (AIA) retrievals.</summary>
			CERT_CHAIN_DISABLE_AIA = 0x00002000,

			/// <summary>Revocation checking is done on the end certificate and only the end certificate.</summary>
			CERT_CHAIN_REVOCATION_CHECK_END_CERT = 0x10000000,

			/// <summary>Revocation checking is done on all of the certificates in every chain.</summary>
			CERT_CHAIN_REVOCATION_CHECK_CHAIN = 0x20000000,

			/// <summary>Revocation checking is done on all certificates in all of the chains except the root certificate.</summary>
			CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT = 0x40000000,
		}

		/// <summary>Flags used by <see cref="CERT_CHAIN_POLICY_PARA"/></summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "5e4fffcb-132b-42c0-81b2-9f866e274c32")]
		[Flags]
		public enum CertChainPolicyFlags : uint
		{
			/// <summary>Ignore not time valid errors.</summary>
			CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG = 0x00000001,

			/// <summary>Ignore certificate trust list (CTL) not time valid errors.</summary>
			CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG = 0x00000002,

			/// <summary>Ignore time nesting errors.</summary>
			CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG = 0x00000004,

			/// <summary>Ignore basic constraint errors.</summary>
			CERT_CHAIN_POLICY_IGNORE_INVALID_BASIC_CONSTRAINTS_FLAG = 0x00000008,

			/// <summary>Ignore all time validity errors.</summary>
			CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS = (CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG | CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG | CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG),

			/// <summary>Allow untrusted roots.</summary>
			CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG = 0x00000010,

			/// <summary>Ignore invalid usage errors.</summary>
			CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG = 0x00000020,

			/// <summary>Ignore invalid name errors.</summary>
			CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG = 0x00000040,

			/// <summary>Ignore invalid policy errors.</summary>
			CERT_CHAIN_POLICY_IGNORE_INVALID_POLICY_FLAG = 0x00000080,

			/// <summary>Ignores errors in obtaining valid revocation information.</summary>
			CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG = 0x00000100,

			/// <summary>Ignores errors in obtaining valid CTL revocation information.</summary>
			CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG = 0x00000200,

			/// <summary>Ignores errors in obtaining valid certification authority (CA) revocation information.</summary>
			CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG = 0x00000400,

			/// <summary>Ignores errors in obtaining valid root revocation information.</summary>
			CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG = 0x00000800,

			/// <summary>Ignores errors in obtaining valid revocation information.</summary>
			CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS = (CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG | CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG | CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG | CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG),

			/// <summary>Allow untrusted test roots.</summary>
			CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG = 0x00008000,

			/// <summary>Always trust test roots.</summary>
			CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG = 0x00004000,

			/// <summary>Ignore critical extension not supported errors.</summary>
			CERT_CHAIN_POLICY_IGNORE_NOT_SUPPORTED_CRITICAL_EXT_FLAG = 0x00002000,

			/// <summary>Ignore peer trusts.</summary>
			CERT_CHAIN_POLICY_IGNORE_PEER_TRUST_FLAG = 0x00001000,

			/// <summary/>
			CERT_CHAIN_POLICY_IGNORE_WEAK_SIGNATURE_FLAG = 0x08000000,

			/// <summary>Checks if the first certificate element is a CA.</summary>
			BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_CA_FLAG = 0x80000000,

			/// <summary>Checks if the first certificate element is an end entity.</summary>
			BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_END_ENTITY_FLAG = 0x40000000,

			/// <summary>Also check for the Microsoft test roots in addition to the Microsoft public root.</summary>
			MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG = 0x00010000,

			/// <summary/>
			MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG = 0x00020000,

			/// <summary/>
			MICROSOFT_ROOT_CERT_CHAIN_POLICY_DISABLE_FLIGHT_ROOT_FLAG = 0x00040000,
		}

		/// <summary>Optional flags that modify chain retrieval behavior.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "86094e1c-be59-4a15-a05b-21769f80e653")]
		[Flags]
		public enum CertChainStrongSignFlags
		{
			/// <summary>
			/// If the chain is strong signed, the public key in the end certificate will be checked to verify whether it satisfies the
			/// minimum public key length requirements for a strong signature. You can specify CERT_CHAIN_STRONG_SIGN_DISABLE_END_CHECK_FLAG
			/// to disable default checking.
			/// </summary>
			CERT_CHAIN_STRONG_SIGN_DISABLE_END_CHECK_FLAG = 0x00000001,
		}

		/// <summary>Flags used by <see cref="CertCreateCTLEntryFromCertificateContextProperties"/>.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "90ac512f-3cbe-4543-9b34-8e384f730cfe")]
		[Flags]
		public enum CertCreateCTLEntryFlags
		{
			/// <summary>Force the inclusion of the chain building hash properties as attributes.</summary>
			CTL_ENTRY_FROM_PROP_CHAIN_FLAG = 1
		}

		/// <summary>Flags for CertVerifyCTLUsage.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "d87d8157-8e52-4198-bfd4-46d83d72eb13")]
		[Flags]
		public enum CertVerifyCTLFlags
		{
			/// <summary>
			/// If the CERT_VERIFY_INHIBIT_CTL_UPDATE_FLAG is not set, a CTL whose time is no longer valid in one of the stores specified by
			/// rghCtlStore in CTL_VERIFY_USAGE_PARA can be replaced. When replaced, the CERT_VERIFY_UPDATED_CTL_FLAG is set in the dwFlags
			/// member of pVerifyUsageStatus. If this flag is set, an update will not be made, even if a time-valid, updated CTL is received
			/// for a CTL that is in the store and whose time is no longer valid.
			/// </summary>
			CERT_VERIFY_INHIBIT_CTL_UPDATE_FLAG = 0x1,

			/// <summary>
			/// If the CERT_VERIFY_TRUSTED_SIGNERS_FLAG is set, only the signer stores specified by rghSignerStore in CTL_VERIFY_USAGE_PARA
			/// are searched to find the signer. Otherwise, the signer stores provide additional sources to find the signer's certificate.
			/// </summary>
			CERT_VERIFY_TRUSTED_SIGNERS_FLAG = 0x2,

			/// <summary>If CERT_VERIFY_NO_TIME_CHECK_FLAG is set, the CTLs are not checked for time validity. Otherwise, they are.</summary>
			CERT_VERIFY_NO_TIME_CHECK_FLAG = 0x4,

			/// <summary>
			/// If CERT_VERIFY_ALLOW_MORE_USAGE_FLAG is set, the CTL can contain usage identifiers in addition to those specified by
			/// pSubjectUsage. Otherwise, the found CTL will contain no additional usage identifiers.
			/// </summary>
			CERT_VERIFY_ALLOW_MORE_USAGE_FLAG = 0x8,
		}

		/// <summary>Flags used by <see cref="CryptMsgEncodeAndSignCTL"/>.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "5c0e9e2e-a50d-45d0-b51d-065784d1d912")]
		[Flags]
		public enum CryptMsgEncodeFlags
		{
			/// <summary>
			/// Set if the CTL entries are to be sorted before encoding. This flag is set if the CertFindSubjectInSortedCTL or
			/// CertEnumSubjectInSortedCTL functions will be called.
			/// </summary>
			CMSG_ENCODE_SORTED_CTL_FLAG = 0x1,

			/// <summary>
			/// Set if CMSG_ENCODE_SORTED_CTL_FLAG is set, and the identifier for the TrustedSubjects is a hash, such as MD5 or SHA1.
			/// </summary>
			CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG = 0x2,
		}

		/// <summary>Flags for <see cref="CryptMsgGetAndVerifySigner"/>.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "380c9cf3-27a2-4354-b1c8-97cec33f4e44")]
		[Flags]
		public enum CryptMsgSignerFlags
		{
			/// <summary>
			/// The stores in rghSignerStore are assumed trusted and they are the only stores searched to find the certificate corresponding
			/// to the signer's issuer and serial number. Otherwise, signer stores can be provided to supplement the message's store of
			/// certificates. If a signer certificate is found, its public key is used to verify the message signature.
			/// </summary>
			CMSG_TRUSTED_SIGNER_FLAG = 0x1,

			/// <summary>Return the signer without doing the signature verification.</summary>
			CMSG_SIGNER_ONLY_FLAG = 0x2,

			/// <summary>
			/// Only the signer specified by *pdwSignerIndex is returned. Otherwise, iterate through all the signers until a signature is
			/// verified or there are no more signers.
			/// </summary>
			CMSG_USE_SIGNER_INDEX_FLAG = 0x4,
		}

		/// <summary>Flags for <see cref="CryptMsgSignCTL"/>.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "85ae8ce3-d0a7-4fcb-beaa-ede09d30930e")]
		[Flags]
		public enum CryptMsgSignFlags
		{
			/// <summary>
			/// If CMS_PKCS7 is defined, can be set to CMSG_CMS_ENCAPSULATED_CTL_FLAG to encode a CMS compatible V3 SignedData message.
			/// </summary>
			CMSG_CMS_ENCAPSULATED_CTL_FLAG = 0x00008000
		}

		/// <summary>Flags returned in CTL_VERIFY_USAGE_STATUS.</summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "2b7ef953-9422-4dcf-b293-a78a06bb080e")]
		[Flags]
		public enum CtlVerifyUsageStatusFlags
		{
			/// <summary>CertVerifyCTLUsage updated a CTL whose time was no longer valid with a new, time-valid CTL.</summary>
			CERT_VERIFY_UPDATED_CTL_FLAG = 0x1
		}

		/// <summary>
		/// Determines the kind of issuer matching to be done. In <c>AND</c> logic, the certificate must meet all criteria. In <c>OR</c>
		/// logic, the certificate must meet at least one of the criteria.
		/// </summary>
		[PInvokeData("wincrypt.h", MSDNShortId = "6154f1f7-4293-4b8e-91ab-9f57bb6f5743")]
		public enum UsageMatchType
		{
			/// <summary>AND logic</summary>
			USAGE_MATCH_TYPE_AND = 0x00000000,

			/// <summary>OR logic</summary>
			USAGE_MATCH_TYPE_OR = 0x00000001,
		}

		/// <summary>
		/// The <c>CertCreateCertificateChainEngine</c> function creates a new, nondefault chain engine for an application. A chain engine
		/// restricts the certificates in the root store that can be used for verification, restricts the certificate stores to be searched
		/// for certificates and certificate trust lists (CTLs), sets a time-out limit for searches that involve URLs, and limits the number
		/// of certificates checked between checking for a certificate cycle.
		/// </summary>
		/// <param name="pConfig">A pointer to a CERT_CHAIN_ENGINE_CONFIG data structure that specifies the parameters for the chain engine.</param>
		/// <param name="phChainEngine">
		/// A pointer to the handle of the chain engine created. When you have finished using the chain engine, release the chain engine by
		/// calling the CertFreeCertificateChainEngine function.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, it returns zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// <para>The phChainEngine parameter returns the chain engine handle.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certcreatecertificatechainengine BOOL
		// CertCreateCertificateChainEngine( PCERT_CHAIN_ENGINE_CONFIG pConfig, HCERTCHAINENGINE *phChainEngine );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "e173016a-d3d7-42e0-aad8-e738abaf1df9")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CertCreateCertificateChainEngine(in CERT_CHAIN_ENGINE_CONFIG pConfig, out SafeHCERTCHAINENGINE phChainEngine);

		/// <summary>
		/// <para>
		/// The <c>CertCreateCTLEntryFromCertificateContextProperties</c> function creates a certificate trust list (CTL) entry whose
		/// attributes are the properties of the certificate context. The SubjectIdentifier in the CTL entry is the SHA1 hash of the certificate.
		/// </para>
		/// <para>
		/// The certificate properties are added as attributes. The property attribute OID is the decimal PROP_ID preceded by
		/// szOID_CERT_PROP_ID_PREFIX. Each property value is copied as a single attribute value.
		/// </para>
		/// <para>Additional attributes can be included in the CTL entry by using the cOptAttr and rgOptAttr parameters.</para>
		/// </summary>
		/// <param name="pCertContext">A pointer to the CERT_CONTEXT used to create the CTL.</param>
		/// <param name="cOptAttr">A <c>DWORD</c> that specifies the number of additional attributes to be added.</param>
		/// <param name="rgOptAttr">A pointer to any array of CRYPT_ATTRIBUTE attributes to be added to the CTL.</param>
		/// <param name="dwFlags">
		/// A <c>DWORD</c>. Can be set to CTL_ENTRY_FROM_PROP_CHAIN_FLAG to force the inclusion of the chain building hash properties as attributes.
		/// </param>
		/// <param name="pvReserved">A pointer to a <c>VOID</c>. Reserved for future use.</param>
		/// <param name="pCtlEntry">
		/// Address of a pointer to a CTL_ENTRY structure. Call this function twice to retrieve a CTL entry. Set this parameter to
		/// <c>NULL</c> on the first call. When the function returns, use the number of bytes retrieved from the pcbCtlEntry parameter to
		/// allocate memory. Call the function again, setting this parameter to the address of the allocated memory.
		/// </param>
		/// <param name="pcbCtlEntry">
		/// Pointer to a <c>DWORD</c> that contains the number of bytes that must be allocated for the CTL_ENTRY structure. Call this
		/// function twice to retrieve the number of bytes. For the first call, set this parameter to the address of a <c>DWORD</c> value
		/// that contains zero and set the pCtlEntry parameter to <c>NULL</c>. If the first call succeeds, the <c>DWORD</c> value will
		/// contain the number of bytes that you must allocate for the <c>CTL_ENTRY</c> structure. Allocate the required memory and call the
		/// function again, supplying the address of the memory in the pCtlEntry parameter.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, it returns zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certcreatectlentryfromcertificatecontextproperties BOOL
		// CertCreateCTLEntryFromCertificateContextProperties( PCCERT_CONTEXT pCertContext, DWORD cOptAttr, PCRYPT_ATTRIBUTE rgOptAttr,
		// DWORD dwFlags, void *pvReserved, PCTL_ENTRY pCtlEntry, DWORD *pcbCtlEntry );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "90ac512f-3cbe-4543-9b34-8e384f730cfe")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CertCreateCTLEntryFromCertificateContextProperties([In] PCCERT_CONTEXT pCertContext, uint cOptAttr, [In, MarshalAs(UnmanagedType.LPArray)] CRYPT_ATTRIBUTE[] rgOptAttr,
			CertCreateCTLEntryFlags dwFlags, [Optional] IntPtr pvReserved, [Out] IntPtr pCtlEntry, ref uint pcbCtlEntry);

		/// <summary>
		/// The <c>CertDuplicateCertificateChain</c> function duplicates a pointer to a certificate chain by incrementing the chain's
		/// reference count.
		/// </summary>
		/// <param name="pChainContext">A pointer to a CERT_CHAIN_CONTEXT chain context to be duplicated.</param>
		/// <returns>
		/// <para>
		/// If the function succeeds, a pointer is returned to the chain context. This pointer has the same value as the pChainContext
		/// passed into the function. When you have finished using the chain context, release the chain context by calling the
		/// CertFreeCertificateChain function.
		/// </para>
		/// <para>If the function fails, <c>NULL</c> is returned.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certduplicatecertificatechain PCCERT_CHAIN_CONTEXT
		// CertDuplicateCertificateChain( PCCERT_CHAIN_CONTEXT pChainContext );
		[DllImport(Lib.Crypt32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "fea72a3e-5a22-47c7-8f6e-0d76fc3339f8")]
		public static extern PCCERT_CHAIN_CONTEXT CertDuplicateCertificateChain(PCCERT_CHAIN_CONTEXT pChainContext);

		/// <summary>
		/// The <c>CertFindChainInStore</c> function finds the first or next certificate in a store that meets the specified criteria. It
		/// then builds and verifies a certificate chain context for that certificate. The certificate that is found and for which the chain
		/// is built is selected according to criteria established by the dwFindFlags, dwFindType, and pvFindPara parameters. This function
		/// can be used in a loop to find all of the certificates in a certificate store that match the specified find criteria and to build
		/// a certificate chain context for each certificate found.
		/// </summary>
		/// <param name="hCertStore">
		/// The handle of the store to be searched for a certificate upon which a chain is built. This handle is passed as an additional
		/// store to the CertGetCertificateChain function as the chain is built.
		/// </param>
		/// <param name="dwCertEncodingType">
		/// <para>
		/// The certificate encoding type that was used to encode the store. The message encoding type identifier, contained in the high
		/// <c>WORD</c> of this value, is ignored by this function.
		/// </para>
		/// <para>This parameter can be the following currently defined certificate encoding type.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>X509_ASN_ENCODING 1 (0x1)</term>
		/// <term>Specifies X.509 certificate encoding.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="dwFindFlags">
		/// <para>
		/// Contains additional options for the search. The possible values for this parameter depend on the value of the dwFindType parameter.
		/// </para>
		/// <para>This parameter can contain zero or a combination of one or more of the following values when dwFindType contains <c>CERT_CHAIN_FIND_BY_ISSUER</c>.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CERT_CHAIN_FIND_BY_ISSUER_COMPARE_KEY_FLAG</term>
		/// <term>
		/// Compares the public key in the certificate with the cryptographic service provider's public key. This comparison is the last
		/// check made on the chain when it is built. Because the hCryptProv member of an issuer contains a private key, it might need to be
		/// checked several times during this process; to facilitate this checking, the dwAcquirePrivateKeyFlags member can be set in the
		/// CERT_CHAIN_FIND_BY_ISSUER_PARA structure to enable caching of that hCryptProv.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_FIND_BY_ISSUER_COMPLEX_CHAIN_FLAG</term>
		/// <term>
		/// By default, only the first simple chain is checked for issuer name matches. With this flag set, the default is overridden and
		/// subsequent simple chains are also checked for issuer name matches.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_FLAG</term>
		/// <term>
		/// Improves the performance of this function by causing it to search only the cached system stores (Root, My, Ca, Trust) to find
		/// issuer certificates. If this flag is not set, the function searches the cached system stores and the store represented by the
		/// hCertStore parameter.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_FIND_BY_ISSUER_CACHE_ONLY_URL_FLAG</term>
		/// <term>Only the URL cache is searched. The Internet is not searched.</term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_FIND_BY_ISSUER_LOCAL_MACHINE_FLAG</term>
		/// <term>Only opens the Local Machine certificate stores. The certificate stores of the current user are not opened.</term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_FIND_BY_ISSUER_NO_KEY_FLAG</term>
		/// <term>No check is made to determine whether the certificate has an associated private key.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="dwFindType">
		/// <para>Determines what criteria to use to find a certificate in the store.</para>
		/// <para>This parameter can be the following currently defined value.</para>
		/// <para>CERT_CHAIN_FIND_BY_ISSUER</para>
		/// <para>
		/// Finds the certificate based on the name of the issuer. The pvFindPara parameter is a pointer to a CERT_CHAIN_FIND_BY_ISSUER_PARA
		/// structure that contains members that modify the search.
		/// </para>
		/// <para>
		/// The certificate chain is built for a certificate with an available private key. By default, only the issuers in the first simple
		/// chain are compared in an issuer name match. If this flag is set, all of the chains are checked for an issuer certificate that
		/// matches one of a set of issuer names.
		/// </para>
		/// <para>
		/// This function will compare the name BLOBs passed in the pvFindPara structure to any certification authority (CA) in the chain,
		/// not just the certification authority in the root certificate.
		/// </para>
		/// <para>This function does not perform any revocation checks.</para>
		/// <para>
		/// If pPrevChainContext is not <c>NULL</c>, this function will return a chain for a different certificate every time the function
		/// is called. If there is only one suitable certificate, but there are two matching issuing certificate authorities, one of which
		/// is revoked, it is possible for this function to return the revoked chain. If the application then checks for revocation itself
		/// through calls to the CertVerifyRevocation function and finds the chain unsuitable, an additional call to the
		/// <c>CertFindChainInStore</c> function will not return a chain that includes the same certificate from the valid certification
		/// authority. It will instead return a completely different chain with a different certificate or <c>NULL</c>, if no such chain can
		/// be found.
		/// </para>
		/// </param>
		/// <param name="pvFindPara">
		/// A pointer that contains additional search criteria. The type and format of the data this parameter points to depends on the
		/// value of the dwFindType parameter.
		/// </param>
		/// <param name="pPrevChainContext">
		/// A pointer to a CERT_CHAIN_CONTEXT structure returned from a previous call to this function. The search is begun from this
		/// certificate. For the first call to this function, this parameter must be <c>NULL</c>. In subsequent calls, it is the pointer
		/// returned by the previous call to the function. If this parameter is not <c>NULL</c>, this function will free this structure.
		/// </param>
		/// <returns>
		/// If the first or next chain context is not built, <c>NULL</c> is returned. Otherwise, a pointer to a read-only CERT_CHAIN_CONTEXT
		/// structure is returned. The <c>CERT_CHAIN_CONTEXT</c> structure is freed when passed as the pPrevChainContext parameter on a
		/// subsequent call to this function. Otherwise, the <c>CERT_CHAIN_CONTEXT</c> structure must be freed explicitly by calling the
		/// CertFreeCertificateChain function.
		/// </returns>
		/// <remarks>
		/// The pPrevChainContext parameter must be <c>NULL</c> on the first call to build the chain context. To build the next chain
		/// context, the pPrevChainContext is set to the CERT_CHAIN_CONTEXT structure returned by a previous call. If pPrevChainContext is
		/// not <c>NULL</c>, the structure is always freed by this function by using the CertFreeCertificateChain function, even if an error occurs.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certfindchaininstore PCCERT_CHAIN_CONTEXT
		// CertFindChainInStore( HCERTSTORE hCertStore, DWORD dwCertEncodingType, DWORD dwFindFlags, DWORD dwFindType, const void
		// *pvFindPara, PCCERT_CHAIN_CONTEXT pPrevChainContext );
		[DllImport(Lib.Crypt32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "698cece8-71a8-4bfa-8ee6-8035a6dcbe05")]
		public static extern SafePCCERT_CHAIN_CONTEXT CertFindChainInStore(HCERTSTORE hCertStore, uint dwCertEncodingType, uint dwFindFlags, uint dwFindType, IntPtr pvFindPara, PCCERT_CHAIN_CONTEXT pPrevChainContext);

		/// <summary>
		/// <para>
		/// The <c>CertFreeCertificateChain</c> function frees a certificate chain by reducing its reference count. If the reference count
		/// becomes zero, memory allocated for the chain is released.
		/// </para>
		/// <para>
		/// To free a context obtained by a get, duplicate, or create function, call the appropriate free function. To free a context
		/// obtained by a find or enumerate function, either pass it in as the previous context parameter to a subsequent invocation of the
		/// function, or call the appropriate free function. For more information, see the reference topic for the function that obtains the context.
		/// </para>
		/// </summary>
		/// <param name="pChainContext">
		/// A pointer to a CERT_CHAIN_CONTEXT certificate chain context to be freed. If the reference count on the context reaches zero, the
		/// storage allocated for the context is freed.
		/// </param>
		/// <returns>This function does not return a value.</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certfreecertificatechain void CertFreeCertificateChain(
		// PCCERT_CHAIN_CONTEXT pChainContext );
		[DllImport(Lib.Crypt32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "5ba181c2-6936-4848-a571-2bb58f46f081")]
		public static extern void CertFreeCertificateChain(PCCERT_CHAIN_CONTEXT pChainContext);

		/// <summary>The <c>CertFreeCertificateChainEngine</c> function frees a certificate trust engine.</summary>
		/// <param name="hChainEngine">Handle of the chain engine to be freed.</param>
		/// <returns>This function does not return a value.</returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certfreecertificatechainengine void
		// CertFreeCertificateChainEngine( HCERTCHAINENGINE hChainEngine );
		[DllImport(Lib.Crypt32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "5aebc09d-342d-4938-8a1a-0cbfdc147bb5")]
		public static extern void CertFreeCertificateChainEngine(HCERTCHAINENGINE hChainEngine);

		/// <summary>The <c>CertFreeCertificateChainList</c> function frees the array of pointers to chain contexts.</summary>
		/// <param name="prgpSelection">A pointer to a PCCERT_CHAIN_CONTEXT structure returned by the CertSelectCertificateChains function.</param>
		/// <returns>This function does not return a value.</returns>
		/// <remarks>
		/// Before calling the <c>CertFreeCertificateChainList</c> function, you must call the CertFreeCertificateChain function on each
		/// chain context within the array pointed to by the prgpSelection parameter.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certfreecertificatechainlist void
		// CertFreeCertificateChainList( PCCERT_CHAIN_CONTEXT *prgpSelection );
		[DllImport(Lib.Crypt32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "a53b02ca-bc3f-43fd-8c90-2f646d550182")]
		public static extern void CertFreeCertificateChainList(in IntPtr prgpSelection);

		/// <summary>
		/// The <c>CertGetCertificateChain</c> function builds a certificate chain context starting from an end certificate and going back,
		/// if possible, to a trusted root certificate.
		/// </summary>
		/// <param name="hChainEngine">
		/// A handle of the chain engine (namespace and cache) to be used. If hChainEngine is <c>NULL</c>, the default chain engine,
		/// HCCE_CURRENT_USER, is used. This parameter can be set to HCCE_LOCAL_MACHINE.
		/// </param>
		/// <param name="pCertContext">
		/// A pointer to the CERT_CONTEXT of the end certificate, the certificate for which a chain is being built. This certificate context
		/// will be the zero-index element in the first simple chain.
		/// </param>
		/// <param name="pTime">
		/// A pointer to a FILETIME variable that indicates the time for which the chain is to be validated. Note that the time does not
		/// affect trust list, revocation, or root store checking. The current system time is used if <c>NULL</c> is passed to this
		/// parameter. Trust in a particular certificate being a trusted root is based on the current state of the root store and not the
		/// state of the root store at a time passed in by this parameter. For revocation, a certificate revocation list (CRL), itself, must
		/// be valid at the current time. The value of this parameter is used to determine whether a certificate listed in a CRL has been revoked.
		/// </param>
		/// <param name="hAdditionalStore">
		/// A handle to any additional store to search for supporting certificates and certificate trust lists (CTLs). This parameter can be
		/// <c>NULL</c> if no additional store is to be searched.
		/// </param>
		/// <param name="pChainPara">A pointer to a CERT_CHAIN_PARA structure that includes chain-building parameters.</param>
		/// <param name="dwFlags">
		/// <para>Flag values that indicate special processing. This parameter can be a combination of one or more of the following flags.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CERT_CHAIN_CACHE_END_CERT 0x00000001</term>
		/// <term>
		/// When this flag is set, the end certificate is cached, which might speed up the chain-building process. By default, the end
		/// certificate is not cached, and it would need to be verified each time a chain is built for it.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY 0x80000000</term>
		/// <term>Revocation checking only accesses cached URLs.</term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_REVOCATION_CHECK_OCSP_CERT 0x04000000</term>
		/// <term>
		/// This flag is used internally during chain building for an online certificate status protocol (OCSP) signer certificate to
		/// prevent cyclic revocation checks. During chain building, if the OCSP response is signed by an independent OCSP signer, then, in
		/// addition to the original chain build, there is a second chain built for the OCSP signer certificate itself. This flag is used
		/// during this second chain build to inhibit a recursive independent OCSP signer certificate. If the signer certificate contains
		/// the szOID_PKIX_OCSP_NOCHECK extension, revocation checking is skipped for the leaf signer certificate. Both OCSP and CRL
		/// checking are allowed. Windows Server 2003 and Windows XP: This value is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL 0x00000004</term>
		/// <term>
		/// Uses only cached URLs in building a certificate chain. The Internet and intranet are not searched for URL-based objects. Note
		/// This flag is not applicable to revocation checking. Set CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY to use only cached URLs for
		/// revocation checking.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_DISABLE_PASS1_QUALITY_FILTERING 0x00000040</term>
		/// <term>
		/// For performance reasons, the second pass of chain building only considers potential chain paths that have quality greater than
		/// or equal to the highest quality determined during the first pass. The first pass only considers valid signature, complete chain,
		/// and trusted roots to calculate chain quality. This flag can be set to disable this optimization and consider all potential chain
		/// paths during the second pass.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_DISABLE_MY_PEER_TRUST 0x00000800</term>
		/// <term>This flag is not supported. Certificates in the "My" store are never considered for peer trust.</term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_ENABLE_PEER_TRUST 0x00000400</term>
		/// <term>
		/// End entity certificates in the "TrustedPeople" store are trusted without performing any chain building. This function does not
		/// set the CERT_TRUST_IS_PARTIAL_CHAIN or CERT_TRUST_IS_UNTRUSTED_ROOT dwErrorStatus member bits of the ppChainContext parameter.
		/// Windows Server 2003 Windows XP : This flag is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_OPT_IN_WEAK_SIGNATURE 0x00010000</term>
		/// <term>
		/// Setting this flag indicates the caller wishes to opt into weak signature checks. This flag is available in the rollup update for
		/// each OS starting with Windows 7 and Windows Server 2008 R2.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS 0x00000080</term>
		/// <term>
		/// The default is to return only the highest quality chain path. Setting this flag will return the lower quality chains. These are
		/// returned in the cLowerQualityChainContext and rgpLowerQualityChainContext fields of the chain context.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_DISABLE_AUTH_ROOT_AUTO_UPDATE 0x00000100</term>
		/// <term>Setting this flag inhibits the auto update of third-party roots from the Windows Update Web Server.</term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT 0x08000000</term>
		/// <term>
		/// When you set CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT and you also specify a value for the dwUrlRetrievalTimeout member of the
		/// CERT_CHAIN_PARA structure, the value you specify in dwUrlRetrievalTimeout represents the cumulative timeout across all
		/// revocation URL retrievals. If you set CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT but do not specify a dwUrlRetrievalTimeout
		/// value, the maximum cumulative timeout is set, by default, to 20 seconds. Each URL tested will timeout after half of the
		/// remaining cumulative balance has passed. That is, the first URL times out after 10 seconds, the second after 5 seconds, the
		/// third after 2.5 seconds and so on until a URL succeeds, 20 seconds has passed, or there are no more URLs to test. If you do not
		/// set CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT, each revocation URL in the chain is assigned a maximum timeout equal to the
		/// value specified in dwUrlRetrievalTimeout. If you do not specify a value for the dwUrlRetrievalTimeout member, each revocation
		/// URL is assigned a maximum default timeout of 15 seconds. If no URL succeeds, the maximum cumulative timeout value is 15 seconds
		/// multiplied by the number of URLs in the chain. You can set the default values by using Group Policy.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_TIMESTAMP_TIME 0x00000200</term>
		/// <term>
		/// When this flag is set, pTime is used as the time stamp time to determine whether the end certificate was time valid. Current
		/// time can also be used to determine whether the end certificate remains time valid. All other certification authority (CA) and
		/// root certificates in the chain are checked by using current time and not pTime.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_DISABLE_AIA 0x00002000</term>
		/// <term>Setting this flag explicitly turns off Authority Information Access (AIA) retrievals.</term>
		/// </item>
		/// </list>
		/// <para>You can also set the following revocation flags, but only one flag from this group may be set at a time.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CERT_CHAIN_REVOCATION_CHECK_END_CERT 0x10000000</term>
		/// <term>Revocation checking is done on the end certificate and only the end certificate.</term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_REVOCATION_CHECK_CHAIN 0x20000000</term>
		/// <term>Revocation checking is done on all of the certificates in every chain.</term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT 0x40000000</term>
		/// <term>Revocation checking is done on all certificates in all of the chains except the root certificate.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pvReserved">This parameter is reserved and must be <c>NULL</c>.</param>
		/// <param name="ppChainContext">
		/// The address of a pointer to the chain context created. When you have finished using the chain context, release the chain by
		/// calling the CertFreeCertificateChain function.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, it returns zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// When an application requests a certificate chain, the structure returned is in the form of a CERT_CHAIN_CONTEXT. This context
		/// contains an array of CERT_SIMPLE_CHAIN structures where each simple chain goes from an end certificate to a self-signed
		/// certificate. The chain context connects simple chains through trust lists. Each simple chain contains the chain of certificates,
		/// summary trust information about the chain, and trust information about each certificate element in the chain.
		/// </para>
		/// <para>The following remarks apply to strong signature checking:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// You can enable strong signature checking for this function by setting the <c>pStrongSignPara</c> member of the CERT_CHAIN_PARA
		/// structure that is pointed to by the pChainPara parameter.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If a certificate without a strong signature is found in the chain, the <c>CERT_TRUST_HAS_WEAK_SIGNATURE</c> and
		/// <c>CERT_TRUST_IS_NOT_SIGNATURE_VALID</c> errors are set in the <c>dwErrorStatus</c> field of the CERT_TRUST_STATUS structure.
		/// The ppChainContext parameter points to a CERT_CHAIN_CONTEXT structure which, in turn, points to the <c>CERT_TRUST_STATUS</c> structure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If the chain is strong signed, the public key in the end certificate is checked to determine whether it satisfies the minimum
		/// public key length requirements for a strong signature. If the condition is not satisfied, the
		/// <c>CERT_TRUST_HAS_WEAK_SIGNATURE</c> and <c>CERT_TRUST_IS_NOT_SIGNATURE_VALID</c> errors are set in the <c>dwErrorStatus</c>
		/// field of the CERT_TRUST_STATUS structure. To disable checking the key length, set the
		/// <c>CERT_CHAIN_STRONG_SIGN_DISABLE_END_CHECK_FLAG</c> value in the <c>dwStrongSignFlags</c> member of the CERT_CHAIN_PARA
		/// structure pointed to by the pChainPara parameter.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If the <c>CERT_STRONG_SIGN_ENABLE_CRL_CHECK</c> or <c>CERT_STRONG_SIGN_ENABLE_OCSP_CHECK</c> flags are set in the
		/// CERT_STRONG_SIGN_SERIALIZED_INFO structure and a CRL or OCSP response is found without a strong signature, the CRL or OCSP
		/// response will be treated as being offline. That is, the <c>CERT_TRUST_IS_OFFLINE_REVOCATION</c> and
		/// <c>CERT_TRUST_REVOCATION_STATUS_UNKNOWN</c> errors are set in the <c>dwErrorStatus</c> field of the CERT_TRUST_STATUS structure.
		/// Also, the <c>dwRevocationResult</c> member of the CERT_REVOCATION_INFO structure is set to <c>NTE_BAD_ALGID</c>.
		/// </term>
		/// </item>
		/// </list>
		/// <para>Examples</para>
		/// <para>For an example that uses this function, see Example C Program: Creating a Certificate Chain.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certgetcertificatechain BOOL CertGetCertificateChain(
		// HCERTCHAINENGINE hChainEngine, PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore, PCERT_CHAIN_PARA
		// pChainPara, DWORD dwFlags, LPVOID pvReserved, PCCERT_CHAIN_CONTEXT *ppChainContext );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "8c93036c-0b93-40d4-b0e3-ba1f2fc72db1")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CertGetCertificateChain([Optional] HCERTCHAINENGINE hChainEngine, [In] PCCERT_CONTEXT pCertContext, in FILETIME pTime,
			[Optional] HCERTSTORE hAdditionalStore, in CERT_CHAIN_PARA pChainPara, CertChainFlags dwFlags, [Optional] IntPtr pvReserved, out SafePCCERT_CHAIN_CONTEXT ppChainContext);

		/// <summary>
		/// The <c>CertGetCertificateChain</c> function builds a certificate chain context starting from an end certificate and going back,
		/// if possible, to a trusted root certificate.
		/// </summary>
		/// <param name="hChainEngine">
		/// A handle of the chain engine (namespace and cache) to be used. If hChainEngine is <c>NULL</c>, the default chain engine,
		/// HCCE_CURRENT_USER, is used. This parameter can be set to HCCE_LOCAL_MACHINE.
		/// </param>
		/// <param name="pCertContext">
		/// A pointer to the CERT_CONTEXT of the end certificate, the certificate for which a chain is being built. This certificate context
		/// will be the zero-index element in the first simple chain.
		/// </param>
		/// <param name="pTime">
		/// A pointer to a FILETIME variable that indicates the time for which the chain is to be validated. Note that the time does not
		/// affect trust list, revocation, or root store checking. The current system time is used if <c>NULL</c> is passed to this
		/// parameter. Trust in a particular certificate being a trusted root is based on the current state of the root store and not the
		/// state of the root store at a time passed in by this parameter. For revocation, a certificate revocation list (CRL), itself, must
		/// be valid at the current time. The value of this parameter is used to determine whether a certificate listed in a CRL has been revoked.
		/// </param>
		/// <param name="hAdditionalStore">
		/// A handle to any additional store to search for supporting certificates and certificate trust lists (CTLs). This parameter can be
		/// <c>NULL</c> if no additional store is to be searched.
		/// </param>
		/// <param name="pChainPara">A pointer to a CERT_CHAIN_PARA structure that includes chain-building parameters.</param>
		/// <param name="dwFlags">
		/// <para>Flag values that indicate special processing. This parameter can be a combination of one or more of the following flags.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CERT_CHAIN_CACHE_END_CERT 0x00000001</term>
		/// <term>
		/// When this flag is set, the end certificate is cached, which might speed up the chain-building process. By default, the end
		/// certificate is not cached, and it would need to be verified each time a chain is built for it.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY 0x80000000</term>
		/// <term>Revocation checking only accesses cached URLs.</term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_REVOCATION_CHECK_OCSP_CERT 0x04000000</term>
		/// <term>
		/// This flag is used internally during chain building for an online certificate status protocol (OCSP) signer certificate to
		/// prevent cyclic revocation checks. During chain building, if the OCSP response is signed by an independent OCSP signer, then, in
		/// addition to the original chain build, there is a second chain built for the OCSP signer certificate itself. This flag is used
		/// during this second chain build to inhibit a recursive independent OCSP signer certificate. If the signer certificate contains
		/// the szOID_PKIX_OCSP_NOCHECK extension, revocation checking is skipped for the leaf signer certificate. Both OCSP and CRL
		/// checking are allowed. Windows Server 2003 and Windows XP: This value is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL 0x00000004</term>
		/// <term>
		/// Uses only cached URLs in building a certificate chain. The Internet and intranet are not searched for URL-based objects. Note
		/// This flag is not applicable to revocation checking. Set CERT_CHAIN_REVOCATION_CHECK_CACHE_ONLY to use only cached URLs for
		/// revocation checking.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_DISABLE_PASS1_QUALITY_FILTERING 0x00000040</term>
		/// <term>
		/// For performance reasons, the second pass of chain building only considers potential chain paths that have quality greater than
		/// or equal to the highest quality determined during the first pass. The first pass only considers valid signature, complete chain,
		/// and trusted roots to calculate chain quality. This flag can be set to disable this optimization and consider all potential chain
		/// paths during the second pass.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_DISABLE_MY_PEER_TRUST 0x00000800</term>
		/// <term>This flag is not supported. Certificates in the "My" store are never considered for peer trust.</term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_ENABLE_PEER_TRUST 0x00000400</term>
		/// <term>
		/// End entity certificates in the "TrustedPeople" store are trusted without performing any chain building. This function does not
		/// set the CERT_TRUST_IS_PARTIAL_CHAIN or CERT_TRUST_IS_UNTRUSTED_ROOT dwErrorStatus member bits of the ppChainContext parameter.
		/// Windows Server 2003 Windows XP : This flag is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_OPT_IN_WEAK_SIGNATURE 0x00010000</term>
		/// <term>
		/// Setting this flag indicates the caller wishes to opt into weak signature checks. This flag is available in the rollup update for
		/// each OS starting with Windows 7 and Windows Server 2008 R2.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS 0x00000080</term>
		/// <term>
		/// The default is to return only the highest quality chain path. Setting this flag will return the lower quality chains. These are
		/// returned in the cLowerQualityChainContext and rgpLowerQualityChainContext fields of the chain context.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_DISABLE_AUTH_ROOT_AUTO_UPDATE 0x00000100</term>
		/// <term>Setting this flag inhibits the auto update of third-party roots from the Windows Update Web Server.</term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT 0x08000000</term>
		/// <term>
		/// When you set CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT and you also specify a value for the dwUrlRetrievalTimeout member of the
		/// CERT_CHAIN_PARA structure, the value you specify in dwUrlRetrievalTimeout represents the cumulative timeout across all
		/// revocation URL retrievals. If you set CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT but do not specify a dwUrlRetrievalTimeout
		/// value, the maximum cumulative timeout is set, by default, to 20 seconds. Each URL tested will timeout after half of the
		/// remaining cumulative balance has passed. That is, the first URL times out after 10 seconds, the second after 5 seconds, the
		/// third after 2.5 seconds and so on until a URL succeeds, 20 seconds has passed, or there are no more URLs to test. If you do not
		/// set CERT_CHAIN_REVOCATION_ACCUMULATIVE_TIMEOUT, each revocation URL in the chain is assigned a maximum timeout equal to the
		/// value specified in dwUrlRetrievalTimeout. If you do not specify a value for the dwUrlRetrievalTimeout member, each revocation
		/// URL is assigned a maximum default timeout of 15 seconds. If no URL succeeds, the maximum cumulative timeout value is 15 seconds
		/// multiplied by the number of URLs in the chain. You can set the default values by using Group Policy.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_TIMESTAMP_TIME 0x00000200</term>
		/// <term>
		/// When this flag is set, pTime is used as the time stamp time to determine whether the end certificate was time valid. Current
		/// time can also be used to determine whether the end certificate remains time valid. All other certification authority (CA) and
		/// root certificates in the chain are checked by using current time and not pTime.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_DISABLE_AIA 0x00002000</term>
		/// <term>Setting this flag explicitly turns off Authority Information Access (AIA) retrievals.</term>
		/// </item>
		/// </list>
		/// <para>You can also set the following revocation flags, but only one flag from this group may be set at a time.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CERT_CHAIN_REVOCATION_CHECK_END_CERT 0x10000000</term>
		/// <term>Revocation checking is done on the end certificate and only the end certificate.</term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_REVOCATION_CHECK_CHAIN 0x20000000</term>
		/// <term>Revocation checking is done on all of the certificates in every chain.</term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_REVOCATION_CHECK_CHAIN_EXCLUDE_ROOT 0x40000000</term>
		/// <term>Revocation checking is done on all certificates in all of the chains except the root certificate.</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pvReserved">This parameter is reserved and must be <c>NULL</c>.</param>
		/// <param name="ppChainContext">
		/// The address of a pointer to the chain context created. When you have finished using the chain context, release the chain by
		/// calling the CertFreeCertificateChain function.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero ( <c>TRUE</c>).</para>
		/// <para>If the function fails, it returns zero ( <c>FALSE</c>). For extended error information, call GetLastError.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// When an application requests a certificate chain, the structure returned is in the form of a CERT_CHAIN_CONTEXT. This context
		/// contains an array of CERT_SIMPLE_CHAIN structures where each simple chain goes from an end certificate to a self-signed
		/// certificate. The chain context connects simple chains through trust lists. Each simple chain contains the chain of certificates,
		/// summary trust information about the chain, and trust information about each certificate element in the chain.
		/// </para>
		/// <para>The following remarks apply to strong signature checking:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// You can enable strong signature checking for this function by setting the <c>pStrongSignPara</c> member of the CERT_CHAIN_PARA
		/// structure that is pointed to by the pChainPara parameter.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If a certificate without a strong signature is found in the chain, the <c>CERT_TRUST_HAS_WEAK_SIGNATURE</c> and
		/// <c>CERT_TRUST_IS_NOT_SIGNATURE_VALID</c> errors are set in the <c>dwErrorStatus</c> field of the CERT_TRUST_STATUS structure.
		/// The ppChainContext parameter points to a CERT_CHAIN_CONTEXT structure which, in turn, points to the <c>CERT_TRUST_STATUS</c> structure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If the chain is strong signed, the public key in the end certificate is checked to determine whether it satisfies the minimum
		/// public key length requirements for a strong signature. If the condition is not satisfied, the
		/// <c>CERT_TRUST_HAS_WEAK_SIGNATURE</c> and <c>CERT_TRUST_IS_NOT_SIGNATURE_VALID</c> errors are set in the <c>dwErrorStatus</c>
		/// field of the CERT_TRUST_STATUS structure. To disable checking the key length, set the
		/// <c>CERT_CHAIN_STRONG_SIGN_DISABLE_END_CHECK_FLAG</c> value in the <c>dwStrongSignFlags</c> member of the CERT_CHAIN_PARA
		/// structure pointed to by the pChainPara parameter.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If the <c>CERT_STRONG_SIGN_ENABLE_CRL_CHECK</c> or <c>CERT_STRONG_SIGN_ENABLE_OCSP_CHECK</c> flags are set in the
		/// CERT_STRONG_SIGN_SERIALIZED_INFO structure and a CRL or OCSP response is found without a strong signature, the CRL or OCSP
		/// response will be treated as being offline. That is, the <c>CERT_TRUST_IS_OFFLINE_REVOCATION</c> and
		/// <c>CERT_TRUST_REVOCATION_STATUS_UNKNOWN</c> errors are set in the <c>dwErrorStatus</c> field of the CERT_TRUST_STATUS structure.
		/// Also, the <c>dwRevocationResult</c> member of the CERT_REVOCATION_INFO structure is set to <c>NTE_BAD_ALGID</c>.
		/// </term>
		/// </item>
		/// </list>
		/// <para>Examples</para>
		/// <para>For an example that uses this function, see Example C Program: Creating a Certificate Chain.</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certgetcertificatechain BOOL CertGetCertificateChain(
		// HCERTCHAINENGINE hChainEngine, PCCERT_CONTEXT pCertContext, LPFILETIME pTime, HCERTSTORE hAdditionalStore, PCERT_CHAIN_PARA
		// pChainPara, DWORD dwFlags, LPVOID pvReserved, PCCERT_CHAIN_CONTEXT *ppChainContext );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "8c93036c-0b93-40d4-b0e3-ba1f2fc72db1")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CertGetCertificateChain([Optional] HCERTCHAINENGINE hChainEngine, [In] PCCERT_CONTEXT pCertContext, [In, Optional] IntPtr pTime,
			[Optional] HCERTSTORE hAdditionalStore, in CERT_CHAIN_PARA pChainPara, CertChainFlags dwFlags, [Optional] IntPtr pvReserved, out SafePCCERT_CHAIN_CONTEXT ppChainContext);

		/// <summary>
		/// The <c>CertIsValidCRLForCertificate</c> function checks a CRL to find out if it is a CRL that would include a specific
		/// certificate if that certificate were revoked. If the CRL has an issuing distribution point (IDP) extension, the function checks
		/// whether that IDP is valid for the certificate being checked.
		/// </summary>
		/// <param name="pCert">A pointer to a certificate context.</param>
		/// <param name="pCrl">
		/// A pointer to a CRL. The function checks this CRL to determine whether it could contain the certificate context pointed to by
		/// pCert. The function does not look for the certificate in the CRL.
		/// </param>
		/// <param name="dwFlags">Currently not used and must be set to zero.</param>
		/// <param name="pvReserved">Currently not used and must be set to <c>NULL</c>.</param>
		/// <returns>
		/// The function returns <c>TRUE</c> if the CRL is a valid CRL to be searched for the specific certificate. It returns <c>FALSE</c>
		/// if the CRL is not a valid CRL for searching for the certificate.
		/// </returns>
		/// <remarks>
		/// For the CRL to be valid for the certificate, the <c>CertIsValidCRLForCertificate</c> function does not require the CRL to be
		/// issued by the same certification authority (CA) as the issuer of the certificate.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certisvalidcrlforcertificate BOOL
		// CertIsValidCRLForCertificate( PCCERT_CONTEXT pCert, PCCRL_CONTEXT pCrl, DWORD dwFlags, void *pvReserved );
		[DllImport(Lib.Crypt32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "06047b7a-4bdd-42f9-bb85-49b6ec6f35a0")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CertIsValidCRLForCertificate(PCCERT_CONTEXT pCert, PCCRL_CONTEXT pCrl, uint dwFlags = 0, IntPtr pvReserved = default);

		/// <summary>
		/// The <c>CertSetCertificateContextPropertiesFromCTLEntry</c> function sets the properties on the certificate context by using the
		/// attributes in the specified certificate trust list (CTL) entry.
		/// </summary>
		/// <param name="pCertContext">A pointer to the CERT_CONTEXT whose attributes are to be set.</param>
		/// <param name="pCtlEntry">A pointer to the CTL_ENTRY structure used to set the attributes on the certificate.</param>
		/// <param name="dwFlags">
		/// A <c>DWORD</c>. This parameter can be set to CERT_SET_PROPERTY_IGNORE_PERSIST_ERROR_FLAG to ignore any persisted error flags.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the function returns nonzero.</para>
		/// <para>If the function fails, it returns zero. For extended error information, call GetLastError.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certsetcertificatecontextpropertiesfromctlentry BOOL
		// CertSetCertificateContextPropertiesFromCTLEntry( PCCERT_CONTEXT pCertContext, PCTL_ENTRY pCtlEntry, DWORD dwFlags );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "b53b046a-68d4-4dc5-ab89-1b30ebd1de60")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CertSetCertificateContextPropertiesFromCTLEntry(PCCERT_CONTEXT pCertContext, in CTL_ENTRY pCtlEntry, uint dwFlags);

		/// <summary>
		/// The <c>CertVerifyCertificateChainPolicy</c> function checks a certificate chain to verify its validity, including its compliance
		/// with any specified validity policy criteria.
		/// </summary>
		/// <param name="pszPolicyOID">
		/// <para>Current predefined verify chain policy structures are listed in the following table.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_BASE (LPCSTR) 1</term>
		/// <term>
		/// Implements the base chain policy verification checks. The dwFlags member of the structure pointed to by pPolicyPara can be set
		/// to alter the default policy checking behavior.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_AUTHENTICODE (LPCSTR) 2</term>
		/// <term>
		/// Implements the Authenticode chain policy verification checks. The pvExtraPolicyPara member of the structure pointed to by
		/// pPolicyPara can be set to point to an AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA structure. The pvExtraPolicyStatus member of the
		/// structure pointed to by pPolicyStatus can be set to point to an AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_STATUS structure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_AUTHENTICODE_TS (LPCSTR) 3</term>
		/// <term>
		/// Implements Authenticode Time Stamp chain policy verification checks. The pvExtraPolicyPara member of the data structure pointed
		/// to by pPolicyPara can be set to point to an AUTHENTICODE_TS_EXTRA_CERT_CHAIN_POLICY_PARA structure. The pvExtraPolicyStatus
		/// member of the data structure pointed to by pPolicyStatus is not used and must be set to NULL
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_SSL (LPCSTR) 4</term>
		/// <term>
		/// Implements the SSL client/server chain policy verification checks. The pvExtraPolicyPara member in the data structure pointed to
		/// by pPolicyPara can be set to point to an SSL_EXTRA_CERT_CHAIN_POLICY_PARA structure initialized with additional policy criteria.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_BASIC_CONSTRAINTS (LPCSTR) 5</term>
		/// <term>
		/// Implements the basic constraints chain policy. Iterates through all the certificates in the chain checking for either a
		/// szOID_BASIC_CONSTRAINTS or a szOID_BASIC_CONSTRAINTS2 extension. If neither extension is present, the certificate is assumed to
		/// have valid policy. Otherwise, for the first certificate element, checks if it matches the expected CA_FLAG or END_ENTITY_FLAG
		/// specified in the dwFlags member of the CERT_CHAIN_POLICY_PARA structure pointed to by the pPolicyPara parameter. If neither or
		/// both flags are set, then, the first element can be either a CA or END_ENTITY. All other elements must be a certification
		/// authority (CA). If the PathLenConstraint is present in the extension, it is checked. The first elements in the remaining simple
		/// chains (that is, the certificates used to sign the CTL) are checked to be an END_ENTITY. If this verification fails, dwError
		/// will be set to TRUST_E_BASIC_CONSTRAINTS.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_NT_AUTH (LPCSTR) 6</term>
		/// <term>
		/// Implements the Windows NT Authentication chain policy, which consists of three distinct chain verifications in the following order:
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_MICROSOFT_ROOT (LPCSTR) 7</term>
		/// <term>
		/// Checks the last element of the first simple chain for a Microsoft root public key. If that element does not contain a Microsoft
		/// root public key, the dwError member of the CERT_CHAIN_POLICY_STATUS structure pointed to by the pPolicyStatus parameter is set
		/// to CERT_E_UNTRUSTEDROOT. The dwFlags member of the CERT_CHAIN_POLICY_PARA structure pointed to by the pPolicyStatus parameter
		/// can contain the MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG flag, which causes this function to also check for
		/// the Microsoft application root "Microsoft Root Certificate Authority 2011". The dwFlags member of the CERT_CHAIN_POLICY_PARA
		/// structure pointed to by the pPolicyPara parameter can contain the MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG flag,
		/// which causes this function to also check for the Microsoft test roots.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_EV (LPCSTR) 8</term>
		/// <term>
		/// Specifies that extended validation of certificates is performed. Windows Server 2008, Windows Vista, Windows Server 2003 and
		/// Windows XP: This value is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_SSL_F12 (LPCSTR) 9</term>
		/// <term>
		/// Checks if any certificates in the chain have weak crypto or if third party root certificate compliance and provide an error
		/// string. The pvExtraPolicyStatus member of the CERT_CHAIN_POLICY_STATUS structure pointed to by the pPolicyStatus parameter must
		/// point to SSL_F12_EXTRA_CERT_CHAIN_POLICY_STATUS, which is updated with the results of the weak crypto and root program
		/// compliance checks. Before calling, the cbSize member of the CERT_CHAIN_POLICY_STATUS structure pointed to by the pPolicyStatus
		/// parameter must be set to a value greater than or equal to sizeof(SSL_F12_EXTRA_CERT_CHAIN_POLICY_STATUS). The dwError member in
		/// CERT_CHAIN_POLICY_STATUS structure pointed to by the pPolicyStatus parameter will be set to TRUST_E_CERT_SIGNATURE for potential
		/// weak crypto and set to CERT_E_UNTRUSTEDROOT for Third Party Roots not in compliance with the Microsoft Root Program. Windows 10,
		/// version 1607, Windows Server 2016, Windows 10, version 1511 with KB3172985, Windows 10 RTM with KB3163912, Windows 8.1 and
		/// Windows Server 2012 R2 with KB3163912, and Windows 7 with SP1 and Windows Server 2008 R2 SP1 with KB3161029
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pChainContext">A pointer to a CERT_CHAIN_CONTEXT structure that contains a chain to be verified.</param>
		/// <param name="pPolicyPara">
		/// <para>
		/// A pointer to a CERT_CHAIN_POLICY_PARA structure that provides the policy verification criteria for the chain. The <c>dwFlags</c>
		/// member of that structure can be set to change the default policy checking behavior.
		/// </para>
		/// <para>In addition, policy-specific parameters can also be passed in the <c>pvExtraPolicyPara</c> member of the structure.</para>
		/// </param>
		/// <param name="pPolicyStatus">
		/// A pointer to a CERT_CHAIN_POLICY_STATUS structure where status information on the chain is returned. OID-specific extra status
		/// can be returned in the <c>pvExtraPolicyStatus</c> member of this structure.
		/// </param>
		/// <returns>
		/// <para>
		/// The return value indicates whether the function was able to check for the policy, it does not indicate whether the policy check
		/// failed or passed.
		/// </para>
		/// <para>
		/// If the chain can be verified for the specified policy, <c>TRUE</c> is returned and the <c>dwError</c> member of the
		/// pPolicyStatus is updated. A <c>dwError</c> of 0 (ERROR_SUCCESS or S_OK) indicates the chain satisfies the specified policy.
		/// </para>
		/// <para>
		/// If the chain cannot be validated, the return value is <c>TRUE</c> and you need to verify the pPolicyStatus parameter for the
		/// actual error.
		/// </para>
		/// <para>A value of <c>FALSE</c> indicates that the function wasn't able to check for the policy.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// A <c>dwError</c> member of the CERT_CHAIN_POLICY_STATUS structure pointed to by pPolicyStatus can apply to a single chain
		/// element, to a simple chain, or to an entire chain context. If <c>dwError</c> applies to the entire chain context, both the
		/// <c>lChainIndex</c> and the <c>lElementIndex</c> members of the <c>CERT_CHAIN_POLICY_STATUS</c> structure are set to –1. If
		/// <c>dwError</c> applies to a complete simple chain, <c>lElementIndex</c> is set to –1 and <c>lChainIndex</c> is set to the index
		/// of the first chain that has an error. If <c>dwError</c> applies to a single certificate element, <c>lChainIndex</c> and
		/// <c>lElementIndex</c> index the first certificate that has the error.
		/// </para>
		/// <para>To get the certificate element use this syntax:</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certverifycertificatechainpolicy BOOL
		// CertVerifyCertificateChainPolicy( LPCSTR pszPolicyOID, PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
		// PCERT_CHAIN_POLICY_STATUS pPolicyStatus );
		[DllImport(Lib.Crypt32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "19c37f77-1072-4740-b244-764b816a2a1f")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CertVerifyCertificateChainPolicy([In] SafeOID pszPolicyOID, [In] PCCERT_CHAIN_CONTEXT pChainContext,
			in CERT_CHAIN_POLICY_PARA pPolicyPara, ref CERT_CHAIN_POLICY_STATUS pPolicyStatus);

		/// <summary>
		/// The <c>CertVerifyCertificateChainPolicy</c> function checks a certificate chain to verify its validity, including its compliance
		/// with any specified validity policy criteria.
		/// </summary>
		/// <param name="pszPolicyOID">
		/// <para>Current predefined verify chain policy structures are listed in the following table.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_BASE (LPCSTR) 1</term>
		/// <term>
		/// Implements the base chain policy verification checks. The dwFlags member of the structure pointed to by pPolicyPara can be set
		/// to alter the default policy checking behavior.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_AUTHENTICODE (LPCSTR) 2</term>
		/// <term>
		/// Implements the Authenticode chain policy verification checks. The pvExtraPolicyPara member of the structure pointed to by
		/// pPolicyPara can be set to point to an AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_PARA structure. The pvExtraPolicyStatus member of the
		/// structure pointed to by pPolicyStatus can be set to point to an AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_STATUS structure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_AUTHENTICODE_TS (LPCSTR) 3</term>
		/// <term>
		/// Implements Authenticode Time Stamp chain policy verification checks. The pvExtraPolicyPara member of the data structure pointed
		/// to by pPolicyPara can be set to point to an AUTHENTICODE_TS_EXTRA_CERT_CHAIN_POLICY_PARA structure. The pvExtraPolicyStatus
		/// member of the data structure pointed to by pPolicyStatus is not used and must be set to NULL
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_SSL (LPCSTR) 4</term>
		/// <term>
		/// Implements the SSL client/server chain policy verification checks. The pvExtraPolicyPara member in the data structure pointed to
		/// by pPolicyPara can be set to point to an SSL_EXTRA_CERT_CHAIN_POLICY_PARA structure initialized with additional policy criteria.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_BASIC_CONSTRAINTS (LPCSTR) 5</term>
		/// <term>
		/// Implements the basic constraints chain policy. Iterates through all the certificates in the chain checking for either a
		/// szOID_BASIC_CONSTRAINTS or a szOID_BASIC_CONSTRAINTS2 extension. If neither extension is present, the certificate is assumed to
		/// have valid policy. Otherwise, for the first certificate element, checks if it matches the expected CA_FLAG or END_ENTITY_FLAG
		/// specified in the dwFlags member of the CERT_CHAIN_POLICY_PARA structure pointed to by the pPolicyPara parameter. If neither or
		/// both flags are set, then, the first element can be either a CA or END_ENTITY. All other elements must be a certification
		/// authority (CA). If the PathLenConstraint is present in the extension, it is checked. The first elements in the remaining simple
		/// chains (that is, the certificates used to sign the CTL) are checked to be an END_ENTITY. If this verification fails, dwError
		/// will be set to TRUST_E_BASIC_CONSTRAINTS.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_NT_AUTH (LPCSTR) 6</term>
		/// <term>
		/// Implements the Windows NT Authentication chain policy, which consists of three distinct chain verifications in the following order:
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_MICROSOFT_ROOT (LPCSTR) 7</term>
		/// <term>
		/// Checks the last element of the first simple chain for a Microsoft root public key. If that element does not contain a Microsoft
		/// root public key, the dwError member of the CERT_CHAIN_POLICY_STATUS structure pointed to by the pPolicyStatus parameter is set
		/// to CERT_E_UNTRUSTEDROOT. The dwFlags member of the CERT_CHAIN_POLICY_PARA structure pointed to by the pPolicyStatus parameter
		/// can contain the MICROSOFT_ROOT_CERT_CHAIN_POLICY_CHECK_APPLICATION_ROOT_FLAG flag, which causes this function to also check for
		/// the Microsoft application root "Microsoft Root Certificate Authority 2011". The dwFlags member of the CERT_CHAIN_POLICY_PARA
		/// structure pointed to by the pPolicyPara parameter can contain the MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG flag,
		/// which causes this function to also check for the Microsoft test roots.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_EV (LPCSTR) 8</term>
		/// <term>
		/// Specifies that extended validation of certificates is performed. Windows Server 2008, Windows Vista, Windows Server 2003 and
		/// Windows XP: This value is not supported.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CERT_CHAIN_POLICY_SSL_F12 (LPCSTR) 9</term>
		/// <term>
		/// Checks if any certificates in the chain have weak crypto or if third party root certificate compliance and provide an error
		/// string. The pvExtraPolicyStatus member of the CERT_CHAIN_POLICY_STATUS structure pointed to by the pPolicyStatus parameter must
		/// point to SSL_F12_EXTRA_CERT_CHAIN_POLICY_STATUS, which is updated with the results of the weak crypto and root program
		/// compliance checks. Before calling, the cbSize member of the CERT_CHAIN_POLICY_STATUS structure pointed to by the pPolicyStatus
		/// parameter must be set to a value greater than or equal to sizeof(SSL_F12_EXTRA_CERT_CHAIN_POLICY_STATUS). The dwError member in
		/// CERT_CHAIN_POLICY_STATUS structure pointed to by the pPolicyStatus parameter will be set to TRUST_E_CERT_SIGNATURE for potential
		/// weak crypto and set to CERT_E_UNTRUSTEDROOT for Third Party Roots not in compliance with the Microsoft Root Program. Windows 10,
		/// version 1607, Windows Server 2016, Windows 10, version 1511 with KB3172985, Windows 10 RTM with KB3163912, Windows 8.1 and
		/// Windows Server 2012 R2 with KB3163912, and Windows 7 with SP1 and Windows Server 2008 R2 SP1 with KB3161029
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pChainContext">A pointer to a CERT_CHAIN_CONTEXT structure that contains a chain to be verified.</param>
		/// <param name="pPolicyPara">
		/// <para>
		/// A pointer to a CERT_CHAIN_POLICY_PARA structure that provides the policy verification criteria for the chain. The <c>dwFlags</c>
		/// member of that structure can be set to change the default policy checking behavior.
		/// </para>
		/// <para>In addition, policy-specific parameters can also be passed in the <c>pvExtraPolicyPara</c> member of the structure.</para>
		/// </param>
		/// <param name="pPolicyStatus">
		/// A pointer to a CERT_CHAIN_POLICY_STATUS structure where status information on the chain is returned. OID-specific extra status
		/// can be returned in the <c>pvExtraPolicyStatus</c> member of this structure.
		/// </param>
		/// <returns>
		/// <para>
		/// The return value indicates whether the function was able to check for the policy, it does not indicate whether the policy check
		/// failed or passed.
		/// </para>
		/// <para>
		/// If the chain can be verified for the specified policy, <c>TRUE</c> is returned and the <c>dwError</c> member of the
		/// pPolicyStatus is updated. A <c>dwError</c> of 0 (ERROR_SUCCESS or S_OK) indicates the chain satisfies the specified policy.
		/// </para>
		/// <para>
		/// If the chain cannot be validated, the return value is <c>TRUE</c> and you need to verify the pPolicyStatus parameter for the
		/// actual error.
		/// </para>
		/// <para>A value of <c>FALSE</c> indicates that the function wasn't able to check for the policy.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// A <c>dwError</c> member of the CERT_CHAIN_POLICY_STATUS structure pointed to by pPolicyStatus can apply to a single chain
		/// element, to a simple chain, or to an entire chain context. If <c>dwError</c> applies to the entire chain context, both the
		/// <c>lChainIndex</c> and the <c>lElementIndex</c> members of the <c>CERT_CHAIN_POLICY_STATUS</c> structure are set to –1. If
		/// <c>dwError</c> applies to a complete simple chain, <c>lElementIndex</c> is set to –1 and <c>lChainIndex</c> is set to the index
		/// of the first chain that has an error. If <c>dwError</c> applies to a single certificate element, <c>lChainIndex</c> and
		/// <c>lElementIndex</c> index the first certificate that has the error.
		/// </para>
		/// <para>To get the certificate element use this syntax:</para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certverifycertificatechainpolicy BOOL
		// CertVerifyCertificateChainPolicy( LPCSTR pszPolicyOID, PCCERT_CHAIN_CONTEXT pChainContext, PCERT_CHAIN_POLICY_PARA pPolicyPara,
		// PCERT_CHAIN_POLICY_STATUS pPolicyStatus );
		[DllImport(Lib.Crypt32, SetLastError = false, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "19c37f77-1072-4740-b244-764b816a2a1f")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CertVerifyCertificateChainPolicy(IntPtr pszPolicyOID, [In] PCCERT_CHAIN_CONTEXT pChainContext,
			in CERT_CHAIN_POLICY_PARA pPolicyPara, ref CERT_CHAIN_POLICY_STATUS pPolicyStatus);

		/// <summary>
		/// The <c>CertVerifyCTLUsage</c> function verifies that a subject is trusted for a specified usage by finding a signed and
		/// time-valid certificate trust list (CTL) with the usage identifiers that contain the subject. A certificate's subject can be
		/// identified by either its certificate context or any unique identifier such as the SHA1 hash of the subject's certificate.
		/// </summary>
		/// <param name="dwEncodingType">
		/// <para>
		/// Specifies the encoding type used. Currently, only X509_ASN_ENCODING and PKCS_7_ASN_ENCODING are being used; however, additional
		/// encoding types can be added in the future. For either current encoding type, use
		/// </para>
		/// <para>X509_ASN_ENCODING | PKCS_7_ASN_ENCODING.</para>
		/// </param>
		/// <param name="dwSubjectType">
		/// <para>
		/// If the dwSubjectType parameter is set to CTL_CERT_SUBJECT_TYPE, pvSubject points to a CERT_CONTEXT structure. The structure's
		/// <c>SubjectAlgorithm</c> member is examined to determine the representation of the subject's identity. Initially, only SHA1 and
		/// MD5 hashes are supported as values for <c>SubjectAlgorithm</c>. The appropriate hash property is obtained from the
		/// <c>CERT_CONTEXT</c> structure.
		/// </para>
		/// <para>
		/// If the dwSubjectType parameter is set to CTL_ANY_SUBJECT_TYPE, pvSubject points to the CTL_ANY_SUBJECT_INFO structure. The
		/// <c>SubjectAlgorithm</c> member of this structure must match the algorithm type of the CTL, and the <c>SubjectIdentifier</c>
		/// member must match one of the CTL entries.
		/// </para>
		/// <para>If dwSubjectType is set to either preceding value, dwEncodingType is not used.</para>
		/// </param>
		/// <param name="pvSubject">Value used in conjunction with the dwSubjectType parameter.</param>
		/// <param name="pSubjectUsage">A pointer to a CTL_USAGE structure used to specify the intended usage of the subject.</param>
		/// <param name="dwFlags">
		/// <para>
		/// If the CERT_VERIFY_INHIBIT_CTL_UPDATE_FLAG is not set, a CTL whose time is no longer valid in one of the stores specified by
		/// <c>rghCtlStore</c> in CTL_VERIFY_USAGE_PARA can be replaced. When replaced, the CERT_VERIFY_UPDATED_CTL_FLAG is set in the
		/// <c>dwFlags</c> member of pVerifyUsageStatus. If this flag is set, an update will not be made, even if a time-valid, updated CTL
		/// is received for a CTL that is in the store and whose time is no longer valid.
		/// </para>
		/// <para>
		/// If the CERT_VERIFY_TRUSTED_SIGNERS_FLAG is set, only the signer stores specified by <c>rghSignerStore</c> in
		/// CTL_VERIFY_USAGE_PARA are searched to find the signer. Otherwise, the signer stores provide additional sources to find the
		/// signer's certificate. For more information, see Remarks.
		/// </para>
		/// <para>If CERT_VERIFY_NO_TIME_CHECK_FLAG is set, the CTLs are not checked for time validity. Otherwise, they are.</para>
		/// <para>
		/// If CERT_VERIFY_ALLOW_MORE_USAGE_FLAG is set, the CTL can contain usage identifiers in addition to those specified by
		/// pSubjectUsage. Otherwise, the found CTL will contain no additional usage identifiers.
		/// </para>
		/// </param>
		/// <param name="pVerifyUsagePara">
		/// A pointer to a CTL_VERIFY_USAGE_PARA structure that specifies the stores to be searched to find the CTL and the stores that
		/// contain acceptable CTL signers. Setting the <c>ListIdentifier</c> member further limits the search.
		/// </param>
		/// <param name="pVerifyUsageStatus">
		/// A pointer to a CTL_VERIFY_USAGE_STATUS structure. The <c>cbSize</c> member of the structure must to be set to the size, in
		/// bytes, of the structure, and all other fields must be set to zero before <c>CertVerifyCTLUsage</c> is called. For more
		/// information, see <c>CTL_VERIFY_USAGE_STATUS</c>.
		/// </param>
		/// <returns>
		/// <para>
		/// If the subject is trusted for the specified usage, <c>TRUE</c> is returned. Otherwise, <c>FALSE</c> is returned. GetLastError
		/// can return one of the following error codes.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_E_NO_VERIFY_USAGE_DLL</term>
		/// <term>No DLL or exported function was found to verify subject usage.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_E_NO_VERIFY_USAGE_CHECK</term>
		/// <term>The called function was not able to do a usage check on the subject.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_E_VERIFY_USAGE_OFFLINE</term>
		/// <term>The server was offline; therefore, the called function could not complete the usage check.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_E_NOT_IN_CTL</term>
		/// <term>The subject was not found in a CTL.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_E_NO_TRUSTED_SIGNER</term>
		/// <term>No trusted signer was found to verify the signature of the message or trust list.</term>
		/// </item>
		/// </list>
		/// <para>The <c>dwError</c> member of the CTL_VERIFY_USAGE_PARA pointed to by pVerifyUsageStatus is set to the same error code.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// <c>CertVerifyCTLUsage</c> is a dispatcher to functions that can be installed by using an object identifier (OID). First, it
		/// tries to find an OID function that matches the first usage object identifier in the CLT_USAGE structure pointed to by
		/// pSubjectUsage. If this fails, it uses the default <c>CertDllVerifyCTLUsage</c> functions.
		/// </para>
		/// <para>The <c>CertDllVerifyCTLUsage</c> function in Cryptnet.dll can be installed by using an OID; it has the following properties:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// If CTL stores are specified by <c>rghCtlStore</c> in pVerifyUsagePara, only those stores are searched to find a CTL. Otherwise,
		/// the Trust system store is searched to find a CTL.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If CERT_VERIFY_TRUSTED_SIGNERS_FLAG is set, only the signer stores specified by <c>rghSignerStore</c> in pVerifyUsagePara are
		/// searched to find the certificate that corresponds to the signer's issuer and serial number. Otherwise, the CTL message's store,
		/// the signer stores specified by <c>rghSignerStore</c> in pVerifyUsagePara, the Trust system store, CA system store, ROOT, and
		/// Software Publisher Certificate (SPC) system stores are searched to find the signer's certificate. In either case, the public key
		/// in the found certificate is used to verify the signature of the CTL.
		/// </term>
		/// </item>
		/// <item>
		/// <term>If the CTL has a set <c>NextUpdate</c> member and CERT_VERIFY_NO_TIME_CHECK is not set, it is verified for time validity.</term>
		/// </item>
		/// <item>
		/// <term>
		/// If the CTL obtained from the store has a time that is not valid, an attempt is made to get a time-valid version. The
		/// <c>CertDllVerifyCTLUsage</c> function uses the <c>NextUpdateLocation</c> property or the <c>NextUpdateLocation</c> extension of
		/// the CTL, or it searches the signer's information for a <c>NextUpdateLocation</c> attribute.
		/// </term>
		/// </item>
		/// </list>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certverifyctlusage BOOL CertVerifyCTLUsage( DWORD
		// dwEncodingType, DWORD dwSubjectType, void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags, PCTL_VERIFY_USAGE_PARA
		// pVerifyUsagePara, PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "d87d8157-8e52-4198-bfd4-46d83d72eb13")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CertVerifyCTLUsage(CertEncodingType dwEncodingType, CtlCertSubject dwSubjectType, [In] IntPtr pvSubject, in CTL_USAGE pSubjectUsage,
			CertVerifyCTLFlags dwFlags, in CTL_VERIFY_USAGE_PARA pVerifyUsagePara, ref CTL_VERIFY_USAGE_STATUS pVerifyUsageStatus);

		/// <summary>
		/// The <c>CertVerifyCTLUsage</c> function verifies that a subject is trusted for a specified usage by finding a signed and
		/// time-valid certificate trust list (CTL) with the usage identifiers that contain the subject. A certificate's subject can be
		/// identified by either its certificate context or any unique identifier such as the SHA1 hash of the subject's certificate.
		/// </summary>
		/// <param name="dwEncodingType">
		/// <para>
		/// Specifies the encoding type used. Currently, only X509_ASN_ENCODING and PKCS_7_ASN_ENCODING are being used; however, additional
		/// encoding types can be added in the future. For either current encoding type, use
		/// </para>
		/// <para>X509_ASN_ENCODING | PKCS_7_ASN_ENCODING.</para>
		/// </param>
		/// <param name="dwSubjectType">
		/// <para>
		/// If the dwSubjectType parameter is set to CTL_CERT_SUBJECT_TYPE, pvSubject points to a CERT_CONTEXT structure. The structure's
		/// <c>SubjectAlgorithm</c> member is examined to determine the representation of the subject's identity. Initially, only SHA1 and
		/// MD5 hashes are supported as values for <c>SubjectAlgorithm</c>. The appropriate hash property is obtained from the
		/// <c>CERT_CONTEXT</c> structure.
		/// </para>
		/// <para>
		/// If the dwSubjectType parameter is set to CTL_ANY_SUBJECT_TYPE, pvSubject points to the CTL_ANY_SUBJECT_INFO structure. The
		/// <c>SubjectAlgorithm</c> member of this structure must match the algorithm type of the CTL, and the <c>SubjectIdentifier</c>
		/// member must match one of the CTL entries.
		/// </para>
		/// <para>If dwSubjectType is set to either preceding value, dwEncodingType is not used.</para>
		/// </param>
		/// <param name="pvSubject">Value used in conjunction with the dwSubjectType parameter.</param>
		/// <param name="pSubjectUsage">A pointer to a CTL_USAGE structure used to specify the intended usage of the subject.</param>
		/// <param name="dwFlags">
		/// <para>
		/// If the CERT_VERIFY_INHIBIT_CTL_UPDATE_FLAG is not set, a CTL whose time is no longer valid in one of the stores specified by
		/// <c>rghCtlStore</c> in CTL_VERIFY_USAGE_PARA can be replaced. When replaced, the CERT_VERIFY_UPDATED_CTL_FLAG is set in the
		/// <c>dwFlags</c> member of pVerifyUsageStatus. If this flag is set, an update will not be made, even if a time-valid, updated CTL
		/// is received for a CTL that is in the store and whose time is no longer valid.
		/// </para>
		/// <para>
		/// If the CERT_VERIFY_TRUSTED_SIGNERS_FLAG is set, only the signer stores specified by <c>rghSignerStore</c> in
		/// CTL_VERIFY_USAGE_PARA are searched to find the signer. Otherwise, the signer stores provide additional sources to find the
		/// signer's certificate. For more information, see Remarks.
		/// </para>
		/// <para>If CERT_VERIFY_NO_TIME_CHECK_FLAG is set, the CTLs are not checked for time validity. Otherwise, they are.</para>
		/// <para>
		/// If CERT_VERIFY_ALLOW_MORE_USAGE_FLAG is set, the CTL can contain usage identifiers in addition to those specified by
		/// pSubjectUsage. Otherwise, the found CTL will contain no additional usage identifiers.
		/// </para>
		/// </param>
		/// <param name="pVerifyUsagePara">
		/// A pointer to a CTL_VERIFY_USAGE_PARA structure that specifies the stores to be searched to find the CTL and the stores that
		/// contain acceptable CTL signers. Setting the <c>ListIdentifier</c> member further limits the search.
		/// </param>
		/// <param name="pVerifyUsageStatus">
		/// A pointer to a CTL_VERIFY_USAGE_STATUS structure. The <c>cbSize</c> member of the structure must to be set to the size, in
		/// bytes, of the structure, and all other fields must be set to zero before <c>CertVerifyCTLUsage</c> is called. For more
		/// information, see <c>CTL_VERIFY_USAGE_STATUS</c>.
		/// </param>
		/// <returns>
		/// <para>
		/// If the subject is trusted for the specified usage, <c>TRUE</c> is returned. Otherwise, <c>FALSE</c> is returned. GetLastError
		/// can return one of the following error codes.
		/// </para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Description</term>
		/// </listheader>
		/// <item>
		/// <term>CRYPT_E_NO_VERIFY_USAGE_DLL</term>
		/// <term>No DLL or exported function was found to verify subject usage.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_E_NO_VERIFY_USAGE_CHECK</term>
		/// <term>The called function was not able to do a usage check on the subject.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_E_VERIFY_USAGE_OFFLINE</term>
		/// <term>The server was offline; therefore, the called function could not complete the usage check.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_E_NOT_IN_CTL</term>
		/// <term>The subject was not found in a CTL.</term>
		/// </item>
		/// <item>
		/// <term>CRYPT_E_NO_TRUSTED_SIGNER</term>
		/// <term>No trusted signer was found to verify the signature of the message or trust list.</term>
		/// </item>
		/// </list>
		/// <para>The <c>dwError</c> member of the CTL_VERIFY_USAGE_PARA pointed to by pVerifyUsageStatus is set to the same error code.</para>
		/// </returns>
		/// <remarks>
		/// <para>
		/// <c>CertVerifyCTLUsage</c> is a dispatcher to functions that can be installed by using an object identifier (OID). First, it
		/// tries to find an OID function that matches the first usage object identifier in the CLT_USAGE structure pointed to by
		/// pSubjectUsage. If this fails, it uses the default <c>CertDllVerifyCTLUsage</c> functions.
		/// </para>
		/// <para>The <c>CertDllVerifyCTLUsage</c> function in Cryptnet.dll can be installed by using an OID; it has the following properties:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// If CTL stores are specified by <c>rghCtlStore</c> in pVerifyUsagePara, only those stores are searched to find a CTL. Otherwise,
		/// the Trust system store is searched to find a CTL.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If CERT_VERIFY_TRUSTED_SIGNERS_FLAG is set, only the signer stores specified by <c>rghSignerStore</c> in pVerifyUsagePara are
		/// searched to find the certificate that corresponds to the signer's issuer and serial number. Otherwise, the CTL message's store,
		/// the signer stores specified by <c>rghSignerStore</c> in pVerifyUsagePara, the Trust system store, CA system store, ROOT, and
		/// Software Publisher Certificate (SPC) system stores are searched to find the signer's certificate. In either case, the public key
		/// in the found certificate is used to verify the signature of the CTL.
		/// </term>
		/// </item>
		/// <item>
		/// <term>If the CTL has a set <c>NextUpdate</c> member and CERT_VERIFY_NO_TIME_CHECK is not set, it is verified for time validity.</term>
		/// </item>
		/// <item>
		/// <term>
		/// If the CTL obtained from the store has a time that is not valid, an attempt is made to get a time-valid version. The
		/// <c>CertDllVerifyCTLUsage</c> function uses the <c>NextUpdateLocation</c> property or the <c>NextUpdateLocation</c> extension of
		/// the CTL, or it searches the signer's information for a <c>NextUpdateLocation</c> attribute.
		/// </term>
		/// </item>
		/// </list>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-certverifyctlusage BOOL CertVerifyCTLUsage( DWORD
		// dwEncodingType, DWORD dwSubjectType, void *pvSubject, PCTL_USAGE pSubjectUsage, DWORD dwFlags, PCTL_VERIFY_USAGE_PARA
		// pVerifyUsagePara, PCTL_VERIFY_USAGE_STATUS pVerifyUsageStatus );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "d87d8157-8e52-4198-bfd4-46d83d72eb13")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CertVerifyCTLUsage(CertEncodingType dwEncodingType, CtlCertSubject dwSubjectType, [In] IntPtr pvSubject, in CTL_USAGE pSubjectUsage,
			CertVerifyCTLFlags dwFlags, [In, Optional] IntPtr pVerifyUsagePara, ref CTL_VERIFY_USAGE_STATUS pVerifyUsageStatus);

		/// <summary>
		/// <para>The <c>CryptMsgEncodeAndSignCTL</c> function encodes a CTL and creates a signed message containing the encoded CTL.</para>
		/// <para>This function first encodes the CTL pointed to by pCtlInfo and then calls CryptMsgSignCTL to sign the encoded message.</para>
		/// </summary>
		/// <param name="dwMsgEncodingType">
		/// <para>
		/// Specifies the encoding type used. It is always acceptable to specify both the certificate and message encoding types by
		/// combining them with a bitwise- <c>OR</c> operation as shown in the following example:
		/// </para>
		/// <para>X509_ASN_ENCODING | PKCS_7_ASN_ENCODING</para>
		/// <para>Currently defined encoding types are:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>X509_ASN_ENCODING</term>
		/// </item>
		/// <item>
		/// <term>PKCS_7_ASN_ENCODING</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pCtlInfo">A pointer to the CTL_INFO structure containing the CTL to be encoded and signed.</param>
		/// <param name="pSignInfo">
		/// <para>A pointer to a CMSG_SIGNED_ENCODE_INFO structure that contains an array of a CMSG_SIGNER_ENCODE_INFO structures.</para>
		/// <para>
		/// The message can be encoded without signers if the <c>cbSize</c> member of the structure is set to the size of the structure and
		/// all of the other members are set to zero.
		/// </para>
		/// </param>
		/// <param name="dwFlags">
		/// <para>
		/// CMSG_ENCODE_SORTED_CTL_FLAG is set if the CTL entries are to be sorted before encoding. This flag is set if the
		/// CertFindSubjectInSortedCTL or CertEnumSubjectInSortedCTL functions will be called.
		/// </para>
		/// <para>
		/// CMSG_ENCODE_HASHED_SUBJECT_IDENTIFIER_FLAG is set if CMSG_ENCODE_SORTED_CTL_FLAG is set, and the identifier for the
		/// TrustedSubjects is a hash, such as MD5 or SHA1.
		/// </para>
		/// <para>
		/// If CMS_PKCS7 is defined, dwFlags can be set to CMSG_CMS_ENCAPSULATED_CTL_FLAG to encode a CMS compatible V3 SignedData message.
		/// </para>
		/// </param>
		/// <param name="pbEncoded">
		/// <para>A pointer to a buffer that receives the encoded, signed message created.</para>
		/// <para>
		/// This parameter can be <c>NULL</c> to set the size of this information for memory allocation purposes. For more information, see
		/// Retrieving Data of Unknown Length.
		/// </para>
		/// </param>
		/// <param name="pcbEncoded">
		/// A pointer to a <c>DWORD</c> that specifies the size, in bytes, of the pbEncoded buffer. When the function returns, the
		/// <c>DWORD</c> contains the number of bytes stored or to be stored in the buffer.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero ( <c>TRUE</c>).</para>
		/// <para>
		/// If the function fails, the return value is zero ( <c>FALSE</c>). To get extended error information, call GetLastError. Errors
		/// can be propagated from calls to CryptMsgOpenToEncode and CryptMsgUpdate.
		/// </para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptmsgencodeandsignctl BOOL CryptMsgEncodeAndSignCTL(
		// DWORD dwMsgEncodingType, PCTL_INFO pCtlInfo, PCMSG_SIGNED_ENCODE_INFO pSignInfo, DWORD dwFlags, BYTE *pbEncoded, DWORD
		// *pcbEncoded );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "5c0e9e2e-a50d-45d0-b51d-065784d1d912")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptMsgEncodeAndSignCTL(CertEncodingType dwMsgEncodingType, in CTL_INFO pCtlInfo, in CMSG_SIGNED_ENCODE_INFO pSignInfo,
			CryptMsgEncodeFlags dwFlags, [Out] IntPtr pbEncoded, ref uint pcbEncoded);

		/// <summary>The <c>CryptMsgGetAndVerifySigner</c> function verifies a cryptographic message's signature.</summary>
		/// <param name="hCryptMsg">Handle of a cryptographic message.</param>
		/// <param name="cSignerStore">Number of stores in the rghSignerStore array.</param>
		/// <param name="rghSignerStore">Array of certificate store handles that can be searched for a signer's certificate.</param>
		/// <param name="dwFlags">
		/// <para>Indicates particular use of the function.</para>
		/// <list type="table">
		/// <listheader>
		/// <term>Value</term>
		/// <term>Meaning</term>
		/// </listheader>
		/// <item>
		/// <term>CMSG_TRUSTED_SIGNER_FLAG</term>
		/// <term>
		/// The stores in rghSignerStore are assumed trusted and they are the only stores searched to find the certificate corresponding to
		/// the signer's issuer and serial number. Otherwise, signer stores can be provided to supplement the message's store of
		/// certificates. If a signer certificate is found, its public key is used to verify the message signature.
		/// </term>
		/// </item>
		/// <item>
		/// <term>CMSG_SIGNER_ONLY_FLAG</term>
		/// <term>Return the signer without doing the signature verification.</term>
		/// </item>
		/// <item>
		/// <term>CMSG_USE_SIGNER_INDEX_FLAG</term>
		/// <term>
		/// Only the signer specified by *pdwSignerIndex is returned. Otherwise, iterate through all the signers until a signature is
		/// verified or there are no more signers.
		/// </term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="ppSigner">
		/// If the signature is verified, ppSigner is updated to point to the signer's certificate context. When you have finished using the
		/// certificate, free the context by calling the CertFreeCertificateContext function. This parameter can be <c>NULL</c> if the
		/// application has no need for the signer's certificate.
		/// </param>
		/// <param name="pdwSignerIndex">
		/// If the signature is verified, pdwSigner is updated to point to the index of the signer in the array of signers. This parameter
		/// can be <c>NULL</c> if the application has no need for the index of the signer.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero (TRUE).</para>
		/// <para>If the function fails, the return value is zero (FALSE). For extended error information, call GetLastError.</para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptmsggetandverifysigner BOOL
		// CryptMsgGetAndVerifySigner( HCRYPTMSG hCryptMsg, DWORD cSignerStore, HCERTSTORE *rghSignerStore, DWORD dwFlags, PCCERT_CONTEXT
		// *ppSigner, DWORD *pdwSignerIndex );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "380c9cf3-27a2-4354-b1c8-97cec33f4e44")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptMsgGetAndVerifySigner(HCRYPTMSG hCryptMsg, uint cSignerStore, [In, MarshalAs(UnmanagedType.LPArray)] HCERTSTORE[] rghSignerStore,
			CryptMsgSignerFlags dwFlags, out SafePCCERT_CONTEXT ppSigner, ref uint pdwSignerIndex);

		/// <summary>The <c>CryptMsgSignCTL</c> function creates a signed message containing an encoded CTL.</summary>
		/// <param name="dwMsgEncodingType">
		/// <para>
		/// Specifies the encoding type used. It is always acceptable to specify both the certificate and message encoding types by
		/// combining them with a bitwise- <c>OR</c> operation as shown in the following example:
		/// </para>
		/// <para>X509_ASN_ENCODING | PKCS_7_ASN_ENCODING</para>
		/// <para>Currently defined encoding types are:</para>
		/// <list type="bullet">
		/// <item>
		/// <term>X509_ASN_ENCODING</term>
		/// </item>
		/// <item>
		/// <term>PKCS_7_ASN_ENCODING</term>
		/// </item>
		/// </list>
		/// </param>
		/// <param name="pbCtlContent">
		/// The encoded CTL_INFO that can be a member of a CTL_CONTEXT structure or can be created using the CryptEncodeObject function.
		/// </param>
		/// <param name="cbCtlContent">The size, in bytes, of the content pointed to by pbCtlContent.</param>
		/// <param name="pSignInfo">
		/// <para>A pointer to a CMSG_SIGNED_ENCODE_INFO structure containing an array of a CMSG_SIGNER_ENCODE_INFO structures.</para>
		/// <para>
		/// The message can be encoded without signers if the <c>cbSize</c> member of the structure is set to the size of the structure and
		/// all of the other members are set to zero.
		/// </para>
		/// </param>
		/// <param name="dwFlags">
		/// If CMS_PKCS7 is defined, can be set to CMSG_CMS_ENCAPSULATED_CTL_FLAG to encode a CMS compatible V3 SignedData message.
		/// </param>
		/// <param name="pbEncoded">
		/// <para>A pointer to a buffer to receives the encoded message.</para>
		/// <para>
		/// This parameter can be <c>NULL</c> to get the size of this information for memory allocation purposes. For more information, see
		/// Retrieving Data of Unknown Length.
		/// </para>
		/// </param>
		/// <param name="pcbEncoded">
		/// A pointer to a <c>DWORD</c> specifying the size, in bytes, of the pbEncoded buffer. When the function returns, the <c>DWORD</c>
		/// contains the number of bytes stored or to be stored in the buffer.
		/// </param>
		/// <returns>
		/// <para>If the function succeeds, the return value is nonzero ( <c>TRUE</c>).</para>
		/// <para>
		/// If the function fails, the return value is zero ( <c>FALSE</c>). For extended error information, call GetLastError. This
		/// function can return errors propagated from calls to CryptMsgOpenToEncode and CryptMsgUpdate.
		/// </para>
		/// </returns>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/nf-wincrypt-cryptmsgsignctl BOOL CryptMsgSignCTL( DWORD
		// dwMsgEncodingType, BYTE *pbCtlContent, DWORD cbCtlContent, PCMSG_SIGNED_ENCODE_INFO pSignInfo, DWORD dwFlags, BYTE *pbEncoded,
		// DWORD *pcbEncoded );
		[DllImport(Lib.Crypt32, SetLastError = true, ExactSpelling = true)]
		[PInvokeData("wincrypt.h", MSDNShortId = "85ae8ce3-d0a7-4fcb-beaa-ede09d30930e")]
		[return: MarshalAs(UnmanagedType.Bool)]
		public static extern bool CryptMsgSignCTL(CertEncodingType dwMsgEncodingType, [In] IntPtr pbCtlContent, uint cbCtlContent, in CMSG_SIGNED_ENCODE_INFO pSignInfo,
			CryptMsgSignFlags dwFlags, [Out] IntPtr pbEncoded, ref uint pcbEncoded);

		/// <summary>
		/// The <c>CERT_CHAIN_ENGINE_CONFIG</c> structure sets parameters for building a non-default certificate chain engine. The engine
		/// used determines the ways that certificate chains are built.
		/// </summary>
		/// <remarks>
		/// <para>
		/// The chain-building engine uses four certificate stores in building chains. These are hRoot, hWorld, hTrust, and hOther. These
		/// stores' handles are established by using information in this structure when a chain engine is created.
		/// </para>
		/// <para>
		/// hRoot is the store handle from <c>hRestrictedRoot</c> or, if <c>hRestrictedRoot</c> is <c>NULL</c>, the handle for System Store "Root."
		/// </para>
		/// <para>
		/// hWorld is a collection certificate store including sibling stores hRoot, "CA," "My," "Trust," and any additional stores whose
		/// handles are in the array pointed to by <c>rghAdditionalStore</c>.
		/// </para>
		/// <para>hTrust is the store handle from <c>hRestrictedTrust</c> or, if <c>hRestrictedTrust</c> is <c>NULL</c>, hWorld.</para>
		/// <para>
		/// hOther is <c>hRestrictedOther</c> plus hRoot or, if <c>hRestrictedTrust</c> is non- <c>NULL</c>, the hWorld collection store
		/// plus the store handle from <c>hRestrictedTrust</c>.
		/// </para>
		/// <para>
		/// Exclusive trust mode allows applications to specify trust anchors and peer-trusted certificates for certificate chain
		/// validation. In the exclusive trust mode, the root store and the trusted people store on the system are ignored, and the anchors
		/// and certificates pointed to by the <c>hExclusiveRoot</c> and <c>hExclusiveTrustedPeople</c> members are used instead.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_chain_engine_config typedef struct
		// _CERT_CHAIN_ENGINE_CONFIG { DWORD cbSize; HCERTSTORE hRestrictedRoot; HCERTSTORE hRestrictedTrust; HCERTSTORE hRestrictedOther;
		// DWORD cAdditionalStore; HCERTSTORE *rghAdditionalStore; DWORD dwFlags; DWORD dwUrlRetrievalTimeout; DWORD
		// MaximumCachedCertificates; DWORD CycleDetectionModulus; HCERTSTORE hExclusiveRoot; HCERTSTORE hExclusiveTrustedPeople; DWORD
		// dwExclusiveFlags; } CERT_CHAIN_ENGINE_CONFIG, *PCERT_CHAIN_ENGINE_CONFIG;
		[PInvokeData("wincrypt.h", MSDNShortId = "9e010eb9-2cbb-4fca-ba5c-4a5a50f23786")]
		[StructLayout(LayoutKind.Sequential)]
		public struct CERT_CHAIN_ENGINE_CONFIG
		{
			/// <summary>Size of this structure in bytes.</summary>
			public uint cbSize;

			/// <summary>
			/// This configuration parameter can be used to restrict the root store. If used, it can be the handle of any HCERTSTORE
			/// containing only a proper subset of the certificates in the root store.
			/// </summary>
			public HCERTSTORE hRestrictedRoot;

			/// <summary>Store handle. If used, restricts the stores searched to find CTLs.</summary>
			public HCERTSTORE hRestrictedTrust;

			/// <summary>Store handle. If used, restricts the stores searched for certificates and CRLs.</summary>
			public HCERTSTORE hRestrictedOther;

			/// <summary>Count of additional stores to be searched for certificates and CRLs needed to build chains.</summary>
			public uint cAdditionalStore;

			/// <summary>A pointer to an array of store handles for any additional stores to be searched in building chains.</summary>
			public IntPtr rghAdditionalStore;

			/// <summary>
			/// <para>The following flags are defined.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>CERT_CHAIN_CACHE_END_CERT 0x00000001</term>
			/// <term>
			/// Information in the end certificate is cached. By default, information in all certificates except the end certificate is
			/// cached as a chain is built. Setting this flag extends the caching to the end certificate.
			/// </term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_CACHE_ONLY_URL_RETRIEVAL 0x00000004</term>
			/// <term>Use only cached URLs in building a certificate chain. The Internet and intranet are not searched for URL-based objects.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_USE_LOCAL_MACHINE_STORE 0x00000008</term>
			/// <term>Build the chain using the LocalMachine registry location as opposed to the CurrentUser location.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_ENABLE_CACHE_AUTO_UPDATE 0x00000010</term>
			/// <term>Enable automatic updating of the cache as a chain is being built.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_ENABLE_SHARE_STORE 0x00000020</term>
			/// <term>Allow certificate stores used to build the chain to be shared.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_DISABLE_AIA 0x00002000</term>
			/// <term>Turn off Authority Information Access (AIA) retrievals explicitly.</term>
			/// </item>
			/// </list>
			/// </summary>
			public CertChainEngineFlags dwFlags;

			/// <summary>
			/// Number of milliseconds before a time-out for network based–URL object retrievals. Can be set to zero to use the default limit.
			/// </summary>
			public uint dwUrlRetrievalTimeout;

			/// <summary>
			/// Limit on the number of certificates that can be cached as a chain is built. Can be set to 0 to use the default limit.
			/// </summary>
			public uint MaximumCachedCertificates;

			/// <summary>
			/// <para>
			/// Number of certificates added to the chain before a check is made to determine whether there is a cycle of certificates in
			/// the chain. A cycle may be defined as having the same certificate in two different places in a chain.
			/// </para>
			/// <para>
			/// The lower the number, the more frequently checks will be made. Extra checking for cycles of certificates will slow the
			/// process considerably. This parameter can be set to zero to use the default limit.
			/// </para>
			/// </summary>
			public uint CycleDetectionModulus;

			/// <summary>
			/// <para>
			/// Handle to a certificate store that contains exclusive trust anchors. If either the <c>hExclusiveRoot</c> or
			/// <c>hExclusiveTrustedPeople</c> member points to a valid store, exclusive trust mode is used for the chain building.
			/// </para>
			/// <para><c>Windows 7 and Windows Server 2008 R2:</c> Support for this member begins.</para>
			/// </summary>
			public HCERTSTORE hExclusiveRoot;

			/// <summary>
			/// <para>
			/// Handle to a certificate store that contains application-specific peer trusted certificates. If either the
			/// <c>hExclusiveRoot</c> or <c>hExclusiveTrustedPeople</c> member points to a valid store, exclusive trust mode is used for the
			/// chain building.
			/// </para>
			/// <para><c>Windows 7 and Windows Server 2008 R2:</c> Support for this member begins.</para>
			/// </summary>
			public HCERTSTORE hExclusiveTrustedPeople;

			/// <summary>
			/// <para>
			/// The following flag can be set. The flag applies only if the <c>hExclusiveRoot</c> or <c>hExclusiveTrustedPeople</c> or both
			/// are not <c>NULL</c>.
			/// </para>
			/// <para><c>Windows 8 and Windows Server 2012:</c> Support for this member begins.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>CERT_CHAIN_EXCLUSIVE_ENABLE_CA_FLAG 0x00000001</term>
			/// <term>
			/// Indicates that a non-self-signed intermediate CA certificate in the hExclusiveRoot store should be treated as a trust anchor
			/// during certificate validation. If a certificate chains up to this CA, chain building is terminated and the certificate is
			/// considered trusted. No signature verification or revocation checking is performed on the CA certificate. By default, if this
			/// flag is not set, only self-signed certificates in the hExclusiveRoot store are treated as trust anchors. See also the
			/// CERT_TRUST_IS_CA_TRUSTED value in the CERT_TRUST_STATUS structure.
			/// </term>
			/// </item>
			/// </list>
			/// </summary>
			public CertChainEngineExclusiveFlags dwExclusiveFlags;
		}

		/// <summary>
		/// The <c>CERT_CHAIN_PARA</c> structure establishes the searching and matching criteria to be used in building a certificate chain.
		/// </summary>
		/// <remarks>
		/// <para>The following remarks apply when checking for strong signatures.</para>
		/// <list type="bullet">
		/// <item>
		/// <term>
		/// Set the <c>pStrongSignPara</c> member to check for strong signatures when using the CertGetCertificateChain or
		/// CertSelectCertificateChains function.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If a certificate without a strong signature is found in the chain, the <c>CERT_TRUST_HAS_WEAK_SIGNATURE</c> and
		/// <c>CERT_TRUST_IS_NOT_SIGNATURE_VALID</c> errors are set in the <c>dwErrorStatus</c> field of the CERT_TRUST_STATUS structure.
		/// The ppChainContext parameter of the CertGetCertificateChain function and the pprgpSelection parameter of the
		/// CertSelectCertificateChains function point to a CERT_CHAIN_CONTEXT structure which, in turn, points to the
		/// <c>CERT_TRUST_STATUS</c> structure.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If the chain is strong signed, the public key in the end certificate is checked to determine whether it satisfies the minimum
		/// public key length requirements for a strong signature. If the condition is not satisfied, the
		/// <c>CERT_TRUST_HAS_WEAK_SIGNATURE</c> and <c>CERT_TRUST_IS_NOT_SIGNATURE_VALID</c> errors are set in the <c>dwErrorStatus</c>
		/// field of the CERT_TRUST_STATUS structure. Set the <c>CERT_CHAIN_STRONG_SIGN_DISABLE_END_CHECK_FLAG</c> value in the
		/// <c>dwStrongSignFlags</c> member to disable this check.
		/// </term>
		/// </item>
		/// <item>
		/// <term>
		/// If the <c>CERT_STRONG_SIGN_ENABLE_CRL_CHECK</c> or <c>CERT_STRONG_SIGN_ENABLE_OCSP_CHECK</c> flags are set in the
		/// CERT_STRONG_SIGN_SERIALIZED_INFO structure referenced by the CERT_STRONG_SIGN_PARA structure pointed to by the
		/// <c>pStrongSignPara</c> member, and a CRL or OCSP response is found without a strong signature, the CRL or OCSP response will be
		/// treated as being offline. That is, the <c>CERT_TRUST_IS_OFFLINE_REVOCATION</c> and <c>CERT_TRUST_REVOCATION_STATUS_UNKNOWN</c>
		/// errors are set in the <c>dwErrorStatus</c> field of the CERT_TRUST_STATUS structure. Also, the <c>dwRevocationResult</c> member
		/// of the CERT_REVOCATION_INFO structure is set to <c>NTE_BAD_ALGID</c>.
		/// </term>
		/// </item>
		/// </list>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_chain_para typedef struct _CERT_CHAIN_PARA { DWORD
		// cbSize; CERT_USAGE_MATCH RequestedUsage; CERT_USAGE_MATCH RequestedIssuancePolicy; DWORD dwUrlRetrievalTimeout; BOOL
		// fCheckRevocationFreshnessTime; DWORD dwRevocationFreshnessTime; LPFILETIME pftCacheResync; PCCERT_STRONG_SIGN_PARA
		// pStrongSignPara; DWORD dwStrongSignFlags; } CERT_CHAIN_PARA, *PCERT_CHAIN_PARA;
		[PInvokeData("wincrypt.h", MSDNShortId = "86094e1c-be59-4a15-a05b-21769f80e653")]
		[StructLayout(LayoutKind.Sequential)]
		public struct CERT_CHAIN_PARA
		{
			/// <summary>The size, in bytes, of this structure.</summary>
			public uint cbSize;

			/// <summary>
			/// Structure indicating the kind of matching necessary to find issuer certificates for building a certificate chain. The
			/// structure pointed to indicates whether AND or OR logic is to be used in the matching process. The structure also includes an
			/// array of OIDs to be matched.
			/// </summary>
			public CERT_USAGE_MATCH RequestedUsage;

			/// <summary>
			/// <para>
			/// Optional structure that indicates the kind of issuance policy constraint matching that applies when building a certificate
			/// chain. The structure pointed to indicates whether AND or OR logic is to be used in the matching process. The structure also
			/// includes an array of OIDs to be matched.
			/// </para>
			/// <para>
			/// <c>Note</c> This member can be used only if <c>CERT_CHAIN_PARA_HAS_EXTRA_FIELDS</c> is defined by using the <c>#define</c>
			/// directive before including Wincrypt.h. If this value is defined, the application must zero all unused fields.
			/// </para>
			/// </summary>
			public CERT_USAGE_MATCH RequestedIssuancePolicy;

			/// <summary>
			/// <para>Optional time, in milliseconds, before revocation checking times out. This member is optional.</para>
			/// <para>
			/// <c>Note</c> This member can be used only if <c>CERT_CHAIN_PARA_HAS_EXTRA_FIELDS</c> is defined by using the <c>#define</c>
			/// directive before including Wincrypt.h. If this value is defined, the application must zero all unused fields.
			/// </para>
			/// </summary>
			public uint dwUrlRetrievalTimeout;

			/// <summary>
			/// <para>
			/// Optional member. When this flag is <c>TRUE</c>, an attempt is made to retrieve a new CRL if this update is greater than or
			/// equal to the current system time minus the <c>dwRevocationFreshnessTime</c> value. If this flag is not set, the CRL's next
			/// update time is used.
			/// </para>
			/// <para>
			/// <c>Note</c> This member can be used only if <c>CERT_CHAIN_PARA_HAS_EXTRA_FIELDS</c> is defined by using the <c>#define</c>
			/// directive before including Wincrypt.h. If this value is defined, the application must zero all unused fields.
			/// </para>
			/// </summary>
			[MarshalAs(UnmanagedType.Bool)] public bool fCheckRevocationFreshnessTime;

			/// <summary>
			/// <para>The current time, in seconds, minus the CRL's update time of all elements checked.</para>
			/// <para>
			/// <c>Note</c> This member can be used only if <c>CERT_CHAIN_PARA_HAS_EXTRA_FIELDS</c> is defined by using the <c>#define</c>
			/// directive before including Wincrypt.h. If this value is defined, the application must zero all unused fields.
			/// </para>
			/// </summary>
			public uint dwRevocationFreshnessTime;

			/// <summary>
			/// <para>
			/// Optional member. When set to a non- <c>NULL</c> value, information cached before the time specified is considered to be not
			/// valid and cache resynchronization is performed.
			/// </para>
			/// <para><c>Windows Vista:</c> Support for this member begins.</para>
			/// <para>
			/// <c>Note</c> This member can be used only if <c>CERT_CHAIN_PARA_HAS_EXTRA_FIELDS</c> is defined by using the <c>#define</c>
			/// directive before including Wincrypt.h. If this value is defined, the application must zero all unused fields.
			/// </para>
			/// </summary>
			public IntPtr pftCacheResync;

			/// <summary>
			/// <para>Optional. Specify a pointer to a CERT_STRONG_SIGN_PARA structure to enable strong signature checking.</para>
			/// <para><c>Windows 8 and Windows Server 2012:</c> Support for this member begins.</para>
			/// <para>
			/// <c>Note</c> This member can be used only if <c>CERT_CHAIN_PARA_HAS_EXTRA_FIELDS</c> is defined by using the <c>#define</c>
			/// directive before including Wincrypt.h. If this value is defined, the application must zero all unused fields.
			/// </para>
			/// </summary>
			public IntPtr pStrongSignPara;

			/// <summary>
			/// <para>Optional flags that modify chain retrieval behavior. This can be zero or the following value.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>CERT_CHAIN_STRONG_SIGN_DISABLE_END_CHECK_FLAG 0x00000001</term>
			/// <term>
			/// If the chain is strong signed, the public key in the end certificate will be checked to verify whether it satisfies the
			/// minimum public key length requirements for a strong signature. You can specify CERT_CHAIN_STRONG_SIGN_DISABLE_END_CHECK_FLAG
			/// to disable default checking.
			/// </term>
			/// </item>
			/// </list>
			/// <para><c>Windows 8 and Windows Server 2012:</c> Support for this property begins.</para>
			/// <para>
			/// <c>Note</c> This member can be used only if <c>CERT_CHAIN_PARA_HAS_EXTRA_FIELDS</c> is defined by using the <c>#define</c>
			/// directive before including Wincrypt.h. If this value is defined, the application must zero all unused fields.
			/// </para>
			/// </summary>
			public uint dwStrongSignFlags;
		}

		/// <summary>
		/// The <c>CERT_CHAIN_POLICY_PARA</c> structure contains information used in CertVerifyCertificateChainPolicy to establish policy
		/// criteria for the verification of certificate chains.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_chain_policy_para typedef struct
		// _CERT_CHAIN_POLICY_PARA { DWORD cbSize; DWORD dwFlags; void *pvExtraPolicyPara; } CERT_CHAIN_POLICY_PARA, *PCERT_CHAIN_POLICY_PARA;
		[PInvokeData("wincrypt.h", MSDNShortId = "5e4fffcb-132b-42c0-81b2-9f866e274c32")]
		[StructLayout(LayoutKind.Sequential)]
		public struct CERT_CHAIN_POLICY_PARA
		{
			/// <summary>The size, in bytes, of this structure.</summary>
			public uint cbSize;

			/// <summary>
			/// <para>
			/// A set of flags that indicate conditions that could potentially be not valid and that are to be ignored in building
			/// certificate chains.
			/// </para>
			/// <para>The pszPolicyOID parameter of the CertVerifyCertificateChainPolicy function can contain one of the following values:</para>
			/// <list type="bullet">
			/// <item>
			/// <term><c>CERT_CHAIN_POLICY_BASE</c></term>
			/// </item>
			/// <item>
			/// <term><c>CERT_CHAIN_POLICY_AUTHENTICODE</c></term>
			/// </item>
			/// <item>
			/// <term><c>CERT_CHAIN_POLICY_AUTHENTICODE_TS</c></term>
			/// </item>
			/// <item>
			/// <term><c>CERT_CHAIN_POLICY_SSL</c></term>
			/// </item>
			/// <item>
			/// <term><c>CERT_CHAIN_POLICY_NT_AUTH</c></term>
			/// </item>
			/// </list>
			/// <para>If the</para>
			/// <para>pszPolicyOID</para>
			/// <para>parameter of the</para>
			/// <para>CertVerifyCertificateChainPolicy</para>
			/// <para>
			/// function contains one of the preceding values, then this member can be zero or a combination of one or more of the following values.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_NOT_TIME_VALID_FLAG</term>
			/// <term>Ignore not time valid errors.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_CTL_NOT_TIME_VALID_FLAG</term>
			/// <term>Ignore certificate trust list (CTL) not time valid errors.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_NOT_TIME_NESTED_FLAG</term>
			/// <term>Ignore time nesting errors.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_ALL_NOT_TIME_VALID_FLAGS</term>
			/// <term>Ignore all time validity errors.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_INVALID_BASIC_CONSTRAINTS_FLAG</term>
			/// <term>Ignore basic constraint errors.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_ALLOW_UNKNOWN_CA_FLAG</term>
			/// <term>Allow untrusted roots.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_WRONG_USAGE_FLAG</term>
			/// <term>Ignore invalid usage errors.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_INVALID_NAME_FLAG</term>
			/// <term>Ignore invalid name errors.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_INVALID_POLICY_FLAG</term>
			/// <term>Ignore invalid policy errors.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_END_REV_UNKNOWN_FLAG</term>
			/// <term>Ignores errors in obtaining valid revocation information.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_CTL_SIGNER_REV_UNKNOWN_FLAG</term>
			/// <term>Ignores errors in obtaining valid CTL revocation information.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_CA_REV_UNKNOWN_FLAG</term>
			/// <term>Ignores errors in obtaining valid certification authority (CA) revocation information.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_ROOT_REV_UNKNOWN_FLAG</term>
			/// <term>Ignores errors in obtaining valid root revocation information.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_ALL_REV_UNKNOWN_FLAGS</term>
			/// <term>Ignores errors in obtaining valid revocation information.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_ALLOW_TESTROOT_FLAG</term>
			/// <term>Allow untrusted test roots.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_TRUST_TESTROOT_FLAG</term>
			/// <term>Always trust test roots.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_NOT_SUPPORTED_CRITICAL_EXT_FLAG</term>
			/// <term>Ignore critical extension not supported errors.</term>
			/// </item>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_PEER_TRUST_FLAG</term>
			/// <term>Ignore peer trusts.</term>
			/// </item>
			/// </list>
			/// <para>
			/// If the pszPolicyOID parameter of the CertVerifyCertificateChainPolicy function contains
			/// <c>CERT_CHAIN_POLICY_BASIC_CONSTRAINTS</c>, this member can be zero or a combination of one or more of the following values.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>CERT_CHAIN_POLICY_IGNORE_PEER_TRUST_FLAG</term>
			/// <term>Ignore peer trusts.</term>
			/// </item>
			/// <item>
			/// <term>BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_CA_FLAG</term>
			/// <term>Checks if the first certificate element is a CA.</term>
			/// </item>
			/// <item>
			/// <term>BASIC_CONSTRAINTS_CERT_CHAIN_POLICY_END_ENTITY_FLAG</term>
			/// <term>Checks if the first certificate element is an end entity.</term>
			/// </item>
			/// </list>
			/// <para>
			/// If the pszPolicyOID parameter of the CertVerifyCertificateChainPolicy function contains
			/// <c>CERT_CHAIN_POLICY_MICROSOFT_ROOT</c>, this member can be zero or the following value.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>MICROSOFT_ROOT_CERT_CHAIN_POLICY_ENABLE_TEST_ROOT_FLAG</term>
			/// <term>Also check for the Microsoft test roots in addition to the Microsoft public root.</term>
			/// </item>
			/// </list>
			/// </summary>
			public CertChainPolicyFlags dwFlags;

			/// <summary>The address of a pszPolicyOID-specific structure that provides additional validity policy conditions.</summary>
			public IntPtr pvExtraPolicyPara;
		}

		/// <summary>
		/// The <c>CERT_CHAIN_POLICY_STATUS</c> structure holds certificate chain status information returned by the
		/// CertVerifyCertificateChainPolicy function when the certificate chains are validated.
		/// </summary>
		/// <remarks>
		/// If both <c>lChainIndex</c> and <c>lElementIndex</c> are set to –1, the error or condition that is not valid applies to the whole
		/// chain context. If only <c>lElementIndex</c> is set to –1, the error or condition that is not valid applies to the chain indexed
		/// by <c>lChainIndex</c>. Otherwise, the error or condition that is not valid applies to the certificate element at
		/// pChainContext-&gt;rgpChain[ <c>lChainIndex</c>]-&gt;rgpElement[ <c>lElementIndex</c>].
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_chain_policy_status typedef struct
		// _CERT_CHAIN_POLICY_STATUS { DWORD cbSize; DWORD dwError; LONG lChainIndex; LONG lElementIndex; void *pvExtraPolicyStatus; }
		// CERT_CHAIN_POLICY_STATUS, *PCERT_CHAIN_POLICY_STATUS;
		[PInvokeData("wincrypt.h", MSDNShortId = "599a09b6-fe9e-4489-99ae-8a88fa78a660")]
		[StructLayout(LayoutKind.Sequential)]
		public struct CERT_CHAIN_POLICY_STATUS
		{
			/// <summary>The size, in bytes, of this structure.</summary>
			public uint cbSize;

			/// <summary>
			/// <para>
			/// A value that indicates that an error or invalid condition was encountered during the validation process. The values of this
			/// member are specific to the policy type as specified by the value of the pszPolicyOID parameter of the
			/// CertVerifyCertificateChainPolicy function.
			/// </para>
			/// <para>Base Policy errors ( <c>CERT_CHAIN_POLICY_BASE</c>)</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>TRUST_E_CERT_SIGNATURE 0x80096004L</term>
			/// <term>The signature of the certificate cannot be verified.</term>
			/// </item>
			/// <item>
			/// <term>CRYPT_E_REVOKED 0x80092010L</term>
			/// <term>The certificate or signature has been revoked.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_UNTRUSTEDROOT 0x800B0109L</term>
			/// <term>A certification chain processed correctly but terminated in a root certificate that is not trusted by the trust provider.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_UNTRUSTEDTESTROOT 0x800B010DL</term>
			/// <term>The root certificate is a testing certificate, and policy settings disallow test certificates.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_CHAINING 0x800B010AL</term>
			/// <term>A chain of certificates was not correctly created.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_WRONG_USAGE 0x800B0110L</term>
			/// <term>The certificate is not valid for the requested usage.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_EXPIRED 0x800B0101L</term>
			/// <term>A required certificate is not within its validity period.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_INVALID_NAME 0x800B0114L</term>
			/// <term>The certificate has an invalid name. Either the name is not included in the permitted list, or it is explicitly excluded.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_INVALID_POLICY 0x800B0113L</term>
			/// <term>The certificate has an invalid policy.</term>
			/// </item>
			/// <item>
			/// <term>TRUST_E_BASIC_CONSTRAINTS 0x80096019L</term>
			/// <term>The basic constraints of the certificate are not valid, or they are missing.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_CRITICAL 0x800B0105L</term>
			/// <term>The certificate is being used for a purpose other than the purpose specified by its CA.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_VALIDITYPERIODNESTING 0x800B0102L</term>
			/// <term>The validity periods of the certification chain do not nest correctly.</term>
			/// </item>
			/// <item>
			/// <term>CRYPT_E_NO_REVOCATION_CHECK 0x80092012L</term>
			/// <term>The revocation function was unable to check revocation for the certificate.</term>
			/// </item>
			/// <item>
			/// <term>CRYPT_E_REVOCATION_OFFLINE 0x80092013L</term>
			/// <term>The revocation function was unable to check revocation because the revocation server was offline.</term>
			/// </item>
			/// </list>
			/// <para>Basic Constraints Policy errors ( <c>CERT_CHAIN_POLICY_BASIC_CONSTRAINTS</c>).</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>TRUST_E_BASIC_CONSTRAINTS 0x80096019L</term>
			/// <term>The basic constraints of the certificate are not valid, or they are missing.</term>
			/// </item>
			/// </list>
			/// <para>Authenticode Policy errors ( <c>CERT_CHAIN_POLICY_AUTHENTICODE</c> and <c>CERT_CHAIN_POLICY_AUTHENTICODE_TS</c>).</para>
			/// <para>These errors are in addition to the Base Policy errors.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>CERT_E_PURPOSE 0x800B0106L</term>
			/// <term>The certificate is being used for a purpose other than one specified by the issuing CA.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_REVOKED 0x800B010CL</term>
			/// <term>The certificate has been explicitly revoked by the issuer.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_REVOCATION_FAILURE 0x800B010EL</term>
			/// <term>The revocation process could not continue, and the certificate could not be checked.</term>
			/// </item>
			/// </list>
			/// <para>SSL Policy errors ( <c>CERT_CHAIN_POLICY_SSL</c>).</para>
			/// <para>These errors are in addition to the Base Policy errors.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>CERT_E_UNTRUSTEDROOT 0x800B0109L</term>
			/// <term>A certification chain processed correctly but terminated in a root certificate that is not trusted by the trust provider.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_CN_NO_MATCH 0x800B010FL</term>
			/// <term>The certificate's CN name does not match the passed value.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_PURPOSE 0x800B0106L</term>
			/// <term>The certificate is being used for a purpose other than the purposes specified by its CA.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_ROLE 0x800B0103L</term>
			/// <term>A certificate that can only be used as an end-entity is being used as a CA or vice versa.</term>
			/// </item>
			/// </list>
			/// <para>Microsoft Root Policy errors ( <c>CERT_CHAIN_POLICY_MICROSOFT_ROOT</c>).</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>CERT_E_UNTRUSTEDROOT 0x800B0109L</term>
			/// <term>A certification chain processed correctly but terminated in a root certificate that is not trusted by the trust provider.</term>
			/// </item>
			/// </list>
			/// <para>EV Policy errors.</para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>CERT_E_CHAINING 0x800B010AL</term>
			/// <term>The certificate chain to a trusted root authority could not be built.</term>
			/// </item>
			/// <item>
			/// <term>CERT_E_WRONG_USAGE 0x800B0110L</term>
			/// <term>The certificate is not valid for the requested usage.</term>
			/// </item>
			/// </list>
			/// </summary>
			public uint dwError;

			/// <summary>
			/// Index that indicates the chain in which an error or condition that is not valid was found. For more information, see Remarks.
			/// </summary>
			public int lChainIndex;

			/// <summary>
			/// Index that indicates the element in a chain where an error or condition that is not valid was found. For more information,
			/// see Remarks.
			/// </summary>
			public int lElementIndex;

			/// <summary>
			/// A pointer to a structure. The structure type is determined by the value of the <c>pszPolicyOID</c> parameter of the
			/// CertVerifyCertificateChainPolicy function. In addition to <c>dwError</c> errors, policy OID–specific extra status can also
			/// be returned here to provide additional chain status information. This pointer can be optionally set to point to an
			/// AUTHENTICODE_EXTRA_CERT_CHAIN_POLICY_STATUS structure.
			/// </summary>
			public IntPtr pvExtraPolicyStatus;
		}

		/// <summary>
		/// The <c>CERT_USAGE_MATCH</c> structure provides criteria for identifying issuer certificates to be used to build a certificate chain.
		/// </summary>
		/// <remarks>
		/// <para>If the dwType member is set to <c>USAGE_MATCH_TYPE_OR</c>, the Usage member cannot be empty.</para>
		/// <para>
		/// If the dwType member is set to <c>USAGE_MATCH_TYPE_AND</c>, an empty Usage member means that any nested usage in the chain will work.
		/// </para>
		/// <para>The following describes the behavior given two enhanced key usage (EKU) extensions EKU A and EKU B.</para>
		/// <para>AND Logic</para>
		/// <para>
		/// If the caller specifies EKU A AND EKU B then the target certificate is valid if EKU A and EKU B are supported by every
		/// certificate in the path (either by an explicit EKU setting or through an absent EKU extension in CA certificates.)
		/// </para>
		/// <para>OR Logic</para>
		/// <para>
		/// If the caller specifies EKU A OR EKU B then the target certificate is valid if either EKU A or EKU B is supported in the path.
		/// </para>
		/// <para>
		/// Besides the simple case where the certificates in the path contain EKU A or EKU B, the <c>OR</c> clause has the following
		/// special evaluation.
		/// </para>
		/// <para>Given the following path, the <c>OR</c> test is deemed valid:</para>
		/// <para>
		/// Although the intersection of the EKUs in the chain is an empty set, the use of the EE certificate is valid for EKU A because the
		/// request to the cryptography API specifies that the certificate is valid if each certificate of the path supports either EKU A OR
		/// EKU B.
		/// </para>
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cert_usage_match typedef struct _CERT_USAGE_MATCH { DWORD
		// dwType; CERT_ENHKEY_USAGE Usage; } CERT_USAGE_MATCH, *PCERT_USAGE_MATCH;
		[PInvokeData("wincrypt.h", MSDNShortId = "6154f1f7-4293-4b8e-91ab-9f57bb6f5743")]
		[StructLayout(LayoutKind.Sequential)]
		public struct CERT_USAGE_MATCH
		{
			/// <summary>
			/// <para>
			/// Determines the kind of issuer matching to be done. In <c>AND</c> logic, the certificate must meet all criteria. In <c>OR</c>
			/// logic, the certificate must meet at least one of the criteria. The following codes are defined to determine the logic used
			/// in the match. For more information about how this applied, see Remarks.
			/// </para>
			/// <list type="table">
			/// <listheader>
			/// <term>Value</term>
			/// <term>Meaning</term>
			/// </listheader>
			/// <item>
			/// <term>USAGE_MATCH_TYPE_AND</term>
			/// <term>AND logic</term>
			/// </item>
			/// <item>
			/// <term>USAGE_MATCH_TYPE_OR</term>
			/// <term>OR logic</term>
			/// </item>
			/// </list>
			/// <para>Default usage match logic is USAGE_MATCH_TYPE_AND.</para>
			/// </summary>
			public UsageMatchType dwType;

			/// <summary>
			/// CERT_ENHKEY_USAGE structure ( <c>CERT_ENHKEY_USAGE</c> is an alternate typedef name for the <c>CTL_USAGE</c> structure) that
			/// includes an array of certificate object identifiers (OIDs) that a certificate must match in order to be valid.
			/// </summary>
			public CTL_USAGE Usage;
		}

		/// <summary>
		/// The <c>CMSG_SIGNED_ENCODE_INFO</c> structure contains information to be passed to CryptMsgOpenToEncode if dwMsgType is CMSG_SIGNED.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-cmsg_signed_encode_info typedef struct
		// _CMSG_SIGNED_ENCODE_INFO { DWORD cbSize; DWORD cSigners; PCMSG_SIGNER_ENCODE_INFO rgSigners; DWORD cCertEncoded; PCERT_BLOB
		// rgCertEncoded; DWORD cCrlEncoded; PCRL_BLOB rgCrlEncoded; DWORD cAttrCertEncoded; PCERT_BLOB rgAttrCertEncoded; }
		// CMSG_SIGNED_ENCODE_INFO, *PCMSG_SIGNED_ENCODE_INFO;
		[PInvokeData("wincrypt.h", MSDNShortId = "93138744-8316-461b-908a-1eab47e83f63")]
		[StructLayout(LayoutKind.Sequential)]
		public struct CMSG_SIGNED_ENCODE_INFO
		{
			/// <summary>Size of this structure in bytes.</summary>
			public uint cbSize;

			/// <summary>Number of elements in the <c>rgSigners</c> array.</summary>
			public uint cSigners;

			/// <summary>Array of pointers to CMSG_SIGNER_ENCODE_INFOstructures each holding signer information.</summary>
			public IntPtr rgSigners;

			/// <summary>Number of elements in the <c>rgCertEncoded</c> array.</summary>
			public uint cCertEncoded;

			/// <summary>Array of pointers to CERT_BLOB structures, each containing an encoded certificate.</summary>
			public IntPtr rgCertEncoded;

			/// <summary>Number of elements in the <c>rgCrlEncoded</c> array.</summary>
			public uint cCrlEncoded;

			/// <summary>Array of pointers to CRL_BLOB structures, each containing an encoded CRL.</summary>
			public IntPtr rgCrlEncoded;

			/// <summary>
			/// Number of elements in the <c>rgAttrCertEncoded</c> array. Used only if CMSG_SIGNED_ENCODE_INFO_HAS_CMS_FIELDS is defined.
			/// </summary>
			public uint cAttrCertEncoded;

			/// <summary>
			/// Array of encoded attribute certificates. Used only if CMSG_SIGNED_ENCODE_INFO_HAS_CMS_FIELDS is defined. This array of
			/// encoded attribute certificates can be used with CMS for PKCS #7 processing.
			/// </summary>
			public IntPtr rgAttrCertEncoded;
		}

		/// <summary>
		/// The <c>CTL_VERIFY_USAGE_PARA</c> structure contains parameters used by CertVerifyCTLUsage to establish the validity of a CTL's usage.
		/// </summary>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-ctl_verify_usage_para typedef struct
		// _CTL_VERIFY_USAGE_PARA { DWORD cbSize; CRYPT_DATA_BLOB ListIdentifier; DWORD cCtlStore; HCERTSTORE *rghCtlStore; DWORD
		// cSignerStore; HCERTSTORE *rghSignerStore; } CTL_VERIFY_USAGE_PARA, *PCTL_VERIFY_USAGE_PARA;
		[PInvokeData("wincrypt.h", MSDNShortId = "bf9a3c81-f8c4-45a6-b045-8cbefebebbd3")]
		[StructLayout(LayoutKind.Sequential)]
		public struct CTL_VERIFY_USAGE_PARA
		{
			/// <summary>Size of this structure in bytes.</summary>
			public uint cbSize;

			/// <summary>
			/// <para>
			/// BLOB that specifies a <c>ListIdentifier</c> of a CTL to be found or verified. Normally the <c>cbData</c> member of the
			/// <c>ListIdentifier</c> BLOB will be zero, indicating that a CTL with any <c>ListIdentifier</c> can be a match.
			/// </para>
			/// <para>
			/// To match only CTLs with no <c>ListIdentifier</c>, the <c>cbData</c> member of the <c>ListIdentifier</c> BLOB is set to CTL_FIND_NO_LIST_ID_CBDATA.
			/// </para>
			/// <para>
			/// If an issuer creates multiple CTLs for the same <c>SubjectUsage</c>, a <c>ListIdentifier</c> can distinguish among them.
			/// </para>
			/// </summary>
			public CRYPTOAPI_BLOB ListIdentifier;

			/// <summary>The count of stores to be searched for a matching CTL.</summary>
			public uint cCtlStore;

			/// <summary>Array of handles of stores to be searched to find a matching CTL.</summary>
			public IntPtr rghCtlStore;

			/// <summary>Count of stores to be searched for acceptable CTL signers.</summary>
			public uint cSignerStore;

			/// <summary>Array of handles of stores to be searched for acceptable CTL signers.</summary>
			public IntPtr rghSignerStore;
		}

		/// <summary>
		/// The <c>CTL_VERIFY_USAGE_STATUS</c> structure contains information about a Certificate Trust List (CTL) returned by CertVerifyCTLUsage.
		/// </summary>
		/// <remarks>
		/// The members <c>dwError</c>, <c>dwFlags</c>, <c>dwCtlEntryIndex</c>, and <c>dwSignerIndex</c> should be initialized to zero by
		/// the calling application.
		/// </remarks>
		// https://docs.microsoft.com/en-us/windows/win32/api/wincrypt/ns-wincrypt-ctl_verify_usage_status typedef struct
		// _CTL_VERIFY_USAGE_STATUS { DWORD cbSize; DWORD dwError; DWORD dwFlags; PCCTL_CONTEXT *ppCtl; DWORD dwCtlEntryIndex;
		// PCCERT_CONTEXT *ppSigner; DWORD dwSignerIndex; } CTL_VERIFY_USAGE_STATUS, *PCTL_VERIFY_USAGE_STATUS;
		[PInvokeData("wincrypt.h", MSDNShortId = "2b7ef953-9422-4dcf-b293-a78a06bb080e")]
		[StructLayout(LayoutKind.Sequential)]
		public struct CTL_VERIFY_USAGE_STATUS
		{
			/// <summary>
			/// The size, in bytes, of the structure. The application calling CertVerifyCTLUsage sets this parameter. If <c>cbSize</c> is
			/// not greater than or equal to the required size of the structure, <c>CertVerifyCTLUsage</c> returns <c>FALSE</c> and
			/// GetLastError returns <c>E_INVALIDARG</c>.
			/// </summary>
			public uint cbSize;

			/// <summary>
			/// The error status, if any, returned by the call to CertVerifyCTLUsage. For the list of possible error values, see the Return
			/// Values section in <c>CertVerifyCTLUsage</c>.
			/// </summary>
			public uint dwError;

			/// <summary>
			/// If <c>CERT_VERIFY_UPDATED_CTL_FLAG</c> is returned, CertVerifyCTLUsage updated a CTL whose time was no longer valid with a
			/// new, time-valid CTL.
			/// </summary>
			public CtlVerifyUsageStatusFlags dwFlags;

			/// <summary>
			/// <para>
			/// Pointer to a pointer to a CTL context containing the matched subject. The calling application can set this pointer to
			/// <c>NULL</c> to indicate that a CTL containing the subject is not to be returned.
			/// </para>
			/// <para>If <c>ppCtl</c> is not <c>NULL</c>, the calling application must free the returned context using CertFreeCTLContext.</para>
			/// </summary>
			public IntPtr ppCtl;

			/// <summary>Returns the array location of the matching subject's entry in the CTL's array.</summary>
			public uint dwCtlEntryIndex;

			/// <summary>
			/// <para>
			/// A pointer to a pointer to the certificate context of the signer of the CTL. This pointer can be set to <c>NULL</c> by the
			/// calling application indicating that the certificate of the signer of the CTL is not to be returned.
			/// </para>
			/// <para>If <c>ppSigner</c> is not <c>NULL</c>, the calling application must free the returned context using CertFreeCTLContext.</para>
			/// </summary>
			public IntPtr ppSigner;

			/// <summary>Index of the signer actually used. Needed if a message has more than one signer.</summary>
			public uint dwSignerIndex;
		}

		/// <summary>Provides a handle to a CERT_CHAIN_CONTEXT.</summary>
		[StructLayout(LayoutKind.Sequential)]
		public struct PCCERT_CHAIN_CONTEXT : IHandle
		{
			private IntPtr handle;

			/// <summary>Initializes a new instance of the <see cref="PCCERT_CHAIN_CONTEXT"/> struct.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			public PCCERT_CHAIN_CONTEXT(IntPtr preexistingHandle) => handle = preexistingHandle;

			/// <summary>Returns an invalid handle by instantiating a <see cref="PCCERT_CHAIN_CONTEXT"/> object with <see cref="IntPtr.Zero"/>.</summary>
			public static PCCERT_CHAIN_CONTEXT NULL => new PCCERT_CHAIN_CONTEXT(IntPtr.Zero);

			/// <summary>Gets a value indicating whether this instance is a null handle.</summary>
			public bool IsNull => handle == IntPtr.Zero;

			/// <summary>Performs an explicit conversion from <see cref="PCCERT_CHAIN_CONTEXT"/> to <see cref="IntPtr"/>.</summary>
			/// <param name="h">The handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static explicit operator IntPtr(PCCERT_CHAIN_CONTEXT h) => h.handle;

			/// <summary>Performs an explicit conversion from <see cref="PCCERT_CHAIN_CONTEXT"/> to <see cref="CERT_CHAIN_CONTEXT"/>.</summary>
			/// <param name="h">The <see cref="PCCERT_CHAIN_CONTEXT"/> instance.</param>
			/// <returns>The resulting <see cref="CERT_CHAIN_CONTEXT"/> instance from the conversion.</returns>
			public static explicit operator CERT_CHAIN_CONTEXT(PCCERT_CHAIN_CONTEXT h) => h.handle.ToStructure<CERT_CHAIN_CONTEXT>();

			/// <summary>Performs an implicit conversion from <see cref="IntPtr"/> to <see cref="PCCERT_CHAIN_CONTEXT"/>.</summary>
			/// <param name="h">The pointer to a handle.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator PCCERT_CHAIN_CONTEXT(IntPtr h) => new PCCERT_CHAIN_CONTEXT(h);

			/// <summary>Implements the operator !=.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator !=(PCCERT_CHAIN_CONTEXT h1, PCCERT_CHAIN_CONTEXT h2) => !(h1 == h2);

			/// <summary>Implements the operator ==.</summary>
			/// <param name="h1">The first handle.</param>
			/// <param name="h2">The second handle.</param>
			/// <returns>The result of the operator.</returns>
			public static bool operator ==(PCCERT_CHAIN_CONTEXT h1, PCCERT_CHAIN_CONTEXT h2) => h1.Equals(h2);

			/// <inheritdoc/>
			public override bool Equals(object obj) => obj is PCCERT_CHAIN_CONTEXT h ? handle == h.handle : false;

			/// <inheritdoc/>
			public override int GetHashCode() => handle.GetHashCode();

			/// <inheritdoc/>
			public IntPtr DangerousGetHandle() => handle;
		}

		/// <summary>Provides a <see cref="SafeHandle"/> for <see cref="HCERTCHAINENGINE"/> that is disposed using <see cref="CertFreeCertificateChainEngine"/>.</summary>
		public class SafeHCERTCHAINENGINE : SafeHANDLE
		{
			/// <summary>Initializes a new instance of the <see cref="SafeHCERTCHAINENGINE"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			/// <param name="ownsHandle">
			/// <see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).
			/// </param>
			public SafeHCERTCHAINENGINE(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

			/// <summary>Initializes a new instance of the <see cref="SafeHCERTCHAINENGINE"/> class.</summary>
			private SafeHCERTCHAINENGINE() : base() { }

			/// <summary>Performs an implicit conversion from <see cref="SafeHCERTCHAINENGINE"/> to <see cref="HCERTCHAINENGINE"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator HCERTCHAINENGINE(SafeHCERTCHAINENGINE h) => h.handle;

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle() { CertFreeCertificateChainEngine(handle); return true; }
		}

		/// <summary>Provides a <see cref="SafeHandle"/> for <see cref="PCCERT_CHAIN_CONTEXT"/> that is disposed using <see cref="CertFreeCertificateChain"/>.</summary>
		public class SafePCCERT_CHAIN_CONTEXT : SafeHANDLE
		{
			/// <summary>Initializes a new instance of the <see cref="SafePCCERT_CHAIN_CONTEXT"/> class and assigns an existing handle.</summary>
			/// <param name="preexistingHandle">An <see cref="IntPtr"/> object that represents the pre-existing handle to use.</param>
			/// <param name="ownsHandle">
			/// <see langword="true"/> to reliably release the handle during the finalization phase; otherwise, <see langword="false"/> (not recommended).
			/// </param>
			public SafePCCERT_CHAIN_CONTEXT(IntPtr preexistingHandle, bool ownsHandle = true) : base(preexistingHandle, ownsHandle) { }

			/// <summary>Initializes a new instance of the <see cref="SafePCCERT_CHAIN_CONTEXT"/> class.</summary>
			private SafePCCERT_CHAIN_CONTEXT() : base() { }

			/// <summary>Performs an implicit conversion from <see cref="SafePCCERT_CHAIN_CONTEXT"/> to <see cref="PCCERT_CHAIN_CONTEXT"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The result of the conversion.</returns>
			public static implicit operator PCCERT_CHAIN_CONTEXT(SafePCCERT_CHAIN_CONTEXT h) => h.handle;

			/// <summary>Performs an explicit conversion from <see cref="SafePCCERT_CHAIN_CONTEXT"/> to <see cref="CERT_CHAIN_CONTEXT"/>.</summary>
			/// <param name="h">The safe handle instance.</param>
			/// <returns>The resulting <see cref="CERT_CHAIN_CONTEXT"/> instance from the conversion.</returns>
			public static explicit operator CERT_CHAIN_CONTEXT(SafePCCERT_CHAIN_CONTEXT h) => h.handle.ToStructure<CERT_CHAIN_CONTEXT>();

			/// <inheritdoc/>
			protected override bool InternalReleaseHandle() { CertFreeCertificateChain(handle); return true; }
		}

		/// <summary>Predefined verify chain policies.</summary>
		public static class CertVerifyChainPolicy
		{
			/// <summary/>
			public const int CERT_CHAIN_POLICY_BASE = 1;
			/// <summary/>
			public const int CERT_CHAIN_POLICY_AUTHENTICODE = 2;
			/// <summary/>
			public const int CERT_CHAIN_POLICY_AUTHENTICODE_TS = 3;
			/// <summary/>
			public const int CERT_CHAIN_POLICY_SSL = 4;
			/// <summary/>
			public const int CERT_CHAIN_POLICY_BASIC_CONSTRAINTS = 5;
			/// <summary/>
			public const int CERT_CHAIN_POLICY_NT_AUTH = 6;
			/// <summary/>
			public const int CERT_CHAIN_POLICY_MICROSOFT_ROOT = 7;
			/// <summary/>
			public const int CERT_CHAIN_POLICY_EV = 8;
			/// <summary/>
			public const int CERT_CHAIN_POLICY_SSL_F12 = 9;
			/// <summary/>
			public const int CERT_CHAIN_POLICY_SSL_HPKP_HEADER = 10;
			/// <summary/>
			public const int CERT_CHAIN_POLICY_THIRD_PARTY_ROOT = 11;
			/// <summary/>
			public const int CERT_CHAIN_POLICY_SSL_KEY_PIN = 12;
		}
	}
}