На пути к использованию хранилища ключей Windows для OpenSSL и клиентских сертификатов я нашел эту статью: https://anexdev.blogspot.com/2018/10/how-to-send-client-certificate-with.html
Помимо некоторых опечаток в данном коде, этот пример вдохновил меня на написание кода, использующего ENGINE CAPI для использования ключей. Подводя итог, найдя сертификат в хранилище ( L"MY"
), я смог выполнить ENGINE_load_private_key(), который, наконец, вернул новую выделенную структуру EVP_PKEY.
Однако мне не удалось использовать этот ключ в сочетании с сертификатом. После некоторого исследования я выяснил, что структура содержит только версию, модуль и компонент публичного ключа:
RSAPrivateKey ::= SEQUENCE {
version Version,
modulus INTEGER, -- n
publicExponent INTEGER, -- e
privateExponent INTEGER, -- d (this field and everything following is mising)
prime1 INTEGER, -- p
prime2 INTEGER, -- q
exponent1 INTEGER, -- d mod (p-1)
exponent2 INTEGER, -- d mod (q-1)
coefficient INTEGER, -- (inverse of q) mod p
otherPrimeInfos OtherPrimeInfos OPTIONAL
}
Поэтому я изучил код реализации OpenSSL. И на самом деле, ENGINE_load_private_key(), по крайней мере, в случае механизма CAPI, очевидно, не предназначен для экспорта закрытого ключа.
В openssl/crypto/engine/eng_pkey.c функция вызывает член load_privkey()
выбранного движка. В случае CAPI реализация определяется в openssl/engines/ e_capi.c. Эта функция вызывает capi_find_key()
для поиска ключа и capi_get_pkey()
для его получения.
Более пристальный взгляд на определение static EVP_PKEY *capi_get_pkey(ENGINE *eng, CAPI_KEY *key)
, кажется, объясняет корень моей проблемы:
if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, pubkey, &len)) {
CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_ERROR);
capi_addlasterror();
goto err;
}
Почему capi_get_pkey()
звонит CryptExportKey()
с PUBLICKEYBLOB
? Это делается намеренно, чтобы обойти какие-либо правила Windows и извлечь закрытый ключ в результате известной ошибки Windows, или ENGINE_load_private_key()
де-факто не работает в сочетании с CAPI?
Кто-нибудь знает замену ENGINE_load_private_key()
для моего приложения?