Checking an assembly for a strong name and a specific public key
I’m currently writing some code where I needed to check if a, dynamically, loaded assembly had a strong name and was signed using a specific (in this case, the same as the host application) public key.
At first I could only figure out how to check the public key but I was unable to find a way to check for a valid strong name as well. That is, until I dig some digging and found out that there was no managed code to perform the check. but instead I had to turn over to interop to get the job done.
It wasn’t until I found the .NET Security Blog that I found out that there was an unmanaged function called StrongNameSignatureVerificationEx, in the mscoree.dll file, which would do the trick. So I wrote a couple of extension methods for the Assembly class to help check for a strong name, a specific public key and a method which performed both calls for me.
1: using System.Linq;
2: using System.Reflection;
3: using System.Runtime.InteropServices;
4:
5: /// <summary>
6: /// Adds functionality to the <see cref="Assembly"/> class, to check for
7: /// a valid strong name and for a specific public key.
8: /// </summary>
9: public static class AssemblyExtensions
10: {11: [DllImport("mscoree.dll", CharSet = CharSet.Unicode)]12: private static extern bool StrongNameSignatureVerificationEx(
13: string filePath,
14: bool forceVerification,
15: ref bool wasVerified
16: );
17:
18: /// <summary>
19: /// Checks if the <see cref="Assembly"/> has a strong name and is
20: /// signed with the same public key as the executing assembly.
21: /// </summary>
22: /// <param name="target">The <see cref="Assembly"/> to check.</param>
23: /// <returns>
24: /// true if the assembly contained the public key; otherwise false.
25: /// </returns>
26: public static bool IsTrusted(this Assembly target)
27: {28: byte[] publicKey =
29: Assembly.GetExecutingAssembly().GetName().GetPublicKey();
30:
31: return IsTrusted(target, publicKey);
32: }
33:
34: /// <summary>
35: /// Checks if the <see cref="Assembly"/> has a strong name and is signed
36: /// with the provided public key.
37: /// </summary>
38: /// <param name="target">The <see cref="Assembly"/> to check.</param>
39: /// <param name="publicKey">The public key to check for.</param>
40: /// <returns>
41: /// true if the assembly contained the public key; otherwise false.
42: /// </returns>
43: public static bool IsTrusted(this Assembly target, byte[] publicKey)
44: {45: return IsStrongNamed(target) && IsSignedWith(target, publicKey);
46: }
47:
48: /// <summary>
49: /// Checks if the <see cref="Assembly"/> is signed with the provided
50: /// public key.
51: /// </summary>
52: /// <param name="target">The <see cref="Assembly"/> to check.</param>
53: /// <param name="publicKey">The public key to check for.</param>
54: /// <returns>
55: /// true if the assembly has a strong name; otherwise false.
56: /// </returns>
57: public static bool IsSignedWith(this Assembly target, byte[] publicKey)
58: {59: if (publicKey != null)
60: {61: if (target.GetName().GetPublicKey().SequenceEqual(publicKey))
62: {63: return true;
64: }
65: }
66:
67: return false;
68: }
69:
70: /// <summary>
71: /// Checks if the <see cref="Assembly"/> has been signed with
72: /// a strong name.
73: /// </summary>
74: /// <param name="target">The <see cref="Assembly"/> to check.</param>
75: /// <returns>
76: /// true if the assembly has a strong name; otherwise false.
77: /// </returns>
78: public static bool IsStrongNamed(this Assembly target)
79: {80: bool notForced = false;
81: bool verified =
82: StrongNameSignatureVerificationEx(target.Location,
83: false, ref notForced);
84:
85: return verified;
86: }
87: }
Once you have added the extensions methods to your project, you can, for example, check if a loaded assembly is strong named and is signed by the same public key as the hosting application by calling the IsTrusted method
1: Assembly file =
2: Assembly.LoadFrom(@"SomeAssembly.dll");
3:
4: if (file.IsTrusted())
5: {6: // do some magic
7: }
If you need to check for another public key just use the overload and pass in the key in question. The IsStrongNamed method can be called to check for a strong name, and the IsSignedWith method will only check for the specified public key.
The fill source code can be downloaded from my codeplex page.