商店对性能的影响.打开并存储.证书.在 X509Store 中查找方法

本文关键字:证书 存储 X509Store 方法 查找 性能 影响 | 更新日期: 2023-09-27 18:20:56

private static X509Certificate2 FindCertificate(string certificateSubject)
{
    const StoreName StoreName = StoreName.My;
    const StoreLocation StoreLocation = StoreLocation.LocalMachine;
    var store = new X509Store(StoreName, StoreLocation); 
    try
    {
        store.Open(OpenFlags.ReadOnly);
        // Find with the FindBySubjectName does fetch all the certs partially matching the subject name.
        // Hence, further filter for the certs that match the exact subject name.
        List<X509Certificate2> clientCertificates =
            store.Certificates.Find(X509FindType.FindBySubjectName, certificateSubject, validOnly: true)
                .Cast<X509Certificate2>()
                .Where(c => string.Equals(
                    c.Subject.Split(',').First().Trim(),
                    string.Concat("CN=", certificateSubject).Trim(),
                    StringComparison.OrdinalIgnoreCase)).ToList();
        if (!clientCertificates.Any())
        {
            throw new InvalidDataException(
                string.Format(CultureInfo.InvariantCulture, "Certificate {0} not found in the store {1}.", certificateSubject, StoreLocation.LocalMachine));
        }
        X509Certificate2 result = null;
        foreach (X509Certificate2 cert in clientCertificates)
        {
            DateTime now = DateTime.Now;
            DateTime effectiveDate = DateTime.Parse(cert.GetEffectiveDateString(), CultureInfo.CurrentCulture);
            DateTime expirationDate = DateTime.Parse(cert.GetExpirationDateString(), CultureInfo.CurrentCulture);
            if (effectiveDate <= now && expirationDate.Subtract(now) >= TimeSpan.FromDays(1))
            {
                result = cert;
                break;
            }
        }
        return result;
    }
    finally
    {
        store.Close();
    }
}

我的库中有这段代码,每次创建新请求时,它都会调用此方法。所以基本上是每秒的请求数是 1000 次,那么它将被调用 1000 次。当我使用 PerfView 工具时,我注意到此方法使用了 35% 的 CPU。最大的罪魁祸首是商店。打开并存储。证书.查找方法。

其他人在他们的代码中发现了类似的问题。此外,如果您可以分享您为解决由此引起的性能影响所做的工作。

商店对性能的影响.打开并存储.证书.在 X509Store 中查找方法

只要目标系统没有安装大量证书,就可以跳过对 X509Store 的 .Find() 方法的调用。根据我的经验,它的表现不是很好,之后您已经在对目标subjectName进行必要的过滤。

另外,不要循环访问X509Certificate2的集合两次!如果只需要满足所有条件的第一个匹配证书,则可以将事情简化为单个 LINQ 语句,如下所示:

X509Certificate2 cert =
    store.Certificates.Cast<X509Certificate2>()
        .FirstOrDefault(xc =>
            xc.Subject.Equals("CN=" + certificateSubject, StringComparison.OrdinalIgnoreCase)
            && xc.NotAfter >= DateTime.Now.AddDays(-1)
            && xc.NotBefore <= DateTime.Now);

(请注意,根据您的使用情况和证书,您可能需要也可能不需要修改上述内容以像原始代码一样在逗号上拆分主题(。

最后,正如 Wiktor Zychla 所提到的,如果您的目标计算机没有安装大量证书,您可以通过调用 store.Certificates.Cast<X509Certificate2>().ToList() 来缓存整个证书列表,或者如果您搜索的subjectNames数量有限,则使用从 subjectName 派生的键和基于 NotAfter 属性的过期时间来简单地缓存此方法的结果可能更有效。