Skip to content

Commit

Permalink
feat: implement TAP-12 support
Browse files Browse the repository at this point in the history
Main changes:

- allow IDs that aren't the SHA2 of the public key
- but disallow multiple distinct keys with the same ID
- test for TAP-12 compliance
  - Adding keys should disallow different keys with the same ID, but allow everything else
  - Verification should ensure that we have unique keys for each signature

Fixes #232.
  • Loading branch information
znewman01 committed Jun 8, 2022
1 parent fa0d956 commit 52e27a1
Show file tree
Hide file tree
Showing 5 changed files with 63 additions and 43 deletions.
20 changes: 2 additions & 18 deletions client/client.go
Expand Up @@ -499,15 +499,7 @@ func (c *Client) loadAndVerifyRootMeta(rootJSON []byte, ignoreExpiredCheck bool)
ndb := verify.NewDB()
for id, k := range root.Keys {
if err := ndb.AddKey(id, k); err != nil {
// TUF is considering in TAP-12 removing the
// requirement that the keyid hash algorithm be derived
// from the public key. So to be forwards compatible,
// we ignore `ErrWrongID` errors.
//
// TAP-12: https://github.com/theupdateframework/taps/blob/master/tap12.md
if _, ok := err.(verify.ErrWrongID); !ok {
return err
}
return err
}
}
for name, role := range root.Roles {
Expand Down Expand Up @@ -555,15 +547,7 @@ func (c *Client) verifyRoot(aJSON []byte, bJSON []byte) (*data.Root, error) {
ndb := verify.NewDB()
for id, k := range aRoot.Keys {
if err := ndb.AddKey(id, k); err != nil {
// TUF is considering in TAP-12 removing the
// requirement that the keyid hash algorithm be derived
// from the public key. So to be forwards compatible,
// we ignore `ErrWrongID` errors.
//
// TAP-12: https://github.com/theupdateframework/taps/blob/master/tap12.md
if _, ok := err.(verify.ErrWrongID); !ok {
return nil, err
}
return nil, err
}
}
for name, role := range aRoot.Roles {
Expand Down
10 changes: 1 addition & 9 deletions repo.go
Expand Up @@ -103,15 +103,7 @@ func (r *Repo) topLevelKeysDB() (*verify.DB, error) {
}
for id, k := range root.Keys {
if err := db.AddKey(id, k); err != nil {
// TUF is considering in TAP-12 removing the
// requirement that the keyid hash algorithm be derived
// from the public key. So to be forwards compatible,
// we ignore `ErrWrongID` errors.
//
// TAP-12: https://github.com/theupdateframework/taps/blob/master/tap12.md
if _, ok := err.(verify.ErrWrongID); !ok {
return nil, err
}
return nil, err
}
}
for name, role := range root.Roles {
Expand Down
19 changes: 13 additions & 6 deletions verify/db.go
Expand Up @@ -53,13 +53,23 @@ func NewDBFromDelegations(d *data.Delegations) (*DB, error) {
}

func (db *DB) AddKey(id string, k *data.PublicKey) error {
if !k.ContainsID(id) {
return ErrWrongID{}
}
verifier, err := keys.GetVerifier(k)
if err != nil {
return ErrInvalidKey
}

// TUF is considering in TAP-12 removing the
// requirement that the keyid hash algorithm be derived
// from the public key. So to be forwards compatible,
// we allow any key ID, rather than checking k.ContainsID(id)
//
// AddKey should be idempotent, so we allow re-adding the same PublicKey.
//
// TAP-12: https://github.com/theupdateframework/taps/blob/master/tap12.md
if oldVerifier, exists := db.verifiers[id]; exists && oldVerifier.Public() != verifier.Public() {
return ErrRepeatID{}
}

db.verifiers[id] = verifier
return nil
}
Expand All @@ -74,9 +84,6 @@ func (db *DB) AddRole(name string, r *data.Role) error {
Threshold: r.Threshold,
}
for _, id := range r.KeyIDs {
if len(id) != data.KeyIDLength {
return ErrInvalidKeyID
}
role.KeyIDs[id] = struct{}{}
}

Expand Down
51 changes: 44 additions & 7 deletions verify/db_test.go
Expand Up @@ -5,6 +5,7 @@ import (

"github.com/stretchr/testify/assert"
"github.com/theupdateframework/go-tuf/data"
"github.com/theupdateframework/go-tuf/pkg/keys"
)

func TestDelegationsDB(t *testing.T) {
Expand Down Expand Up @@ -33,13 +34,6 @@ func TestDelegationsDB(t *testing.T) {
}},
initErr: ErrInvalidThreshold,
},
{
testName: "invalid keys",
delegations: &data.Delegations{Keys: map[string]*data.PublicKey{
"a": {Type: data.KeySchemeEd25519},
}},
initErr: ErrWrongID{},
},
}

for _, tt := range dbTests {
Expand All @@ -55,3 +49,46 @@ func TestDelegationsDB(t *testing.T) {
})
}
}

// Test key database for compliance with TAP-12.
//
// Previously, every key's key ID was the SHA256 of the public key. TAP-12
// allows arbitrary key IDs, with no loss in security.
//
//
// TAP-12: https://github.com/theupdateframework/taps/blob/master/tap12.md
func TestTAP12(t *testing.T) {
db := NewDB()
// Need to use a signer type that supports random signatures.
key1, _ := keys.GenerateRsaKey()
key2, _ := keys.GenerateRsaKey()
msg := []byte("{}")
sig1, _ := key1.SignMessage(msg)
sig1Duplicate, _ := key1.SignMessage(msg)
assert.NotEqual(t, sig1, sig1Duplicate, "Signatures should be random")
sig2, _ := key2.SignMessage(msg)

// Idempotent: adding the same key with the same ID is okay.
assert.Nil(t, db.AddKey("key1", key1.PublicData()), "initial add")
assert.Nil(t, db.AddKey("key1", key1.PublicData()), "re-add")
// Adding a different key is allowed, unless the key ID is the same.
assert.Nil(t, db.AddKey("key2", key2.PublicData()), "different key with different ID")
assert.ErrorIs(t, db.AddKey("key1", key2.PublicData()), ErrRepeatID{}, "different key with same key ID")
assert.Nil(t, db.AddKey("key1-duplicate", key1.PublicData()), "same key with different ID should succeed")
assert.Nil(t, db.AddRole("diffkeys", &data.Role{
KeyIDs: []string{"key1", "key2"},
Threshold: 2,
}), "adding role")
assert.Nil(t, db.AddRole("samekeys", &data.Role{
KeyIDs: []string{"key1", "key1-alt"},
Threshold: 2,
}), "adding role")
assert.Nil(t, db.VerifySignatures(&data.Signed{
Signed: msg,
Signatures: []data.Signature{{KeyID: "key1", Signature: sig1}, {KeyID: "key2", Signature: sig2}},
}, "diffkeys"), "Signature with different keys: ")
assert.ErrorIs(t, db.VerifySignatures(&data.Signed{
Signed: msg,
Signatures: []data.Signature{{KeyID: "key1", Signature: sig1}, {KeyID: "key1-alt", Signature: sig1Duplicate}},
}, "samekeys"), ErrRoleThreshold{2, 1}, "Threshold signing with repeat key")
}
6 changes: 3 additions & 3 deletions verify/errors.go
Expand Up @@ -21,10 +21,10 @@ var (
ErrMissingTargetFile = errors.New("tuf: missing previously listed targets metadata file")
)

type ErrWrongID struct{}
type ErrRepeatID struct{}

func (ErrWrongID) Error() string {
return "tuf: key id mismatch"
func (ErrRepeatID) Error() string {
return "tuf: duplicate key id"
}

type ErrUnknownRole struct {
Expand Down

0 comments on commit 52e27a1

Please sign in to comment.