Or maybe your haven’t seen this error message but have encountered an issue with Identity Server signing it tokens. If this is the case, I would highly recommend you stop and enable logging before you go any further, restart your application and check your logs for the error message above. Logging is key, we need to see what is going on in order to know how to fix it! Jump ahead to Enabling Logging in Identity Server V3 then come back to find out what the error is all about.

Assumptions

Now, this article assumes you have checked some of the obvious things. Run through the following list and if the answer is “Yes!” for every question then you may proceed 🙂

Have you checked that the certificate you are using actually has a private key?

Have you checked that the password you are using to access the private key is correct?

Have you checked that the account your application is running under has permissions to access to the private key?

OK, so you have answered yes to all of these questions – so it is maybe beginning to be more likely that you are falling foul of a Cng Key issue.

What is a CNG Key?

Certificates in Windows are stored using Storage Providers. Windows has two of these providers, that are not compatible. The old style “Cryptographic Service Providers” or CSP in short and the new style “Cryptography API: Next Generation” or CNG. The CNG providers have been around since Windows Vista, and although it is more secure and easier to use many facets of software are still not compatible with CNG providers. This appears to also include the .NET Framework.

A possible workaround to this may be to use CryptoAPI/CNG API directly to deal with CNG keys. But if we want an easier and pure .NET solution which understands CNG, we need to find another solution (details to follow!).

How was my PFX file generated?

In this case, I used the powershell module New-SelfSignedCertificate to generate a self-signed certificate and then exported that certificate to a PFX file via the Management Console.

Proving out the issue

So let’s investigate what’s causing the “Signing certificate has not private key or private key is not accessible” error.

To help me figure this out, I created the following test stub which I used to load a certificate (from an embedded resource in this case) and attempt to access the private key.

GoogleFoo resulted in me discovering Alejandro Magencio’s blog post on this very exception. His post describes in detail the background to what is going on underneath the covers and why we are getting this exception.

In short, the .NET Framework being used does not like CNG keys. In order access them we need to either talk directly to the CryptoAPI/CNG API or we could use the CLR Security open source library.

Adding in usage of the CLR Security library allows me to interogate the type of private key that my certificate has.

This is great, but I would prefer to not have to code my way out of this. I would rather have a certificate in a format that can be readily accessed by my .NET code. So, let’s convert my certificate private key from CNG to RSA.

Converting your certificate key from CNG to RSA

Steps:

Extract your public key and full certificate chain from your PFX file

Extract the CNG private key

Convert the private key to RSA format

Merge public keys with RSA private key to a new PFX file

After changing your application to use the new PFX you just created, you should find that your issues have been resolved.

Enabling Logging in Identity Server

Identity Server v3 provides a wealth of information to developers through it’s two logging features. Development time logging provides really low level details to assist developers diagnose issues during development and testing. Production-time logging comes in the form of a number of events being raised to assist in system monitoring and fault diagnosis. The reason there are two levels of logging is that it is possible that sensitive information may be exposed through development logging and this facility should therefor always be disabled when the system is in production.

Now that you have configured logging, build and rerun your application and confirm that a log file is being created. Then check the log file for error. You may now wish to return to reading about the certificate error upon which this post is based.

4 Comments

Awesome work. IdentityServer is a beast of a thing to get running. I’ve been struggling with this exact issue and your clear and concise information resolved it.

I never used to get this issue when I used makecert. It must be using the older CSP. Unfortunately makecert has been flagged as obsolete by Microsoft, so I switched over to the PowerShell New-SelfSignedCertificate script thinking it would work the same way. Obviously not.

I’m not using Identity server but had a similar problem when trying to use my self-signed certificate (created with New-SelfSignedCertificate) when I’d retrieve it from the Local machine cert store. If I loaded the cert from disk or an embedded resource it was fine, but when loading it from the cert store the PrivateKey would throw the dreaded CryptographicException: Invalid provider type specified. Converting your certificate key from CNG to RSA fixed it for me.