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;

// http://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)