X509Store 证书问题。查找 FindByThumbprint

Posted

技术标签:

【中文标题】X509Store 证书问题。查找 FindByThumbprint【英文标题】:Problems with X509Store Certificates.Find FindByThumbprint 【发布时间】:2012-01-16 21:39:18 【问题描述】:

我在使用方法X509Store.Certificates.Find时遇到问题

public static X509Certificate2 FromStore(StoreName storeName, 
          StoreLocation storeLocation, X509FindType findType, string findValue)

    X509Store store = new X509Store(storeName, storeLocation);
    store.Open(OpenFlags.ReadOnly);
    try
    
        //findValue = "7a6fa503ab57b81d6318a51ca265e739a51ce660"
        var results = store.Certificates.Find(findType, findValue, true);

        return results[0];                
    
    finally
    
        store.Close();
    

在这种情况下,Find 方法返回 0 个结果 (results.Count == 0),但如果我将 findValue 设为常量,则该方法会找到证书。

public static X509Certificate2 FromStore(StoreName storeName, 
           StoreLocation storeLocation, X509FindType findType, string findValue)

    X509Store store = new X509Store(storeName, storeLocation);
    store.Open(OpenFlags.ReadOnly);
    try
             
        //findValue= "7a6fa503ab57b81d6318a51ca265e739a51ce660"
        var results = store.Certificates.Find(findType, 
                              "7a6fa503ab57b81d6318a51ca265e739a51ce660", true);
        return results[0];
    
    finally
    
        store.Close();
    

【问题讨论】:

【参考方案1】:

我在这里收集了一些答案并将它们组合成一个静态方法,该方法负责删除特殊字符和大写所有内容。希望其他人可以使用它。

public static X509Certificate2 GetCertificate(string thumbprint)

    // strip any non-hexadecimal values and make uppercase
    thumbprint = Regex.Replace(thumbprint, @"[^\da-fA-F]", string.Empty).ToUpper();
    var store = new X509Store(StoreName.My, StoreLocation.LocalMachine);

    try
    
        store.Open(OpenFlags.ReadOnly);

        var certCollection = store.Certificates;
        var signingCert = certCollection.Find(X509FindType.FindByThumbprint, thumbprint, false);
        if (signingCert.Count == 0)
        
            throw new FileNotFoundException(string.Format("Cert with thumbprint: '0' not found in local machine cert store.", thumbprint));
        

        return signingCert[0];
    
    finally
    
        store.Close();
    

【讨论】:

这应该被接受为答案。完美运行! Regex.Replace 应该是 "[^\da-fA-F]" - 指纹是十六进制字符串。 谢谢,Regex 刚刚解决了我对代码发誓半小时后遇到的问题。 很好的正则表达式来处理令人讨厌的秘密隐藏字符巫毒...... 正则表达式确实是不错的解决方案。尽管如此,我对此进行了一些私人研究,尽管有大写/小写或空格,但我的证书总是被发现。唯一的麻烦制造者将是“隐形”部分。在 .NET fw 4.7 上测试。可能取决于固件版本?【参考方案2】:

经过长时间的分析,这对我有用。

    将指纹从证书复制到记事本。 将指纹从记事本复制到 Visual Studio。 以管理员身份运行 Visual Studio。

这就像一个魅力。

【讨论】:

【参考方案3】:

+1 表示 Aasmund Eldhuset 的答案(和其他答案)。

令人讨厌的是,指纹文本框中的第一个字符是 不可见的 Unicode“从左到右标记”控制字符。

很难验证它是否存在。例如,将指纹从我的配置文件复制到 VS 二进制编辑器有时会得到不可见字符,有时不会。

此代码也未能显示问题。我浏览了代码并将鼠标悬停在 x509Store 上以找到我想要的证书。

                X509Certificate2 cert2 = null;
                string storeName = StoreName.My.ToString();
                var x509Store = new X509Store(storeName, StoreLocation.LocalMachine);
                x509Store.Open(OpenFlags.ReadOnly);

                var cert3 = x509Store.Certificates[4];
                var thumbprint3 = cert3.Thumbprint;
                int gotIt = thumbprint3.CompareTo(clientCert);

【讨论】:

【参考方案4】:

我想您已将 Windows 证书信息对话框中的指纹复制粘贴到您的代码中(或者如果这是一个简化示例,则粘贴到配置文件中)。令人讨厌的是,指纹文本框中的第一个字符是invisible Unicode "left-to-right-mark" control character。尝试选择开头的字符串引号和指纹的第一个字符,删除它们(这也将去掉中间的不可见字符),然后手动重新键入它们。


我今天自己也遇到了这种奇怪的行为,我花了一个多小时才弄明白。我最终看到它的方式是使用调试器检查证书对象的findValueThumbprint 的长度和哈希码,结果证明是不同的。这导致我在调试器中检查了这些字符串的字符数组,其中出现了不可见的字符。

【讨论】:

比重新键入更简单的方法是从证书管理控制台对话框中复制指纹并将其粘贴到文本编辑器(如 Notepad++)中,此时不可见的 Unicode 字符将显示为“ ?”或其他一些明显奇怪的角色。然后,您可以取消该字符并将“更新”字符串复制到您的代码/配置/文本框。 @nateirvin:是的(我建议手动重新输入有点矫枉过正,并受到我当时的沮丧情绪的启发)- 或者将其粘贴到 UTF-8 模式并打开显示隐藏的字符(这更有趣,因为它可以准确地向您显示它是哪个字符)。 @James 我相信如果你也删除周围的引号它会被删除(正如我写的那样),但实际上,删除整行肯定应该摆脱它。 此处记录的错误 support.microsoft.com/en-us/kb/2023835 教训是不要从 MMC 复制和粘贴 为了记录指纹不区分大小写。同样在 VS2015 和记事本中,我只需点击删除即可删除不可见字符 - 并首先使用光标键验证它是否存在【参考方案5】:

为了让你知道隐形字符是什么,我看到 mmc 中的指纹是:75 3a ...

然后我将其复制并粘贴到我的 vim 中,我看到以下内容:

75 3a ...

所以在你去掉第一个字符“”和多余的空格之后,你会没事的。

【讨论】:

【参考方案6】:

我也遇到了这个不可见的 Unicode 字符。尝试使用记事本(Windows 10)不知何故对我也不起作用。最后,我使用 PowerShell 来获取干净的指纹十六进制:

PS C:\> $tp= (Get-ChildItem -Path Cert:\LocalMachine\My | Where-Object $_.Subject -match "mycert").Thumbprint;
PS C:\> $tp

Unicode 字符太多了。

【讨论】:

【参考方案7】:

这也让我大吃一惊,我写了这个函数来清除从 MMC 复制和粘贴的指纹:

public string CleanThumbprint(string mmcThumbprint)
    
        //replace spaces, non word chars and convert to uppercase
        return Regex.Replace(mmcThumbprint, @"\s|\W", "").ToUpper();
    

...
        var myThumbprint = CleanThumbprint("‎b3 ab 84 e5 1e e5 e4 75 e7 a5 3e 27 8c 87 9d 2f 05 02 27 56");
        var myCertificate = certificates.Find(X509FindType.FindByThumbprint, myThumbprint, true)[0];

【讨论】:

【参考方案8】:

这是上述建议的简单代码版本-当然对我有用

 private X509Certificate2 GetCertificate()
    
        var certStore = new X509Store("my");
        certStore.Open(OpenFlags.ReadOnly);
        try
        
            const string thumbprint = "18 33 fe 3a 67 d1 9e 0d f6 1e e5 d5 58 aa 8a 97 8c c4 d8 c3";
            var certCollection = certStore.Certificates.Find(X509FindType.FindByThumbprint,
            Regex.Replace(thumbprint, @"\s+", "").ToUpper(), false);
            if (certCollection.Count > 0)
                return certCollection[0];
        
        finally
        
            certStore.Close();
        
        return null;
    

【讨论】:

【参考方案9】:

我遇到了同样的问题并解决了:

    我将指纹从 mmc 直接复制到 VS。我比较了字符串,没有发现任何区别。

    用 hash.length 检查长度,有区别,41 vs. 40。

有一个不可见的 Char 通过从 mmc 中复制出来添加到字符串中。


解决:

    将指纹从 mmc 复制到 Notepad.exe 再次复制此字符串 粘贴到您的代码中

它正在工作。

【讨论】:

【参考方案10】:

我遇到了同样的事情。我在这里的任何地方都找不到这个答案,所以我会发布它。对我来说,X509Store 查找功能似乎无法正常工作。我通过一个简单的 for 循环验证了这一点并手动检索证书。

  X509Store store = new X509Store(StoreName.Root,StoreLocation.LocalMachine);
        store.Open(OpenFlags.ReadOnly);
        X509Certificate cert = new X509Certificate();
        for (int i = 0; i < store.Certificates.Count; i++)
        
            if (store.Certificates[i].SerialNumber == "XXXX")
            
                cert = store.Certificates[i];
            
        

【讨论】:

【参考方案11】:

我成了这个的受害者。指纹的 Windows 控制台管理单元显示中不仅有一个 Unicode“从左到右”字符,而且它还有小写十六进制字符,每两个字符之间有空格。 CertUtil 的输出也有小写字符和空格。为了获得匹配,我必须将 findValue 指定为已转换为

的字符串
    删除前导特殊字符, 删除字符簇之间的空白, 将所有字符改为大写

【讨论】:

【参考方案12】:

这段代码应该可以工作。

我想您已经从证书管理控制台复制了这个指纹。 并且该复制的值包含在 Visual Studio 中不可见的 unicode 不可读符号。尝试删除第一个不可见的符号,如果这是我的想法, 这应该工作。

【讨论】:

【参考方案13】:

替换代码以在商店中找到您的证书,如下所示:

var results = store.Certificates.Find(findType, findValue, true); 

第三个参数是 bool,仅当证书有效时才返回证书。因此,请确保您的证书有效。如果您有一个自签名证书,那么只需将第三个参数传递为“false”

【讨论】:

证书是有效的,因为当一个 put 硬编码方法返回 1 值 var results = store.Certificates.Find(findType, "7a6fa503ab57b81d6318a51ca265e739a51ce660", true); //result.Count = 1 :) 你能检查在运行时传递给方法的指纹 ID 是什么吗? 是正确的,我把它们放在即时窗口上,他有相同的价值:( 您是否将语法更改为上面代码中显示的语法? 现在是英文的:) 我的应用程序中的原始代码和上面一样,只是复制+粘贴错误:)【参考方案14】:
var results = store.Certificates.Find(findType, findType, true);

我认为您的意思是第二个参数是“findValue”。

【讨论】:

第二个参数确实是 findValue, 如果是这样,那么问题出在其他地方。文字字符串与字符串变量参数不会像这样中断,除非实际内容不同(空格?尾随换行符?)

以上是关于X509Store 证书问题。查找 FindByThumbprint的主要内容,如果未能解决你的问题,请参考以下文章

当颁发者不是 X509Store 受信任的根时使用证书,以使用 Microsoft .NET 框架进行客户端身份验证

X509Store 类

在发行人名称与特定值匹配的集合中查找X509证书

x509certificate2 中的空 PrivateKey

读取服务器的证书存储

在 Store C# 中通过哈希查找证书