如何使用.net读取PKCS12格式数字证书

随着《电子签名法》的颁布,数字证书应用越来越广泛,在一般的应用中,我们都是在系统中安装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

 

你可能感兴趣的:(.net)