0

I'm trying to create a CngKey in .NET 4.7.2 from a PEM file so I can sign an Apple auth JWT token.

It all worked fine in dev, but when I deployed to staging I was met with a "file not found error" from calling CngKey.Import(). Of course. The app is running under some IIS app pool user with no user directory structure for the OS to store keys in.

Since then I've been trying to use CngKey.Create() to import a machine-wide key, but I keep getting the following unhelpful error:

System.Security.Cryptography.CryptographicException: 'The requested operation is not supported.'

This exception was originally thrown at this call stack:
System.Security.Cryptography.NCryptNative.SetProperty(Microsoft.Win32.SafeHandles.SafeNCryptHandle, string, byte[], System.Security.Cryptography.CngPropertyOptions)
System.Security.Cryptography.CngKey.SetKeyProperties(Microsoft.Win32.SafeHandles.SafeNCryptKeyHandle, System.Security.Cryptography.CngKeyCreationParameters)
System.Security.Cryptography.CngKey.Create(System.Security.Cryptography.CngAlgorithm, string, System.Security.Cryptography.CngKeyCreationParameters)
SigningTest.Program.MachineKey() in Program.cs
SigningTest.Program.Main() in Program.cs

Here is my current code:

var keyParameters = new CngKeyCreationParameters
{
    ExportPolicy = CngExportPolicies.AllowPlaintextExport,
    KeyCreationOptions = CngKeyCreationOptions.MachineKey,
    KeyUsage = CngKeyUsages.AllUsages,
    Provider = CngProvider.MicrosoftSoftwareKeyStorageProvider,
    UIPolicy = new CngUIPolicy(CngUIProtectionLevels.None)
};

// KeyMeat is the part of the PEM file between "-----BEGIN PRIVATE KEY-----" and "-----END PRIVATE KEY-----"
var keyBytes = Convert.FromBase64String(KeyMeat); 

keyParameters.Parameters.Add(new CngProperty(
    CngKeyBlobFormat.GenericPrivateBlob.Format,
    keyBytes,
    CngPropertyOptions.None)
);

var privateKey = CngKey.Create(CngAlgorithm.ECDsaP256, "someName", keyParameters);

Note that the error occurs at CngKey.Create(), but only when keyParameters.Parameters.Add() is not commented out.

Benjineer
  • 1,530
  • 18
  • 22

1 Answers1

1

Open IIS and specify LoadUserProfile for your pool:  Alternatively you can open AppSettings in your IIS and set

WEBSITE_LOAD_USER_PROFILE = 1
Access Denied
  • 8,723
  • 4
  • 42
  • 72
  • What exactly does this do? Does it enable me to use a machine wide key? – Benjineer Mar 25 '20 at 05:34
  • @Benjineer By default cryptography tries to create key in user store and when it's set into false it can't create it and fails with this exception. And when it is true user store is available and exception goes away. https://learn.microsoft.com/en-us/dotnet/api/system.security.cryptography.x509certificates.x509keystorageflags?redirectedfrom=MSDN&view=netframework-4.8 – Access Denied Mar 25 '20 at 06:18
  • @Benjineer I updated screenshot and you can read what it does. – Access Denied Mar 25 '20 at 06:27