Some checks failed
Go package / build (push) Has been cancelled
- Reject RPM, Debian, and Arch metadata that fails the configured signature policy before trusting its checksums or package paths. - Preserve the last verified repository generation when signed metadata rotates inconsistently or required files remain unavailable. - Let operators pin signer keyrings or retrieve unknown issuers from configured keyservers, including archived GnuPG v1 RSA signatures. - Gate cached server entry points and package misses until a crawl completes under the active signature policy.
80 lines
2.7 KiB
Go
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)
|
|
}
|