-
Notifications
You must be signed in to change notification settings - Fork 10.5k
Description
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.Keysv1.2.2 - Set up DataProtection with
ProtectKeysWithAzureKeyVault - Protect something so key is stored
- Update to
Azure.Extensions.AspNetCore.DataProtection.Keysv1.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.