2017-04-12 1 views
0

J'utilise ce code pour évaluer chaque certificat dans une chaîne de statut racine CA:Comment s'assurer que nous obtenons le certificat d'autorité de certification racine le plus élevé d'une chaîne?

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 

Il fonctionne bien, mais dans le cas actuel, il est de retour les deux certificats StartCom:

Certificate Chain

(Oui, je sais que StartCom a été retiré de la liste-traitera avec je vais plus tard cette semaine.)

le délégué ServerCertificateValidationCallback reçoit le X509Chain, qui à son tour contient un tableau des certificats qui composent la chaîne. Je ne suis pas convaincu que nous pouvons compter sur l'ordre des éléments dans le tableau pour déterminer l'autorité de certification racine de niveau supérieur.

J'ai trouvé this et this, mais le premier repose sur Magic Strings ™ et le second repose sur un champ facultatif. Et la propriété Extension.CertificateAuthority ci-dessus ne le réduit pas assez non plus. Comme nous pouvons le voir, deux certificats dans la chaîne ont cette propriété définie sur True.

Les propriétés publiques d'un X509Certificate2 ne semblent pas inclure quoi que ce soit que nous puissions utiliser pour identifier de manière fiable son émetteur dans la chaîne. Le plus pratique serait quelque chose comme Certificate.IssuerThumbprint ou similaire.

De toute évidence, cette information est disponible en quelque sorte, puisque la chaîne a été construite en premier lieu. Et j'ai du mal à considérer la possibilité que cette capacité simple ait été négligée dans l'API.

Je dois être absent quelque part.

--EDIT--

Je trouve la propriété X509ChainPolicy.ExtraStore, qui semble contenir tous les certificats sauf celui que nous sommes après. De là, il est une simple question d'exclusion:

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)) 

Est-ce un moyen fiable de trouver l'autorité de certification racine de niveau supérieur dans une chaîne?

Répondre

1

Les ChainElements sont dans l'ordre du plus grand nombre de feuilles jusqu'à la racine. Donc, tant que vous n'obtenez pas d'erreur PartialChain, c'est le dernier certificat 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; 
} 
+0

... et c'est un ordre de tri 100% fiable? (Voir mon édition.) – InteXX

+0

Oui, 1 signes 0, 2 signes 1, et cetera – bartonjs

+0

Voilà, alors. Merci. – InteXX