c# - 如何以编程方式查找用于签署给定证书的证书?

标签 c# .net ssl x509certificate x509certificate2

在我的 C# 代码中,我有一个 X509Certificate2 对象,它表示一个 SSL 证书(来自本地存储或来自通过 SSL 的成功 HTTP 请求)。该证书使用一些中间证书签名,这些证书可能存在于本地存储中,也可能不存在,因此使用 X509Chain.Build() 可能无法正常工作。

一张Firefox证书查看器的图片(因为我还没有可用的代码):

enter image description here

在“详细信息”下的“证书层次结构”中,我看到了这一点:

  • DigiCert 高保证 EV 根 CA
    • DigiCert SHA2 扩展验证服务器 CA
      • github.com

我的对象代表“github.com”,链中的最低行。我需要以编程方式识别中间线(“DigiCert SHA2 扩展验证服务器 CA”)。

我如何知道可以让我识别哪个证书用于签署我的证书的指纹或任何等效物?

最佳答案

在这种特定情况下 (github.com),X509Chain.Build 将起作用,因为最终证书包含有关颁发者证书位置的信息(在授权信息访问扩展中)。

但有时这可能不起作用(例如,对于 Thawte 证书,因为 Thawte 不提供有关颁发者证书位置的明确信息)。如果证书安装在本地证书存储中,则无法自动定位颁发者。

选项 1 -- SSL 连接

但是,如果您使用 SSL 证书并且可以建立 SSL session ,则可以通过向 ServicePointManager.ServerCertificateValidationCallback 属性添加监听器来获取证书:https://msdn.microsoft.com/en-us/library/system.net.servicepointmanager.servercertificatevalidationcallback.aspx

RemoteCertificateValidationCallback delegate包含几个参数,其中一个参数是chain,它包含了服务器返回的SSL证书链。如果远程服务器包含颁发者证书,它将出现在 ChainElements 集合中。该对象通常包含几个元素:

-Leaf Certificate
    -Issuer Certificate
        -(Optional Issuer certs when available)

因此,您需要检查两件事:

  1. 如果 ChainElements 包含至少两个元素(例如,叶证书和提议的颁发者)。
  2. 如果 ChainElements 集合的第一个元素在 ChainelementStatus 集合中没有 NotSignatureValid 状态。

您可以在 RemoteCertificateValidationCallback 委托(delegate)中添加以下代码来执行这些检查:

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 -- 搜索本地证书存储

好的,根据您的意见,您要确定颁发者证书是否安装在本地证书存储中。通过阅读你的问题,我没有明白。为什么我们应该猜测您实际在看什么?最终,我仍然不确定您是否知道/理解您想要实现的目标。

如果想查找本地store是否安装了issuer,可以使用如下算法:

1) 使用 X509Certificate2Collection.Find方法并通过主题名称查找候选证书

2) 在候选列表(在步骤 1 中检索)中找到主题 key 标识符值与主题中证书的授权 key 标识符值相同的证书。

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 变量将证书存储在主题中(搜索颁发者)。这种方法存在问题,因为它不验证签名并且可能返回误报。

关于c# - 如何以编程方式查找用于签署给定证书的证书?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35601196/

相关文章:

c# - 使用自定义工作流事件更新同一网站集中不同网站中的列表项

c# - .net Sap 连接器 3.0 连接失败

.net - EqualityComparer<Uri>.Default.Equals() 返回错误结果还是什么?

c# - C# 编程的 COM 对象中的 Long 类型在 VB6 中显示为不受支持的变体类型

ssl - Erlang SSL - 证书不适合 sni_fun 回调

PHP cURL 表示不支持 https

c# - 为什么 C# 编译器甚至不警告无限递归?

c# - 使用 Exists 谓词执行 .. While.. 操作。访问修改后的闭包?

.net - 从更高级别获取信息?

macos - 如何从自制软件的 tcl-tk 包中获取 tls?