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:
@@ -3,14 +3,12 @@ package mfer
|
||||
import (
|
||||
"bytes"
|
||||
"crypto/sha256"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/klauspost/compress/zstd"
|
||||
"github.com/multiformats/go-multihash"
|
||||
"google.golang.org/protobuf/proto"
|
||||
)
|
||||
|
||||
@@ -82,7 +80,7 @@ func (m *manifest) generateOuter() error {
|
||||
}
|
||||
sha256Hash := h.Sum(nil)
|
||||
|
||||
o := &MFFileOuter{
|
||||
m.pbOuter = &MFFileOuter{
|
||||
InnerMessage: compressedData,
|
||||
Size: int64(len(innerData)),
|
||||
Sha256: sha256Hash,
|
||||
@@ -93,36 +91,29 @@ func (m *manifest) generateOuter() error {
|
||||
|
||||
// Sign the manifest if signing options are provided
|
||||
if m.signingOptions != nil && m.signingOptions.KeyID != "" {
|
||||
// Encode hash as multihash
|
||||
mh, err := multihash.Encode(sha256Hash, multihash.SHA2_256)
|
||||
sigString, err := m.signatureString()
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to encode multihash: %w", err)
|
||||
return fmt.Errorf("failed to generate signature string: %w", err)
|
||||
}
|
||||
|
||||
// Build signature string: MAGIC-UUID-MULTIHASH
|
||||
uuidStr := hex.EncodeToString(manifestUUID[:])
|
||||
mhStr := hex.EncodeToString(mh)
|
||||
sigString := fmt.Sprintf("%s-%s-%s", MAGIC, uuidStr, mhStr)
|
||||
|
||||
sig, err := gpgSign([]byte(sigString), m.signingOptions.KeyID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to sign manifest: %w", err)
|
||||
}
|
||||
o.Signature = sig
|
||||
m.pbOuter.Signature = sig
|
||||
|
||||
fingerprint, err := gpgGetKeyFingerprint(m.signingOptions.KeyID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to get key fingerprint: %w", err)
|
||||
}
|
||||
o.Signer = fingerprint
|
||||
m.pbOuter.Signer = fingerprint
|
||||
|
||||
pubKey, err := gpgExportPublicKey(m.signingOptions.KeyID)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to export public key: %w", err)
|
||||
}
|
||||
o.SigningPubKey = pubKey
|
||||
m.pbOuter.SigningPubKey = pubKey
|
||||
}
|
||||
|
||||
m.pbOuter = o
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user