CryptographicException: The key ... was not found in the key ring (IIS)

I talked with a user the other day experiencing this error on a website hosted on IIS: System.Security.Cryptography.CryptographicException: The key {...} was not found in the key ring. It's a common error that can happen when hosting .NET code on IIS, why I want to put a few words on the error and how to fix it. The error indicates that the application is trying to use a key that does not exist in the key ring. Stay tuned for possible causes and how to resolve the error.

Before digging into the fixes, let's quickly look at the error and what it means when caused by a website hosted on IIS. If hosting on another web server like IIS Express or Kestrel when running locally, you probably don't see this error before hitting production.

The CryptographicException indicates that an error happens while running a cryptographic operation. There can be multiple causes for this error when writing cryptographic code manually and the exception message typically tells you what's wrong. For errors thrown by a website on IIS, the following sections list some things to try.

Incorrect Key Location

One of the most common causes of this error is that the key is not located in the correct location. Try looking at the stack trace part of the exception to figure out which component that generated the cryptographic operation. By default, IIS looks for keys in the machine key store, which is located in the C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys folder. If no configuration is provided for the operation, make sure that this folder exists and that it contains the key files you expect.

For websites running on ASP.NET Core, cryptography is used for a feature like Data Protection. With this feature, the key location is configured through the startup code like this:

builder.Services.AddDataProtection()
    // ...
    .ProtectKeysWithAzureKeyVault(
        new Uri("..."),
        new DefaultAzureCredential());

Make sure that the URI provided for whatever method used to help locate the key exists and that it can be requested using the provided credentials.

Incorrect Key Permissions

In the case where a key was actually found but lacks the correct permissions, the error can be thrown as well. By default, the key should have read and execute permissions for the IIS_IUSRS group. In case it doesn't, IIS will not be able to access it.

Key permissions can be inspected in a couple of ways. One is a bit of C# code:

string keyFilePath = @"C:\ProgramData\Microsoft\Crypto\RSA\MachineKeys\yourkey.key";
var fileSecurity = File.GetAccessControl(keyFilePath);
var rules = fileSecurity.GetAccessRules(true, true, typeof(NTAccount));
foreach (var rule in rules)
{
    Console.WriteLine("Identity: " + rule.IdentityReference);
    Console.WriteLine("Access: " + rule.AccessControlType);
    Console.WriteLine("Rights: " + rule.FileSystemRights);
}

I'm not a big PowerShell expert, but I'm sure a similar output can be generated from PowerShell.

Incorrect Application Pool Identity

The application pool identity for the website might not have permission to access the key. We already went through permission problems in the previous section. But what if the website is running with the wrong app pool identity? To quickly test this, open the IIS Manager, locate your website in the Connections window and click Basic Settings... Here you will be able to see the configured app pool and change it if misconfigured:

Incorrect Key Format

Another possible cause is that the key is not in the correct format. IIS uses the RSA key format and won't be able to use different formats. Debugging this requires an actual key found in the location expected by IIS.

To check if a key is in fact in RSA format, you can use the ssh-keygen tool:

In this case, I'm outputting details about my id_rsa key to inspect the type. Notice the (RSA) at the end of the output.