The short answer
To sign a NuGet package, run dotnet nuget sign MyPackage.nupkg with a code signing certificate and an RFC 3161 timestamp URL. Since June 1, 2023 that certificate's private key must live on certified hardware — a USB token, an HSM, or a cloud signing service — so instead of pointing at a .pfx file you reference the certificate in your store by its SHA-256 fingerprint. To ship on NuGet.org the primary signature must be an author signature, it must carry one valid timestamp, and you must register the certificate's fingerprint on your NuGet.org account first.
On this page
What you need before you sign
Signing a NuGet package takes three things: the package itself as a .nupkg, a publicly trusted code signing certificate whose key is held on hardware, and a command-line signer — either the classic nuget sign (NuGet CLI, Windows) or dotnet nuget sign, built into the .NET SDK since version 6. If you plan to publish to NuGet.org, add a fourth: the certificate has to be registered on your account before the feed will accept an author-signed upload.
It helps to know what signing does and doesn't buy you. An author signature proves the package came from you and hasn't been tampered with since — a claim that stays attached to the file across mirrors, proxies, and offline copies. It does not encrypt the package or hide its contents, and it isn't the same as the repository signature NuGet.org stamps on everything it serves. We map both layers out below.
The certificate — and where the key lives
You need a code signing certificate: one whose Extended Key Usage lists id-kp-codeSigning, with an RSA key of at least 2048 bits. For NuGet.org it must chain to a root that ships trusted on Windows — self-signed and self-issued certificates are rejected. This is the same publicly trusted certificate class you'd use to sign an EXE or an MSI, so if you already sign Windows binaries, you're set.
Here's the part most older tutorials get wrong. Since June 1, 2023, every publicly trusted code signing key has to be generated and stored on hardware certified to FIPS 140-2 Level 2 (or Common Criteria EAL 4+), and it must be non-exportable. There is no .pfx to copy onto a build box anymore. The key sits on a USB token, your own HSM, or a cloud signing service, and the certificate gets surfaced into your machine's certificate store — which is where the signer picks it up.
If you don't have a certificate yet, a standard (OV) code signing certificate is enough for NuGet — you don't need EV for this. My-SSL issues code signing certificates through Certum with the hardware or cloud key delivery the current rules require. If you're weighing where that key should live before you buy, our comparison of cloud code signing versus USB tokens walks through the trade-offs for a shared or automated setup.
Sign the package with dotnet nuget sign
With the certificate in your store, sign the package by referencing it — not a file. The --certificate-fingerprint option finds the certificate in the store (default store name My) by its fingerprint, which is exactly how a hardware token or cloud service exposes it. From .NET 9 you pass a SHA-256 fingerprint; a SHA-1 fingerprint raises the NU3043 warning and, from .NET 10, is rejected as an error.
# Sign using a certificate held on a token/HSM/cloud (surfaced into the store)
dotnet nuget sign MyPackage.1.0.0.nupkg \
--certificate-fingerprint <SHA-256 fingerprint> \
--timestamper <your CA's RFC 3161 timestamp URL>For a private or test package whose key is a plain file, you can point at the certificate directly instead — but remember this path is not valid for public certificates:
# Test/private only — file-based key, not allowed for public code signing
dotnet nuget sign MyPackage.1.0.0.nupkg \
--certificate-path cert.pfx \
--certificate-password <password> \
--timestamper <RFC 3161 timestamp URL>The older NuGet CLI uses the same ideas with PascalCase switches — nuget sign MyPackage.nupkg -CertificateFingerprint <hash> -Timestamper <url>. Signing overwrites the package in place with the signed version; use --output if you'd rather write the signed copy somewhere else.
Timestamp so the signature outlives the certificate
Always pass --timestamper. A timestamp is a trusted authority's signed proof of when you signed, and it's what keeps a package verifiable after the signing certificate expires. Without it, the signature is only trusted while the certificate is valid — and NuGet.org won't accept the upload at all, because it requires the primary signature to carry a single valid RFC 3161 timestamp.
Use the RFC 3161 endpoint your certificate authority publishes; the timestamping certificate behind it must be valid for id-kp-timeStamping and use an RSA key of 2048 bits or more, which reputable CA timestamp services already meet. The mechanics are the same ones behind SignTool and jarsigner — our guide to code signing timestamps covers why a shipped build stays trusted for years while the certificate that signed it quietly expires.
Verify the signature
Before you push, confirm the signature is well-formed and trusted on the signing machine. dotnet nuget verify checks the author signature, its certificate chain, and the timestamp, and prints the certificate's fingerprint — the value you'll register on NuGet.org in the next step.
# Verify the signature and print certificate details
dotnet nuget verify MyPackage.1.0.0.nupkg --all
# NuGet CLI equivalent
nuget verify -Signatures MyPackage.1.0.0.nupkgA clean result lists your author signature with a valid chain and a timestamp. If it flags an untrusted chain, that's usually a missing intermediate certificate or a machine that doesn't trust the issuing root — fix it now rather than discover it on upload. For a private feed you control, you can pin the signer explicitly with dotnet nuget trust instead of relying on the machine's trust store.
Register the certificate and publish to NuGet.org
NuGet.org won't accept an author-signed package from an unknown certificate. First, on your NuGet.org account, open the package's or your account's certificate settings and register the signing certificate — by uploading it or entering its SHA-256 fingerprint. From then on, every version you publish must be signed by a certificate you've registered, which is what stops anyone else from impersonating your package ID.
With the certificate registered, push as usual. NuGet.org verifies your author signature, confirms it matches a registered certificate, and then adds its own repository signature on top before serving the package.
dotnet nuget push MyPackage.1.0.0.nupkg \
--api-key <your-api-key> \
--source https://api.nuget.org/v3/index.jsonSigning in CI/CD without exposing the key
Automating this is where the hardware-key rule bites. Because there's no key file to drop into a pipeline secret, unattended signing means connecting the build to the hardware or cloud service that holds the key. A USB token can be plugged into a dedicated self-hosted runner; a cloud signing service authenticates from the pipeline and signs remotely; and tools like the open-source dotnet sign or an Azure Key Vault signer submit only a hash to the key and never move the private material.
The design rules are the same across all three: the key never leaves its hardware boundary, the pipeline authenticates with a short-lived credential rather than an embedded secret, and only trusted branches can trigger a signing job. Our code signing in CI/CD guide lays out each pattern — self-hosted-runner token, cloud session, and pipeline-native service — and where each one fits.
Where My-SSL fits
| You publish NuGet packages and need a code signing certificate that NuGet.org will accept | Code signing certificate |
| You're deciding whether the key should sit on a token or in the cloud | Cloud signing vs USB tokens |
| You want signing to run in your build pipeline without a key in a secret | Code signing in CI/CD |
Common errors and fixes
Most signing failures come down to the certificate, the chain, or a missing timestamp. Here are the ones that stop first attempts, and what each one is really telling you.
- NU3001 — certificate not found or no code signing EKU. The fingerprint matched nothing in the store, or the certificate can't be used for code signing. Confirm the token or cloud provider surfaced the certificate into the right store and that its EKU includes
id-kp-codeSigning. - NU3018 — chain could not be built or isn't trusted. Usually a missing intermediate certificate or a self-signed certificate. Install the full chain and make sure the certificate rolls up to a publicly trusted root; NuGet.org rejects self-signed signers outright.
- NU3043 — SHA-1 certificate fingerprint. From .NET 9 a SHA-1 fingerprint warns; from .NET 10 it's an error. Pass the SHA-256 (or stronger) fingerprint instead.
- Upload rejected: certificate not registered. NuGet.org won't accept an author-signed package until its certificate is registered on your account. Add the fingerprint in your account settings, then push again.
- Upload rejected: missing or invalid timestamp. The signature has no valid RFC 3161 timestamp. Re-sign with
--timestamperpointed at your CA's endpoint.
FAQ
Need the certificate that makes this work?
Author signing only counts if the certificate chains to a publicly trusted root and its key sits on compliant hardware. My-SSL issues code signing certificates through Certum, a publicly trusted certificate authority, with the token, HSM, or cloud key delivery the current rules require — the same certificate signs your NuGet packages, EXEs, and installers.
Related reading
- Code signing timestamps — why your signature outlives the certificate, and the commands to add one.
- Cloud code signing vs USB tokens — where your signing key should live once you're automating.
- Code signing in CI/CD — automating signatures without pasting a key into a pipeline secret.
Sources worth checking directly
- Microsoft Learn — Signing NuGet Packages and dotnet nuget sign (command syntax, fingerprint signing, SHA-1 deprecation)
- Microsoft Learn — Signed Packages Reference (certificate and timestamp requirements, author vs repository signatures)
- CA/Browser Forum — Baseline Requirements for Code Signing (hardware key rule and CSC-31 460-day validity)