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

MonoGame Not Strongly-Named Assembly #4147

Open
NArnott opened this issue Sep 22, 2015 · 14 comments

Comments

@NArnott
Copy link

commented Sep 22, 2015

I'm trying to use MonoGame inside my application (which must be signed), but I can't because MonoGame assembly (and the referenced SharpDX assemblies I've noticed) is not signed (is not a strongly-named assembly). Is it possible to sign them (at least the NuGet version)? I'd rather not have to go through the fuss of building my own version of everything just to sign them.

@danzel

This comment has been minimized.

Copy link
Contributor

commented Sep 24, 2015

IIRC if you use something that is SNK signed, then you need to be SNK signed yourself.
So we probably don't want to do this, as it would require everyones projects to be SNK.
Could ship a separate dll for it maybe....

@mrhelmut

This comment has been minimized.

Copy link
Contributor

commented Sep 24, 2015

The major problem is that some MonoGame Pipeline dependencies are not all signed, which prevent the ContentPipeline project to be signed (and therefore the core MonoGame library too because it has friend assemblies with the pipeline).
Signing the Pipeline assemblies is problematic due to all its dependencies (but that's not really a problem since the typical scenario doesn't involve them to be shipped with a game), but it is possible to ship a signed core MonoGame if one temporarily remove the assembly friendship (in AssemblyInfo.cs), as long as both SharpDX and OpenTK are signed too (right now in the develop branch, both are signed).
I'm doing so in our projects, it's not secure at all to sign MonoGame myself, but we had to do it because some system configurations showed warnings regarding non-trusted libraries.

It would be useful to have at least signed versions of MonoGame.Framework.dll for publishing purpose (the pipeline would still require the non-signed one, because assembly friendship can't be given to signed assemblies if the other one isn't).

@NArnott

This comment has been minimized.

Copy link
Author

commented Sep 24, 2015

@danzel I think you have that backwards. You can used all the signed assemblies you want, and not be signed yourself. Just think about the .NET framework. All those assemblies are signed, but that doesn't force you to sign your assembly to use them. Only if you're signed, can you NOT reference unsigned assemblies. This is why I'm requesting it. I have a signed assembly and I cannot use MonoGame because they are not signed.

@mrhelmut Thanks for the reasoning. Sounds like those dependencies need to be signed as well then. It may not be easy, but it is sure a headache when projects like this aren't signed and become a show stopper...

@danzel

This comment has been minimized.

Copy link
Contributor

commented Sep 24, 2015

Cool, I had a feeling it applied in both directions for some reason.

@tgjones

This comment has been minimized.

Copy link
Contributor

commented Jan 24, 2016

+1 on this. I'd like to use MonoGame in a VS extension I'm working on (think level editor), but VS extensions can only reference signed DLLs.

@tomspilman

This comment has been minimized.

Copy link
Member

commented Jan 25, 2016

I don't know the first thing about signing assemblies, so @dellis1972 or @KonajuGames will have to help here.

I assume there is some command line tool to do it. I assume we need some sort of certificate... possibly the same one we can use for signing installers.

Assuming we have to get any 3rd party assemblies we use in the pipeline to be signed. I suspect we won't be signing the pipeline itself. That said the pipeline executes via the MGCB.exe... I don't think you need that signed to be able to execute it.

Anything else i'm missing here?

@KonajuGames

This comment has been minimized.

Copy link
Contributor

commented Jan 25, 2016

@tomspilman

This comment has been minimized.

Copy link
Member

commented Jan 25, 2016

If the MonoGame assembly itself is signed, any assemblies it loads need to
be signed.

Does that include native libraries like sdl2?

@KonajuGames

This comment has been minimized.

Copy link
Contributor

commented Jan 25, 2016

@Helikin

This comment has been minimized.

Copy link
Contributor

commented Jan 25, 2016

We have added strong naming in our MonoGame fork (https://github.com/DigitalRune/MonoGame). I don't have time today, but in the next days I can write down a summary of all changes we had to make.

@tomspilman

This comment has been minimized.

Copy link
Member

commented Jan 25, 2016

That would be great @Helikin !

@Helikin

This comment has been minimized.

Copy link
Contributor

commented Jan 29, 2016

Here is a summary of the MonoGame changes in our fork regarding strong-name signing. I also add a copy of my notes on strong names for readers who are less familiar with the topic:

What is strong-name signing?

Strong-naming a .NET assembly creates a unique identity for the assembly by signing it with a private key. For more detailed information just google "strong name signing" and read the MSDN articles.

Related Terms

Following terms are used in the literature: to sign with a strong name, strong-name signing, strong-naming, signed DLLs, strong-named DLLs

Why use a strong name?

  • A strong name is required to install an assembly in the GAC (global assembly cache).
  • DLLs with a strong-name cannot be modified. (However, you can remove the strong name. Change the DLL. And use the unsigned DLL or sign it with a different strong name.)
  • A strong-named .NET assembly can only reference other strong-named .NET assemblies. That means, if you create a library and do not provide a strong name, then customers cannot reference the library in strong-named projects.
  • Using strong-named DLLs you can add two DLLs to a project which contain the same types, for example: Create an XNA Game. Add MonoGame. Now, there are duplicate type conflicts. If you set an alias for the MonoGame assembly (see VS Properties window), then you can use both assemblies in one project!

Disadvantages

If you strong-name your assembly, then you cannot reference other .NET DLLs without a strong-name. Getting strong-named DLLs for all third-party references can be very annoying and slows development down. For example, I built MonoMac, SharpDX from source to add missing strong names.
I only recently discovered tools which you can use to sign any third party DLL, which made things a lot easier. (See section Tools below.)

How to sign an assembly?

Create key pair: sn -k MonoGame.snk
sn.exe is the strong name tool, which is installed with Visual Studio.
The file MonoGame.snk contains the private and public key and should be kept private and secure.
To sign the assembly: In Visual Studio just go to Project | Properties | Signing.

How to get the public key (public key token)?

Sometimes you need to specify the public key token, e.g. in the InternalsVisibleTo attribute. To get the public key token from a strong-named DLL call: sn -Tp myassembly.dll

Necessary MonoGame change

In our fork we sign the MonoGame.Framework DLLs and the MonoGame.Framework.Net DLLs. We do not sign the MonoGame.Framework.Content.Pipeline DLLs because most users will not reference them directly and we did not want to spend time signing all referenced third party DLLs.

We use bait-and-switch PCL. This works only if the PCL DLL and the platform-specific DLLs are all signed or all unsigned, e.g. you cannot sign only the Windows build.

Following changes were necessary:

  • Create .snk file with key pair.
  • Enable strong-name signing in MonoGame.Framework and MonoGame.Framework.Net .csproj (by changing the Protobuild XSLT files). Following lines need to be added to the .csproj:
    <SignAssembly>true</SignAssembly> <AssemblyOriginatorKeyFile>..\MonoGame.snk</AssemblyOriginatorKeyFile>
  • Add strong-names to the third party .NET DLLs:
    • Official SharpDX packages contain signed and unsigned DLLs. → Replace unsigned DLLs in MonoGame ThirdParty repo with signed DLLs. Exception: I did not find officially signed SharpDX DLL for WP8.0, so I built them manually with our own strong name key.
    • Built MonoMac.dll from source with our own strong name key.
    • Added strong-name to NVorbis DLL. (This was the first time I tried a tool instead of building from source and it worked without problems.)
    • Lidgren: Add strong-name signing in .csproj.
  • Friend assemblies:
    • MonoGame.Framework.Content.Pipeline references the MonoGame.Framework project, which is no problem because a DLL without a strong-name can reference a strong-named DLL. However, the MonoGame.Framework projects contains

      [assembly: InternalsVisibleTo("MonoGame.Framework.Content.Pipeline")]

      InternalsvisibleTo cannot be used in this case. That means some classes in MonoGame.Framework need to be made public:

      • Content/ContentExtensions.cs
      • Graphics/GraphicsExtensions.cs
      • Utilities/ReflectionHelper.cs
      • Utilities/Hash.cs
    • In AssemblyInfo.cs of MonoGame.Framework

      [assembly: InternalsVisibleTo("MonoGame.Framework.Net")]

      needs to be changed to use the strong name

      [assembly: InternalsVisibleTo("MonoGame.Framework.Net, PublicKey=…")]

Where to store the .snk key file?

Ideally, the .snk is kept private and secure. I think this is the case in SharpDX: The official packages contain unsigned DLLs and signed DLLs with a key which is kept private.
I have seen other popular open source projects (e.g. MVVMLight) that just add the key to the public repository.
The latter is obviously bad for security reasons but a lot more convenient.
I am not sure which is the way to go if you want to keep the key private:

  • Have two project versions? The users who want to build from source need a project without strong name. The build server needs a project with strong name.
  • Have two keys? An insecure dummy .snk file is in the repository. The secure .snk file is used on the build server.
  • There is also Delayed Signing where you build the project without requiring the .snk file and then you use the sn.exe tool to sign the DLL later. (I have no experience with this approach.)

Tools

Strong-naming projects is annoying if you have to build third-party DLLs yourself to add a strong name or if you have to pester the original author to supply a strong-named build. Recently I discovered tools which can add a strong-name to a DLL (without needing the source code). The most interesting tool is: .NET Assembly Strong-Name Signer (http://brutaldev.com/post/NET-Assembly-Strong-Name-Signer, https://github.com/brutaldev/StrongNameSigner/).
Important to note is that this should also work if there are groups of friend assemblies (using InternalsVisibleToAttribute). Just drop all related DLLs into the tool.
I have tested this only with the NVorbis DLL so far. So my experience with this tool is limited.
I have seen open source projects which do not use a strong name and just tell their users to add a strong-name themselves using such tools when they really need signed DLLs.

What now?

I see a few ways how MonoGame could handle this:
A) Make the changes described above and decide where to store the .snk file.
B) Just use the tool on the build server to sign the final DLLs.
C) Just educate the users how they can add a strong-name to any DLL when they need it.

In my opinion, the first option is the best solution. Properly strong-name sign all DLLs, store the key publicly in the MonoGame repository. (All other solutions create a fragile ecosystem where third-party developers and middleware providers need to come up with their own strong-name signing strategy. As a result, the third-party DLLs won't be compatible anymore.)

@tgjones Would you also need strong-named versions of the MonGame content pipeline DLLs for your VS extension?

@tgjones

This comment has been minimized.

Copy link
Contributor

commented Jan 29, 2016

@Helikin That's a great write-up, thank you.

Would you also need strong-named versions of the MonGame content pipeline DLLs for your VS extension?

The short answer is no, at the moment I don't. (A more complete answer would be: my scene editor extension does include a tool window that displays rendered content previews, but it doesn't build the content itself - it relies on the content already having been built by the user. In order to extract the available content items from the .mgcb, it relies on PipelineProject and other types in Pipeline.exe, which isn't a great solution, because they are not supported public APIs, and Pipeline.exe isn't signed, nor would I expect it to be. It would be nice if PipelineProject and its friends were in MonoGame.Framework.Content.Pipeline.dll, or at least somewhere where I can rely on their existence, in which case yes, I would need strong-named versions of the content pipeline DLLs. But there are enough prerequisites and complexities there that I'm happy to handle that as a separate, subsequent, issue, unless anybody else needs it done now.)

Just to make this less abstract, here's the current state of the VS extension I'm talking about:

VS extension

@crystalbyte

This comment has been minimized.

Copy link

commented May 28, 2017

Has there been any progress made on this issue ?

@Jjagg Jjagg added the Maintenance label Dec 11, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
9 participants
You can’t perform that action at this time.