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 关注
- 141 浏览
添加回答
举报