How to get info from client certificates issued by a CA (C#)

Hi all,

The following C# sample shows how to use Certadm.dll and CryptoAPI to get the name of the template and the enhanced usages of client certificates in a CA

<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.Collections;
using System.Runtime.InteropServices;
using System.DirectoryServices;
using CERTADMINLib;

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

        private void button1_Click(object sender, EventArgs e)
        {
            // Variables
            string strServerName = "MyServer";
            DirectoryEntry rootEntry = null;
            DirectoryEntry templatesEntry = null;

            try
            {
                // Get AD entry that we will use to translate a certificate template OID to its correspondent name
                rootEntry = new DirectoryEntry("LDAP://" + strServerName + "/rootDSE");
                templatesEntry = new DirectoryEntry("LDAP://" + strServerName + "/cn=certificate templates,cn=public key services,cn=services,cn=configuration," + (string)rootEntry.Properties["defaultNamingContext"][0]);

                // Get Certificate Services Database info
                ViewCertificateServicesDatabase(strServerName, strServerName, templatesEntry);
            }
            catch (Exception ex)
            {
                // Errors?
                MessageBox.Show(ex.Message);
            }
            finally
            {
                // Clean up
                if (rootEntry != null)
                {
                    rootEntry.Dispose();
                }
                if (templatesEntry != null)
                {
                    templatesEntry.Dispose();
                }
            }
        }

        private void ViewCertificateServicesDatabase(string strServer, string strCAName, DirectoryEntry templatesEntry)
        {
            // Variables
            CERTADMINLib.CCertView certView = null;
            CERTADMINLib.IEnumCERTVIEWROW certViewRow = null;
            CERTADMINLib.IEnumCERTVIEWCOLUMN certViewColumn = null;
            CERTADMINLib.IEnumCERTVIEWEXTENSION certViewExt = null;
            int iColumnCount = 0;
            string strBase64Value = "";
            string strValue = "";
            string strOID = "";
            int iStartIndex = 0;
            string strDisplayName = "";
            object objValue = null;
            string strOutput = "";

            // Connecting to the Certificate Authority
            certView = new CERTADMINLib.CCertViewClass();
            certView.OpenConnection(strServer + "\\" + strCAName);

            // Get a column count and place columns into the view
            iColumnCount = certView.GetColumnCount(0);
            certView.SetResultColumnCount(iColumnCount);

            // Place each column in the view.
            for (int x = 0; x < iColumnCount; x++)
            {
                certView.SetResultColumn(x);
            }

            // Open the View and reset the row position
            certViewRow = certView.OpenView();
            certViewRow.Reset();

            // Enumerate Row and Column Information

            // Rows         
            for (int x = 0; certViewRow.Next() != -1; x++)
            {
                // Extensions
                strOutput = "ROW #" + x.ToString() + " EXTENSIONS\n\n";
                certViewExt = certViewRow.EnumCertViewExtension(0);
                certViewExt.Reset();

                while (certViewExt.Next() != -1)
                {
                    switch (certViewExt.GetName())
                    {
                        // Certificate Template
                        case "1.3.6.1.4.1.311.21.7":

                            // Certificate Template OID, Mayor Version Number and Minor Version Number
                            strBase64Value = (string)certViewExt.GetValue(Win32.PROPTYPE_BINARY, Win32.CV_OUT_BASE64);
                            strValue = FormatObject("1.3.6.1.4.1.311.21.7", Convert.FromBase64String(strBase64Value));
                            strOutput += "Certificate Template OID = \"" + strValue + "\"\n\n";

                            strDisplayName = "";
                            if (strValue.StartsWith("Template="))
                            {
                                // Certificate Template OID
                                iStartIndex = strValue.IndexOf("=") + 1;
                                strOID = strValue.Substring(iStartIndex, strValue.IndexOf(",") - iStartIndex);

                                // Certificate Template Display Name
                                strDisplayName = TranslateTemplateOID(strOID, templatesEntry);
                            }
                            strOutput += "Certificate Template Display Name = \"" + strDisplayName + "\"\n\n";
                            break;

                        // Enhanced Key Usage
                        case "2.5.29.37":
                            strBase64Value = (string)certViewExt.GetValue(Win32.PROPTYPE_BINARY, Win32.CV_OUT_BASE64);
                            strValue = FormatObject("2.5.29.37", Convert.FromBase64String(strBase64Value));
                            strOutput += "Enhanced Key Usage = \"" + strValue + "\"\n\n";
                            break;

                        default:
                            break;
                    }
                }

                // Columns
                strOutput += "ROW #" + x.ToString() + " COLUMNS\n\n";
                certViewColumn = certViewRow.EnumCertViewColumn();
                while (certViewColumn.Next() != -1)
                {
                    switch (certViewColumn.GetDisplayName())
                    {
                        // Certificate Template
                        case "Certificate Template":
                            objValue = certViewColumn.GetValue(Win32.PROPTYPE_STRING);
                            if (objValue != null)
                            {
                                strOutput += "Certificate Template Name = \"" + objValue.ToString() + "\"\n\n";
                            }
                            else
                            {
                                strOutput += "Certificate Template Name = \"\"\n\n";
                            }
                            break;

                        // "Certificate Expiration Date"
                        case "Certificate Expiration Date":
                            objValue = certViewColumn.GetValue(Win32.PROPTYPE_DATE);
                            if (objValue != null)
                            {
                                strOutput += "Certificate Expiration Date = \"" + objValue.ToString() + "\"\n\n";
                            }
                            else
                            {
                                strOutput += "Certificate Expiration Date = \"\"\n\n";
                            }
                            break;

                        default:
                            break;
                    }
                }

                // Show row info
                MessageBox.Show(strOutput);
            }
        }

        string FormatObject(string strOID, byte[] pbEncoded)
        {
            // Variables
            IntPtr pbFormat = IntPtr.Zero;
            int cbFormat = 0;
            string strValue = "";
            bool bWorked = false;

            try
            {
                // Get size for decoded data
                bWorked = Win32.CryptFormatObject(
                    Win32.X509_ASN_ENCODING,
                    0,
                    Win32.CRYPT_FORMAT_STR_NO_HEX,
                    IntPtr.Zero,
                    strOID,
                    pbEncoded,
                    pbEncoded.Length,
                    IntPtr.Zero,
                    ref cbFormat
                );
                if (!bWorked) { throw new Win32Exception(Marshal.GetLastWin32Error()); }

                // Create buffer for decoded data
                pbFormat = Marshal.AllocHGlobal(cbFormat);

                // Get decoded data
                bWorked = Win32.CryptFormatObject(
                    Win32.X509_ASN_ENCODING,
                    0,
                    Win32.CRYPT_FORMAT_STR_NO_HEX,
                    IntPtr.Zero,
                    strOID,
                    pbEncoded,
                    pbEncoded.Length,
                    pbFormat,
                    ref cbFormat
                );
                if (!bWorked) { throw new Win32Exception(Marshal.GetLastWin32Error()); }

                strValue = Marshal.PtrToStringUni(pbFormat);
            }
            catch (Exception ex)
            {
                // Error?
                strValue = "FormatObject error: " + ex.Message;
            }
            finally
            {
                // Clean up
                if (!pbFormat.Equals(IntPtr.Zero))
                {
                    Marshal.FreeHGlobal(pbFormat);
                }
            }

            return strValue;
        }

        string TranslateTemplateOID(string strOID, DirectoryEntry templatesEntry)
        {
            // Variables
            DirectorySearcher searcher = null;
            SearchResult result = null;
            string strDisplayName = "";

            try
            {
                // Look for the Display Name of a template OID in AD
                searcher = new DirectorySearcher(templatesEntry);
                searcher.Filter = "(&(msPKI-Cert-Template-OID=" + strOID + ")) ";
                result = searcher.FindOne();
                strDisplayName = (string)result.Properties["displayName"][0];
            }
            catch (Exception ex)
            {
                // Error?
                strDisplayName = "TranslateTemplateOID error: " + ex.Message;
            }
            finally
            {
                // Clean up
                if (searcher != null)
                {
                    searcher.Dispose();
                }
            }

            return strDisplayName;
        }
    }
}

</SAMPLE>

<SAMPLE file="Win32.cs">

 using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;

namespace CertAdminTest
{
    class Win32
    {
        public const int X509_ASN_ENCODING = 0x00000001;

        public const int CRYPT_FORMAT_STR_NO_HEX = 0x0010;

        public const int CV_OUT_BASE64 = 0x1;

        public const int PROPTYPE_DATE = 0x2;
        public const int PROPTYPE_BINARY = 0x3;
        public const int PROPTYPE_STRING = 0x4;

        [DllImport("crypt32.dll", CharSet = CharSet.Ansi, SetLastError = true)]
        public static extern Boolean CryptFormatObject(
            int dwCertEncodingType,
            int dwFormatType,
            int dwFormatStrType,
            IntPtr pFormatStruct,
            String lpszStructType,
            Byte[] pbEncoded,
            int cbEncoded,
            IntPtr pbFormat,
            ref int pcbFormat
        );
    }
}

</SAMPLE> 

 

I hope it helps. 

Regards,

 

Alex (Alejandro Campos Magencio)