manifest: extend signing payload to cover the whole manifest - #34
Merged
TeoSlayer merged 1 commit intoJul 26, 2026
Merged
Conversation
The v1 signing payload was built from Store.Publisher, ID, ManifestVersion, Binary.SHA256 and a hash of Grants. Every other field — Binary.Path, Binary.Runtime, Exposes, Protection, Affiliates, Depends, Extends, DynamicExtends, AppVersion — sat outside the signed bytes and could be edited without disturbing the signature, even though several of them decide what the app is allowed to do (exec path, IPC entrypoints, hook points, co-trusted peers, storage protection). Add a v2 payload that commits to the publisher key plus a sha256 over the canonical JSON of the manifest with Store.Signature blanked, under the domain-separation tag "pilot.app-manifest.v2". Compatibility: VerifySignature tries v2 first and falls back to v1 while AllowLegacySignaturePayload is true, which is the default, so every manifest signed under the old scheme keeps verifying and no installed app is affected. Setting the flag to false accepts v2 only. New signatures are produced by the new Manifest.Sign / Manifest.SigningPayload helpers, which emit v2. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
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.
What
The manifest signing payload (
signingPayload,manifest.go:188-197) was built from only five inputs:Store.Publisher : ID : ManifestVersion : Binary.SHA256 : sha256(Grants)Everything else in the manifest sat outside the signed bytes and could be edited without disturbing the signature:
Binary.PathBinary.RuntimeExposesProtectionshareablevsguardedstorage/process isolationAffiliatesDependsExtendsDynamicExtendsAppVersionChange
Adds a v2 payload that commits to the entire manifest:
Blanking
store.signatureis what makes the hash reproducible on both sides. The domain-separation prefix keeps v1 and v2 payload bytes disjoint, so a signature for one scheme can never verify under the other.New exported helpers:
Manifest.SigningPayload()(returns v2 bytes) andManifest.Sign(priv)(signs v2, refuses a key that does not matchStore.Publisher).Compatibility — nothing breaks now
VerifySignaturetries v2 first, then falls back to v1 whileAllowLegacySignaturePayloadistrue. That flag defaults totrue, so every already-signed manifest in the wild keeps verifying and no installed app is disturbed. Existing signing code paths (includingplugin/appstoretest helpers, which still sign v1) are untouched and still pass. Flipping the flag tofalsemoves to v2-only.Tests
New
pkg/manifest/zz3_signing_payload_test.go:TestV2PayloadCoversWholeManifest— 16 sub-cases, one per field listed above plus the fields v1 already covered; each mutation must break verification.TestV1SignatureStillVerifies— v1 signatures verify with the default flag.TestLegacyFallbackCanBeDisabled— flag off rejects v1, still accepts v2.TestV1PayloadLeavesFieldsUnsigned— pins the exact v1/v2 delta.TestSigningPayloadIndependentOfSignatureField— payload stable regardless ofstore.signature, and computing it does not mutate the manifest.TestSignRejectsMismatchedPublisher,TestV2SignatureIsNotAcceptedForAnotherPublisher.go build ./...,go vet ./...andgo test ./...all green.🤖 Generated with Claude Code