// 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 }
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 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 }