How to get a HCRYPTKEY from X.509 certificate?
<p>The certificate is obtained from a smart card via the BSI API (<code>gscBsiPkiGetCertificate</code>) and I'm trying to get the key handle to its public/private key pair to perform asymmetric crypto operations using the CryptoAPI's <code>CryptEncrypt</code> and <code>CryptDecrypt</code> functions.</p>

<h2>What I've Tried</h2>

<p><code>gscBsiPkiGetCertificate</code> returns the raw certificate data in hex encoded form and I was able to decode it and successfully call <code>CertCreateCertificateContext</code> to get the <code>CERT_CONTEXT</code> structure. With this <code>CERT_CONTEXT</code>, I had tried <code>CertGetCertificateContextProperty</code> with parameters</p>

<ul>
<li><code>CERT_KEY_CONTEXT_PROP_ID</code></li>
<li><code>CERT_KEY_PROV_HANDLE_PROP_ID</code></li>
<li><code>CERT_KEY_PROV_INFO_PROP_ID</code></li>
<li><code>CERT_HCRYPTPROV_OR_NCRYPT_KEY_HANDLE_PROP_ID</code></li>
<li><code>CERT_HCRYPTPROV_TRANSFER_PROP_ID</code></li>
</ul>

<p>However all of them returned <code>CRYPT_E_NOT_FOUND</code>. I had also tried <code>GetCryptProvFromCert</code> in hope of getting the certificate container handle, which would then allow me to get the key handle via <code>CryptGetUserKey</code>. However <code>GetCryptProvFromCert</code> failed with error <code>CRYPT_E_NO_KEY_PROPERTY</code>. </p>

<p>I am currently using pure CryptoAPI as a workaround: <code>CryptAcquireContext</code> to access card -> <code>CryptGetProvParam</code> to enumerate certificate containers -> <code>CryptAcquireContext</code> to access container -> <code>CryptGetUserKey</code> to get key handle. This is far from ideal since I've to interate through the containers to find the required certificate. <code>gscBsiPkiGetCertificate</code> allows me to specify an AID value to get the certificate directly.</p>

<p>I had also tried using <code>CryptEncryptMessage</code> which takes a <code>PCCERT_CONTEXT</code> directly and thus avoiding the need for the <code>HCRYPTKEY</code>. However, trying with algorithm identifiers <code>szOID_RSA</code>, <code>szOID_RSA_ENCRPT</code>, and <code>szOID_RSA_DH</code> all returned <code>CRYPT_E_UNKNOWN_ALGO</code>. I'm quite sure the certificate supports RSA encryption since calling <code>CryptGetKeyParam</code> with <code>KP_ALGID</code> on the key handle obtained through CryptoAPI returns me <code>CALG_RSA_KEYX</code></p>

<h2>Bonus Challenge</h2>

<p>I am using BSI API to access both data and certificate containers within the card. I would like to avoid the workaround as I want to standardise all smart card operations to use only BSI or CryptoAPI. If it's impossible for me to get the key handle using BSI API, I would then like know how to use CryptoAPI to access the data containers. <code>CryptGetProvParam</code> only enumerates the certificate containers.</p>