В данном конкретном случае (github.com) будет работать X509Chain.Build
, поскольку конечный сертификат содержит информацию о расположении сертификата издателя (в расширении доступа к информации о полномочиях).
Но иногда это может не сработать (например, с сертификатами Thawte, поскольку Thawte не предоставляет явной информации о расположении сертификата эмитента). И если сертификат установлен в локальном хранилище сертификатов, нет возможности автоматически найти издателя.
Вариант 1 — SSL-соединение
Однако если вы работаете с SSL-сертификатом и можете установить сеанс SSL, вы можете получить сертификат, добавив прослушиватель к свойству ServicePointManager.ServerCertificateValidationCallback
: https://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.servercertificatevalidationcallback.aspx
Делегат RemoteCertificateValidationCallback содержит несколько параметров, один из них chain
, который содержит цепочку SSL-сертификатов, возвращенную сервером. И если на удаленном сервере есть сертификат эмитента, то он будет представлен там в коллекции ChainElements
. Этот объект обычно содержит несколько элементов:
-Leaf Certificate
-Issuer Certificate
-(Optional Issuer certs when available)
Итак, вам нужно проверить две вещи:
- Если
ChainElements
содержит как минимум два элемента (скажем, конечный сертификат и предлагаемый эмитент).
- Если первый элемент коллекции
ChainElements
не имеет статуса NotSignatureValid
в коллекции ChainelementStatus
.
Вы можете добавить следующий фрагмент кода в делегат RemoteCertificateValidationCallback
для выполнения этих проверок:
X509Certificate2 issuer = null;
if (
chain.ChainElements.Count > 1 &&
!chain.ChainElements[0].ChainElementStatus.Any(x => x.Status == X509ChainStatusFlags.NotSignatureValid)) {
issuer = chain.ChainElements[1].Certificate;
}
Если после выполнения этого фрагмента кода переменная issuer
будет равна null
, то вы не сможете автоматически определить, кто является эмитентом вашего сертификата. Этот процесс потребует некоторых дополнительных исследований. И это не null
, тогда переменная issuer
будет содержать фактический сертификат эмитента.
Вариант 2 — поиск локального хранилища сертификатов
Хорошо, согласно вашим комментариям, вы хотите определить, установлен ли сертификат эмитента в локальном хранилище сертификатов или нет. Прочитав ваш вопрос, я не понял. Почему мы должны угадывать, что вы на самом деле ищете? В конце концов, я все еще не уверен, знаете ли вы/понимаете, чего хотите достичь.
Если вы хотите узнать, установлен ли эмитент в локальном хранилище, вы можете использовать следующий алгоритм:
1) используйте X509Certificate2Collection.Find и найти сертификаты-кандидаты по имени субъекта
2) найдите в списке кандидатов (полученном на шаге 1) те, у которых значение идентификатора ключа субъекта совпадает со значением идентификатора ключа органа сертификации сертификата в субъекте.
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);
}
}
предполагая, что переменная cert
хранит сертификат в теме (для которой ищется эмитент). У этого подхода есть проблемы, поскольку он не проверяет подпись и может возвращать ложные срабатывания.
person
Crypt32
schedule
24.02.2016
IssuerName
? - person erickson   schedule 25.02.2016