//*************************************************** // // VerifyCertSigner // Verifies certificate issuer and signature // // Copyright (C) 2004. Michel I. Gallant // // //*************************************************** using System; using System.IO; using System.Collections; using System.Runtime.InteropServices; using System.Security.Cryptography.X509Certificates; using System.ComponentModel; public class Win32 { [DllImport("crypt32.dll", CharSet=CharSet.Auto, SetLastError=true)] public static extern IntPtr CertCreateCertificateContext( uint dwCertEncodingType, byte[] pbCertEncoded, uint cbCertEncoded) ; [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 IntPtr CertFindCertificateInStore( IntPtr hCertStore, uint dwCertEncodingType, uint dwFindFlags, uint dwFindType, IntPtr pCertNameBlob, 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 bool CryptVerifyCertificateSignature( IntPtr hCryptProv, uint dwCertEncodingType, byte[] pbEncoded, // binary DER cert data uint cbEncoded, IntPtr pPublicKey); //PCERT_PUBLIC_KEY_INFO } //-------- 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; } public class VerifyCertSigner { const string MY = "my"; const string ROOT = "root"; const string SUBCA = "ca"; //Intermediate Certificate Authorities const string OTHERS = "addressbook"; const uint PKCS_7_ASN_ENCODING = 0x00010000; const uint X509_ASN_ENCODING = 0x00000001; const uint CERT_FIND_SUBJECT_STR = 0x00080007; const uint CERT_FIND_SUBJECT_NAME = 0x00020007; const uint CERT_FIND_ISSUER_NAME = 0x00020004; static uint MY_ENCODING_TYPE = PKCS_7_ASN_ENCODING | X509_ASN_ENCODING ; static ArrayList searchStores = new ArrayList(); public static void Main(string[] args){ IntPtr hSysStore = IntPtr.Zero; IntPtr hCertCntxt = IntPtr.Zero; IntPtr hIssuerCertCntxt = IntPtr.Zero; searchStores.Add(ROOT); searchStores.Add(SUBCA); searchStores.Add(OTHERS); searchStores.Add(MY); if(args.Length<2){ Console.WriteLine("Usage: VerifyCertSigner [certfile] [certificate_store]"); return; } String fname = args[0]; if (!File.Exists(fname)){ Console.WriteLine("\nFile '" + fname + "' not found "); return; } String searchStore = args[1].ToLower(); if(!searchStores.Contains(searchStore)){ //check for alias certstore names if(searchStore.Equals("personal")) searchStore = "my"; else if (searchStore.Equals("others") || searchStore.Equals("other people")) searchStore = "addressbook"; else { Console.WriteLine("Store '{0}' not known", searchStore) ; return; } } byte[] pcert = getCert(fname); //binary DER encoded cert. data if(pcert == null) return; hCertCntxt = Win32.CertCreateCertificateContext(MY_ENCODING_TYPE, pcert, (uint)pcert.Length); if(hCertCntxt==IntPtr.Zero) { Console.WriteLine("Couldn't create certificate context"); return; } Console.WriteLine("\nCreated certificate context from file {0}", fname); CERT_CONTEXT certcntxt = (CERT_CONTEXT)Marshal.PtrToStructure(hCertCntxt, typeof(CERT_CONTEXT)); IntPtr certinfo = certcntxt.pCertInfo ; //---- Console.WriteLine("pCertInfo:\t0x{0:X}", certinfo); //--- Walk IntPtr offset in CERT_INFO to CERT_NAME_BLOB Issuer (3 ints, 3 IntPtrs) IntPtr pIssuerName = (IntPtr)(3*4 + 3*IntPtr.Size + (int)certinfo); Console.WriteLine("Got IssuerName for certificate\n"); //----- Now search for issuer in searchStore with matching SubjectName -------- //----- The SubjectName of this issuer cert should match the IssuerName of hCertCntxt --- hSysStore = Win32.CertOpenSystemStore(IntPtr.Zero, searchStore) ; Console.WriteLine("Got handle for '{0}' store", searchStore); if(hSysStore != IntPtr.Zero) { hIssuerCertCntxt=Win32.CertFindCertificateInStore( hSysStore, MY_ENCODING_TYPE, 0, CERT_FIND_SUBJECT_NAME, pIssuerName , IntPtr.Zero) ; if(hIssuerCertCntxt != IntPtr.Zero){ X509Certificate foundcert = new X509Certificate(hIssuerCertCntxt); Console.WriteLine("Found matching issuer certificate in '{0}' store", searchStore) ; Console.WriteLine("Issuer SubjectName:\t{0}", foundcert.GetName()); Console.WriteLine("Issuer Serial No:\t{0}", foundcert.GetSerialNumberString()); CERT_CONTEXT issuerCntxt = (CERT_CONTEXT)Marshal.PtrToStructure(hIssuerCertCntxt, typeof(CERT_CONTEXT)); IntPtr issuercertinfo = issuerCntxt.pCertInfo ; //--- walk IntPtr offset in CERT_INFO to SubjectPublicKeyInfo structure (5 ints, 2 longs, 5 IntPtrs) IntPtr pPublicKeyinfo = (IntPtr)(9*4 + 5*IntPtr.Size + (int)issuercertinfo); //Console.WriteLine("Issuer Public key size: {0}", Win32.CertGetPublicKeyLength(MY_ENCODING_TYPE, pPublicKeyinfo)) ; Console.WriteLine("\nVerifying Issuer signature on certificate ..."); if(Win32.CryptVerifyCertificateSignature(IntPtr.Zero, MY_ENCODING_TYPE, pcert, (uint)pcert.Length, pPublicKeyinfo)) Console.WriteLine("****** Verified signature on certificate *********"); else Console.WriteLine("!!!!!! FAILED to verify signature on certificate !!!!!!") ; } else Console.WriteLine("Could not find issuer cert in '{0}' store matching IssuerName in cert '{1}'", searchStore, fname); } //------- Clean Up ----------- if(hCertCntxt != IntPtr.Zero) Win32.CertFreeCertificateContext(hCertCntxt); if(hIssuerCertCntxt != IntPtr.Zero) Win32.CertFreeCertificateContext(hIssuerCertCntxt); if(hSysStore != IntPtr.Zero) Win32.CertCloseStore(hSysStore, 0) ; } private static byte[] getCert(String filename) { if (!File.Exists(filename)) return null; Stream stream=new FileStream(filename,FileMode.Open); int datalen = (int)stream.Length; byte[] buffer=new byte[datalen]; stream.Seek(0,SeekOrigin.Begin); stream.Read(buffer,0,datalen); stream.Close(); return buffer; } }