120

I have 2 projects in my solution:

  1. Assembly (Basic Library)
  2. Test Assembly (NUnit)

I had declared the test assembly as friends assembly in first project:

[assembly: InternalsVisibleTo ("Company.Product.Tests")]

Everything was working fine till I realised that I have forgot to setup the solution to sign my assemblies. So created a snk file and setup the visual studio project to sign the first assembly (Basic Library). Now when I compile the first project, I get following error:

Friend assembly reference 'Company.Product.Tests' is invalid. Strong-name signed assemblies must specify a public key in their InternalsVisibleTo declarations.

I tried to extract the public key from my snk file using sn utility but it generates a wired binary file which I am unsure how to use. How can I fix the problem?

Hemant
  • 19,486
  • 24
  • 91
  • 127

3 Answers3

210

You need to sign both assemblies, because effectively both assemblies reference each other.

You have to put the public key in the InternalsVisibleTo attribute. For example, in Protocol Buffers I use:

[assembly:InternalsVisibleTo("Google.ProtocolBuffers.Test,PublicKey="+
"00240000048000009400000006020000002400005253413100040000010001008179f2dd31a648"+
"2a2359dbe33e53701167a888e7c369a9ae3210b64f93861d8a7d286447e58bc167e3d99483beda"+
"72f738140072bb69990bc4f98a21365de2c105e848974a3d210e938b0a56103c0662901efd6b78"+
"0ee6dbe977923d46a8fda18fb25c65dd73b149a5cd9f3100668b56649932dadd8cf5be52eb1dce"+
"ad5cedbf")]

The public key is retrieved by running

sn -Tp path\to\test\assembly.dll

Alternatively, get it from the .snk file:

sn -p MyStrongnameKey.snk public.pk
sn -tp public.pk
Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • Don't multiple assemblies signed with the same key end up with the same public key? Would this provide an "end-run" around the problem, perhaps? – Bevan Jul 14 '09 at 07:03
  • @Bevan: Yes, quite possibly. Just compiling a dummy file with the key is probably a faster way to go - will edit. – Jon Skeet Jul 14 '09 at 07:16
  • If both assemblies are being signed with different keys, I assume I need to specify public key of friend assembly (inside InternalsVisibleTo attribute). Is that right? – Hemant Jul 14 '09 at 07:31
  • 7
    And it is damn irritating to see the MSDN documentation (http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx) mention ridiculously short public key which almost look like public key **token** to me. – Hemant Jul 14 '09 at 07:34
  • Hemant: I think at one stage the docs actually claimed it *did* need to be the token. Doh. – Jon Skeet Jul 14 '09 at 09:00
  • 4
    You can extract the public key directly from a .snk file: sn -k MyStrongnameKey.snk // sn -p MyStrongnameKey.snk public.pk // sn -tp public.pk // – Tim Long Apr 30 '10 at 17:49
  • @Tim: Thanks, I seem to remember this being corrected in another answer, but not this one. Will edit now. – Jon Skeet Apr 30 '10 at 18:22
  • Guys.. is there any explanation as to why we need to add the publickey. Why signing the referenced project with same .snk file not enough? – R3D3vil Jul 31 '12 at 14:11
  • @Nisarg: The original assembly is trying to express the idea of trusting a different assembly. As an attacker, I shouldn't be able to swap out *your* signed friend assembly for *my* assembly, even if I've managed to sign my assembly with my key. – Jon Skeet Jul 31 '12 at 14:12
  • How does one know the name of the assembly? – Colonel Panic Nov 19 '12 at 12:05
  • @ColonelPanic: Um, you're trying to give access to a particular assembly. You should know the name already. – Jon Skeet Nov 19 '12 at 13:29
  • 1
    I was using the 'assembly title' specified in `AssemblyInfo.cs`. Since then deduced the right name to use is the 'assembly name' from the project's Properties/Application dialog (which differs again from project's name in Visual Studio's solution explorer). – Colonel Panic Nov 19 '12 at 13:35
  • 1
    To quickly get Public Key for an assembly you can refer to http://msdn.microsoft.com/en-us/library/ee539398.ASPX – sean717 Nov 14 '13 at 20:26
  • 7
    As helpful as these answers and comments have been, I needed some experimentation to realize that the public key is the one from the assembly containing the tests, NOT the assembly that contains the 'InternalsInvisibleTo' declaration. – Andreas Dec 10 '13 at 13:06
  • 3
    @Andreas: Well it goes along with the assembly you're naming - you're specifying the strong name of the assembly to trust, within the assembly that's doing the trusting. – Jon Skeet Dec 10 '13 at 13:07
  • You put the PK from Google.ProtocolBuffers.Test or ProtoBuf in assembly:InternalsVisibleTo? – Ricardo Mar 29 '20 at 15:19
  • @Ricardo: From the *target*, so in this case `Google.ProtocolBuffers.Test`. You're saying "I want you to trust this assembly". – Jon Skeet Mar 29 '20 at 15:23
  • the problem with i have is : i can get public key from snk file and can put it into assemblyinfo as `assembly: System.Runtime.CompilerServices.InternalsVisibleTo("TestServerApi,PublicKey=" + ...`, but right after i compile the project, this publicKey= is gone. i also added same key to csproj itemsgroup: `...`, it does not change anything - after build public key is gone from assembly – Sasha Bond May 20 '22 at 00:52
  • @SashaBond: I don't know what you mean by "is gone" - are you modifying a *generated* AssemblyInfo.cs by any chance? If so, don't do that - just add a separate one. I don't quite know what's going on in your situation (and I've never used an MSBuild property for this) but I *do* trust signed assemblies all the time... – Jon Skeet May 20 '22 at 05:55
-3

You can directrly get publicKey from assembly which you interest, without magic with sn.exe

<!-- language: c# -->
var assemblyName = Assembly.GetExecutingAssembly().GetName();
Console.WriteLine("{0}, PublicKey={1}",
    assemblyName.Name,
string.Join("", assemblyName.GetPublicKey().Select(m => string.Format("{0:x2}", m))));
ezyuzin
  • 31
  • 5
  • 1
    This is not an answer to _this_ question. It should be a comment on [the answer it is addressing](http://stackoverflow.com/a/1123831/1350209) – Cole Tobin Feb 18 '15 at 17:07
-7

I think you need to put in the strong name, which would be something like "Company.Product.Tests, Version=1.0.0.0, Culture=neutral, PublicKeyToken=17135d9fcba0119f". I assume Company.Product.Tests is your assembly name and 17135d9fcba0119f is the public key.

Another way to resolve this problem would be not to use separate assemblies. I usually put the source code and the testing code in the same assembly. I don't know if you have any special concern that you must separate them.

user95319
  • 1,213
  • 1
  • 8
  • 12
  • I dont think we need to specify the version number and culture (see http://msdn.microsoft.com/en-us/library/system.runtime.compilerservices.internalsvisibletoattribute.aspx). I havent really tried putting the test code in the assembly itself. Will try and see how it works (+1 for the tip). – Hemant Jul 14 '09 at 07:33
  • 4
    For InternalsVisibleTo, PublicKeToken is not enough. You need the entire public key :-( – Sean Reilly Jul 14 '09 at 07:42