In questo caso specifico (github.com), X509Chain.Build
funzionerà, poiché il certificato di fine contiene informazioni sull'ubicazione del certificato di emittente (nell'estensione di accesso alle informazioni di autorità).
Ma a volte questo potrebbe non funzionare (ad esempio, con certificati Thawte, perché Thawte non fornisce informazioni esplicite sull'ubicazione del certificato dell'emittente). E se il certificato è installato nell'archivio certificati locale, non è possibile localizzare automaticamente l'emittente.
Opzione 1 - connessione SSL
Tuttavia, se si lavora con un certificato SSL e si può stabilire una sessione SSL, è possibile ottenere il certificato con l'aggiunta di un listener per la proprietà ServicePointManager.ServerCertificateValidationCallback
: https://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.servercertificatevalidationcallback.aspx
RemoteCertificateValidationCallback delegato contiene diversi parametri, uno di questi è chain
, che contiene una catena di certificati SSL restituita dal server. E se il server remoto contiene un certificato di emittente, verrà presentato nella collezione ChainElements
. Questo oggetto di solito contiene diversi elementi:
-Leaf Certificate
-Issuer Certificate
-(Optional Issuer certs when available)
Quindi, è necessario verificare due cose:
- Se
ChainElements
contiene almeno due elementi (ad esempio, certificato di foglie e proposto dell'emittente).
- Se il primo elemento della raccolta
ChainElements
non ha lo stato NotSignatureValid
nella raccolta ChainelementStatus
.
si potrebbe aggiungere il seguente pezzo di codice nel RemoteCertificateValidationCallback
delegato di eseguire questi controlli:
X509Certificate2 issuer = null;
if (
chain.ChainElements.Count > 1 &&
!chain.ChainElements[0].ChainElementStatus.Any(x => x.Status == X509ChainStatusFlags.NotSignatureValid)) {
issuer = chain.ChainElements[1].Certificate;
}
Se dopo l'esecuzione di questo pezzo di codice variabile issuer
è null
, allora non è possibile determinare automaticamente chi è l'emittente del certificato. Questo processo richiederà alcune ricerche aggiuntive. E non è null
, quindi la variabile issuer
manterrà il certificato di emissione effettivo.
Opzione 2 - ricerca certificati locale
Ok, secondo i vostri commenti, si vuole determinare se il certificato emittente è installato nell'archivio certificati locale o no. Leggendo la tua domanda non l'ho capito. Perché dovremmo indovinare cosa stai guardando? Alla fine, sono ancora insicuro se sai/capisci cosa vuoi ottenere.
Se si vuole trovare se l'emittente è installato nel negozio locale, è possibile utilizzare il seguente algoritmo:
1) utilizzare X509Certificate2Collection.Find metodo e trovare i certificati candidati con il loro nome soggetto
2) trovare nell'elenco dei candidati (recuperato nel passaggio 1) quelli con valore Identificatore chiave soggetto identico al valore Identificatore chiave autorizzazione del certificato nell'oggetto.
X509Certificate2Collection certs = new X509Certificate2Collection();
// grab candidates from CA and Root stores
foreach (var storeName in new[] { StoreName.CertificateAuthority, StoreName.Root }) {
X509Store store = new X509Store(storeName, StoreLocation.CurrentUser);
store.Open(OpenFlags.ReadOnly);
certs.AddRange(store.Certificates);
store.Close();
}
certs = certs.Find(X509FindType.FindBySubjectDistinguishedName, cert.Issuer, false);
if (certs.Count == 0) {
Console.WriteLine("Issuer is not installed in the local certificate store.");
return;
}
var aki = cert.Extensions["2.5.29.35"];
if (aki == null) {
Console.WriteLine("Issuer candidates: ");
foreach (var candidate in certs) {
Console.WriteLine(candidate.Thumbprint);
}
return;
}
var match = Regex.Match(aki.Format(false), "KeyID=(.+)", RegexOptions.IgnoreCase);
if (match.Success) {
var keyid = match.Groups[1].Value.Replace(" ", null).ToUpper();
Console.WriteLine("Issuer candidates: ");
foreach (var candidate in certs.Find(X509FindType.FindBySubjectKeyIdentifier, keyid, false)) {
Console.WriteLine(candidate.Thumbprint);
}
} else {
// if KeyID is not presented in the AKI extension, attempt to get serial number from AKI:
match = Regex.Match(aki.Format(false), "Certificate SerialNumber=(.+)", RegexOptions.IgnoreCase);
var serial = match.Groups[1].Value.Replace(" ", null);
Console.WriteLine("Issuer candidates: ");
foreach (var candidate in certs.Find(X509FindType.FindBySerialNumber, serial, false)) {
Console.WriteLine(candidate.Thumbprint);
}
}
supponendo che cert
variabile memorizza certificato nel soggetto (per cui l'emittente viene ricercato). Questo approccio presenta problemi poiché non convalida la firma e può restituire falsi positivi.
Come hai [chiesto una meta domanda sulla chiusura] (http://meta.stackoverflow.com/q/317570/1364007), ti risponderò in dettaglio qui.Per favore concedimi qualche minuto per rispondere. –
Ho [risposto] (http://meta.stackoverflow.com/a/317581/1364007). Scuse per il ritardo. –
Cosa c'è di sbagliato nella proprietà 'IssuerName'? – erickson