Original URL: | https://blogs.msdn.microsoft.com/alejacma/2010/05/10/how-to-get-info-from-client-certificates-issued-by-a-ca-c/ |
Post name: | How to get info from client certificates issued by a CA (C#) |
Original author: | Alejandro Campos Magencio |
Posting date: | 2010-05-10T03:58:00+00:00 |
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)
Comments: