Reputation: 31
on the way to use the Windows Key Store for OpenSSL and Client Certificates I found this article: https://anexdev.blogspot.com/2018/10/how-to-send-client-certificate-with.html
Apart from some typos in the given code, the example inspired me to write some code that made use of the ENGINE CAPI for key usage. To summarize, after finding the certificate in the store ( L"MY"
) I was able to issue ENGINE_load_private_key() that finally returned a new allocated EVP_PKEY structure.
However I was unable to use this key in combination with the certificate. After some investigation I figured out, that the structure only contains a version, a modulus and a pubkey component:
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
}
So I took a look into the code of the OpenSSL implementation. And in fact, ENGINE_load_private_key() is at least in case of the CAPI engine obviousle not intended to export the private key.
In openssl/crypto/engine/eng_pkey.c the function calls the member load_privkey()
of the selected engine. In case of CAPI, the implementation is defined in openssl/engines/e_capi.c. This function calls capi_find_key()
to find the key and capi_get_pkey()
to receive it.
A closer look into the definition of static EVP_PKEY *capi_get_pkey(ENGINE *eng, CAPI_KEY *key)
seem to explain the root of my problem:
if (!CryptExportKey(key->key, 0, PUBLICKEYBLOB, 0, pubkey, &len)) {
CAPIerr(CAPI_F_CAPI_GET_PKEY, CAPI_R_PUBKEY_EXPORT_ERROR);
capi_addlasterror();
goto err;
}
Why does capi_get_pkey()
call CryptExportKey()
with PUBLICKEYBLOB
? Is this intentionally to circumvent any rules of Windows and extract a private key as a result of known Windows bug or is ENGINE_load_private_key()
defacto broken in combination with CAPI?
Does anyone know a replacement for ENGINE_load_private_key()
for my application?
Upvotes: 2
Views: 1233
Reputation: 193
I hit the same wall and did a small research. It looks like it is not a bug but a way how Microsoft CryptoAPI works. In case of non-exportable keys, it is impossible to export key from windows certificates store with CryptExportKey and PRIVATEKEYBLOB. So you can just get a reference, an id to a key pair, which later you can use to make all cryptographic operations via CryptoAPI (cannot export a real key). So openssl CAPI engine has followed this path, they get just a required key pair id, and then pump it into CryptoAPI to perform required actions.
I assume this is also a reason that capi_rsa_priv_enc is not implemented (CryptEncrypt always chooses public key from provided key pair id) and because there is no real exported private key (just key pair id), they cound not even perform the encryption with private key even beside CryptoAPI. But it is just my guess.
Upvotes: 3