Compare --require-signature with the key that signed (closes #167)
check / check (push) Canceled after 0s
check / check (push) Canceled after 0s
check and fetch --require-signature compared the required fingerprint with the first key in the manifest's embedded public key block, while gpg accepted a good signature by any key in that block. Loading a signed manifest now refuses one whose embedded block holds more than one primary key, counted as gpg reads the block, or whose signer field is not the primary key fingerprint gpg reports for the signature. --require-signature compares with the signer field, which loading has checked. Signing names and embeds the key gpg reports it signed with, so a key ID matching several keys still writes a manifest that loads. docs/FORMAT.md states what a verifier checks. Model: opus-5-5
This commit was merged in pull request #171.
This commit is contained in:
+13
-3
@@ -7,6 +7,7 @@ import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"strings"
|
||||
|
||||
"github.com/klauspost/compress/zstd"
|
||||
"github.com/spf13/afero"
|
||||
@@ -28,6 +29,8 @@ var (
|
||||
errInvalidManifestPath = errors.New("manifest contains invalid path")
|
||||
errDecodedTooLarge = errors.New(
|
||||
"manifest would take too much memory to decode")
|
||||
errSignerNotSigningKey = errors.New(
|
||||
"signer is not the fingerprint of the key that made the signature")
|
||||
)
|
||||
|
||||
// validateUUID checks that the byte slice is the 16 bytes of a binary UUID.
|
||||
@@ -60,8 +63,10 @@ func (m *manifest) validateOuterHeader() error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// verifyOuterIntegrity checks the hash of the compressed payload and,
|
||||
// if a signature is present, verifies it against the embedded public key.
|
||||
// verifyOuterIntegrity checks the hash of the compressed payload and, if a
|
||||
// signature is present, verifies it against the embedded public key, which
|
||||
// must be one key, and checks that the signer field is that key's
|
||||
// fingerprint.
|
||||
func (m *manifest) verifyOuterIntegrity() error {
|
||||
h := sha256.New()
|
||||
|
||||
@@ -91,7 +96,7 @@ func (m *manifest) verifyOuterIntegrity() error {
|
||||
}
|
||||
|
||||
// Loading a manifest takes no context; gpgTimeout still bounds gpg.
|
||||
err = gpgVerify(
|
||||
signingKey, err := gpgVerify(
|
||||
context.Background(),
|
||||
[]byte(sigString),
|
||||
m.pbOuter.GetSignature(),
|
||||
@@ -101,6 +106,11 @@ func (m *manifest) verifyOuterIntegrity() error {
|
||||
return fmt.Errorf("signature verification failed: %w", err)
|
||||
}
|
||||
|
||||
if !strings.EqualFold(string(m.pbOuter.GetSigner()), signingKey) {
|
||||
return fmt.Errorf("%w: signer %q, signing key %s",
|
||||
errSignerNotSigningKey, m.pbOuter.GetSigner(), signingKey)
|
||||
}
|
||||
|
||||
log.Infof("signature verified successfully")
|
||||
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user