How to use INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT with InternetQueryOption in C#

Hi all,

The other day I needed to use the certificate chain context (CERT_CHAIN_CONTEXT structure) returned by a call to InternetQueryOption, in C# .

The call in C++  looks like this:

 PCCERT_CHAIN_CONTEXT CertCtx=NULL; 
… 
if (InternetQueryOption(hReq, INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT, (LPVOID)&CertCtx, &cbCertSize)) 
{ 
 PCCERT_CHAIN_CONTEXT pChainContext=CertCtx; 
 … 
} 
 

Some additional info about this call can be found here:

Option Flags

" INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT
105
Retrieves the server’s certificate-chain context as a duplicated PCCERT_CHAIN_CONTEXT. You may pass this duplicated context to any Crypto API function
which takes a PCCERT_CHAIN_CONTEXT. You must call CertFreeCertificateChain on the returned PCCERT_CHAIN_CONTEXT when you are done with the certificate-chain context.
Version: Requires Internet Explorer 8.0."

 

I got a good C++ sample from here: “Understanding the new WinInet option INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT”. So I took that sample as a base. I also used some of the p/invoke code I had already created for this C# sample: How to call InternetErrorDlg to deal with certificate issues on SSL connections (C#).

This is the C# sample I created:

<SAMPLE file="form1.cs">

 using System; 
using System.Collections.Generic; 
using System.ComponentModel; 
using System.Data; 
using System.Drawing; 
using System.Linq; 
using System.Text; 
using System.Windows.Forms; 
using System.Runtime.InteropServices; 
 
namespace WindowsFormsApplication1 
{ 
 public partial class Form1 : Form 
 { 
 public Form1() 
 { 
 InitializeComponent(); 
 } 
 
 private void button1_Click(object sender, EventArgs e) 
 { 
 // Consts 
 const int SIZE = 255; 
 
 // Variables 
 Win32.CERT_CHAIN_CONTEXT certChainContext = new Win32.CERT_CHAIN_CONTEXT(); 
 Win32.CERT_SIMPLE_CHAIN certSimpleChain = new Win32.CERT_SIMPLE_CHAIN(); 
 //Win32.CERT_CONTEXT certContext = new Win32.CERT_CONTEXT(); 
 Win32.CERT_CHAIN_ELEMENT certChainElement = new Win32.CERT_CHAIN_ELEMENT(); 
 StringBuilder pszSubject = new StringBuilder(SIZE); 
 StringBuilder pszIssuer = new StringBuilder(SIZE); 
 IntPtr hInternet = IntPtr.Zero; 
 IntPtr hConnect = IntPtr.Zero; 
 IntPtr hRequest = IntPtr.Zero; 
 IntPtr lpBufferData = IntPtr.Zero; 
 IntPtr lpBufferChain = IntPtr.Zero; 
 ulong ulOptionMask = 0; 
 int dwContext = 0; 
 int lpdwBufferLength = 0; 
 int dwError = 0; 
 int iResult = 0; 
 int dwNumberOfBytesAvailable = 0; 
 int dwNumberOfBytesRead = 0; 
 int cchNameString = 0; 
 bool bResult = false; 
 
 try 
 { 
 // Initialize WinINet 
 hInternet = Win32.InternetOpen("alejacma", Win32.INTERNET_OPEN_TYPE_PRECONFIG, null, null, 0); 
 if (hInternet == IntPtr.Zero) 
 { 
 throw new Exception("InternetOpen error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error())); 
 } 
 
 // Open HTTP session 
 hConnect = Win32.InternetConnect(hInternet, textBox1.Text, Win32.INTERNET_DEFAULT_HTTPS_PORT, null, null, Win32.INTERNET_SERVICE_HTTP, 0, ref dwContext); 
 if (hConnect == IntPtr.Zero) 
 { 
 throw new Exception("InternetConnect error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error())); 
 } 
 
 // Create HTTP request 
 hRequest = Win32.HttpOpenRequest(hConnect, "GET", textBox2.Text, null, null, IntPtr.Zero, Win32.INTERNET_FLAG_SECURE, ref dwContext); 
 if (hRequest == IntPtr.Zero) 
 { 
 throw new Exception("HttpOpenRequest error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error())); 
 } 
 
 // Configure request to get combined cert errors 
 ulOptionMask = Win32.INTERNET_ERROR_MASK_COMBINED_SEC_CERT; 
 bResult = Win32.InternetSetOption(hRequest, Win32.INTERNET_OPTION_ERROR_MASK, ref ulOptionMask, Marshal.SizeOf(typeof(IntPtr))); 
 if (!bResult) 
 { 
 throw new Exception("InternetSetOption Error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error())); 
 } 
 
 do 
 { 
 // Send request to the server 
 bResult = Win32.HttpSendRequest(hRequest, null, 0, IntPtr.Zero, 0); 
 if (bResult == false) 
 { 
 // Deal with possible errors 
 dwError = Marshal.GetLastWin32Error(); 
 switch (dwError) 
 { 
 case Win32.ERROR_INTERNET_SEC_CERT_ERRORS: 
 case Win32.ERROR_INTERNET_INVALID_CA: 
 case Win32.ERROR_INTERNET_SEC_CERT_CN_INVALID: 
 case Win32.ERROR_INTERNET_SEC_CERT_DATE_INVALID: 
 case Win32.ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED: 
 break; 
 default: 
 // Unknown error 
 throw new Exception("HttpSendRequest error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error())); 
 } 
 
 // Display cert error dialog box 
 iResult = Win32.InternetErrorDlg(this.Handle, hRequest, dwError, Win32.FLAGS_ERROR_UI_FLAGS_GENERATE_DATA + Win32.FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS, IntPtr.Zero); 
 switch (iResult) 
 { 
 case Win32.ERROR_SUCCESS: 
 break; 
 case Win32.ERROR_CANCELLED: 
 throw new Exception("InternetErrorDlg error\nThe function was canceled by the user"); 
 case Win32.ERROR_INTERNET_FORCE_RETRY: 
 throw new Exception("InternetErrorDlg error\nFunction needs to redo its request. In the case of authentication this indicates that the user clicked the OK button."); 
 case Win32.ERROR_INVALID_HANDLE: 
 throw new Exception("InternetErrorDlg error\nThe handle to the parent window is invalid"); 
 default: 
 throw new Exception("InternetErrorDlg error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error())); 
 } 
 } 
 
 } while (!bResult); 
 
 // Retrieve the server’s certificate-chain context 
 lpdwBufferLength = Marshal.SizeOf(typeof(IntPtr)); 
 bResult = Win32.InternetQueryOption(hRequest, Win32.INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT, ref lpBufferChain, ref lpdwBufferLength); 
 if (bResult == false) 
 { 
 throw new Exception("InternetQueryOption error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error())); 
 } 
 
 // Display some of the contents of the chain 
 certChainContext = (Win32.CERT_CHAIN_CONTEXT)Marshal.PtrToStructure(lpBufferChain, typeof(Win32.CERT_CHAIN_CONTEXT)); 
 switch(certChainContext.TrustStatus.dwErrorStatus) 
 { 
 case Win32.CERT_TRUST_NO_ERROR: 
 MessageBox.Show("No error found for this certificate or chain"); 
 break; 
 case Win32.CERT_TRUST_IS_NOT_TIME_VALID: 
 MessageBox.Show("This certificate or one of the certificates in the certificate chain is not time-valid"); 
 break; 
 case Win32.CERT_TRUST_IS_REVOKED: 
 MessageBox.Show("Trust for this certificate or one of the certificates in the certificate chain has been revoked"); 
 break; 
 case Win32.CERT_TRUST_IS_NOT_SIGNATURE_VALID: 
 MessageBox.Show("The certificate or one of the certificates in the certificate chain does not have a valid signature"); 
 break; 
 case Win32.CERT_TRUST_IS_NOT_VALID_FOR_USAGE: 
 MessageBox.Show("The certificate or certificate chain is not valid in its proposed usage"); 
 break; 
 case Win32.CERT_TRUST_IS_UNTRUSTED_ROOT: 
 MessageBox.Show("The certificate or certificate chain is based on an untrusted root"); 
 break; 
 case Win32.CERT_TRUST_REVOCATION_STATUS_UNKNOWN: 
 MessageBox.Show("The revocation status of the certificate or one of the certificates in the certificate chain is unknown"); 
 break; 
 case Win32.CERT_TRUST_IS_CYCLIC: 
 MessageBox.Show("One of the certificates in the chain was issued by a certification authority that the original certificate had certified"); 
 break; 
 case Win32.CERT_TRUST_IS_PARTIAL_CHAIN: 
 MessageBox.Show("The certificate chain is not complete"); 
 break; 
 case Win32.CERT_TRUST_CTL_IS_NOT_TIME_VALID: 
 MessageBox.Show("A CTL used to create this chain was not time-valid"); 
 break; 
 case Win32.CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID: 
 MessageBox.Show("A CTL used to create this chain did not have a valid signature"); 
 break; 
 case Win32.CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE: 
 MessageBox.Show("A CTL used to create this chain is not valid for this usage"); 
 break; 
 default: 
 MessageBox.Show("TrustStatus.dwErrorStatus = " + certChainContext.TrustStatus.dwErrorStatus.ToString()); 
 break; 
 } 
 
 switch (certChainContext.TrustStatus.dwInfoStatus) 
 { 
 case 0: 
 MessageBox.Show("No information status reported"); 
 break; 
 case Win32.CERT_TRUST_HAS_EXACT_MATCH_ISSUER: 
 MessageBox.Show("An exact match issuer certificate has been found for this certificate"); 
 break; 
 case Win32.CERT_TRUST_HAS_KEY_MATCH_ISSUER: 
 MessageBox.Show("A key match issuer certificate has been found for this certificate"); 
 break; 
 case Win32.CERT_TRUST_HAS_NAME_MATCH_ISSUER: 
 MessageBox.Show("A name match issuer certificate has been found for this certificate"); 
 break; 
 case Win32.CERT_TRUST_IS_SELF_SIGNED: 
 MessageBox.Show("This certificate is self-signed"); 
 break; 
 case Win32.CERT_TRUST_IS_COMPLEX_CHAIN: 
 MessageBox.Show("The certificate chain created is a complex chain"); 
 break; 
 case Win32.CERT_TRUST_HAS_PREFERRED_ISSUER: 
 MessageBox.Show("The certificate chain has a preferred issuer"); 
 break; 
 case Win32.CERT_TRUST_HAS_ISSUANCE_CHAIN_POLICY: 
 MessageBox.Show("The certificate chain has issuance chain policy"); 
 break; 
 case Win32.CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS: 
 MessageBox.Show("The certificate chain valid name contraints"); 
 break; 
 case Win32.CERT_TRUST_IS_PEER_TRUSTED: 
 MessageBox.Show("The certificate chain is peer trusted"); 
 break; 
 case Win32.CERT_TRUST_HAS_CRL_VALIDITY_EXTENDED: 
 MessageBox.Show("The certificate chain has CRL validity extended"); 
 break; 
 case Win32.CERT_TRUST_IS_FROM_EXCLUSIVE_TRUST_STORE: 
 MessageBox.Show("The certificate chain was found in a store specified by hExclusiveRoot or hExclusiveTrustedPeople"); 
 break; 
 } 
 
 for (int i = 0; i < certChainContext.cChain; i++) 
 { 
 
 certSimpleChain = (Win32.CERT_SIMPLE_CHAIN)Marshal.PtrToStructure(Marshal.ReadIntPtr(certChainContext.rgpChain + i * Marshal.SizeOf(typeof(IntPtr))), typeof(Win32.CERT_SIMPLE_CHAIN)); 
 
 // For each certificate chain in this context... 
 for (int simpleCertChainIndex = 0; simpleCertChainIndex < certSimpleChain.cElement; simpleCertChainIndex++) 
 { 
 // get the certificates in it 
 certChainElement = (Win32.CERT_CHAIN_ELEMENT)Marshal.PtrToStructure(Marshal.ReadIntPtr(certSimpleChain.rgpElement + simpleCertChainIndex * Marshal.SizeOf(typeof(IntPtr))), typeof(Win32.CERT_CHAIN_ELEMENT)); 
 //certContext = (Win32.CERT_CONTEXT)Marshal.PtrToStructure(certChainElement.pCertContext, typeof(Win32.CERT_CONTEXT)); 
 
 // Find and print the name of the subject of the certificate 
 cchNameString = Win32.CertGetNameString(certChainElement.pCertContext, Win32.CERT_NAME_SIMPLE_DISPLAY_TYPE, 0, IntPtr.Zero, pszSubject, SIZE); 
 if (cchNameString == 0) 
 { 
 throw new Exception("CertGetNameString error"); 
 } 
 
 // Get the issuer 
 cchNameString = Win32.CertGetNameString(certChainElement.pCertContext, Win32.CERT_NAME_SIMPLE_DISPLAY_TYPE, Win32.CERT_NAME_ISSUER_FLAG, IntPtr.Zero, pszIssuer, SIZE); 
 if (cchNameString == 0) 
 { 
 throw new Exception("CertGetNameString error"); 
 } 
 
 MessageBox.Show("Chain " + i.ToString() + "\nCert " + simpleCertChainIndex.ToString() + "\nSubject: " + pszSubject.ToString() + "\nIssuer: " + pszIssuer.ToString()); 
 } 
 } 
 
 // Determine the amount of data available 
 dwNumberOfBytesAvailable = 0; 
 bResult = Win32.InternetQueryDataAvailable(hRequest, ref dwNumberOfBytesAvailable, 0, IntPtr.Zero); 
 if (!bResult) 
 { 
 throw new Exception("InternetQueryDataAvailable error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error())); 
 } 
 
 // Read data 
 lpBufferData = Marshal.AllocHGlobal(dwNumberOfBytesAvailable); 
 dwNumberOfBytesRead = 0; 
 bResult = Win32.InternetReadFile(hRequest, lpBufferData, dwNumberOfBytesAvailable, ref dwNumberOfBytesRead); 
 if (bResult == false) 
 { 
 throw new Exception("InternetReadFile error #" + Marshal.GetLastWin32Error().ToString(), new Win32Exception(Marshal.GetLastWin32Error())); 
 } 
 
 // Everything went well. Show data 
 MessageBox.Show(Marshal.PtrToStringAnsi(lpBufferData, dwNumberOfBytesRead)); 
 } 
 catch (Exception ex) 
 { 
 // Show exception 
 if (ex.InnerException != null) 
 { 
 MessageBox.Show(ex.Message + "\n" + ex.InnerException.Message); 
 } 
 else 
 { 
 MessageBox.Show(ex.Message); 
 } 
 } 
 finally 
 { 
 // Clean up stuff 
 if (lpBufferData != IntPtr.Zero) 
 { 
 Marshal.FreeHGlobal(lpBufferData); 
 } 
 if (lpBufferChain != IntPtr.Zero) 
 { 
 Win32.CertFreeCertificateChain(lpBufferChain); 
 } 
 if (hRequest != IntPtr.Zero) 
 { 
 Win32.InternetCloseHandle(hRequest); 
 } 
 if (hConnect != IntPtr.Zero) 
 { 
 Win32.InternetCloseHandle(hConnect); 
 } 
 if (hInternet != IntPtr.Zero) 
 { 
 Win32.InternetCloseHandle(hInternet); 
 } 
 } 
 } 
 } 
}

</SAMPLE>

<SAMPLE file="win32.cs">

 using System; 
using System.Collections.Generic; 
using System.Linq; 
using System.Text; 
using System.Runtime.InteropServices; 
 
namespace WindowsFormsApplication1 
{ 
 class Win32 
 { 
 #region "CONSTS" 
 
 public const int INTERNET_OPEN_TYPE_PRECONFIG = 0; 
 
 public const int INTERNET_DEFAULT_HTTP_PORT = 80; 
 public const int INTERNET_DEFAULT_HTTPS_PORT = 443; 
 
 public const int INTERNET_SERVICE_HTTP = 3; 
 
 public const int INTERNET_FLAG_SECURE = 0x00800000; 
 
 public const int INTERNET_OPTION_SERVER_CERT_CHAIN_CONTEXT = 105; 
 
 public const int INTERNET_OPTION_ERROR_MASK = 62; 
 
 public const ulong INTERNET_ERROR_MASK_COMBINED_SEC_CERT = 0x2; 
 
 public const int INTERNET_ERROR_BASE = 12000; 
 
 public const int ERROR_INTERNET_FORCE_RETRY = INTERNET_ERROR_BASE + 32; 
 
 public const int ERROR_INTERNET_SEC_CERT_DATE_INVALID = INTERNET_ERROR_BASE + 37; 
 
 public const int ERROR_INTERNET_SEC_CERT_CN_INVALID = INTERNET_ERROR_BASE + 38; 
 
 public const int ERROR_INTERNET_CLIENT_AUTH_CERT_NEEDED = INTERNET_ERROR_BASE + 44; 
 
 public const int ERROR_INTERNET_SEC_CERT_ERRORS = INTERNET_ERROR_BASE + 55; 
 
 public const int ERROR_INTERNET_INVALID_CA = INTERNET_ERROR_BASE + 45; 
 
 public const int FLAGS_ERROR_UI_FLAGS_CHANGE_OPTIONS = 0x02; 
 
 public const int FLAGS_ERROR_UI_FLAGS_GENERATE_DATA = 0x04; 
 
 public const int ERROR_SUCCESS = 0; 
 
 public const int ERROR_CANCELLED = 1223; 
 
 public const int ERROR_INVALID_HANDLE = 6; 
 
 // https://msdn.microsoft.com/en-us/library/windows/desktop/aa377590(v=vs.85).aspx 
 public const int CERT_TRUST_NO_ERROR = 0x00000000; 
 public const int CERT_TRUST_IS_NOT_TIME_VALID = 0x00000001; 
 public const int CERT_TRUST_IS_REVOKED = 0x00000004; 
 public const int CERT_TRUST_IS_NOT_SIGNATURE_VALID = 0x00000008; 
 public const int CERT_TRUST_IS_NOT_VALID_FOR_USAGE = 0x00000010; 
 public const int CERT_TRUST_IS_UNTRUSTED_ROOT = 0x00000020; 
 public const int CERT_TRUST_REVOCATION_STATUS_UNKNOWN = 0x00000040; 
 public const int CERT_TRUST_IS_CYCLIC = 0x00000080; 
 public const int CERT_TRUST_INVALID_EXTENSION = 0x00000100; 
 public const int CERT_TRUST_INVALID_POLICY_CONSTRAINTS = 0x00000200; 
 public const int CERT_TRUST_INVALID_BASIC_CONSTRAINTS = 0x00000400; 
 public const int CERT_TRUST_INVALID_NAME_CONSTRAINTS = 0x00000800; 
 public const int CERT_TRUST_HAS_NOT_SUPPORTED_NAME_CONSTRAINT = 0x00001000; 
 public const int CERT_TRUST_HAS_NOT_DEFINED_NAME_CONSTRAINT = 0x00002000; 
 public const int CERT_TRUST_HAS_NOT_PERMITTED_NAME_CONSTRAINT = 0x00004000; 
 public const int CERT_TRUST_HAS_EXCLUDED_NAME_CONSTRAINT = 0x00008000; 
 public const int CERT_TRUST_IS_OFFLINE_REVOCATION = 0x01000000; 
 public const int CERT_TRUST_NO_ISSUANCE_CHAIN_POLICY = 0x02000000; 
 public const int CERT_TRUST_IS_EXPLICIT_DISTRUST = 0x04000000; 
 public const int CERT_TRUST_HAS_NOT_SUPPORTED_CRITICAL_EXT = 0x08000000; 
 public const int CERT_TRUST_IS_PARTIAL_CHAIN = 0x00010000; 
 public const int CERT_TRUST_CTL_IS_NOT_TIME_VALID = 0x00020000; 
 public const int CERT_TRUST_CTL_IS_NOT_SIGNATURE_VALID = 0x00040000; 
 public const int CERT_TRUST_CTL_IS_NOT_VALID_FOR_USAGE = 0x00080000; 
 
 public const int CERT_TRUST_HAS_EXACT_MATCH_ISSUER = 0x00000001; 
 public const int CERT_TRUST_HAS_KEY_MATCH_ISSUER = 0x00000002; 
 public const int CERT_TRUST_HAS_NAME_MATCH_ISSUER = 0x00000004; 
 public const int CERT_TRUST_IS_SELF_SIGNED = 0x00000008; 
 public const int CERT_TRUST_HAS_PREFERRED_ISSUER = 0x00000100; 
 public const int CERT_TRUST_HAS_ISSUANCE_CHAIN_POLICY = 0x00000200; 
 public const int CERT_TRUST_HAS_VALID_NAME_CONSTRAINTS = 0x00000400; 
 public const int CERT_TRUST_IS_PEER_TRUSTED = 0x00000800; 
 public const int CERT_TRUST_HAS_CRL_VALIDITY_EXTENDED = 0x00001000; 
 public const int CERT_TRUST_IS_FROM_EXCLUSIVE_TRUST_STORE = 0x00002000; 
 public const int CERT_TRUST_IS_COMPLEX_CHAIN = 0x00010000; 
 
 public const int CERT_NAME_SIMPLE_DISPLAY_TYPE = 4; 
 
 public const int CERT_NAME_ISSUER_FLAG = 0x1; 
 
 #endregion 
 
 #region "STRUCTS" 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CERT_TRUST_STATUS 
 { 
 public int dwErrorStatus; 
 public int dwInfoStatus; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct BLOB 
 { 
 public int cbData; 
 public IntPtr pbData; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CRYPT_ALGORITHM_IDENTIFIER 
 { 
 public string pszObjId; 
 public BLOB Parameters; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct FILETIME 
 { 
 public int dwLowDateTime; 
 public int dwHighDateTime; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CRYPT_BIT_BLOB 
 { 
 public int cbData; 
 public IntPtr pbData; 
 public int cUnusedBits; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CERT_PUBLIC_KEY_INFO 
 { 
 public CRYPT_ALGORITHM_IDENTIFIER Algorithm; 
 public CRYPT_BIT_BLOB PublicKey; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CERT_EXTENSION 
 { 
 public string pszObjId; 
 public bool fCritical; 
 public BLOB Value; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CERT_INFO 
 { 
 public int dwVersion; 
 public BLOB SerialNumber; 
 public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm; 
 public BLOB Issuer; 
 public FILETIME NotBefore; 
 public FILETIME NotAfter; 
 public BLOB Subject; 
 public CERT_PUBLIC_KEY_INFO SubjectPublicKeyInfo; 
 public CRYPT_BIT_BLOB IssuerUniqueId; 
 public CRYPT_BIT_BLOB SubjectUniqueId; 
 public int cExtension; 
 public IntPtr rgExtension; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CERT_CONTEXT 
 { 
 public int dwCertEncodingType; 
 public IntPtr pbCertEncoded; 
 public int cbCertEncoded; 
 public IntPtr pCertInfo; 
 public IntPtr hCertStore; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CERT_REVOCATION_INFO 
 { 
 public int cbSize; 
 public int dwRevocationResult; 
 public string pszRevocationOid; 
 public IntPtr pvOidSpecificInfo; 
 public bool fHasFreshnessTime; 
 public int dwFreshnessTime; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CTL_USAGE 
 { 
 public int cUsageIdentifier; 
 public IntPtr rgpszUsageIdentifier; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CERT_CHAIN_ELEMENT 
 { 
 public int cbSize; 
 public IntPtr pCertContext; 
 public CERT_TRUST_STATUS TrustStatus; 
 public IntPtr pRevocationInfo; 
 public IntPtr pIssuanceUsage; 
 public IntPtr pApplicationUsage; 
 public string pwszExtendedErrorInfo; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CRYPT_ATTRIBUTE 
 { 
 public string pszObjId; 
 public int cValue; 
 public IntPtr rgValue; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CTL_ENTRY 
 { 
 public BLOB SubjectIdentifier; 
 public int cAttribute; 
 public IntPtr rgAttribute; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CTL_INFO 
 { 
 public int dwVersion; 
 public CTL_USAGE SubjectUsage; 
 public BLOB ListIdentifier; 
 public BLOB SequenceNumber; 
 public FILETIME ThisUpdate; 
 public FILETIME NextUpdate; 
 public CRYPT_ALGORITHM_IDENTIFIER SubjectAlgorithm; 
 public int cCTLEntry; 
 public IntPtr rgCTLEntry; 
 public int cExtension; 
 public IntPtr rgExtension; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CTL_CONTEXT 
 { 
 public int dwMsgAndCertEncodingType; 
 public IntPtr pbCtlEncoded; 
 public int cbCtlEncoded; 
 public IntPtr pCtlInfo; 
 public IntPtr hCertStore; 
 public IntPtr hCryptMsg; 
 public IntPtr pbCtlContent; 
 public int cbCtlContent; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CERT_TRUST_LIST_INFO 
 { 
 public int cbSize; 
 public IntPtr pCtlEntry; 
 public IntPtr pCtlContext; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CERT_SIMPLE_CHAIN 
 { 
 public int cbSize; 
 public CERT_TRUST_STATUS TrustStatus; 
 public int cElement; 
 public IntPtr rgpElement; 
 public IntPtr pTrustListInfo; 
 public bool fHasRevocationFreshnessTime; 
 public int dwRevocationFreshnessTime; 
 } 
 
 [StructLayout(LayoutKind.Sequential)] 
 public struct CERT_CHAIN_CONTEXT 
 { 
 public int cbSize; 
 public CERT_TRUST_STATUS TrustStatus; 
 public int cChain; 
 public IntPtr rgpChain; 
 public int cLowerQualityChainContext; 
 public IntPtr rgpLowerQualityChainContext; 
 public bool fHasRevocationFreshnessTime; 
 public int dwRevocationFreshnessTime; 
 } 
 
 #endregion 
 
 #region "FUNCTIONS" 
 
 [DllImport("Wininet.dll", CharSet = CharSet.Auto, SetLastError = true)] 
 public static extern IntPtr InternetOpen( 
 string lpszAgent, 
 int dwAccessType, 
 string lpszProxyName, 
 string lpszProxyBypass, 
 int dwFlags 
 ); 
 
 [DllImport("Wininet.dll", CharSet = CharSet.Auto, SetLastError = true)] 
 public static extern IntPtr InternetCloseHandle( 
 IntPtr hInternet 
 ); 
 
 [DllImport("Wininet.dll", CharSet = CharSet.Auto, SetLastError = true)] 
 public static extern IntPtr InternetConnect( 
 IntPtr hInternet, 
 string lpszServerName, 
 short nServerPort, 
 string lpszUsername, 
 string lpszPassword, 
 int dwService, 
 int dwFlags, 
 ref int dwContext 
 ); 
 
 [DllImport("Wininet.dll", CharSet = CharSet.Auto, SetLastError = true)] 
 public static extern IntPtr HttpOpenRequest( 
 IntPtr hConnect, 
 string lpszVerb, 
 string lpszObjectName, 
 string lpszVersion, 
 string lpszReferer, 
 IntPtr lplpszAcceptTypes, 
 int dwFlags, 
 ref int dwContext 
 ); 
 
 [DllImport("Wininet.dll", CharSet = CharSet.Auto, SetLastError = true)] 
 public static extern bool HttpSendRequest( 
 IntPtr hRequest, 
 string lpszHeaders, 
 int dwHeadersLength, 
 IntPtr lpOptional, 
 int dwOptionalLength 
 ); 
 
 [DllImport("wininet.dll", SetLastError = true)] 
 public static extern bool InternetSetOption 
 ( 
 IntPtr hInternet, 
 int dwOption, 
 ref ulong lpBuffer, 
 int dwBufferLength 
 ); 
 
 [DllImport("Wininet.dll", CharSet = CharSet.Auto, SetLastError = true)] 
 public static extern bool InternetQueryOption( 
 IntPtr hInternet, 
 int dwOption, 
 ref IntPtr lpBuffer, 
 ref int lpdwBufferLength 
 ); 
 
 [DllImport("wininet.dll", SetLastError = true)] 
 public static extern int InternetErrorDlg 
 ( 
 IntPtr hWnd, 
 IntPtr hRequest, 
 int dwError, 
 int dwFlags, 
 IntPtr lppvData 
 ); 
 
 [DllImport("wininet.dll", SetLastError = true)] 
 public static extern bool InternetQueryDataAvailable 
 ( 
 IntPtr hFile, 
 ref int dwNumberOfBytesAvailable, 
 int dwFlags, 
 IntPtr dwContext 
 ); 
 
 [DllImport("wininet.dll", SetLastError = true)] 
 public static extern bool InternetReadFile 
 ( 
 IntPtr hFile, 
 IntPtr lpBuffer, 
 int dwNumberOfBytesToRead, 
 ref int dwNumberOfBytesRead 
 ); 
 
 [DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
 public static extern void CertFreeCertificateChain( 
 IntPtr pChainContext 
 ); 
 
 [DllImport("Crypt32.dll", CharSet = CharSet.Auto, SetLastError = true)] 
 public static extern int CertGetNameString( 
 IntPtr pCertContext, 
 int dwType, 
 int dwFlags, 
 IntPtr pvTypePara, 
 StringBuilder pszNameString, 
 int cchNameString 
 ); 
 
 #endregion 
 
 } 
}

</SAMPLE>

 

I hope this helps.

Regards,

 

Alex (Alejandro Campos Magencio)