我使用此代码评估根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
,而Extension.CertificateAuthority
又包含构成链的证书数组。我并不相信我们可以依赖这些元素'在数组中按顺序确定顶级根CA.
我找到this和this,但第一个依赖于Magic Strings™,第二个依赖于可选字段。而且上面的True
属性也不会缩小范围。我们可以看到,链中的两个证书将此属性设置为X509Certificate2
。
Certificate.IssuerThumbprint
的公共财产似乎不包括我们可以用来可靠地识别链中发行人的任何内容。最方便的是X509ChainPolicy.ExtraStore
或类似的东西。
显然,这些信息是以某种方式提供的,因为该链是首先建立的。而且我很难考虑这种简单功能在API中被忽略的可能性。
我必须在某个地方错过它。
- 编辑 -
我找到了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))
属性,它似乎包含所有证书,除了我们之后的那个。从这里开始,这是一个简单的排除问题:
ideally_the_result : dependencies
<tab>the commands
<tab>the commands
<tab>the commands
这是在链中查找顶级根CA的可靠方法吗?
答案 0 :(得分:1)
ChainElements按顺序从最多到最根。因此,只要您没有收到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;
}