Как получить хранилище сертификатов со смарт-карты (USB Token) с помощью CNG?

Я использую функцию CryptAcquireContext API Crypto ( https://docs.microsoft.com/en-us/windows/desktop/api/Wincrypt/nf-wincrypt-cryptacquirecontexta), чтобы получить доступ к моему хранилищу сертификатов, содержащемуся в моем USB-токене, и это работает как шарм!

Однако функция CryptAcquireContext устарела, и документация Crypto API рекомендует использовать CNG для достижения тех же результатов. Вся моя проблема сейчас в том, как использовать CNG для получения контекста сертификата из моего USB-токена, и для этого я использую следующий код:

var
  Provider: NCRYPT_PROV_HANDLE;
  Reader: PByte;
  ReaderSize: DWORD;
  MemorySize: DWORD;
begin
  // Get a handle to the smartcard reader specific provider
  Status := NCryptOpenStorageProvider(@Provider
                                     ,'SafeSign Standard RSA and AES Cryptographic Service Provider'
                                     ,0); // returns ERROR_SUCCESS
  // Convert the name of the reader to a PByte
  UnicodeStringToBinary('Giesecke & Devrient GmbH StarSign CUT 0',Reader,ReaderSize);

  // Inform the name of the reader to the CNG
  Status := NCryptSetProperty(Provider
                             ,NCRYPT_READER_PROPERTY
                             ,Reader
                             ,ReaderSize
                             ,0); // returns ERROR_SUCCESS

  MemorySize := SizeOf(HCERTSTORE);

  // Try to get the size needed to a variable of type HCERTSTORE.
  // This is the first step before get the certificate store
  Status := NCryptGetProperty(Provider
                             ,NCRYPT_USER_CERTSTORE_PROPERTY
                             ,nil
                             ,0
                             ,@MemorySize
                             ,0); //Returns 0x80090029 (NTE_NOT_SUPPORTED)
end;

Как вы можете видеть NCryptGetProperty функция завершается с кодом ошибки 0x80090029 что значит NTE_NOT_SUPPORTED, Что я делаю не так? Я нашел пример (C++), выполняющий то же самое, что и я, так что, я думаю, все в порядке с моей реализацией, но...

Моя цель - перечислить все сертификаты на моей смарт-карте (на самом деле USB-токен). Я могу сделать это с помощью Crypto API, но CryptAcquireContext функция устарела, поэтому мне нужно использовать другую. Используя CAPI, я получаю хранилище сертификатов и могу перечислять его, используя диалоговое окно сертификатов по умолчанию, поэтому мне нужно, используя CNG, заставить хранилище сертификатов делать то же самое, но то, что я делаю сейчас, кажется неправильным.

Ну и несколько замечаний:

  1. Я не проверяю возвраты здесь (переменная состояния), чтобы упростить этот пример кода
  2. Функция UnicodeStringToBinary является строго правильной. Возвращенный буфер (PByte) имеет удвоенный размер исходной строки, и все байты равны "nn 00 nn 00 nn 00", поэтому переменная Reader содержит строку Unicode, как того требует свойство NCRYPT_READER_PROPERTY. Я могу опубликовать код по запросу.
  3. Моя подпись NCryptOpenStorageProvider ближе к версии Windows API, поэтому ее первый аргумент - указатель на NCRYPT_PROV_HANDLE

1 ответ

Я не работаю с delphi ... но имя читателя должно оканчиваться нулем.

Я получил это, работая в .NET с Microsoft Smart Card Key Storage Provider и звонок:

      NCrypt.NCryptSetProperty(
        provider,
        NCrypt.KeyStoragePropertyIdentifiers.NCRYPT_READER_PROPERTY,
        Encoding.Unicode.GetBytes(smartCardReader + '\0')
        );
Другие вопросы по тегам