Add GPG signature verification on manifest load

- Implement gpgVerify function that creates a temporary keyring to verify
  detached signatures against embedded public keys
- Signature verification happens during deserialization after hash
  validation but before decompression
- Extract signatureString() as a method on manifest for generating the
  canonical signature string (MAGIC-UUID-MULTIHASH)
- Add --require-signature flag to check command to mandate signature from
  a specific GPG key ID
- Expose IsSigned() and Signer() methods on Checker for signature status
This commit is contained in:
2025-12-18 05:28:35 -08:00
parent 213364bab5
commit 4a2060087d
8 changed files with 269 additions and 16 deletions

View File

@@ -4,6 +4,7 @@ import (
"bytes"
"crypto/sha256"
"errors"
"fmt"
"io"
"github.com/google/uuid"
@@ -45,10 +46,28 @@ func (m *manifest) deserializeInner() error {
if _, err := h.Write(m.pbOuter.InnerMessage); err != nil {
return err
}
if !bytes.Equal(h.Sum(nil), m.pbOuter.Sha256) {
sha256Hash := h.Sum(nil)
if !bytes.Equal(sha256Hash, m.pbOuter.Sha256) {
return errors.New("compressed data hash mismatch")
}
// Verify signature if present
if len(m.pbOuter.Signature) > 0 {
if len(m.pbOuter.SigningPubKey) == 0 {
return errors.New("signature present but no public key")
}
sigString, err := m.signatureString()
if err != nil {
return fmt.Errorf("failed to generate signature string for verification: %w", err)
}
if err := gpgVerify([]byte(sigString), m.pbOuter.Signature, m.pbOuter.SigningPubKey); err != nil {
return fmt.Errorf("signature verification failed: %w", err)
}
log.Infof("signature verified successfully")
}
bb := bytes.NewBuffer(m.pbOuter.InnerMessage)
zr, err := zstd.NewReader(bb)