.NET中如何操作数字证书详解
http://blog.csdn.net/zjlovety/article/details/7252792
.NET为我们提供了操作数字证书的两个主要的类,分为为:
System.Security.Cryptography.X509Certificates.X509Certificate2类, 每个这个类的实例可以表示一个证书;
System.Security.Cryptography.X509Certificates.X509Store类,可以对保存在计算机安全区域内的证书进行add/remove/get操作。
另外我们可以使用System.Security.Cryptography.X509Certificates.X509Certificate2UI类来显示证书消息的对话框,它就是在IE中的证书查看器的.NE实现。
生成证书
在介绍以上类的使用方法之前,我们先要拥有一个数字证书,获取数字证书有三种方法,一是从CA机构申请,二是自己搭建服务器发布证书,三是使用makecert.exe来生成一个证书文件。这里我们使用makecert.exe来生成一个证书文件,用来测试。启动VS2010的命令行,输入对应参数,生成名为TestCertificates的证书文件。如图6-28所示。
生成证书
图6-28 生成证书
makecert.exe的参数读者可以查看帮助,这里只解释图6-28中的参数。
参数说明:
-sr CurrentUser:指定主题的证书存储位置。Location 可以是 currentuser(默认值)或 localmachine
-ss MyTestContainer:指定主题的证书存储名称,输出证书即存储在那里。
-n CN=TestCert:指定主题的证书名称。此名称必须符合 X.500 标准。最简单的方法是在双引号中指定此名称,并加上前缀 CN=;例如,"CN=myName"。
-sky exchange:指定颁发者的密钥类型,必须是 signature、exchange 或一个表示提供程序类型的整数。默认情况下,可传入 1 表示交换密钥,传入 2 表示签名密钥。
-pe:将所生成的私钥标记为可导出。这样可将私钥包括在证书中。
生成的密钥文件被保存在了我们指定的MyTestContainer中,但到哪去查看我们的证书呢?Windows没有给我们准备好直接的管理证书的入口,但我们可以在MMC控制台自行添加。
开始 运行 MMC,打开一个空的MMC控制台。
在控制台菜单,文件 添加/删除管理单元 添加按钮 选"证书" 添加 选"我的用户账户" 关闭 确定
在控制台菜单,文件 添加/删除管理单元 添加按钮 选"证书" 添加 选"计算机账户" 关闭 确定
如图6-29,我们可以查看两个账户的证书管理,在我的账户中可以看到MyTestContainer下的证书TestCert。
在MMC控制台查看和管理证书
图6-29 在MMC控制台查看和管理证书
当然我们也可以将证书文件保存为文件,如图6-30所示。
将证书保存为文件
图6-30 将证书保存为文件
打开E盘,可以看到生成的证书文件。如图6-31所示。
生成的证书文件
图6-31 生成的证书文件
将证书保存为文件时,我们有三种选择:
带有私钥的证书
由Public Key Cryptography Standards #12,PKCS#12标准定义,包含了公钥和私钥的二进制格式的证书形式,以pfx作为证书文件后缀名。
二进制编码的证书
证书中没有私钥,DER 编码二进制格式的证书文件,以cer作为证书文件后缀名。
Base64编码的证书
证书中没有私钥,BASE64 编码格式的证书文件,也是以cer作为证书文件后缀名。
右键单击本地的证书文件,我们可以看到安装选项,可以把该证书文件安装到证书存储区。也可在MMC的证书管理台上执行导出任务将存储区的证书导出为文件。这里就不再演示了,读者可以自行实践。
编程操作证书
我们可以通过编程的方式操作操作本地的证书文件和在存储区中的证书。我们以刚才保存在E盘的test.cer文件为例,讲解如何读取本地的证书文件,并将它添加到存储区中。先看代码清单6-17。
代码清单 6-17 操作本地证书文件
class OperCert
{
internal static byte[] ReadFile(string fileName)
{
FileStream f = new FileStream(fileName, FileMode.Open, FileAccess.Read);
int size = (int)f.Length;
byte[] data = new byte[size];
size = f.Read(data, 0, size);
f.Close();
return data;
}
static void Main(string[] args)
{
try
{
X509Certificate2 x509 = new X509Certificate2();
byte[] rawData = ReadFile(@"e:\test.cer");
x509.Import(rawData);
Console.WriteLine("{0}Subject: {1}{0}", Environment.NewLine, x509.Subject);
Console.WriteLine("{0}Issuer: {1}{0}", Environment.NewLine, x509.Issuer);
Console.WriteLine("{0}Version: {1}{0}", Environment.NewLine, x509.Version);
Console.WriteLine("{0}Valid Date: {1}{0}", Environment.NewLine, x509.NotBefore);
Console.WriteLine("{0}Expiry Date: {1}{0}", Environment.NewLine, x509.NotAfter);
Console.WriteLine("{0}Thumbprint: {1}{0}", Environment.NewLine, x509.Thumbprint);
Console.WriteLine("{0}Serial Number: {1}{0}", Environment.NewLine, x509.SerialNumber);
Console.WriteLine("{0}Friendly Name: {1}{0}", Environment.NewLine, x509.PublicKey.Oid.FriendlyName);
Console.WriteLine("{0}Public Key Format: {1}{0}", Environment.NewLine, x509.PublicKey.EncodedKeyValue.Format(true));
Console.WriteLine("{0}Raw Data Length: {1}{0}", Environment.NewLine, x509.RawData.Length);
Console.WriteLine("{0}Certificate to string: {1}{0}", Environment.NewLine, x509.ToString(true));
Console.WriteLine("{0}Certificate to XML String: {1}{0}", Environment.NewLine, x509.PublicKey.Key.ToXmlString(false));
X509Store store = new X509Store();
store.Open(OpenFlags.MaxAllowed);
store.Add(x509);
store.Close();
}
catch (Exception e)
{
Console.WriteLine("Error:"+e.Message);
}
}
}
代码清单6-17演示了如何读取本地证书文件的方法。静态方法ReadFile用来从本地磁盘中读取证书文件到byte数组中。主要的操作都在Main方法中。X509Certificate2 x509 = new X509Certificate2()一句使用无参数的构造函数初始化X509Certificate2类的实例x509。然后我们使用x509.Import(rawData)语句将byte数组导入到当前证书实例。接下来是输出该证书的信息。
输出信息之后,我们看下面的四行代码:
X509Store store = new X509Store();
store.Open(OpenFlags.MaxAllowed);
store.Add(x509);
store.Close();
首先我们初始化一个X509Store类的实例store,然后使用Open方法打开存储区,添加上面读取的证书到存储区。
X509Certificate2一共提供了14个构造函数供我们使用,这里就不一一介绍了。我们也可以通过X509Certificate2类的构造函数直接导入本地的证书文件,可以使用代码清单6-18所示的方式。
代码清单6-18 使用构造函数导入证书文件
X509Certificate2 myX509Certificate2 = new X509Certificate2(
@"e:\MyTestCert.pfx", //证书路径
"password", //证书的私钥保护密码
X509KeyStorageFlags.Exportable //表示此证书的私钥以后还可以导出
);
代码清单6-18给出了如何导入带私钥保护密码的证书的方法。X509KeyStorageFlags 枚举用来标识X.509 证书的私钥导出到何处以及如何导出。该枚举的成员说明如表6-1所示。
表6-1 X509KeyStorageFlags 枚举说明
成员名称
说明
DefaultKeySet
使用默认的密钥集。用户密钥集通常为默认值。
UserKeySet
私钥存储在当前用户存储区而不是本地计算机存储区。既使证书指定密钥应存储在本地计算机存储区,私钥也会存储到当前用户存储区。
MachineKeySet
私钥存储在本地计算机存储区而不是当前用户存储区。
Exportable
导入的密钥被标记为可导出。
UserProtected
通过对话框或其他方法,通知用户密钥被访问。使用的加密服务提供程序 (CSP) 定义确切的行为。
PersistKeySet
导入证书时会保存与 PFX 文件关联的密钥。
那么如何操作存储区中的证书呢,可以使用代码清单6-19的方式。
代码清单6-19 操作存储区中的证书
X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
//轮询存储区中的所有证书
foreach(X509Certificate2 myX509Certificate2 in store.Certificates)
{
//将证书的名称跟要导出的证书MyTestCert比较,找到要导出的证书
if (myX509Certificate2.Subject == "CN=TestCert")
{
//证书导出到byte[]中,password为私钥保护密码
byte[] CertByte = myX509Certificate2.Export(X509ContentType.Pfx,"password");
//将证书的字节流写入到证书文件
FileStream fStream = new FileStream(
@"C:\Samples\PartnerAEncryptMsg\MyTestCert_Exp.pfx",
FileMode.Create,
FileAccess.Write);
fStream.Write(CertByte, 0, CertByte.Length);
fStream.Close();
}
}
store.Close();
代码清单6-19首先声明X509Store类的实例store,使用了两个参数的构造函数,第一个参数是存储容器的名称,StoreName枚举只能枚举系统默认的存储区名称。第二个参数是StoreLocation枚举,用来标识是本机证书还是当前用户证书。导出容器证书使用的是Export方法。第一个参数X509ContentType.Pfx表示要导出为含有私钥的pfx证书形式,第二个参数为私钥保护密码。如果要导出为不含私钥的cer证书,第一个参数使用X509ContentType.Cert,表示导出为不含私钥的cer证书,也就不需要密码了。
创建发行者证书
发行者证书是验证发行者可靠性的证书文件,保护证书发行者的签名。我们可以从证书颁发机构获得该文件。做为程序测试,我们可以使用Cert2spc.exe来生成发行者证书。从命令行启动该程序,如图6-32所示。
生成SPC文件
图6-32 生成SPC文件
如图6-32,我们使用Cert2spc.exe以test.cer为参数生成目标为tset.spc的发行者证书,如果存在多个证书文件,可以作为参数以空格隔开生成统一的发行者证书。
使用证书对文件签名
签名工具 (SignTool.exe) 是一个命令行工具,用于对文件进行数字签名,验证文件或时间戳文件中的签名。我们可以对cab文件、dll文件或者其他文件进行签名,从互联网访问这些文件的时候就需要安装和验证证书。该工具详细的说明读者可以从MSDN上找到,我就不在重复了。
========
C#中使用X509Certificate2类获取数字证书颁发者和持有者的名称信息
在 .NET Framework 中有一个名为 X509Certificate2 的类,使用该类包含的属性可以方便地获得 X.509 格式数字证书中的序列号、有效期起始日、有效期终止日等信息。在MSDN网站上可以查到关于该类的详细说明。
在该类的属性中,Issuer 和 IssuerName、Subject 和 SubjectName 这两对看起来比较像,容易让人混淆。这里做一下说明:
1) Issuer 和 Subject 属性的类型都是 string,使用这两个属性,可以分别得到证书颁发者和证书持有者的 Distinguished Name。Distinguished Name 通常是一个类似下面形式的字符串:"CN=MyName, O=MyOrg, OU=MyOrgUnit, C=US"
这种字符串内部用 , 作为分隔符(注意是英文中的逗号,不是中文中的逗号),其中 CN 代表 Common Name,O 代表组织名,OU 代表组织下属机构名,C 代表国家名。
2) IssuerName 和 SubjectName 属性的类型都是 System.Security.Cryptography.X509Certificates.X500DistinguishedName,注意不是 string。X500DistinguishedName 有三个属性,分别是:Name, Oid 和 RawData。使用 Name 属性也可以获得 Distinguished Name。即:
X509Certificate2.Issuer 与 X509Certificate2.IssuerName.Name 的值是相等的;
X509Certificate2.Subject 与 X509Certificate2.SubjectName.Name 的值是相等的。
对于证书颁发者或持有者的 Distinguished Name,经常被用到的部分是其中的 Common Name,即 CN= 后面的内容。但是 .NET Framework 中并没有直接提供从 Distinguished Name 中提取出 Common Name 的方法。由于 Distinguished Name 的内部是用 , 来隔开不同含义的部分,于是就可以用 , 作为分隔符,将 Distinguished Name 拆分为多个子串,然后在子串中查找 CN= ,找到以后把 CN= 后面的部分提取出来,这样就可以得到 Common Name 的值了。具体实现代码如下:
/**************************************************
* Author: HAN Wei
* Author's blog: http://blog.csdn.net/henter/
* Date: April 23rd, 2015
* Description: demonstrate how to extract Common Name
* from Distinguished Name
**************************************************/
using System;
namespace ExtractCnFromDn
{
class Program
{
public static string ExtractCommonNameFromDN(string DistinguishedName)
{
if (String.IsNullOrEmpty(DistinguishedName))
{
throw new ArgumentNullException("Distinguishedname");
}
string strCommonName = string.Empty;
bool bFoundSubStr = false;
string strStartSubStr = "CN=";
char[] chDelimiterChars = { ',' };
string[] NameArray = DistinguishedName.Split(chDelimiterChars);
int iNameLength;
for (int i = 0; i < NameArray.Length; i++)
{
iNameLength = NameArray[i].Length;
if (iNameLength > 3)
{
if (String.Compare(strStartSubStr, NameArray[i].Substring(0, 3), true) == 0)
{
strCommonName = NameArray[i].Substring(3, (iNameLength - 3));
bFoundSubStr = true;
break;
}
}
}
if (bFoundSubStr == false)
strCommonName = string.Empty;
return strCommonName;
}
/*************************************************/
static void Main(string[] args)
{
string strDn = "CN=测试人员,
[email protected], S=上海市, C=CN"; /* 注意这里的 , 不是中文里的逗号 */
string strCn = string.Empty;
try
{
strCn = ExtractCommonNameFromDN(strDn);
}
catch (ArgumentNullException e)
{
Console.WriteLine("Error message: {0}", e.Message);
Console.ReadLine();
return;
}
Console.WriteLine("Distinguished name: {0}", strDn);
Console.WriteLine("Common name: {0}", strCn);
Console.ReadLine();
return;
}
}
}
========
C#创建数字证书并导出为pfx,并使用pfx进行非对称加解密
http://www.cnblogs.com/luminji/archive/2010/10/28/1863179.html
本文源程序下载:http://download.csdn.net/source/2444494
我的项目当中,考虑到安全性,需要为每个客户端分发一个数字证书,同时使用数字证书中的公私钥来进行数据的加解密。为了完成这个安全模块,特写了如下一个DEMO程序,该DEMO程序包含的功能有:
1:调用.NET2.0的MAKECERT创建含有私钥的数字证书,并存储到个人证书区;
2:将该证书导出为pfx文件,并为其指定一个用来打开pfx文件的password;
3:读取pfx文件,导出pfx中公钥和私钥;
4:用pfx证书中的公钥进行数据的加密,用私钥进行数据的解密;
系统界面:
image
代码如下:
01.///
02. /// 将证书从证书存储区导出,并存储为pfx文件,同时为pfx文件指定打开的密码
03. /// 本函数同时也演示如何用公钥进行加密,私钥进行解密
04. ///
05. ///
06. ///
07. private void btn_toPfxFile_Click(object sender, EventArgs e)
08. {
09. X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
10. store.Open(OpenFlags.ReadWrite);
11. X509Certificate2Collection storecollection = (X509Certificate2Collection)store.Certificates;
12. foreach (X509Certificate2 x509 in storecollection)
13. {
14. if (x509.Subject == "CN=luminji")
15. {
16. Debug.Print(string.Format("certificate name: {0}", x509.Subject));
17. byte[] pfxByte = x509.Export(X509ContentType.Pfx, "123");
18. using (FileStream fileStream = new FileStream("luminji.pfx", FileMode.Create))
19. {
20. // Write the data to the file, byte by byte.
21. for (int i = 0; i < pfxByte.Length; i++)
22. fileStream.WriteByte(pfxByte[i]);
23. // Set the stream position to the beginning of the file.
24. fileStream.Seek(0, SeekOrigin.Begin);
25. // Read and verify the data.
26. for (int i = 0; i < fileStream.Length; i++)
27. {
28. if (pfxByte[i] != fileStream.ReadByte())
29. {
30. Debug.Print("Error writing data.");
31. return;
32. }
33. }
34. fileStream.Close();
35. Debug.Print("The data was written to {0} " +
36. "and verified.", fileStream.Name);
37. }
38. string myname = "my name is luminji! and i love huzhonghua!";
39. string enStr = this.RSAEncrypt(x509.PublicKey.Key.ToXmlString(false), myname);
40. MessageBox.Show("密文是:" + enStr);
41. string deStr = this.RSADecrypt(x509.PrivateKey.ToXmlString(true), enStr);
42. MessageBox.Show("明文是:" + deStr);
43. }
44. }
45. store.Close();
46. store = null;
47. storecollection = null;
48. }
49. ///
50. /// 创建还有私钥的证书
51. ///
52. ///
53. ///
54. private void btn_createPfx_Click(object sender, EventArgs e)
55. {
56. string MakeCert = "C:\\Program Files\\Microsoft Visual Studio 8\\SDK\\v2.0\\Bin\\makecert.exe";
57. string x509Name = "CN=luminji";
58. string param = " -pe -ss my -n \"" + x509Name + "\" " ;
59. Process p = Process.Start(MakeCert, param);
60. p.WaitForExit();
61. p.Close();
62. MessageBox.Show("over");
63. }
64. ///
65. /// 从pfx文件读取证书信息
66. ///
67. ///
68. ///
69. private void btn_readFromPfxFile(object sender, EventArgs e)
70. {
71. X509Certificate2 pc = new X509Certificate2("luminji.pfx", "123");
72. MessageBox.Show("name:" + pc.SubjectName.Name);
73. MessageBox.Show("public:" + pc.PublicKey.ToString());
74. MessageBox.Show("private:" + pc.PrivateKey.ToString());
75. pc = null;
76. }
77. ///
78. /// RSA解密
79. ///
80. ///
81. ///
82. ///
83. public string RSADecrypt(string xmlPrivateKey, string m_strDecryptString)
84. {
85. RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
86. provider.FromXmlString(xmlPrivateKey);
87. byte[] rgb = Convert.FromBase64String(m_strDecryptString);
88. byte[] bytes = provider.Decrypt(rgb, false);
89. return new UnicodeEncoding().GetString(bytes);
90. }
91. ///
92. /// RSA加密
93. ///
94. ///
95. ///
96. ///
97. public string RSAEncrypt(string xmlPublicKey, string m_strEncryptString)
98. {
99. RSACryptoServiceProvider provider = new RSACryptoServiceProvider();
100. provider.FromXmlString(xmlPublicKey);
101. byte[] bytes = new UnicodeEncoding().GetBytes(m_strEncryptString);
102. return Convert.ToBase64String(provider.Encrypt(bytes, false));
103. }
上文是一个示例程序,一个完整的证书工具类如下:
01.public sealed class DataCertificate
02. {
03. #region 生成证书
04. ///
05. /// 根据指定的证书名和makecert全路径生成证书(包含公钥和私钥,并保存在MY存储区)
06. ///
07. ///
08. ///
09. ///
10. public static bool CreateCertWithPrivateKey(string subjectName, string makecertPath)
11. {
12. subjectName = "CN=" + subjectName;
13. string param = " -pe -ss my -n \"" + subjectName + "\" ";
14. try
15. {
16. Process p = Process.Start(makecertPath, param);
17. p.WaitForExit();
18. p.Close();
19. }
20. catch (Exception e)
21. {
22. LogRecord.putErrorLog(e.ToString(), "DataCerficate.CreateCertWithPrivateKey");
23. return false;
24. }
25. return true;
26. }
27. #endregion
28.
29. #region 文件导入导出
30. ///
31. /// 从WINDOWS证书存储区的个人MY区找到主题为subjectName的证书,
32. /// 并导出为pfx文件,同时为其指定一个密码
33. /// 并将证书从个人区删除(如果isDelFromstor为true)
34. ///
35. ///
证书主题,不包含CN=
36. ///
pfx文件名
37. ///
pfx文件密码
38. ///
是否从存储区删除
39. ///
40. public static bool ExportToPfxFile(string subjectName, string pfxFileName,
41. string password, bool isDelFromStore)
42. {
43. subjectName = "CN=" + subjectName;
44. X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
45. store.Open(OpenFlags.ReadWrite);
46. X509Certificate2Collection storecollection = (X509Certificate2Collection)store.Certificates;
47. foreach (X509Certificate2 x509 in storecollection)
48. {
49. if (x509.Subject == subjectName)
50. {
51. Debug.Print(string.Format("certificate name: {0}", x509.Subject));
52.
53. byte[] pfxByte = x509.Export(X509ContentType.Pfx, password);
54. using (FileStream fileStream = new FileStream(pfxFileName, FileMode.Create))
55. {
56. // Write the data to the file, byte by byte.
57. for (int i = 0; i < pfxByte.Length; i++)
58. fileStream.WriteByte(pfxByte[i]);
59. // Set the stream position to the beginning of the file.
60. fileStream.Seek(0, SeekOrigin.Begin);
61. // Read and verify the data.
62. for (int i = 0; i < fileStream.Length; i++)
63. {
64. if (pfxByte[i] != fileStream.ReadByte())
65. {
66. LogRecord.putErrorLog("Export pfx error while verify the pfx file!", "ExportToPfxFile");
67. fileStream.Close();
68. return false;
69. }
70. }
71. fileStream.Close();
72. }
73. if( isDelFromStore == true)
74. store.Remove(x509);
75. }
76. }
77. store.Close();
78. store = null;
79. storecollection = null;
80. return true;
81. }
82. ///
83. /// 从WINDOWS证书存储区的个人MY区找到主题为subjectName的证书,
84. /// 并导出为CER文件(即,只含公钥的)
85. ///
86. ///
87. ///
88. ///
89. public static bool ExportToCerFile(string subjectName, string cerFileName)
90. {
91. subjectName = "CN=" + subjectName;
92. X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
93. store.Open(OpenFlags.ReadWrite);
94. X509Certificate2Collection storecollection = (X509Certificate2Collection)store.Certificates;
95. foreach (X509Certificate2 x509 in storecollection)
96. {
97. if (x509.Subject == subjectName)
98. {
99. Debug.Print(string.Format("certificate name: {0}", x509.Subject));
100. //byte[] pfxByte = x509.Export(X509ContentType.Pfx, password);
101. byte[] cerByte = x509.Export(X509ContentType.Cert);
102. using (FileStream fileStream = new FileStream(cerFileName, FileMode.Create))
103. {
104. // Write the data to the file, byte by byte.
105. for (int i = 0; i < cerByte.Length; i++)
106. fileStream.WriteByte(cerByte[i]);
107. // Set the stream position to the beginning of the file.
108. fileStream.Seek(0, SeekOrigin.Begin);
109. // Read and verify the data.
110. for (int i = 0; i < fileStream.Length; i++)
111. {
112. if (cerByte[i] != fileStream.ReadByte())
113. {
114. LogRecord.putErrorLog("Export CER error while verify the CERT file!", "ExportToCERFile");
115. fileStream.Close();
116. return false;
117. }
118. }
119. fileStream.Close();
120. }
121. }
122. }
123. store.Close();
124. store = null;
125. storecollection = null;
126. return true;
127. }
128. #endregion
129.
130. #region 从证书中获取信息
131. ///
132. /// 根据私钥证书得到证书实体,得到实体后可以根据其公钥和私钥进行加解密
133. /// 加解密函数使用DEncrypt的RSACryption类
134. ///
135. ///
136. ///
137. ///
138. public static X509Certificate2 GetCertificateFromPfxFile(string pfxFileName,
139. string password)
140. {
141. try
142. {
143. return new X509Certificate2(pfxFileName, password, X509KeyStorageFlags.Exportable);
144. }
145. catch (Exception e)
146. {
147. LogRecord.putErrorLog("get certificate from pfx" + pfxFileName + " error:" + e.ToString(),
148. "GetCertificateFromPfxFile");
149. return null;
150. }
151. }
152. ///
153. /// 到存储区获取证书
154. ///
155. ///
156. ///
157. public static X509Certificate2 GetCertificateFromStore(string subjectName)
158. {
159. subjectName = "CN=" + subjectName;
160. X509Store store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
161. store.Open(OpenFlags.ReadWrite);
162. X509Certificate2Collection storecollection = (X509Certificate2Collection)store.Certificates;
163. foreach (X509Certificate2 x509 in storecollection)
164. {
165. if (x509.Subject == subjectName)
166. {
167. return x509;
168. }
169. }
170. store.Close();
171. store = null;
172. storecollection = null;
173. return null;
174. }
175. ///
176. /// 根据公钥证书,返回证书实体
177. ///
178. ///
179. public static X509Certificate2 GetCertFromCerFile(string cerPath)
180. {
181. try
182. {
183. return new X509Certificate2(cerPath);
184. }
185. catch (Exception e)
186. {
187. LogRecord.putErrorLog(e.ToString(), "DataCertificate.LoadStudentPublicKey");
188. return null;
189. }
190. }
191. #endregion
192. }
Creative Commons License
本文基于Creative Commons Attribution 2.5 China Mainland License发布,欢迎转载,演绎或用于商业目的,但是必须保留本文的署名http://www.cnblogs.com/luminji(包含链接)。
========