簡體   English   中英

C# X509 證書驗證,帶在線 CRL 檢查,無需將根證書導入受信任的根 CA 證書存儲

[英]C# X509 certificate validation, with Online CRL check, without importing root certificate to trusted root CA certificate store

我正在嘗試驗證 X509 證書鏈而不將根 CA 證書導入受信任的根 CA 證書存儲(在生產中,此代碼將在 Azure Function 中運行,並且您無法將證書添加到受信任的根 CA 證書存儲Azure 應用服務)。

我們還需要對此證書鏈執行在線 CRL 檢查。

我對此進行了搜索,發現許多其他人都面臨同樣的問題,但似乎沒有任何建議有效。 我遵循了這篇SO 帖子中概述的方法,這與 dotnet/runtime GitHub 上的 issue #26449中的建議相呼應。 這是一個重現問題的小型控制台應用程序(針對 .NET Core 3.1):

static void Main(string[] args)
{
    var rootCaCertificate = new X509Certificate2("root-ca-cert.cer");
    var intermediateCaCertificate = new X509Certificate2("intermediate-ca-cert.cer");
    var endUserCertificate = new X509Certificate2("end-user-cert.cer");

    var chain = new X509Chain();
    chain.ChainPolicy.ExtraStore.Add(rootCaCertificate);
    chain.ChainPolicy.ExtraStore.Add(intermediateCaCertificate);
    chain.ChainPolicy.VerificationFlags = X509VerificationFlags.AllowUnknownCertificateAuthority;
    chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
    chain.Build(endUserCertificate);
    chain.Build(new X509Certificate2(endUserCertificate));

    var errors = chain.ChainStatus.ToList();
    if (!errors.Any())
    {
        Console.WriteLine("Certificate is valid");
        return;
    }

    foreach (var error in errors)
    {
        Console.WriteLine($"{error.Status.ToString()}: {error.StatusInformation}");
    }
}

運行時返回三個錯誤:

UntrustedRoot: A certificate chain processed, but terminated in a root certificate which is not trusted by the trust provider.
RevocationStatusUnknown: The revocation function was unable to check revocation for the certificate.
OfflineRevocation: The revocation function was unable to check revocation because the revocation server was offline.

但是,如果我將根 CA 證書添加到受信任的根 CA 證書存儲中,則所有三個錯誤都會消失。

問題

  1. 這是我的實現有問題,還是我試圖做的事情不可能?
  2. 我有什么選擇來嘗試實現這一目標? 一些谷歌搜索表明 .NET 5 中提供的X509ChainPolicy.CustomTrustStore可能會節省一天的時間。 充氣城堡是實現這一目標的另一種選擇嗎?

好吧,不是一個完整的答案,但它可能會讓你繼續前進。

我們在 Azure Web 應用程序(不是 function 應用程序,但我想沒關系)之前構建了您想要的應用程序。 花了我們一周左右的時間。 完整的答案是發布整個應用程序的代碼,我們顯然做不到。 不過有些提示。

我們通過將證書上傳到應用程序(TLS 設置)並通過 WEBSITE_LOAD_CERTIFICATES 設置在代碼中訪問它們來解決證書問題(您將指紋放在那里,您發布的鏈接中也提到了),而不是您可以在代碼中獲取它們並構建您的自己的證書存儲:

var certThumbprintsString = Environment.GetEnvironmentVariable("WEBSITE_LOAD_CERTIFICATES");
var certThumbprints = certThumbprintsString.Split(",").ToList();

var store = new X509Store(StoreName.My, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
for (var i = 0; i < certThumbprints.Count; i++)
{
  store.Certificates.Find(X509FindType.FindByThumbprint, certThumbprint, false);
}

比我們實施了許多驗證器:對於主題、時間、證書鏈(你基本上以某種方式標記你的根和 go 從證書中驗證你的商店中的鏈,看看你是否最終進入你的根)和 CRL。

對於 CRL Bouncy Castle 提供支持:

// Get CRL from certificate, fetch it, cache it
var crlParser = new X509CrlParser();
var crl = crlParser.ReadCrl(data);
var isRevoked = crl.IsRevoked(cert);

從證書中獲取 CRL 很棘手,但可行(我遵循此目的,或多或少https://docs.microsoft.com/en-us/archive/blogs/joetalksmicrosoft/pki-authentication-as-a-azure -網絡應用程序)。

一些谷歌搜索表明 .NET 5 中提供的 X509ChainPolicy.CustomTrustStore 可能會節省一天的時間

是的。

不是將rootCaCertificate放入ExtraStore,而是放入CustomTrustStore,然后設置chain.ChainPolicy.TrustMode chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust; . 現在您提供的根是唯一對鏈有效的根。 您還可以刪除 AllowUnknownCertificateAuthority 標志。

離線撤銷

這個錯誤有點誤導。 這意味着“請求撤銷鏈,但缺少一個或多個撤銷響應”。 在這種情況下,它丟失了,因為構建器沒有要求它,因為它不信任根。 (一旦您不信任根,您就無法信任 CRL/OCSP 響應,那么為什么要要求它們呢?)

撤銷狀態未知

同樣,未知是因為它沒有要求它。 此代碼與 OfflineRevocation 不同,因為從技術上講,有效的 OCSP 響應是(實際上)“我不知道”。 那將是在線/未知的。

不受信任的根

由上面的自定義信任代碼解決。


其他注意事項:確定證書有效的正確方法是從 chain.Build 捕獲 boolean 返回值。 對於您當前的鏈,如果您禁用了撤銷 ( chain.ChainPolicy.RevocationMode = X509RevocationMode.NoCheck ),那么 Build 將返回true ...但UntrustedRoot錯誤仍會出現在 ChainStatus output 中。 如果存在任何VerificationFlags 沒有說要忽略的錯誤,則Build的 boolean 返回為false

您也只需要調用一次 Build :)。

static void Main(string[] args)
{
    var rootCaCertificate = new X509Certificate2("root-ca-cert.cer");
    var intermediateCaCertificate = new X509Certificate2("intermediate-ca-cert.cer");
    var endUserCertificate = new X509Certificate2("end-user-cert.cer");

    var chain = new X509Chain();
    chain.ChainPolicy.CustomTrustStore.Add(rootCaCertificate);
    chain.ChainPolicy.ExtraStore.Add(intermediateCaCertificate);
    chain.ChainPolicy.RevocationMode = X509RevocationMode.Online;
    chain.ChainPolicy.TrustMode = X509ChainTrustMode.CustomRootTrust;
    bool success = chain.Build(endUserCertificate);

    if (success)
    {
        return;
    }

    foreach (X509ChainStatus error in chain.ChainStatus)
    {
        Console.WriteLine($"{error.Status.ToString()}: {error.StatusInformation}");
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM