예제 #1
0
파일: tuf.go 프로젝트: aaronlehmann/notary
func tufLookup(cmd *cobra.Command, args []string) {
	if len(args) < 2 {
		cmd.Usage()
		fatalf("must specify a GUN and target")
	}
	gun := args[0]
	targetName := args[1]
	kdb := keys.NewDB()
	repo := tuf.NewTufRepo(kdb, nil)

	remote, err := getRemoteStore(gun)
	c, err := bootstrapClient(gun, remote, repo, kdb)
	if err != nil {
		return
	}
	err = c.Update()
	if err != nil {
		logrus.Error("Error updating client: ", err.Error())
		return
	}
	meta := c.TargetMeta(targetName)
	if meta == nil {
		logrus.Infof("Target %s not found in %s.", targetName, gun)
		return
	}
	if rawOutput {
		fmt.Println(targetName, fmt.Sprintf("sha256:%s", meta.Hashes["sha256"]), meta.Length)
	} else {
		fmt.Println(targetName, fmt.Sprintf("sha256:%s", meta.Hashes["sha256"]), meta.Length)
	}
}
예제 #2
0
func TestUpdateDelegations(t *testing.T) {
	ed25519 := signed.NewEd25519()
	keyDB := keys.NewDB()
	repo := initRepo(t, ed25519, keyDB)

	testKey, err := ed25519.Create("targets/test", data.ED25519Key)
	if err != nil {
		t.Fatal(err)
	}
	role, err := data.NewRole("targets/test", 1, []string{testKey.ID()}, []string{"test"}, []string{})
	if err != nil {
		t.Fatal(err)
	}

	err = repo.UpdateDelegations(role, []data.Key{testKey}, "")
	if err != nil {
		t.Fatal(err)
	}

	testDeepKey, err := ed25519.Create("targets/test/deep", data.ED25519Key)
	if err != nil {
		t.Fatal(err)
	}
	roleDeep, err := data.NewRole("targets/test/deep", 1, []string{testDeepKey.ID()}, []string{"test/deep"}, []string{})
	if err != nil {
		t.Fatal(err)
	}

	err = repo.UpdateDelegations(roleDeep, []data.Key{testDeepKey}, "")
	if err != nil {
		t.Fatal(err)
	}

	writeRepo(t, "/tmp/tufdelegation", repo)
}
예제 #3
0
파일: client.go 프로젝트: jalateras/notary
func (r *NotaryRepository) bootstrapClient() (*tufclient.Client, error) {
	remote, err := getRemoteStore(r.baseURL, r.Gun)
	if err != nil {
		return nil, err
	}
	rootJSON, err := remote.GetMeta("root", 5<<20)
	if err != nil {
		return nil, err
	}
	root := &data.Signed{}
	err = json.Unmarshal(rootJSON, root)
	if err != nil {
		return nil, err
	}

	err = r.validateRoot(root)
	if err != nil {
		return nil, err
	}

	kdb := keys.NewDB()
	r.tufRepo = tuf.NewTufRepo(kdb, r.signer)

	err = r.tufRepo.SetRoot(root)
	if err != nil {
		return nil, err
	}

	return tufclient.NewClient(
		r.tufRepo,
		remote,
		kdb,
	), nil
}
예제 #4
0
파일: tuf.go 프로젝트: progrium/notary
func tufList(cmd *cobra.Command, args []string) {
	if len(args) < 1 {
		cmd.Usage()
		fatalf("must specify a GUN")
	}
	gun := args[0]
	kdb := keys.NewDB()
	repo := tuf.NewTufRepo(kdb, nil)

	remote, err := store.NewHTTPStore(
		"https://notary:4443/v2/"+gun+"/_trust/tuf/",
		"",
		"json",
		"",
	)
	c, err := bootstrapClient(remote, repo, kdb)
	if err != nil {
		return
	}
	err = c.Update()
	if err != nil {
		logrus.Error("Error updating client: ", err.Error())
		return
	}

	if rawOutput {
		for name, meta := range repo.Targets["targets"].Signed.Targets {
			fmt.Println(name, " ", meta.Hashes["sha256"], " ", meta.Length)
		}
	} else {
		for name, meta := range repo.Targets["targets"].Signed.Targets {
			fmt.Println(name, " ", meta.Hashes["sha256"], " ", meta.Length)
		}
	}
}
예제 #5
0
파일: tuf.go 프로젝트: progrium/notary
func tufAdd(cmd *cobra.Command, args []string) {
	if len(args) < 3 {
		cmd.Usage()
		fatalf("must specify a GUN, target, and path to target data")
	}

	gun := args[0]
	targetName := args[1]
	targetPath := args[2]
	kdb := keys.NewDB()
	signer := signed.NewSigner(NewCryptoService(gun))
	repo := tuf.NewTufRepo(kdb, signer)

	b, err := ioutil.ReadFile(targetPath)
	if err != nil {
		fatalf(err.Error())
	}

	filestore := bootstrapRepo(gun, repo)

	fmt.Println("Generating metadata for target")
	meta, err := data.NewFileMeta(bytes.NewBuffer(b))
	if err != nil {
		fatalf(err.Error())
	}

	fmt.Printf("Adding target \"%s\" with sha256 \"%s\" and size %d bytes.\n", targetName, meta.Hashes["sha256"], meta.Length)
	_, err = repo.AddTargets("targets", data.Files{targetName: meta})
	if err != nil {
		fatalf(err.Error())
	}

	saveRepo(repo, filestore)
}
예제 #6
0
func TestRotationNewSigMissing(t *testing.T) {
	logrus.SetLevel(logrus.DebugLevel)
	kdb := keys.NewDB()
	signer := signed.NewEd25519()
	repo := tuf.NewRepo(kdb, signer)
	remote := store.NewMemoryStore(nil, nil)
	cache := store.NewMemoryStore(nil, nil)

	// Generate initial root key and role and add to key DB
	rootKey, err := signer.Create("root", data.ED25519Key)
	assert.NoError(t, err, "Error creating root key")
	rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil)
	assert.NoError(t, err, "Error creating root role")

	kdb.AddKey(rootKey)
	err = kdb.AddRole(rootRole)
	assert.NoError(t, err, "Error adding root role to db")

	// Generate new key and role. These will appear in the root.json
	// but will not be added to the keyDB.
	replacementKey, err := signer.Create("root", data.ED25519Key)
	assert.NoError(t, err, "Error creating replacement root key")
	replacementRole, err := data.NewRole("root", 1, []string{replacementKey.ID()}, nil, nil)
	assert.NoError(t, err, "Error creating replacement root role")

	assert.NotEqual(t, rootKey.ID(), replacementKey.ID(), "Key IDs are the same")

	// Generate a new root with the replacement key and role
	testRoot, err := data.NewRoot(
		map[string]data.PublicKey{replacementKey.ID(): replacementKey},
		map[string]*data.RootRole{"root": &replacementRole.RootRole},
		false,
	)
	assert.NoError(t, err, "Failed to create new root")

	_, ok := testRoot.Signed.Keys[rootKey.ID()]
	assert.False(t, ok, "Old root key appeared in test root")

	// Sign testRoot with both old and new keys
	signedRoot, err := testRoot.ToSigned()
	err = signed.Sign(signer, signedRoot, rootKey)
	assert.NoError(t, err, "Failed to sign root")
	var origKeySig bool
	var replKeySig bool
	for _, sig := range signedRoot.Signatures {
		if sig.KeyID == rootKey.ID() {
			origKeySig = true
		} else if sig.KeyID == replacementKey.ID() {
			replKeySig = true
		}
	}
	assert.True(t, origKeySig, "Original root key signature not present")
	assert.False(t, replKeySig, "Replacement root key signature was present and shouldn't be")

	client := NewClient(repo, remote, kdb, cache)

	err = client.verifyRoot("root", signedRoot, 0)
	assert.Error(t, err, "Should have errored on verify as replacement signature was missing.")

}
예제 #7
0
파일: tuf_test.go 프로젝트: progrium/notary
func TestInitRepo(t *testing.T) {
	ed25519 := signed.NewEd25519()
	signer := signed.NewSigner(ed25519)
	keyDB := keys.NewDB()
	repo := initRepo(t, signer, keyDB)
	writeRepo(t, "/tmp/tufrepo", repo)
}
예제 #8
0
func (r *NotaryRepository) bootstrapClient() (*tufclient.Client, error) {
	var rootJSON []byte
	remote, err := getRemoteStore(r.baseURL, r.gun, r.roundTrip)
	if err == nil {
		// if remote store successfully set up, try and get root from remote
		rootJSON, err = remote.GetMeta("root", maxSize)
	}

	// if remote store couldn't be setup, or we failed to get a root from it
	// load the root from cache (offline operation)
	if err != nil {
		if err, ok := err.(store.ErrMetaNotFound); ok {
			// if the error was MetaNotFound then we successfully contacted
			// the store and it doesn't know about the repo.
			return nil, err
		}
		rootJSON, err = r.fileStore.GetMeta("root", maxSize)
		if err != nil {
			// if cache didn't return a root, we cannot proceed
			return nil, store.ErrMetaNotFound{}
		}
	}
	// can't just unmarshal into SignedRoot because validate root
	// needs the root.Signed field to still be []byte for signature
	// validation
	root := &data.Signed{}
	err = json.Unmarshal(rootJSON, root)
	if err != nil {
		return nil, err
	}

	err = r.KeyStoreManager.ValidateRoot(root, r.gun)
	if err != nil {
		return nil, err
	}

	kdb := keys.NewDB()
	r.tufRepo = tuf.NewTufRepo(kdb, r.cryptoService)

	signedRoot, err := data.RootFromSigned(root)
	if err != nil {
		return nil, err
	}
	err = r.tufRepo.SetRoot(signedRoot)
	if err != nil {
		return nil, err
	}

	return tufclient.NewClient(
		r.tufRepo,
		remote,
		kdb,
		r.fileStore,
	), nil
}
예제 #9
0
파일: tuf.go 프로젝트: progrium/notary
func verify(cmd *cobra.Command, args []string, output io.WriteCloser) {
	if len(args) < 2 {
		cmd.Usage()
		fatalf("must specify a GUN and target")
	}

	// Reads all of the data on STDIN
	//TODO (diogo): Change this to do a streaming hash
	payload, err := ioutil.ReadAll(os.Stdin)
	if err != nil {
		fatalf("error reading content from STDIN: %v", err)
	}

	//TODO (diogo): This code is copy/pasted from lookup.
	gun := args[0]
	targetName := args[1]
	kdb := keys.NewDB()
	repo := tuf.NewTufRepo(kdb, nil)

	remote, err := store.NewHTTPStore(
		"https://notary:4443/v2/"+gun+"/_trust/tuf/",
		"",
		"json",
		"",
	)

	c, err := bootstrapClient(remote, repo, kdb)
	if err != nil {
		logrus.Error("Unable to setup client.")
		return
	}

	err = c.Update()
	if err != nil {
		fmt.Println("Update failed")
		fatalf(err.Error())
	}
	meta := c.TargetMeta(targetName)
	if meta == nil {
		logrus.Error("notary: data not present in the trusted collection.")
		os.Exit(1)
	}

	// Create hasher and hash data
	stdinHash := fmt.Sprintf("sha256:%x", sha256.Sum256(payload))
	serverHash := fmt.Sprintf("sha256:%s", meta.Hashes["sha256"])
	if stdinHash != serverHash {
		logrus.Error("notary: data not present in the trusted collection.")
		os.Exit(1)
	} else {
		_, _ = output.Write(payload)
		output.Close()
	}
	return
}
예제 #10
0
파일: download.go 프로젝트: progrium/notary
func download(ctx *cli.Context) {
	if len(ctx.Args()) < 1 {
		fmt.Println("At least one target name must be provided.")
		return
	}
	var root []byte
	r := &data.Signed{}
	err := json.Unmarshal(root, r)
	if err != nil {
		fmt.Println("Could not read initial root.json")
		return
	}
	kdb := keys.NewDB()
	repo := tuf.NewTufRepo(kdb, nil)
	repo.SetRoot(r)
	remote, err := store.NewHTTPStore(
		ctx.String("host"),
		ctx.String("meta"),
		ctx.String("ext"),
		ctx.String("targets"),
	)
	cached := store.NewFileCacheStore(remote, "/tmp/tuf")
	if err != nil {
		fmt.Println(err)
		return
	}

	client := client.NewClient(repo, cached, kdb)

	err = client.Update()
	if err != nil {
		fmt.Println(err)
		return
	}
	filename := filepath.Base(ctx.Args()[0])
	f, err := os.OpenFile(filename, os.O_TRUNC|os.O_CREATE|os.O_RDWR, 0644)
	if err != nil {
		fmt.Println(err)
		return
	}
	defer f.Close()
	m := client.TargetMeta(ctx.Args()[0])
	if m == nil {
		fmt.Println("Requested package not found.")
		return
	}
	err = client.DownloadTarget(f, ctx.Args()[0], m)
	if err != nil {
		fmt.Println(err)
		return
	}
	fmt.Println("Requested pacakge downloaded.")
}
예제 #11
0
파일: client.go 프로젝트: jalateras/notary
func (r *NotaryRepository) bootstrapRepo() error {
	fileStore, err := store.NewFilesystemStore(
		r.tufRepoPath,
		"metadata",
		"json",
		"targets",
	)
	if err != nil {
		return err
	}

	kdb := keys.NewDB()
	tufRepo := tuf.NewTufRepo(kdb, r.signer)

	fmt.Println("Loading trusted collection.")
	rootJSON, err := fileStore.GetMeta("root", 0)
	if err != nil {
		return err
	}
	root := &data.Signed{}
	err = json.Unmarshal(rootJSON, root)
	if err != nil {
		return err
	}
	tufRepo.SetRoot(root)
	targetsJSON, err := fileStore.GetMeta("targets", 0)
	if err != nil {
		return err
	}
	targets := &data.Signed{}
	err = json.Unmarshal(targetsJSON, targets)
	if err != nil {
		return err
	}
	tufRepo.SetTargets("targets", targets)
	snapshotJSON, err := fileStore.GetMeta("snapshot", 0)
	if err != nil {
		return err
	}
	snapshot := &data.Signed{}
	err = json.Unmarshal(snapshotJSON, snapshot)
	if err != nil {
		return err
	}
	tufRepo.SetSnapshot(snapshot)

	r.tufRepo = tufRepo
	r.fileStore = fileStore

	return nil
}
예제 #12
0
파일: repo.go 프로젝트: diogomonica/gotuf
// EmptyRepo creates an in memory key database, crypto service
// and initializes a repo with no targets or delegations.
func EmptyRepo() (*keys.KeyDB, *tuf.Repo, signed.CryptoService) {
	c := signed.NewEd25519()
	kdb := keys.NewDB()
	r := tuf.NewRepo(kdb, c)

	for _, role := range []string{"root", "targets", "snapshot", "timestamp"} {
		key, _ := c.Create(role, data.ED25519Key)
		role, _ := data.NewRole(role, 1, []string{key.ID()}, nil, nil)
		kdb.AddKey(key)
		kdb.AddRole(role)
	}

	r.InitRepo(false)
	return kdb, r, c
}
예제 #13
0
func TestApplyChangelist(t *testing.T) {
	kdb := keys.NewDB()
	role, err := data.NewRole("targets", 1, nil, nil, nil)
	assert.NoError(t, err)
	kdb.AddRole(role)

	repo := tuf.NewTufRepo(kdb, nil)
	err = repo.InitTargets()
	assert.NoError(t, err)
	hash := sha256.Sum256([]byte{})
	f := &data.FileMeta{
		Length: 1,
		Hashes: map[string][]byte{
			"sha256": hash[:],
		},
	}
	fjson, err := json.Marshal(f)
	assert.NoError(t, err)

	cl := changelist.NewMemChangelist()
	addChange := &changelist.TufChange{
		Actn:       changelist.ActionCreate,
		Role:       changelist.ScopeTargets,
		ChangeType: "target",
		ChangePath: "latest",
		Data:       fjson,
	}
	cl.Add(addChange)
	err = applyChangelist(repo, cl)
	assert.NoError(t, err)
	assert.NotNil(t, repo.Targets["targets"].Signed.Targets["latest"])

	cl.Clear("")

	removeChange := &changelist.TufChange{
		Actn:       changelist.ActionDelete,
		Role:       changelist.ScopeTargets,
		ChangeType: "target",
		ChangePath: "latest",
		Data:       nil,
	}
	cl.Add(removeChange)
	err = applyChangelist(repo, cl)
	assert.NoError(t, err)
	_, ok := repo.Targets["targets"].Signed.Targets["latest"]
	assert.False(t, ok)
}
예제 #14
0
func (r *NotaryRepository) bootstrapRepo() error {
	kdb := keys.NewDB()
	tufRepo := tuf.NewTufRepo(kdb, r.cryptoService)

	logrus.Debugf("Loading trusted collection.")
	rootJSON, err := r.fileStore.GetMeta("root", 0)
	if err != nil {
		return err
	}
	root := &data.SignedRoot{}
	err = json.Unmarshal(rootJSON, root)
	if err != nil {
		return err
	}
	err = tufRepo.SetRoot(root)
	if err != nil {
		return err
	}
	targetsJSON, err := r.fileStore.GetMeta("targets", 0)
	if err != nil {
		return err
	}
	targets := &data.SignedTargets{}
	err = json.Unmarshal(targetsJSON, targets)
	if err != nil {
		return err
	}
	tufRepo.SetTargets("targets", targets)
	snapshotJSON, err := r.fileStore.GetMeta("snapshot", 0)
	if err != nil {
		return err
	}
	snapshot := &data.SignedSnapshot{}
	err = json.Unmarshal(snapshotJSON, snapshot)
	if err != nil {
		return err
	}
	tufRepo.SetSnapshot(snapshot)

	r.tufRepo = tufRepo

	return nil
}
예제 #15
0
파일: tuf.go 프로젝트: progrium/notary
func tufRemove(cmd *cobra.Command, args []string) {
	if len(args) < 2 {
		cmd.Usage()
		fatalf("must specify a GUN and target")
	}
	gun := args[0]
	targetName := args[1]
	kdb := keys.NewDB()
	signer := signed.NewSigner(NewCryptoService(gun))
	repo := tuf.NewTufRepo(kdb, signer)

	fmt.Println("Removing target ", targetName, " from ", gun)

	filestore := bootstrapRepo(gun, repo)

	err := repo.RemoveTargets("targets", targetName)
	if err != nil {
		fatalf(err.Error())
	}

	saveRepo(repo, filestore)
}
예제 #16
0
func TestClientUpdate(t *testing.T) {
	pypiRoot := `{
 "signatures": [
  {
   "keyid": "92db731bf30e31c13e775360453f0adc8bfd3107f5000b99431c4bdbcebb31ed", 
   "method": "PyCrypto-PKCS#1 PSS", 
   "sig": "31d1fa4712eaf591b367740f69ba7577fb5565863639d7e89145abe159f047d5f848e7696fbaf16f5c4214e1f2295d14e3078f5c0a6e2cbc015c13f8557836a039208970b436bb13b921f86f3e4d4518ce2f731bd7a55083d45634f206dc92e886daeb15e65a513f6451575811e9e44b5573d6999d4b69f86a27f01d0d9a868a535a1f0f6534bd9e555d4df95f019ea6859c83fca30e95e0d1c2ce1dcb2b19c91facd98a7cae9f4c81b5ff4c12980f333e38eac99f4561a8f9e5342382443f165cf0af840d5c61b62698b27413d7f5e1bdba714b98759bcfc7c3d65c567459ce093c66c88ebae836665bcdf2efc1e6921bd792406c0529dab2678a922e5fa6ef39e92f89d3072a22bd755a49b2e2e2c801ce73006fd8a7f56595fae01af3e2a49a3bce4ce9fcaec43e1aae5b0c0fc807bc4caca9fae7c34ff026a417262b5435cfd6cbf17b70aae041eae30a6bd6a857db88566c89f2c02171674b9195f22a84ec5839a4e46e2e63fbb5d4821ae66237ea261846c7d5a341d5f4ab2e12412d4e"
  }
 ], 
 "signed": {
  "_type": "Root", 
  "expires": "2014-08-31 00:49:33 UTC", 
  "keys": {
   "07f12f6c470e60d49fe6a60cd893dfba870db387083d50fe4fc43c6171a0be59": {
    "keytype": "rsa", 
    "keyval": {
     "private": "", 
     "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAtb4vuMJF1kOc1deExdqV\nZ3o9W6zulfRDX6u8Exd3NEL0/9bCYluqpshFzgmDYpCsuS79Ve5S8WgXAnEXyWOf\nHL/FnAVqFSnmgmYr52waMYV57BsNMY8pXxOnJm1opUbt0PdnF2D2yfLLY8IgZ/0m\niJ+gWojwEBMRlTOnHFx+l/UVvZAhpVsua6C8C2ThFLrXlmmtkg5BAIm1kWPsZ0nB\n3Cczcwh8zE0l2ytVi458AuRGKwi1TMIGXl064ekjsWexH1zCuoEcv/CKob0BkL4c\nLFUKe6WD6XlEp/xnMh6lNG8LT+UKzSb1hPkTtt23RntFB4Qx7UUT8LoO79bv6coE\njeEqHltmeohHpVmTLWsbTdaX7W3clWPUErGh5kAO0SJu1EM94p5nGWlZ+kwASxtO\nz1qR8AqQ02HBBQU+cY24CNnOwKDq/Kgsg1Aw7bqglvtUwBUQkuuCuisjHI0bSMFr\ntGIhlswxItfQ709/OMrN44Vw/H/Z50UzGFtRlu1h07/vAgMBAAE=\n-----END PUBLIC KEY-----"
    }
   }, 
   "2d9f41a1b79429e9d950a687fe00da0bb4fd751da98aeade1524b8d28968eb89": {
    "keytype": "rsa", 
    "keyval": {
     "private": "", 
     "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAmjt8CIbohZxZQ1+I8CQn\nvugLsGXq1G2OiMZvbN281q1/E1futll3+EnfxPLP0SBlyYxixma/ozoMj94lPyOX\nBbiF/U1WJ0Wp5D1kpT0Jzt9Ar0bkRxWoPhubeJ7D4k8Br2m7aG+wchfozdbMmUwK\n/MiAZ1fmpKQAr1ek3/hJiN/dURw+mQEdgXwgA4raDy4Ty3AkG7SDCG1cYoYYMJa3\nKg82AWISQQEHUO1MwRVBon2B5d2UriUEzsYYi+2whDOekchjgyd2xdcRvdCBbdGv\nJBCtzVZpd52lCwqAMJUyDGre6Mb6NmKC2nuk+TYEujqRQK97LnjmPwI42b4cBHqv\nDtg7Z8K3rEQIyD+VvrcWlu+1cE8drjh3y+r7oTtjRPr1M8xaCWn/dh8huSJmaFlk\nmWKDX9KI3/5pxFjgpry20eBRYkZHJWwByc9GVvwhRsIF61QdKvA6uGqkFHy9YQBW\nnzWTPo/4UTUwcpfjneoyMOVKx2K05ZePa5UNAgJVDgFfAgMBAAE=\n-----END PUBLIC KEY-----"
    }
   }, 
   "92db731bf30e31c13e775360453f0adc8bfd3107f5000b99431c4bdbcebb31ed": {
    "keytype": "rsa", 
    "keyval": {
     "private": "", 
     "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEArvqUPYb6JJROPJQglPTj\n5uDrsxQKl34Mo+3pSlBVuD6puE4lDnG649a2YksJy+C8ZIPJgokn5w+C3alh+dMe\nzbdWHHxrY1h9CLpYz5cbMlE16303ubkt1rvwDqEezG0HDBzPaKj4oP9YJ9x7wbsq\ndvFcy+Qc3wWd7UWcieo6E0ihbJkYcY8chRXVLg1rL7EfZ+e3bq5+ojA2ECM5JqzZ\nzgDpqCv5hTCYYZp72MZcG7dfSPAHrcSGIrwg7whzz2UsEtCOpsJTuCl96FPN7kAu\n4w/WyM3+SPzzr4/RQXuY1SrLCFD8ebM2zHt/3ATLhPnGmyG5I0RGYoegFaZ2AViw\nlqZDOYnBtgDvKP0zakMtFMbkh2XuNBUBO7Sjs0YcZMjLkh9gYUHL1yWS3Aqus1Lw\nlI0gHS22oyGObVBWkZEgk/Foy08sECLGao+5VvhmGpfVuiz9OKFUmtPVjWzRE4ng\niekEu4drSxpH41inLGSvdByDWLpcTvWQI9nkgclh3AT/AgMBAAE=\n-----END PUBLIC KEY-----"
    }
   }, 
   "e1ccde549849bb6aa548412e79c407c93f303f3a3ca0ab1e5923ff7d5c4de769": {
    "keytype": "rsa", 
    "keyval": {
     "private": "", 
     "public": "-----BEGIN PUBLIC KEY-----\nMIIBojANBgkqhkiG9w0BAQEFAAOCAY8AMIIBigKCAYEAqnNAzjIb73u2Nk+r2AdU\nnK+xvKDcZgIzjSzRVjtRJgu3MVffzPcGIsjv2RS8/LLl8nSf48V+tWZf/PnTzkMn\n1iJhbdOQTt6bABiizm5dLP9Jm/AIMTTUpbu+fpFbV8vNH+qM5/Z0WNOptQnOEfNs\n84MNh919lJjHc5VPTw86h68Mkn7W5RChZqnwEv75M1XfWdAnUGeLfZh6BKxFMnaB\nciYxieUvc1bnCtqsdaDE2Ab86WXM7cmNCqyLAh4JkTV+RcMzqEnZCAm68TkO6gM/\n5g4A7fbnn9Jc4O3fJvu80fYOg63nS6hAFldmN74oYu2h5PV75xyTIEERoXqJbSaj\n1Agj/98khIZGsSVjoQ5Mi7ETcSbsH7rqWdHFIu+dbKw8vlnqWnEQYjXA8CIOY3X7\nB6/u5FBS5AdxjO6AR/MuaqpWdDTZwXwgZ9c4wqO4Re4z73sGM1PugUK4dbXIGwVe\nRtzv7cSFOB7OPmj53miJWt2ILACb+Dpnxt9h6TzT1C0JAgMBAAE=\n-----END PUBLIC KEY-----"
    }
   }
  }, 
  "roles": {
   "release": {
    "keyids": [
     "e1ccde549849bb6aa548412e79c407c93f303f3a3ca0ab1e5923ff7d5c4de769"
    ], 
    "threshold": 1
   }, 
   "root": {
    "keyids": [
     "92db731bf30e31c13e775360453f0adc8bfd3107f5000b99431c4bdbcebb31ed"
    ], 
    "threshold": 1
   }, 
   "targets": {
    "keyids": [
     "07f12f6c470e60d49fe6a60cd893dfba870db387083d50fe4fc43c6171a0be59"
    ], 
    "threshold": 1
   }, 
   "timestamp": {
    "keyids": [
     "2d9f41a1b79429e9d950a687fe00da0bb4fd751da98aeade1524b8d28968eb89"
    ], 
    "threshold": 1
   }
  }, 
  "version": 1
 }
}`

	data.SetTUFTypes(
		map[string]string{
			"snapshot": "Release",
		},
	)
	data.SetValidRoles(
		map[string]string{
			"snapshot": "release",
		},
	)

	s := &data.Signed{}
	err := json.Unmarshal([]byte(pypiRoot), s)
	if err != nil {
		t.Fatal(err)
	}
	kdb := keys.NewDB()

	logrus.SetLevel(logrus.DebugLevel)

	// Being able to set the second argument, signer, to nil is a great
	// test as we shouldn't need to instantiate a signer just for reading
	// a repo.
	repo := tuf.NewTufRepo(kdb, nil)
	repo.SetRoot(s)
	remote, err := store.NewHTTPStore(
		"http://mirror1.poly.edu/test-pypi/",
		"metadata",
		"txt",
		"targets",
	)
	cached := store.NewFileCacheStore(remote, "/tmp/tuf")
	if err != nil {
		t.Fatal(err)
	}
	client := Client{
		local:  repo,
		remote: cached,
		keysDB: kdb,
	}

	err = client.Update()
	if err != nil {
		t.Fatal(err)
	}

	testTarget := "packages/2.3/T/TracHTTPAuth/TracHTTPAuth-1.0.1-py2.3.egg"
	expectedHash := "dbcaa6dc0035a636234f9b457d24bf1aeecac0a29b4da97a3b32692f2729f9db"
	expectedSize := int64(8140)
	m := client.TargetMeta(testTarget)
	if m == nil {
		t.Fatal("Failed to find existing target")
	}
	if m.Hashes["sha256"].String() != expectedHash {
		t.Fatal("Target hash incorrect.\nExpected:", expectedHash, "\nReceived:", m.Hashes["sha256"].String())
	}
	if m.Length != expectedSize {
		t.Fatal("Target size incorrect.\nExpected:", expectedSize, "\nReceived:", m.Length)
	}
	err = client.DownloadTarget(ioutil.Discard, testTarget, m)
	if err != nil {
		t.Fatal(err)
	}
}
예제 #17
0
func Test(t *testing.T) {
	cryptoService := NewEd25519()
	type test struct {
		name  string
		keys  []data.PublicKey
		roles map[string]*data.Role
		s     *data.Signed
		ver   int
		exp   *time.Time
		typ   string
		role  string
		err   error
		mut   func(*test)
	}

	expiredTime := time.Now().Add(-time.Hour)
	minVer := 10
	tests := []test{
		{
			name: "no signatures",
			mut:  func(t *test) { t.s.Signatures = []data.Signature{} },
			err:  ErrNoSignatures,
		},
		{
			name: "unknown role",
			role: "foo",
			err:  ErrUnknownRole,
		},
		//{
		//	name: "wrong signature method",
		//	mut:  func(t *test) { t.s.Signatures[0].Method = "foo" },
		//	err:  ErrWrongMethod,
		//},
		//	{
		//		name: "signature wrong length",
		//		mut:  func(t *test) { t.s.Signatures[0].Signature = []byte{0} },
		//		err:  ErrInvalid,
		//	},
		{
			name: "key missing from role",
			mut:  func(t *test) { t.roles["root"].KeyIDs = nil },
			err:  ErrRoleThreshold{},
		},
		//	{
		//		name: "invalid signature",
		//		mut:  func(t *test) { t.s.Signatures[0].Signature = make([]byte, ed25519.SignatureSize) },
		//		err:  ErrInvalid,
		//	},
		{
			name: "not enough signatures",
			mut:  func(t *test) { t.roles["root"].Threshold = 2 },
			err:  ErrRoleThreshold{},
		},
		{
			name: "exactly enough signatures",
		},
		{
			name: "more than enough signatures",
			mut: func(t *test) {
				k, _ := cryptoService.Create("root", data.ED25519Key)
				Sign(cryptoService, t.s, k)
				t.keys = append(t.keys, k)
				t.roles["root"].KeyIDs = append(t.roles["root"].KeyIDs, k.ID())
			},
		},
		{
			name: "duplicate key id",
			mut: func(t *test) {
				t.roles["root"].Threshold = 2
				t.s.Signatures = append(t.s.Signatures, t.s.Signatures[0])
			},
			err: ErrRoleThreshold{},
		},
		{
			name: "unknown key",
			mut: func(t *test) {
				k, _ := cryptoService.Create("root", data.ED25519Key)
				Sign(cryptoService, t.s, k)
			},
		},
		{
			name: "unknown key below threshold",
			mut: func(t *test) {
				k, _ := cryptoService.Create("root", data.ED25519Key)
				Sign(cryptoService, t.s, k)
				t.roles["root"].Threshold = 2
			},
			err: ErrRoleThreshold{},
		},
		{
			name: "unknown keys in db",
			mut: func(t *test) {
				k, _ := cryptoService.Create("root", data.ED25519Key)
				Sign(cryptoService, t.s, k)
				t.keys = append(t.keys, k)
			},
		},
		{
			name: "unknown keys in db below threshold",
			mut: func(t *test) {
				k, _ := cryptoService.Create("root", data.ED25519Key)
				Sign(cryptoService, t.s, k)
				t.keys = append(t.keys, k)
				t.roles["root"].Threshold = 2
			},
			err: ErrRoleThreshold{},
		},
		{
			name: "wrong type",
			typ:  "bar",
			err:  ErrWrongType,
		},
		{
			name: "low version",
			ver:  minVer - 1,
			err:  ErrLowVersion{minVer - 1, minVer},
		},
		{
			role: "root",
			name: "expired",
			exp:  &expiredTime,
			err:  ErrExpired{"root", expiredTime.Format("Mon Jan 2 15:04:05 MST 2006")},
		},
	}
	for _, run := range tests {
		if run.role == "" {
			run.role = "root"
		}
		if run.ver == 0 {
			run.ver = minVer
		}
		if run.exp == nil {
			expires := time.Now().Add(time.Hour)
			run.exp = &expires
		}
		if run.typ == "" {
			run.typ = data.TUFTypes[run.role]
		}
		if run.keys == nil && run.s == nil {
			k, _ := cryptoService.Create("root", data.ED25519Key)
			meta := &data.SignedCommon{Type: run.typ, Version: run.ver, Expires: *run.exp}

			b, err := cjson.Marshal(meta)
			assert.NoError(t, err)
			s := &data.Signed{Signed: b}
			Sign(cryptoService, s, k)
			run.s = s
			run.keys = []data.PublicKey{k}
		}
		if run.roles == nil {
			run.roles = map[string]*data.Role{
				"root": &data.Role{
					RootRole: data.RootRole{
						KeyIDs:    []string{run.keys[0].ID()},
						Threshold: 1,
					},
					Name: "root",
				},
			}
		}
		if run.mut != nil {
			run.mut(&run)
		}

		db := keys.NewDB()
		for _, k := range run.keys {
			db.AddKey(k)
		}
		for _, r := range run.roles {
			err := db.AddRole(r)
			assert.NoError(t, err)
		}

		err := Verify(run.s, run.role, minVer, db)
		if e, ok := run.err.(ErrExpired); ok {
			assertErrExpired(t, err, e)
		} else {
			assert.Equal(t, run.err, err)
		}
	}
}
예제 #18
0
파일: tuf.go 프로젝트: progrium/notary
func tufInit(cmd *cobra.Command, args []string) {
	if len(args) < 1 {
		cmd.Usage()
		fatalf("Must specify a GUN")
	}

	gun := args[0]
	kdb := keys.NewDB()
	signer := signed.NewSigner(NewCryptoService(gun))

	rootKey, err := signer.Create("root")
	if err != nil {
		fatalf(err.Error())
	}
	targetsKey, err := signer.Create("targets")
	if err != nil {
		fatalf(err.Error())
	}
	snapshotKey, err := signer.Create("snapshot")
	if err != nil {
		fatalf(err.Error())
	}
	timestampKey, err := signer.Create("timestamp")
	if err != nil {
		fatalf(err.Error())
	}

	kdb.AddKey(rootKey)
	kdb.AddKey(targetsKey)
	kdb.AddKey(snapshotKey)
	kdb.AddKey(timestampKey)

	rootRole, err := data.NewRole("root", 1, []string{rootKey.ID()}, nil, nil)
	if err != nil {
		fatalf(err.Error())
	}
	targetsRole, err := data.NewRole("targets", 1, []string{targetsKey.ID()}, nil, nil)
	if err != nil {
		fatalf(err.Error())
	}
	snapshotRole, err := data.NewRole("snapshot", 1, []string{snapshotKey.ID()}, nil, nil)
	if err != nil {
		fatalf(err.Error())
	}
	timestampRole, err := data.NewRole("timestamp", 1, []string{timestampKey.ID()}, nil, nil)
	if err != nil {
		fatalf(err.Error())
	}

	err = kdb.AddRole(rootRole)
	if err != nil {
		fatalf(err.Error())
	}
	err = kdb.AddRole(targetsRole)
	if err != nil {
		fatalf(err.Error())
	}
	err = kdb.AddRole(snapshotRole)
	if err != nil {
		fatalf(err.Error())
	}
	err = kdb.AddRole(timestampRole)
	if err != nil {
		fatalf(err.Error())
	}

	repo := tuf.NewTufRepo(kdb, signer)

	filestore, err := store.NewFilesystemStore(
		path.Join(viper.GetString("tufDir"), gun), // TODO: base trust dir from config
		"metadata",
		"json",
		"targets",
	)
	if err != nil {
		fatalf(err.Error())
	}

	err = repo.InitRepo(false)
	if err != nil {
		fatalf(err.Error())
	}
	saveRepo(repo, filestore)
}
예제 #19
0
파일: client.go 프로젝트: ChanderG/docker
// Initialize creates a new repository by using rootKey as the root Key for the
// TUF repository.
func (r *NotaryRepository) Initialize(uCryptoService *cryptoservice.UnlockedCryptoService) error {
	rootCert, err := uCryptoService.GenerateCertificate(r.gun)
	if err != nil {
		return err
	}
	r.KeyStoreManager.AddTrustedCert(rootCert)

	// The root key gets stored in the TUF metadata X509 encoded, linking
	// the tuf root.json to our X509 PKI.
	// If the key is RSA, we store it as type RSAx509, if it is ECDSA we store it
	// as ECDSAx509 to allow the gotuf verifiers to correctly decode the
	// key on verification of signatures.
	var algorithmType data.KeyAlgorithm
	algorithm := uCryptoService.PrivKey.Algorithm()
	switch algorithm {
	case data.RSAKey:
		algorithmType = data.RSAx509Key
	case data.ECDSAKey:
		algorithmType = data.ECDSAx509Key
	default:
		return fmt.Errorf("invalid format for root key: %s", algorithm)
	}

	// Generate a x509Key using the rootCert as the public key
	rootKey := data.NewPublicKey(algorithmType, trustmanager.CertToPEM(rootCert))

	// Creates a symlink between the certificate ID and the real public key it
	// is associated with. This is used to be able to retrieve the root private key
	// associated with a particular certificate
	logrus.Debugf("Linking %s to %s.", rootKey.ID(), uCryptoService.ID())
	err = r.KeyStoreManager.RootKeyStore().Link(uCryptoService.ID()+"_root", rootKey.ID()+"_root")
	if err != nil {
		return err
	}

	// All the timestamp keys are generated by the remote server.
	remote, err := getRemoteStore(r.baseURL, r.gun, r.roundTrip)
	rawTSKey, err := remote.GetKey("timestamp")
	if err != nil {
		return err
	}

	parsedKey := &data.TUFKey{}
	err = json.Unmarshal(rawTSKey, parsedKey)
	if err != nil {
		return err
	}

	// Turn the JSON timestamp key from the remote server into a TUFKey
	timestampKey := data.NewPublicKey(parsedKey.Algorithm(), parsedKey.Public())
	logrus.Debugf("got remote %s timestamp key with keyID: %s", parsedKey.Algorithm(), timestampKey.ID())

	// This is currently hardcoding the targets and snapshots keys to ECDSA
	// Targets and snapshot keys are always generated locally.
	targetsKey, err := r.cryptoService.Create("targets", data.ECDSAKey)
	if err != nil {
		return err
	}
	snapshotKey, err := r.cryptoService.Create("snapshot", data.ECDSAKey)
	if err != nil {
		return err
	}

	kdb := keys.NewDB()

	kdb.AddKey(rootKey)
	kdb.AddKey(targetsKey)
	kdb.AddKey(snapshotKey)
	kdb.AddKey(timestampKey)

	err = initRoles(kdb, rootKey, targetsKey, snapshotKey, timestampKey)
	if err != nil {
		return err
	}

	r.tufRepo = tuf.NewTufRepo(kdb, r.cryptoService)

	err = r.tufRepo.InitRoot(false)
	if err != nil {
		logrus.Debug("Error on InitRoot: ", err.Error())
		switch err.(type) {
		case tuferrors.ErrInsufficientSignatures, trustmanager.ErrPasswordInvalid:
		default:
			return err
		}
	}
	err = r.tufRepo.InitTargets()
	if err != nil {
		logrus.Debug("Error on InitTargets: ", err.Error())
		return err
	}
	err = r.tufRepo.InitSnapshot()
	if err != nil {
		logrus.Debug("Error on InitSnapshot: ", err.Error())
		return err
	}

	return r.saveMetadata(uCryptoService.CryptoService)
}
예제 #20
0
파일: client.go 프로젝트: jalateras/notary
// Initialize creates a new repository by using rootKey as the root Key for the
// TUF repository.
func (r *NotaryRepository) Initialize(uSigner *UnlockedSigner) error {
	rootCert, err := uSigner.GenerateCertificate(r.Gun)
	if err != nil {
		return err
	}
	r.certificateStore.AddCert(rootCert)
	rootKey := data.NewPublicKey("RSA", trustmanager.CertToPEM(rootCert))
	err = r.rootKeyStore.Link(uSigner.ID(), rootKey.ID())
	if err != nil {
		return err
	}

	remote, err := getRemoteStore(r.baseURL, r.Gun)
	rawTSKey, err := remote.GetKey("timestamp")
	if err != nil {
		return err
	}

	parsedKey := &data.TUFKey{}
	err = json.Unmarshal(rawTSKey, parsedKey)
	if err != nil {
		return err
	}

	timestampKey := data.NewPublicKey(parsedKey.Cipher(), parsedKey.Public())

	targetsKey, err := r.signer.Create("targets")
	if err != nil {
		return err
	}
	snapshotKey, err := r.signer.Create("snapshot")
	if err != nil {
		return err
	}

	kdb := keys.NewDB()

	kdb.AddKey(rootKey)
	kdb.AddKey(targetsKey)
	kdb.AddKey(snapshotKey)
	kdb.AddKey(timestampKey)

	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
	}

	r.tufRepo = tuf.NewTufRepo(kdb, r.signer)

	r.fileStore, err = store.NewFilesystemStore(
		r.tufRepoPath,
		"metadata",
		"json",
		"targets",
	)
	if err != nil {
		return err
	}

	if err := r.tufRepo.InitRepo(false); err != nil {
		return err
	}

	if err := r.saveMetadata(uSigner.signer); err != nil {
		return err
	}

	// Creates an empty snapshot
	return r.snapshot()
}
예제 #21
0
파일: validation.go 프로젝트: cxxly/notary
// validateUpload checks that the updates being pushed
// are semantically correct and the signatures are correct
func validateUpdate(gun string, updates []storage.MetaUpdate, store storage.MetaStore) error {
	kdb := keys.NewDB()
	repo := tuf.NewRepo(kdb, nil)
	rootRole := data.RoleName(data.CanonicalRootRole)
	targetsRole := data.RoleName(data.CanonicalTargetsRole)
	snapshotRole := data.RoleName(data.CanonicalSnapshotRole)

	// check that the necessary roles are present:
	roles := make(map[string]storage.MetaUpdate)
	for _, v := range updates {
		roles[v.Role] = v
	}
	if err := hierarchyOK(roles); err != nil {
		logrus.Error("ErrBadHierarchy: ", err.Error())
		return ErrBadHierarchy{msg: err.Error()}
	}
	logrus.Debug("Successfully validated hierarchy")

	var root *data.SignedRoot
	oldRootJSON, err := store.GetCurrent(gun, rootRole)
	if _, ok := err.(*storage.ErrNotFound); err != nil && !ok {
		// problem with storage. No expectation we can
		// write if we can't read so bail.
		logrus.Error("error reading previous root: ", err.Error())
		return err
	}
	if rootUpdate, ok := roles[rootRole]; ok {
		// if root is present, validate its integrity, possibly
		// against a previous root
		if root, err = validateRoot(gun, oldRootJSON, rootUpdate.Data); err != nil {
			logrus.Error("ErrBadRoot: ", err.Error())
			return ErrBadRoot{msg: err.Error()}
		}
		// setting root will update keys db
		if err = repo.SetRoot(root); err != nil {
			logrus.Error("ErrValidation: ", err.Error())
			return ErrValidation{msg: err.Error()}
		}
		logrus.Debug("Successfully validated root")
	} else {
		if oldRootJSON == nil {
			return ErrValidation{msg: "no pre-existing root and no root provided in update."}
		}
		parsedOldRoot := &data.SignedRoot{}
		if err := json.Unmarshal(oldRootJSON, parsedOldRoot); err != nil {
			return ErrValidation{msg: "pre-existing root is corrupted and no root provided in update."}
		}
		if err = repo.SetRoot(parsedOldRoot); err != nil {
			logrus.Error("ErrValidation: ", err.Error())
			return ErrValidation{msg: err.Error()}
		}
	}

	// TODO: validate delegated targets roles.
	var t *data.SignedTargets
	if _, ok := roles[targetsRole]; ok {
		if t, err = validateTargets(targetsRole, roles, kdb); err != nil {
			logrus.Error("ErrBadTargets: ", err.Error())
			return ErrBadTargets{msg: err.Error()}
		}
		repo.SetTargets(targetsRole, t)
	}
	logrus.Debug("Successfully validated targets")

	var oldSnap *data.SignedSnapshot
	oldSnapJSON, err := store.GetCurrent(gun, snapshotRole)
	if _, ok := err.(*storage.ErrNotFound); err != nil && !ok {
		// problem with storage. No expectation we can
		// write if we can't read so bail.
		logrus.Error("error reading previous snapshot: ", err.Error())
		return err
	} else if err == nil {
		oldSnap = &data.SignedSnapshot{}
		if err := json.Unmarshal(oldSnapJSON, oldSnap); err != nil {
			oldSnap = nil
		}
	}

	if err := validateSnapshot(snapshotRole, oldSnap, roles[snapshotRole], roles, kdb); err != nil {
		logrus.Error("ErrBadSnapshot: ", err.Error())
		return ErrBadSnapshot{msg: err.Error()}
	}
	logrus.Debug("Successfully validated snapshot")
	return nil
}
예제 #22
0
func (VerifySuite) Test(c *C) {
	trust := NewEd25519()
	type test struct {
		name  string
		keys  []*data.PublicKey
		roles map[string]*data.Role
		s     *data.Signed
		ver   int
		exp   *time.Time
		typ   string
		role  string
		err   error
		mut   func(*test)
	}

	expiredTime := time.Now().Add(-time.Hour)
	minVer := 10
	tests := []test{
		{
			name: "no signatures",
			mut:  func(t *test) { t.s.Signatures = []data.Signature{} },
			err:  ErrNoSignatures,
		},
		{
			name: "unknown role",
			role: "foo",
			err:  ErrUnknownRole,
		},
		//{
		//	name: "wrong signature method",
		//	mut:  func(t *test) { t.s.Signatures[0].Method = "foo" },
		//	err:  ErrWrongMethod,
		//},
		//	{
		//		name: "signature wrong length",
		//		mut:  func(t *test) { t.s.Signatures[0].Signature = []byte{0} },
		//		err:  ErrInvalid,
		//	},
		{
			name: "key missing from role",
			mut:  func(t *test) { t.roles["root"].KeyIDs = nil },
			err:  ErrRoleThreshold,
		},
		//	{
		//		name: "invalid signature",
		//		mut:  func(t *test) { t.s.Signatures[0].Signature = make([]byte, ed25519.SignatureSize) },
		//		err:  ErrInvalid,
		//	},
		{
			name: "not enough signatures",
			mut:  func(t *test) { t.roles["root"].Threshold = 2 },
			err:  ErrRoleThreshold,
		},
		{
			name: "exactly enough signatures",
		},
		{
			name: "more than enough signatures",
			mut: func(t *test) {
				k, _ := trust.Create("root", data.ED25519Key)
				Sign(trust, t.s, k)
				t.keys = append(t.keys, k)
				t.roles["root"].KeyIDs = append(t.roles["root"].KeyIDs, k.ID())
			},
		},
		{
			name: "duplicate key id",
			mut: func(t *test) {
				t.roles["root"].Threshold = 2
				t.s.Signatures = append(t.s.Signatures, t.s.Signatures[0])
			},
			err: ErrRoleThreshold,
		},
		{
			name: "unknown key",
			mut: func(t *test) {
				k, _ := trust.Create("root", data.ED25519Key)
				Sign(trust, t.s, k)
			},
		},
		{
			name: "unknown key below threshold",
			mut: func(t *test) {
				k, _ := trust.Create("root", data.ED25519Key)
				Sign(trust, t.s, k)
				t.roles["root"].Threshold = 2
			},
			err: ErrRoleThreshold,
		},
		{
			name: "unknown keys in db",
			mut: func(t *test) {
				k, _ := trust.Create("root", data.ED25519Key)
				Sign(trust, t.s, k)
				t.keys = append(t.keys, k)
			},
		},
		{
			name: "unknown keys in db below threshold",
			mut: func(t *test) {
				k, _ := trust.Create("root", data.ED25519Key)
				Sign(trust, t.s, k)
				t.keys = append(t.keys, k)
				t.roles["root"].Threshold = 2
			},
			err: ErrRoleThreshold,
		},
		{
			name: "wrong type",
			typ:  "bar",
			err:  ErrWrongType,
		},
		{
			name: "low version",
			ver:  minVer - 1,
			err:  ErrLowVersion{minVer - 1, minVer},
		},
		{
			name: "expired",
			exp:  &expiredTime,
			err:  ErrExpired{expiredTime.Format("2006-01-02 15:04:05 MST")},
		},
	}
	for _, t := range tests {
		if t.role == "" {
			t.role = "root"
		}
		if t.ver == 0 {
			t.ver = minVer
		}
		if t.exp == nil {
			expires := time.Now().Add(time.Hour)
			t.exp = &expires
		}
		if t.typ == "" {
			t.typ = data.TUFTypes[t.role]
		}
		if t.keys == nil && t.s == nil {
			k, _ := trust.Create("root", data.ED25519Key)
			meta := &signedMeta{Type: t.typ, Version: t.ver, Expires: t.exp.Format("2006-01-02 15:04:05 MST")}

			b, err := cjson.Marshal(meta)
			c.Assert(err, IsNil)
			s := &data.Signed{Signed: b}
			Sign(trust, s, k)
			t.s = s
			t.keys = []*data.PublicKey{k}
		}
		if t.roles == nil {
			t.roles = map[string]*data.Role{
				"root": &data.Role{
					RootRole: data.RootRole{
						KeyIDs:    []string{t.keys[0].ID()},
						Threshold: 1,
					},
					Name: "root",
				},
			}
		}
		if t.mut != nil {
			t.mut(&t)
		}

		db := keys.NewDB()
		for _, k := range t.keys {
			db.AddKey(k)
		}
		for _, r := range t.roles {
			err := db.AddRole(r)
			c.Assert(err, IsNil)
		}

		err := Verify(t.s, t.role, minVer, db)
		if e, ok := t.err.(ErrExpired); ok {
			assertErrExpired(c, err, e)
		} else {
			c.Assert(err, DeepEquals, t.err, Commentf("name = %s", t.name))
		}
	}
}