diff --git a/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/AssemblyIdentityTests.cs b/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/AssemblyIdentityTests.cs index 3217b8a57f5c1fcec3f0695c0b90fdac977df6dd..f7231b8786e54e598df78c143fb21a59fee83d26 100644 --- a/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/AssemblyIdentityTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/AssemblyIdentityTests.cs @@ -24,8 +24,7 @@ public void Equality() var id4 = new AssemblyIdentity("Foo", new Version(1, 0, 1, 0), "", RoPublicKeyToken1, hasPublicKey: false, isRetargetable: false); var id5 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "en-US", RoPublicKeyToken1, hasPublicKey: false, isRetargetable: false); var id6 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", default(ImmutableArray), hasPublicKey: false, isRetargetable: false); - var id7 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", RoPublicKeyToken1, hasPublicKey: true, isRetargetable: false); - var id8 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", RoPublicKey1, hasPublicKey: true, isRetargetable: true); + var id7 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", RoPublicKey1, hasPublicKey: true, isRetargetable: true); var win1 = new AssemblyIdentity("Foo", new Version(1, 0, 0, 0), "", RoPublicKey1, hasPublicKey: true, isRetargetable: false, contentType: AssemblyContentType.WindowsRuntime); var win2 = new AssemblyIdentity("Bar", new Version(1, 0, 0, 0), "", RoPublicKey1, hasPublicKey: true, isRetargetable: false, contentType: AssemblyContentType.WindowsRuntime); @@ -44,7 +43,6 @@ public void Equality() Assert.False(id1.Equals(id5)); Assert.False(id1.Equals(id6)); Assert.False(id1.Equals(id7)); - Assert.False(id1.Equals(id8)); Assert.Equal((object)id1, id1); Assert.NotNull(id1); @@ -233,24 +231,6 @@ public void MetadataConstructor() AssertEx.Equal(PublicKeyToken1, id.PublicKeyToken); Assert.Equal(AssemblyContentType.Default, id.ContentType); - // incorrect size of the key token: - id = new AssemblyIdentity("Foo", new Version(1, 2, 3, 4), null, RoPublicKey1, hasPublicKey: false, isRetargetable: false, contentType: AssemblyContentType.Default, noThrow: true); - Assert.Equal(AssemblyNameFlags.PublicKey, id.Flags); - Assert.Equal("", id.CultureName); - Assert.Equal(true, id.HasPublicKey); - AssertEx.Equal(PublicKey1, id.PublicKey); - AssertEx.Equal(PublicKeyToken1, id.PublicKeyToken); - Assert.Equal(AssemblyContentType.Default, id.ContentType); - - // missing key: - id = new AssemblyIdentity("Foo", new Version(1, 2, 3, 4), null, ImmutableArray.Create(), hasPublicKey: true, isRetargetable: false, contentType: AssemblyContentType.Default, noThrow: true); - Assert.Equal(AssemblyNameFlags.None, id.Flags); - Assert.Equal("", id.CultureName); - Assert.Equal(false, id.HasPublicKey); - Assert.Equal(0, id.PublicKey.Length); - Assert.Equal(0, id.PublicKeyToken.Length); - Assert.Equal(AssemblyContentType.Default, id.ContentType); - // invalid content type: id = new AssemblyIdentity("Foo", new Version(1, 2, 3, 4), null, ImmutableArray.Create(), hasPublicKey: false, isRetargetable: false, contentType: (AssemblyContentType)2, noThrow: true); Assert.Equal(AssemblyNameFlags.None, id.Flags); @@ -277,15 +257,6 @@ public void MetadataConstructor() Assert.Equal("blah,", id.CultureName); id = new AssemblyIdentity("Foo", new Version(1, 2, 3, 4), "*", ImmutableArray.Create(), hasPublicKey: false, isRetargetable: false, contentType: AssemblyContentType.Default, noThrow: true); Assert.Equal("*", id.CultureName); - - // public key is default (mimics PEModule.CreateAssemblyIdentityOrThrow in case where "publicKey.IsNil") - id = new AssemblyIdentity("Foo", new Version(1, 2, 3, 4), null, default(ImmutableArray), hasPublicKey: true, isRetargetable: false, contentType: AssemblyContentType.Default, noThrow: true); - Assert.Equal(AssemblyNameFlags.None, id.Flags); - Assert.Equal("", id.CultureName); - Assert.Equal(false, id.HasPublicKey); - Assert.Equal(0, id.PublicKey.Length); - Assert.Equal(0, id.PublicKeyToken.Length); - Assert.Equal(AssemblyContentType.Default, id.ContentType); } [Fact] diff --git a/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataReferenceTests.cs b/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataReferenceTests.cs index a81e44e24f93844969b4fb92882c589219a61845..81a21aea19a07ae43f50cef6bda1335962f4b519 100644 --- a/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataReferenceTests.cs +++ b/src/Compilers/Core/CodeAnalysisTest/MetadataReferences/MetadataReferenceTests.cs @@ -471,5 +471,14 @@ public void DocCommentProvider() var summary = list.GetDocumentationCommentXml(); Assert.Equal("T:System.Collections.ArrayList", summary); } + + [Fact] + public void InvalidPublicKey() + { + var r = MetadataReference.CreateFromStream(new MemoryStream(TestResources.SymbolsTests.Metadata.InvalidPublicKey, writable: false)); + Assert.Equal(CodeAnalysisResources.InMemoryAssembly, r.Display); + + Assert.Throws(((AssemblyMetadata)r.GetMetadata()).GetAssembly); + } } } diff --git a/src/Compilers/Core/Portable/CodeAnalysisResources.Designer.cs b/src/Compilers/Core/Portable/CodeAnalysisResources.Designer.cs index 223a30aad43c409f916016d77448d7221fe7820c..0bf3a575c984d76a9ac03dbadd3bae0acc3807d1 100644 --- a/src/Compilers/Core/Portable/CodeAnalysisResources.Designer.cs +++ b/src/Compilers/Core/Portable/CodeAnalysisResources.Designer.cs @@ -969,5 +969,23 @@ internal class CodeAnalysisResources { return ResourceManager.GetString("XmlReferencesNotSupported", resourceCulture); } } + + /// + /// Looks up a localized string similar to Invalid public key.. + /// + internal static string InvalidPublicKey { + get { + return ResourceManager.GetString("InvalidPublicKey", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Invalid public key token.. + /// + internal static string InvalidPublicKeyToken { + get { + return ResourceManager.GetString("InvalidPublicKeyToken", resourceCulture); + } + } } } diff --git a/src/Compilers/Core/Portable/CodeAnalysisResources.resx b/src/Compilers/Core/Portable/CodeAnalysisResources.resx index a114ec68024c0ee73fd1d29b74f66dfb3ef77861..89d00f228afcc6039db83bd710ddbc8ecf4ac5b0 100644 --- a/src/Compilers/Core/Portable/CodeAnalysisResources.resx +++ b/src/Compilers/Core/Portable/CodeAnalysisResources.resx @@ -420,4 +420,10 @@ The item specified is not the element of a list. - \ No newline at end of file + + Invalid public key. + + + Invalid public key token. + + diff --git a/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs b/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs index 9873eeb74a4f73e014fd4824e6054518b2d51a78..b566f14d26f020896430c6286ebc1e3e62c29ecc 100644 --- a/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs +++ b/src/Compilers/Core/Portable/MetadataReader/MetadataHelpers.cs @@ -897,5 +897,139 @@ internal static bool SplitNameEqualsFullyQualifiedName(string namespaceName, str fullyQualified.StartsWith(namespaceName, StringComparison.Ordinal) && fullyQualified.EndsWith(typeName, StringComparison.Ordinal); } + + internal static bool IsValidPublicKey(ImmutableArray bytes) + { + return PublicKeyDecoder.TryDecode(bytes); + } + + private static class PublicKeyDecoder + { + private enum AlgorithmClass + { + Signature = 1, + Hash = 4, + } + + private enum AlgorithmSubId + { + Sha1Hash = 4, + MacHash = 5, + RipeMdHash = 6, + RipeMd160Hash = 7, + Ssl3ShaMD5Hash = 8, + HmacHash = 9, + Tls1PrfHash = 10, + HashReplacOwfHash = 11, + Sha256Hash = 12, + Sha384Hash = 13, + Sha512Hash = 14, + } + + private struct AlgorithmId + { + // From wincrypt.h + private const int AlgorithmClassOffset = 13; + private const int AlgorithmClassMask = 0x7; + private const int AlgorithmSubIdOffset = 0; + private const int AlgorithmSubIdMask = 0x1ff; + + private readonly uint flags; + + public bool IsSet + { + get { return flags != 0; } + } + + public AlgorithmClass Class + { + get { return (AlgorithmClass)((flags >> AlgorithmClassOffset) & AlgorithmClassMask); } + } + + public AlgorithmSubId SubId + { + get { return (AlgorithmSubId)((flags >> AlgorithmSubIdOffset) & AlgorithmSubIdMask); } + } + + public AlgorithmId(uint flags) + { + this.flags = flags; + } + } + + // From ECMAKey.h + private static readonly ImmutableArray ecmaKey = ImmutableArray.Create(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0 }); + + // From strongname.h + // + // The public key blob has the following format as a little-endian packed C struct: + // + // struct + // { + // uint32_t SigAlgId; // Signature algorithm ID + // uint32_t HashAlgId; // Hash algorithm ID + // uint32_t PublicKeySize; // Size of public key data in bytes, not including the header + // uint8_t PublicKey[0]; // PublicKeySize bytes of publc key data + // } + // + // The offsets of each relevant field are recorded below. + private const int SigAlgIdOffset = 0; + private const int HashAlgIdOffset = SigAlgIdOffset + sizeof(uint); + private const int PublicKeySizeOffset = HashAlgIdOffset + sizeof(uint); + private const int PublicKeyDataOffset = PublicKeySizeOffset + sizeof(uint); + private const int HeaderSize = PublicKeyDataOffset; + + // From wincrypt.h + private const byte PublicKeyBlob = 0x06; + + private static uint ToUInt32(ImmutableArray bytes, int offset) + { + Debug.Assert((bytes.Length - offset) > sizeof(int)); + return (uint)((int)bytes[offset] | ((int)bytes[offset + 1] << 8) | ((int)bytes[offset + 2] << 16) | ((int)bytes[offset + 3] << 24)); + } + + // From StrongNameInternal.cpp + public static bool TryDecode(ImmutableArray bytes) + { + // The number of public key bytes must be at least large enough for the header and one byte of data. + if (bytes.IsDefault || bytes.Length < HeaderSize + 1) + { + return false; + } + + // The number of public key bytes must be the same as the size of the header plus the size of the public key data. + var dataSize = ToUInt32(bytes, PublicKeySizeOffset); + if (bytes.Length != HeaderSize + dataSize) + { + return false; + } + + // Check for the ECMA key, which does not obey the invariants checked below. + if (ByteSequenceComparer.Equals(bytes, ecmaKey)) + { + return true; + } + + var signatureAlgorithmId = new AlgorithmId(ToUInt32(bytes, 0)); + if (signatureAlgorithmId.IsSet && signatureAlgorithmId.Class != AlgorithmClass.Signature) + { + return false; + } + + var hashAlgorithmId = new AlgorithmId(ToUInt32(bytes, 4)); + if (hashAlgorithmId.IsSet && (hashAlgorithmId.Class != AlgorithmClass.Hash || hashAlgorithmId.SubId < AlgorithmSubId.Sha1Hash)) + { + return false; + } + + if (bytes[PublicKeyDataOffset] != PublicKeyBlob) + { + return false; + } + + return true; + } + } + } } diff --git a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs index b5a4a98b148af82108c66dad77b6f568665715f4..561a7c4498b4fc6a53a660fac2b51dfd0882e882 100644 --- a/src/Compilers/Core/Portable/MetadataReader/PEModule.cs +++ b/src/Compilers/Core/Portable/MetadataReader/PEModule.cs @@ -389,7 +389,8 @@ private static ImmutableArray GetReferencedAssembliesOrThrow(M reference.Flags, reference.PublicKeyOrToken, reference.Name, - reference.Culture)); + reference.Culture, + isReference: true)); } return result.ToImmutable(); @@ -453,7 +454,8 @@ internal AssemblyIdentity ReadAssemblyIdentityOrThrow() assemblyDef.Flags, assemblyDef.PublicKey, assemblyDef.Name, - assemblyDef.Culture); + assemblyDef.Culture, + isReference: false); } /// An exception from metadata reader. @@ -463,7 +465,8 @@ internal AssemblyIdentity ReadAssemblyIdentityOrThrow() AssemblyFlags flags, BlobHandle publicKey, StringHandle name, - StringHandle culture) + StringHandle culture, + bool isReference) { string nameStr = reader.GetString(name); if (!MetadataHelpers.IsValidMetadataIdentifier(nameStr)) @@ -477,12 +480,35 @@ internal AssemblyIdentity ReadAssemblyIdentityOrThrow() throw new BadImageFormatException(string.Format(CodeAnalysisResources.InvalidCultureName, cultureName)); } + var hasPublicKey = (flags & AssemblyFlags.PublicKey) != 0; + var publicKeyOrToken = !publicKey.IsNil ? reader.GetBlobBytes(publicKey).AsImmutableOrNull() : default(ImmutableArray); + if (hasPublicKey) + { + if (!MetadataHelpers.IsValidPublicKey(publicKeyOrToken)) + { + throw new BadImageFormatException(CodeAnalysisResources.InvalidPublicKey); + } + } + else if (isReference) + { + if (!publicKeyOrToken.IsDefaultOrEmpty && publicKeyOrToken.Length != AssemblyIdentity.PublicKeyTokenSize) + { + throw new BadImageFormatException(CodeAnalysisResources.InvalidPublicKeyToken); + } + } + else + { + // Assembly definitions do not contain public key tokens, but they may contain public key + // data without being marked as strong name signed (e.g. delay-signed assemblies). + publicKeyOrToken = default(ImmutableArray); + } + return new AssemblyIdentity( name: nameStr, version: version, cultureName: cultureName, - publicKeyOrToken: (!publicKey.IsNil) ? reader.GetBlobBytes(publicKey).AsImmutableOrNull() : default(ImmutableArray), - hasPublicKey: (flags & AssemblyFlags.PublicKey) != 0, + publicKeyOrToken: publicKeyOrToken, + hasPublicKey: hasPublicKey, isRetargetable: (flags & AssemblyFlags.Retargetable) != 0, contentType: (AssemblyContentType)((int)(flags & AssemblyFlags.ContentTypeMask) >> 9), noThrow: true); diff --git a/src/Compilers/Core/Portable/MetadataReference/AssemblyIdentity.DisplayName.cs b/src/Compilers/Core/Portable/MetadataReference/AssemblyIdentity.DisplayName.cs index 7745d41777fae05d998aa0c135ae875072b4559e..e651af395527a814cfbd6d5398756fd07a0553d0 100644 --- a/src/Compilers/Core/Portable/MetadataReference/AssemblyIdentity.DisplayName.cs +++ b/src/Compilers/Core/Portable/MetadataReference/AssemblyIdentity.DisplayName.cs @@ -5,7 +5,6 @@ using System.Diagnostics; using System.Linq; using System.Reflection; -using System.Runtime.InteropServices; using System.Text; using Microsoft.CodeAnalysis.Collections; using Roslyn.Utilities; @@ -611,152 +610,25 @@ internal static bool TryParseVersion(string str, out ulong result, out AssemblyI } } - private static class PublicKeyDecoder - { - private enum AlgorithmClass - { - Signature = 1, - Hash = 4, - } - - private enum AlgorithmSubId - { - Sha1Hash = 4, - MacHash = 5, - RipeMdHash = 6, - RipeMd160Hash = 7, - Ssl3ShaMD5Hash = 8, - HmacHash = 9, - Tls1PrfHash = 10, - HashReplacOwfHash = 11, - Sha256Hash = 12, - Sha384Hash = 13, - Sha512Hash = 14, - } - - private struct AlgorithmId - { - // From wincrypt.h - private const int AlgorithmClassOffset = 13; - private const int AlgorithmClassMask = 0x7; - private const int AlgorithmSubIdOffset = 0; - private const int AlgorithmSubIdMask = 0x1ff; - - private readonly uint flags; - - public bool IsSet - { - get { return flags != 0; } - } - - public AlgorithmClass Class - { - get { return (AlgorithmClass)((flags >> AlgorithmClassOffset) & AlgorithmClassMask); } - } - - public AlgorithmSubId SubId - { - get { return (AlgorithmSubId)((flags >> AlgorithmSubIdOffset) & AlgorithmSubIdMask); } - } - - public AlgorithmId(uint flags) - { - this.flags = flags; - } - } - - // From ECMAKey.h - private static readonly ImmutableArray ecmaKey = ImmutableArray.Create(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 4, 0, 0, 0, 0, 0, 0, 0 }); - - // From strongname.h - [StructLayout(LayoutKind.Sequential, Pack = 0)] - private unsafe struct PublicKeyHeader - { - public const int SigAlgIdOffset = 0; - public const int HashAlgIdOffset = SigAlgIdOffset + sizeof(uint); - public const int PublicKeySizeOffset = HashAlgIdOffset + sizeof(uint); - public const int PublicKeyDataOffset = PublicKeySizeOffset + sizeof(uint); - public const int Size = PublicKeyDataOffset; - - uint SigAlgId; - uint HashAlgId; - uint PublicKeySize; - } - - // From wincrypt.h - private const byte PublicKeyBlob = 0x06; - - // From StrongNameInternal.cpp - public static bool TryDecode(byte[] bytes, out ImmutableArray key) - { - // The number of public key bytes must be at least large enough for the header and one byte of data. - if (bytes.Length < PublicKeyHeader.Size + 1) - { - key = default(ImmutableArray); - return false; - } - - // The number of public key bytes must be the same as the size of the header plus the size of the public key data. - var dataSize = (uint)BitConverter.ToInt32(bytes, PublicKeyHeader.PublicKeySizeOffset); - if (bytes.Length != PublicKeyHeader.Size + dataSize) - { - key = default(ImmutableArray); - return false; - } - - // Check for ECMA key - if (bytes.Length == ecmaKey.Length) - { - for (int i = 0; i < bytes.Length; i++) - { - if (bytes[i] != ecmaKey[i]) - { - goto notEcmaKey; - } - } - - key = ecmaKey; - return true; - } - - notEcmaKey: - var signatureAlgorithmId = new AlgorithmId((uint)BitConverter.ToInt32(bytes, 0)); - if (signatureAlgorithmId.IsSet && signatureAlgorithmId.Class != AlgorithmClass.Signature) - { - key = default(ImmutableArray); - return false; - } - - var hashAlgorithmId = new AlgorithmId((uint)BitConverter.ToInt32(bytes, 4)); - if (hashAlgorithmId.IsSet && (hashAlgorithmId.Class != AlgorithmClass.Hash || hashAlgorithmId.SubId < AlgorithmSubId.Sha1Hash)) - { - key = default(ImmutableArray); - return false; - } - - if (bytes[PublicKeyHeader.PublicKeyDataOffset] != PublicKeyBlob) - { - key = default(ImmutableArray); - return false; - } - - key = bytes.AsImmutable(); - return true; - } - } - const int MaxPublicKeyBytes = 2048; private static bool TryParsePublicKey(string value, out ImmutableArray key) { - byte[] result; + ImmutableArray result; if (value.Length > (MaxPublicKeyBytes * 2) || !TryParseHexBytes(value, out result)) { key = default(ImmutableArray); return false; } - return PublicKeyDecoder.TryDecode(result, out key); + if (!MetadataHelpers.IsValidPublicKey(result)) + { + key = default(ImmutableArray); + return false; + } + + key = result; + return true; } const int PublicKeyTokenBytes = 8; @@ -770,41 +642,43 @@ private static bool TryParsePublicKeyToken(string value, out ImmutableArray result; if (value.Length != (PublicKeyTokenBytes * 2) || !TryParseHexBytes(value, out result)) { token = default(ImmutableArray); return false; } - token = result.AsImmutable(); + token = result; return true; } - private static bool TryParseHexBytes(string value, out byte[] result) + private static bool TryParseHexBytes(string value, out ImmutableArray result) { if (value.Length == 0 || (value.Length % 2) != 0) { - result = null; + result = default(ImmutableArray); return false; } - var bytes = new byte[value.Length / 2]; - for (int i = 0; i < bytes.Length; i++) + var length = value.Length / 2; + var bytes = ArrayBuilder.GetInstance(length); + for (int i = 0; i < length; i++) { int hi = HexValue(value[i * 2]); int lo = HexValue(value[i * 2 + 1]); if (hi < 0 || lo < 0) { - result = null; + result = default(ImmutableArray); + bytes.Free(); return false; } - bytes[i] = (byte)((hi << 4) | lo); + bytes.Add((byte)((hi << 4) | lo)); } - result = bytes; + result = bytes.ToImmutableAndFree(); return true; } diff --git a/src/Compilers/Core/Portable/MetadataReference/AssemblyIdentity.cs b/src/Compilers/Core/Portable/MetadataReference/AssemblyIdentity.cs index fff89a9ac454b586cc460186eea6a05f21d028a2..f812a459af6f590379b5007051ec7810a37d4756 100644 --- a/src/Compilers/Core/Portable/MetadataReference/AssemblyIdentity.cs +++ b/src/Compilers/Core/Portable/MetadataReference/AssemblyIdentity.cs @@ -48,7 +48,7 @@ public sealed partial class AssemblyIdentity : IEquatable // cached hash code private int lazyHashCode; - private const int PublicKeyTokenSize = 8; + internal const int PublicKeyTokenSize = 8; /// /// Constructs an from its constituent parts. @@ -98,9 +98,9 @@ public sealed partial class AssemblyIdentity : IEquatable if (hasPublicKey) { - if (publicKeyOrToken.IsDefaultOrEmpty) + if (!MetadataHelpers.IsValidPublicKey(publicKeyOrToken)) { - throw new ArgumentException(CodeAnalysisResources.ExpectedNonEmptyPublicKey, "publicKeyOrToken"); + throw new ArgumentException(CodeAnalysisResources.InvalidPublicKey, "publicKeyOrToken"); } } else @@ -135,7 +135,7 @@ public sealed partial class AssemblyIdentity : IEquatable Debug.Assert(IsValidName(name)); Debug.Assert(IsValid(version)); Debug.Assert(IsValidCultureName(cultureName)); - Debug.Assert((hasPublicKey && !publicKeyOrToken.IsDefaultOrEmpty) || (publicKeyOrToken.IsDefaultOrEmpty || publicKeyOrToken.Length == PublicKeyTokenSize)); + Debug.Assert((hasPublicKey && MetadataHelpers.IsValidPublicKey(publicKeyOrToken)) || (!hasPublicKey && (publicKeyOrToken.IsDefaultOrEmpty || publicKeyOrToken.Length == PublicKeyTokenSize))); this.name = name; this.version = version ?? NullVersion; @@ -145,7 +145,7 @@ public sealed partial class AssemblyIdentity : IEquatable InitializeKey(publicKeyOrToken, hasPublicKey, out this.publicKey, out this.lazyPublicKeyToken); } - // error-tolerant constructor used by metadata reader: + // constructor used by metadata reader: internal AssemblyIdentity( string name, Version version, @@ -157,32 +157,15 @@ public sealed partial class AssemblyIdentity : IEquatable bool noThrow) { Debug.Assert(!string.IsNullOrEmpty(name)); + Debug.Assert((hasPublicKey && MetadataHelpers.IsValidPublicKey(publicKeyOrToken)) || (!hasPublicKey && (publicKeyOrToken.IsDefaultOrEmpty || publicKeyOrToken.Length == PublicKeyTokenSize))); Debug.Assert(noThrow); - if (hasPublicKey) - { - if (publicKeyOrToken.IsDefaultOrEmpty) - { - // PublicKey flag but no key specified => assume the flag is wrong: - hasPublicKey = false; - } - } - else - { - if (!publicKeyOrToken.IsDefaultOrEmpty && publicKeyOrToken.Length != PublicKeyTokenSize) - { - // token specified but its size isn't correct => assume it's the full key: - hasPublicKey = true; - } - } - - InitializeKey(publicKeyOrToken, hasPublicKey, out this.publicKey, out this.lazyPublicKeyToken); - this.name = name; this.version = version ?? NullVersion; this.cultureName = cultureName ?? string.Empty; this.contentType = IsValid(contentType) ? contentType : AssemblyContentType.Default; this.isRetargetable = isRetargetable && this.contentType != AssemblyContentType.WindowsRuntime; + InitializeKey(publicKeyOrToken, hasPublicKey, out this.publicKey, out this.lazyPublicKeyToken); } static private void InitializeKey(ImmutableArray publicKeyOrToken, bool hasPublicKey, diff --git a/src/Compilers/Test/Resources/Core/SymbolsTests/Metadata/InvalidPublicKey.dll b/src/Compilers/Test/Resources/Core/SymbolsTests/Metadata/InvalidPublicKey.dll new file mode 100644 index 0000000000000000000000000000000000000000..464eaeef315a8c56fa993af99b7615457f4bb6b8 Binary files /dev/null and b/src/Compilers/Test/Resources/Core/SymbolsTests/Metadata/InvalidPublicKey.dll differ diff --git a/src/Compilers/Test/Resources/Core/SymbolsTests/Metadata/Metadata.Designer.vb b/src/Compilers/Test/Resources/Core/SymbolsTests/Metadata/Metadata.Designer.vb index cce35a6f90cd29afe3265fa2e4810f767600c00a..ecb80397a2e17cee1a7193f99f532d582d93c877 100644 --- a/src/Compilers/Test/Resources/Core/SymbolsTests/Metadata/Metadata.Designer.vb +++ b/src/Compilers/Test/Resources/Core/SymbolsTests/Metadata/Metadata.Designer.vb @@ -153,5 +153,16 @@ Namespace TestResources.SymbolsTests Return CType(obj,Byte()) End Get End Property + + ''' + ''' Looks up a localized resource of type System.Byte[]. + ''' + Public Shared ReadOnly Property InvalidPublicKey() As Byte() + Get + Dim obj As Object = ResourceManager.GetObject("InvalidPublicKey", resourceCulture) + Return CType(obj,Byte()) + End Get + End Property + End Class End Namespace diff --git a/src/Compilers/Test/Resources/Core/SymbolsTests/Metadata/Metadata.resx b/src/Compilers/Test/Resources/Core/SymbolsTests/Metadata/Metadata.resx index e960eddd8baecb2382564d53f459e13f8a5646b1..d96913920ceeb292771eaad992db7ce3a25334eb 100644 --- a/src/Compilers/Test/Resources/Core/SymbolsTests/Metadata/Metadata.resx +++ b/src/Compilers/Test/Resources/Core/SymbolsTests/Metadata/Metadata.resx @@ -147,4 +147,7 @@ MscorlibNamespacesAndTypes.bsl;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - \ No newline at end of file + + InvalidPublicKey.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + +