2
votes

My question is about use case with CNG API and Microsoft providers. I don't write code sample because I ask for your help about the best way to use CNG API in my application compared to CSP API.

I built an application which use symetric keys stored using these steps:

  • enumerate certificates in "My" store using CertFindCertificateInStore
  • for each certificate found, asking for private key informations using CertGetCertificateContextProperty
  • for each private key informations found, storing provider name pwszProvName and container name pwszContainerName

Then, when a key is found, my application performs signature function using private key found using CSP API:

  • Initialize provider operation using CryptAcquireContext with pwszProvName and pwszContainerName
  • Compute signature using CSP functions: CryptCreateHash, CryptHashData and CryptSignHash

All is OK with CSP function.

Now I try signature operation using CNG API:

  • Initialize provider operation using NCryptOpenStorageProvider with pwszProvName
  • Open algorithm provider using CNG function BCryptOpenAlgorithmProvider fails with STATUS_NOT_FOUND

This error happens when the private key is stored in Microsoft Software Key Storage Provider. Reading Microsoft documentation I understand that type of provider is KSP provider, and only functions about key management. That's why it fails when I try a primitive function, I need to use a "Primitive Provider".

I found the way to use CNG provider following these setps:

  • Windows Server 2008: create a certificate template with provider requirement (on "encryption" tab). And the only one provider availabe is "Microsoft Software Key Storage Provider
  • Windows 7: user ask for key generation, the key is stored in Microsoft KSP.

So here are my questions:

  • Is it normal I can't perform primitive function with "Microsoft Software Key Storage Provider" ?

  • If I can't perform primitive functions (signature, encryption, decryption, hash) with Microsoft KSP (which is KSP provider), how can I make my private key stored and managed in a Microsoft Primitive Provider?

My trouble here, is that with CSP API, default Microsoft CSP provider performs signature (and decyrption, encryption, etc) function. But with CNG API, default provider only performs key storage management.

1

1 Answers

1
votes

For asymmetric keys, the functionality supported by a CNG Key Storage Provider is comparable to that of a Primitive Provider, apart of course from the the fact that the KSP (Key Storage Provider) allows you to persist and load keys.

In fact, the KSP API calls for doing the crypto operations look much the same as the primitive ones, except the KSP ones start with N and the primitive ones start with B.

For example:

What is missing from the KSP is symmetric functionality (including hashing), and this may be where the confusion has arisen. Compared to CAPI (CSP/Crypto API), the CNG signing functions are a bit more low-level - you hash the data separately first, and then pass that hash byteblock to NCryptSignHash (no hash object handle like in CAPI).

To re-iterate, as this is a source of confusion for people coming from CAPI, you can hash with any primitive provider, MS_PRIMITIVE_PROVIDER or a third-party provider, and then pass the result to any Key Storage Provider's NCryptSignHash, because it's just bytes of data, it doesn't matter who did the hashing. The NCRYPT_KEY_HANDLE passed to NCryptSignHash determines what KSP is used to do the signing; there is no CNG equivalent of HCRYPTHASH passed to NCryptSignHash.

So, if you want to sign with a KSP, you should hash the message to be signed first with a primitive provider (using BCryptCreateHash/BCryptHashData/BCryptFinishHash), and pass the result to NCryptSignHash.