.net 如何确保我们';正在从链中获取最顶层的根CA证书?

.net 如何确保我们';正在从链中获取最顶层的根CA证书?,.net,ssl,ssl-certificate,x509certificate2,.net,Ssl,Ssl Certificate,X509certificate2,我正在使用此代码评估链中的每个证书的根CA状态: Function GetRootCaCertificates(Chain As X509Chain) As IEnumerable(Of X509Certificate2) With Chain.ChainElements.Cast(Of X509ChainElement) With .Select(Function(Element As X509ChainElement) Element.Certificate) Ret

我正在使用此代码评估链中的每个证书的根CA状态:

Function GetRootCaCertificates(Chain As X509Chain) As IEnumerable(Of X509Certificate2)
  With Chain.ChainElements.Cast(Of X509ChainElement)
    With .Select(Function(Element As X509ChainElement) Element.Certificate)
      Return .Where(Function(Certificate As X509Certificate2)
                      With Certificate.Extensions.Cast(Of X509Extension)
                        With .Where(Function(Extension As X509Extension) TypeOf Extension Is X509BasicConstraintsExtension)
                          With .Cast(Of X509BasicConstraintsExtension)
                            Return .Where(Function(Extension As X509BasicConstraintsExtension) Extension.CertificateAuthority = True).Count > 0
                          End With
                        End With
                      End With
                    End Function).ToList
    End With
  End With
End Function
它运行良好,但在当前情况下,它将返回两个StartCom证书:

(是的,我知道StartCom已经退市,我将在本周晚些时候处理此事。)

ServerCertificateValidationCallback
委托接收
X509Chain
,该链又包含组成链的证书数组。我不相信我们可以依靠数组中元素的顺序来确定顶级根CA

我找到了和,但第一个依赖于魔术弦™ 第二个依赖于可选字段。而且上面的
扩展名.CertificateAuthority
属性也没有将其缩小到足够的范围。如我们所见,链中的两个证书将此属性设置为
True

X509Certificate2
的公共属性似乎不包含任何我们可以用来可靠识别其链中发行人的内容。最方便的是类似于
Certificate.IssuerThumbprint
或类似的东西

显然,这些信息在某种程度上是可用的,因为该链是在第一时间构建的。我很难考虑这个简单的功能在API中被忽略的可能性

我一定是在什么地方错过了

--编辑--

我找到了
X509ChainPolicy.ExtraStore
属性,它似乎包含除我们要查找的证书之外的所有证书。在这里,这是一个简单的排除问题:

Dim oCertificates As List(Of X509Certificate2)
Dim oThumbprints As IEnumerable(Of String)

oThumbprints = Chain.ChainPolicy.ExtraStore.Cast(Of X509Certificate2).Select(Function(Certificate As X509Certificate2) Certificate.Thumbprint)
oCertificates = Chain.ChainElements.Cast(Of X509ChainElement).Select(Function(Element As X509ChainElement) Element.Certificate).ToList
oCertificates.RemoveAll(Function(Certificate As X509Certificate2) oThumbprints.Contains(Certificate.Thumbprint))

这是在链中查找顶级根CA的可靠方法吗?

链元素按从最叶到最根的顺序排列。因此,只要您没有得到PartialChain错误,它就是最后一个ChainElement的证书

private static X509Certificate2 GetRootCertificate(X509Chain chain)
{
    // Assumes that chain.Build was already called

    X509ChainElement chainElement = chain.ChainElements[chain.ChainElements.Count - 1];

    foreach (X509ChainStatus status in chainElement.ChainElementStatus)
    {
        if (status.Status == X509ChainStatusFlags.PartialChain)
        {
            return null;
        }
    }

    return chainElement.Certificate;
}

…这是100%可靠的排序顺序?(见我的编辑)是的,1号表示0,2号表示1,等等,就是这样。谢谢