Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Error when upgrading Azure.Extensions.AspNetCore.DataProtection.Keys #54253

Closed
1 task done
khellang opened this issue Feb 28, 2024 · 1 comment · Fixed by #54256
Closed
1 task done

Error when upgrading Azure.Extensions.AspNetCore.DataProtection.Keys #54253

khellang opened this issue Feb 28, 2024 · 1 comment · Fixed by #54256
Assignees
Labels
area-dataprotection Includes: DataProtection

Comments

@khellang
Copy link
Member

Is there an existing issue for this?

  • I have searched the existing issues

Describe the bug

When upgrading between different versions of Azure.Extensions.AspNetCore.DataProtection.Keys, we're seeing the following error:

Could not load file or assembly 'Azure.Extensions.AspNetCore.DataProtection.Keys, Version=1.2.2.0, Culture=neutral, PublicKeyToken=92742159e12e44c8' or one of its dependencies. The located assembly's manifest definition does not match the assembly reference. (Exception from HRESULT: 0x80131040)

I first thought this was an issue with Azure.Extensions.AspNetCore.DataProtection.Keys itself (see Azure/azure-sdk-for-net#42223), but ended up tracking down the bug to this PR.

Expected Behavior

Being able to upgrade to newer versions of Azure.Extensions.AspNetCore.DataProtection.Keys, without having to manually patch key entries in our database.

Steps To Reproduce

  • Install Azure.Extensions.AspNetCore.DataProtection.Keys v1.2.2
  • Set up DataProtection with ProtectKeysWithAzureKeyVault
  • Protect something so key is stored
  • Update to Azure.Extensions.AspNetCore.DataProtection.Keys v1.2.3
  • Attempt to unprotect the same thing that was just protected with the previous version

Exceptions (if any)

at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMarkHandle stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName, ObjectHandleOnStack type)
   at System.RuntimeTypeHandle.GetTypeByName(String name, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark, IntPtr pPrivHostBinder, Boolean loadTypeFromPartialName)
   at System.RuntimeType.GetType(String typeName, Boolean throwOnError, Boolean ignoreCase, Boolean reflectionOnly, StackCrawlMark& stackMark)
   at System.Type.GetType(String typeName, Boolean throwOnError)
   at Microsoft.AspNetCore.DataProtection.XmlEncryption.XmlEncryptionExtensions.CreateDecryptor(IActivator activator, String decryptorTypeName)
   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.<GetLazyDescriptorDelegate>g__GetLazyDescriptorDelegate|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.get_Descriptor()
   at Microsoft.AspNetCore.DataProtection.AuthenticatedEncryption.CngGcmAuthenticatedEncryptorFactory.CreateEncryptorInstance(IKey key)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyBase.CreateEncryptor()
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRing.KeyHolder.GetEncryptorInstance(Boolean& isRevoked)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRing.GetAuthenticatedEncryptorByKeyId(Guid keyId, Boolean& isRevoked)
   at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status)

.NET Version

.NET Framework 4.8.4645.0

Anything else?

The code in XmlEncryptionExtensions used to call IActivator.CreateInstance directly. Since the KeyVault extensions register their own IActivator, which handles their own forwarding, it worked across versions, but after the change in #41650, it tries to call Type.GetType first, which results in the mentioned System.IO.FileLoadException.

I think the fix here is probably just to catch the exception from Type.GetType and fall back to calling activator.CreateInstance<IXmlDecryptor>(decryptorTypeName). I can send a PR if that sounds reasonable.

// @JamesNK @amcasey

@amcasey
Copy link
Member

amcasey commented Feb 28, 2024

@khellang I just want to say thanks for filing such a high quality bug

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area-dataprotection Includes: DataProtection
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants