2011-05-23 75 views
6

我的程序包含2個我認識並信任的root證書。 我必須驗證所有源自這兩個根證書的信任中心頒發的信任中心證書和「用戶」證書。如何在不導入root證書的情況下驗證X509證書?

我使用X509Chain類進行驗證,但只有在根證書位於Windows證書存儲區時纔有效。

我正在尋找一種方法來驗證證書,而不導入這些根證書 - 以某種方式告訴X509Chain類,我信任這個根證書,它應該只檢查鏈中的證書,而不是其他任何東西。

實際代碼:

 X509Chain chain = new X509Chain(); 
     chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; 
     chain.ChainPolicy.ExtraStore.Add(root); // i do trust this 
     chain.ChainPolicy.ExtraStore.Add(trust); 
     chain.Build(cert); 

編輯:這是一個.NET 2.0 WinForms應用程序。

回答

1

獲得此方法的方法是編寫自定義驗證。

如果你在此通過細分System.IdentityModel.Selectors.X509CertificateValidator並指定自定義驗證的serviceBehavior對象在web.config中做了WCF背景:

<serviceBehaviors> 
    <behavior name="IdentityService"> 
     <serviceMetadata httpGetEnabled="true" /> 
     <serviceDebug includeExceptionDetailInFaults="true" /> 
     <serviceCredentials> 
     <clientCertificate> 
      <authentication customCertificateValidatorType="SSOUtilities.MatchInstalledCertificateCertificateValidator, SSOUtilities" 
      certificateValidationMode="Custom" /> 
     </clientCertificate> 
     <serviceCertificate findValue="CN=SSO ApplicationManagement" 
      storeLocation="LocalMachine" storeName="My" /> 
     </serviceCredentials> 
    </behavior> 

但如果你只是在尋找一個辦法接受SSL證書從另一臺主機,你可以在web.config文件中修改system.net設置:

下面是一個X509CertificateValidator示例,用於測試客戶端證書是否存在於LocalMachine/Personal存儲中。 (這是你需要的不是什麼,但作爲一個例子可能是有用的。

using System.Collections.Generic; 
using System.Linq; 
using System.Security; 
using System.Security.Cryptography.X509Certificates; 

/// <summary> 
/// This class can be injected into the WCF validation 
/// mechanism to create more strict certificate validation 
/// based on the certificates common name. 
/// </summary> 
public class MatchInstalledCertificateCertificateValidator 
    : System.IdentityModel.Selectors.X509CertificateValidator 
{ 
    /// <summary> 
    /// Initializes a new instance of the MatchInstalledCertificateCertificateValidator class. 
    /// </summary> 
    public MatchInstalledCertificateCertificateValidator() 
    { 
    } 

    /// <summary> 
    /// Validates the certificate. Throws SecurityException if the certificate 
    /// does not validate correctly. 
    /// </summary> 
    /// <param name="certificateToValidate">Certificate to validate</param> 
    public override void Validate(X509Certificate2 certificateToValidate) 
    { 
     var log = SSOLog.GetLogger(this.GetType()); 
     log.Debug("Validating certificate: " 
      + certificateToValidate.SubjectName.Name 
      + " (" + certificateToValidate.Thumbprint + ")"); 

     if (!GetAcceptedCertificates().Where(cert => certificateToValidate.Thumbprint == cert.Thumbprint).Any()) 
     { 
      log.Info(string.Format("Rejecting certificate: {0}, ({1})", certificateToValidate.SubjectName.Name, certificateToValidate.Thumbprint)); 
      throw new SecurityException("The certificate " + certificateToValidate 
       + " with thumprint " + certificateToValidate.Thumbprint 
       + " was not found in the certificate store"); 
     } 

     log.Info(string.Format("Accepting certificate: {0}, ({1})", certificateToValidate.SubjectName.Name, certificateToValidate.Thumbprint)); 
    } 

    /// <summary> 
    /// Returns all accepted certificates which is the certificates present in 
    /// the LocalMachine/Personal store. 
    /// </summary> 
    /// <returns>A set of certificates considered valid by the validator</returns> 
    private IEnumerable<X509Certificate2> GetAcceptedCertificates() 
    { 
     X509Store k = new X509Store(StoreName.My, StoreLocation.LocalMachine); 

     try 
     { 
      k.Open(OpenFlags.ReadOnly | OpenFlags.OpenExistingOnly); 
      foreach (var cert in k.Certificates) 
      { 
       yield return cert; 
      } 
     } 
     finally 
     { 
      k.Close(); 
     } 
    } 
} 
+0

我編輯了這個問題,它是一個.NET 2.0 Winforms應用程序。 – RainerM 2011-05-23 14:54:23

1

如果你知道哪些證書可以是根證書和中間證書的證書來檢查,你可以加載根和中間的公共密鑰ChainPolicy.ExtraStoreX509Chain對象集合

我的任務是編寫一個Windows Forms應用程序來安裝證書,只要它是依賴於我國政府已知的「國家根證書」發佈的。是允許頒發證書來驗證與國家Web服務的連接的有限數量的CA,所以我擁有了一個有限的一組證書可能在鏈中,並且可能在目標機器上丟失。我收集了CA和政府根證書的所有公鑰,並將其存儲在應用的子目錄「cert」中: chain certificates

在Visual Studio中,我將該目錄cert添加到解決方案中,資源。這讓我枚舉了我的c#庫代碼中的「可信」證書集合,即使未安裝頒發者證書,也可以構建一個鏈來檢查證書。我做了一個包裝類X509Chain爲了這個目的:

private class X509TestChain : X509Chain, IDisposable 
{ 
    public X509TestChain(X509Certificate2 oCert) 
    : base(false) 
    { 
    try 
    { 
     ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; 
     ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority; 
     if (!Build(oCert) || (ChainElements.Count <= 1)) 
     { 
     Trace.WriteLine("X509Chain.Build failed with installed certificates."); 
     Assembly asmExe = System.Reflection.Assembly.GetEntryAssembly(); 
     if (asmExe != null) 
     { 
      string[] asResources = asmExe.GetManifestResourceNames(); 
      foreach (string sResource in asResources) 
      { 
      if (sResource.IndexOf(".cert.") >= 0) 
      { 
       try 
       { 
       using (Stream str = asmExe.GetManifestResourceStream(sResource)) 
       using (BinaryReader br = new BinaryReader(str)) 
       { 
        byte[] abResCert = new byte[str.Length]; 
        br.Read(abResCert, 0, abResCert.Length); 
        X509Certificate2 oResCert = new X509Certificate2(abResCert); 
        Trace.WriteLine("Adding extra certificate: " + oResCert.Subject); 
        ChainPolicy.ExtraStore.Add(oResCert); 
       } 
       } 
       catch (Exception ex) 
       { 
       Trace.Write(ex); 
       } 
      } 
      } 
     } 
     if (Build(oCert) && (ChainElements.Count > 1)) 
      Trace.WriteLine("X509Chain.Build succeeded with extra certificates."); 
     else 
      Trace.WriteLine("X509Chain.Build still fails with extra certificates."); 
     } 
    } 
    catch (Exception ex) 
    { 
     Trace.Write(ex); 
    } 
    } 

    public void Dispose() 
    { 
    try 
    { 
     Trace.WriteLine(string.Format("Dispose: remove {0} extra certificates.", ChainPolicy.ExtraStore.Count)); 
     ChainPolicy.ExtraStore.Clear(); 
    } 
    catch (Exception ex) 
    { 
     Trace.Write(ex); 
    } 
    } 
} 

在調用函數,我現在就可以成功地檢查是否有未知的證書由國家根證書導出:

bool bChainOK = false; 
    using (X509TestChain oChain = new X509TestChain(oCert)) 
    { 
     if ((oChain.ChainElements.Count > 0) 
     && IsPKIOverheidRootCert(oChain.ChainElements[oChain.ChainElements.Count - 1].Certificate)) 
     bChainOK = true; 
     if (!bChainOK) 
     { 
     TraceChain(oChain); 
     sMessage = "Root certificate not present or not PKI Overheid (Staat der Nederlanden)"; 
     return false; 
     } 
    } 
    return true; 

要完成圖片:檢查根證書(通常是安裝的,因爲它包含在Windows Update中,但理論上也可能丟失),我將友好名稱和指紋與公佈的值進行比較:

private static bool IsPKIOverheidRootCert(X509Certificate2 oCert) 
{ 
    if (oCert != null) 
    { 
    string sFriendlyName = oCert.FriendlyName; 
    if ((sFriendlyName.IndexOf("Staat der Nederlanden") >= 0) 
     && (sFriendlyName.IndexOf(" Root CA") >= 0)) 
    { 
     switch (oCert.Thumbprint) 
     { 
     case "101DFA3FD50BCBBB9BB5600C1955A41AF4733A04": // Staat der Nederlanden Root CA - G1 
     case "59AF82799186C7B47507CBCF035746EB04DDB716": // Staat der Nederlanden Root CA - G2 
     case "76E27EC14FDB82C1C0A675B505BE3D29B4EDDBBB": // Staat der Nederlanden EV Root CA 
      return true; 
     } 
    } 
    } 
    return false; 
} 

我不確定這個檢查是否安全,但在我的情況下,Windows Forms應用程序的操作員非常確定可以訪問要安裝的有效證書。該軟件的目標是過濾證書列表,以幫助他在計算機的機器存儲區中只安裝正確的證書(該軟件還安裝中間證書和根證書的公鑰,以確保證書的運行時行爲Web服務客戶端是正確的)。

3

我發現這個解決方案不依賴於構建方法的結果,而是檢查ChainStatus屬性。 (沒有測試.NET 2.0,但是這是我找到了這個常見問題的唯一解決方案)

X509Chain chain = new X509Chain(); 
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; 
chain.ChainPolicy.ExtraStore.Add(root); 
chain.Build(cert); 
if (chain.ChainStatus.Length == 1 && 
    chain.ChainStatus.First().Status == X509ChainStatusFlags.UntrustedRoot) 
{ 
    // chain is valid, thus cert signed by root certificate 
    // and we expect that root is untrusted which the status flag tells us 
} 
else 
{ 
    // not valid for one or more reasons 
} 

也有人通過實驗發現,設置

ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority; 

將允許構建方法返回即使您沒有將證書添加到ExtraStore中也是如此,這完全破壞了檢查的目的。我不建議因任何原因使用此標誌。

+0

即使用於簽署最終實體證書的根目錄不同,這似乎也會返回「不可信根」。不是很想要的行爲。 – 2016-05-16 14:31:30

+0

我同意你對AllowUnknownCertificateAuthority的評論,我自己也得出了同樣的結論,同時將我自己的CA證書添加到ExtraStore – tul 2017-01-19 15:44:41

0

我剛剛擴展了@Tristan中的代碼,並檢查根證書是添加到ExtraStore的證書之一。

X509Chain chain = new X509Chain(); 
chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck; 
chain.ChainPolicy.ExtraStore.Add(root); 
chain.Build(cert); 
if (chain.ChainStatus.Length == 1 && 
    chain.ChainStatus.First().Status == X509ChainStatusFlags.UntrustedRoot && 
    chain.ChainPolicy.ExtraStore.Contains(chain.ChainElements[chain.ChainElements.Count - 1].Certificate)) 
{ 
    // chain is valid, thus cert signed by root certificate 
    // and we expect that root is untrusted which the status flag tells us 
    // but we check that it is a known certificate 
} 
else 
{ 
    // not valid for one or more reasons 
}