Retired Microsoft Blog disclaimer

This directory is a mirror of retired "Decrypt My World" MSDN blog and is provided as is. All posting authorship and copyrights belong to respective authors.
Original URL: https://blogs.msdn.microsoft.com/alejacma/2009/04/01/how-to-get-information-from-a-crl-net/
Post name: How to get information from a CRL (.NET)
Original author: Alejandro Campos Magencio
Posting date: 2009-04-01T05:00:00+00:00


Hi all,


The following C# sample uses CryptoAPI to read the info of a CRL (Certificate Revocation List)stored in a file:

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;

namespace GetCRLInfo
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}

private void getInfoButton_Click(object sender, EventArgs e)
{
// Variables
//
Boolean bResult = false;
IntPtr pvContext = IntPtr.Zero;
Win32.CRL_CONTEXT CRLContext;
Win32.CRL_INFO CRLInfo;
Int32 csz = 0;
StringBuilder psz = null;
IntPtr rgCRLEntry = IntPtr.Zero;
Win32.CRL_ENTRY CRLEntry;
String strSerialNumber = "";
IntPtr pByte = IntPtr.Zero;
Byte bByte = 0;
IntPtr rgExtension = IntPtr.Zero;
Win32.CERT_EXTENSION CRLExtension;
Int32 cbFormat = 0;
StringBuilder pbFormat = null;
String strCRLReasonCode = "";

// Clean screen
//
issuerTextBox.Text = "";
revocationListBox.Items.Clear();

try
{
// Get CRL context
//
bResult = Win32.CryptQueryObject(
Win32.CERT_QUERY_OBJECT_FILE,
fileTextBox.Text,
Win32.CERT_QUERY_CONTENT_FLAG_CRL,
Win32.CERT_QUERY_FORMAT_FLAG_BINARY,
0,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
IntPtr.Zero,
ref pvContext
);
if (!bResult)
{
throw new Exception("CryptQueryObject error #" + Marshal.GetLastWin32Error());
}

CRLContext = (Win32.CRL_CONTEXT)Marshal.PtrToStructure(pvContext, typeof(Win32.CRL_CONTEXT));

// Get CRL info
//
CRLInfo = (Win32.CRL_INFO)Marshal.PtrToStructure(CRLContext.pCrlInfo, typeof(Win32.CRL_INFO));

// Get CRL issuer
//
csz = Win32.CertNameToStr(
Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
ref CRLInfo.Issuer,
Win32.CERT_X500_NAME_STR,
null,
0
);
if (csz <= 0)
{
throw new Exception("CertNameToStr error #" + Marshal.GetLastWin32Error());
}

psz = new StringBuilder(csz);

csz = Win32.CertNameToStr(
Win32.X509_ASN_ENCODING | Win32.PKCS_7_ASN_ENCODING,
ref CRLInfo.Issuer,
Win32.CERT_X500_NAME_STR,
psz,
csz
);
if (csz <= 0)
{
throw new Exception("CertNameToStr error #" + Marshal.GetLastWin32Error());
}

// Show CRL issuer
//
issuerTextBox.Text = psz.ToString();

// Get revocation list
//
rgCRLEntry = CRLInfo.rgCRLEntry;
for (int i = 0; i < CRLInfo.cCRLEntry; i++)
{
// Get the serial number of one revoked certificate
//
strSerialNumber = "";

CRLEntry = (Win32.CRL_ENTRY)Marshal.PtrToStructure(rgCRLEntry, typeof(Win32.CRL_ENTRY));

pByte = CRLEntry.SerialNumber.pbData;
for (int j = 0; j < CRLEntry.SerialNumber.cbData; j++)
{
bByte = Marshal.ReadByte(pByte);
strSerialNumber = bByte.ToString("X").PadLeft(2, '0') + " " + strSerialNumber;
pByte = (IntPtr)((Int32)pByte + Marshal.SizeOf(typeof(Byte)));
}

// Get the CRL Reason Code of that revoked certificate
//
strCRLReasonCode = "";

rgExtension = Win32.CertFindExtension(
Win32.szOID_CRL_REASON_CODE,
CRLEntry.cExtension,
CRLEntry.rgExtension
);
if (rgExtension.Equals(IntPtr.Zero))
{
throw new Exception("CertFindExtension found no CRL Reason Code");
}

CRLExtension = (Win32.CERT_EXTENSION)Marshal.PtrToStructure(rgExtension, typeof(Win32.CERT_EXTENSION));

// Format that CRL Reason Code so we can show it
//
cbFormat = 0;
pbFormat = null;
bResult = Win32.CryptFormatObject(
Win32.X509_ASN_ENCODING,
0,
0,
IntPtr.Zero,
Win32.szOID_CRL_REASON_CODE,
CRLExtension.Value.pbData,
CRLExtension.Value.cbData,
null,
ref cbFormat
);
if (!bResult)
{
throw new Exception("CryptFormatObject error #" + Marshal.GetLastWin32Error());
}

pbFormat = new StringBuilder(cbFormat);

bResult = Win32.CryptFormatObject(
Win32.X509_ASN_ENCODING,
0,
0,
IntPtr.Zero,
Win32.szOID_CRL_REASON_CODE,
CRLExtension.Value.pbData,
CRLExtension.Value.cbData,
pbFormat,
ref cbFormat
);
if (!bResult)
{
throw new Exception("CryptFormatObject error #" + Marshal.GetLastWin32Error());
}

strCRLReasonCode = pbFormat.ToString();

// Show Serial Number and CRL Reason Code
//
revocationListBox.Items.Add(strSerialNumber + "\t-->\t" + strCRLReasonCode);

// Continue with the next entry in the list
//
rgCRLEntry = (IntPtr)((Int32)rgCRLEntry + Marshal.SizeOf(typeof(Win32.CRL_ENTRY)));
}
}
catch (Exception ex)
{
// Show errors
//
MessageBox.Show(ex.Message);
}
finally
{
// Do some clean up
//
if (!pvContext.Equals(IntPtr.Zero))
{
Win32.CertFreeCRLContext(pvContext);
}
}
}
}
}

public class Win32
{
#region APIs

[DllImport("CRYPT32.DLL", EntryPoint = "CryptQueryObject", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean CryptQueryObject(
Int32 dwObjectType,
[MarshalAs(UnmanagedType.LPWStr)]String pvObject,
Int32 dwExpectedContentTypeFlags,
Int32 dwExpectedFormatTypeFlags,
Int32 dwFlags,
IntPtr pdwMsgAndCertEncodingType,
IntPtr pdwContentType,
IntPtr pdwFormatType,
IntPtr phCertStore,
IntPtr phMsg,
ref IntPtr ppvContext
);

[DllImport("CRYPT32.DLL", EntryPoint = "CertFreeCRLContext", SetLastError = true)]
public static extern Boolean CertFreeCRLContext(
IntPtr pCrlContext
);

[DllImport("CRYPT32.DLL", EntryPoint = "CertNameToStr", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Int32 CertNameToStr(
Int32 dwCertEncodingType,
ref CRYPTOAPI_BLOB pName,
Int32 dwStrType,
StringBuilder psz,
Int32 csz
);

[DllImport("CRYPT32.DLL", EntryPoint = "CertFindExtension", CharSet = CharSet.Auto, SetLastError = true)]
public static extern IntPtr CertFindExtension(
[MarshalAs(UnmanagedType.LPStr)]String pszObjId,
Int32 cExtensions,
IntPtr rgExtensions
);

[DllImport("CRYPT32.DLL", EntryPoint = "CryptFormatObject", CharSet = CharSet.Auto, SetLastError = true)]
public static extern Boolean CryptFormatObject(
Int32 dwCertEncodingType,
Int32 dwFormatType,
Int32 dwFormatStrType,
IntPtr pFormatStruct,
[MarshalAs(UnmanagedType.LPStr)]String lpszStructType,
IntPtr pbEncoded,
Int32 cbEncoded,
StringBuilder pbFormat,
ref Int32 pcbFormat
);

#endregion APIs

#region Structs

[StructLayout(LayoutKind.Sequential)]
public struct CRL_CONTEXT
{
public Int32 dwCertEncodingType;
public IntPtr pbCrlEncoded;
public Int32 cbCrlEncoded;
public IntPtr pCrlInfo;
public IntPtr hCertStore;
}

[StructLayout(LayoutKind.Sequential)]
public struct CRL_INFO
{
public Int32 dwVersion;
public CRYPT_ALGORITHM_IDENTIFIER SignatureAlgorithm;
public CRYPTOAPI_BLOB Issuer;
public FILETIME ThisUpdate;
public FILETIME NextUpdate;
public Int32 cCRLEntry;
public IntPtr rgCRLEntry;
public Int32 cExtension;
public IntPtr rgExtension;
}

[StructLayout(LayoutKind.Sequential)]
public struct CRYPT_ALGORITHM_IDENTIFIER
{
[MarshalAs(UnmanagedType.LPStr)]public String pszObjId;
public CRYPTOAPI_BLOB Parameters;
}

[StructLayout(LayoutKind.Sequential)]
public struct CRYPTOAPI_BLOB
{
public Int32 cbData;
public IntPtr pbData;
}

[StructLayout(LayoutKind.Sequential)]
public struct FILETIME
{
public Int32 dwLowDateTime;
public Int32 dwHighDateTime;
}

[StructLayout(LayoutKind.Sequential)]
public struct CRL_ENTRY
{
public CRYPTOAPI_BLOB SerialNumber;
public FILETIME RevocationDate;
public Int32 cExtension;
public IntPtr rgExtension;
}

[StructLayout(LayoutKind.Sequential)]
public struct CERT_EXTENSION
{
[MarshalAs(UnmanagedType.LPStr)]public String pszObjId;
public Boolean fCritical;
public CRYPTOAPI_BLOB Value;
}

#endregion Structs

#region Consts

public const Int32 CERT_QUERY_OBJECT_FILE = 0x00000001;
public const Int32 CERT_QUERY_CONTENT_CRL = 3;
public const Int32 CERT_QUERY_CONTENT_FLAG_CRL = 1 << CERT_QUERY_CONTENT_CRL;
public const Int32 CERT_QUERY_FORMAT_BINARY = 1;
public const Int32 CERT_QUERY_FORMAT_BASE64_ENCODED = 2;
public const Int32 CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED = 3;
public const Int32 CERT_QUERY_FORMAT_FLAG_BINARY = 1 << CERT_QUERY_FORMAT_BINARY;
public const Int32 CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED = 1 << CERT_QUERY_FORMAT_BASE64_ENCODED;
public const Int32 CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED = 1 << CERT_QUERY_FORMAT_ASN_ASCII_HEX_ENCODED;
public const Int32 CERT_QUERY_FORMAT_FLAG_ALL = CERT_QUERY_FORMAT_FLAG_BINARY | CERT_QUERY_FORMAT_FLAG_BASE64_ENCODED | CERT_QUERY_FORMAT_FLAG_ASN_ASCII_HEX_ENCODED;

public const Int32 X509_ASN_ENCODING = 0x00000001;
public const Int32 PKCS_7_ASN_ENCODING = 0x00010000;

public const Int32 X509_NAME = 7;

public const Int32 CERT_SIMPLE_NAME_STR = 1;
public const Int32 CERT_OID_NAME_STR = 2;
public const Int32 CERT_X500_NAME_STR = 3;

public const String szOID_CRL_REASON_CODE = "2.5.29.21";

#endregion
}


I hope this helps.


Regards,



Alex (Alejandro Campos Magencio)


Share this article:

Comments:

Comments are closed.