Update gotuf to 875881b1d0ce625f54318e3ebfd79414a6b5e285

This brings in the Signer removal.

Signed-off-by: Aaron Lehmann <aaron.lehmann@docker.com>
This commit is contained in:
Aaron Lehmann
2015-07-13 14:42:24 -07:00
parent a139807d89
commit ea298b4999
36 changed files with 158 additions and 1190 deletions

2
Godeps/Godeps.json generated
View File

@@ -52,7 +52,7 @@
},
{
"ImportPath": "github.com/endophage/gotuf",
"Rev": "ab4ba80203ffa5bfd742e6891bd28bfbf43a9453"
"Rev": "875881b1d0ce625f54318e3ebfd79414a6b5e285"
},
{
"ImportPath": "github.com/go-sql-driver/mysql",

View File

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

View File

@@ -1,27 +0,0 @@
package main
import (
"os"
"github.com/codegangsta/cli"
)
func main() {
app := cli.NewApp()
app.Name = "tufc"
app.Usage = "tuf download <package name>"
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)
}

View File

@@ -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] <command> [<args>...]
Options:
-h, --help
Commands:
help Show usage for a specific command
meta Generate metadata from the given file path
See "tuf help <command>" for more information on a specific command
`
args, _ := docopt.Parse(usage, nil, true, "", true)
cmd := args.String["<command>"]
cmdArgs := args.All["<args>"].([]string)
if cmd == "help" {
if len(cmdArgs) == 0 { // `tuf help`
fmt.Println(usage)
return
} else { // `tuf help <command>`
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)
}

View File

@@ -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 [<path>...]
Generate sample metadata for file(s) given by path.
`)
}
func cmdMeta(args *docopt.Args, repo *tuf.Repo) error {
paths := args.All["<path>"].([]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
}

View File

@@ -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
```

View File

@@ -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=<path>] <url> <target>
Options:
-s <path> 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["<target>"])
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
}

View File

@@ -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=<path>] <url> [<root-keys-file>]
Options:
-s <path> 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["<root-keys-file>"]
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))
}

View File

@@ -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=<path>] <url>
Options:
-s <path> 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
}

View File

@@ -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] <command> [<args>...]
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 <command>" for more information on a specific command.
`
args, _ := docopt.Parse(usage, nil, true, "", true)
cmd := args.String["<command>"]
cmdArgs := args.All["<args>"].([]string)
if cmd == "help" {
if len(cmdArgs) == 0 { // `tuf-client help`
fmt.Println(usage)
return
} else { // `tuf-client help <command>`
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["<url>"], nil)
if err != nil {
return nil, err
}
return client.NewClient(local, remote), nil
}

View File

@@ -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=<days>] [--custom=<data>] [<path>...]
Add target file(s).
Options:
--expires=<days> Set the targets manifest to expire <days> days from now.
--custom=<data> 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["<path>"].([]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...)
}

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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=<days>] <role>
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=<days> Set the root manifest to expire <days> days from now.
`)
}
func cmdGenKey(args *docopt.Args, repo *tuf.Repo) error {
role := args.String["<role>"]
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
}

View File

@@ -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")
}

View File

@@ -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=<dir>] [--insecure-plaintext] <command> [<args>...]
Options:
-h, --help
-d <dir> 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 <command>" for more information on a specific command
`
args, _ := docopt.Parse(usage, nil, true, "", true)
cmd := args.String["<command>"]
cmdArgs := args.All["<args>"].([]string)
if cmd == "help" {
if len(cmdArgs) == 0 { // `tuf help`
fmt.Println(usage)
return
} else { // `tuf help <command>`
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
}

View File

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

View File

@@ -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=<days>] [--all] [<path>...]
Remove target file(s).
Options:
--all Remove all target files.
--expires=<days> Set the targets manifest to expire <days> days from now.
`)
}
func cmdRemove(args *docopt.Args, repo *tuf.Repo) error {
paths := args.All["<path>"].([]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)
}

View File

@@ -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=<days>] <role> <id>
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=<days> Set the root manifest to expire <days> 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["<role>"], args.String["<id>"], expires)
}
return repo.RevokeKey(args.String["<role>"], args.String["<id>"])
}

View File

@@ -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)
}

View File

@@ -1,18 +0,0 @@
package main
import (
"github.com/endophage/gotuf"
"github.com/flynn/go-docopt"
)
func init() {
register("sign", cmdSign, `
usage: tuf sign <manifest>
Sign a manifest.
`)
}
func cmdSign(args *docopt.Args, repo *tuf.Repo) error {
return repo.Sign(args.String["<manifest>"])
}

View File

@@ -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=<days>] [--compression=<format>]
Update the snapshot manifest.
Options:
--expires=<days> Set the snapshot manifest to expire <days> 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)
}

View File

@@ -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=<days>]
Update the timestamp manifest.
Options:
--expires=<days> Set the timestamp manifest to expire <days> 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()
}

View File

@@ -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),

View File

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

View File

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

View File

@@ -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

View File

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

View File

@@ -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)

View File

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

View File

@@ -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

View File

@@ -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)

View File

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

View File

@@ -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-----\n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\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)
}

View File

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

View File

@@ -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)
}