- What is NuGet?
- Key Takeaways
- Environment Matrix
- Let's talk about the Package Flow
- Understanding NuGet Signing
- General requirements of NuGet Signing
- Certificate minimum requirements
- Supported Algorithms:
- NuGet Signing Workflow – Signing a package
- The Actual Signing and Verification Commands
- Common Errors
- CI/CD Use and Cleanup
- Frequently Asked Questions
- Conclusion
- References:
What is NuGet?
NuGet is the official package manager for the .Net ecosystem. It provides platforms and tools that help developers to create, publish, and consume .Net Packages. You must be wondering now, what’s a package! Packages can generally be compiled libraries packed with descriptive metadata into a nice shareable unit. NuGet’s job is to make those libraries as accessible and easy to share as possible in the form of packages. NuGet helps developers leverage an entire ecosystem and build on the existing solutions instead of building everything from scratch.
Go through the article below to better understand what NuGet Signing is.
Signing a NuGet package, in short: run
nuget sign <package.nupkg> -CertificatePath <cert.pfx> -Timestamper <timestamp_url>(or the newerdotnet nuget signequivalent), then verify withnuget verify -Signatures <package.nupkg>. The signing certificate must be valid for the id-kp-codeSigning EKU, have an RSA key of 2048 bits or higher, and must not carry the lifetime-signing EKU.
Key Takeaways
- A NuGet package may have exactly one primary signature (author or repository); co-signing is explicitly disallowed by the specification.
- The certificate must NOT have the lifetime-signing EKU (1.3.6.1.4.1.311.10.3.13). This is a hard requirement, not a recommendation, and a certificate with this EKU will be rejected.
Environment Matrix
| Component | Requirement |
|---|---|
| Tooling | nuget.exe CLI, or dotnet nuget sign/verify (available in .NET SDK) |
| Certificate EKU | id-kp-codeSigning (RFC 5280 §4.2.1.12); must NOT have the lifetime-signing EKU |
| Certificate key | RSA, 2048 bits or higher |
| Supported hash algorithms | SHA-2-256, SHA-2-384, SHA-2-512 |
| Timestamp certificate | id-kp-timeStamping EKU, RSA 2048-bit minimum |
| Primary signatures per package | Exactly one (author or repository); co-signing not supported |
Let’s talk about the Package Flow
In its public role, NuGet is like a big library (nuget.org) with over 100,000 different packages. These packages are used by lots of .NET/.NET Core developers every day. NuGet also lets you have your private library in the cloud (like on Azure DevOps), on a private network, or just on your computer. This way, only certain developers with access to the library can use those packages, and you can share them with a specific group. You can learn more about these options by Hosting your own NuGet feeds. By setting things up a certain way, you can control which libraries a computer can get packages from, ensuring they come from specific sources and not just the big public library (nuget.org).
No matter what, a library is like a meeting place for package creators and package users. Creators make helpful NuGet packages and put them in a library. Users then look for useful packages in accessible libraries, download them, and add them to their projects. Once in a project, these packages’ tools are ready to be used in the rest of the project code.
Before we dive deep into NuGet signing, let’s understand what Code signing is.
Code signing is a cryptographic process that involves attaching a digital signature to software to verify its origin and ensure it hasn’t been tampered with. This digital signature is generated using a private key and can be verified using the corresponding public key, providing users with confidence in the authenticity and integrity of the code.
Key Benefits of Code Signing:
-
Authenticity
Code signing verifies the software publisher’s identity, ensuring that users can trust the source of the code.
-
Integrity
Attaching a digital signature to the code can detect unauthorized modifications, safeguarding against tampering.
-
Tamper-proof Distribution
Code signing allows developers to distribute their software securely, reducing the risk of malicious alterations during transit.
Understanding NuGet Signing
As discussed above, NuGet is a popular package manager for .NET development, allowing developers to share and consume code easily. NuGet signing is an extension of code signing tailored for NuGet packages. When a NuGet package is signed, it includes a digital signature that provides the same benefits as traditional code signing, ensuring the authenticity and integrity of the packaged code.
General requirements of NuGet Signing
-
Ensure that a signed package remains compatible with package readers and writers lacking support for package signing
-
Integrate the package signature intricately within the package file.
-
Strictly adhere to the rule that each signed package should contain precisely one primary signature. (co-signing explicitly disallowed)
-
Ideally, designate the primary signature as either an author or repository signature.
-
When applying an author signature, ensure it serves as the primary signature. Remove the existing primary signature before adding an author signature to an already signed package.
Certificate minimum requirements
A NuGet signing certificate MUST meet the following minimum requirements:
-
The certificate MUST be valid for the id-kp-codeSigning purpose [RFC 5280 section 4.2.1.12].
-
The certificate MUST have an RSA public key length of 2048 bits or higher.
A timestamping certificate MUST meet the following minimum requirements:
-
The certificate MUST be valid for the id-kp-timeStamping purpose [RFC 5280 section 4.2.1.12].
-
The certificate MUST have an RSA public key length of 2048 bits or higher.
At signing time, a certificate MUST be within its validity period according to the package writer and MUST NOT be revoked. At validation time, the certificate’s revocation status SHOULD be rechecked; however, package readers MAY fail to open if revocation status is unavailable (e.g., a CRL is inaccessible).
Certificates MUST NOT have the lifetime signing EKU (1.3.6.1.4.1.311.10.3.13).
Supported Algorithms:
The following hash algorithms MUST be supported:
| Hash Algorithm | Hash-Algorithm-Oid |
| SHA-2-256 | 2.16.840.1.101.3.4.2.1 |
| SHA-2-384 | 2.16.840.1.101.3.4.2.2 |
| SHA-2-512 | 2.16.840.1.101.3.4.2.3 |
NuGet Signing Workflow – Signing a package
The following steps are outlined for the author signing a package.
Step 1: Determine if the package is signed
- If the package is signed and the sign operation should not overwrite an existing signature – the sign operation fails with a message that “the package is already signed.”
- If the package is signed and the sign operation should overwrite an existing signature – remove the existing signature and follow step 2
- If the package is not signed, continue with step 2
Step 2: Verify the signing certificate satisfied the minimum requirements (as mentioned above)
Step 3: Verify that the supported hash, signature, and timestamp hash algorithms are used. (as mentioned above)
Step 4: Generate Package signature File
- Create author signature
- Obtain a timestamp from the author signature
Please verify that the timestamp signing certificate satisfies certificate minimum requirements (as mentioned above) and uses the supported hash algorithm.
- Extend the author signature to CAdES-T [RFC 5126]
- Encode the author signature CMS SignedData
- Write the encoded author signature to the file
Step 5: Add the package signature file as an uncompressed (stored) file to the package being signed
Step 6: Validate the signed package
- Determine if the package is signed ( if not signed, stop the validation immediately)
- Verify the package signature file is an uncompressed and regular file.
- Verify the package signature format is supported.
- Verify package integrity
- Verify primary signature validity and trust
- If no failures have been encountered, treat the package as a valid signed package.
The Actual Signing and Verification Commands
Using a certificate file directly:
nuget sign MyPackage.nupkg -CertificatePath cert.pfx -CertificatePassword <password> -Timestamper http://timestamp.digicert.com
Using a certificate already installed in the certificate store (typical when the KSP registers an HSM-backed key there):
nuget sign MyPackage.nupkg -CertificateStoreName My -CertificateStoreLocation CurrentUser -CertificateSubjectName "<certificate subject>" -Timestamper http://timestamp.digicert.com
The newer .NET SDK exposes the same functionality via dotnet nuget sign <package.nupkg> --certificate-path cert.pfx --timestamper http://timestamp.digicert.com. Verify a signed package with:
nuget verify -Signatures MyPackage.nupkg
A successful verification reports the signature is valid and names the signing certificate; a failure names the specific validation step that failed (signature format, package integrity, or trust) rather than a generic error, which is useful for diagnosing which requirement above wasn’t met.
Common Errors
| Error | Likely Cause | Fix |
|---|---|---|
| “The package is already signed” | Attempting to sign a package that already has a primary signature without removing it first | Remove the existing signature before re-signing, since co-signing isn’t supported |
| Certificate rejected during signing | Certificate has the lifetime-signing EKU, an RSA key under 2048 bits, or lacks the id-kp-codeSigning EKU | Confirm the certificate meets all three minimum requirements before attempting to sign |
| Verification fails with a trust error | The certificate chain doesn’t resolve to a trusted root, or the certificate was revoked after signing | Confirm the certificate authority is trusted by the environment verifying the package, and check revocation status |
CI/CD Use and Cleanup
For repeated signing in a pipeline, supply the certificate path and timestamp URL as pipeline variables rather than hardcoding them, and add nuget verify -Signatures as a required stage immediately after signing so the build fails rather than publishing an unverifiable package. If a .pfx certificate file was copied to a build agent for testing, remove it once the pipeline is confirmed working, and prefer certificate-store-based signing (which keeps the key HSM-backed) over file-based signing in production pipelines.
Frequently Asked Questions
Can I sign a NuGet package with more than one certificate?
No. Co-signing is explicitly disallowed by the NuGet signing specification; a package may have exactly one primary signature, either an author or repository signature.
Why does the specification prohibit the lifetime-signing EKU?
The lifetime-signing EKU is designed to make a signature remain valid indefinitely regardless of certificate expiration, which conflicts with NuGet’s model of validating certificates against their stated validity period and revocation status at signing time.
Conclusion
NuGet is an open-source and free package manager for the .NET ecosystem. In a world where software supply chain attacks are rising, implementing robust security measures like code signing and NuGet Signing is essential. These practices instill trust in the software supply chain, giving developers and end-users confidence in the authenticity and integrity of the code they consume.
CodeSign Secure helps sign NuGet Package without any hassle, With Encryption Consulting’s CodeSign Secure solution, we offer a highly effective and efficient approach to signing NuGet packages. Our solution not only ensures the security of your packages through robust cryptographic measures but also streamlines the signing process, enhancing the overall efficiency of your software development lifecycle.
References:
RFC 5126 – CMS Advanced Electronic Signatures (CAdES) (ietf.org)
RFC 3161 – Internet X.509 Public Key Infrastructure Time-Stamp Protocol (TSP) (ietf.org)
- What is NuGet?
- Key Takeaways
- Environment Matrix
- Let's talk about the Package Flow
- Understanding NuGet Signing
- General requirements of NuGet Signing
- Certificate minimum requirements
- Supported Algorithms:
- NuGet Signing Workflow – Signing a package
- The Actual Signing and Verification Commands
- Common Errors
- CI/CD Use and Cleanup
- Frequently Asked Questions
- Conclusion
- References:
