repo-sync/mirror/signature_test.go
James Coleman 67c64a084d
Some checks are pending
Go package / build (push) Waiting to run
Verify repository OpenPGP signatures
2026-09-01 18:22:04 -05:00

80 lines
2.7 KiB
Go

package mirror
import (
"bytes"
"context"
"crypto"
"crypto/rand"
"crypto/rsa"
"encoding/binary"
"math/big"
"os"
"path/filepath"
"testing"
"github.com/ProtonMail/go-crypto/openpgp"
"github.com/ProtonMail/go-crypto/openpgp/armor"
"github.com/ProtonMail/go-crypto/openpgp/packet"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TestVerifyLegacyDetachedSignature locks the OpenPGP version 3 RSA packet
// shape used by GnuPG v1 to sign archived CentOS 7 repomd.xml files.
func TestVerifyLegacyDetachedSignature(t *testing.T) {
entity, err := openpgp.NewEntity("CentOS fixture", "", "security@example.com", nil)
require.NoError(t, err)
privateKey, ok := entity.PrivateKey.PrivateKey.(*rsa.PrivateKey)
require.True(t, ok)
data := []byte("signed repository metadata\n")
hashed := make([]byte, 5)
hashed[0] = byte(packet.SigTypeBinary)
binary.BigEndian.PutUint32(hashed[1:], 1678292750)
h := crypto.SHA256.New()
_, _ = h.Write(data)
_, _ = h.Write(hashed)
digest := h.Sum(nil)
rsaSignature, err := rsa.SignPKCS1v15(rand.Reader, privateKey, crypto.SHA256, digest)
require.NoError(t, err)
mpi := new(big.Int).SetBytes(rsaSignature)
mpiBytes := mpi.Bytes()
body := []byte{3, 5}
body = append(body, hashed...)
body = binary.BigEndian.AppendUint64(body, entity.PrimaryKey.KeyId)
body = append(body, byte(packet.PubKeyAlgoRSA), 8, digest[0], digest[1])
body = binary.BigEndian.AppendUint16(body, uint16(mpi.BitLen()))
body = append(body, mpiBytes...)
var packetData bytes.Buffer
require.NoError(t, (&packet.OpaquePacket{Tag: 2, Contents: body}).Serialize(&packetData))
var signature bytes.Buffer
armoredSignature, err := armor.Encode(&signature, openpgp.SignatureType, nil)
require.NoError(t, err)
_, err = armoredSignature.Write(packetData.Bytes())
require.NoError(t, err)
require.NoError(t, armoredSignature.Close())
var publicKey bytes.Buffer
armoredKey, err := armor.Encode(&publicKey, openpgp.PublicKeyType, nil)
require.NoError(t, err)
require.NoError(t, entity.Serialize(armoredKey))
require.NoError(t, armoredKey.Close())
dir := t.TempDir()
dataPath := filepath.Join(dir, "repomd.xml")
sigPath := dataPath + ".asc"
keyPath := dataPath + ".key"
require.NoError(t, os.WriteFile(dataPath, data, 0644))
require.NoError(t, os.WriteFile(sigPath, signature.Bytes(), 0644))
require.NoError(t, os.WriteFile(keyPath, publicKey.Bytes(), 0644))
verifier := &signatureVerifier{}
fingerprint, err := verifier.verifyDetached(context.Background(), dataPath, sigPath, keyPath)
require.NoError(t, err)
assert.NotEmpty(t, fingerprint)
require.NoError(t, os.WriteFile(dataPath, []byte("modified repository metadata\n"), 0644))
_, err = verifier.verifyDetached(context.Background(), dataPath, sigPath, keyPath)
assert.Error(t, err)
}