亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

C#/.NET 中的根證書固定

C#/.NET 中的根證書固定

C#
動漫人物 2022-10-23 15:48:45
我想在我的 C# 應用程序中實現證書/公鑰固定。我已經看到了很多直接固定服務器證書的解決方案,例如在這個問題中。但是,為了更靈活,我只想固定根證書。服務器在設置中獲得的證書由中間 CA 簽名,該 CA 本身由根簽名。到目前為止,我實現的是一個服務器,它從 PKCS#12 (.pfx) 文件中加載自己的證書、私鑰、中間證書和根證書。我使用以下命令創建了文件:openssl pkcs12 -export -inkey privkey.pem -in server_cert.pem -certfile chain.pem -out outfile.pfxchain.pem文件包含根證書和中間證書。服務器加載此證書并希望對客戶端進行身份驗證:// certPath is the path to the .pfx file created beforevar cert = new X509Certificate2(certPath, certPass)var clientSocket = Socket.Accept();var sslStream = new SslStream(    new NetworkStream(clientSocket),    false);try {    sslStream.AuthenticateAsServer(cert, false, SslProtocols.Tls12, false);} catch(Exception) {     // Error during authentication}現在,客戶端想要對服務器進行身份驗證:public void Connect() {    var con = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);    con.Connect(new IPEndPoint(this.address, this.port));    var sslStream = new SslStream(        new NetworkStream(con),        false,        new RemoteCertificateValidationCallback(ValidateServerCertificate),        null    );    sslStream.AuthenticateAsClient("serverCN");}public static bool ValidateServerCertificate(    object sender,    X509Certificate certificate,    X509Chain chain,    SslPolicyErrors sslPolicyErrors){    // ??}現在的問題是服務器只將自己的證書發送給客戶端。鏈參數也不包含更多信息。這在某種程度上是合理的,因為X509Certificate2 證書(在服務器代碼中)僅包含服務器證書,沒有關于中間證書或根證書的信息。但是,客戶端無法驗證整個鏈,因為(至少)缺少中間證書。到目前為止,我還沒有發現任何讓 .NET 發送整個證書鏈的可能性,但我不想固定服務器證書本身或中間證書,因為這破壞了根證書固定的靈活性。因此,有沒有人知道讓 SslStream 發送整個鏈進行身份驗證或使用其他方法實現功能的可能性?還是我必須以不同的方式包裝證書?謝謝!編輯:我做了一些其他測試來檢測問題。正如評論中所建議的,我創建了一個X509Store包含所有證書的證書。之后,我X509Chain使用我的服務器證書和商店構建了一個。在服務器本身上,新鏈正確包含所有證書,但不在ValidateServerCertificate函數中。
查看完整描述

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 分發端點上可用,并且頒發的證書應該帶有授權信息訪問擴展,以便能夠動態定位它們。


查看完整回答
反對 回復 2022-10-23
  • 1 回答
  • 0 關注
  • 196 瀏覽

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號