//*************************************************************** // // CertAttributes // CryptoAPI P/Invoke to enumerate certificate Extensions // // Copyright (C) 2003. Michel I. Gallant //*************************************************************** using System; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; using System.ComponentModel; using System.Text; public class Win32 { [DllImport("crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern IntPtr CertOpenSystemStore( IntPtr hCryptProv, string storename) ; [DllImport("crypt32.dll", SetLastError=true)] public static extern bool CertCloseStore( IntPtr hCertStore, uint dwFlags) ; [DllImport("crypt32.dll", SetLastError=true)] public static extern IntPtr CertFindCertificateInStore( IntPtr hCertStore, uint dwCertEncodingType, uint dwFindFlags, uint dwFindType, [In, MarshalAs(UnmanagedType.LPWStr)]String pszFindString, IntPtr pPrevCertCntxt) ; [DllImport("crypt32.dll", SetLastError=true)] public static extern bool CertFreeCertificateContext( IntPtr hCertStore) ; [DllImport("crypt32.dll", SetLastError=true)] public static extern int CertGetPublicKeyLength( uint dwCertEncodingType, IntPtr pPublicKeyInfo) ; [DllImport("crypt32.dll", SetLastError=true)] public static extern IntPtr CertFindExtension( [In, MarshalAs(UnmanagedType.LPStr)]String pszObjId, int cExtensions, IntPtr rgExtensions) ; [DllImport("crypt32.dll")] public static extern bool CryptDecodeObject( uint CertEncodingType, [In, MarshalAs(UnmanagedType.LPStr)]String lpszStructType, IntPtr pbEncoded, uint cbEncoded, uint flags, [In, Out] byte[] pvStructInfo, ref uint cbStructInfo); [DllImport("crypt32.dll")] public static extern bool CryptDecodeObject( uint CertEncodingType, [In, MarshalAs(UnmanagedType.LPStr)]String lpszStructType, IntPtr pbEncoded, uint cbEncoded, uint flags, IntPtr pvStructInfo, ref uint cbStructInfo); } //-------- Win32 structs prototypes --------------- [StructLayout(LayoutKind.Sequential)] public struct CERT_CONTEXT { public uint dwCertEncodingType; public IntPtr pbCertEncoded; public int cbCertEncoded; public IntPtr pCertInfo; public IntPtr hCertStore; } [StructLayout(LayoutKind.Sequential)] internal struct CERT_EXTENSION { [MarshalAs(UnmanagedType.LPStr)] public String pszObjId; public int fCritical; public int cbData; public IntPtr pbData; } [StructLayout(LayoutKind.Sequential)] internal struct CERT_ENHKEY_USAGE { public int cUsageIdentifier; public IntPtr rgpszUsageIdentifier; } public class CertAttributes { const string MY = "MY"; const string OTHERS = "AddressBook"; const uint PKCS_7_ASN_ENCODING = 0x00010000; const uint X509_ASN_ENCODING = 0x00000001; const uint CERT_FIND_SUBJECT_STR = 0x00080007; static string[] OIDNAMES = { "szOID_AUTHORITY_KEY_IDENTIFIER", "szOID_KEY_ATTRIBUTES", "szOID_CERT_POLICIES_95", "szOID_KEY_USAGE_RESTRICTION", "szOID_SUBJECT_ALT_NAME", "szOID_ISSUER_ALT_NAME", "szOID_BASIC_CONSTRAINTS", "szOID_KEY_USAGE", "szOID_PRIVATEKEY_USAGE_PERIOD", "szOID_BASIC_CONSTRAINTS2", "szOID_CERT_POLICIES", "szOID_ANY_CERT_POLICY", "szOID_AUTHORITY_KEY_IDENTIFIER2", "szOID_SUBJECT_KEY_IDENTIFIER", "szOID_SUBJECT_ALT_NAME2", "szOID_ISSUER_ALT_NAME2", "szOID_CRL_REASON_CODE", "szOID_REASON_CODE_HOLD", "szOID_CRL_DIST_POINTS", "szOID_ENHANCED_KEY_USAGE", "szOID_NETSCAPE_CERT_TYPE" }; static string[] extensionOID = {"2.5.29.1", "2.5.29.2", "2.5.29.3", "2.5.29.4", "2.5.29.7", "2.5.29.8", "2.5.29.10", "2.5.29.15", "2.5.29.16", "2.5.29.19", "2.5.29.32", "2.5.29.32.0", "2.5.29.35", "2.5.29.14", "2.5.29.17", "2.5.29.18", "2.5.29.21", "2.5.29.23", "2.5.29.31", "2.5.29.37", "2.16.840.1.113730.1.1" } ; static uint MY_ENCODING_TYPE = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING ; static string lpszCertSubject = "" ; public static void Main(string[] args){ IntPtr hSysStore = IntPtr.Zero; IntPtr hCertCntxt = IntPtr.Zero; if(args.Length<1) { Console.WriteLine("Usage: CertAttributes "); return; } lpszCertSubject = args[0]; hSysStore = Win32.CertOpenSystemStore(IntPtr.Zero, MY) ; if(hSysStore == IntPtr.Zero) //no cert store return; hCertCntxt=Win32.CertFindCertificateInStore( hSysStore, MY_ENCODING_TYPE, 0, CERT_FIND_SUBJECT_STR, lpszCertSubject , IntPtr.Zero) ; if(hCertCntxt == IntPtr.Zero){ //no certificate found Console.WriteLine("Could not find SubjectName containing string \"{0}\"", lpszCertSubject); return; } //Console.WriteLine("CertContext:\t0x{0:X}", hCertCntxt.ToInt32()) ; X509Certificate foundcert = new X509Certificate(hCertCntxt); Console.WriteLine("\nFound certificate with SubjectName string \"{0}\"",lpszCertSubject); Console.WriteLine("SubjectName:\t{0}", foundcert.GetName()); Console.WriteLine("Serial No:\t{0}", foundcert.GetSerialNumberString()); Console.WriteLine("HashString:\t{0}" , foundcert.GetCertHashString()); CERT_CONTEXT cntxt = (CERT_CONTEXT)Marshal.PtrToStructure(hCertCntxt, typeof(CERT_CONTEXT)); Console.WriteLine("pCertInfo:\t0x{0:X}", cntxt.pCertInfo); IntPtr certinfo = cntxt.pCertInfo ; //--- walk IntPtr offset in CERT_INFO to SubjectPublicKeyInfo structure (5 ints, 2 longs, 5 IntPtrs) IntPtr publickeyinfo = (IntPtr)(9*4 + 5*IntPtr.Size + (int)certinfo); Console.WriteLine("\nPublic key size: {0} bits", Win32.CertGetPublicKeyLength(MY_ENCODING_TYPE, publickeyinfo)) ; //--- walk IntPtr offset in CERT_INFO to cExtension (additional offset 7 ints, 5 IntPtrs) IntPtr pcExtension = (IntPtr)(7*4 + 5*IntPtr.Size + (int)publickeyinfo); int cExtension = Marshal.ReadInt32(pcExtension, 0); //get number of extensions Console.WriteLine("\n--- This certificate has {0} extensions : ---", cExtension); IntPtr offsetrgExtensions = (IntPtr)(4 + (int)pcExtension) ; //next entry is pointer to rgExtensions IntPtr rgExtensions = Marshal.ReadIntPtr(offsetrgExtensions, 0) ; IntPtr pExten = IntPtr.Zero; IntPtr structinfo = IntPtr.Zero; uint blobbytes = 0; ASCIIEncoding ascii = new ASCIIEncoding(); for (int i=0; i