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) } }
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) }
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 }
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) } } }
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) }
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.") }
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) }
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 }
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 }
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.") }
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 }
// 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 }
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) }
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 }
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) }
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) } }
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) } } }
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) }
// 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) }
// 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() }
// 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 }
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)) } } }