Compare commits
1
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e00ec787e8 |
No files matched your search
+2
-3
@@ -153,9 +153,8 @@ that key (or one of its subkeys), and `signer` is that key's fingerprint. The
|
|||||||
reference implementation refuses to load a manifest that fails these checks;
|
reference implementation refuses to load a manifest that fails these checks;
|
||||||
`check` and `fetch` given `--require-signature` then compare the required
|
`check` and `fetch` given `--require-signature` then compare the required
|
||||||
fingerprint with `signer`. It also refuses a manifest whose `signingPubKey`
|
fingerprint with `signer`. It also refuses a manifest whose `signingPubKey`
|
||||||
holds a DSA key or subkey, or any secret key or subkey, since checking the
|
holds a DSA key or subkey, since checking the self-signatures of a DSA key with
|
||||||
self-signatures of a DSA key or the numbers of a secret key can take hours when
|
very large numbers can take hours.
|
||||||
those numbers are very large.
|
|
||||||
|
|
||||||
## Deterministic Serialization
|
## Deterministic Serialization
|
||||||
|
|
||||||
|
|||||||
+7
-20
@@ -46,7 +46,6 @@ const (
|
|||||||
var (
|
var (
|
||||||
errKeyCount = errors.New("must hold exactly one key")
|
errKeyCount = errors.New("must hold exactly one key")
|
||||||
errDSAKey = errors.New("must not hold a DSA key")
|
errDSAKey = errors.New("must not hold a DSA key")
|
||||||
errSecretKey = errors.New("must not hold a secret key")
|
|
||||||
errNoSecretKey = errors.New("signing key file holds no secret key")
|
errNoSecretKey = errors.New("signing key file holds no secret key")
|
||||||
errNotV4Key = errors.New("signing key must be an OpenPGP version 4 key, " +
|
errNotV4Key = errors.New("signing key must be an OpenPGP version 4 key, " +
|
||||||
"the only kind whose fingerprint --require-signature takes")
|
"the only kind whose fingerprint --require-signature takes")
|
||||||
@@ -127,7 +126,7 @@ func readSigningKey(opts *SigningOptions) (*openpgp.Entity, error) {
|
|||||||
// readSecretKey returns the one key in secretKey, armored or binary,
|
// readSecretKey returns the one key in secretKey, armored or binary,
|
||||||
// which must be a version 4 key and include its secret key.
|
// which must be a version 4 key and include its secret key.
|
||||||
func readSecretKey(secretKey []byte) (*openpgp.Entity, error) {
|
func readSecretKey(secretKey []byte) (*openpgp.Entity, error) {
|
||||||
key, err := readOneKey(secretKey, "signing key file", false)
|
key, err := readOneKey(secretKey, "signing key file")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@@ -145,9 +144,9 @@ func readSecretKey(secretKey []byte) (*openpgp.Entity, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// readOneKey returns the key in data, armored or binary, which must hold
|
// readOneKey returns the key in data, armored or binary, which must hold
|
||||||
// exactly one primary key and no DSA key or subkey, and when publicOnly no
|
// exactly one primary key and no DSA key or subkey. what names data in
|
||||||
// secret key or subkey either. what names data in errors.
|
// errors.
|
||||||
func readOneKey(data []byte, what string, publicOnly bool) (*openpgp.Entity, error) {
|
func readOneKey(data []byte, what string) (*openpgp.Entity, error) {
|
||||||
packets, err := dearmor(data)
|
packets, err := dearmor(data)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read %s: %w", what, err)
|
return nil, fmt.Errorf("read %s: %w", what, err)
|
||||||
@@ -162,20 +161,8 @@ func readOneKey(data []byte, what string, publicOnly bool) (*openpgp.Entity, err
|
|||||||
return nil, fmt.Errorf("%s %w, found %d", what, errKeyCount, keys)
|
return nil, fmt.Errorf("%s %w, found %d", what, errKeyCount, keys)
|
||||||
}
|
}
|
||||||
|
|
||||||
// openpgp.ReadKeyRing checks the numbers of every secret key it reads,
|
// openpgp.ReadKeyRing checks every self-signature, and a DSA key with
|
||||||
// and an ElGamal secret subkey with a very large prime makes that take
|
// very large numbers makes each check take seconds to minutes.
|
||||||
// minutes.
|
|
||||||
secretKeys, err := countPackets(packets, secretKeyPacketTag, secretSubkeyPacketTag)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("read %s: %w", what, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if publicOnly && secretKeys != 0 {
|
|
||||||
return nil, fmt.Errorf("%s %w", what, errSecretKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
// openpgp.ReadKeyRing also checks every self-signature, and a DSA key
|
|
||||||
// with very large numbers makes each check take seconds to minutes.
|
|
||||||
dsa, err := holdsDSAKey(packets)
|
dsa, err := holdsDSAKey(packets)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, fmt.Errorf("read %s: %w", what, err)
|
return nil, fmt.Errorf("read %s: %w", what, err)
|
||||||
@@ -247,7 +234,7 @@ func fingerprint(key *openpgp.Entity) string {
|
|||||||
// and returns that primary key's fingerprint. signature and pubKey may each
|
// and returns that primary key's fingerprint. signature and pubKey may each
|
||||||
// be armored or binary.
|
// be armored or binary.
|
||||||
func verifySignature(data, signature, pubKey []byte) (string, error) {
|
func verifySignature(data, signature, pubKey []byte) (string, error) {
|
||||||
key, err := readOneKey(pubKey, "embedded public key block", true)
|
key, err := readOneKey(pubKey, "embedded public key block")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return "", err
|
return "", err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,7 +17,6 @@ import (
|
|||||||
|
|
||||||
"github.com/ProtonMail/go-crypto/openpgp"
|
"github.com/ProtonMail/go-crypto/openpgp"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/armor"
|
"github.com/ProtonMail/go-crypto/openpgp/armor"
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/elgamal"
|
|
||||||
"github.com/ProtonMail/go-crypto/openpgp/packet"
|
"github.com/ProtonMail/go-crypto/openpgp/packet"
|
||||||
"github.com/spf13/afero"
|
"github.com/spf13/afero"
|
||||||
"github.com/stretchr/testify/assert"
|
"github.com/stretchr/testify/assert"
|
||||||
@@ -608,54 +607,6 @@ func TestManifestRefusesDSAKey(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// elGamalSecretSubkeyPacket returns a secret subkey packet holding an
|
|
||||||
// ElGamal key. Its numbers are not a working key: loading must refuse the
|
|
||||||
// packet before it uses them.
|
|
||||||
func elGamalSecretSubkeyPacket(t *testing.T) []byte {
|
|
||||||
t.Helper()
|
|
||||||
|
|
||||||
key := packet.NewElGamalPrivateKey(time.Now(), &elgamal.PrivateKey{
|
|
||||||
P: big.NewInt(23), G: big.NewInt(4), Y: big.NewInt(8), X: big.NewInt(3),
|
|
||||||
})
|
|
||||||
key.IsSubkey = true
|
|
||||||
|
|
||||||
var buf bytes.Buffer
|
|
||||||
|
|
||||||
require.NoError(t, key.Serialize(&buf))
|
|
||||||
|
|
||||||
return buf.Bytes()
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestManifestRefusesSecretKey loads manifests whose embedded public key
|
|
||||||
// block holds a secret key: the key that signed the manifest with its
|
|
||||||
// secret key, or its public key followed by an ElGamal secret subkey.
|
|
||||||
// openpgp.ReadKeyRing checks the numbers of every secret key it reads,
|
|
||||||
// which for an ElGamal key with a very large prime takes minutes. Loading
|
|
||||||
// must refuse each block before that.
|
|
||||||
func TestManifestRefusesSecretKey(t *testing.T) {
|
|
||||||
t.Parallel()
|
|
||||||
|
|
||||||
signer := newTestKey(t, nil)
|
|
||||||
manifest := signedTestManifest(t,
|
|
||||||
&SigningOptions{SecretKey: armoredSecretKeys(t, signer)})
|
|
||||||
|
|
||||||
var signerKey bytes.Buffer
|
|
||||||
|
|
||||||
require.NoError(t, signer.Serialize(&signerKey))
|
|
||||||
|
|
||||||
for _, block := range [][]byte{
|
|
||||||
armoredSecretKeys(t, signer),
|
|
||||||
slices.Concat(signerKey.Bytes(), elGamalSecretSubkeyPacket(t)),
|
|
||||||
} {
|
|
||||||
embedded := rewriteOuter(t, manifest, func(outer *MFFileOuter) {
|
|
||||||
outer.SigningPubKey = block
|
|
||||||
})
|
|
||||||
|
|
||||||
_, err := NewManifestFromReader(bytes.NewReader(embedded))
|
|
||||||
require.ErrorIs(t, err, errSecretKey)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// TestManifestRefusesTwoSignatures loads a manifest whose signature field
|
// TestManifestRefusesTwoSignatures loads a manifest whose signature field
|
||||||
// holds its good signature twice, not armored. Loading must refuse it.
|
// holds its good signature twice, not armored. Loading must refuse it.
|
||||||
func TestManifestRefusesTwoSignatures(t *testing.T) {
|
func TestManifestRefusesTwoSignatures(t *testing.T) {
|
||||||
|
|||||||
Reference in new issue
Block a user