|
|
随着《电子签名法》的颁布,数字证书应用越来越广泛,在一般的应用中,我们都是在系统中安装pkcs12格式的证书。在访问应用(一般是网页、电子邮件等)时,选择合适的证书。我们也可以使用编程来直接读取证书文件。下面我们就介绍如何使用.net读取数字证书。
要读取pkcs12格式的证书,我们需要调用API,在WIN32类中,我们声明这些API的引用:
1 using System; 2 using System.Runtime.InteropServices; 3 4 namespace X509Cert 5  { 6 7 public class WIN32 8 { 9 public const uint CRYPT_USER_KEYSET = 0x00001000; 10 public const uint CERT_KEY_PROV_INFO_PROP_ID = 0x00000002; 11 public const uint CRYPT_DELETEKEYSET = 0x00000010; 12 13 [DllImport("crypt32.dll", SetLastError=true)] 14 public static extern IntPtr PFXImportCertStore(ref CRYPT_DATA_BLOB pPfx,[MarshalAs(UnmanagedType.LPWStr)] String szPassword,uint dwFlags); 15 16 [DllImport("CRYPT32.DLL", EntryPoint="CertEnumCertificatesInStore", CharSet=CharSet.Auto, SetLastError=true)] 17 public static extern IntPtr CertEnumCertificatesInStore( IntPtr storeProvider, IntPtr prevCertContext); 18 19 [DllImport("CRYPT32.DLL",CharSet=CharSet.Auto, SetLastError=true)] 20 public static extern bool CertGetCertificateContextProperty(IntPtr pCertContext,uint dwPropId,IntPtr pvData,ref uint pcbData); 21 22 [DllImport("advapi32.dll",EntryPoint="CryptAcquireContext",CharSet=CharSet.Auto, SetLastError=true)] 23 public static extern bool CryptAcquireContext(ref IntPtr phProv,string szContainer,string szProvider,uint dwProvType,uint dwFlags); 24 25 [StructLayout(LayoutKind.Sequential)] 26 public struct CRYPT_DATA_BLOB { 27 public int cbData; 28 public IntPtr pbData; 29 } 30 31 [StructLayout(LayoutKind.Sequential)] 32 public struct CRYPT_KEY_PROV_INFO { 33 34 [MarshalAs(UnmanagedType.LPWStr)] 35 public String ContainerName; 36 37 [MarshalAs(UnmanagedType.LPWStr)] 38 public String ProvName; 39 40 public uint ProvType; 41 42 public uint Flags; 43 44 public uint ProvParam; 45 46 public IntPtr rgProvParam; 47 48 public uint KeySpec; 49 50 } 51 52 public WIN32() 53 { 54 // 55 // TODO: 在此处添加构造函数逻辑 56 // 57 } 58 } 59 } 60
然后在Cert类中写一个Read方法读取其中的证书。注意:pfx文件有可能包含几个证书
1 using System; 2 using System.IO; 3 using System.Runtime.InteropServices; 4 using System.Security.Cryptography.X509Certificates; 5 6 namespace X509Cert 7  { 8 /**//// <summary> 9 /// Cert 的摘要说明。 10 /// </summary> 11 public class Cert 12 { 13 public Cert() 14 { 15 // 16 // TODO: 在此处添加构造函数逻辑 17 // 18 } 19 public static System.Security.Cryptography.X509Certificates.X509Certificate[] Read(string filename,string password) { 20 21 //打开证书文件,并读到一个字节数组中。 22 FileStream stream = new FileStream(filename,FileMode.Open); 23 byte[] buffer = new byte[stream.Length]; 24 stream.Read(buffer,0,buffer.Length); 25 stream.Close(); 26 27 //声明并实例化WIN32.CRYPT_DATA_BLOB 将读取到的字节数组拷贝到它的pbData属性中。将字节数组长度赋给cbData属性 28 WIN32.CRYPT_DATA_BLOB cryptdata = new WIN32.CRYPT_DATA_BLOB(); 29 cryptdata.cbData = buffer.Length; 30 cryptdata.pbData = Marshal.AllocHGlobal(cryptdata.cbData); 31 Marshal.Copy(buffer,0,cryptdata.pbData,buffer.Length); 32 IntPtr hMemStore = WIN32.PFXImportCertStore(ref cryptdata,"1234",WIN32.CRYPT_USER_KEYSET); 33 Marshal.FreeHGlobal(cryptdata.pbData); 34 35 uint provinfosize = 0; 36 WIN32.CRYPT_KEY_PROV_INFO certinfo = new WIN32.CRYPT_KEY_PROV_INFO(); 37 38 System.Collections.ArrayList certs = new System.Collections.ArrayList(); 39 40 IntPtr certHandle = IntPtr.Zero; 41 while((certHandle = WIN32.CertEnumCertificatesInStore(hMemStore,certHandle)) != IntPtr.Zero) { 42 43 if(WIN32.CertGetCertificateContextProperty(certHandle,WIN32.CERT_KEY_PROV_INFO_PROP_ID,IntPtr.Zero,ref provinfosize)) { 44 45 IntPtr info = Marshal.AllocHGlobal((int)provinfosize); 46 47 if(WIN32.CertGetCertificateContextProperty(certHandle,WIN32.CERT_KEY_PROV_INFO_PROP_ID,info,ref provinfosize)) { 48 certinfo = (WIN32.CRYPT_KEY_PROV_INFO)Marshal.PtrToStructure(info,typeof(WIN32.CRYPT_KEY_PROV_INFO)); 49 50 certs.Add(new X509Certificate(certHandle)); 51 } 52 Marshal.FreeHGlobal(info); 53 54 } 55 } 56 57 Marshal.FreeHGlobal(hMemStore); 58 59 IntPtr hCryptProv = IntPtr.Zero; 60 if(!WIN32.CryptAcquireContext(ref hCryptProv,certinfo.ContainerName,certinfo.ProvName,certinfo.ProvType,WIN32.CRYPT_DELETEKEYSET)) 61 throw new Exception("释放内存错误"); 62 return (X509Certificate[])certs.ToArray(typeof(X509Certificate)); 63 64 } 65 } 66 } 67
|