NuGet Package Signing

Topics: Ecosystem
May 17, 2013 at 7:17 PM
Edited May 18, 2013 at 2:36 PM
UPDATED: Due to a massive brainfart, I earlier kept mentioning nuspec files when of course I mean nupkg files.

Hello all,

In the interests of getting this started and off of Twitter, I've thrown together a back-of-a-napkin summary of points that seem pertinent to me.

First up, I suggest that the notion of package signing should be split into two logical operatons, each offering different forms of qualitative and quantitative guarantees/assertions/evidence. These would take the form of two signatures, one from the NuGet server which would be always applied and one from the package author which should probably be optional in the interest of reducing roadblocks to productivity. Let's look at both ideas:

NuGet Server Signature

What would this offer?

This package came from the official NuGet feed and has not been tampered with. As a consequence of this, the following evidence is useful to package consumers:

Validated download count

This is generally perceived as a vote of confidence, assuming the downloads occurred over a reasonable period of time. However, large amounts of downloads over a short period are also valid for package upgrades, for example.

Package version history

Updates can be linked to prior versions in a strong-ish fashion, and the aggregate evidence taken into account.

Tamper proofing

Obviously the primary purpose of a NuGet server signature would be for integrity checks of the nupkg and contents.

Non-repudiation of package source

The NuGet server should offer the guarantee that version 1.0 of Foo.Bar is the only 1.0 of Foo.Bar in existence. This is important because currently it's possible to have different 1.0 Foo.Bar packages if they come from different sources. You might not trust Foo.Bar 1.0 from a 3rd party NuGet feed, but you may want to trust it from the official NuGet feed.

Package revocation status

The package has not (yet) been determined to be dangerous and/or compromised.

Perhaps we might also offer the ability to directly revoke a package to users (keep reading, please,) but perhaps having a fixed limit of one revocation per year (for example) to dissuade people from using this as a quickfix for "Duh I goofed on teh spelling." Errors and bugs should continue to be managed with a package update and version bump.

A revocation should be for exceptional cases where install.ps1 might trash a package consumer's machine or something else equally nasty. Resetting revocation limits would be done on a case-by-case basis (which seems more managable than the current "email us to remove a package" state.)

Also, to encourage authors to sign their packages, we should only offer revocation functionality to users who have provided a public key. The revocation request might be issued by nuget.exe (for example) or a PM console cmdlet and would be signed by their private key. This allows the NuGet server to use two factor authentication for revocation requests (username/password + pk.) The revocation process would also validate the author's signature on the package being revoked. This mitigates the scenario where a compromised account has its public key replaced by an attacker in an attempt to revoke a package he or she did not submit.

Risks

The NuGet server platform must be capable of authenticode signing in an automated fashion in order to scale. A compromise of the official Nuget server may leak the authenticode signing cert. However, with authenticode being based on the real world's PKI (i.e. not self-signed), it can be revoked via the normal Windows mechanisms (IE CRL etc) and a new key reissued.

If this happens, it may not be a total disaster. A new NuGet server cert could be used to resign all of the packages, if the packages were determined to have retained their integrity by way of the author's public key signature.

Package Author Signature

What would this offer?

This package came from the package author registered on the NuGet server; in effect this is a secondary authenticator of the author's identity. Tamper proofing is served by the NuGet server signature, so is not neccessarily a function of this signature.

The following evidence is useful to package consumers:

Authenticated author's history / reputation

The author's other packages and package history is a useful metric for gauging trustworthiness. The metadata also provides links to project source, blog sites etc.

Non repudiation of author identity

The author, or someone possessing knowledge of both authenticating factors (username/password + private key), uploaded this package.

Risks

If author loses self-signed cert or it is compromised, there is the option of one-time revocation as discussed above. Author can then replace his self-signed cert locally with a new one and upload/associate a new public key. If the currently associated public key cannot validate author signed packages, the nuget client (e.g. VS) might emit a warning, or refuse to serve it.

Notes

A nupkg would either be signed by only the NuGet server certificate, or by BOTH the NuGet server AND the package author.

NuGet Server Signing

One approach might be with authenticode, in which case we may have to support a new format, say .nupkgX, which is possibly just a .nupkg encased in a signed cab (one of the few formats that authenticode can sign - the others being ( (.exe, .cab, .dll, .ocx, .msi, .xpi, and .xap ). We might also just create nupkg cabs and system.io.packaging archives and detect on the server/client with magic numbers (yuck.)

If wrapping in a cab is too clumsy, there's also the detached signature approach that Windows drivers take; a signed catalog (.cat/.cdf) file that contains sha1 hashes of the contents of the package, the package name, version, author username and the author's public key (if there is one.) The detached cdf/cat should reference the author signed manifest if there is one.

Package Author Signing

The .nupkg might contain an author-signed manifest of sha1 hashes (kinda like a authenticode cdf) from author's self-signed x509 cert. the public portion should be associated with the nuget account on the server end, and the private portion kept with the author (possibly integrate signing / manifest generation into nuget.exe); signed manifest might be counter-signed by nuget upon upload, or just referenced on the authenticode .cat/cdf.

The NuGet server itself may offer the generation of a self-signed cert for a user, providing the full cert with private key to the user and automatically associating the public key with the users account -- and/or -- we could let the user generate their own code signing cert and offer guidance.

Thoughts, additions, corrections, clarifications, laughter, outright mockery?
May 17, 2013 at 8:33 PM
I'm confused about the comments on NuSpec. Why would we wrap or sign the nuspec at all? If it's in a signed package, then the package can't be tampered with until the package has been unpacked. Once the package is unpacked though, all bets are off anyways.

I think the default for most users should be getting signed by the NuGet server using some, likely self-signed certificate, ie they had no idea it even happened. I'm not sure of the need to give the public-private key.

I'm not very high on the idea of package revocation and ultimately I think it's a separate issue from signing. I'd recommend evaluating that issue separate of the signing issue.

Eric
May 17, 2013 at 8:50 PM
Edited May 18, 2013 at 2:31 AM
Eric,

EDIT: Sorry! I am an idiot - I kept saying nuspec when I meant nupkg. Updated.

There are different benefits from signatures, depending on who's doing the signing. The NuGet server might sign (ignore how, that's not important) the package, and the author may additionally sign the package (again, ignore how that's not important.) I've written out some points for each act of signing and what it gives in terms of reassurances for a package consumer.

Yes, once the package is unpacked, all bets are off. That's not the goal of signing in either case. Simply put, given a nupkg, we want to know if the package is a) from the official nuget feed, and b) was it uploaded by a particular author. There are more details than that, but this is the crux of it. The user would not be aware of NuGet signing anything, correct. The author signature would be entirely optional.

All points above are up for discussion individually - it's just a summary of ideas :)

Oisin.
May 20, 2013 at 4:12 PM
It's important to note that the OPC standard, which the nupkg format conforms to, supports signing. There's no need to wrap anything or create a custom manifest, that's built into OPC. Outercurve signs VSIX files (which are also OPC) using the System.IO.Packaging namespace in the .NET framework and that works perfectly fine.

Authenticode signing and cryptographic signing are really the same thing. Cryptographic signing takes in any certificate with a public-private key pair. Authenticode signing just implies that the signing certificate comes from a trusted entity, such as Verisign.

One thing that I'm unsure of is how OPC handles dual signatures, i.e. NuGet server signature AND author signature. I don't think it's actually needed though. Any signature on an OPC file provides two things: that the file was signed by someone with control of a specific private key and that the file has not been changed since it was signed. If something changes, the signature contains a hash that is no longer valid.

By having the general NuGet server signing certificate sign the package, the user knows that the file has not been changed since the package was uploaded to the NuGet server. The user just doesn't know who specifically made the package. If there's an author signature, the user knows not only that the package hasn't been modified since it was created but also who exactly made the package.

Eric
May 20, 2013 at 4:31 PM
Quick points, since I'm terribly busy today.

As @wwahammy points out, OPC supports signing. No need to invent a new way of doing anything.

The only real virtues of the signature are:
  • to uniquely identify the package publisher,
  • to validate that the package has not been tampered since the publisher has signed the package.
The spinoffs that unique identification get you may include
  • the ability for the consumer to make a trust decision. This is a tricky thing, as a number of factors go into making a trust decision: --read this to understand more about Trust and Reputation.
  • once an initial trust decision is made, a digital signature can allow the user to reliably get upgrades without having re-evaluate their trust of a given publisher.
  • provides a kind of 'namespace' for packages -- ie, two publishers can both put out a Foo.Bar package, and the user can select the one from a publisher they trust.
The NuGet repository should NEVER, EVER sign packages. It didn't make them, it has no particular reason to assert any level of package identity or safety. Where you get a package from is not a reliable means of ensuring anything. Trust decisions can only be made against the package publisher, not the by which you got the package.

The simplest way to encourage packaging is to have the NuGet pack command apply an XMLDSIG signature at package creation time. It would be trivial to assist the user in creation of a self-signed certificate in the case they do not possess a CA-issued X509v3 certificate.

I'm a bit busy today, so I'll leave it at that for now.

G
May 20, 2013 at 5:04 PM
@wwahammy, @fearthecowboy

All good points, and please remember that I'm trying to think of this in terms of keeping publishing as easy as it currently is. People make decisions on trusting NuGet and the packages it serves already, and there is not a certificate in sight. I tried to enumerate some of the major factors that people are currently using to make these decisions and to come up with a pragmatic way of making those factors somewhat more reliable. If the NuGet server signs then nothing changes for authors, but of course there's a lot less trustiness (with apologies to Stephen Colbert) involved.

That said, I see private NuGet servers popping up in enterprises too (mine included), so don't ignore these scenarios where package source identity is probably easier to manage at the server level, and strong naming (spit) doing the grunt work at the package level.
May 20, 2013 at 7:29 PM
The only real virtues of the signature are:
•to uniquely identify the package publisher, 
• to validate that the package has not been tampered since the publisher has signed the package. 
I want to point out that NuGet today does validate the package file hash before installation to make sure it hasn't been tampered with. Coupled with the fact that we use HTTPS by default, I think we have that concern covered.

That leaves us with the other virtue of signature: identify the package publisher. Today, nuget.org automatically replaces the Owners field in the nuspec file with the account username of the user who uploads the package. So one way to address this concern is to establish a trust system on the nuget.org website itself. We have indeed discussed about doing it a while go, with David Ebbo and Phil Haack suggested relaying on Twitter or StackOverflow. Once we have that system in place, we don't need to sign packages at all.
May 22, 2013 at 4:59 PM
I strongly recommend we use signing instead. Getting trust and security right is a brutally difficult problem but in this space it's been solved. I don't understand the reluctance to just use the tools we have available to us.
May 22, 2013 at 5:01 PM
And simplify the process.
Developer
May 22, 2013 at 5:10 PM
YES!

Sent from my Windows Phone

From: [email removed]
Sent: ‎22/‎05/‎2013 19:01
To: [email removed]
Subject: Re: NuGet Package Signing [nuget:444089]

From: fearthecowboy

And simplify the process.
May 22, 2013 at 5:15 PM
What process?

This topic is only about trust, not about security.
May 22, 2013 at 5:16 PM
Edited May 22, 2013 at 5:17 PM
And I want to repost the link to Phil's blog about trust in NuGet. This is the NuGet team's stance on the topic of package signing.

http://haacked.com/archive/2013/02/19/trust-and-nuget.aspx
May 22, 2013 at 5:39 PM
Edited May 22, 2013 at 5:40 PM
dotnetjunky wrote:
And I want to repost the link to Phil's blog about trust in NuGet. This is the NuGet team's stance on the topic of package signing.

http://haacked.com/archive/2013/02/19/trust-and-nuget.aspx

And I significantly disagree with some of Phil's assertions.

http://coapp.org/news/2013-04-04-Trust-And-Identity.html

And, you'd damn well read Kim Cameron's Laws of Identity: http://www.identityblog.com/?p=352

Having worked in the Digital Identity ecosystem (and authored a book on the subject) I can tell you that this isn't a trivial problem.

To Address specific issues:

That said, I see private NuGet servers popping up in enterprises too (mine included), so don't ignore these scenarios where package source identity is probably easier to manage at the server level, and strong naming (spit) doing the grunt work at the package level.

Enterprises should be encouraged to issue individual certificates off of a common CA, with which each developer can sign binaries for use inside the organization with. This actually gives a greater degree of trust, since you can track down the individual who actually compiled the binary, and have an effective audit trail.

I want to point out that NuGet today does validate the package file hash before installation to make sure it hasn't been tampered with. Coupled with the fact that we use HTTPS by default, I think we have that concern covered.

No. You don't. Who generated the hash? This doesn't provide any ability to ensure that a poisoned package hasn't been inserted at all. Nor does it provide the ability to know specifically who created a package .

What process?

One of the fears that keeps getting brought up is that for some reason people view signing as "hard" or "difficult" or "complicated" ... the tools can be built so that this is implicit, and requires zero additional work on the part of the developer, and shouldn't require any significant functionality at the server (since, NuGet packages are very useful even without a server).

Today, nuget.org automatically replaces the Owners field in the nuspec file with the account username of the user who uploads the package. So one way to address this concern is to establish a trust system on the nuget.org website itself

And this is a perfect example of tampering with the package. Not Cool.

David Ebbo and Phil Haack suggested relaying on Twitter or StackOverflow. Once we have that system in place, we don't need to sign packages at all.

OMFG. NO.

Relying on a third-party authentication system significantly weakens trust. What happens when someone's Twitter or SO account is hacked? Worse, what if they go offline? What if they disappear?

This is a direct violation of Law 3 :

JUSTIFIABLE PARTIES -- Digital identity systems must be designed so the disclosure of identifying information is limited to parties having a necessary and justifiable place in a given identity relationship.

Involving an unrelated third party is not acceptable.
May 23, 2013 at 4:41 PM
@dotnetjunky the hash is added by whom? And what how do we know that the hash hasn't been tampered with? What prevents someone from modifying the contents of the package and creating a new hash? Signing would be a pretty strong guarantee that the user would know the package has been modified because the hash is encrypted by the private key. If someone tries to modify the hash without the original private key, the signature is invalid. For some users, being warned that a package has an invalid signature is okay with them because they may have modified the package or they know who modified the package. For a lot of users, it gives them pause to think "wait a minute, something is wrong here." It's a way to guarantee that we know if a package is in the same condition as the creator made it.

I think a web of trust is a perfectly fine idea. It just shouldn't NEGATE signing. Signing isn't a particularly hard issue for the package creator because tools can be written to make it simpler. Fortunately, we're writing a tool right now to simply difficult problems: NuGet.
May 23, 2013 at 4:50 PM
The hash is computed automatically by nuget.org when the package is uploaded. You can see it from the feed (https://nuget.org/api/v2/Packages).

When NuGet downloads the package, it recalculates the package hash itself, and compare with the value from the feed. If the hashes don't match, NuGet won't install the package.
May 23, 2013 at 6:03 PM
The current method of using hashes isn't great for a few reasons. First it requires me to trust that nuget.org hasn't been compromised. This is a massive point of a failure because if someone gets access to NuGet.org they can poison EVERY package and change the hash appropriately. Literally, 13,000 packages which are used as part of build systems for billions of dollars worth of software are riding on the bet that no one can guess a password to NuGet.org. On top of that, if the package is compromised after it's already on my local machine, or before it's been uploaded to the server, there's no way to know. That means I have to trust NuGet.org's (or any repos) security, the package uploader's security and the security of all of the programs on my build machine. With signing I need to trust one thing: that the packager took care of their key. If by default, we create a one-time key as part of "nuget pack" to sign the newly created package, and we immedidately discard that key, I know that the package has never been tampered with since creation. I don't know anything about who signed the package but I know it hasn't been tampered with.

We can also allow people to choose to reuse the same key multiple times by giving them a pfx file when they run nuget pack , then we not only know it hasn't been modified with but for future versions of the package we know it was signed by the same key. If they choose to use a key from someone like Verisign, we not only know it hasn't been modified with and that for future versions of the package we know it was signed by the same key but we also know that the identity of the person has been verified!
Mar 2, 2014 at 4:15 PM
Steps to digital sign a nugget package?