Проблемы с сертификатами X509Store. Найти FindByThumbprint

84

У меня проблема при использовании метода 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();
    }
}

В этом случае метод поиска возвращает 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();
    }
}
нунофамель
источник

Ответы:

136

Я предполагаю, что вы скопировали отпечаток из диалогового окна информации о сертификате Windows в свой код (или в файл конфигурации, если это упрощенный пример). Досадно, что первым символом в текстовом поле отпечатка является невидимый управляющий символ Unicode «слева направо» . Попробуйте выбрать кавычку в открывающей строке и первый символ отпечатка пальца, удалить их (что также избавит от невидимого символа между ними) и ввести их вручную.


Сегодня я сам подвергся такому странному поведению, и мне потребовалось больше часа, чтобы понять это. Образом я наконец увидел это было с помощью отладчика для проверки длины и хэш - коды findValueи из Thumbprintобъекта сертификата, который оказался по - другому. Это привело меня к проверке символьных массивов этих строк в отладчике, где обнаружился невидимый символ.

Осмунд Эльдхусет
источник
4
Более простой способ, чем повторный ввод, - скопировать отпечаток пальца из диалогового окна консоли управления сертификатами и вставить его в текстовый редактор (например, Notepad ++), после чего невидимый символ Unicode появится как "?" или какой-нибудь другой явно странный персонаж. Затем вы можете удалить этот символ и скопировать «обновленную» строку в свой код / ​​конфигурацию / текстовое поле.
nateirvin 08
2
@nateirvin: True (мое предложение перепечатать вручную - это немного излишне, и я был вдохновлен тем, насколько я был разочарован в тот момент) - или вставьте его в режим UTF-8 и включите отображение скрытых символов (что еще интереснее потому что он показывает вам, какой именно персонаж).
Осмунд Эльдхусет
1
@James Я считаю, что он будет удален, если вы также удалите окружающие кавычки (как я уже писал), но на самом деле удаление всей строки обязательно должно избавить от нее.
Осмунд Эльдхусет
1
Ошибка, описанная здесь support.microsoft.com/en-us/kb/2023835 урок: не копировать и вставлять из MMC
Даррил Браатен
3
для записи отпечаток не чувствителен к регистру. также в VS2015 и блокноте я смог просто нажать удалить, чтобы удалить невидимый символ - и проверить, что он был там в первую очередь с помощью клавиш управления курсором
Simon_Weaver
50

Я взял здесь некоторые ответы и объединил их в статический метод, который позаботится об удалении специальных символов и всего верхнего регистра. Надеюсь, кто-нибудь еще сможет им воспользоваться.

    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();
        }
    }
Jhilden
источник
2
Это следует принять как ответ. Прекрасно работает !!
Aster Veigas
6
Это Regex.Replace должно быть "[^ \ da-fA-F]" - отпечатки пальцев представляют собой шестнадцатеричные строки.
Росс Паттерсон
Спасибо, что Regex только что решил проблему, которая возникла у меня после получасового ругательства над кодом.
Frans
Хорошее регулярное выражение для борьбы с этим надоедливым вуду с секретными скрытыми символами ...
granadaCoder
23

У меня была такая же проблема, и я решил ее:

  1. Я скопировал отпечаток пальца из mmc прямо в VS. Я сравнил струны и не нашел никакой разницы.

  2. Проверяя длину с помощью hash.length, было различие: 41 против 40.

К строке добавлен невидимый Char, скопировав его из mmc.


Решение:

  1. скопируйте отпечаток пальца из mmc в Notepad.exe
  2. скопируйте эту строку снова
  3. вставить в свой код

Работает.

Томас
источник
10

Это меня тоже сбило с толку, я написал эту функцию для очистки отпечатка пальца при копировании и вставке из 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];
Роб С
источник
9

Я стал жертвой этого. В оснастке консоли Windows для отображения отпечатка пальца был не только символ Unicode «слева направо», но и шестнадцатеричные символы нижнего регистра с пробелами между каждыми двумя символами. В выводе CertUtil также были символы нижнего регистра и пробелы. Чтобы найти совпадение, мне пришлось указать findValue как строку, которая была преобразована в

  1. Удалить ведущий специальный символ,
  2. Удалите пробелы между кластерами символов,
  3. Измените все символы на прописные .
Грег
источник
3

Этот код должен работать.

Я полагаю, вы скопировали этот отпечаток из консоли управления сертификатами. И это скопированное значение содержит нечитаемый символ Юникода, который невидим в Visual Studio. Попробуйте удалить первый невидимый символ, и если это то, о чем я думаю, это должно сработать.

Дмитрий Дьячков
источник
2

Я столкнулся с тем же самым. Я нигде не нашел здесь этого ответа, поэтому отправлю его. Мне кажется, что функция поиска 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];
            }
        }
викинг
источник
1

Замените код, чтобы найти сертификат в магазине, как показано ниже:

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

Также третий параметр, который является bool, возвращает сертификаты, только если сертификат действителен. Поэтому убедитесь, что ваш сертификат действителен. Если у вас есть самоподписанный сертификат или около того, просто передайте третий параметр как "false"

Раджеш
источник
Сертификат действителен, потому что, когда метод put жестко закодирован, возвращает 1 значение var results = store.Certificates.Find (findType, "7a6fa503ab57b81d6318a51ca265e739a51ce660", true); //result.Count = 1 :)
nunofamel
Можете ли вы проверить, какой идентификатор отпечатка передается методу во время выполнения?
Раджеш
правильно, я поместил их в окна Imediate, и он имеет такое же значение :(
nunofamel
Вы изменили синтаксис в коде на тот, который показан выше?
Раджеш
Теперь на английском :) Исходный код в моем приложении такой же, как и выше, это просто ошибка копирования + вставки :)
nunofamel
1

Вот простая версия кода для вышеупомянутых предложений - конечно, сработала для меня

 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;
    }
Джей
источник
1

Я также сталкиваюсь с этим невидимым символом Unicode. Попытка использовать Блокнот (Windows 10) тоже как-то не сработала. Наконец, я использую PowerShell, чтобы получить чистый шестнадцатеричный код отпечатка:

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

ТАК много для Unicode char.

Риза Мархабан
источник
0
var results = store.Certificates.Find(findType, findType, true);

Я думаю, вы имеете в виду, что второй параметр - «findValue».

Джо
источник
второй параметр на самом деле findValue,
nunofamel
Если это так, то проблема в другом. Буквальная строка по сравнению с параметром строковой переменной не разорвется таким образом, если фактическое содержимое не будет другим (пробелы? Конечная новая строка?)
Джо
0

Просто чтобы вы знали, что это за невидимый символ, я вижу отпечаток большого пальца в mmc: 75 3a ...

Затем я копирую и вставляю его в свой vim, я вижу следующее:

<200e> 75 3a ...

Так что после того, как вы избавитесь от первого символа «<200e>» и лишних пробелов, все будет в порядке.

iefgnoix
источник
0

+1 за ответ Осмунда Эльдхусета (и другие ответы).

Досадно, что первый символ в текстовом поле отпечатка пальца - это невидимый управляющий символ 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);
mmesser314
источник
0

После долгого анализа у меня сработало вот что.

  1. Скопируйте отпечаток большого пальца из сертификата в блокнот.
  2. Скопируйте отпечаток большого пальца из блокнота в Visual Studio.
  3. Запустите Visual Studio от имени администратора.

Это работает как шарм.

пальцы10
источник