NCryptSignHash возвращает NTE_INVALID_PARAMETER (0x80090027)C++

Программы на C++. Форум разработчиков
Ответить
Anonymous
 NCryptSignHash возвращает NTE_INVALID_PARAMETER (0x80090027)

Сообщение Anonymous »

Я работаю со старым кодом, который подписывал данные с использованием установленного сертификата и CryptoAPI, и мне нужно перенести его на использование CNG. Я попробовал два разных подхода: один с использованием CryptAcquireCertificatePrivateKey(), а другой с использованием NCryptOpenStorageProvider() и NCryptOpenKey(). Оба подхода открывают ключ CNG, и первый вызов NCryptSignHash() правильно возвращает длину подписи как 256 байт.
Второй вызов NCryptOpenKey() для создания данных подписи всегда происходит сбой с NTE_INVALID_PARAMETER (0x80090027).
Я сформулировал проблему в этом примере:

Код: Выделить всё

#define MY_TYPE  (X509_ASN_ENCODING | PKCS_7_ASN_ENCODING)

HRESULT AcquireCertificatePrivateKey (PCCERT_CONTEXT pSignerCert, NCRYPT_PROV_HANDLE* phProvider, NCRYPT_KEY_HANDLE* phKey, DWORD dwFlags)
{
HRESULT hr;
DWORD dwSize = 0;
CRYPT_KEY_PROV_INFO* pKeyProvInfo = NULL;
NCRYPT_PROV_HANDLE hProvider = NULL;

CheckIf(NULL == pSignerCert || NULL == phKey, E_INVALIDARG);

CheckIfGetLastError(!CertGetCertificateContextProperty(pSignerCert, CERT_KEY_PROV_INFO_PROP_ID, NULL, &dwSize));

pKeyProvInfo = (CRYPT_KEY_PROV_INFO*)malloc(dwSize);
CheckAlloc(pKeyProvInfo);

CheckIfGetLastError(!CertGetCertificateContextProperty(pSignerCert, CERT_KEY_PROV_INFO_PROP_ID, pKeyProvInfo, &dwSize));

Check(NCryptOpenStorageProvider(&hProvider, pKeyProvInfo->pwszProvName, 0));
Check(NCryptOpenKey(
hProvider,
phKey,
pKeyProvInfo->pwszContainerName,
pKeyProvInfo->dwKeySpec,
dwFlags));
if(phProvider)
{
*phProvider = hProvider;
hProvider = NULL;
}

Cleanup:
if(hProvider)
NCryptFreeObject(hProvider);
free(pKeyProvInfo);
return hr;
}

INT main (INT cArgs, __in_ecount(cArgs) PCSTR* ppcszArgs)
{
HRESULT hr;
HCERTSTORE hStoreHandle = NULL;
PCCERT_CONTEXT pSignerCert = NULL;
PCWSTR pcwzSigner = L"name of my certificate";
DWORD dwKeySpec = 0, dwSigLen = 0;
BOOL fCallerFree = FALSE;
NCRYPT_PROV_HANDLE hProvider = NULL;
NCRYPT_KEY_HANDLE hKey = NULL;
BYTE bData[20], *pbSignature = NULL;

hStoreHandle = CertOpenStore(CERT_STORE_PROV_SYSTEM, 0, NULL, CERT_SYSTEM_STORE_LOCAL_MACHINE | CERT_STORE_READONLY_FLAG | CERT_STORE_OPEN_EXISTING_FLAG /*CERT_SYSTEM_STORE_CURRENT_USER*/, L"Root");
CheckIfGetLastError(NULL == hStoreHandle);

pSignerCert = CertFindCertificateInStore(hStoreHandle, MY_TYPE, 0, CERT_FIND_SUBJECT_STR, pcwzSigner, pSignerCert);
CheckIfGetLastError(NULL == pSignerCert);

/*
CheckIfGetLastError(!CryptAcquireCertificatePrivateKey(pSignerCert,
CRYPT_ACQUIRE_ONLY_NCRYPT_KEY_FLAG, NULL,
(HCRYPTPROV_OR_NCRYPT_KEY_HANDLE*)&hKey,
&dwKeySpec, &fCallerFree));
CheckIf(0 == (dwKeySpec & CERT_NCRYPT_KEY_SPEC), E_FAIL);
CheckIf(!fCallerFree, E_FAIL);
*/
Check(AcquireCertificatePrivateKey(pSignerCert, &hProvider, &hKey, NCRYPT_MACHINE_KEY_FLAG));
fCallerFree = TRUE;

// The real data is a SHA-1 hash, but this should be fine for testing
for(int i = 0; i < sizeof(bData); i++)
bData[i] = i;
Check(NCryptSignHash(hKey, NULL, bData, sizeof(bData), NULL, 0, &dwSigLen, 0));

pbSignature = (BYTE*)malloc(dwSigLen);
CheckAlloc(pbSignature);

Check(NCryptSignHash(hKey, NULL, bData, sizeof(bData), pbSignature, dwSigLen, &dwSigLen, 0));

Cleanup:
if(pbSignature)
free(pbSignature);
if(hKey && fCallerFree)
NCryptFreeObject(hKey);
if(hProvider)
NCryptFreeObject(hProvider);
if(hStoreHandle)
CertCloseStore(hStoreHandle, CERT_CLOSE_STORE_CHECK_FLAG);
return hr;
}
Когда я попробовал AcquireCertificatePrivateKey(), я подтвердил, что pKeyProvInfo->dwKeySpec содержит AT_KEYEXCHANGE, который также использовался в исходном коде. Я передаю NCRYPT_MACHINE_KEY_FLAG из-за того, как настроен сертификат, и во время тестирования я запускаю Visual Studio и Embarcadero от имени администратора.
Есть идеи?
Спасибо!


Подробнее здесь: https://stackoverflow.com/questions/787 ... 0x80090027
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C++»