diff --git a/Godeps/Godeps.json b/Godeps/Godeps.json index 0c43be0a63..c24dd8f672 100644 --- a/Godeps/Godeps.json +++ b/Godeps/Godeps.json @@ -52,7 +52,7 @@ }, { "ImportPath": "github.com/endophage/gotuf", - "Rev": "ab4ba80203ffa5bfd742e6891bd28bfbf43a9453" + "Rev": "82786136d505f582d0f898a2e80c9f6b97b1402c" }, { "ImportPath": "github.com/go-sql-driver/mysql", diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/README.md b/Godeps/_workspace/src/github.com/endophage/gotuf/README.md index 5b436c3116..3c50f8b8b5 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/README.md +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/README.md @@ -1,24 +1,36 @@ +# GOTUF + This is still a work in progress but will shortly be a fully compliant Go implementation of [The Update Framework (TUF)](http://theupdateframework.com/). +## Where's the CLI + +This repository provides a library only. The [Notary project](https://github.com/docker/notary) +from Docker should be considered the official CLI to be used with this implementation of TUF. + +## TODOs: + +- [X] Add Targets to existing repo +- [X] Sign metadata files +- [X] Refactor TufRepo to take care of signing ~~and verification~~ +- [ ] Ensure consistent capitalization in naming (TUF\_\_\_ vs Tuf\_\_\_) +- [ ] Make caching of metadata files smarter - PR #5 +- [ ] ~~Add configuration for CLI commands. Order of configuration priority from most to least: flags, config file, defaults~~ Notary should be the official CLI +- [X] Reasses organization of data types. Possibly consolidate a few things into the data package but break up package into a few more distinct files +- [ ] Comprehensive test cases +- [ ] Delete files no longer in use +- [ ] Fix up errors. Some have to be instantiated, others don't, the inconsistency is annoying. +- [X] Bump version numbers in meta files (could probably be done better) + +## Credits + This implementation was originally forked from [flynn/go-tuf](https://github.com/flynn/go-tuf), however in attempting to add delegations I found I was making such significant changes that I could not maintain backwards compatibility without the code becoming overly convoluted. +Some features such as pluggable verifiers have alreayd been merged upstream to flynn/go-tuf +and we are in discussion with [titanous](https://github.com/titanous) about working to merge the 2 implementations. + This implementation retains the same 3 Clause BSD license present on the original flynn implementation. - -TODOs: - -- [X] Add Targets to existing repo -- [X] Sign metadata files -- [X] Refactor TufRepo to take care of signing ~~and verification~~ -- [ ] Ensure consistent capitalization in naming (TUF\_\_\_ vs Tuf\_\_\_) -- [ ] Make caching of metadata files smarter -- [ ] ~~Add configuration for CLI commands. Order of configuration priority from most to least: flags, config file, defaults~~ Notary should be the official CLI -- [ ] Reasses organization of data types. Possibly consolidate a few things into the data package but break up package into a few more distinct files -- [ ] Comprehensive test cases -- [ ] Delete files no longer in use -- [ ] Fix up errors. Some have to be instantiated, others don't, the inconsistency is annoying. -- [X] Bump version numbers in meta files (could probably be done better) diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/client/download.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/client/download.go deleted file mode 100644 index 4c187b830b..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/client/download.go +++ /dev/null @@ -1,111 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "os" - "path/filepath" - - "github.com/codegangsta/cli" - "github.com/endophage/gotuf/keys" - - "github.com/endophage/gotuf" - "github.com/endophage/gotuf/client" - "github.com/endophage/gotuf/data" - "github.com/endophage/gotuf/store" -) - -var commandDownload = cli.Command{ - Name: "download", - Usage: "provide the path to a target you wish to download.", - Action: download, -} - -func init() { - commandDownload.Flags = []cli.Flag{ - cli.StringFlag{ - Name: "root, r", - Value: "", - Usage: "The local file path to the current, or immediately previous, root.json for the TUF repo.", - EnvVar: "TUF_ROOT", - }, - cli.StringFlag{ - Name: "host, h", - Value: "", - Usage: "The scheme and hostname of the TUF repository, e.g. http://example.com/.", - EnvVar: "TUF_HOST", - }, - cli.StringFlag{ - Name: "meta, m", - Value: "", - Usage: "The path prefix for TUF metadata files.", - EnvVar: "TUF_META_PREFIX", - }, - cli.StringFlag{ - Name: "ext, e", - Value: "json", - Usage: "The file extension for TUF metadata files.", - EnvVar: "TUF_META_EXT", - }, - cli.StringFlag{ - Name: "targets, t", - Value: "", - Usage: "The path prefix for target files.", - EnvVar: "TUF_TARGETS_PREFIX", - }, - } -} - -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.") -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/client/main.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/client/main.go deleted file mode 100644 index 4dd2a11fb1..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/client/main.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "os" - - "github.com/codegangsta/cli" -) - -func main() { - app := cli.NewApp() - app.Name = "tufc" - app.Usage = "tuf download " - - app.Flags = []cli.Flag{ - cli.StringFlag{ - Name: "config", - Value: "config.json", - Usage: "Set the path to a json configuration file for the TUF repo you want to interact with.", - }, - } - - app.Commands = []cli.Command{ - commandDownload, - } - - app.Run(os.Args) -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tools/main.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tools/main.go deleted file mode 100644 index bdd42798fe..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tools/main.go +++ /dev/null @@ -1,84 +0,0 @@ -package main - -import ( - "fmt" - "log" - - "github.com/endophage/gotuf" - "github.com/endophage/gotuf/signed" - "github.com/endophage/gotuf/store" - "github.com/endophage/gotuf/testutils" - "github.com/flynn/go-docopt" -) - -func main() { - log.SetFlags(0) - - usage := `usage: tuftools [-h|--help] [...] - -Options: - -h, --help - -Commands: - help Show usage for a specific command - meta Generate metadata from the given file path - -See "tuf help " for more information on a specific command -` - - args, _ := docopt.Parse(usage, nil, true, "", true) - cmd := args.String[""] - cmdArgs := args.All[""].([]string) - - if cmd == "help" { - if len(cmdArgs) == 0 { // `tuf help` - fmt.Println(usage) - return - } else { // `tuf help ` - cmd = cmdArgs[0] - cmdArgs = []string{"--help"} - } - } - - if err := runCommand(cmd, cmdArgs); err != nil { - log.Fatalln("ERROR:", err) - } -} - -type cmdFunc func(*docopt.Args, *tuf.Repo) error - -type command struct { - usage string - f cmdFunc -} - -var commands = make(map[string]*command) - -func register(name string, f cmdFunc, usage string) { - commands[name] = &command{usage: usage, f: f} -} - -func runCommand(name string, args []string) error { - argv := make([]string, 1, 1+len(args)) - argv[0] = name - argv = append(argv, args...) - - cmd, ok := commands[name] - if !ok { - return fmt.Errorf("%s is not a tuf command. See 'tuf help'", name) - } - - parsedArgs, err := docopt.Parse(cmd.usage, argv, true, "", true) - if err != nil { - return err - } - - db := testutils.GetSqliteDB() - local := store.DBStore(db, "") - signer := signed.Ed25519{} - repo, err := tuf.NewRepo(&signer, local, "sha256") - if err != nil { - return err - } - return cmd.f(parsedArgs, repo) -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tools/meta.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tools/meta.go deleted file mode 100644 index 5ba108813c..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tools/meta.go +++ /dev/null @@ -1,39 +0,0 @@ -package main - -import ( - "encoding/json" - "fmt" - "io/ioutil" - "os" - - "github.com/endophage/gotuf" - "github.com/endophage/gotuf/data" - "github.com/flynn/go-docopt" -) - -func init() { - register("meta", cmdMeta, ` -usage: tuftools meta [...] - -Generate sample metadata for file(s) given by path. - -`) -} - -func cmdMeta(args *docopt.Args, repo *tuf.Repo) error { - paths := args.All[""].([]string) - for _, file := range paths { - reader, _ := os.Open(file) - meta, _ := data.NewFileMeta(reader, "sha256") - jsonBytes, err := json.Marshal(meta) - if err != nil { - return err - } - filename := fmt.Sprintf("%s.meta.json", file) - err = ioutil.WriteFile(filename, jsonBytes, 0644) - if err != nil { - return err - } - } - return nil -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/README.md b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/README.md deleted file mode 100644 index 0bafb6a3a2..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/README.md +++ /dev/null @@ -1,48 +0,0 @@ -# go-tuf client CLI - -## Install - -``` -go get github.com/flynn/go-tuf/cmd/tuf-client -``` - -## Usage - -The CLI provides three commands: - -* `tuf-client init` - initialize a local file store using root keys (e.g. from - the output of `tuf root-keys`) -* `tuf-client list` - list available targets and their file sizes -* `tuf-client get` - get a target file and write to STDOUT - -All commands require the base URL of the TUF repository as the first non-flag -argument, and accept an optional `--store` flag which is the path to the local -storage. - -Run `tuf-client help` from the command line to get more detailed usage -information. - -## Examples - -``` -# init -$ tuf-client init https://example.com/path/to/repo - -# init with a custom store path -$ tuf-client init --store /tmp/tuf.db https://example.com/path/to/repo - -# list available targets -$ tuf-client list https://example.com/path/to/repo -PATH SIZE -/foo.txt 1.6KB -/bar.txt 336B -/baz.txt 1.5KB - -# get a target -$ tuf-client get https://example.com/path/to/repo /foo.txt -the contents of foo.txt - -# the prefixed / is optional -$ tuf-client get https://example.com/path/to/repo foo.txt -the contents of foo.txt -``` diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/get.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/get.go deleted file mode 100644 index e699cbc170..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/get.go +++ /dev/null @@ -1,52 +0,0 @@ -package main - -import ( - "io" - "io/ioutil" - "os" - - tuf "github.com/endophage/gotuf/client" - "github.com/endophage/gotuf/utils" - "github.com/flynn/go-docopt" -) - -func init() { - register("get", cmdGet, ` -usage: tuf-client get [-s|--store=] - -Options: - -s The path to the local file store [default: tuf.db] - -Get a target from the repository. - `) -} - -type tmpFile struct { - *os.File -} - -func (t *tmpFile) Delete() error { - t.Close() - return os.Remove(t.Name()) -} - -func cmdGet(args *docopt.Args, client *tuf.Client) error { - if _, err := client.Update(); err != nil && !tuf.IsLatestSnapshot(err) { - return err - } - target := utils.NormalizeTarget(args.String[""]) - file, err := ioutil.TempFile("", "gotuf") - if err != nil { - return err - } - tmp := tmpFile{file} - if err := client.Download(target, &tmp); err != nil { - return err - } - defer tmp.Delete() - if _, err := tmp.Seek(0, os.SEEK_SET); err != nil { - return err - } - _, err = io.Copy(os.Stdout, file) - return err -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/init.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/init.go deleted file mode 100644 index b9ba0cb1f3..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/init.go +++ /dev/null @@ -1,41 +0,0 @@ -package main - -import ( - "encoding/json" - "io" - "os" - - tuf "github.com/endophage/gotuf/client" - "github.com/endophage/gotuf/data" - "github.com/flynn/go-docopt" -) - -func init() { - register("init", cmdInit, ` -usage: tuf-client init [-s|--store=] [] - -Options: - -s The path to the local file store [default: tuf.db] - -Initialize the local file store with root keys. - `) -} - -func cmdInit(args *docopt.Args, client *tuf.Client) error { - file := args.String[""] - var in io.Reader - if file == "" || file == "-" { - in = os.Stdin - } else { - var err error - in, err = os.Open(file) - if err != nil { - return err - } - } - var rootKeys []*data.Key - if err := json.NewDecoder(in).Decode(&rootKeys); err != nil { - return err - } - return client.Init(rootKeys, len(rootKeys)) -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/list.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/list.go deleted file mode 100644 index 495eca69ac..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/list.go +++ /dev/null @@ -1,39 +0,0 @@ -package main - -import ( - "fmt" - "os" - "text/tabwriter" - - "github.com/dustin/go-humanize" - tuf "github.com/endophage/gotuf/client" - "github.com/flynn/go-docopt" -) - -func init() { - register("list", cmdList, ` -usage: tuf-client list [-s|--store=] - -Options: - -s The path to the local file store [default: tuf.db] - -List available target files. - `) -} - -func cmdList(args *docopt.Args, client *tuf.Client) error { - if _, err := client.Update(); err != nil && !tuf.IsLatestSnapshot(err) { - return err - } - targets, err := client.Targets() - if err != nil { - return err - } - w := tabwriter.NewWriter(os.Stdout, 1, 2, 2, ' ', 0) - defer w.Flush() - fmt.Fprintln(w, "PATH\tSIZE") - for path, meta := range targets { - fmt.Fprintf(w, "%s\t%s\n", path, humanize.Bytes(uint64(meta.Length))) - } - return nil -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/main.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/main.go deleted file mode 100644 index d43a55e992..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf-client/main.go +++ /dev/null @@ -1,94 +0,0 @@ -package main - -import ( - "fmt" - "log" - - "github.com/endophage/gotuf/client" - "github.com/endophage/gotuf/store" - "github.com/flynn/go-docopt" -) - -func main() { - log.SetFlags(0) - - usage := `usage: tuf-client [-h|--help] [...] - -Options: - -h, --help - -Commands: - help Show usage for a specific command - init Initialize with root keys - list List available target files - get Get a target file - -See "tuf-client help " for more information on a specific command. -` - - args, _ := docopt.Parse(usage, nil, true, "", true) - cmd := args.String[""] - cmdArgs := args.All[""].([]string) - - if cmd == "help" { - if len(cmdArgs) == 0 { // `tuf-client help` - fmt.Println(usage) - return - } else { // `tuf-client help ` - cmd = cmdArgs[0] - cmdArgs = []string{"--help"} - } - } - - if err := runCommand(cmd, cmdArgs); err != nil { - log.Fatalln("ERROR:", err) - } -} - -type cmdFunc func(*docopt.Args, *client.Client) error - -type command struct { - usage string - f cmdFunc -} - -var commands = make(map[string]*command) - -func register(name string, f cmdFunc, usage string) { - commands[name] = &command{usage: usage, f: f} -} - -func runCommand(name string, args []string) error { - argv := make([]string, 1, 1+len(args)) - argv[0] = name - argv = append(argv, args...) - - cmd, ok := commands[name] - if !ok { - return fmt.Errorf("%s is not a tuf-client command. See 'tuf-client help'", name) - } - - parsedArgs, err := docopt.Parse(cmd.usage, argv, true, "", true) - if err != nil { - return err - } - - client, err := tufClient(parsedArgs) - if err != nil { - return err - } - return cmd.f(parsedArgs, client) -} - -func tufClient(args *docopt.Args) (*client.Client, error) { - storePath, ok := args.String["--store"] - if !ok { - storePath = args.String["-s"] - } - local := store.FileSystemStore(storePath, nil) - remote, err := client.HTTPRemoteStore(args.String[""], nil) - if err != nil { - return nil, err - } - return client.NewClient(local, remote), nil -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/add.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/add.go deleted file mode 100644 index 088fc78725..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/add.go +++ /dev/null @@ -1,36 +0,0 @@ -package main - -import ( - // "encoding/json" - - "github.com/endophage/gotuf" - "github.com/flynn/go-docopt" -) - -func init() { - register("add", cmdAdd, ` -usage: tuf add [--expires=] [--custom=] [...] - -Add target file(s). - -Options: - --expires= Set the targets manifest to expire days from now. - --custom= Set custom JSON data for the target(s). -`) -} - -func cmdAdd(args *docopt.Args, repo *tuf.Repo) error { - // var custom json.RawMessage - // if c := args.String["--custom"]; c != "" { - // custom = json.RawMessage(c) - // } - paths := args.All[""].([]string) - if arg := args.String["--expires"]; arg != "" { - expires, err := parseExpires(arg) - if err != nil { - return err - } - return repo.AddTargetsWithExpires(nil, expires, paths...) - } - return repo.AddTargets(nil, paths...) -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/clean.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/clean.go deleted file mode 100644 index e8eb07e76c..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/clean.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "github.com/endophage/gotuf" - "github.com/flynn/go-docopt" -) - -func init() { - register("clean", cmdClean, ` -usage: tuf clean - -Remove all staged manifests. - `) -} - -func cmdClean(args *docopt.Args, repo *tuf.Repo) error { - return repo.Clean() -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/commit.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/commit.go deleted file mode 100644 index 6fbe4ce9a2..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/commit.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "github.com/endophage/gotuf" - "github.com/flynn/go-docopt" -) - -func init() { - register("commit", cmdCommit, ` -usage: tuf commit - -Commit staged files to the repository. -`) -} - -func cmdCommit(args *docopt.Args, repo *tuf.Repo) error { - return repo.Commit() -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/gen_key.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/gen_key.go deleted file mode 100644 index ba55600c14..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/gen_key.go +++ /dev/null @@ -1,43 +0,0 @@ -package main - -import ( - "fmt" - - "github.com/endophage/gotuf" - "github.com/flynn/go-docopt" -) - -func init() { - register("gen-key", cmdGenKey, ` -usage: tuf gen-key [--expires=] - -Generate a new signing key for the given role. - -The key will be serialized to JSON and written to the "keys" directory with -filename pattern "ROLE-KEYID.json". The root manifest will also be staged -with the addition of the key's ID to the role's list of key IDs. - -Options: - --expires= Set the root manifest to expire days from now. -`) -} - -func cmdGenKey(args *docopt.Args, repo *tuf.Repo) error { - role := args.String[""] - var id string - var err error - if arg := args.String["--expires"]; arg != "" { - expires, err := parseExpires(arg) - if err != nil { - return err - } - id, err = repo.GenKeyWithExpires(role, expires) - } else { - id, err = repo.GenKey(role) - } - if err != nil { - return err - } - fmt.Println("Generated", role, "key with ID", id) - return nil -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/init.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/init.go deleted file mode 100644 index 11e5e81e0f..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/init.go +++ /dev/null @@ -1,23 +0,0 @@ -package main - -import ( - "github.com/endophage/gotuf" - "github.com/flynn/go-docopt" -) - -func init() { - register("init", cmdInit, ` -usage: tuf init [--consistent-snapshot=false] - -Initialize a new repository. - -This is only required if the repository should not generate consistent -snapshots (i.e. by passing "--consistent-snapshot=false"). If consistent -snapshots should be generated, the repository will be implicitly -initialized to do so when generating keys. - `) -} - -func cmdInit(args *docopt.Args, repo *tuf.Repo) error { - return repo.Init(args.String["--consistent-snapshot"] != "false") -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/main.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/main.go deleted file mode 100644 index 09f3836c73..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/main.go +++ /dev/null @@ -1,167 +0,0 @@ -package main - -import ( - "bufio" - "bytes" - "errors" - "fmt" - "log" - "os" - "strconv" - "strings" - "time" - - "github.com/docker/docker/pkg/term" - "github.com/flynn/go-docopt" - - "github.com/endophage/gotuf" - "github.com/endophage/gotuf/signed" - "github.com/endophage/gotuf/store" - "github.com/endophage/gotuf/utils" -) - -func main() { - log.SetFlags(0) - - usage := `usage: tuf [-h|--help] [-d|--dir=] [--insecure-plaintext] [...] - -Options: - -h, --help - -d The path to the repository (defaults to the current working directory) - --insecure-plaintext Don't encrypt signing keys - -Commands: - help Show usage for a specific command - gen-key Generate a new signing key for a specific manifest - revoke-key Revoke a signing key - add Add target file(s) - remove Remove a target file - snapshot Update the snapshot manifest - timestamp Update the timestamp manifest - sign Sign a manifest - commit Commit staged files to the repository - regenerate Recreate the targets manifest - clean Remove all staged manifests - root-keys Output a JSON serialized array of root keys to STDOUT - -See "tuf help " for more information on a specific command -` - - args, _ := docopt.Parse(usage, nil, true, "", true) - cmd := args.String[""] - cmdArgs := args.All[""].([]string) - - if cmd == "help" { - if len(cmdArgs) == 0 { // `tuf help` - fmt.Println(usage) - return - } else { // `tuf help ` - cmd = cmdArgs[0] - cmdArgs = []string{"--help"} - } - } - - dir, ok := args.String["-d"] - if !ok { - dir = args.String["--dir"] - } - if dir == "" { - var err error - dir, err = os.Getwd() - if err != nil { - log.Fatal(err) - } - } - - if err := runCommand(cmd, cmdArgs, dir, args.Bool["--insecure-plaintext"]); err != nil { - log.Fatalln("ERROR:", err) - } -} - -type cmdFunc func(*docopt.Args, *tuf.Repo) error - -type command struct { - usage string - f cmdFunc -} - -var commands = make(map[string]*command) - -func register(name string, f cmdFunc, usage string) { - commands[name] = &command{usage: usage, f: f} -} - -func runCommand(name string, args []string, dir string, insecure bool) error { - argv := make([]string, 1, 1+len(args)) - argv[0] = name - argv = append(argv, args...) - - cmd, ok := commands[name] - if !ok { - return fmt.Errorf("%s is not a tuf command. See 'tuf help'", name) - } - - parsedArgs, err := docopt.Parse(cmd.usage, argv, true, "", true) - if err != nil { - return err - } - - var p utils.PassphraseFunc - if !insecure { - p = getPassphrase - } - signer := signed.Ed25519{} - repo, err := tuf.NewRepo(&signer, store.FileSystemStore(dir, p), "sha256") - if err != nil { - return err - } - return cmd.f(parsedArgs, repo) -} - -func parseExpires(arg string) (time.Time, error) { - days, err := strconv.Atoi(arg) - if err != nil { - return time.Time{}, fmt.Errorf("failed to parse --expires arg: %s", err) - } - return time.Now().AddDate(0, 0, days).UTC(), nil -} - -func getPassphrase(role string, confirm bool) ([]byte, error) { - if pass := os.Getenv(fmt.Sprintf("TUF_%s_PASSPHRASE", strings.ToUpper(role))); pass != "" { - return []byte(pass), nil - } - - state, err := term.SaveState(0) - if err != nil { - return nil, err - } - term.DisableEcho(0, state) - defer term.RestoreTerminal(0, state) - - stdin := bufio.NewReader(os.Stdin) - - fmt.Printf("Enter %s keys passphrase: ", role) - passphrase, err := stdin.ReadBytes('\n') - fmt.Println() - if err != nil { - return nil, err - } - passphrase = passphrase[0 : len(passphrase)-1] - - if !confirm { - return passphrase, nil - } - - fmt.Printf("Repeat %s keys passphrase: ", role) - confirmation, err := stdin.ReadBytes('\n') - fmt.Println() - if err != nil { - return nil, err - } - confirmation = confirmation[0 : len(confirmation)-1] - - if !bytes.Equal(passphrase, confirmation) { - return nil, errors.New("The entered passphrases do not match") - } - return passphrase, nil -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/regenerate.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/regenerate.go deleted file mode 100644 index b3bba56720..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/regenerate.go +++ /dev/null @@ -1,22 +0,0 @@ -package main - -import ( - "log" - - "github.com/endophage/gotuf" - "github.com/flynn/go-docopt" -) - -func init() { - register("regenerate", cmdRegenerate, ` -usage: tuf regenerate [--consistent-snapshot=false] - -Recreate the targets manifest. - `) -} - -func cmdRegenerate(args *docopt.Args, repo *tuf.Repo) error { - // TODO: implement this - log.Println("not implemented") - return nil -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/remove.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/remove.go deleted file mode 100644 index 471fd113f0..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/remove.go +++ /dev/null @@ -1,35 +0,0 @@ -package main - -import ( - "errors" - - "github.com/endophage/gotuf" - "github.com/flynn/go-docopt" -) - -func init() { - register("remove", cmdRemove, ` -usage: tuf remove [--expires=] [--all] [...] - -Remove target file(s). - -Options: - --all Remove all target files. - --expires= Set the targets manifest to expire days from now. -`) -} - -func cmdRemove(args *docopt.Args, repo *tuf.Repo) error { - paths := args.All[""].([]string) - if len(paths) == 0 && !args.Bool["--all"] { - return errors.New("either specify some paths or set the --all flag to remove all targets") - } - if arg := args.String["--expires"]; arg != "" { - expires, err := parseExpires(arg) - if err != nil { - return err - } - return repo.RemoveTargetsWithExpires(expires, paths...) - } - return repo.RemoveTargets(paths) -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/revoke_key.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/revoke_key.go deleted file mode 100644 index c176e098dd..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/revoke_key.go +++ /dev/null @@ -1,31 +0,0 @@ -package main - -import ( - "github.com/endophage/gotuf" - "github.com/flynn/go-docopt" -) - -func init() { - register("revoke-key", cmdRevokeKey, ` -usage: tuf revoke-key [--expires=] - -Revoke a signing key - -The key will be removed from the root manifest, but the key will remain in the -"keys" directory if present. - -Options: - --expires= Set the root manifest to expire days from now. -`) -} - -func cmdRevokeKey(args *docopt.Args, repo *tuf.Repo) error { - if arg := args.String["--expires"]; arg != "" { - expires, err := parseExpires(arg) - if err != nil { - return err - } - return repo.RevokeKeyWithExpires(args.String[""], args.String[""], expires) - } - return repo.RevokeKey(args.String[""], args.String[""]) -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/root_keys.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/root_keys.go deleted file mode 100644 index 2cafff1559..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/root_keys.go +++ /dev/null @@ -1,27 +0,0 @@ -package main - -import ( - "encoding/json" - "os" - - "github.com/endophage/gotuf" - "github.com/flynn/go-docopt" -) - -func init() { - register("root-keys", cmdRootKeys, ` -usage: tuf root-keys - -Outputs a JSON serialized array of root keys to STDOUT. - -The resulting JSON should be distributed to clients for performing initial updates. -`) -} - -func cmdRootKeys(args *docopt.Args, repo *tuf.Repo) error { - keys, err := repo.RootKeys() - if err != nil { - return err - } - return json.NewEncoder(os.Stdout).Encode(keys) -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/sign.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/sign.go deleted file mode 100644 index d92267cd69..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/sign.go +++ /dev/null @@ -1,18 +0,0 @@ -package main - -import ( - "github.com/endophage/gotuf" - "github.com/flynn/go-docopt" -) - -func init() { - register("sign", cmdSign, ` -usage: tuf sign - -Sign a manifest. -`) -} - -func cmdSign(args *docopt.Args, repo *tuf.Repo) error { - return repo.Sign(args.String[""]) -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/snapshot.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/snapshot.go deleted file mode 100644 index 2a6aa67cc1..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/snapshot.go +++ /dev/null @@ -1,29 +0,0 @@ -package main - -import ( - "github.com/endophage/gotuf" - "github.com/flynn/go-docopt" -) - -func init() { - register("snapshot", cmdSnapshot, ` -usage: tuf snapshot [--expires=] [--compression=] - -Update the snapshot manifest. - -Options: - --expires= Set the snapshot manifest to expire days from now. -`) -} - -func cmdSnapshot(args *docopt.Args, repo *tuf.Repo) error { - // TODO: parse --compression - if arg := args.String["--expires"]; arg != "" { - expires, err := parseExpires(arg) - if err != nil { - return err - } - return repo.SnapshotWithExpires(tuf.CompressionTypeNone, expires) - } - return repo.Snapshot(tuf.CompressionTypeNone) -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/timestamp.go b/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/timestamp.go deleted file mode 100644 index a3ba349d3a..0000000000 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/cmd/tuf/timestamp.go +++ /dev/null @@ -1,28 +0,0 @@ -package main - -import ( - "github.com/endophage/gotuf" - "github.com/flynn/go-docopt" -) - -func init() { - register("timestamp", cmdTimestamp, ` -usage: tuf timestamp [--expires=] - -Update the timestamp manifest. - -Options: - --expires= Set the timestamp manifest to expire days from now. -`) -} - -func cmdTimestamp(args *docopt.Args, repo *tuf.Repo) error { - if arg := args.String["--expires"]; arg != "" { - expires, err := parseExpires(arg) - if err != nil { - return err - } - return repo.TimestampWithExpires(expires) - } - return repo.Timestamp() -} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/data/keys.go b/Godeps/_workspace/src/github.com/endophage/gotuf/data/keys.go index 4287ef8ec4..b0eb564d03 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/data/keys.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/data/keys.go @@ -10,7 +10,7 @@ import ( type Key interface { ID() string - Cipher() string + Algorithm() KeyAlgorithm Public() []byte Private() []byte } @@ -21,14 +21,14 @@ type KeyPair struct { } type TUFKey struct { - id string `json:"-"` - Type string `json:"keytype"` - Value KeyPair `json:"keyval"` + id string `json:"-"` + Type KeyAlgorithm `json:"keytype"` + Value KeyPair `json:"keyval"` } -func NewTUFKey(cipher string, public, private []byte) *TUFKey { +func NewTUFKey(algorithm KeyAlgorithm, public, private []byte) *TUFKey { return &TUFKey{ - Type: cipher, + Type: algorithm, Value: KeyPair{ Public: public, Private: private, @@ -36,13 +36,13 @@ func NewTUFKey(cipher string, public, private []byte) *TUFKey { } } -func (k TUFKey) Cipher() string { +func (k TUFKey) Algorithm() KeyAlgorithm { return k.Type } func (k *TUFKey) ID() string { if k.id == "" { - pubK := NewTUFKey(k.Cipher(), k.Public(), nil) + pubK := NewTUFKey(k.Algorithm(), k.Public(), nil) data, err := cjson.Marshal(&pubK) if err != nil { logrus.Error("Error generating key ID:", err) @@ -65,10 +65,10 @@ func (k PublicKey) Private() []byte { return nil } -func NewPublicKey(cipher string, public []byte) *PublicKey { +func NewPublicKey(algorithm KeyAlgorithm, public []byte) *PublicKey { return &PublicKey{ TUFKey{ - Type: cipher, + Type: algorithm, Value: KeyPair{ Public: public, Private: nil, @@ -87,10 +87,10 @@ type PrivateKey struct { TUFKey } -func NewPrivateKey(cipher string, public, private []byte) *PrivateKey { +func NewPrivateKey(algorithm KeyAlgorithm, public, private []byte) *PrivateKey { return &PrivateKey{ TUFKey{ - Type: cipher, + Type: algorithm, Value: KeyPair{ Public: []byte(public), Private: []byte(private), diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/data/types.go b/Godeps/_workspace/src/github.com/endophage/gotuf/data/types.go index eccaf2e3ef..a0baa4dd97 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/data/types.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/data/types.go @@ -8,21 +8,37 @@ import ( "hash" "io" "io/ioutil" + "strings" "time" "github.com/Sirupsen/logrus" ) +type KeyAlgorithm string + +func (k KeyAlgorithm) String() string { + return string(k) +} + +type SigAlgorithm string + +func (k SigAlgorithm) String() string { + return string(k) +} + const ( defaultHashAlgorithm = "sha256" - EDDSASignature = "eddsa" - RSAPSSSignature = "rsapss" - ECDSASignature = "ecdsa" - RSAKey = "rsa" - RSAx509Key = "rsa-x509" - ECDSAKey = "ecdsa" - ECDSAx509Key = "ecdsa-x509" - PyCryptoSignature = "pycrypto-pkcs#1 pss" + + EDDSASignature SigAlgorithm = "eddsa" + RSAPSSSignature SigAlgorithm = "rsapss" + ECDSASignature SigAlgorithm = "ecdsa" + PyCryptoSignature SigAlgorithm = "pycrypto-pkcs#1 pss" + + ED25519Key KeyAlgorithm = "ed25519" + RSAKey KeyAlgorithm = "rsa" + RSAx509Key KeyAlgorithm = "rsa-x509" + ECDSAKey KeyAlgorithm = "ecdsa" + ECDSAx509Key KeyAlgorithm = "ecdsa-x509" ) var TUFTypes = map[string]string{ @@ -63,9 +79,9 @@ type Signed struct { } type Signature struct { - KeyID string `json:"keyid"` - Method string `json:"method"` - Signature HexBytes `json:"sig"` + KeyID string `json:"keyid"` + Method SigAlgorithm `json:"method"` + Signature HexBytes `json:"sig"` } type Files map[string]FileMeta @@ -144,3 +160,16 @@ func DefaultExpires(role string) time.Time { } return t.UTC().Round(time.Second) } + +type unmarshalledSignature Signature + +func (s *Signature) UnmarshalJSON(data []byte) error { + uSignature := unmarshalledSignature{} + err := json.Unmarshal(data, &uSignature) + if err != nil { + return err + } + uSignature.Method = SigAlgorithm(strings.ToLower(string(uSignature.Method))) + *s = Signature(uSignature) + return nil +} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/data/types_test.go b/Godeps/_workspace/src/github.com/endophage/gotuf/data/types_test.go index 14b032fc1d..e91ceba5be 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/data/types_test.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/data/types_test.go @@ -2,6 +2,7 @@ package data import ( "bytes" + "encoding/json" . "gopkg.in/check.v1" ) @@ -43,3 +44,14 @@ func (TypesSuite) TestGenerateFileMetaExplicit(c *C) { c.Assert(hash.String(), DeepEquals, val) } } + +func (TypesSuite) TestSignatureUnmarshalJSON(c *C) { + signatureJSON := `{"keyid":"97e8e1b51b6e7cf8720a56b5334bd8692ac5b28233c590b89fab0b0cd93eeedc","method":"RSA","sig":"2230cba525e4f5f8fc744f234221ca9a92924da4cc5faf69a778848882fcf7a20dbb57296add87f600891f2569a9c36706314c240f9361c60fd36f5a915a0e9712fc437b761e8f480868d7a4444724daa0d29a2669c0edbd4046046649a506b3d711d0aa5e70cb9d09dec7381e7de27a3168e77731e08f6ed56fcce2478855e837816fb69aff53412477748cd198dce783850080d37aeb929ad0f81460ebd31e61b772b6c7aa56977c787d4281fa45dbdefbb38d449eb5bccb2702964a52c78811545939712c8280dee0b23b2fa9fbbdd6a0c42476689ace655eba0745b4a21ba108bcd03ad00fdefff416dc74e08486a0538f8fd24989e1b9fc89e675141b7c"}` + + var sig Signature + err := json.Unmarshal([]byte(signatureJSON), &sig) + c.Assert(err, IsNil) + + // Check that the method string is lowercased + c.Assert(sig.Method.String(), Equals, "rsa") +} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/ed25519.go b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/ed25519.go index ddf2c622be..224ea7b860 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/ed25519.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/ed25519.go @@ -2,6 +2,7 @@ package signed import ( "crypto/rand" + "errors" "github.com/agl/ed25519" "github.com/endophage/gotuf/data" @@ -37,7 +38,7 @@ func (trust *Ed25519) Sign(keyIDs []string, toSign []byte) ([]data.Signature, er sig := ed25519.Sign(&priv, toSign) signatures = append(signatures, data.Signature{ KeyID: kID, - Method: "ED25519", + Method: data.EDDSASignature, Signature: sig[:], }) } @@ -45,13 +46,17 @@ func (trust *Ed25519) Sign(keyIDs []string, toSign []byte) ([]data.Signature, er } -func (trust *Ed25519) Create(role string) (*data.PublicKey, error) { +func (trust *Ed25519) Create(role string, algorithm data.KeyAlgorithm) (*data.PublicKey, error) { + if algorithm != data.ED25519Key { + return nil, errors.New("only ED25519 supported by this cryptoservice") + } + pub, priv, err := ed25519.GenerateKey(rand.Reader) if err != nil { return nil, err } - public := data.NewPublicKey("ED25519", pub[:]) - private := data.NewPrivateKey("ED25519", pub[:], priv[:]) + public := data.NewPublicKey(data.ED25519Key, pub[:]) + private := data.NewPrivateKey(data.ED25519Key, pub[:], priv[:]) trust.addKey(private) return public, nil } diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/interface.go b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/interface.go index c805820a4e..0b55066b31 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/interface.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/interface.go @@ -18,10 +18,9 @@ type SigningService interface { type KeyService interface { // Create issues a new key pair and is responsible for loading // the private key into the appropriate signing service. - Create(role string) (*data.PublicKey, error) - - // PublicKeys return the PublicKey instances for the given KeyIDs - // PublicKeys(keyIDs ...string) (map[string]*data.PublicKey, error) + // The role isn't currently used for anything, but it's here to support + // future features + Create(role string, algorithm data.KeyAlgorithm) (*data.PublicKey, error) } // CryptoService defines a unified Signing and Key Service as this diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/sign.go b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/sign.go index 3095e2a78f..608bab380a 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/sign.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/sign.go @@ -5,19 +5,9 @@ import ( "github.com/endophage/gotuf/data" ) -// Signer encapsulates a signing service with some convenience methods to -// interface between TUF keys and the generic service interface -type Signer struct { - service CryptoService -} - -func NewSigner(service CryptoService) *Signer { - return &Signer{service} -} - // Sign takes a data.Signed and a key, calculated and adds the signature // to the data.Signed -func (signer *Signer) Sign(s *data.Signed, keys ...*data.PublicKey) error { +func Sign(service CryptoService, s *data.Signed, keys ...*data.PublicKey) error { logrus.Debugf("sign called with %d keys", len(keys)) signatures := make([]data.Signature, 0, len(s.Signatures)+1) keyIDMemb := make(map[string]struct{}) @@ -34,7 +24,7 @@ func (signer *Signer) Sign(s *data.Signed, keys ...*data.PublicKey) error { } signatures = append(signatures, sig) } - newSigs, err := signer.service.Sign(keyIDs, s.Signed) + newSigs, err := service.Sign(keyIDs, s.Signed) if err != nil { return err } @@ -42,12 +32,3 @@ func (signer *Signer) Sign(s *data.Signed, keys ...*data.PublicKey) error { s.Signatures = append(signatures, newSigs...) return nil } - -func (signer *Signer) Create(role string) (*data.PublicKey, error) { - key, err := signer.service.Create(role) - return key, err -} - -//func (signer *Signer) PublicKeys(keyIDs ...string) (map[string]*data.PublicKey, error) { -// return signer.service.PublicKeys(keyIDs...) -//} diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/sign_test.go b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/sign_test.go index 7a565f7c3a..89ea21be4f 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/sign_test.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/sign_test.go @@ -27,7 +27,7 @@ func (mts *MockCryptoService) Sign(keyIDs []string, _ []byte) ([]data.Signature, return sigs, nil } -func (mts *MockCryptoService) Create(_ string) (*data.PublicKey, error) { +func (mts *MockCryptoService) Create(_ string, _ data.KeyAlgorithm) (*data.PublicKey, error) { return &mts.testKey, nil } @@ -42,16 +42,14 @@ var _ CryptoService = &MockCryptoService{} func TestBasicSign(t *testing.T) { testKey, _ := pem.Decode([]byte(testKeyPEM1)) k := data.NewPublicKey(data.RSAKey, testKey.Bytes) - signer := Signer{&MockCryptoService{ - testKey: *k, - }} - key, err := signer.Create("root") + mockCryptoService := &MockCryptoService{testKey: *k} + key, err := mockCryptoService.Create("root", data.ED25519Key) if err != nil { t.Fatal(err) } testData := data.Signed{} - signer.Sign(&testData, key) + Sign(mockCryptoService, &testData, key) if len(testData.Signatures) != 1 { t.Fatalf("Incorrect number of signatures: %d", len(testData.Signatures)) @@ -69,13 +67,11 @@ func TestBasicSign(t *testing.T) { func TestReSign(t *testing.T) { testKey, _ := pem.Decode([]byte(testKeyPEM1)) k := data.NewPublicKey(data.RSAKey, testKey.Bytes) - signer := Signer{&MockCryptoService{ - testKey: *k, - }} + mockCryptoService := &MockCryptoService{testKey: *k} testData := data.Signed{} - signer.Sign(&testData, k) - signer.Sign(&testData, k) + Sign(mockCryptoService, &testData, k) + Sign(mockCryptoService, &testData, k) if len(testData.Signatures) != 1 { t.Fatalf("Incorrect number of signatures: %d", len(testData.Signatures)) @@ -88,16 +84,16 @@ func TestReSign(t *testing.T) { } func TestMultiSign(t *testing.T) { - signer := Signer{&MockCryptoService{}} + mockCryptoService := &MockCryptoService{} testData := data.Signed{} testKey, _ := pem.Decode([]byte(testKeyPEM1)) key := data.NewPublicKey(data.RSAKey, testKey.Bytes) - signer.Sign(&testData, key) + Sign(mockCryptoService, &testData, key) testKey, _ = pem.Decode([]byte(testKeyPEM2)) key = data.NewPublicKey(data.RSAKey, testKey.Bytes) - signer.Sign(&testData, key) + Sign(mockCryptoService, &testData, key) if len(testData.Signatures) != 2 { t.Fatalf("Incorrect number of signatures: %d", len(testData.Signatures)) @@ -115,11 +111,9 @@ func TestMultiSign(t *testing.T) { func TestCreate(t *testing.T) { testKey, _ := pem.Decode([]byte(testKeyPEM1)) k := data.NewPublicKey(data.RSAKey, testKey.Bytes) - signer := Signer{&MockCryptoService{ - testKey: *k, - }} + mockCryptoService := &MockCryptoService{testKey: *k} - key, err := signer.Create("root") + key, err := mockCryptoService.Create("root", data.ED25519Key) if err != nil { t.Fatal(err) diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verifiers.go b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verifiers.go index 2a3c0fb3ac..aaa12c9bd9 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verifiers.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verifiers.go @@ -18,7 +18,7 @@ import ( // Verifiers serves as a map of all verifiers available on the system and // can be injected into a verificationService. For testing and configuration // purposes, it will not be used by default. -var Verifiers = map[string]Verifier{ +var Verifiers = map[data.SigAlgorithm]Verifier{ data.RSAPSSSignature: RSAPSSVerifier{}, data.PyCryptoSignature: RSAPyCryptoVerifier{}, data.ECDSASignature: ECDSAVerifier{}, @@ -27,8 +27,8 @@ var Verifiers = map[string]Verifier{ // RegisterVerifier provides a convenience function for init() functions // to register additional verifiers or replace existing ones. -func RegisterVerifier(name string, v Verifier) { - curr, ok := Verifiers[name] +func RegisterVerifier(algorithm data.SigAlgorithm, v Verifier) { + curr, ok := Verifiers[algorithm] if ok { typOld := reflect.TypeOf(curr) typNew := reflect.TypeOf(v) @@ -38,9 +38,9 @@ func RegisterVerifier(name string, v Verifier) { typNew.PkgPath(), typNew.Name(), ) } else { - logrus.Debug("adding verifier for: ", name) + logrus.Debug("adding verifier for: ", algorithm) } - Verifiers[name] = v + Verifiers[algorithm] = v } type Ed25519Verifier struct{} @@ -83,10 +83,10 @@ type RSAPSSVerifier struct{} // Verify does the actual check. func (v RSAPSSVerifier) Verify(key data.Key, sig []byte, msg []byte) error { - cipher := key.Cipher() + algorithm := key.Algorithm() var pubKey crypto.PublicKey - switch cipher { + switch algorithm { case data.RSAx509Key: pemCert, _ := pem.Decode([]byte(key.Public())) if pemCert == nil { @@ -107,7 +107,7 @@ func (v RSAPSSVerifier) Verify(key data.Key, sig []byte, msg []byte) error { return ErrInvalid } default: - logrus.Infof("invalid key type for RSAPSS verifier: %s", cipher) + logrus.Infof("invalid key type for RSAPSS verifier: %s", algorithm) return ErrInvalid } @@ -145,10 +145,10 @@ type ECDSAVerifier struct{} // Verify does the actual check. func (v ECDSAVerifier) Verify(key data.Key, sig []byte, msg []byte) error { - cipher := key.Cipher() + algorithm := key.Algorithm() var pubKey crypto.PublicKey - switch cipher { + switch algorithm { case data.ECDSAx509Key: pemCert, _ := pem.Decode([]byte(key.Public())) if pemCert == nil { @@ -170,7 +170,7 @@ func (v ECDSAVerifier) Verify(key data.Key, sig []byte, msg []byte) error { return ErrInvalid } default: - logrus.Infof("invalid key type for ECDSA verifier: %s", cipher) + logrus.Infof("invalid key type for ECDSA verifier: %s", algorithm) return ErrInvalid } diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verifiers_test.go b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verifiers_test.go index 279442511e..ae87f03c26 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verifiers_test.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verifiers_test.go @@ -19,7 +19,7 @@ import ( ) type KeyTemplate struct { - KeyType string + KeyType data.KeyAlgorithm } const baseRSAKey = `{"keytype":"{{.KeyType}}","keyval":{"public":"MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAyyvBtTg2xzYS+MTTIBqSpI4V78tt8Yzqi7Jki/Z6NqjiDvcnbgcTqNR2t6B2W5NjGdp/hSaT2jyHM+kdmEGaPxg/zIuHbL3NIp4e0qwovWiEgACPIaELdn8O/kt5swsSKl1KMvLCH1sM86qMibNMAZ/hXOwd90TcHXCgZ91wHEAmsdjDC3dB0TT+FBgOac8RM01Y196QrZoOaDMTWh0EQfw7YbXAElhFVDFxBzDdYWbcIHSIogXQmq0CP+zaL/1WgcZZIClt2M6WCaxxF1S34wNn45gCvVZiZQ/iKWHerSr/2dGQeGo+7ezMSutRzvJ+01fInD86RS/CEtBCFZ1VyQIDAQAB","private":"MIIEpAIBAAKCAQEAyyvBtTg2xzYS+MTTIBqSpI4V78tt8Yzqi7Jki/Z6NqjiDvcnbgcTqNR2t6B2W5NjGdp/hSaT2jyHM+kdmEGaPxg/zIuHbL3NIp4e0qwovWiEgACPIaELdn8O/kt5swsSKl1KMvLCH1sM86qMibNMAZ/hXOwd90TcHXCgZ91wHEAmsdjDC3dB0TT+FBgOac8RM01Y196QrZoOaDMTWh0EQfw7YbXAElhFVDFxBzDdYWbcIHSIogXQmq0CP+zaL/1WgcZZIClt2M6WCaxxF1S34wNn45gCvVZiZQ/iKWHerSr/2dGQeGo+7ezMSutRzvJ+01fInD86RS/CEtBCFZ1VyQIDAQABAoIBAHar8FFxrE1gAGTeUpOF8fG8LIQMRwO4U6eVY7V9GpWiv6gOJTHXYFxU/aL0Ty3eQRxwy9tyVRo8EJz5pRex+e6ws1M+jLOviYqW4VocxQ8dZYd+zBvQfWmRfah7XXJ/HPUx2I05zrmR7VbGX6Bu4g5w3KnyIO61gfyQNKF2bm2Q3yblfupx3URvX0bl180R/+QN2Aslr4zxULFE6b+qJqBydrztq+AAP3WmskRxGa6irFnKxkspJqUpQN1mFselj6iQrzAcwkRPoCw0RwCCMq1/OOYvQtgxTJcO4zDVlbw54PvnxPZtcCWw7fO8oZ2Fvo2SDo75CDOATOGaT4Y9iqECgYEAzWZSpFbN9ZHmvq1lJQg//jFAyjsXRNn/nSvyLQILXltz6EHatImnXo3v+SivG91tfzBI1GfDvGUGaJpvKHoomB+qmhd8KIQhO5MBdAKZMf9fZqZofOPTD9xRXECCwdi+XqHBmL+l1OWz+O9Bh+Qobs2as/hQVgHaoXhQpE0NkTcCgYEA/Tjf6JBGl1+WxQDoGZDJrXoejzG9OFW19RjMdmPrg3t4fnbDtqTpZtCzXxPTCSeMrvplKbqAqZglWyq227ksKw4p7O6YfyhdtvC58oJmivlLr6sFaTsER7mDcYce8sQpqm+XQ8IPbnOk0Z1l6g56euTwTnew49uy25M6U1xL0P8CgYEAxEXv2Kw+OVhHV5PX4BBHHj6we88FiDyMfwM8cvfOJ0datekf9X7ImZkmZEAVPJpWBMD+B0J0jzU2b4SLjfFVkzBHVOH2Ob0xCH2MWPAWtekin7OKizUlPbW5ZV8b0+Kq30DQ/4a7D3rEhK8UPqeuX1tHZox1MAqrgbq3zJj4yvcCgYEAktYPKPm4pYCdmgFrlZ+bA0iEPf7Wvbsd91F5BtHsOOM5PQQ7e0bnvWIaEXEad/2CG9lBHlBy2WVLjDEZthILpa/h6e11ao8KwNGY0iKBuebT17rxOVMqqTjPGt8CuD2994IcEgOPFTpkAdUmyvG4XlkxbB8F6St17NPUB5DGuhsCgYA//Lfytk0FflXEeRQ16LT1YXgV7pcR2jsha4+4O5pxSFw/kTsOfJaYHg8StmROoyFnyE3sg76dCgLn0LENRCe5BvDhJnp5bMpQldG3XwcAxH8FGFNY4LtV/2ZKnJhxcONkfmzQPOmTyedOzrKQ+bNURsqLukCypP7/by6afBY4dA=="}}` @@ -248,8 +248,8 @@ func TestECDSAVerifierWithInvalidSignature(t *testing.T) { } func rsaSign(privKey *data.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) { - if privKey.Cipher() != data.RSAKey { - return nil, fmt.Errorf("private key type not supported: %s", privKey.Cipher()) + if privKey.Algorithm() != data.RSAKey { + return nil, fmt.Errorf("private key type not supported: %s", privKey.Algorithm()) } // Create an rsa.PrivateKey out of the private key bytes @@ -268,8 +268,8 @@ func rsaSign(privKey *data.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, } func ecdsaSign(privKey *data.PrivateKey, hashed []byte) ([]byte, error) { - if privKey.Cipher() != data.ECDSAKey { - return nil, fmt.Errorf("private key type not supported: %s", privKey.Cipher()) + if privKey.Algorithm() != data.ECDSAKey { + return nil, fmt.Errorf("private key type not supported: %s", privKey.Algorithm()) } // Create an ecdsa.PrivateKey out of the private key bytes diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verify.go b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verify.go index 1767e3e62f..7dcefde02e 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verify.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verify.go @@ -3,7 +3,6 @@ package signed import ( "encoding/json" "errors" - "strings" "time" "github.com/Sirupsen/logrus" @@ -45,8 +44,8 @@ func VerifyRoot(s *data.Signed, minVersion int, keys map[string]*data.PublicKey, valid := make(map[string]struct{}) for _, sig := range s.Signatures { - // make method lookup consistent with case uniformity. - method := strings.ToLower(sig.Method) + // method lookup is consistent due to Unmarshal JSON doing lower case for us. + method := sig.Method verifier, ok := Verifiers[method] if !ok { logrus.Debugf("continuing b/c signing method is not supported for verify root: %s\n", sig.Method) @@ -133,8 +132,8 @@ func VerifySignatures(s *data.Signed, role string, db *keys.KeyDB) error { logrus.Debugf("continuing b/c keyid lookup was nil: %s\n", sig.KeyID) continue } - // make method lookup consistent with case uniformity. - method := strings.ToLower(sig.Method) + // method lookup is consistent due to Unmarshal JSON doing lower case for us. + method := sig.Method verifier, ok := Verifiers[method] if !ok { logrus.Debugf("continuing b/c signing method is not supported: %s\n", sig.Method) diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verify_test.go b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verify_test.go index f9f5748d3f..9b38d1b771 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verify_test.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/signed/verify_test.go @@ -20,7 +20,6 @@ var _ = Suite(&VerifySuite{}) func (VerifySuite) Test(c *C) { trust := NewEd25519() - signer := NewSigner(trust) type test struct { name string keys []*data.PublicKey @@ -78,8 +77,8 @@ func (VerifySuite) Test(c *C) { { name: "more than enough signatures", mut: func(t *test) { - k, _ := signer.Create("root") - signer.Sign(t.s, k) + 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()) }, @@ -95,15 +94,15 @@ func (VerifySuite) Test(c *C) { { name: "unknown key", mut: func(t *test) { - k, _ := signer.Create("root") - signer.Sign(t.s, k) + k, _ := trust.Create("root", data.ED25519Key) + Sign(trust, t.s, k) }, }, { name: "unknown key below threshold", mut: func(t *test) { - k, _ := signer.Create("root") - signer.Sign(t.s, k) + k, _ := trust.Create("root", data.ED25519Key) + Sign(trust, t.s, k) t.roles["root"].Threshold = 2 }, err: ErrRoleThreshold, @@ -111,16 +110,16 @@ func (VerifySuite) Test(c *C) { { name: "unknown keys in db", mut: func(t *test) { - k, _ := signer.Create("root") - signer.Sign(t.s, k) + 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, _ := signer.Create("root") - signer.Sign(t.s, k) + k, _ := trust.Create("root", data.ED25519Key) + Sign(trust, t.s, k) t.keys = append(t.keys, k) t.roles["root"].Threshold = 2 }, @@ -157,13 +156,13 @@ func (VerifySuite) Test(c *C) { t.typ = data.TUFTypes[t.role] } if t.keys == nil && t.s == nil { - k, _ := signer.Create("root") + 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} - signer.Sign(s, k) + Sign(trust, s, k) t.s = s t.keys = []*data.PublicKey{k} } diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/store/httpstore_test.go b/Godeps/_workspace/src/github.com/endophage/gotuf/store/httpstore_test.go index bac7e4f2ce..40c8f2ab1b 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/store/httpstore_test.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/store/httpstore_test.go @@ -4,7 +4,6 @@ import ( "encoding/hex" "encoding/json" "net/http" - "strings" "testing" "github.com/tent/canonical-json-go" @@ -55,7 +54,7 @@ func TestGetMeta(t *testing.T) { if err != nil { t.Fatal(err) } - method := strings.ToLower(p.Signatures[0].Method) + method := p.Signatures[0].Method err = signed.Verifiers[method].Verify(k, sigBytes, msg) if err != nil { t.Fatal(err) @@ -68,13 +67,13 @@ func TestPyCryptoRSAPSSCompat(t *testing.T) { //privPem := "-----BEGIN RSA PRIVATE KEY-----\nMIIG4wIBAAKCAYEAnKuXZeefa2LmgxaL5NsMzKOHNe+x/nL6ik+lDBCTV6OdcwAh\nHQS+PONGhrChIUVR6Vth3hUCrreLzPO73Oo5VSCuRJ53UronENl6lsa5mFKP8StY\nLvIDITNvkoT3j52BJIjyNUK9UKY9As2TNqDfBEPIRp28ev/NViwGOEkBu2UAbwCI\ndnDXm8JQErCZA0Ydm7PKGgjLbFsFGrVzqXHK6pdzJXlhr9yap3UpgQ/iO9JtoEYB\n2EXsnSrPc9JRjR30bNHHtnVql3fvinXrAEwq3xmN4p+R4VGzfdQN+8Kl/IPjqWB5\n35twhFYEG/B7Ze8IwbygBjK3co/KnOPqMUrMBI8ztvPiogz+MvXb8WvarZ6TMTh8\nifZI96r7zzqyzjR1hJulEy3IsMGvz8XS2J0X7sXoaqszEtXdq5ef5zKVxkiyIQZc\nbPgmpHLq4MgfdryuVVc/RPASoRIXG4lKaTJj1ANMFPxDQpHudCLxwCzjCb+sVa20\nHBRPTnzo8LSZkI6jAgMBAAECggGAdzyI7z/HLt2IfoAsXDLynNRgVYZluzgawiU3\ngeUjnnGhpSKWERXJC2IWDPBk0YOGgcnQxErNTdfXiFZ/xfRlSgqjVwob2lRe4w4B\npLr+CZXcgznv1VrPUvdolOSp3R2Mahfn7u0qVDUQ/g8jWVI6KW7FACmQhzQkPM8o\ntLGrpcmK+PA465uaHKtYccEB02ILqrK8v++tknv7eIZczrsSKlS1h/HHjSaidYxP\n2DAUiF7wnChrwwQEvuEUHhwVgQcoDMBoow0zwHdbFiFO2ZT54H2oiJWLhpR/x6RK\ngM1seqoPH2sYErPJACMcYsMtF4Tx7b5c4WSj3vDCGb+jeqnNS6nFC3aMnv75mUS2\nYDPU1heJFd8pNHVf0RDejLZZUiJSnXf3vpOxt9Xv2+4He0jeMfLV7zX0mO2Ni3MJ\nx6PiVy4xerHImOuuHzSla5crOq2ECiAxd1wEOFDRD2LRHzfhpk1ghiA5xA1qwc7Z\neRnkVfoy6PPZ4lZakZTm0p8YCQURAoHBAMUIC/7vnayLae7POmgy+np/ty7iMfyd\nV1eO6LTO21KAaGGlhaY26WD/5LcG2FUgc5jKKahprGrmiNLzLUeQPckJmuijSEVM\nl/4DlRvCo867l7fLaVqYzsQBBdeGIFNiT+FBOd8atff87ZBEfH/rXbDi7METD/VR\n4TdblnCsKYAXEJUdkw3IK7SUGERiQZIwKXrH/Map4ibDrljJ71iCgEureU0DBwcg\nwLftmjGMISoLscdRxeubX5uf/yxtHBJeRwKBwQDLjzHhb4gNGdBHUl4hZPAGCq1V\nLX/GpfoOVObW64Lud+tI6N9GNua5/vWduL7MWWOzDTMZysganhKwsJCY5SqAA9p0\nb6ohusf9i1nUnOa2F2j+weuYPXrTYm+ZrESBBdaEJPuj3R5YHVujrBA9Xe0kVOe3\nne151A+0xJOI3tX9CttIaQAsXR7cMDinkDITw6i7X4olRMPCSixHLW97cDsVDRGt\necO1d4dP3OGscN+vKCoL6tDKDotzWHYPwjH47sUCgcEAoVI8WCiipbKkMnaTsNsE\ngKXvO0DSgq3k5HjLCbdQldUzIbgfnH7bSKNcBYtiNxjR7OihgRW8qO5GWsnmafCs\n1dy6a/2835id3cnbHRaZflvUFhVDFn2E1bCsstFLyFn3Y0w/cO9yzC/X5sZcVXRF\nit3R0Selakv3JZckru4XMJwx5JWJYMBjIIAc+miknWg3niL+UT6pPun65xG3mXWI\nS+yC7c4rw+dKQ44UMLs2MDHRBoxqi8T0W/x9NkfDszpjAoHAclH7S4ZdvC3RIR0L\nLGoJuvroGbwx1JiGdOINuooNwGuswge2zTIsJi0gN/H3hcB2E6rIFiYid4BrMrwW\nmSeq1LZVS6siu0qw4p4OVy+/CmjfWKQD8j4k6u6PipiK6IMk1JYIlSCr2AS04JjT\njgNgGVVtxVt2cUM9huIXkXjEaRZdzK7boA60NCkIyGJdHWh3LLQdW4zg/A64C0lj\nIMoJBGuQkAKgfRuh7KI6Q6Qom7BM3OCFXdUJUEBQHc2MTyeZAoHAJdBQGBn1RFZ+\nn75AnbTMZJ6Twp2fVjzWUz/+rnXFlo87ynA18MR2BzaDST4Bvda29UBFGb32Mux9\nOHukqLgIE5jDuqWjy4B5eCoxZf/OvwlgXkX9+gprGR3axn/PZBFPbFB4ZmjbWLzn\nbocn7FJCXf+Cm0cMmv1jIIxej19MUU/duq9iq4RkHY2LG+KrSEQIUVmImCftXdN3\n/qNP5JetY0eH6C+KRc8JqDB0nvbqZNOgYXOfYXo/5Gk8XIHTFihm\n-----END RSA PRIVATE KEY-----" testStr := "The quick brown fox jumps over the lazy dog." sigHex := "4e05ee9e435653549ac4eddbc43e1a6868636e8ea6dbec2564435afcb0de47e0824cddbd88776ddb20728c53ecc90b5d543d5c37575fda8bd0317025fc07de62ee8084b1a75203b1a23d1ef4ac285da3d1fc63317d5b2cf1aafa3e522acedd366ccd5fe4a7f02a42922237426ca3dc154c57408638b9bfaf0d0213855d4e9ee621db204151bcb13d4dbb18f930ec601469c992c84b14e9e0b6f91ac9517bb3b749dd117e1cbac2e4acb0e549f44558a2005898a226d5b6c8b9291d7abae0d9e0a16858b89662a085f74a202deb867acab792bdbd2c36731217caea8b17bd210c29b890472f11e5afdd1dd7b69004db070e04201778f2c49f5758643881403d45a58d08f51b5c63910c6185892f0b590f191d760b669eff2464456f130239bba94acf54a0cb98f6939ff84ae26a37f9b890be259d9b5d636f6eb367b53e895227d7d79a3a88afd6d28c198ee80f6527437c5fbf63accb81709925c4e03d1c9eaee86f58e4bd1c669d6af042dbd412de0d13b98b1111e2fadbe34b45de52125e9a" - k := data.NewPublicKey("RSA", []byte(pubPem)) + k := data.NewPublicKey(data.RSAKey, []byte(pubPem)) sigBytes, err := hex.DecodeString(sigHex) if err != nil { t.Fatal(err) } - v := signed.RSAPSSVerifier{} + v := signed.RSAPyCryptoVerifier{} err = v.Verify(k, sigBytes, []byte(testStr)) if err != nil { t.Fatal(err) @@ -88,11 +87,11 @@ func TestPyNaCled25519Compat(t *testing.T) { sigHex := "166e7013e48f26dccb4e68fe4cf558d1cd3af902f8395534336a7f8b4c56588694aa3ac671767246298a59d5ef4224f02c854f41bfcfe70241db4be1546d6a00" pub, _ := hex.DecodeString(pubHex) - k := data.NewPublicKey("ED25519", pub) + k := data.NewPublicKey(data.ED25519Key, pub) sigBytes, _ := hex.DecodeString(sigHex) - err := signed.Verifiers["ED25519"].Verify(k, sigBytes, []byte(testStr)) + err := signed.Verifiers[data.EDDSASignature].Verify(k, sigBytes, []byte(testStr)) if err != nil { t.Fatal(err) } diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/tuf.go b/Godeps/_workspace/src/github.com/endophage/gotuf/tuf.go index eb9410e830..301200d286 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/tuf.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/tuf.go @@ -50,21 +50,21 @@ func (err *ErrNotLoaded) Error() string { // fetching raw JSON and using the Set* functions to populate // the TufRepo instance. type TufRepo struct { - Root *data.SignedRoot - Targets map[string]*data.SignedTargets - Snapshot *data.SignedSnapshot - Timestamp *data.SignedTimestamp - keysDB *keys.KeyDB - signer *signed.Signer + Root *data.SignedRoot + Targets map[string]*data.SignedTargets + Snapshot *data.SignedSnapshot + Timestamp *data.SignedTimestamp + keysDB *keys.KeyDB + cryptoService signed.CryptoService } // NewTufRepo initializes a TufRepo instance with a keysDB and a signer. // If the TufRepo will only be used for reading, the signer should be nil. -func NewTufRepo(keysDB *keys.KeyDB, signer *signed.Signer) *TufRepo { +func NewTufRepo(keysDB *keys.KeyDB, cryptoService signed.CryptoService) *TufRepo { repo := &TufRepo{ - Targets: make(map[string]*data.SignedTargets), - keysDB: keysDB, - signer: signer, + Targets: make(map[string]*data.SignedTargets), + keysDB: keysDB, + cryptoService: cryptoService, } return repo } @@ -75,7 +75,7 @@ func (tr *TufRepo) AddBaseKeys(role string, keys ...data.Key) error { return &ErrNotLoaded{role: "root"} } for _, k := range keys { - key := data.NewPublicKey(k.Cipher(), k.Public()) + key := data.NewPublicKey(k.Algorithm(), k.Public()) tr.Root.Signed.Keys[key.ID()] = key tr.keysDB.AddKey(key) tr.Root.Signed.Roles[role].KeyIDs = append(tr.Root.Signed.Roles[role].KeyIDs, key.ID()) @@ -142,7 +142,7 @@ func (tr *TufRepo) UpdateDelegations(role *data.Role, keys []data.Key, before st return errors.ErrInvalidRole{} } for _, k := range keys { - key := data.NewPublicKey(k.Cipher(), k.Public()) + key := data.NewPublicKey(k.Algorithm(), k.Public()) if !utils.StrSliceContains(role.KeyIDs, key.ID()) { role.KeyIDs = append(role.KeyIDs, key.ID()) } @@ -203,7 +203,7 @@ func (tr *TufRepo) InitRoot(consistent bool) error { // checked by KeyDB when role was added. key := tr.keysDB.GetKey(kid) // Create new key object to doubly ensure private key is excluded - k := data.NewPublicKey(key.Cipher(), key.Public()) + k := data.NewPublicKey(key.Algorithm(), key.Public()) rootKeys[kid] = k } } @@ -449,7 +449,7 @@ func (tr *TufRepo) UpdateTimestamp(s *data.Signed) error { return nil } -func (tr *TufRepo) SignRoot(expires time.Time, signer *signed.Signer) (*data.Signed, error) { +func (tr *TufRepo) SignRoot(expires time.Time, cryptoService signed.CryptoService) (*data.Signed, error) { logrus.Debug("signing root...") if tr.Root.Dirty { tr.Root.Signed.Version++ @@ -459,7 +459,7 @@ func (tr *TufRepo) SignRoot(expires time.Time, signer *signed.Signer) (*data.Sig if err != nil { return nil, err } - signed, err = tr.sign(signed, *root, signer) + signed, err = tr.sign(signed, *root, cryptoService) if err != nil { return nil, err } @@ -467,7 +467,7 @@ func (tr *TufRepo) SignRoot(expires time.Time, signer *signed.Signer) (*data.Sig return signed, nil } -func (tr *TufRepo) SignTargets(role string, expires time.Time, signer *signed.Signer) (*data.Signed, error) { +func (tr *TufRepo) SignTargets(role string, expires time.Time, cryptoService signed.CryptoService) (*data.Signed, error) { logrus.Debugf("sign targets called for role %s", role) if tr.Targets[role].Dirty { tr.Targets[role].Signed.Version++ @@ -477,7 +477,7 @@ func (tr *TufRepo) SignTargets(role string, expires time.Time, signer *signed.Si return nil, err } targets := tr.keysDB.GetRole(role) - signed, err = tr.sign(signed, *targets, signer) + signed, err = tr.sign(signed, *targets, cryptoService) if err != nil { logrus.Debug("errored signing ", role) return nil, err @@ -494,10 +494,10 @@ func (tr *TufRepo) SignTargets(role string, expires time.Time, signer *signed.Si } } -func (tr *TufRepo) SignSnapshot(expires time.Time, signer *signed.Signer) (*data.Signed, error) { +func (tr *TufRepo) SignSnapshot(expires time.Time, cryptoService signed.CryptoService) (*data.Signed, error) { logrus.Debug("signing snapshot...") if tr.Root.Dirty { - signedRoot, err := tr.SignRoot(data.DefaultExpires("root"), signer) + signedRoot, err := tr.SignRoot(data.DefaultExpires("root"), cryptoService) if err != nil { return nil, err } @@ -511,7 +511,7 @@ func (tr *TufRepo) SignSnapshot(expires time.Time, signer *signed.Signer) (*data if !targets.Dirty { continue } - signedTargets, err := tr.SignTargets(role, data.DefaultExpires("targets"), signer) + signedTargets, err := tr.SignTargets(role, data.DefaultExpires("targets"), cryptoService) if err != nil { return nil, err } @@ -528,7 +528,7 @@ func (tr *TufRepo) SignSnapshot(expires time.Time, signer *signed.Signer) (*data return nil, err } snapshot := tr.keysDB.GetRole(data.ValidRoles["snapshot"]) - signed, err = tr.sign(signed, *snapshot, signer) + signed, err = tr.sign(signed, *snapshot, cryptoService) if err != nil { return nil, err } @@ -543,10 +543,10 @@ func (tr *TufRepo) SignSnapshot(expires time.Time, signer *signed.Signer) (*data } } -func (tr *TufRepo) SignTimestamp(expires time.Time, signer *signed.Signer) (*data.Signed, error) { +func (tr *TufRepo) SignTimestamp(expires time.Time, cryptoService signed.CryptoService) (*data.Signed, error) { logrus.Debug("SignTimestamp") if tr.Snapshot.Dirty { - signedSnapshot, err := tr.SignSnapshot(data.DefaultExpires("snapshot"), signer) + signedSnapshot, err := tr.SignSnapshot(data.DefaultExpires("snapshot"), cryptoService) if err != nil { return nil, err } @@ -562,7 +562,7 @@ func (tr *TufRepo) SignTimestamp(expires time.Time, signer *signed.Signer) (*dat return nil, err } timestamp := tr.keysDB.GetRole(data.ValidRoles["timestamp"]) - signed, err = tr.sign(signed, *timestamp, signer) + signed, err = tr.sign(signed, *timestamp, cryptoService) if err != nil { return nil, err } @@ -578,7 +578,7 @@ func (tr *TufRepo) SignTimestamp(expires time.Time, signer *signed.Signer) (*dat } } -func (tr TufRepo) sign(signed *data.Signed, role data.Role, signer *signed.Signer) (*data.Signed, error) { +func (tr TufRepo) sign(signedData *data.Signed, role data.Role, cryptoService signed.CryptoService) (*data.Signed, error) { ks := make([]*data.PublicKey, 0, len(role.KeyIDs)) for _, kid := range role.KeyIDs { k := tr.keysDB.GetKey(kid) @@ -590,16 +590,12 @@ func (tr TufRepo) sign(signed *data.Signed, role data.Role, signer *signed.Signe if len(ks) < 1 { return nil, keys.ErrInvalidKey } - if signer != nil { - err := signer.Sign(signed, ks...) - if err != nil { - return nil, err - } - } else { - err := tr.signer.Sign(signed, ks...) - if err != nil { - return nil, err - } + if cryptoService == nil { + cryptoService = tr.cryptoService } - return signed, nil + err := signed.Sign(cryptoService, signedData, ks...) + if err != nil { + return nil, err + } + return signedData, nil } diff --git a/Godeps/_workspace/src/github.com/endophage/gotuf/tuf_test.go b/Godeps/_workspace/src/github.com/endophage/gotuf/tuf_test.go index 21a895165a..479df718a6 100644 --- a/Godeps/_workspace/src/github.com/endophage/gotuf/tuf_test.go +++ b/Godeps/_workspace/src/github.com/endophage/gotuf/tuf_test.go @@ -13,21 +13,20 @@ import ( "github.com/endophage/gotuf/signed" ) -func initRepo(t *testing.T, signer *signed.Signer, keyDB *keys.KeyDB) *TufRepo { - - rootKey, err := signer.Create("root") +func initRepo(t *testing.T, cryptoService signed.CryptoService, keyDB *keys.KeyDB) *TufRepo { + rootKey, err := cryptoService.Create("root", data.ED25519Key) if err != nil { t.Fatal(err) } - targetsKey, err := signer.Create("targets") + targetsKey, err := cryptoService.Create("targets", data.ED25519Key) if err != nil { t.Fatal(err) } - snapshotKey, err := signer.Create("snapshot") + snapshotKey, err := cryptoService.Create("snapshot", data.ED25519Key) if err != nil { t.Fatal(err) } - timestampKey, err := signer.Create("timestamp") + timestampKey, err := cryptoService.Create("timestamp", data.ED25519Key) if err != nil { t.Fatal(err) } @@ -71,7 +70,7 @@ func initRepo(t *testing.T, signer *signed.Signer, keyDB *keys.KeyDB) *TufRepo { keyDB.AddRole(snapshotRole) keyDB.AddRole(timestampRole) - repo := NewTufRepo(keyDB, signer) + repo := NewTufRepo(keyDB, cryptoService) err = repo.InitRepo(false) if err != nil { t.Fatal(err) @@ -124,19 +123,17 @@ func writeRepo(t *testing.T, dir string, repo *TufRepo) { func TestInitRepo(t *testing.T) { ed25519 := signed.NewEd25519() - signer := signed.NewSigner(ed25519) keyDB := keys.NewDB() - repo := initRepo(t, signer, keyDB) + repo := initRepo(t, ed25519, keyDB) writeRepo(t, "/tmp/tufrepo", repo) } func TestUpdateDelegations(t *testing.T) { ed25519 := signed.NewEd25519() - signer := signed.NewSigner(ed25519) keyDB := keys.NewDB() - repo := initRepo(t, signer, keyDB) + repo := initRepo(t, ed25519, keyDB) - testKey, err := signer.Create("targets/test") + testKey, err := ed25519.Create("targets/test", data.ED25519Key) if err != nil { t.Fatal(err) } @@ -150,7 +147,7 @@ func TestUpdateDelegations(t *testing.T) { t.Fatal(err) } - testDeepKey, err := signer.Create("targets/test/deep") + testDeepKey, err := ed25519.Create("targets/test/deep", data.ED25519Key) if err != nil { t.Fatal(err) } diff --git a/client/cli_crypto_service.go b/client/cli_crypto_service.go index 3b9aa8a3f5..72ba2ef7a4 100644 --- a/client/cli_crypto_service.go +++ b/client/cli_crypto_service.go @@ -15,51 +15,52 @@ import ( "github.com/endophage/gotuf/data" ) -type genericCryptoService struct { +// CryptoService implements Sign and Create, holding a specific GUN and keystore to +// operate on +type CryptoService struct { gun string passphrase string keyStore *trustmanager.KeyFileStore } -// RSACryptoService implements Sign and Create, holding a specific GUN and keystore to -// operate on -type RSACryptoService struct { - genericCryptoService -} - -// ECDSACryptoService implements Sign and Create, holding a specific GUN and keystore to -// operate on -type ECDSACryptoService struct { - genericCryptoService -} - -// NewRSACryptoService returns an instance of CryptoService -func NewRSACryptoService(gun string, keyStore *trustmanager.KeyFileStore, passphrase string) *RSACryptoService { - return &RSACryptoService{genericCryptoService{gun: gun, keyStore: keyStore, passphrase: passphrase}} +// NewCryptoService returns an instance of CryptoService +func NewCryptoService(gun string, keyStore *trustmanager.KeyFileStore, passphrase string) *CryptoService { + return &CryptoService{gun: gun, keyStore: keyStore, passphrase: passphrase} } // Create is used to generate keys for targets, snapshots and timestamps -func (ccs *RSACryptoService) Create(role string) (*data.PublicKey, error) { - privKey, err := trustmanager.GenerateRSAKey(rand.Reader, rsaKeySize) - if err != nil { - return nil, fmt.Errorf("failed to generate RSA key: %v", err) +func (ccs *CryptoService) Create(role string, algorithm data.KeyAlgorithm) (*data.PublicKey, error) { + var privKey *data.PrivateKey + var err error + + switch algorithm { + case data.RSAKey: + privKey, err = trustmanager.GenerateRSAKey(rand.Reader, rsaKeySize) + if err != nil { + return nil, fmt.Errorf("failed to generate RSA key: %v", err) + } + case data.ECDSAKey: + privKey, err = trustmanager.GenerateECDSAKey(rand.Reader) + if err != nil { + return nil, fmt.Errorf("failed to generate EC key: %v", err) + } + default: + return nil, fmt.Errorf("private key type not supported for key generation: %s", algorithm) } + logrus.Debugf("generated new %s key for role: %s and keyID: %s", algorithm, role, privKey.ID()) // Store the private key into our keystore with the name being: /GUN/ID.key err = ccs.keyStore.AddKey(filepath.Join(ccs.gun, privKey.ID()), privKey) if err != nil { return nil, fmt.Errorf("failed to add key to filestore: %v", err) } - - logrus.Debugf("generated new RSA key for role: %s and keyID: %s", role, privKey.ID()) - return data.PublicKeyFromPrivate(*privKey), nil } // Sign returns the signatures for the payload with a set of keyIDs. It ignores // errors to sign and expects the called to validate if the number of returned // signatures is adequate. -func (ccs *RSACryptoService) Sign(keyIDs []string, payload []byte) ([]data.Signature, error) { +func (ccs *CryptoService) Sign(keyIDs []string, payload []byte) ([]data.Signature, error) { // Create hasher and hash data hash := crypto.SHA256 hashed := sha256.Sum256(payload) @@ -72,11 +73,8 @@ func (ccs *RSACryptoService) Sign(keyIDs []string, payload []byte) ([]data.Signa var privKey *data.PrivateKey var err error - // Read PrivateKey from file. - // TODO(diogo): This assumes both that only root keys are encrypted and - // that encrypted keys are always X509 encoded + // Read PrivateKey from file and decrypt it if there is a passphrase. if ccs.passphrase != "" { - // This is a root key privKey, err = ccs.keyStore.GetDecryptedKey(keyName, ccs.passphrase) } else { privKey, err = ccs.keyStore.GetKey(keyName) @@ -86,27 +84,33 @@ func (ccs *RSACryptoService) Sign(keyIDs []string, payload []byte) ([]data.Signa // InitRepo gets a signer that doesn't have access to // the root keys. Continuing here is safe because we // end up not returning any signatures. - logrus.Debugf("ignoring error attempting to retrieve RSA key ID: %s, %v", keyid, err) + logrus.Debugf("ignoring error attempting to retrieve key ID: %s, %v", keyid, err) continue } - sig, err := rsaSign(privKey, hash, hashed[:]) + algorithm := privKey.Algorithm() + var sigAlgorithm data.SigAlgorithm + var sig []byte + + switch algorithm { + case data.RSAKey: + sig, err = rsaSign(privKey, hash, hashed[:]) + sigAlgorithm = data.RSAPSSSignature + case data.ECDSAKey: + sig, err = ecdsaSign(privKey, hashed[:]) + sigAlgorithm = data.ECDSASignature + } if err != nil { - // If the rsaSign method got called with a non RSA private key, - // we ignore this call. - // This might happen when root is ECDSA, targets and snapshots RSA, and - // gotuf still attempts to sign root with this cryptoserver - // return nil, err - logrus.Debugf("ignoring error attempting to RSA sign with keyID: %s, %v", keyid, err) + logrus.Debugf("ignoring error attempting to %s sign with keyID: %s, %v", algorithm, keyid, err) continue } - logrus.Debugf("appending RSA signature with Key ID: %s", privKey.ID()) + logrus.Debugf("appending %s signature with Key ID: %s", algorithm, keyid) // Append signatures to result array signatures = append(signatures, data.Signature{ KeyID: keyid, - Method: data.RSAPSSSignature, + Method: sigAlgorithm, Signature: sig[:], }) } @@ -115,8 +119,8 @@ func (ccs *RSACryptoService) Sign(keyIDs []string, payload []byte) ([]data.Signa } func rsaSign(privKey *data.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) { - if privKey.Cipher() != data.RSAKey { - return nil, fmt.Errorf("private key type not supported: %s", privKey.Cipher()) + if privKey.Algorithm() != data.RSAKey { + return nil, fmt.Errorf("private key type not supported: %s", privKey.Algorithm()) } // Create an rsa.PrivateKey out of the private key bytes @@ -134,94 +138,9 @@ func rsaSign(privKey *data.PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, return sig, nil } -// NewECDSACryptoService returns an instance of CryptoService -func NewECDSACryptoService(gun string, keyStore *trustmanager.KeyFileStore, passphrase string) *ECDSACryptoService { - return &ECDSACryptoService{genericCryptoService{gun: gun, keyStore: keyStore, passphrase: passphrase}} -} - -// Create is used to generate keys for targets, snapshots and timestamps -func (ccs *ECDSACryptoService) Create(role string) (*data.PublicKey, error) { - privKey, err := trustmanager.GenerateECDSAKey(rand.Reader) - if err != nil { - return nil, fmt.Errorf("failed to generate EC key: %v", err) - } - - // Store the private key into our keystore with the name being: /GUN/ID.key - err = ccs.keyStore.AddKey(filepath.Join(ccs.gun, privKey.ID()), privKey) - if err != nil { - return nil, fmt.Errorf("failed to add key to filestore: %v", err) - } - - logrus.Debugf("generated new ECDSA key for role %s with keyID: %s", role, privKey.ID()) - - return data.PublicKeyFromPrivate(*privKey), nil -} - -// Sign returns the signatures for the payload with a set of keyIDs. It ignores -// errors to sign and expects the called to validate if the number of returned -// signatures is adequate. -func (ccs *ECDSACryptoService) Sign(keyIDs []string, payload []byte) ([]data.Signature, error) { - // Create hasher and hash data - hashed := sha256.Sum256(payload) - - signatures := make([]data.Signature, 0, len(keyIDs)) - for _, keyid := range keyIDs { - // ccs.gun will be empty if this is the root key - keyName := filepath.Join(ccs.gun, keyid) - - var privKey *data.PrivateKey - var err error - - // Read PrivateKey from file - // TODO(diogo): This assumes both that only root keys are encrypted and - // that encrypted keys are always X509 encoded - if ccs.passphrase != "" { - // This is a root key - privKey, err = ccs.keyStore.GetDecryptedKey(keyName, ccs.passphrase) - } else { - privKey, err = ccs.keyStore.GetKey(keyName) - } - if err != nil { - // Note that GetDecryptedKey always fails on InitRepo. - // InitRepo gets a signer that doesn't have access to - // the root keys. Continuing here is safe because we - // end up not returning any signatures. - // TODO(diogo): figure out if there are any specific error types to - // check. We're swallowing all errors. - logrus.Debugf("Ignoring error attempting to retrieve ECDSA key ID: %s, %v", keyid, err) - continue - } - if err != nil { - fmt.Println("ERROR: ", err.Error()) - } - - sig, err := ecdsaSign(privKey, hashed[:]) - if err != nil { - // If the ecdsaSign method got called with a non ECDSA private key, - // we ignore this call. - // This might happen when root is RSA, targets and snapshots ECDSA, and - // gotuf still attempts to sign root with this cryptoserver - // return nil, err - logrus.Debugf("ignoring error attempting to ECDSA sign with keyID: %s, %v", privKey.ID(), err) - continue - } - - logrus.Debugf("appending ECDSA signature with Key ID: %s", privKey.ID()) - - // Append signatures to result array - signatures = append(signatures, data.Signature{ - KeyID: keyid, - Method: data.ECDSASignature, - Signature: sig[:], - }) - } - - return signatures, nil -} - func ecdsaSign(privKey *data.PrivateKey, hashed []byte) ([]byte, error) { - if privKey.Cipher() != data.ECDSAKey { - return nil, fmt.Errorf("private key type not supported: %s", privKey.Cipher()) + if privKey.Algorithm() != data.ECDSAKey { + return nil, fmt.Errorf("private key type not supported: %s", privKey.Algorithm()) } // Create an ecdsa.PrivateKey out of the private key bytes diff --git a/client/client.go b/client/client.go index 9cea571efb..0961d7ff63 100644 --- a/client/client.go +++ b/client/client.go @@ -55,11 +55,12 @@ const ( /// that doesn't exist. var ErrRepositoryNotExist = errors.New("repository does not exist") -// UnlockedSigner encapsulates a private key and a signer that uses that private key, -// providing convinience methods for generation of certificates. -type UnlockedSigner struct { - privKey *data.PrivateKey - signer *signed.Signer +// UnlockedCryptoService encapsulates a private key and a cryptoservice that +// uses that private key, providing convinience methods for generation of +// certificates. +type UnlockedCryptoService struct { + privKey *data.PrivateKey + cryptoService signed.CryptoService } // NotaryRepository stores all the information needed to operate on a notary @@ -72,11 +73,10 @@ type NotaryRepository struct { caStore trustmanager.X509Store certificateStore trustmanager.X509Store fileStore store.MetadataStore - signer *signed.Signer + cryptoService signed.CryptoService tufRepo *tuf.TufRepo privKeyStore *trustmanager.KeyFileStore rootKeyStore *trustmanager.KeyFileStore - rootSigner *UnlockedSigner roundTrip http.RoundTripper } @@ -115,17 +115,16 @@ func NewNotaryRepository(baseDir, gun, baseURL string, rt http.RoundTripper) (*N return nil, err } - // TODO(diogo): This hardcodes snapshots and targets to using EC. Change it. - signer := signed.NewSigner(NewECDSACryptoService(gun, privKeyStore, "")) + cryptoService := NewCryptoService(gun, privKeyStore, "") nRepo := &NotaryRepository{ - gun: gun, - baseDir: baseDir, - baseURL: baseURL, - tufRepoPath: filepath.Join(baseDir, tufDir, gun), - signer: signer, - privKeyStore: privKeyStore, - roundTrip: rt, + gun: gun, + baseDir: baseDir, + baseURL: baseURL, + tufRepoPath: filepath.Join(baseDir, tufDir, gun), + cryptoService: cryptoService, + privKeyStore: privKeyStore, + roundTrip: rt, } if err := nRepo.loadKeys(trustDir, rootKeysDir); err != nil { @@ -137,8 +136,8 @@ func NewNotaryRepository(baseDir, gun, baseURL string, rt http.RoundTripper) (*N // 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) +func (r *NotaryRepository) Initialize(uCryptoService *UnlockedCryptoService) error { + rootCert, err := uCryptoService.GenerateCertificate(r.gun) if err != nil { return err } @@ -149,25 +148,25 @@ func (r *NotaryRepository) Initialize(uSigner *UnlockedSigner) error { // 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 cipherType string - cipher := uSigner.privKey.Cipher() - switch cipher { + var algorithmType data.KeyAlgorithm + algorithm := uCryptoService.privKey.Algorithm() + switch algorithm { case data.RSAKey: - cipherType = data.RSAx509Key + algorithmType = data.RSAx509Key case data.ECDSAKey: - cipherType = data.ECDSAx509Key + algorithmType = data.ECDSAx509Key default: - return fmt.Errorf("invalid format for root key: %s", cipher) + return fmt.Errorf("invalid format for root key: %s", algorithm) } // Generate a x509Key using the rootCert as the public key - rootKey := data.NewPublicKey(cipherType, trustmanager.CertToPEM(rootCert)) + 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(), uSigner.ID()) - err = r.rootKeyStore.Link(uSigner.ID(), rootKey.ID()) + logrus.Debugf("Linking %s to %s.", rootKey.ID(), uCryptoService.ID()) + err = r.rootKeyStore.Link(uCryptoService.ID(), rootKey.ID()) if err != nil { return err } @@ -186,15 +185,16 @@ func (r *NotaryRepository) Initialize(uSigner *UnlockedSigner) error { } // Turn the JSON timestamp key from the remote server into a TUFKey - timestampKey := data.NewPublicKey(parsedKey.Cipher(), parsedKey.Public()) - logrus.Debugf("got remote %s timestamp key with keyID: %s", parsedKey.Cipher(), timestampKey.ID()) + 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.signer.Create("targets") + targetsKey, err := r.cryptoService.Create("targets", data.ECDSAKey) if err != nil { return err } - snapshotKey, err := r.signer.Create("snapshot") + snapshotKey, err := r.cryptoService.Create("snapshot", data.ECDSAKey) if err != nil { return err } @@ -236,7 +236,7 @@ func (r *NotaryRepository) Initialize(uSigner *UnlockedSigner) error { return err } - r.tufRepo = tuf.NewTufRepo(kdb, r.signer) + r.tufRepo = tuf.NewTufRepo(kdb, r.cryptoService) r.fileStore, err = store.NewFilesystemStore( r.tufRepoPath, @@ -252,7 +252,7 @@ func (r *NotaryRepository) Initialize(uSigner *UnlockedSigner) error { return err } - if err := r.saveMetadata(uSigner.signer); err != nil { + if err := r.saveMetadata(uCryptoService.cryptoService); err != nil { return err } @@ -389,11 +389,11 @@ func (r *NotaryRepository) Publish(getPass passwordRetriever) error { return err } rootKeyID := r.tufRepo.Root.Signed.Roles["root"].KeyIDs[0] - rootSigner, err := r.GetRootSigner(rootKeyID, passphrase) + rootCryptoService, err := r.GetRootCryptoService(rootKeyID, passphrase) if err != nil { return err } - root, err = r.tufRepo.SignRoot(data.DefaultExpires("root"), rootSigner.signer) + root, err = r.tufRepo.SignRoot(data.DefaultExpires("root"), rootCryptoService.cryptoService) if err != nil { return err } @@ -459,7 +459,7 @@ func (r *NotaryRepository) bootstrapRepo() error { } kdb := keys.NewDB() - tufRepo := tuf.NewTufRepo(kdb, r.signer) + tufRepo := tuf.NewTufRepo(kdb, r.cryptoService) logrus.Debugf("Loading trusted collection.") rootJSON, err := fileStore.GetMeta("root", 0) @@ -499,8 +499,8 @@ func (r *NotaryRepository) bootstrapRepo() error { return nil } -func (r *NotaryRepository) saveMetadata(rootSigner *signed.Signer) error { - signedRoot, err := r.tufRepo.SignRoot(data.DefaultExpires("root"), rootSigner) +func (r *NotaryRepository) saveMetadata(rootCryptoService signed.CryptoService) error { + signedRoot, err := r.tufRepo.SignRoot(data.DefaultExpires("root"), rootCryptoService) if err != nil { return err } @@ -632,7 +632,7 @@ func (r *NotaryRepository) bootstrapClient() (*tufclient.Client, error) { } kdb := keys.NewDB() - r.tufRepo = tuf.NewTufRepo(kdb, r.signer) + r.tufRepo = tuf.NewTufRepo(kdb, r.cryptoService) err = r.tufRepo.SetRoot(root) if err != nil { @@ -653,11 +653,15 @@ func (r *NotaryRepository) ListRootKeys() []string { } // GenRootKey generates a new root key protected by a given passphrase +// TODO(diogo): show not create keys manually, should use a cryptoservice instead func (r *NotaryRepository) GenRootKey(algorithm, passphrase string) (string, error) { var err error var privKey *data.PrivateKey - switch strings.ToLower(algorithm) { + // We don't want external API callers to rely on internal TUF data types, so + // the API here should continue to receive a string algorithm, and ensure + // that it is downcased + switch data.KeyAlgorithm(strings.ToLower(algorithm)) { case data.RSAKey: privKey, err = trustmanager.GenerateRSAKey(rand.Reader, rsaRootKeySize) case data.ECDSAKey: @@ -676,28 +680,18 @@ func (r *NotaryRepository) GenRootKey(algorithm, passphrase string) (string, err return privKey.ID(), nil } -// GetRootSigner retreives a root key that includes the ID and a signer -func (r *NotaryRepository) GetRootSigner(rootKeyID, passphrase string) (*UnlockedSigner, error) { +// GetRootCryptoService retreives a root key and a cryptoservice to use with it +func (r *NotaryRepository) GetRootCryptoService(rootKeyID, passphrase string) (*UnlockedCryptoService, error) { privKey, err := r.rootKeyStore.GetDecryptedKey(rootKeyID, passphrase) if err != nil { return nil, fmt.Errorf("could not get decrypted root key with keyID: %s, %v", rootKeyID, err) } - var signer *signed.Signer - cipher := privKey.Cipher() - // Passing an empty GUN because root keys aren't associated with a GUN. - switch strings.ToLower(cipher) { - case data.RSAKey: - signer = signed.NewSigner(NewRSACryptoService("", r.rootKeyStore, passphrase)) - case data.ECDSAKey: - signer = signed.NewSigner(NewECDSACryptoService("", r.rootKeyStore, passphrase)) - default: - return nil, fmt.Errorf("only RSA or ECDSA keys are currently supported. Found: %s", cipher) - } + cryptoService := NewCryptoService("", r.rootKeyStore, passphrase) - return &UnlockedSigner{ - privKey: privKey, - signer: signer}, nil + return &UnlockedCryptoService{ + privKey: privKey, + cryptoService: cryptoService}, nil } func (r *NotaryRepository) loadKeys(trustDir, rootKeysDir string) error { @@ -738,35 +732,35 @@ func (r *NotaryRepository) loadKeys(trustDir, rootKeysDir string) error { return nil } -// ID gets a consistent ID based on the PrivateKey bytes and cipher type -func (uk *UnlockedSigner) ID() string { - return uk.PublicKey().ID() +// ID gets a consistent ID based on the PrivateKey bytes and algorithm type +func (ucs *UnlockedCryptoService) ID() string { + return ucs.PublicKey().ID() } -// PublicKey Returns the public key associated with the Private Key within the Signer -func (uk *UnlockedSigner) PublicKey() *data.PublicKey { - return data.PublicKeyFromPrivate(*uk.privKey) +// PublicKey Returns the public key associated with the private key +func (ucs *UnlockedCryptoService) PublicKey() *data.PublicKey { + return data.PublicKeyFromPrivate(*ucs.privKey) } // GenerateCertificate generates an X509 Certificate from a template, given a GUN -func (uk *UnlockedSigner) GenerateCertificate(gun string) (*x509.Certificate, error) { - cipher := uk.privKey.Cipher() +func (ucs *UnlockedCryptoService) GenerateCertificate(gun string) (*x509.Certificate, error) { + algorithm := ucs.privKey.Algorithm() var publicKey crypto.PublicKey var privateKey crypto.PrivateKey var err error - switch cipher { + switch algorithm { case data.RSAKey: var rsaPrivateKey *rsa.PrivateKey - rsaPrivateKey, err = x509.ParsePKCS1PrivateKey(uk.privKey.Private()) + rsaPrivateKey, err = x509.ParsePKCS1PrivateKey(ucs.privKey.Private()) privateKey = rsaPrivateKey publicKey = rsaPrivateKey.Public() case data.ECDSAKey: var ecdsaPrivateKey *ecdsa.PrivateKey - ecdsaPrivateKey, err = x509.ParseECPrivateKey(uk.privKey.Private()) + ecdsaPrivateKey, err = x509.ParseECPrivateKey(ucs.privKey.Private()) privateKey = ecdsaPrivateKey publicKey = ecdsaPrivateKey.Public() default: - return nil, fmt.Errorf("only RSA or ECDSA keys are currently supported. Found: %s", cipher) + return nil, fmt.Errorf("only RSA or ECDSA keys are currently supported. Found: %s", algorithm) } if err != nil { return nil, fmt.Errorf("failed to parse root key: %s (%v)", gun, err) diff --git a/client/client_test.go b/client/client_test.go index 084c560e72..dd74ed0cbd 100644 --- a/client/client_test.go +++ b/client/client_test.go @@ -43,11 +43,13 @@ func createTestServer(t *testing.T) (*httptest.Server, *http.ServeMux) { // sure the repository looks correct on disk. // We test this with both an RSA and ECDSA root key func TestInitRepo(t *testing.T) { - testInitRepo(t, data.RSAKey) testInitRepo(t, data.ECDSAKey) + if !testing.Short() { + testInitRepo(t, data.RSAKey) + } } -func testInitRepo(t *testing.T, rootType string) { +func testInitRepo(t *testing.T, rootType data.KeyAlgorithm) { gun := "docker.com/notary" // Temporary directory where test files will be created tempBaseDir, err := ioutil.TempDir("", "notary-test-") @@ -61,13 +63,13 @@ func testInitRepo(t *testing.T, rootType string) { repo, err := NewNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport) assert.NoError(t, err, "error creating repo: %s", err) - rootKeyID, err := repo.GenRootKey(rootType, "passphrase") + rootKeyID, err := repo.GenRootKey(rootType.String(), "passphrase") assert.NoError(t, err, "error generating root key: %s", err) - rootSigner, err := repo.GetRootSigner(rootKeyID, "passphrase") + rootCryptoService, err := repo.GetRootCryptoService(rootKeyID, "passphrase") assert.NoError(t, err, "error retrieving root key: %s", err) - err = repo.Initialize(rootSigner) + err = repo.Initialize(rootCryptoService) assert.NoError(t, err, "error creating repository: %s", err) // Inspect contents of the temporary directory @@ -98,7 +100,7 @@ func testInitRepo(t *testing.T, rootType string) { // Look for keys in root_keys // There should be a file named after the key ID of the root key we // passed in. - rootKeyFilename := rootSigner.ID() + ".key" + rootKeyFilename := rootCryptoService.ID() + ".key" _, err = os.Stat(filepath.Join(tempBaseDir, "private", "root_keys", rootKeyFilename)) assert.NoError(t, err, "missing root key") @@ -184,11 +186,13 @@ type tufChange struct { // internal HTTP server. // We test this with both an RSA and ECDSA root key func TestAddListTarget(t *testing.T) { - testAddListTarget(t, data.RSAKey) testAddListTarget(t, data.ECDSAKey) + if !testing.Short() { + testInitRepo(t, data.RSAKey) + } } -func testAddListTarget(t *testing.T, rootType string) { +func testAddListTarget(t *testing.T, rootType data.KeyAlgorithm) { // Temporary directory where test files will be created tempBaseDir, err := ioutil.TempDir("", "notary-test-") defer os.RemoveAll(tempBaseDir) @@ -203,13 +207,13 @@ func testAddListTarget(t *testing.T, rootType string) { repo, err := NewNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport) assert.NoError(t, err, "error creating repository: %s", err) - rootKeyID, err := repo.GenRootKey(rootType, "passphrase") + rootKeyID, err := repo.GenRootKey(rootType.String(), "passphrase") assert.NoError(t, err, "error generating root key: %s", err) - rootSigner, err := repo.GetRootSigner(rootKeyID, "passphrase") + rootCryptoService, err := repo.GetRootCryptoService(rootKeyID, "passphrase") assert.NoError(t, err, "error retreiving root key: %s", err) - err = repo.Initialize(rootSigner) + err = repo.Initialize(rootCryptoService) assert.NoError(t, err, "error creating repository: %s", err) // Add fixtures/ca.cert as a target. There's no particular reason @@ -367,11 +371,13 @@ func testAddListTarget(t *testing.T, rootType string) { // TestValidateRootKey verifies that the public data in root.json for the root // key is a valid x509 certificate. func TestValidateRootKey(t *testing.T) { - testValidateRootKey(t, data.RSAKey) testValidateRootKey(t, data.ECDSAKey) + if !testing.Short() { + testInitRepo(t, data.RSAKey) + } } -func testValidateRootKey(t *testing.T, rootType string) { +func testValidateRootKey(t *testing.T, rootType data.KeyAlgorithm) { // Temporary directory where test files will be created tempBaseDir, err := ioutil.TempDir("", "notary-test-") defer os.RemoveAll(tempBaseDir) @@ -386,13 +392,13 @@ func testValidateRootKey(t *testing.T, rootType string) { repo, err := NewNotaryRepository(tempBaseDir, gun, ts.URL, http.DefaultTransport) assert.NoError(t, err, "error creating repository: %s", err) - rootKeyID, err := repo.GenRootKey(rootType, "passphrase") + rootKeyID, err := repo.GenRootKey(rootType.String(), "passphrase") assert.NoError(t, err, "error generating root key: %s", err) - rootSigner, err := repo.GetRootSigner(rootKeyID, "passphrase") + rootCryptoService, err := repo.GetRootCryptoService(rootKeyID, "passphrase") assert.NoError(t, err, "error retreiving root key: %s", err) - err = repo.Initialize(rootSigner) + err = repo.Initialize(rootCryptoService) assert.NoError(t, err, "error creating repository: %s", err) rootJSONFile := filepath.Join(tempBaseDir, "tuf", gun, "metadata", "root.json") diff --git a/cmd/notary/tuf.go b/cmd/notary/tuf.go index 2d518a5a1a..c90a0610b7 100644 --- a/cmd/notary/tuf.go +++ b/cmd/notary/tuf.go @@ -13,7 +13,6 @@ import ( "github.com/Sirupsen/logrus" "github.com/docker/docker/pkg/term" notaryclient "github.com/docker/notary/client" - "github.com/endophage/gotuf/data" "github.com/spf13/cobra" "github.com/spf13/viper" ) @@ -120,7 +119,7 @@ func tufInit(cmd *cobra.Command, args []string) { if err != nil { fatalf(err.Error()) } - rootKeyID, err = nRepo.GenRootKey(data.ECDSAKey, passphrase) + rootKeyID, err = nRepo.GenRootKey("ECDSA", passphrase) if err != nil { fatalf(err.Error()) } @@ -134,12 +133,12 @@ func tufInit(cmd *cobra.Command, args []string) { } } - rootSigner, err := nRepo.GetRootSigner(rootKeyID, passphrase) + rootCryptoService, err := nRepo.GetRootCryptoService(rootKeyID, passphrase) if err != nil { fatalf(err.Error()) } - nRepo.Initialize(rootSigner) + nRepo.Initialize(rootCryptoService) if err != nil { fatalf(err.Error()) } diff --git a/server/handlers/default.go b/server/handlers/default.go index 3e0cf1572f..9d608bf906 100644 --- a/server/handlers/default.go +++ b/server/handlers/default.go @@ -165,20 +165,20 @@ func GetTimestampHandler(ctx context.Context, w http.ResponseWriter, r *http.Req Err: fmt.Errorf("Version store not configured"), } } - sign := ctx.Value("signer") - signer, ok := sign.(*signed.Signer) + cryptoServiceVal := ctx.Value("cryptoService") + cryptoService, ok := cryptoServiceVal.(signed.CryptoService) if !ok { return &errors.HTTPError{ HTTPStatus: http.StatusInternalServerError, Code: 9999, - Err: fmt.Errorf("Signer not configured"), + Err: fmt.Errorf("CryptoService not configured"), } } vars := mux.Vars(r) gun := vars["imageName"] - out, err := timestamp.GetOrCreateTimestamp(gun, store, signer) + out, err := timestamp.GetOrCreateTimestamp(gun, store, cryptoService) if err != nil { if _, ok := err.(*storage.ErrNoKey); ok { return &errors.HTTPError{ @@ -224,7 +224,7 @@ func GetTimestampKeyHandler(ctx context.Context, w http.ResponseWriter, r *http. vars := mux.Vars(r) gun := vars["imageName"] - key, err := timestamp.GetOrCreateTimestampKey(gun, store, crypto) + key, err := timestamp.GetOrCreateTimestampKey(gun, store, crypto, data.ECDSAKey) if err != nil { return &errors.HTTPError{ HTTPStatus: http.StatusInternalServerError, diff --git a/server/storage/database.go b/server/storage/database.go index c3cdd554d6..6c7ea3ad4d 100644 --- a/server/storage/database.go +++ b/server/storage/database.go @@ -3,6 +3,7 @@ package storage import ( "database/sql" + "github.com/endophage/gotuf/data" "github.com/go-sql-driver/mysql" ) @@ -91,10 +92,11 @@ func (db *MySQLStorage) Delete(gun string) error { } // GetTimestampKey returns the timestamps Public Key data -func (db *MySQLStorage) GetTimestampKey(gun string) (cipher string, public []byte, err error) { +func (db *MySQLStorage) GetTimestampKey(gun string) (algorithm data.KeyAlgorithm, public []byte, err error) { stmt := "SELECT `cipher`, `public` FROM `timestamp_keys` WHERE `gun`=?;" row := db.QueryRow(stmt, gun) + var cipher string err = row.Scan(&cipher, &public) if err == sql.ErrNoRows { return "", nil, ErrNoKey{gun: gun} @@ -102,13 +104,13 @@ func (db *MySQLStorage) GetTimestampKey(gun string) (cipher string, public []byt return "", nil, err } - return cipher, public, err + return data.KeyAlgorithm(cipher), public, err } // SetTimestampKey attempts to write a TimeStamp key and returns an error if it already exists -func (db *MySQLStorage) SetTimestampKey(gun, cipher string, public []byte) error { +func (db *MySQLStorage) SetTimestampKey(gun string, algorithm data.KeyAlgorithm, public []byte) error { stmt := "INSERT INTO `timestamp_keys` (`gun`, `cipher`, `public`) VALUES (?,?,?);" - _, err := db.Exec(stmt, gun, cipher, public) + _, err := db.Exec(stmt, gun, string(algorithm), public) if err, ok := err.(*mysql.MySQLError); ok { if err.Number == 1022 { // duplicate key error return &ErrTimestampKeyExists{gun: gun} diff --git a/server/storage/interface.go b/server/storage/interface.go index 25ee4f644e..f6296ffb0b 100644 --- a/server/storage/interface.go +++ b/server/storage/interface.go @@ -1,10 +1,12 @@ package storage +import "github.com/endophage/gotuf/data" + // MetaStore holds the methods that are used for a Metadata Store type MetaStore interface { UpdateCurrent(gun, role string, version int, data []byte) error GetCurrent(gun, tufRole string) (data []byte, err error) Delete(gun string) error - GetTimestampKey(gun string) (cipher string, public []byte, err error) - SetTimestampKey(gun, cipher string, public []byte) error + GetTimestampKey(gun string) (algorithm data.KeyAlgorithm, public []byte, err error) + SetTimestampKey(gun string, algorithm data.KeyAlgorithm, public []byte) error } diff --git a/server/storage/memory.go b/server/storage/memory.go index a4d4bfe441..99ac4ed5bd 100644 --- a/server/storage/memory.go +++ b/server/storage/memory.go @@ -4,11 +4,13 @@ import ( "fmt" "strings" "sync" + + "github.com/endophage/gotuf/data" ) type key struct { - cipher string - public []byte + algorithm data.KeyAlgorithm + public []byte } type ver struct { @@ -73,7 +75,7 @@ func (st *MemStorage) Delete(gun string) error { } // GetTimestampKey returns the public key material of the timestamp key of a given gun -func (st *MemStorage) GetTimestampKey(gun string) (cipher string, public []byte, err error) { +func (st *MemStorage) GetTimestampKey(gun string) (algorithm data.KeyAlgorithm, public []byte, err error) { // no need for lock. It's ok to return nil if an update // wasn't observed k, ok := st.tsKeys[gun] @@ -81,12 +83,12 @@ func (st *MemStorage) GetTimestampKey(gun string) (cipher string, public []byte, return "", nil, &ErrNoKey{gun: gun} } - return k.cipher, k.public, nil + return k.algorithm, k.public, nil } // SetTimestampKey sets a Timestamp key under a gun -func (st *MemStorage) SetTimestampKey(gun, cipher string, public []byte) error { - k := &key{cipher: cipher, public: public} +func (st *MemStorage) SetTimestampKey(gun string, algorithm data.KeyAlgorithm, public []byte) error { + k := &key{algorithm: algorithm, public: public} st.lock.Lock() defer st.lock.Unlock() if _, ok := st.tsKeys[gun]; ok { diff --git a/server/storage/memory_test.go b/server/storage/memory_test.go index c6a7f00d53..aba7722b80 100644 --- a/server/storage/memory_test.go +++ b/server/storage/memory_test.go @@ -51,7 +51,7 @@ func TestGetTimestampKey(t *testing.T) { c, k, err := s.GetTimestampKey("gun") assert.Nil(t, err, "Expected error to be nil") - assert.Equal(t, data.RSAKey, c, "Expected cipher rsa, received %s", c) + assert.Equal(t, data.RSAKey, c, "Expected algorithm rsa, received %s", c) assert.Equal(t, []byte("test"), k, "Key data was wrong") } @@ -63,7 +63,7 @@ func TestSetTimestampKey(t *testing.T) { assert.IsType(t, &ErrTimestampKeyExists{}, err, "Expected err to be ErrTimestampKeyExists") k := s.tsKeys["gun"] - assert.Equal(t, data.RSAKey, k.cipher, "Expected cipher to be rsa, received %s", k.cipher) + assert.Equal(t, data.RSAKey, k.algorithm, "Expected algorithm to be rsa, received %s", k.algorithm) assert.Equal(t, []byte("test"), k.public, "Public key did not match expected") } diff --git a/server/timestamp/timestamp.go b/server/timestamp/timestamp.go index e558c7a7b9..dbacecc1f1 100644 --- a/server/timestamp/timestamp.go +++ b/server/timestamp/timestamp.go @@ -17,28 +17,28 @@ import ( // found. It attempts to handle the race condition that may occur if 2 servers try to // create the key at the same time by simply querying the store a second time if it // receives a conflict when writing. -func GetOrCreateTimestampKey(gun string, store storage.MetaStore, crypto signed.CryptoService) (*data.TUFKey, error) { - cipher, public, err := store.GetTimestampKey(gun) +func GetOrCreateTimestampKey(gun string, store storage.MetaStore, crypto signed.CryptoService, fallBackAlgorithm data.KeyAlgorithm) (*data.TUFKey, error) { + keyAlgorithm, public, err := store.GetTimestampKey(gun) if err == nil { - return data.NewTUFKey(cipher, public, nil), nil + return data.NewTUFKey(keyAlgorithm, public, nil), nil } if _, ok := err.(*storage.ErrNoKey); ok { - key, err := crypto.Create("timestamp") + key, err := crypto.Create("timestamp", fallBackAlgorithm) if err != nil { return nil, err } - err = store.SetTimestampKey(gun, key.Cipher(), key.Public()) + err = store.SetTimestampKey(gun, key.Algorithm(), key.Public()) if err == nil { return &key.TUFKey, nil } if _, ok := err.(*storage.ErrTimestampKeyExists); ok { - cipher, public, err = store.GetTimestampKey(gun) + keyAlgorithm, public, err = store.GetTimestampKey(gun) if err != nil { return nil, err } - return data.NewTUFKey(cipher, public, nil), nil + return data.NewTUFKey(keyAlgorithm, public, nil), nil } return nil, err } @@ -48,7 +48,7 @@ func GetOrCreateTimestampKey(gun string, store storage.MetaStore, crypto signed. // GetOrCreateTimestamp returns the current timestamp for the gun. This may mean // a new timestamp is generated either because none exists, or because the current // one has expired. Once generated, the timestamp is saved in the store. -func GetOrCreateTimestamp(gun string, store storage.MetaStore, signer *signed.Signer) ([]byte, error) { +func GetOrCreateTimestamp(gun string, store storage.MetaStore, cryptoService signed.CryptoService) ([]byte, error) { d, err := store.GetCurrent(gun, "timestamp") if err != nil { if _, ok := err.(*storage.ErrNotFound); !ok { @@ -69,7 +69,7 @@ func GetOrCreateTimestamp(gun string, store storage.MetaStore, signer *signed.Si return d, nil } } - sgnd, version, err := createTimestamp(gun, ts, store, signer) + sgnd, version, err := createTimestamp(gun, ts, store, cryptoService) if err != nil { logrus.Error("Failed to create a new timestamp") return nil, err @@ -95,14 +95,14 @@ func timestampExpired(ts *data.SignedTimestamp) bool { // is assumed this is the immediately previous one, and the new one will have a // version number one higher than prev. The store is used to lookup the current // snapshot, this function does not save the newly generated timestamp. -func createTimestamp(gun string, prev *data.SignedTimestamp, store storage.MetaStore, signer *signed.Signer) (*data.Signed, int, error) { - cipher, public, err := store.GetTimestampKey(gun) +func createTimestamp(gun string, prev *data.SignedTimestamp, store storage.MetaStore, cryptoService signed.CryptoService) (*data.Signed, int, error) { + algorithm, public, err := store.GetTimestampKey(gun) if err != nil { // owner of gun must have generated a timestamp key otherwise // we won't proceed with generating everything. return nil, 0, err } - key := data.NewPublicKey(cipher, public) + key := data.NewPublicKey(algorithm, public) snapshot, err := store.GetCurrent(gun, "snapshot") if err != nil { return nil, 0, err @@ -128,7 +128,7 @@ func createTimestamp(gun string, prev *data.SignedTimestamp, store storage.MetaS Signatures: ts.Signatures, Signed: sgndTs, } - err = signer.Sign(out, key) + err = signed.Sign(cryptoService, out, key) if err != nil { return nil, 0, err } diff --git a/server/timestamp/timestamp_test.go b/server/timestamp/timestamp_test.go index e700439c6f..e7da42c4b8 100644 --- a/server/timestamp/timestamp_test.go +++ b/server/timestamp/timestamp_test.go @@ -32,11 +32,11 @@ func TestTimestampExpired(t *testing.T) { func TestGetTimestampKey(t *testing.T) { store := storage.NewMemStorage() crypto := signed.NewEd25519() - k, err := GetOrCreateTimestampKey("gun", store, crypto) + k, err := GetOrCreateTimestampKey("gun", store, crypto, data.ED25519Key) assert.Nil(t, err, "Expected nil error") assert.NotNil(t, k, "Key should not be nil") - k2, err := GetOrCreateTimestampKey("gun", store, crypto) + k2, err := GetOrCreateTimestampKey("gun", store, crypto, data.ED25519Key) assert.Nil(t, err, "Expected nil error") @@ -48,16 +48,15 @@ func TestGetTimestampKey(t *testing.T) { func TestGetTimestamp(t *testing.T) { store := storage.NewMemStorage() crypto := signed.NewEd25519() - signer := signed.NewSigner(crypto) snapshot := &data.SignedSnapshot{} snapJSON, _ := json.Marshal(snapshot) store.UpdateCurrent("gun", "snapshot", 0, snapJSON) // create a key to be used by GetTimestamp - _, err := GetOrCreateTimestampKey("gun", store, crypto) + _, err := GetOrCreateTimestampKey("gun", store, crypto, data.ED25519Key) assert.Nil(t, err, "GetTimestampKey errored") - _, err = GetOrCreateTimestamp("gun", store, signer) + _, err = GetOrCreateTimestamp("gun", store, crypto) assert.Nil(t, err, "GetTimestamp errored") } diff --git a/signer/rufus_trust.go b/signer/rufus_trust.go index adf90b9bba..9d3609711c 100644 --- a/signer/rufus_trust.go +++ b/signer/rufus_trust.go @@ -54,7 +54,7 @@ func (trust *RufusSigner) Sign(keyIDs []string, toSign []byte) ([]data.Signature } signatures = append(signatures, data.Signature{ KeyID: sig.KeyID.ID, - Method: sig.Algorithm.Algorithm, + Method: data.SigAlgorithm(sig.Algorithm.Algorithm), Signature: sig.Content, }) } @@ -62,13 +62,14 @@ func (trust *RufusSigner) Sign(keyIDs []string, toSign []byte) ([]data.Signature } // Create creates a remote key and returns the PublicKey associated with the remote private key -func (trust *RufusSigner) Create(role string) (*data.PublicKey, error) { +// TODO(diogo): Ignoring algorithm for now until rufus supports it +func (trust *RufusSigner) Create(role string, _ data.KeyAlgorithm) (*data.PublicKey, error) { publicKey, err := trust.kmClient.CreateKey(context.Background(), &pb.Void{}) if err != nil { return nil, err } //TODO(mccauley): Update API to return algorithm and/or take it as a param - public := data.NewPublicKey(publicKey.Algorithm.Algorithm, publicKey.PublicKey) + public := data.NewPublicKey(data.KeyAlgorithm(publicKey.Algorithm.Algorithm), publicKey.PublicKey) return public, nil } @@ -82,7 +83,7 @@ func (trust *RufusSigner) PublicKeys(keyIDs ...string) (map[string]*data.PublicK return nil, err } publicKeys[public.KeyID.ID] = - data.NewPublicKey(public.Algorithm.Algorithm, public.PublicKey) + data.NewPublicKey(data.KeyAlgorithm(public.Algorithm.Algorithm), public.PublicKey) } return publicKeys, nil } diff --git a/trustmanager/x509utils.go b/trustmanager/x509utils.go index 614ad8b87a..98c615673a 100644 --- a/trustmanager/x509utils.go +++ b/trustmanager/x509utils.go @@ -100,7 +100,7 @@ func fingerprintCert(cert *x509.Certificate) (CertID, error) { block := pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw} pemdata := pem.EncodeToMemory(&block) - keyType := "" + var keyType data.KeyAlgorithm switch cert.PublicKeyAlgorithm { case x509.RSA: keyType = data.RSAx509Key @@ -228,7 +228,7 @@ func GenerateRSAKey(random io.Reader, bits int) (*data.PrivateKey, error) { } // RSAToPrivateKey converts an rsa.Private key to a TUF data.PrivateKey type -func RSAToPrivateKey(rsaPrivKey *rsa.PrivateKey, keyType string) (*data.PrivateKey, error) { +func RSAToPrivateKey(rsaPrivKey *rsa.PrivateKey, keyType data.KeyAlgorithm) (*data.PrivateKey, error) { // Get a DER-encoded representation of the PublicKey rsaPubBytes, err := x509.MarshalPKIXPublicKey(&rsaPrivKey.PublicKey) if err != nil { @@ -261,7 +261,7 @@ func GenerateECDSAKey(random io.Reader) (*data.PrivateKey, error) { } // ECDSAToPrivateKey converts an rsa.Private key to a TUF data.PrivateKey type -func ECDSAToPrivateKey(ecdsaPrivKey *ecdsa.PrivateKey, keyType string) (*data.PrivateKey, error) { +func ECDSAToPrivateKey(ecdsaPrivKey *ecdsa.PrivateKey, keyType data.KeyAlgorithm) (*data.PrivateKey, error) { // Get a DER-encoded representation of the PublicKey ecdsaPubBytes, err := x509.MarshalPKIXPublicKey(&ecdsaPrivKey.PublicKey) if err != nil { @@ -280,15 +280,15 @@ func ECDSAToPrivateKey(ecdsaPrivKey *ecdsa.PrivateKey, keyType string) (*data.Pr // KeyToPEM returns a PEM encoded key from a Private Key func KeyToPEM(privKey *data.PrivateKey) ([]byte, error) { var pemType string - cipher := privKey.Cipher() + algorithm := privKey.Algorithm() - switch cipher { + switch algorithm { case data.RSAKey: pemType = "RSA PRIVATE KEY" case data.ECDSAKey: pemType = "EC PRIVATE KEY" default: - return nil, fmt.Errorf("only RSA or ECDSA keys are currently supported. Found: %s", cipher) + return nil, fmt.Errorf("only RSA or ECDSA keys are currently supported. Found: %s", algorithm) } return pem.EncodeToMemory(&pem.Block{Type: pemType, Bytes: privKey.Private()}), nil @@ -298,15 +298,15 @@ func KeyToPEM(privKey *data.PrivateKey) ([]byte, error) { // and a passphrase func EncryptPrivateKey(key *data.PrivateKey, passphrase string) ([]byte, error) { var blockType string - cipher := key.Cipher() + algorithm := key.Algorithm() - switch cipher { + switch algorithm { case data.RSAKey: blockType = "RSA PRIVATE KEY" case data.ECDSAKey: blockType = "EC PRIVATE KEY" default: - return nil, fmt.Errorf("only RSA or ECDSA keys are currently supported. Found: %s", cipher) + return nil, fmt.Errorf("only RSA or ECDSA keys are currently supported. Found: %s", algorithm) } password := []byte(passphrase) diff --git a/utils/http.go b/utils/http.go index 3cec365fee..fcdca4b117 100644 --- a/utils/http.go +++ b/utils/http.go @@ -48,9 +48,6 @@ func (root *rootHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) { vars := mux.Vars(r) ctx := context.WithValue(root.context, "repo", vars["imageName"]) - // endophage: I don't guarantee that a signer will always be stateless but a CryptoService - // is expected to be. Create a new Signer for each request. - ctx = context.WithValue(ctx, "signer", signed.NewSigner(root.trust)) ctx = context.WithValue(ctx, "cryptoService", root.trust) ctx = context.WithValue(ctx, "http.request", r)