Problems with X509Store Certificates.Find FindByThumbprint
Asked Answered
I

14

99

I'm having a problem when I use the method 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();
    }
}

In this case the Find Method returns 0 results (results.Count == 0), but if I put the findValue as constant the method find the certificate.

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();
    }
}
Interposition answered 9/12, 2011 at 15:58 Comment(0)
S
147

I suppose that you have copy-pasted the thumbprint from the Windows certificate information dialog box into your code (or to a config file if this is a simplified example). Annoyingly, the first character in the thumbprint textbox is the invisible Unicode "left-to-right-mark" control character. Try selecting the opening string quote and the first character of the thumbprint, deleting them (which will also get rid of the invisible character in-between), and retyping them by hand.


I was subjected to this odd behaviour myself today, and it took me over an hour to figure it out. The way I finally saw it was by using the debugger to check the lengths and hash codes of findValue and of the Thumbprint of the certificate object, which turned out to be different. This led me to inspect the character arrays of those strings in the debugger, where the invisible character showed up.

Savdeep answered 21/2, 2012 at 18:9 Comment(8)
An easier way than re-typing is to copy the thumbprint from the certificate management console dialog and paste it into a text editor (like Notepad++), at which point the invisible Unicode character will appear as a "?" or some other obviously odd character. You can then nix that character and copy the 'updated' string to your code/config/textbox.Chekiang
@nateirvin: True (my suggestion to retype by hand is a bit overkill, and was inspired by how frustrated I was at that point) - or paste it in UTF-8 mode and turn on display of hidden characters (which is even more interesting because it shows you exactly which character it is).Savdeep
If failing in Visual Studio, delete the line as there is an invisible space character you cannot delete individually.Footpound
@Footpound I believe it will get deleted if you also delete the surrounding quotes (as I wrote), but indeed, deleting the entire line should definitely get rid of it.Savdeep
Bug documented here support.microsoft.com/en-us/kb/2023835 lesson is don't copy and paste from MMCMathewmathews
for the record the thumbprint is case insensitive. also in VS2015 and notepad I was able to just hit delete to delete the invisible character - and verify it was there in the first place with the cursor keysOospore
In UTF-8, the offending character (U+200E) will be encoded as these three bytes: 0xE2808EUndoubted
@Undoubted Good point; that'll be useful if someone is looking at a hexdump of a UTF-8-encoded source file, or is using a language that internally represents strings as UTF-8 (like Go). Thank you for the bounty! :-)Savdeep
P
57

I took some of the answers here and combined them into a static method that takes care of removing special characters and upper cases everything. Hopefully someone else can use it.

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();
    }
}
Partridge answered 7/7, 2014 at 19:25 Comment(6)
This should be accepted as the answer. Works perfectly!!Danialdaniala
That Regex.Replace ought to be "[^\da-fA-F]" - thumbprints are hexadecimal strings.Gambrell
Thanks, that Regex just solved the issue I had after swearing at code for half an hour.Osteoblast
Nice regex to deal with that annoying secret-hidden-characters voodoo...Opia
The regex is indeed nice solution. Nevertheless I did some private research on that and my certificate has been always found, despite of upper/lower case or spaces. The only troublemaker would be the "invisible" part. Tested on .NET fw 4.7. Possibly fw version dependant?Abercromby
Right, the regex is removing the invisible parts.Partridge
M
25

I had the same Problem and solved it:

  1. I copied the Fingerprint from mmc directly to VS. I compared the strings and didn't find any difference.

  2. Checking the length with hash.length, there was a difference, 41 vs. 40.

There is an invisible Char added to the string by copying it out of mmc.


Solving:

  1. copy the Fingerprint from mmc to Notepad.exe
  2. copy this string again
  3. paste to your code

It's working.

Merta answered 20/3, 2014 at 8:58 Comment(0)
F
10

I fell victim to this. Not only was there a Unicode "left-to-right" character in the Windows console snap-in display of the thumbprint, but it also had lowercase hex characters, with spaces between every two characters. The output of CertUtil also had lowercase characters, and spaces. To get a match, I had to specify the findValue as a string which has been transformed to

  1. Remove the leading special character,
  2. Remove the whitespace between character clusters,
  3. Change all the characters to uppercase.
Fluoroscopy answered 11/12, 2013 at 23:6 Comment(0)
G
10

This tripped me up too, I wrote this function to clean the thumbprint when copied and pasted from 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];
Gripping answered 24/5, 2016 at 16:35 Comment(0)
H
3

This code should work.

I suppose you have copied this thumbprint from the certificate management console. And that copied value contains unicode non-readable symbol which is invisible in Visual Studio. Try to delete the first invisible symbol and if this is what I think of, this should work.

Harbert answered 2/11, 2012 at 16:25 Comment(0)
R
3

I ran into this same thing. I couldn't find this answer anywhere in here so I'll post it. It seems for me the X509Store find function just was flat not working. I verified this by a simple for loop and retrieving the cert manually.

  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];
            }
        }
Roemer answered 15/1, 2014 at 17:49 Comment(0)
D
1

Replace the code to find your certificate in the store as below:

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

Also the 3rd param which is bool return certificates only if the certificate is valid. So make sure that your certificate is valid. If you have a self signed certificate or so then just pass the 3rd param to be "false"

Device answered 9/12, 2011 at 16:21 Comment(7)
The Certificate is valid, becouse when a put hardcoded the method return 1 value var results = store.Certificates.Find(findType, "7a6fa503ab57b81d6318a51ca265e739a51ce660", true); //result.Count = 1 :)Interposition
Can you check what is the thumbprint Id that is being passed at runtime to the method?Device
is correct i put them on Imediate windows, and he has the same value :(Interposition
Did u change the syntax to the one as shown above in your code?Device
Now in English:) The original code in my application is like the above, it was just a copy + paste error:)Interposition
can you update the code above just that someone else might not think its a error there. Also make sure that the value is exactly the same. Just try to do a string.compare in the code against the hard coded value and the value that is being passed into the methodDevice
+1 for checking that the certificate is valid - that check includes chain trust! See: social.msdn.microsoft.com/Forums/vstudio/en-US/…Homogenetic
F
1

Here is the simple version of code for the above suggestions- ofcourse which is worked for me

 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;
    }
Fidelafidelas answered 19/2, 2016 at 1:19 Comment(0)
L
1

I encounter this invisible Unicode char as well. Trying using Notepad (Windows 10) somehow didn't work well for me either. Finally, I use PowerShell to get the clean thumbprint hex:

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

SO much for Unicode char.

Limey answered 19/6, 2017 at 9:42 Comment(0)
R
0
var results = store.Certificates.Find(findType, findType, true);

I think you mean the 2nd param to be "findValue".

Reitman answered 9/12, 2011 at 16:4 Comment(2)
the 2nd param really is findValue,Interposition
If that's the case, then the problem is elsewhere. A literal string vs. a string variable parameter is not going to break like this unless the actual content is different (whitespace? trailing newline?)Reitman
W
0

Just to let you know what the invisible character is, I see the thumbprint in the mmc being: 75 3a ...

Then I copy and paste it in my vim, I see the following:

<200e>75 3a ...

So after you get rid of the first char "<200e>" and the extra spaces, you'll be fine.

Wretched answered 13/9, 2017 at 21:4 Comment(0)
E
0

+1 for Aasmund Eldhuset's answer (and other answers).

Annoyingly, the first character in the thumbprint textbox is the invisible Unicode "left-to-right-mark" control character.

It can be hard to verify that it is present. For example, copying the thumbprint from my config file to the VS binary editor sometimes gets the invisible character and sometimes doesn't.

Also this code failed to show a problem. I stepped through the code and moused over the x509Store to find the cert I wanted.

                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);
Empathy answered 10/12, 2019 at 20:24 Comment(0)
T
0

After long analysis, Here is what worked for me.

  1. Copy the thumb print from certificate to notepad.
  2. Copy the thumb print from notepad to visual studio.
  3. Run visual studio as admin.

This works like a charm.

Tetartohedral answered 23/3, 2020 at 14:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.