Skip to content
This repository was archived by the owner on Oct 17, 2018. It is now read-only.
This repository was archived by the owner on Oct 17, 2018. It is now read-only.

CryptographicException results when attempting to protect data after configuring with ProtectKeysWithCertificate  #139

@porcus

Description

@porcus

We have an Asp.NET MVC 5 app targeting DNX 4.5.1, and whenever we attempt to use the ProtectKeysWithCertificate method to configure the keys to be encrypted to a specified X509 certificate before being persisted to storage, we get a CryptographicException, with the message: Unable to retrieve the decryption key.

This is how data protection is being configured for the time being in our Startup class. (Code that I presume is irrelevant has been removed for brevity.)

        string _contentRootPath;

        public Startup(IHostingEnvironment hostingEnvironment)
        {
            _contentRootPath = hostingEnvironment.ContentRootPath;
        }

        public IServiceProvider ConfigureServices(IServiceCollection services)
        {
            var pfxFileInfo = new DirectoryInfo(_contentRootPath).EnumerateFiles("*.pfx").Single();
            var x509Cert = new X509Certificate2(File.ReadAllBytes(pfxFileInfo.FullName), "supersecretpassword");
            services.AddDataProtection()
                .SetApplicationName("hrselfservice")
                .ProtectKeysWithCertificate(x509Cert)
                .PersistKeysToFileSystem(new DirectoryInfo(_contentRootPath));
        }

For the purposes of testing, a self-signed pfx file exists at the location corresponding to the ContentRootPath defined above.

The following controller effectively allows me to reproduce the exception we are getting:

    public class DataProtectionController : Controller
    {
        private readonly IDataProtector _dataProtector;

        public DataProtectionController(IDataProtectionProvider dataProtectionProvider) 
        {
            _dataProtector = dataProtectionProvider.CreateProtector("TestDataProtection");
        }

        [HttpGet]
        public bool TestDataProtection()
        {
            var originalData = "This is only a test";
            var protectedData = _dataProtector.Protect(originalData);
            var unprotectedData = _dataProtector.Unprotect(protectedData);
            return unprotectedData == originalData;
        }
    }

When the Protect method (above) is called, a new "key" file (e.g. key-4c76c163-3842-42ae-a502-d1c92e9f5aa0.xml) is created (with encrypted data) alongside the .pfx file, and then the following exception is thrown, presumably while it's trying to use data from the newly created key file:

System.Security.Cryptography.CryptographicException: Unable to retrieve the decryption key.
   at System.Security.Cryptography.Xml.EncryptedXml.GetDecryptionKey(EncryptedData encryptedData, String symmetricAlgorithmUri)
   at System.Security.Cryptography.Xml.EncryptedXml.DecryptDocument()
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.EncryptedXmlDecryptor.Decrypt(XElement encryptedElement)
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.XmlEncryptionExtensions.DecryptElement(XElement element, IActivator activator)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.XmlKeyManager.Microsoft.AspNetCore.DataProtection.KeyManagement.Internal.IInternalXmlKeyManager.DeserializeDescriptorFromKeyElement(XElement keyElement)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.DeferredKey.<>c__DisplayClass1_0.<GetLazyEncryptorDelegate>b__0()
   at System.Lazy`1.CreateValue()
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
   at System.Lazy`1.get_Value()
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyBase.CreateEncryptorInstance()
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRing.KeyHolder.GetEncryptorInstance(Boolean& isRevoked)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRing.get_DefaultAuthenticatedEncryptor()
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Protect(Byte[] plaintext)
   at Microsoft.AspNetCore.DataProtection.DataProtectionExtensions.Protect(IDataProtector protector, String plaintext)

According to the documentation, I believe we're using the API correctly, but perhaps we're missing something about how the X509 certificate is supposed to be set up for decryption of key data. Can you help confirm that we're using the API correctly?

It's worth noting that if we comment out the .ProtectKeysWithCertificate(x509Cert) line in the above example, the key file is created (without the encrypted key value, of course), and the Protect and Unprotect methods of IDataProtector work without throwing any exceptions.

And BTW, we're using version "1.0.0-rc2-20254" of Microsoft.AspNetCore.DataProtection.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions