diff --git a/metadata/keys.go b/metadata/keys.go index c6b14880..9290d7b9 100644 --- a/metadata/keys.go +++ b/metadata/keys.go @@ -78,6 +78,10 @@ func (k *Key) ToPublicKey() (crypto.PublicKey, error) { if err != nil { return nil, err } + // ed25519.Verify panics on a wrong-length public key + if len(publicKey) != ed25519.PublicKeySize { + return nil, fmt.Errorf("invalid ed25519 public key length %d, expected %d", len(publicKey), ed25519.PublicKeySize) + } ed25519Key := ed25519.PublicKey(publicKey) // done for verification - ref. https://github.com/theupdateframework/go-tuf/pull/357 if _, err := x509.MarshalPKIXPublicKey(ed25519Key); err != nil { diff --git a/metadata/metadata_test.go b/metadata/metadata_test.go index 13838644..24d13cf1 100644 --- a/metadata/metadata_test.go +++ b/metadata/metadata_test.go @@ -858,3 +858,25 @@ func TestTargetFilesEmptyHashesRejected(t *testing.T) { assert.Error(t, err) assert.Contains(t, err.Error(), "hashes must not be empty") } + +func TestToPublicKeyEd25519InvalidLength(t *testing.T) { + // A valid-hex but wrong-length ed25519 public key must be rejected: a + // non-32-byte key panics in ed25519.Verify during delegate verification. + key := &Key{ + Type: KeyTypeEd25519, + Scheme: KeySchemeEd25519, + Value: KeyVal{PublicKey: "abcd"}, // decodes to 2 bytes + } + + _, err := key.ToPublicKey() + assert.ErrorContains(t, err, "invalid ed25519 public key length") + + // And it must not panic when reached through VerifyDelegate. + root := Root(time.Now().AddDate(1, 0, 0).UTC()) + err = root.Signed.AddKey(key, ROOT) + assert.NoError(t, err) + assert.NotPanics(t, func() { + err = root.VerifyDelegate(ROOT, root) + }) + assert.Error(t, err) +}