21

I'm using the ASP.NET Core Data Protection system to encrypt data with Application A and decrypt it with Application B.

Encryption and decryption both work when run on the development machine, but when Application B is moved to the production machine it's no longer able to decrypt because the IDataProtector.Unprotect method throws an exception:

System.InvalidOperationException: The key ring does not contain a valid default protection key. The data protection system cannot create a new key because auto-generation of keys is disabled.

Here's the code I'm using to configure decryption in Application B:

sKeysPath = Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "Keys");

services.AddDataProtection()
    .SetApplicationName("My Application") // Application A sets this same name
    .PersistKeysToFileSystem(new DirectoryInfo(sKeysPath))
    .ProtectKeysWithCertificate("634D3F23...")
    //.ProtectKeysWithCertificate(x509Certificate2) // I've tried using an X509 certificate parameter but it gives the same result as providing the thumbprint of the one in the certificate store
    .DisableAutomaticKeyGeneration(); // Application A is the master key generator so do not generate keys

The production machine does contain the same Keys folder (with .pfx and .xml files) and same keys installed in the Windows certificate store.

As I understand it, by providing the certificate file to the Data Protection system, it should work on any machine and not be binded to a specific machine or Windows user. Is that assumption incorrect or is there an issue with the way I'm performing decryption?

Here are some more detailed logging messages:

2018-06-13 16:32:32.6750 | TRACE | Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector | 5 | Performing unprotect operation to key {846541...} with purposes ('My Application', 'My Purpose').

2018-06-13 16:32:32.6750 | DEBUG | Microsoft.AspNetCore.DataProtection.Repositories.FileSystemXmlRepository | 37 | Reading data from file 'C:\inetpub\wwwroot\My Website\Keys\key-846541....xml'.

2018-06-13 16:32:32.6750 | DEBUG | Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager | 18 | Found key {846541...}.

2018-06-13 16:32:32.6750 | DEBUG | Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver | 13 | Considering key {846541...} with expiration date 2038-01-18 20:54:13Z as default key.

2018-06-13 16:32:32.6750 | DEBUG | Microsoft.AspNetCore.DataProtection.TypeForwardingActivator | Forwarded activator type request from Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor, Microsoft.AspNetCore.DataProtection, Version=2.1.0.0, Culture=neutral, PublicKeyToken=adb9793829ddae60 to Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor, Microsoft.AspNetCore.DataProtection, Culture=neutral, PublicKeyToken=adb9793829ddae60

2018-06-13 16:32:32.7051 | ERROR | Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager | 24 | An exception occurred while processing the key element '<key id="846541..." version="1" />'. Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Keyset does not exist

2018-06-13 16:32:32.7051 | TRACE | Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager | 25 | An exception occurred while processing the key element '<key id="846541..." version="1" />...

2018-06-13 16:32:32.7051 | WARN | Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver | 12 | Key {846541...} is ineligible to be the default key because its CreateEncryptor method failed. Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Keyset does not exist

2018-06-13 16:32:32.7051 | DEBUG | Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver | 14 | Key {846541...} is no longer under consideration as default key because it is expired, revoked, or cannot be deciphered.

2018-06-13 16:32:32.7051 | DEBUG | Microsoft.AspNetCore.DataProtection.KeyManagement.DefaultKeyResolver | 53 | Repository contains no viable default key. Caller should generate a key with immediate activation.

2018-06-13 16:32:32.7051 | DEBUG | Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider | 57 | Policy resolution states that a new key should be added to the key ring.

2018-06-13 16:32:32.7051 | ERROR | Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider | 49 | The key ring does not contain a valid default key, and the key manager is configured with auto-generation of keys disabled.

2018-06-13 16:32:32.7051 | ERROR | Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingProvider | 48 | An error occurred while reading the key ring. System.InvalidOperationException: The key ring does not contain a valid default protection key. The data protection system cannot create a new key because auto-generation of keys is disabled.

Community
  • 1
  • 1
Coder6841
  • 1,171
  • 2
  • 13
  • 24
  • 1
    is the system time in sync between the 2 machines? Looking through the source code for [DefaultKeyResolver](https://github.com/aspnet/DataProtection/blob/dev/src/Microsoft.AspNetCore.DataProtection/KeyManagement/DefaultKeyResolver.cs) the logic looks time sensitive and could fail to find a valid defaultkey if the system clocks are not in sync – Joe Audette Jun 13 '18 at 19:17
  • Yes, they're in sync. – Coder6841 Jun 13 '18 at 19:40
  • 1
    how do both machine share the keys? Do they share a common file system drive? ie when machine A creates a new key on the ring in the xml file on disk, how does machine B know about the new keys? – Joe Audette Jun 13 '18 at 20:05
  • Currently, the Keys folder was just copied manually and the expiry date is set to the year 2038 so that active file sharing isn't needed. – Coder6841 Jun 13 '18 at 20:13
  • 1
    Have you tried setting loglevel to debug or trace, looking at the code they log when the consider and rule out a candidate for default key – Joe Audette Jun 13 '18 at 20:22
  • I've just done that and it does provide more useful info. It looks like the issue starts with this message: 2018-06-13 16:32:32.7051 | ERROR | Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager | 24 | An exception occurred while processing the key element ''. Internal.Cryptography.CryptoThrowHelper+WindowsCryptographicException: Keyset does not exist – Coder6841 Jun 13 '18 at 20:38
  • 1
    Have you tried copying the xml file to machine B again. – Joe Audette Jun 13 '18 at 20:46
  • Yes, but the result is the same. I've updated the question with the detailed logging. – Coder6841 Jun 13 '18 at 20:56
  • I had this issue today but one machine was windows and the other a container in a cluster. Turns out setting the same application name works (our keys are in azure key vault). – PmanAce May 13 '19 at 18:09

3 Answers3

11

Thanks to Joe Audette's suggestion I checked out the detailed logging and found a more specific error which pointed me to this answer which had the solution.

The problem was that the permissions for the certificate in the Windows certificate store did not have the IIS_IUSRS group set to allow read access (Right click certificate → All Tasks → Manage Private Keys…). This issue didn't appear on the development machine because there it was running under Visual Studio's user context instead.

Uwe Keim
  • 39,551
  • 56
  • 175
  • 291
Coder6841
  • 1,171
  • 2
  • 13
  • 24
  • 2
    Hello. I'm having the same problem, but the permission didn't solve it. How did you enable this detailed log? Tks – Pascal Oct 17 '18 at 14:21
  • 2
    You can pass options in the DataProtectionProvider.Create and do `options.Services.AddLogging(configure => configure.SetMinimumLevel(LogLevel.Trace).AddConsole());` – mcintyre321 Mar 05 '19 at 16:59
  • Awesome! Setting permissions helped me, too. Thanks a lot! – Uwe Keim Oct 03 '20 at 14:53
  • 1
    In another case, I got the same error message as OP and it was actually due to the fact that I (intentionally) did call [`DisableAutomaticKeyGeneration()`](https://learn.microsoft.com/en-us/dotnet/api/microsoft.aspnetcore.dataprotection.dataprotectionbuilderextensions.disableautomatickeygeneration). After removing the call, the error went away. – Uwe Keim Feb 15 '21 at 14:20
7

I had a similar issue, however it was between two different ASP.NET Core applications that were trying to share the same cookie. A minor version mismatch in Microsoft.AspNetCore.Authentication.Cookies (2.1.2 vs 2.2.0) was causing one of the applications to not be able to find the keys created by the other version.

Adding this answer here (even though it doesn't answer the above question), as the error messages match exactly, and hopefully it saves someone a few hours.

tejas
  • 607
  • 6
  • 11
3

I also had a similar problem in a 2.2 app because the certificate was self-signed. For the moment I've side-stepped it by implementing my own CertificateResolver class and ProtectKeysWithCertificate method which do not validate the certificate. The real solution for me however would be to use a valid certificate.

Just some extra info for anyone that comes across this.

Gup3rSuR4c
  • 9,145
  • 10
  • 68
  • 126