func writeRepo(t *testing.T, dir string, repo *Repo) { err := os.MkdirAll(dir, 0755) assert.NoError(t, err) signedRoot, err := repo.SignRoot(data.DefaultExpires("root")) assert.NoError(t, err) rootJSON, _ := json.Marshal(signedRoot) ioutil.WriteFile(dir+"/root.json", rootJSON, 0755) for r := range repo.Targets { signedTargets, err := repo.SignTargets(r, data.DefaultExpires("targets")) assert.NoError(t, err) targetsJSON, _ := json.Marshal(signedTargets) p := path.Join(dir, r+".json") parentDir := filepath.Dir(p) os.MkdirAll(parentDir, 0755) ioutil.WriteFile(p, targetsJSON, 0755) } signedSnapshot, err := repo.SignSnapshot(data.DefaultExpires("snapshot")) assert.NoError(t, err) snapshotJSON, _ := json.Marshal(signedSnapshot) ioutil.WriteFile(dir+"/snapshot.json", snapshotJSON, 0755) signedTimestamp, err := repo.SignTimestamp(data.DefaultExpires("timestamp")) assert.NoError(t, err) timestampJSON, _ := json.Marshal(signedTimestamp) ioutil.WriteFile(dir+"/timestamp.json", timestampJSON, 0755) }
func TestDownloadSnapshotHappy(t *testing.T) { repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) remoteStorage := store.NewMemoryStore(nil) client := NewClient(repo, remoteStorage, localStorage) // create and "upload" sample snapshot and timestamp signedOrig, err := repo.SignSnapshot(data.DefaultExpires("snapshot")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("snapshot", orig) assert.NoError(t, err) signedOrig, err = repo.SignTimestamp(data.DefaultExpires("timestamp")) assert.NoError(t, err) orig, err = json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("timestamp", orig) assert.NoError(t, err) err = client.downloadSnapshot() assert.NoError(t, err) }
func TestGetTimestampNewSnapshot(t *testing.T) { store := storage.NewMemStorage() crypto := signed.NewEd25519() snapshot := &data.SignedSnapshot{ Signed: data.Snapshot{ Expires: data.DefaultExpires(data.CanonicalSnapshotRole), }, } snapshot.Signed.Version = 0 snapJSON, _ := json.Marshal(snapshot) store.UpdateCurrent("gun", storage.MetaUpdate{Role: "snapshot", Version: 0, Data: snapJSON}) // create a key to be used by GetTimestamp _, err := GetOrCreateTimestampKey("gun", store, crypto, data.ED25519Key) assert.Nil(t, err, "GetKey errored") ts1, err := GetOrCreateTimestamp("gun", store, crypto) assert.Nil(t, err, "GetTimestamp errored") snapshot = &data.SignedSnapshot{ Signed: data.Snapshot{ Expires: data.DefaultExpires(data.CanonicalSnapshotRole), }, } snapshot.Signed.Version = 1 snapJSON, _ = json.Marshal(snapshot) store.UpdateCurrent("gun", storage.MetaUpdate{Role: "snapshot", Version: 1, Data: snapJSON}) ts2, err := GetOrCreateTimestamp("gun", store, crypto) assert.NoError(t, err, "GetTimestamp errored") assert.NotEqual(t, ts1, ts2, "Timestamp was not regenerated when snapshot changed") }
func TestValidateTargetsRoleNotInParent(t *testing.T) { baseRepo, cs, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) store := storage.NewMemStorage() level1Key, err := cs.Create("targets/level1", data.ED25519Key) assert.NoError(t, err) r, err := data.NewRole("targets/level1", 1, []string{level1Key.ID()}, []string{""}) baseRepo.Targets[data.CanonicalTargetsRole].Signed.Delegations.Roles = []*data.Role{r} baseRepo.Targets[data.CanonicalTargetsRole].Signed.Delegations.Keys = data.Keys{ level1Key.ID(): level1Key, } baseRepo.InitTargets("targets/level1") del, err := baseRepo.SignTargets("targets/level1", data.DefaultExpires(data.CanonicalTargetsRole)) assert.NoError(t, err) delJSON, err := json.Marshal(del) assert.NoError(t, err) delUpdate := storage.MetaUpdate{ Role: "targets/level1", Version: 1, Data: delJSON, } // set back to empty so stored targets doesn't have reference to level1 baseRepo.Targets[data.CanonicalTargetsRole].Signed.Delegations.Roles = nil baseRepo.Targets[data.CanonicalTargetsRole].Signed.Delegations.Keys = nil targets, err := baseRepo.SignTargets(data.CanonicalTargetsRole, data.DefaultExpires(data.CanonicalTargetsRole)) tgtsJSON, err := json.Marshal(targets) assert.NoError(t, err) update := storage.MetaUpdate{ Role: data.CanonicalTargetsRole, Version: 1, Data: tgtsJSON, } store.UpdateCurrent("gun", update) roles := map[string]storage.MetaUpdate{ "targets/level1": delUpdate, data.CanonicalTargetsRole: update, } valRepo := tuf.NewRepo(nil) valRepo.SetRoot(baseRepo.Root) // because we sort the roles, the list of returned updates // will contain shallower roles first, in this case "targets", // and then "targets/level1" updates, err := loadAndValidateTargets("gun", valRepo, roles, store) assert.NoError(t, err) assert.Len(t, updates, 1) assert.Equal(t, data.CanonicalTargetsRole, updates[0].Role) assert.Equal(t, tgtsJSON, updates[0].Data) }
func TestValidateTargetsParentInUpdate(t *testing.T) { _, baseRepo, cs, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) store := storage.NewMemStorage() k, err := cs.Create("targets/level1", data.ED25519Key) assert.NoError(t, err) r, err := data.NewRole("targets/level1", 1, []string{k.ID()}, []string{""}, nil) assert.NoError(t, err) baseRepo.UpdateDelegations(r, []data.PublicKey{k}) // no targets file is created for the new delegations, so force one baseRepo.InitTargets("targets/level1") targets, err := baseRepo.SignTargets("targets", data.DefaultExpires(data.CanonicalTargetsRole)) tgtsJSON, err := json.Marshal(targets) assert.NoError(t, err) update := storage.MetaUpdate{ Role: data.CanonicalTargetsRole, Version: 1, Data: tgtsJSON, } store.UpdateCurrent("gun", update) del, err := baseRepo.SignTargets("targets/level1", data.DefaultExpires(data.CanonicalTargetsRole)) assert.NoError(t, err) delJSON, err := json.Marshal(del) assert.NoError(t, err) delUpdate := storage.MetaUpdate{ Role: "targets/level1", Version: 1, Data: delJSON, } roles := map[string]storage.MetaUpdate{ "targets/level1": delUpdate, "targets": update, } kdb := keys.NewDB() valRepo := tuf.NewRepo(kdb, nil) valRepo.SetRoot(baseRepo.Root) // because we sort the roles, the list of returned updates // will contain shallower roles first, in this case "targets", // and then "targets/level1" updates, err := loadAndValidateTargets("gun", valRepo, roles, kdb, store) assert.NoError(t, err) assert.Len(t, updates, 2) assert.Equal(t, "targets", updates[0].Role) assert.Equal(t, tgtsJSON, updates[0].Data) assert.Equal(t, "targets/level1", updates[1].Role) assert.Equal(t, delJSON, updates[1].Data) }
func TestSignRootOldKeyCertMissing(t *testing.T) { gun := "docker/test-sign-root" referenceTime := time.Now() cs := cryptoservice.NewCryptoService(trustmanager.NewKeyMemoryStore( passphrase.ConstantRetriever("password"))) rootPublicKey, err := cs.Create(data.CanonicalRootRole, gun, data.ECDSAKey) require.NoError(t, err) rootPrivateKey, _, err := cs.GetPrivateKey(rootPublicKey.ID()) require.NoError(t, err) oldRootCert, err := cryptoservice.GenerateCertificate(rootPrivateKey, gun, referenceTime.AddDate(-9, 0, 0), referenceTime.AddDate(1, 0, 0)) require.NoError(t, err) oldRootCertKey := trustmanager.CertToKey(oldRootCert) repo := initRepoWithRoot(t, cs, oldRootCertKey) // Create a first signature, using the old key. signedRoot, err := repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole)) require.NoError(t, err) verifySignatureList(t, signedRoot, oldRootCertKey) err = verifyRootSignatureAgainstKey(t, signedRoot, oldRootCertKey) require.NoError(t, err) // Create a new certificate newRootCert, err := cryptoservice.GenerateCertificate(rootPrivateKey, gun, referenceTime, referenceTime.AddDate(10, 0, 0)) require.NoError(t, err) newRootCertKey := trustmanager.CertToKey(newRootCert) require.NotEqual(t, oldRootCertKey.ID(), newRootCertKey.ID()) // Only trust the new certificate err = repo.ReplaceBaseKeys(data.CanonicalRootRole, newRootCertKey) require.NoError(t, err) updatedRootRole, err := repo.GetBaseRole(data.CanonicalRootRole) require.NoError(t, err) updatedRootKeyIDs := updatedRootRole.ListKeyIDs() require.Equal(t, 1, len(updatedRootKeyIDs)) require.Equal(t, newRootCertKey.ID(), updatedRootKeyIDs[0]) // Now forget all about the old certificate: drop it from the Root carried keys delete(repo.Root.Signed.Keys, oldRootCertKey.ID()) repo2 := NewRepo(cs) repo2.Root = repo.Root repo2.originalRootRole = updatedRootRole // Create a second signature signedRoot, err = repo2.SignRoot(data.DefaultExpires(data.CanonicalRootRole)) require.NoError(t, err) verifySignatureList(t, signedRoot, newRootCertKey) // Without oldRootCertKey // Verify that the signature can be verified when trusting the new certificate err = verifyRootSignatureAgainstKey(t, signedRoot, newRootCertKey) require.NoError(t, err) err = verifyRootSignatureAgainstKey(t, signedRoot, oldRootCertKey) require.Error(t, err) }
func TestDBGetChecksum(t *testing.T) { tempBaseDir, err := ioutil.TempDir("", "notary-test-") _, store := SetUpSQLite(t, tempBaseDir) defer os.RemoveAll(tempBaseDir) ts := data.SignedTimestamp{ Signatures: make([]data.Signature, 0), Signed: data.Timestamp{ SignedCommon: data.SignedCommon{ Type: data.TUFTypes[data.CanonicalTimestampRole], Version: 1, Expires: data.DefaultExpires(data.CanonicalTimestampRole), }, }, } j, err := json.Marshal(&ts) require.NoError(t, err) update := MetaUpdate{ Role: data.CanonicalTimestampRole, Version: 1, Data: j, } checksumBytes := sha256.Sum256(j) checksum := hex.EncodeToString(checksumBytes[:]) store.UpdateCurrent("gun", update) // create and add a newer timestamp. We're going to try and get the one // created above by checksum ts = data.SignedTimestamp{ Signatures: make([]data.Signature, 0), Signed: data.Timestamp{ SignedCommon: data.SignedCommon{ Type: data.TUFTypes[data.CanonicalTimestampRole], Version: 2, Expires: data.DefaultExpires(data.CanonicalTimestampRole), }, }, } newJ, err := json.Marshal(&ts) require.NoError(t, err) update = MetaUpdate{ Role: data.CanonicalTimestampRole, Version: 2, Data: newJ, } store.UpdateCurrent("gun", update) cDate, data, err := store.GetChecksum("gun", data.CanonicalTimestampRole, checksum) require.NoError(t, err) require.EqualValues(t, j, data) // the creation date was sometime wthin the last minute require.True(t, cDate.After(time.Now().Add(-1*time.Minute))) require.True(t, cDate.Before(time.Now().Add(5*time.Second))) }
func TestValidateTargetsRoleNotInParent(t *testing.T) { kdb, baseRepo, cs := testutils.EmptyRepo() store := storage.NewMemStorage() k, err := cs.Create("targets/level1", data.ED25519Key) assert.NoError(t, err) r, err := data.NewRole("targets/level1", 1, []string{k.ID()}, []string{""}, nil) assert.NoError(t, err) kdb.AddKey(k) err = kdb.AddRole(r) assert.NoError(t, err) baseRepo.InitTargets("targets/level1") targets, err := baseRepo.SignTargets("targets", data.DefaultExpires(data.CanonicalTargetsRole)) tgtsJSON, err := json.MarshalCanonical(targets) assert.NoError(t, err) update := storage.MetaUpdate{ Role: data.CanonicalTargetsRole, Version: 1, Data: tgtsJSON, } store.UpdateCurrent("gun", update) del, err := baseRepo.SignTargets("targets/level1", data.DefaultExpires(data.CanonicalTargetsRole)) assert.NoError(t, err) delJSON, err := json.MarshalCanonical(del) assert.NoError(t, err) delUpdate := storage.MetaUpdate{ Role: "targets/level1", Version: 1, Data: delJSON, } roles := map[string]storage.MetaUpdate{ "targets/level1": delUpdate, "targets": update, } kdb = keys.NewDB() valRepo := tuf.NewRepo(kdb, nil) valRepo.SetRoot(baseRepo.Root) // because we sort the roles, the list of returned updates // will contain shallower roles first, in this case "targets", // and then "targets/level1" updates, err := loadAndValidateTargets("gun", valRepo, roles, kdb, store) assert.NoError(t, err) assert.Len(t, updates, 1) assert.Equal(t, "targets", updates[0].Role) assert.Equal(t, tgtsJSON, updates[0].Data) }
// reads data from the repository in order to fake data being served via // the ServeMux. func fakeServerData(t *testing.T, repo *NotaryRepository, mux *http.ServeMux) { tempKey, err := data.UnmarshalPrivateKey([]byte(timestampECDSAKeyJSON)) assert.NoError(t, err) savedTUFRepo := repo.tufRepo // in case this is overwritten fileStore, err := trustmanager.NewKeyFileStore(repo.baseDir, passphraseRetriever) assert.NoError(t, err) fileStore.AddKey( filepath.Join(filepath.FromSlash(repo.gun), tempKey.ID()), "nonroot", tempKey) rootJSONFile := filepath.Join(repo.baseDir, "tuf", filepath.FromSlash(repo.gun), "metadata", "root.json") rootFileBytes, err := ioutil.ReadFile(rootJSONFile) signedTargets, err := savedTUFRepo.SignTargets( "targets", data.DefaultExpires("targets")) assert.NoError(t, err) signedSnapshot, err := savedTUFRepo.SignSnapshot( data.DefaultExpires("snapshot")) assert.NoError(t, err) signedTimestamp, err := savedTUFRepo.SignTimestamp( data.DefaultExpires("timestamp")) assert.NoError(t, err) mux.HandleFunc("/v2/docker.com/notary/_trust/tuf/root.json", func(w http.ResponseWriter, r *http.Request) { assert.NoError(t, err) fmt.Fprint(w, string(rootFileBytes)) }) mux.HandleFunc("/v2/docker.com/notary/_trust/tuf/timestamp.json", func(w http.ResponseWriter, r *http.Request) { timestampJSON, _ := json.Marshal(signedTimestamp) fmt.Fprint(w, string(timestampJSON)) }) mux.HandleFunc("/v2/docker.com/notary/_trust/tuf/snapshot.json", func(w http.ResponseWriter, r *http.Request) { snapshotJSON, _ := json.Marshal(signedSnapshot) fmt.Fprint(w, string(snapshotJSON)) }) mux.HandleFunc("/v2/docker.com/notary/_trust/tuf/targets.json", func(w http.ResponseWriter, r *http.Request) { targetsJSON, _ := json.Marshal(signedTargets) fmt.Fprint(w, string(targetsJSON)) }) }
func TestDBGetChecksum(t *testing.T) { tempBaseDir, err := ioutil.TempDir("", "notary-test-") _, store := SetUpSQLite(t, tempBaseDir) defer os.RemoveAll(tempBaseDir) ts := data.SignedTimestamp{ Signatures: make([]data.Signature, 0), Signed: data.Timestamp{ Type: data.TUFTypes["timestamp"], Version: 1, Expires: data.DefaultExpires("timestamp"), }, } j, err := json.Marshal(&ts) require.NoError(t, err) update := MetaUpdate{ Role: data.CanonicalTimestampRole, Version: 1, Data: j, } checksumBytes := sha256.Sum256(j) checksum := hex.EncodeToString(checksumBytes[:]) store.UpdateCurrent("gun", update) // create and add a newer timestamp. We're going to try and get the one // created above by checksum ts = data.SignedTimestamp{ Signatures: make([]data.Signature, 0), Signed: data.Timestamp{ Type: data.TUFTypes["timestamp"], Version: 2, Expires: data.DefaultExpires("timestamp"), }, } newJ, err := json.Marshal(&ts) require.NoError(t, err) update = MetaUpdate{ Role: data.CanonicalTimestampRole, Version: 2, Data: newJ, } store.UpdateCurrent("gun", update) data, err := store.GetChecksum("gun", data.CanonicalTimestampRole, checksum) require.NoError(t, err) require.EqualValues(t, j, data) }
func TestDuplicateSigs(t *testing.T) { cs := NewEd25519() k, err := cs.Create("root", data.ED25519Key) assert.NoError(t, err) r, err := data.NewRole( "root", 2, []string{k.ID()}, nil, nil, ) assert.NoError(t, err) db := keys.NewDB() assert.NoError(t, err) db.AddKey(k) err = db.AddRole(r) assert.NoError(t, err) meta := &data.SignedCommon{Type: "Root", Version: 1, Expires: data.DefaultExpires("root")} b, err := json.MarshalCanonical(meta) assert.NoError(t, err) s := &data.Signed{Signed: b} Sign(cs, s, k) s.Signatures = append(s.Signatures, s.Signatures[0]) err = Verify(s, "root", 1, db) assert.IsType(t, ErrRoleThreshold{}, err) }
func TestGetSnapshotCurrValid(t *testing.T) { store := storage.NewMemStorage() crypto := signed.NewEd25519() _, err := GetOrCreateSnapshotKey("gun", store, crypto, data.ED25519Key) newData := []byte{2} currMeta, err := data.NewFileMeta(bytes.NewReader(newData), "sha256") assert.NoError(t, err) snapshot := &data.SignedSnapshot{ Signed: data.Snapshot{ Expires: data.DefaultExpires(data.CanonicalSnapshotRole), Meta: data.Files{ data.CanonicalRootRole: currMeta, }, }, } snapJSON, _ := json.Marshal(snapshot) // test when db is missing the role data store.UpdateCurrent("gun", storage.MetaUpdate{Role: "snapshot", Version: 0, Data: snapJSON}) _, err = GetOrCreateSnapshot("gun", store, crypto) assert.NoError(t, err) // test when db has the role data store.UpdateCurrent("gun", storage.MetaUpdate{Role: "root", Version: 0, Data: newData}) _, err = GetOrCreateSnapshot("gun", store, crypto) assert.NoError(t, err) // test when db role data is expired store.UpdateCurrent("gun", storage.MetaUpdate{Role: "root", Version: 1, Data: []byte{3}}) _, err = GetOrCreateSnapshot("gun", store, crypto) assert.NoError(t, err) }
// If there is no previous snapshot or the previous snapshot is corrupt, then // even if everything else is in place, getting the snapshot fails func TestGetSnapshotNoPreviousSnapshot(t *testing.T) { repo, crypto, err := testutils.EmptyRepo("gun") require.NoError(t, err) sgnd, err := repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole)) require.NoError(t, err) rootJSON, err := json.Marshal(sgnd) require.NoError(t, err) for _, snapshotJSON := range [][]byte{nil, []byte("invalid JSON")} { store := storage.NewMemStorage() // so we know it's not a failure in getting root require.NoError(t, store.UpdateCurrent("gun", storage.MetaUpdate{Role: data.CanonicalRootRole, Version: 0, Data: rootJSON})) if snapshotJSON != nil { require.NoError(t, store.UpdateCurrent("gun", storage.MetaUpdate{Role: data.CanonicalSnapshotRole, Version: 0, Data: snapshotJSON})) } hashBytes := sha256.Sum256(snapshotJSON) hashHex := hex.EncodeToString(hashBytes[:]) _, _, err = GetOrCreateSnapshot("gun", hashHex, store, crypto) require.Error(t, err, "GetSnapshot should have failed") if snapshotJSON == nil { require.IsType(t, storage.ErrNotFound{}, err) } else { require.IsType(t, &json.SyntaxError{}, err) } } }
func TestDownloadTargetChecksumMismatch(t *testing.T) { repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) remoteStorage := testutils.NewCorruptingMemoryStore(nil) client := NewClient(repo, remoteStorage, localStorage) // create and "upload" sample targets signedOrig, err := repo.SignTargets("targets", data.DefaultExpires("targets")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) origSha256 := sha256.Sum256(orig) err = remoteStorage.SetMeta("targets", orig) assert.NoError(t, err) // create local snapshot with targets file snap := data.SignedSnapshot{ Signed: data.Snapshot{ Meta: data.Files{ "targets": data.FileMeta{ Length: int64(len(orig)), Hashes: data.Hashes{ "sha256": origSha256[:], }, }, }, }, } repo.Snapshot = &snap err = client.downloadTargets("targets") assert.IsType(t, ErrChecksumMismatch{}, err) }
func TestCreateSnapshotNoKeyInCrypto(t *testing.T) { store := storage.NewMemStorage() repo, _, err := testutils.EmptyRepo("gun") require.NoError(t, err) sgnd, err := repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole)) require.NoError(t, err) rootJSON, err := json.Marshal(sgnd) require.NoError(t, err) // create an expired snapshot sgnd, err = repo.SignSnapshot(time.Now().AddDate(-1, -1, -1)) require.True(t, repo.Snapshot.Signed.Expires.Before(time.Now())) require.NoError(t, err) snapshotJSON, err := json.Marshal(sgnd) require.NoError(t, err) // set all the metadata so we know the failure to sign is just because of the key require.NoError(t, store.UpdateCurrent("gun", storage.MetaUpdate{Role: data.CanonicalRootRole, Version: 0, Data: rootJSON})) require.NoError(t, store.UpdateCurrent("gun", storage.MetaUpdate{Role: data.CanonicalSnapshotRole, Version: 0, Data: snapshotJSON})) hashBytes := sha256.Sum256(snapshotJSON) hashHex := hex.EncodeToString(hashBytes[:]) // pass it a new cryptoservice without the key _, _, err = GetOrCreateSnapshot("gun", hashHex, store, signed.NewEd25519()) require.Error(t, err) require.IsType(t, signed.ErrInsufficientSignatures{}, err) }
func TestUnknownKeyBelowThreshold(t *testing.T) { cs := NewEd25519() k, err := cs.Create("root", "", data.ED25519Key) require.NoError(t, err) unknown, err := cs.Create("root", "", data.ED25519Key) require.NoError(t, err) roleWithKeys := data.BaseRole{Name: "root", Keys: data.Keys{k.ID(): k}, Threshold: 2} meta := &data.SignedCommon{Type: "Root", Version: 1, Expires: data.DefaultExpires("root")} b, err := json.MarshalCanonical(meta) require.NoError(t, err) s := &data.Signed{Signed: (*json.RawMessage)(&b)} require.NoError(t, Sign(cs, s, []data.PublicKey{k, unknown}, 2, nil)) s.Signatures = append(s.Signatures) err = VerifySignatures(s, roleWithKeys) require.IsType(t, ErrRoleThreshold{}, err) require.Len(t, s.Signatures, 2) for _, signature := range s.Signatures { if signature.KeyID == k.ID() { require.True(t, signature.IsValid) } else { require.False(t, signature.IsValid) } } }
// Creates metadata in the following manner: // - the snapshot has bad checksums for itself and for timestamp, to show that those aren't checked // - snapshot has valid checksums for root, targets, and targets/other // - snapshot doesn't have a checksum for targets/other/other, but targets/other/other is a valid // delegation role in targets/other and there is metadata for targets/other/other that is correctly // signed func setupSnapshotChecksumming(t *testing.T, gun string) map[string][]byte { repo, _, err := testutils.EmptyRepo(gun, "targets/other", "targets/other/other") require.NoError(t, err) // add invalid checkums for all the other roles to timestamp too, and show that // cached items aren't checksummed against this fakeChecksum, err := data.NewFileMeta(bytes.NewBuffer([]byte("fake")), notary.SHA256, notary.SHA512) require.NoError(t, err) // fake the snapshot and timestamp checksums repo.Snapshot.Signed.Meta[data.CanonicalSnapshotRole] = fakeChecksum repo.Snapshot.Signed.Meta[data.CanonicalTimestampRole] = fakeChecksum meta, err := testutils.SignAndSerialize(repo) require.NoError(t, err) // ensure that the fake metadata for other roles wasn't destroyed by signing require.Len(t, repo.Snapshot.Signed.Meta, 5) // create delegation metadata that should not be in snapshot, but has a valid role and signature _, err = repo.InitTargets("targets/other/other") require.NoError(t, err) s, err := repo.SignTargets("targets/other/other", data.DefaultExpires(data.CanonicalTargetsRole)) require.NoError(t, err) meta["targets/other/other"], err = json.Marshal(s) require.NoError(t, err) return meta }
func TestMoreThanEnoughSigs(t *testing.T) { cs := NewEd25519() k1, err := cs.Create("root", data.ED25519Key) assert.NoError(t, err) k2, err := cs.Create("root", data.ED25519Key) assert.NoError(t, err) r, err := data.NewRole( "root", 1, []string{k1.ID(), k2.ID()}, nil, nil, ) assert.NoError(t, err) db := keys.NewDB() assert.NoError(t, err) db.AddKey(k1) db.AddKey(k2) err = db.AddRole(r) assert.NoError(t, err) meta := &data.SignedCommon{Type: "Root", Version: 1, Expires: data.DefaultExpires("root")} b, err := json.MarshalCanonical(meta) assert.NoError(t, err) s := &data.Signed{Signed: b} Sign(cs, s, k1, k2) assert.Equal(t, 2, len(s.Signatures)) err = Verify(s, "root", 1, db) assert.NoError(t, err) }
func (r *NotaryRepository) saveMetadata() error { logrus.Debugf("Saving changes to Trusted Collection.") signedRoot, err := r.tufRepo.SignRoot(data.DefaultExpires("root")) if err != nil { return err } rootJSON, err := json.Marshal(signedRoot) if err != nil { return err } targetsToSave := make(map[string][]byte) for t := range r.tufRepo.Targets { signedTargets, err := r.tufRepo.SignTargets(t, data.DefaultExpires("targets")) if err != nil { return err } targetsJSON, err := json.Marshal(signedTargets) if err != nil { return err } targetsToSave[t] = targetsJSON } signedSnapshot, err := r.tufRepo.SignSnapshot(data.DefaultExpires("snapshot")) if err != nil { return err } snapshotJSON, err := json.Marshal(signedSnapshot) if err != nil { return err } err = r.fileStore.SetMeta("root", rootJSON) if err != nil { return err } for role, blob := range targetsToSave { parentDir := filepath.Dir(role) os.MkdirAll(parentDir, 0755) r.fileStore.SetMeta(role, blob) } return r.fileStore.SetMeta("snapshot", snapshotJSON) }
func TestValidateRootRotation(t *testing.T) { repo, crypto, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) store := storage.NewMemStorage() r, tg, sn, ts, err := testutils.Sign(repo) assert.NoError(t, err) root, targets, snapshot, timestamp, err := getUpdates(r, tg, sn, ts) assert.NoError(t, err) store.UpdateCurrent("testGUN", root) oldRootRole := repo.Root.Signed.Roles["root"] oldRootKey := repo.Root.Signed.Keys[oldRootRole.KeyIDs[0]] rootKey, err := crypto.Create("root", data.ED25519Key) assert.NoError(t, err) rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil) assert.NoError(t, err) delete(repo.Root.Signed.Keys, oldRootRole.KeyIDs[0]) repo.Root.Signed.Roles["root"] = &rootRole.RootRole repo.Root.Signed.Keys[rootKey.ID()] = rootKey r, err = repo.SignRoot(data.DefaultExpires(data.CanonicalRootRole)) assert.NoError(t, err) err = signed.Sign(crypto, r, rootKey, oldRootKey) assert.NoError(t, err) rt, err := data.RootFromSigned(r) assert.NoError(t, err) repo.SetRoot(rt) sn, err = repo.SignSnapshot(data.DefaultExpires(data.CanonicalSnapshotRole)) assert.NoError(t, err) root, targets, snapshot, timestamp, err = getUpdates(r, tg, sn, ts) assert.NoError(t, err) updates := []storage.MetaUpdate{root, targets, snapshot, timestamp} copyTimestampKey(t, repo, store, "testGUN") _, err = validateUpdate(crypto, "testGUN", updates, store) assert.NoError(t, err) }
// Sign signs all top level roles in a repo in the appropriate order func Sign(repo *tuf.Repo) (root, targets, snapshot, timestamp *data.Signed, err error) { root, err = repo.SignRoot(data.DefaultExpires("root")) if err != nil { return nil, nil, nil, nil, err } targets, err = repo.SignTargets("targets", data.DefaultExpires("targets")) if err != nil { return nil, nil, nil, nil, err } snapshot, err = repo.SignSnapshot(data.DefaultExpires("snapshot")) if err != nil { return nil, nil, nil, nil, err } timestamp, err = repo.SignTimestamp(data.DefaultExpires("timestamp")) if err != nil { return nil, nil, nil, nil, err } return }
func TestDownloadTargetsHappy(t *testing.T) { kdb, repo, _ := testutils.EmptyRepo() localStorage := store.NewMemoryStore(nil, nil) remoteStorage := store.NewMemoryStore(nil, nil) client := NewClient(repo, remoteStorage, kdb, localStorage) signedOrig, err := repo.SignTargets("targets", data.DefaultExpires("targets")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("targets", orig) assert.NoError(t, err) // call repo.SignSnapshot to update the targets role in the snapshot repo.SignSnapshot(data.DefaultExpires("snapshot")) err = client.downloadTargets("targets") assert.NoError(t, err) }
// Sign signs all top level roles in a repo in the appropriate order func Sign(repo *tuf.Repo) (root, targets, snapshot, timestamp *data.Signed, err error) { root, err = repo.SignRoot(data.DefaultExpires("root")) if _, ok := err.(data.ErrInvalidRole); err != nil && !ok { return nil, nil, nil, nil, err } targets, err = repo.SignTargets("targets", data.DefaultExpires("targets")) if _, ok := err.(data.ErrInvalidRole); err != nil && !ok { return nil, nil, nil, nil, err } snapshot, err = repo.SignSnapshot(data.DefaultExpires("snapshot")) if _, ok := err.(data.ErrInvalidRole); err != nil && !ok { return nil, nil, nil, nil, err } timestamp, err = repo.SignTimestamp(data.DefaultExpires("timestamp")) if _, ok := err.(data.ErrInvalidRole); err != nil && !ok { return nil, nil, nil, nil, err } return }
func TestUpdateDownloadRootHappy(t *testing.T) { kdb, repo, _ := testutils.EmptyRepo() localStorage := store.NewMemoryStore(nil, nil) remoteStorage := store.NewMemoryStore(nil, nil) client := NewClient(repo, remoteStorage, kdb, localStorage) // create and "upload" sample root, snapshot, and timestamp signedOrig, err := repo.SignRoot(data.DefaultExpires("root")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("root", orig) assert.NoError(t, err) // sign snapshot to make root meta in snapshot get updated signedOrig, err = repo.SignSnapshot(data.DefaultExpires("snapshot")) err = client.downloadRoot() assert.NoError(t, err) }
// signs and serializes the metadata for a canonical role in a tuf repo to JSON func serializeCanonicalRole(tufRepo *tuf.Repo, role string) (out []byte, err error) { var s *data.Signed switch { case role == data.CanonicalRootRole: s, err = tufRepo.SignRoot(data.DefaultExpires(role)) case role == data.CanonicalSnapshotRole: s, err = tufRepo.SignSnapshot(data.DefaultExpires(role)) case tufRepo.Targets[role] != nil: s, err = tufRepo.SignTargets( role, data.DefaultExpires(data.CanonicalTargetsRole)) default: err = fmt.Errorf("%s not supported role to sign on the client", role) } if err != nil { return } return json.Marshal(s) }
// TestDownloadTargetsLarge: Check that we can download very large targets metadata files, // which may be caused by adding a large number of targets. // This test is slow, so it will not run in short mode. func TestDownloadTargetsLarge(t *testing.T) { if testing.Short() { t.Skip("skipping test in short mode") } repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) remoteStorage := store.NewMemoryStore(nil) client := NewClient(repo, remoteStorage, localStorage) hash := sha256.Sum256([]byte{}) f := data.FileMeta{ Length: 1, Hashes: map[string][]byte{ "sha256": hash[:], }, } // Add a ton of target files to the targets role to make this targets metadata huge // 75,000 targets results in > 5MB (~6.5MB on recent runs) for i := 0; i < 75000; i++ { _, err = repo.AddTargets(data.CanonicalTargetsRole, data.Files{strconv.Itoa(i): f}) assert.NoError(t, err) } signedOrig, err := repo.SignTargets("targets", data.DefaultExpires("targets")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("targets", orig) assert.NoError(t, err) // call repo.SignSnapshot to update the targets role in the snapshot repo.SignSnapshot(data.DefaultExpires("snapshot")) // Clear the cache to force an online download client.cache.RemoveAll() err = client.downloadTargets("targets") assert.NoError(t, err) }
func TestVerifyExpiry(t *testing.T) { tufType := data.TUFTypes[data.CanonicalRootRole] notExpired := data.DefaultExpires(data.CanonicalRootRole) expired := time.Now().Add(-1 * notary.Year) require.NoError(t, VerifyExpiry( &data.SignedCommon{Type: tufType, Version: 1, Expires: notExpired}, data.CanonicalRootRole)) err := VerifyExpiry( &data.SignedCommon{Type: tufType, Version: 1, Expires: expired}, data.CanonicalRootRole) require.Error(t, err) require.IsType(t, ErrExpired{}, err) }
// TestDownloadSnapshotLarge: Check that we can download very large snapshot metadata files, // which may be caused by adding a large number of delegations. // This test is slow, so it will not run in short mode. func TestDownloadSnapshotLarge(t *testing.T) { if testing.Short() { t.Skip("skipping test in short mode") } repo, _, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) localStorage := store.NewMemoryStore(nil) remoteStorage := store.NewMemoryStore(nil) client := NewClient(repo, remoteStorage, localStorage) // Add a ton of empty delegation roles to targets to make snapshot data huge // This can also be done by adding legitimate delegations but it will be much slower // 75,000 delegation roles results in > 5MB (~7.3MB on recent runs) for i := 0; i < 75000; i++ { newRole := &data.SignedTargets{} repo.Targets[fmt.Sprintf("targets/%d", i)] = newRole } // create and "upload" sample snapshot and timestamp signedOrig, err := repo.SignSnapshot(data.DefaultExpires("snapshot")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("snapshot", orig) assert.NoError(t, err) signedOrig, err = repo.SignTimestamp(data.DefaultExpires("timestamp")) assert.NoError(t, err) orig, err = json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("timestamp", orig) assert.NoError(t, err) // Clear the cache to force an online download client.cache.RemoveAll() err = client.downloadSnapshot() assert.NoError(t, err) }
func TestValidateTargetsLoadParent(t *testing.T) { _, baseRepo, cs, err := testutils.EmptyRepo("docker.com/notary") assert.NoError(t, err) store := storage.NewMemStorage() k, err := cs.Create("targets/level1", data.ED25519Key) assert.NoError(t, err) r, err := data.NewRole("targets/level1", 1, []string{k.ID()}, []string{""}, nil) assert.NoError(t, err) err = baseRepo.UpdateDelegations(r, []data.PublicKey{k}) assert.NoError(t, err) // no targets file is created for the new delegations, so force one baseRepo.InitTargets("targets/level1") // we're not going to validate things loaded from storage, so no need // to sign the base targets, just Marshal it and set it into storage tgtsJSON, err := json.Marshal(baseRepo.Targets["targets"]) assert.NoError(t, err) update := storage.MetaUpdate{ Role: data.CanonicalTargetsRole, Version: 1, Data: tgtsJSON, } store.UpdateCurrent("gun", update) // generate the update object we're doing to use to call loadAndValidateTargets del, err := baseRepo.SignTargets("targets/level1", data.DefaultExpires(data.CanonicalTargetsRole)) assert.NoError(t, err) delJSON, err := json.Marshal(del) assert.NoError(t, err) delUpdate := storage.MetaUpdate{ Role: "targets/level1", Version: 1, Data: delJSON, } roles := map[string]storage.MetaUpdate{"targets/level1": delUpdate} kdb := keys.NewDB() valRepo := tuf.NewRepo(kdb, nil) valRepo.SetRoot(baseRepo.Root) updates, err := loadAndValidateTargets("gun", valRepo, roles, kdb, store) assert.NoError(t, err) assert.Len(t, updates, 1) assert.Equal(t, "targets/level1", updates[0].Role) assert.Equal(t, delJSON, updates[0].Data) }
func TestDownloadSnapshotBadChecksum(t *testing.T) { kdb, repo, _ := testutils.EmptyRepo() localStorage := store.NewMemoryStore(nil, nil) remoteStorage := store.NewMemoryStore(nil, nil) client := NewClient(repo, remoteStorage, kdb, localStorage) // sign timestamp to ensure it has a checksum for snapshot _, err := repo.SignTimestamp(data.DefaultExpires("timestamp")) assert.NoError(t, err) // create and "upload" sample snapshot and timestamp signedOrig, err := repo.SignSnapshot(data.DefaultExpires("snapshot")) assert.NoError(t, err) orig, err := json.Marshal(signedOrig) assert.NoError(t, err) err = remoteStorage.SetMeta("snapshot", orig) assert.NoError(t, err) // by not signing timestamp again we ensure it has the wrong checksum err = client.downloadSnapshot() assert.IsType(t, ErrChecksumMismatch{}, err) }