Use of separated certificate and private key might be confusing without understanding how parts or CryptoAPI are related one to another. Apparently,
CryptSignMessage and friends require private key in order to create a digital signature.
It is not a problem when private key resides right in the signing certificate (such as, for example, imported with
CRYPT_SIGN_MESSAGE_PARA Parameters; ZeroMemory(&Parameters, sizeof Parameters); Parameters.cbSize = sizeof Parameters; Parameters.dwMsgEncodingType = X509_ASN_ENCODING | PKCS_7_ASN_ENCODING; Parameters.pSigningCert = CertificateContext; // <<--- Certificate with Private Key // ...
Things get more complicated when the certificate does not contain the private key. API’s error is
CRYPT_E_NO_KEY_PROPERTY which is described as follows:
*pSignParadoes not have a
CERT_KEY_PROV_INFO_PROP_ID is a property to be defined with certificate context and it expects a structure of type
CRYPT_KEY_PROV_INFO. The other one,
CERT_KEY_CONTEXT_PROP_ID takes a
Even though described as “The
CRYPT_KEY_PROV_INFO structure contains information about a key container within a cryptographic service provider (CSP).” and “The
CERT_KEY_CONTEXT structure contains data associated with a
CERT_KEY_CONTEXT_PROP_ID property.” respectively, it is not well clear to see where the key is attached exactly.
The missing part is that the private key is not something to be provided explicitly. Instead, the key is to be pre-loaded into provider and then this provider is associated with
CERT_KEY_CONTEXT structure, which goes as a property value, which in turn is added to signing certificate context, whcih finally gets used for creating a digital signature.
__E(CryptStringToBinary(sPrivateKeyBlob, (DWORD) wcslen(sPrivateKeyBlob), CRYPT_STRING_BASE64_ANY, pnData, &nDataSize, NULL, NULL)); // ... CCryptProvider Provider; __E(Provider.AcquireContext(NULL, NULL, PROV_RSA_FULL, 0)); CCryptKey Key; Key.Attach(Provider.ImportKey(pnData, nDataSize)); __E(Key); // ... CERT_KEY_CONTEXT KeyContext; ZeroMemory(&KeyContext, sizeof KeyContext); KeyContext.cbSize = sizeof KeyContext; KeyContext.hCryptProv = Provider; // <<--- Here we go, ooh KeyContext.dwKeySpec = AT_SIGNATURE; CertificateContext.SetProperty(CERT_KEY_CONTEXT_PROP_ID, &KeyContext);