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:
111
mfer/gpg_test.go
111
mfer/gpg_test.go
@@ -210,6 +210,117 @@ func TestScannerWithSigning(t *testing.T) {
|
||||
assert.NotEmpty(t, manifest.pbOuter.SigningPubKey)
|
||||
}
|
||||
|
||||
func TestGPGVerify(t *testing.T) {
|
||||
keyID, cleanup := testGPGEnv(t)
|
||||
defer cleanup()
|
||||
|
||||
data := []byte("test data to sign and verify")
|
||||
sig, err := gpgSign(data, keyID)
|
||||
require.NoError(t, err)
|
||||
|
||||
pubKey, err := gpgExportPublicKey(keyID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Verify the signature
|
||||
err = gpgVerify(data, sig, pubKey)
|
||||
require.NoError(t, err)
|
||||
}
|
||||
|
||||
func TestGPGVerifyInvalidSignature(t *testing.T) {
|
||||
keyID, cleanup := testGPGEnv(t)
|
||||
defer cleanup()
|
||||
|
||||
data := []byte("test data to sign")
|
||||
sig, err := gpgSign(data, keyID)
|
||||
require.NoError(t, err)
|
||||
|
||||
pubKey, err := gpgExportPublicKey(keyID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Try to verify with different data - should fail
|
||||
wrongData := []byte("different data")
|
||||
err = gpgVerify(wrongData, sig, pubKey)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestGPGVerifyBadPublicKey(t *testing.T) {
|
||||
keyID, cleanup := testGPGEnv(t)
|
||||
defer cleanup()
|
||||
|
||||
data := []byte("test data")
|
||||
sig, err := gpgSign(data, keyID)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Try to verify with invalid public key - should fail
|
||||
badPubKey := []byte("not a valid public key")
|
||||
err = gpgVerify(data, sig, badPubKey)
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestManifestSignatureVerification(t *testing.T) {
|
||||
keyID, cleanup := testGPGEnv(t)
|
||||
defer cleanup()
|
||||
|
||||
// Create a builder with signing options
|
||||
b := NewBuilder()
|
||||
b.SetSigningOptions(&SigningOptions{
|
||||
KeyID: keyID,
|
||||
})
|
||||
|
||||
// Add a test file
|
||||
content := []byte("test file content for verification")
|
||||
reader := bytes.NewReader(content)
|
||||
_, err := b.AddFile("test.txt", FileSize(len(content)), ModTime{}, reader, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Build the manifest
|
||||
var buf bytes.Buffer
|
||||
err = b.Build(&buf)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Parse the manifest - signature should be verified during load
|
||||
manifest, err := NewManifestFromReader(&buf)
|
||||
require.NoError(t, err)
|
||||
require.NotNil(t, manifest)
|
||||
|
||||
// Signature should be present and valid
|
||||
assert.NotEmpty(t, manifest.pbOuter.Signature)
|
||||
}
|
||||
|
||||
func TestManifestTamperedSignatureFails(t *testing.T) {
|
||||
keyID, cleanup := testGPGEnv(t)
|
||||
defer cleanup()
|
||||
|
||||
// Create a signed manifest
|
||||
b := NewBuilder()
|
||||
b.SetSigningOptions(&SigningOptions{
|
||||
KeyID: keyID,
|
||||
})
|
||||
|
||||
content := []byte("test file content")
|
||||
reader := bytes.NewReader(content)
|
||||
_, err := b.AddFile("test.txt", FileSize(len(content)), ModTime{}, reader, nil)
|
||||
require.NoError(t, err)
|
||||
|
||||
var buf bytes.Buffer
|
||||
err = b.Build(&buf)
|
||||
require.NoError(t, err)
|
||||
|
||||
// Tamper with the signature by replacing some bytes
|
||||
data := buf.Bytes()
|
||||
// Find and modify a byte in the signature portion
|
||||
for i := range data {
|
||||
if i > 100 && data[i] == 'A' {
|
||||
data[i] = 'B'
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
// Try to load the tampered manifest - should fail
|
||||
_, err = NewManifestFromReader(bytes.NewReader(data))
|
||||
assert.Error(t, err)
|
||||
}
|
||||
|
||||
func TestBuilderWithoutSigning(t *testing.T) {
|
||||
// Create a builder without signing options
|
||||
b := NewBuilder()
|
||||
|
||||
Reference in New Issue
Block a user