1 回答

TA貢獻1821條經驗 獲得超6個贊
SslStream 永遠不會發送整個鏈(自我頒發的證書除外)。約定是發送除根以外的所有內容,因為另一方要么已經擁有并信任根,要么沒有(因此/或不信任根),無論哪種方式都是浪費帶寬。
但是 SslStream 只有在理解中間體時才能發送中間體。
var cert = new X509Certificate2(certPath, certPass);
這只會提取最終實體證書(帶有私鑰的證書),它會丟棄 PFX 中的任何其他證書。如果要加載需要使用的所有證書X509Certificate2Collection.Import
。但是......這也對你沒有幫助。SslStream 只接受最終實體證書,它希望系統能夠為它構建一個功能鏈。
為了構建功能鏈,您的中間證書和根證書需要位于以下任一位置:
通過 X509Chain.ChainPolicy.ExtraStore 作為手動輸入提供
由于有問題的鏈是由 SslStream 構建的,因此您不能在這里真正做到這一點。
當前用戶\我的 X509Store
*LocalMachine\My X509Store
CurrentUser\CA X509Store
**LocalMachine\CA X509Store
CurrentUser\Root X509Store
**LocalMachine\Root X509Store
*LocalMachine\ThirdPartyRoot X509Store
http
在證書的授權訪問標識符擴展中標識的(非 s)位置。
*
在 Linux 上的 .NET Core 上不存在標記為的商店。標記 的存儲**
在 Linux 上確實存在,但不能由 .NET 應用程序修改。
這還不夠,因為(至少對于 Linux 上的 SslStream 和 .NET Core 上的 macOS 而言)它仍然只在構建它信任的鏈時才發送中間體。因此,服務器需要真正信任根證書才能發送中間證書。(或者客戶端需要信任客戶端證書的根)
另一方面,同樣的規則也適用。不同之處在于,在回調中您可以選擇重建鏈以添加額外的證書。
private static bool IsExpectedRootPin(X509Chain chain)
{
X509Certificate2 lastCert = chain.ChainElements[chain.ChainElements.Count - 1].Certificate;
return lastCert.RawBytes.SequenceEquals(s_pinnedRootBytes);
}
private static bool ValidateServerCertificate(
object sender,
X509Certificate certificate,
X509Chain chain,
SslPolicyErrors sslPolicyErrors
)
{
if ((sslPolicyErrors & ~SslPolicyErrors.RemoteCertificateChainErrors) != 0)
{
// No cert, or name mismatch (or any future errors)
return false;
}
if (IsExpectedRootPin(chain))
{
return true;
}
chain.ChainPolicy.ExtraStore.Add(s_intermediateCert);
chain.ChainPolicy.ExtraStore.Add(s_pinnedRoot);
chain.ChainPolicy.VerificationFlags |= X509VerificationFlags.AllowUnknownCertificateAuthority;
if (chain.Build(chain.ChainElements[0].Certificate))
{
return IsExpectedRootPin(chain);
}
return false;
}
當然,這種方法的問題是你還需要了解并提供遠程端的中間件。真正的解決方案是中間體應該在 HTTP 分發端點上可用,并且頒發的證書應該帶有授權信息訪問擴展,以便能夠動態定位它們。
- 1 回答
- 0 關注
- 196 瀏覽
添加回答
舉報