[C#.NET] X509 數位電子簽章

[C#.NET] X509 數位電子簽章

在上篇[C#.NET] 字串及檔案,利用 RSA 演算法加解密 後半段提到了使用簽章來証明訊息,當時是使用RSA類別提供的Hash演算法來進行簽章動作,根據維基百科所述,我們可以使用數位簽章來提昇安全性。

http://zh.wikipedia.org/zh-hant/RSA%E5%8A%A0%E5%AF%86%E6%BC%94%E7%AE%97%E6%B3%95

image

 

http://zh.wikipedia.org/wiki/%E6%95%B0%E5%AD%97%E8%AE%A4%E8%AF%81

image

 

這是我自己建的CA中心,當然它所產生出的憑證預設是不會被系統所信任的,安裝時可以自己加到信任區,商業用的憑証可花錢購買,來得到系統信任,這是我從咱們 方丈 那裡得到的知識。

image

image


匯入憑証:

可將下載到憑證,雙擊兩下,加入信任區。

SNAGHTML579f3fb

SNAGHTML57a2dfe

SNAGHTML57a8ee3

SNAGHTML57abf35

SNAGHTML57beb25

 

或是開啟MMC控制台

開始程式集→輸入MMC

SNAGHTML5750c1d

SNAGHTML5756d10

SNAGHTML575b68e

SNAGHTML5762d34

SNAGHTML576a494

SNAGHTML576e06b

SNAGHTML5770fb5

SNAGHTML57875c7

 

不管是雙擊兩下還是由MMC控制匯入,都可在這裡查到你匯入的憑証。

SNAGHTML577c982

 

當然也可以匯出,有需要的人就再自己自行操作了,我怕篇幅太長。

SNAGHTML57e51a5


檔案保存格式

  1. 帶有私鑰的憑證以pfx為副檔名
  2. 沒有私鑰以DER編碼為格式的憑証用cer為副檔名
  3. 沒有私鑰以BASE64編碼為格式的憑証用cer為副檔名

 

 

 

從我自己建立的CA憑證中心取得的憑證,在VS2010開起來長這樣。

image


憑証的用法很簡單,只要調用 X509Certificate2 類別

{
    X509Certificate2 cert;
    if (string.IsNullOrEmpty(Password))
    {
        cert = new X509Certificate2(CertFile);
    }
    else
    {
        cert = new X509Certificate2(CertFile, Password);
    }
    return cert;
}

 
我們可以透過一些檢查來驗証憑証是否有效。
{
    if (Cert == null) throw new ArgumentNullException("Ccert");
    X509Chain chain = new X509Chain();

    chain.ChainPolicy.RevocationMode = X509RevocationMode.OnLine;
    chain.Build(Cert);

    if (Cert.NotAfter <= DateTime.Now)
    {
        throw new ApplicationException(string.Format("憑証過期"));
    }
}

憑證匯入並儲存

{
    var cert = this.CreateCertificate(CertFile, Password);
    X509Store store = new X509Store(this.StoreName, this.Location);
    store.Open(OpenFlags.ReadWrite);
    store.Add(cert);
    store.Close();
    return cert;
}

憑証匯出
{
    if (CertSubjectName == null) throw new ArgumentNullException("CertSubjectName");
    if (ExportFile == null) throw new ArgumentNullException("ExportFile");
    X509Store store = new X509Store(this.StoreName, this.Location);
    store.Open(OpenFlags.ReadOnly);
    FileStream fileStream = null;
    try
    {
        fileStream = new FileStream(ExportFile, FileMode.Create, FileAccess.Write);
        foreach (X509Certificate2 cert in store.Certificates)
        {
            if (cert.Subject == CertSubjectName)
            {
                byte[] CertByte;

                if (string.IsNullOrEmpty(Password))
                {
                    CertByte = cert.Export(X509ContentType);
                }
                else
                {
                    CertByte = cert.Export(X509ContentType, Password);
                }
                fileStream.Write(CertByte, 0, CertByte.Length);
                return true;
            }
        }
    }
    finally
    {
        if (fileStream != null) fileStream.Dispose();
        store.Close();
    }
    return false;
}

 
完整範例
{
    private X509ContentType _x509ContentType = X509ContentType.Cert;

    public X509ContentType X509ContentType
    {
        get { return _x509ContentType; }
        set { _x509ContentType = value; }
    }

    private StoreName _storeName = StoreName.My;

    public StoreName StoreName
    {
        get { return _storeName; }
        set { _storeName = value; }
    }

    private StoreLocation _locationr = StoreLocation.CurrentUser;

    public StoreLocation Location
    {
        get { return _locationr; }
        set { _locationr = value; }
    }

    public X509Certificate2 CreateCertificate(string CertFile)
    {
        if (CertFile == null) throw new ArgumentNullException("CertFile");
        return this.CreateCertificate(CertFile, "");
    }

    public X509Certificate2 CreateCertificate(string CertFile, string Password)
    {
        if (CertFile == null) throw new ArgumentNullException("CertFile");
        if (Password == null) throw new ArgumentNullException("Password");
        X509Certificate2 cert = null;
        if (string.IsNullOrEmpty(Password))
        {
            cert = new X509Certificate2(CertFile);
        }
        else
        {
            cert = new X509Certificate2(CertFile, Password);
        }
        return cert;
    }

    public X509Certificate2 ImportCertificate(string CertFile)
    {
        if (CertFile == null) throw new ArgumentNullException("CertFile");
        return this.ImportCertificate(CertFile, "");
    }

    public X509Certificate2 ImportCertificate(string CertFile, string Password)
    {
        if (CertFile == null) throw new ArgumentNullException("CertFile");
        if (Password == null) throw new ArgumentNullException("Password");
        var cert = this.CreateCertificate(CertFile, Password);
        if (cert == null) return null;

        X509Store store = new X509Store(this.StoreName, this.Location);
        store.Open(OpenFlags.ReadWrite);
        store.Add(cert);
        store.Close();
        return cert;
    }

    public bool ExportCertificate(string CertSubjectName, string ExportFile)
    {
        if (CertSubjectName == null) throw new ArgumentNullException("CertSubjectName");
        if (ExportFile == null) throw new ArgumentNullException("ExportFile");
        return ExportCertificate(CertSubjectName, null, ExportFile);
    }

    public bool ExportCertificate(string CertSubjectName, string Password, string ExportFile)
    {
        if (CertSubjectName == null) throw new ArgumentNullException("CertSubjectName");
        if (ExportFile == null) throw new ArgumentNullException("ExportFile");
        X509Store store = new X509Store(this.StoreName, this.Location);
        store.Open(OpenFlags.ReadOnly);
        FileStream fileStream = null;
        try
        {
            fileStream = new FileStream(ExportFile, FileMode.Create, FileAccess.Write);
            foreach (X509Certificate2 cert in store.Certificates)
            {
                if (cert.Subject == CertSubjectName)
                {
                    byte[] CertByte;

                    if (string.IsNullOrEmpty(Password))
                    {
                        CertByte = cert.Export(X509ContentType);
                    }
                    else
                    {
                        CertByte = cert.Export(X509ContentType, Password);
                    }
                    fileStream.Write(CertByte, 0, CertByte.Length);
                    return true;
                }
            }
        }
        finally
        {
            if (fileStream != null) fileStream.Dispose();
            store.Close();
        }
        return false;
    }

    public void VerifyCertificate(X509Certificate2 Cert)
    {
        if (Cert == null) throw new ArgumentNullException("Ccert");
        X509Chain chain = new X509Chain();

        chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck;
        chain.Build(Cert);

        if (Cert.NotAfter <= DateTime.Now)
        {
            throw new ApplicationException(string.Format("憑証過期"));
        }
    }
}

 
憑証匯入單元測試
[DeploymentItem("artag.certnew.cer")]
public void ImportCertificatGetCertTest()
{
    RsaCryptService target = new RsaCryptService();
    target.Location = StoreLocation.CurrentUser;
    target.StoreName = StoreName.AuthRoot;
    target.ImportCertificate("artag.certnew.cer");
}

 
憑証匯出單元測試
public void ExportCertificatTest()
{
    RsaCryptService target = new RsaCryptService();
    target.Location = StoreLocation.CurrentUser;
    target.StoreName = StoreName.AuthRoot;
    string CertName = "CN=artag-AD-CA, DC=artag, DC=com";

    string ExportFile = "export.cer";
    var actual = target.ExportCertificate(CertName, ExportFile);
    Assert.AreEqual(true, actual);
}
憑証檢查單元測試
[DeploymentItem("artag.certnew.cer")]
public void VerifyCertificateTest()
{
    RsaCryptService target = new RsaCryptService();
    X509Certificate2 cert = target.CreateCertificate("artag.certnew.cer");
    target.VerifyCertificate(cert);
}

 

若有謬誤,煩請告知,新手發帖請多包涵


Microsoft MVP Award 2010~2017 C# 第四季
Microsoft MVP Award 2018~2022 .NET

Image result for microsoft+mvp+logo