Repository navigation
Conversation
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
## Summary
Adds support for signing NuGet packages (
.nupkg) and symbol packages (.snupkg) with a NuGet **author signature**. This is the same kind of signaturedotnet nuget signproduces, but it uses the Key Vault key, so the private key never leaves the vault.Packages are detected by file extension. They can be signed in the same run as Authenticode files and use the existing options:
## How it works
-
NuGetKeyVaultSigner(new, inAzureSign.Core) builds the signature content defined by the NuGet signed package spec. It signs it as CMS through the Key VaultRSAwith the signed attributes NuGet requires: signing time, commitment type (proof of origin) and signing-certificate-v2. It can add an RFC 3161 timestamp.-
NuGetPackageArchive(new, internal) reads and rewrites the zip structure the way the spec requires..signature.p7sis added as a stored entry after the last local file entry, and its central directory record goes after the last existing one. Any existing signature is removed first, and the other entries are copied byte for byte.- The package is signed in place, just like Authenticode files. The signed result is written back into the original file, so links, ACLs and other file metadata stay.
- Fully managed. It doesn't need
mssign32/SIP, and it only builds fornet8.0and later (#if NET).-
Programsends each file to the matching signer and only creates the signers the input files need.--skip-signedworks for packages.## NuGet-specific rules
These are checked up front, with clear error messages:
-
--file-digestand--timestamp-digestmust be SHA256/384/512. SHA1 is rejected.- Only RFC 3161 timestamps (
-tr).-t(Authenticode timestamp) is rejected.-
--append-signatureis rejected, because a package can only have one author signature. An existing signature is replaced unless--skip-signedis used.-
--description,--description-urland the page hashing options have no effect on packages.- ZIP64 packages are rejected.
The README has a new "NuGet Packages" section covering these.
## Other changes
- Certificate chain building moved into a shared internal
CertificateChainBuilder, used by both signers.AlgorithmTranslatorgainedHashAlgorithmToOidso there is one hash-OID table.- Timestamp requests for packages use a 30s timeout and up to 3 attempts on transient failures (timeout, 429, 5xx, connection errors). Ctrl+C cancels them.
## Dependencies
- Added
System.Security.Cryptography.PkcstoAzureSign.Corefornet8.0(MIT).- Added
NuGet.Packagingto the test project only (Apache-2.0), so tests can verify signatures with NuGet's own verifier.- Updated packages to their latest versions.
System.Security.Cryptography.Pkcs10.0.6 has known advisories (GHSA-846f-f764-76mx, GHSA-2fmv-rv2c-59x7). xunit.v3 4.x runs on Microsoft Testing Platform, so aglobal.jsonoptsdotnet testinto it. I'm happy to move the non-Pkcs updates into a separate PR if you prefer.## Testing
**Unit tests:** all 78 pass (
dotnet test). There are 29 new NuGet tests covering:- Signing with every RSA test certificate and SHA256/384/512, re-signing an already-signed package,
.snupkg, and timestamping (DigiCert, like the existing Authenticode tests).- Verification with NuGet's own
PackageSignatureVerifier(integrity plus signature trust and validity, with untrusted roots allowed for the test certificates). The tests also check that every original entry is unchanged.- Edge cases: archive comments are kept, a
.signature.p7sentry with the UTF-8 flag set is detected, a locked package isn't reported as signed, and a read-only package fails without being modified.- Rejecting SHA1, Authenticode timestamps and ECDSA keys.
**Manual end-to-end test:** a real package signed with an EV code signing certificate in Azure Key Vault, then checked with
dotnet nuget verify. Identifying details are redacted:## Notes
-
NuGetKeyVaultSigneris a new public type inAzureSign.Core.AuthenticodeKeyVaultSigner's public API is unchanged.- The signer is fully managed, but
azuresigntoolstill only runs on Windows. I didn't change that in this PR.## Disclosure
I used AI to help with the code but I manually tested everything