// VerifySignatures checks the we have sufficient valid signatures for the given role func VerifySignatures(s *data.Signed, role string, db *keys.KeyDB) error { if len(s.Signatures) == 0 { return ErrNoSignatures } roleData := db.GetRole(role) if roleData == nil { return ErrUnknownRole } if roleData.Threshold < 1 { return ErrRoleThreshold{} } logrus.Debugf("%s role has key IDs: %s", role, strings.Join(roleData.KeyIDs, ",")) var decoded map[string]interface{} if err := json.Unmarshal(s.Signed, &decoded); err != nil { return err } msg, err := json.MarshalCanonical(decoded) if err != nil { return err } valid := make(map[string]struct{}) for _, sig := range s.Signatures { logrus.Debug("verifying signature for key ID: ", sig.KeyID) if !roleData.ValidKey(sig.KeyID) { logrus.Debugf("continuing b/c keyid was invalid: %s for roledata %s\n", sig.KeyID, roleData) continue } key := db.GetKey(sig.KeyID) if key == nil { logrus.Debugf("continuing b/c keyid lookup was nil: %s\n", sig.KeyID) continue } // method lookup is consistent due to Unmarshal JSON doing lower case for us. method := sig.Method verifier, ok := Verifiers[method] if !ok { logrus.Debugf("continuing b/c signing method is not supported: %s\n", sig.Method) continue } if err := verifier.Verify(key, sig.Signature, msg); err != nil { logrus.Debugf("continuing b/c signature was invalid\n") continue } valid[sig.KeyID] = struct{}{} } if len(valid) < roleData.Threshold { return ErrRoleThreshold{} } return nil }
// add a key to a KeyDB, and create a role for the key and add it. func addKeyForRole(kdb *keys.KeyDB, role string, key data.PublicKey) error { theRole, err := data.NewRole(role, 1, []string{key.ID()}, nil, nil) if err != nil { return err } kdb.AddKey(key) if err := kdb.AddRole(theRole); err != nil { return err } return nil }
func initRoles(kdb *keys.KeyDB, rootKey, targetsKey, snapshotKey, timestampKey data.PublicKey) error { rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil) if err != nil { return err } targetsRole, err := data.NewRole("targets", 1, []string{targetsKey.ID()}, nil, nil) if err != nil { return err } snapshotRole, err := data.NewRole("snapshot", 1, []string{snapshotKey.ID()}, nil, nil) if err != nil { return err } timestampRole, err := data.NewRole("timestamp", 1, []string{timestampKey.ID()}, nil, nil) if err != nil { return err } if err := kdb.AddRole(rootRole); err != nil { return err } if err := kdb.AddRole(targetsRole); err != nil { return err } if err := kdb.AddRole(snapshotRole); err != nil { return err } if err := kdb.AddRole(timestampRole); err != nil { return err } return nil }
func copyTimestampKey(t *testing.T, fromKeyDB *keys.KeyDB, toStore storage.MetaStore, gun string) { role := fromKeyDB.GetRole(data.CanonicalTimestampRole) assert.NotNil(t, role, "No timestamp role in the KeyDB") assert.Len(t, role.KeyIDs, 1, fmt.Sprintf( "Expected 1 timestamp key in timestamp role, got %d", len(role.KeyIDs))) pubTimestampKey := fromKeyDB.GetKey(role.KeyIDs[0]) assert.NotNil(t, pubTimestampKey, "Timestamp key specified by KeyDB role not in KeysDB") err := toStore.SetKey(gun, data.CanonicalTimestampRole, pubTimestampKey.Algorithm(), pubTimestampKey.Public()) assert.NoError(t, err) }
func initRepo(t *testing.T, cryptoService signed.CryptoService, keyDB *keys.KeyDB) *Repo { rootKey, err := cryptoService.Create("root", data.ED25519Key) assert.NoError(t, err) targetsKey, err := cryptoService.Create("targets", data.ED25519Key) assert.NoError(t, err) snapshotKey, err := cryptoService.Create("snapshot", data.ED25519Key) assert.NoError(t, err) timestampKey, err := cryptoService.Create("timestamp", data.ED25519Key) assert.NoError(t, err) keyDB.AddKey(rootKey) keyDB.AddKey(targetsKey) keyDB.AddKey(snapshotKey) keyDB.AddKey(timestampKey) rootRole := &data.Role{ Name: "root", RootRole: data.RootRole{ KeyIDs: []string{rootKey.ID()}, Threshold: 1, }, } targetsRole := &data.Role{ Name: "targets", RootRole: data.RootRole{ KeyIDs: []string{targetsKey.ID()}, Threshold: 1, }, } snapshotRole := &data.Role{ Name: "snapshot", RootRole: data.RootRole{ KeyIDs: []string{snapshotKey.ID()}, Threshold: 1, }, } timestampRole := &data.Role{ Name: "timestamp", RootRole: data.RootRole{ KeyIDs: []string{timestampKey.ID()}, Threshold: 1, }, } keyDB.AddRole(rootRole) keyDB.AddRole(targetsRole) keyDB.AddRole(snapshotRole) keyDB.AddRole(timestampRole) repo := NewRepo(keyDB, cryptoService) err = repo.InitRepo(false) assert.NoError(t, err) return repo }
func generateSnapshot(gun string, kdb *keys.KeyDB, repo *tuf.Repo, store storage.MetaStore) (*storage.MetaUpdate, error) { role := kdb.GetRole(data.CanonicalSnapshotRole) if role == nil { return nil, validation.ErrBadRoot{Msg: "root did not include snapshot role"} } algo, keyBytes, err := store.GetKey(gun, data.CanonicalSnapshotRole) if err != nil { return nil, validation.ErrBadHierarchy{Msg: "could not retrieve snapshot key. client must provide snapshot"} } foundK := data.NewPublicKey(algo, keyBytes) validKey := false for _, id := range role.KeyIDs { if id == foundK.ID() { validKey = true break } } if !validKey { return nil, validation.ErrBadHierarchy{ Missing: data.CanonicalSnapshotRole, Msg: "no snapshot was included in update and server does not hold current snapshot key for repository"} } currentJSON, err := store.GetCurrent(gun, data.CanonicalSnapshotRole) if err != nil { if _, ok := err.(storage.ErrNotFound); !ok { return nil, validation.ErrValidation{Msg: err.Error()} } } var sn *data.SignedSnapshot if currentJSON != nil { sn = new(data.SignedSnapshot) err := json.Unmarshal(currentJSON, sn) if err != nil { return nil, validation.ErrValidation{Msg: err.Error()} } err = repo.SetSnapshot(sn) if err != nil { return nil, validation.ErrValidation{Msg: err.Error()} } } else { // this will only occurr if no snapshot has ever been created for the repository err := repo.InitSnapshot() if err != nil { return nil, validation.ErrBadSnapshot{Msg: err.Error()} } } sgnd, err := repo.SignSnapshot(data.DefaultExpires(data.CanonicalSnapshotRole)) if err != nil { return nil, validation.ErrBadSnapshot{Msg: err.Error()} } sgndJSON, err := cjson.MarshalCanonical(sgnd) if err != nil { return nil, validation.ErrBadSnapshot{Msg: err.Error()} } return &storage.MetaUpdate{ Role: data.CanonicalSnapshotRole, Version: repo.Snapshot.Signed.Version, Data: sgndJSON, }, nil }