在这种情况下(github.com),
X509Chain.Build
将起作用,因为终端证书包含有关颁发者证书位置的信息(在Authority Information Access扩展中)。
但有时可能会出现问题(例如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
集合的第一个元素在ChainelementStatus
集合中没有NotSignatureValid
状态。
您可以将以下代码片段添加到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中检索到的候选列表),其中Subject Key Identifier值与主题中的证书的Authority Key Identifier值相同。
X509Certificate2Collection certs = new X509Certificate2Collection();
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 {
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
变量存储主题中的证书(用于搜索颁发者)。这种方法存在问题,因为它不会验证签名并可能返回虚警。
IssuerName
属性有什么问题? - erickson