在.NET中操做數字證書(新手教程)

.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的證書文件。如圖工具

生成證書測試

makecert.exe的參數讀者能夠查看幫助,這裏只解釋圖6-28中的參數。編碼

參數說明:加密

-sr CurrentUser:指定主題的證書存儲位置。Location 能夠是 currentuser(默認值)或 localmachinespa

-ss MyTestContainer:指定主題的證書存儲名稱,輸出證書即存儲在那裏。

-n CN=TestCert:指定主題的證書名稱。此名稱必須符合 X.500 標準。最簡單的方法是在雙引號中指定此名稱,並加上前綴 CN=;例如,"CN=myName"。

-sky exchange:指定頒發者的密鑰類型,必須是 signature、exchange 或一個表示提供程序類型的整數。默認狀況下,可傳入 1 表示交換密鑰,傳入 2 表示簽名密鑰。

-pe:將所生成的私鑰標記爲可導出。這樣可將私鑰包括在證書中。

生成的密鑰文件被保存在了咱們指定的MyTestContainer中,但到哪去查看咱們的證書呢?Windows沒有給咱們準備好直接的管理證書的入口,但咱們能夠在MMC控制檯自行添加。

  1. 開始  運行  MMC,打開一個空的MMC控制檯。
  2. 在控制檯菜單,文件  添加/刪除管理單元  添加按鈕  選"證書"  添加  選"個人用戶帳戶"  關閉  肯定
  3. 在控制檯菜單,文件  添加/刪除管理單元  添加按鈕  選"證書"  添加  選"計算機帳戶"  關閉  肯定

如圖6-29,咱們能夠查看兩個帳戶的證書管理,在個人帳戶中能夠看到MyTestContainer下的證書TestCert。

在MMC控制檯查看和管理證書

固然咱們也能夠將證書文件保存爲文件,如圖

圖:將證書保存爲文件

打開E盤,能夠看到生成的證書文件。如圖

圖生成的證書文件

將證書保存爲文件時,咱們有三種選擇:

  1. 帶有私鑰的證書

    由Public Key Cryptography Standards #12,PKCS#12標準定義,包含了公鑰和私鑰的二進制格式的證書形式,以pfx做爲證書文件後綴名。

  2. 二進制編碼的證書

    證書中沒有私鑰,DER 編碼二進制格式的證書文件,以cer做爲證書文件後綴名。

  3. Base64編碼的證書

    證書中沒有私鑰,BASE64 編碼格式的證書文件,也是以cer做爲證書文件後綴名。

右鍵單擊本地的證書文件,咱們能夠看到安裝選項,能夠把該證書文件安裝到證書存儲區。也可在MMC的證書管理臺上執行導出任務將存儲區的證書導出爲文件。這裏就再也不演示了,讀者能夠自行實踐。

編程操做證書

咱們能夠經過編程的方式操做操做本地的證書文件和在存儲區中的證書。咱們以剛纔保存在E盤的test.cer文件爲例,講解如何讀取本地的證書文件,並將它添加到存儲區中。先看代碼清單6-17。

代碼清單 6-17 操做本地證書文件

using System;
using System.IO;
using System.Security.Cryptography.X509Certificates;
using NUnit.Framework;

    [TestFixture]
    public class OperCert
    {
        [Test]
        private 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;
        }

        [Test]
        public void CertTest()
        {
            try
            {
                X509Certificate2 x509 = new X509Certificate2();
                byte[] rawData = ReadFile(@"e:\testc.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);
            }
        }
    }

輸入了以下內容:

 
 

Subject: CN=Joe's-Software-Emporium

 
 


Issuer: CN=Root Agency

 
 


Version: 3

 
 


Valid Date: 2013-6-28 13:12:48

 
 


Expiry Date: 2040-1-1 7:59:59

 
 


Thumbprint: 269ED45BCC22ABB2E416B19E16CBC68E1045DCDD

 
 


Serial Number: D6D43B334428E0BD40E148EE641524C0

 
 


Friendly Name: RSA

 
 


Public Key Format: 30 81 89 02 81 81 00 b7 a3 d1 9a 73 a3 f3 b0 1d 72 1e 5b 67 d2 b9 a6 4c f2 9f 01 7c 9d 7d 81 a5 7f b8 b6 54 fe 29 53 91 0c 99 60 01 89 43 2d 61 9f 4e f6 49 5f 9e 66 51 e3 cc 7d 6e 45 73 65 ef 09 c1 37 71 5c 1a 64 06 b7 ac ef 9f 50 68 8c a9 48 43 d0 7c d0 c5 01 c3 77 9d e5 b1 d4 83 d9 15 83 27 f0 2b f0 00 9a e0 10 2c 9c 6f 97 77 f1 e2 d3 f8 68 17 1c c5 5e a6 ec 03 a4 5c df 93 5e 88 46 fa 5d f7 76 9d bd 02 03 01 00 01

 
 


Raw Data Length: 451

 
 


Certificate to string: [Version]
V3

 
 

[Subject]
CN=Joe's-Software-Emporium
Simple Name: Joe's-Software-Emporium
DNS Name: Joe's-Software-Emporium

 
 

[Issuer]
CN=Root Agency
Simple Name: Root Agency
DNS Name: Root Agency

 
 

[Serial Number]
D6D43B334428E0BD40E148EE641524C0

 
 

[Not Before]
2013-6-28 13:12:48

 
 

[Not After]
2040-1-1 7:59:59

 
 

[Thumbprint]
269ED45BCC22ABB2E416B19E16CBC68E1045DCDD

 
 

[Signature Algorithm]
sha1RSA(1.3.14.3.2.29)

 
 

[Public Key]
Algorithm: RSA
Length: 1024
Key Blob: 30 81 89 02 81 81 00 b7 a3 d1 9a 73 a3 f3 b0 1d 72 1e 5b 67 d2 b9 a6 4c f2 9f 01 7c 9d 7d 81 a5 7f b8 b6 54 fe 29 53 91 0c 99 60 01 89 43 2d 61 9f 4e f6 49 5f 9e 66 51 e3 cc 7d 6e 45 73 65 ef 09 c1 37 71 5c 1a 64 06 b7 ac ef 9f 50 68 8c a9 48 43 d0 7c d0 c5 01 c3 77 9d e5 b1 d4 83 d9 15 83 27 f0 2b f0 00 9a e0 10 2c 9c 6f 97 77 f1 e2 d3 f8 68 17 1c c5 5e a6 ec 03 a4 5c df 93 5e 88 46 fa 5d f7 76 9d bd 02 03 01 00 01
Parameters: 05 00

 
 

[Extensions]
* 頒發機構密鑰標識符(2.5.29.1):
KeyID=12 e4 09 2d 06 1d 1d 4f 00 8d 61 21 dc 16 64 63
Certificate Issuer:
CN=Root Agency
Certificate SerialNumber=06 37 6c 00 aa 00 64 8a 11 cf b8 d4 aa 5c 35 f4

 
 

 

 
 


Certificate to XML String: <RSAKeyValue><Modulus>t6PRmnOj87Adch5bZ9K5pkzynwF8nX2BpX+4tlT+KVORDJlgAYlDLWGfTvZJX55mUePMfW5Fc2XvCcE3cVwaZAa3rO+fUGiMqUhD0HzQxQHDd53lsdSD2RWDJ/Ar8ACa4BAsnG+Xd/Hi0/hoFxzFXqbsA6Rc35NeiEb6Xfd2nb0=</Modulus><Exponent>AQAB</Exponent></RSAKeyValue>

 

代碼清單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所示。

圖6-32 生成SPC文件

如圖6-32,咱們使用Cert2spc.exe以test.cer爲參數生成目標爲tset.spc的發行者證書,若是存在多個證書文件,能夠做爲參數以空格隔開生成統一的發行者證書。

使用證書對文件簽名

簽名工具 (SignTool.exe) 是一個命令行工具,用於對文件進行數字簽名,驗證文件或時間戳文件中的簽名。咱們能夠對cab文件、dll文件或者其餘文件進行簽名,從互聯網訪問這些文件的時候就須要安裝和驗證證書。該工具詳細的說明讀者能夠從MSDN上找到,我就不在重複了。

相關文章
相關標籤/搜索