From 2a8cb01827bfbf098da9a9b662aa9980609df9f0 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Wed, 27 Apr 2022 17:34:37 +0200 Subject: [PATCH 01/14] support plugin keys Signed-off-by: qmuntal --- cmd/notation/cert.go | 29 +++---- cmd/notation/cert_gen.go | 6 +- cmd/notation/key.go | 159 +++++++++++++++++++++++--------------- cmd/notation/main.go | 1 + cmd/notation/plugin.go | 38 +++++++++ cmd/notation/verify.go | 7 +- go.mod | 6 +- go.sum | 9 +-- internal/cmd/signer.go | 7 +- internal/ioutil/print.go | 54 +++++++++++++ internal/slices/slices.go | 27 +++++++ pkg/config/config.go | 38 ++++++++- pkg/config/map.go | 99 ------------------------ pkg/config/util.go | 32 ++------ 14 files changed, 292 insertions(+), 220 deletions(-) create mode 100644 cmd/notation/plugin.go create mode 100644 internal/ioutil/print.go create mode 100644 internal/slices/slices.go delete mode 100644 pkg/config/map.go diff --git a/cmd/notation/cert.go b/cmd/notation/cert.go index 7cd07de43..0ff235038 100644 --- a/cmd/notation/cert.go +++ b/cmd/notation/cert.go @@ -3,10 +3,13 @@ package main import ( "errors" "fmt" + "os" "path/filepath" "time" "github.com/notaryproject/notation-go/crypto/cryptoutil" + "github.com/notaryproject/notation/internal/ioutil" + "github.com/notaryproject/notation/internal/slices" "github.com/notaryproject/notation/pkg/config" "github.com/urfave/cli/v2" ) @@ -123,9 +126,13 @@ func addCert(ctx *cli.Context) error { } func addCertCore(cfg *config.File, name, path string) error { - if ok := cfg.VerificationCertificates.Certificates.Append(name, path); !ok { + if slices.Contains(cfg.VerificationCertificates.Certificates, name) { return errors.New(name + ": already exists") } + cfg.VerificationCertificates.Certificates = append(cfg.VerificationCertificates.Certificates, config.CertificateReference{ + Name: name, + Path: path, + }) return nil } @@ -137,7 +144,7 @@ func listCerts(ctx *cli.Context) error { } // write out - printCertificateSet(cfg.VerificationCertificates.Certificates) + ioutil.PrintCertificateMap(os.Stdout, cfg.VerificationCertificates.Certificates) return nil } @@ -156,9 +163,11 @@ func removeCerts(ctx *cli.Context) error { var removedNames []string for _, name := range names { - if ok := cfg.VerificationCertificates.Certificates.Remove(name); !ok { + idx := slices.Index(cfg.VerificationCertificates.Certificates, name) + if idx < 0 { return errors.New(name + ": not found") } + cfg.VerificationCertificates.Certificates = slices.Delete(cfg.VerificationCertificates.Certificates, idx) removedNames = append(removedNames, name) } if err := cfg.Save(); err != nil { @@ -172,20 +181,6 @@ func removeCerts(ctx *cli.Context) error { return nil } -func printCertificateSet(s config.CertificateMap) { - maxNameSize := 0 - for _, ref := range s { - if len(ref.Name) > maxNameSize { - maxNameSize = len(ref.Name) - } - } - format := fmt.Sprintf("%%-%ds\t%%s\n", maxNameSize) - fmt.Printf(format, "NAME", "PATH") - for _, ref := range s { - fmt.Printf(format, ref.Name, ref.Path) - } -} - func nameFromPath(path string) string { base := filepath.Base(path) name := base[:len(base)-len(filepath.Ext(base))] diff --git a/cmd/notation/cert_gen.go b/cmd/notation/cert_gen.go index 1db476534..ed96b9843 100644 --- a/cmd/notation/cert_gen.go +++ b/cmd/notation/cert_gen.go @@ -63,7 +63,9 @@ func generateTestCert(ctx *cli.Context) error { if err != nil { return err } - isDefaultKey, err := addKeyCore(cfg, name, keyPath, certPath, ctx.Bool(keyDefaultFlag.Name)) + isDefault := ctx.Bool(keyDefaultFlag.Name) + keySuite := config.KeySuite{Name: name, X509KeyPair: &config.X509KeyPair{KeyPath: keyPath, CertificatePath: certPath}} + err = addKeyCore(cfg, keySuite, ctx.Bool(keyDefaultFlag.Name)) if err != nil { return err } @@ -79,7 +81,7 @@ func generateTestCert(ctx *cli.Context) error { // write out fmt.Printf("%s: added to the key list\n", name) - if isDefaultKey { + if isDefault { fmt.Printf("%s: marked as default\n", name) } if trust { diff --git a/cmd/notation/key.go b/cmd/notation/key.go index 34ceeb965..995a520e4 100644 --- a/cmd/notation/key.go +++ b/cmd/notation/key.go @@ -4,8 +4,12 @@ import ( "crypto/tls" "errors" "fmt" + "os" "path/filepath" + "github.com/notaryproject/notation-go/plugin" + "github.com/notaryproject/notation/internal/ioutil" + "github.com/notaryproject/notation/internal/slices" "github.com/notaryproject/notation/pkg/config" "github.com/urfave/cli/v2" ) @@ -31,12 +35,21 @@ var ( keyAddCommand = &cli.Command{ Name: "add", Usage: "Add key to signing key list", - ArgsUsage: " ", + ArgsUsage: "[ ]", Flags: []cli.Flag{ &cli.StringFlag{ Name: "name", Aliases: []string{"n"}, - Usage: "key name", + Usage: "key name (required if --plugin is set)", + }, + &cli.StringFlag{ + Name: "id", + Usage: "key id (required if --plugin is set)", + }, + &cli.StringFlag{ + Name: "plugin", + Aliases: []string{"p"}, + Usage: "signing plugin name", }, keyDefaultFlag, }, @@ -71,63 +84,107 @@ var ( ) func addKey(ctx *cli.Context) error { - // initialize - args := ctx.Args() - switch args.Len() { - case 0: - return errors.New("missing key and certificate paths") - case 1: - return errors.New("missing certificate path for the correspoding key") + cfg, err := config.LoadOrDefault() + if err != nil { + return err + } + var key *config.KeySuite + pluginName := ctx.String("plugin") + if pluginName != "" { + key, err = addExternalKey(ctx, pluginName) + } else { + key, err = newX509KeyPair(ctx) } - - keyPath, err := filepath.Abs(args.Get(0)) if err != nil { return err } - certPath, err := filepath.Abs(args.Get(1)) + + isDefault := ctx.Bool(keyDefaultFlag.Name) + err = addKeyCore(cfg, *key, isDefault) if err != nil { return err } + + if err := cfg.Save(); err != nil { + return err + } + + // write out + if isDefault { + fmt.Printf("%s: marked as default\n", key.Name) + } else { + fmt.Println(key.Name) + } + return nil +} + +func addExternalKey(ctx *cli.Context, pluginName string) (*config.KeySuite, error) { name := ctx.String("name") if name == "" { - name = nameFromPath(keyPath) + return nil, errors.New("missing key name") + } + id := ctx.String("id") + if id == "" { + return nil, errors.New("missing key id") + } + mgr, err := plugin.NewManager() + if err != nil { + return nil, err + } + p, err := mgr.Get(pluginName) + if err != nil { + return nil, err + } + if p.Err != nil { + return nil, fmt.Errorf("invalid plugin: %w", p.Err) } + return &config.KeySuite{ + Name: name, + ExternalKey: &config.ExternalKey{ID: id, PluginName: pluginName}, + }, nil +} - // check key / cert pair - if _, err := tls.LoadX509KeyPair(certPath, keyPath); err != nil { - return err +func newX509KeyPair(ctx *cli.Context) (*config.KeySuite, error) { + args := ctx.Args() + switch args.Len() { + case 0: + return nil, errors.New("missing key and certificate paths") + case 1: + return nil, errors.New("missing certificate path for the corresponding key") } - // core process - cfg, err := config.LoadOrDefault() + keyPath, err := filepath.Abs(args.Get(0)) if err != nil { - return err + return nil, err } - isDefault, err := addKeyCore(cfg, name, keyPath, certPath, ctx.Bool(keyDefaultFlag.Name)) + certPath, err := filepath.Abs(args.Get(1)) if err != nil { - return err + return nil, err } - if err := cfg.Save(); err != nil { - return err + name := ctx.String("name") + if name == "" { + name = nameFromPath(keyPath) } - // write out - if isDefault { - fmt.Printf("%s: marked as default\n", name) - } else { - fmt.Println(name) + // check key / cert pair + if _, err := tls.LoadX509KeyPair(certPath, keyPath); err != nil { + return nil, err } - return nil + return &config.KeySuite{ + Name: name, + X509KeyPair: &config.X509KeyPair{KeyPath: keyPath, CertificatePath: certPath}, + }, nil } -func addKeyCore(cfg *config.File, name, keyPath, certPath string, markDefault bool) (bool, error) { - if ok := cfg.SigningKeys.Keys.Append(name, keyPath, certPath); !ok { - return false, errors.New(name + ": already exists") +func addKeyCore(cfg *config.File, key config.KeySuite, markDefault bool) error { + if slices.Contains(cfg.SigningKeys.Keys, key.Name) { + return errors.New(key.Name + ": already exists") } + cfg.SigningKeys.Keys = append(cfg.SigningKeys.Keys, key) if markDefault { - cfg.SigningKeys.Default = name + cfg.SigningKeys.Default = key.Name } - return cfg.SigningKeys.Default == name, nil + return nil } func updateKey(ctx *cli.Context) error { @@ -142,7 +199,7 @@ func updateKey(ctx *cli.Context) error { if err != nil { return err } - if _, _, ok := cfg.SigningKeys.Keys.Get(name); !ok { + if !slices.Contains(cfg.SigningKeys.Keys, name) { return errors.New(name + ": not found") } if !ctx.Bool(keyDefaultFlag.Name) { @@ -168,7 +225,7 @@ func listKeys(ctx *cli.Context) error { } // write out - printKeySet(cfg.SigningKeys.Default, cfg.SigningKeys.Keys) + ioutil.PrintKeyMap(os.Stdout, cfg.SigningKeys.Default, cfg.SigningKeys.Keys) return nil } @@ -188,9 +245,11 @@ func removeKeys(ctx *cli.Context) error { prevDefault := cfg.SigningKeys.Default var removedNames []string for _, name := range names { - if ok := cfg.SigningKeys.Keys.Remove(name); !ok { + idx := slices.Index(cfg.SigningKeys.Keys, name) + if idx < 0 { return errors.New(name + ": not found") } + cfg.SigningKeys.Keys = slices.Delete(cfg.SigningKeys.Keys, idx) removedNames = append(removedNames, name) if prevDefault == name { cfg.SigningKeys.Default = "" @@ -210,29 +269,3 @@ func removeKeys(ctx *cli.Context) error { } return nil } - -func printKeySet(target string, s config.KeyMap) { - if len(s) == 0 { - fmt.Println("NAME\tPATH") - return - } - - var maxNameSize, maxKeyPathSize int - for _, ref := range s { - if len(ref.Name) > maxNameSize { - maxNameSize = len(ref.Name) - } - if len(ref.KeyPath) > maxKeyPathSize { - maxKeyPathSize = len(ref.KeyPath) - } - } - format := fmt.Sprintf("%%c %%-%ds\t%%-%ds\t%%s\n", maxNameSize, maxKeyPathSize) - fmt.Printf(format, ' ', "NAME", "KEY PATH", "CERTIFICATE PATH") - for _, ref := range s { - mark := ' ' - if ref.Name == target { - mark = '*' - } - fmt.Printf(format, mark, ref.Name, ref.KeyPath, ref.CertificatePath) - } -} diff --git a/cmd/notation/main.go b/cmd/notation/main.go index a51fa425d..e5d653f6e 100644 --- a/cmd/notation/main.go +++ b/cmd/notation/main.go @@ -27,6 +27,7 @@ func main() { certCommand, keyCommand, cacheCommand, + pluginCommand, }, } if err := app.Run(os.Args); err != nil { diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go new file mode 100644 index 000000000..b03aa676f --- /dev/null +++ b/cmd/notation/plugin.go @@ -0,0 +1,38 @@ +package main + +import ( + "os" + + "github.com/notaryproject/notation-go/plugin" + "github.com/notaryproject/notation/internal/ioutil" + "github.com/urfave/cli/v2" +) + +var ( + pluginCommand = &cli.Command{ + Name: "plugin", + Aliases: []string{"ls"}, + Usage: "Manage plugins", + Subcommands: []*cli.Command{ + pluginListCommand, + }, + } + + pluginListCommand = &cli.Command{ + Name: "list", + Usage: "List registered plugins", + Action: listPlugins, + } +) + +func listPlugins(ctx *cli.Context) error { + mgr, err := plugin.NewManager() + if err != nil { + return err + } + plugins, err := mgr.List() + if err != nil { + return err + } + return ioutil.PrintPlugins(os.Stdout, plugins) +} diff --git a/cmd/notation/verify.go b/cmd/notation/verify.go index 97c643c76..5b9642407 100644 --- a/cmd/notation/verify.go +++ b/cmd/notation/verify.go @@ -8,6 +8,7 @@ import ( "github.com/notaryproject/notation-go" "github.com/notaryproject/notation/internal/cmd" + "github.com/notaryproject/notation/internal/slices" "github.com/notaryproject/notation/pkg/cache" "github.com/notaryproject/notation/pkg/config" "github.com/notaryproject/notation/pkg/signature" @@ -137,11 +138,11 @@ func appendCertPathFromName(paths, names []string) ([]string, error) { if err != nil { return nil, err } - path, ok := cfg.VerificationCertificates.Certificates.Get(name) - if !ok { + idx := slices.Index(cfg.VerificationCertificates.Certificates, name) + if idx < 0 { return nil, errors.New("verification certificate not found: " + name) } - paths = append(paths, path) + paths = append(paths, cfg.VerificationCertificates.Certificates[idx].Path) } return paths, nil } diff --git a/go.mod b/go.mod index 019c1afd3..a12da7016 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/notaryproject/notation -go 1.17 +go 1.18 require ( github.com/distribution/distribution/v3 v3.0.0-20210804104954-38ab4c606ee3 @@ -22,6 +22,8 @@ require ( github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect - golang.org/x/sys v0.0.0-20210925032602-92d5a993a665 // indirect + golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect gotest.tools/v3 v3.0.3 // indirect ) + +replace github.com/notaryproject/notation-go => github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220427071552-5bfff3353b2c diff --git a/go.sum b/go.sum index 85a156e93..0182afee6 100644 --- a/go.sum +++ b/go.sum @@ -1,7 +1,6 @@ cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= github.com/Azure/azure-sdk-for-go v16.2.1+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= github.com/Azure/go-autorest v10.8.1+incompatible/go.mod h1:r+4oMnoxhatjLLJ6zxSWATqVooLgysK6ZNox3g/xq24= -github.com/BurntSushi/toml v1.1.0/go.mod h1:CxXYINrC8qIiEnFrOxCa7Jy5BFHlXnUU2pbicEuybxQ= github.com/Shopify/logrus-bugsnag v0.0.0-20171204204709-577dee27f20d/go.mod h1:HI8ITrYtUY+O+ZhtlqUnD8+KwNPOyugEhfP9fdUIaEQ= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= @@ -74,8 +73,6 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= -github.com/notaryproject/notation-go v0.7.0-alpha.1.0.20220422005131-96df588f2f6d h1:qIylQ35uMNA2ZSgppopKTAFGJj34UelBJj5iCH2PgTY= -github.com/notaryproject/notation-go v0.7.0-alpha.1.0.20220422005131-96df588f2f6d/go.mod h1:B/JbgikwvLoD9gFeWYhFtxIEozRoFAs9q31mj3vz1i4= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= @@ -99,6 +96,8 @@ github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= +github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220427071552-5bfff3353b2c h1:azRrivHo78Nd3Gy5Z+48QjFwQiCZL8u0pIHFdwWU1ck= +github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220427071552-5bfff3353b2c/go.mod h1:B/JbgikwvLoD9gFeWYhFtxIEozRoFAs9q31mj3vz1i4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= @@ -141,8 +140,8 @@ golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190801041406-cbf593c0f2f3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20191026070338-33540a1f6037/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= -golang.org/x/sys v0.0.0-20210925032602-92d5a993a665 h1:QOQNt6vCjMpXE7JSK5VvAzJC1byuN3FgTNSBwf+CJgI= -golang.org/x/sys v0.0.0-20210925032602-92d5a993a665/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 h1:id054HUawV2/6IGm2IV8KZQjqtwAOo2CYlOToYqa0d0= +golang.org/x/sys v0.0.0-20211019181941-9d821ace8654/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/tools v0.0.0-20190624222133-a101b041ded4/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/internal/cmd/signer.go b/internal/cmd/signer.go index b50b2c6d2..71a429d1f 100644 --- a/internal/cmd/signer.go +++ b/internal/cmd/signer.go @@ -1,6 +1,7 @@ package cmd import ( + "errors" "time" "github.com/notaryproject/notation-go" @@ -18,11 +19,13 @@ func GetSigner(ctx *cli.Context) (notation.Signer, error) { keyPath = path certPath = ctx.String(FlagCertFile.Name) } else { - var err error - keyPath, certPath, err = config.ResolveKeyPath(ctx.String(FlagKey.Name)) + key, err := config.ResolveKey(ctx.String(FlagKey.Name)) if err != nil { return nil, err } + if key.X509KeyPair == nil { + return nil, errors.New("invalid key type") + } } // construct signer diff --git a/internal/ioutil/print.go b/internal/ioutil/print.go new file mode 100644 index 000000000..6bb45540c --- /dev/null +++ b/internal/ioutil/print.go @@ -0,0 +1,54 @@ +package ioutil + +import ( + "fmt" + "io" + "text/tabwriter" + + "github.com/notaryproject/notation-go/plugin" + "github.com/notaryproject/notation/pkg/config" +) + +func newTabWriter(w io.Writer) *tabwriter.Writer { + return tabwriter.NewWriter(w, 0, 0, 3, ' ', 0) +} + +func PrintPlugins(w io.Writer, v []*plugin.Plugin) error { + tw := newTabWriter(w) + fmt.Fprintln(tw, "NAME\tDESCRIPTION\tVERSION\tURL\tSUPPORTED CONTRACTS\tCAPABILITIES\tERROR\tPATH\t") + for _, p := range v { + fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%v\t%v\t%v\t%s\t\n", + p.Name, p.Description, p.Version, p.URL, p.SupportedContractVersions, p.Capabilities, p.Err, p.Path) + } + return tw.Flush() +} + +func PrintKeyMap(w io.Writer, target string, v []config.KeySuite) error { + tw := newTabWriter(w) + fmt.Fprintln(tw, "NAME\tKEY PATH\tCERTIFICATE PATH\tID\tPLUGIN NAME\t") + for _, key := range v { + name := key.Name + if key.Name == target { + name = "* " + name + } + kp := key.X509KeyPair + if kp == nil { + kp = &config.X509KeyPair{} + } + ext := key.ExternalKey + if ext == nil { + ext = &config.ExternalKey{} + } + fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%s\t\n", name, kp.KeyPath, kp.CertificatePath, ext.ID, ext.PluginName) + } + return tw.Flush() +} + +func PrintCertificateMap(w io.Writer, v []config.CertificateReference) error { + tw := newTabWriter(w) + fmt.Fprintln(tw, "NAME\tPATH\t") + for _, cert := range v { + fmt.Fprintf(tw, "%s\t%s\t\n", cert.Name, cert.Path) + } + return tw.Flush() +} diff --git a/internal/slices/slices.go b/internal/slices/slices.go new file mode 100644 index 000000000..1fffa0883 --- /dev/null +++ b/internal/slices/slices.go @@ -0,0 +1,27 @@ +package slices + +type isser interface { + Is(string) bool +} + +// Index returns the index of the first occurrence of name in s, +// or -1 if not present. +func Index[E isser](s []E, name string) int { + for i, v := range s { + if v.Is(name) { + return i + } + } + return -1 +} + +// Contains reports whether name is present in s. +func Contains[E isser](s []E, name string) bool { + return Index(s, name) >= 0 +} + +// Delete removes the elements s[i:i+1] from s, +// returning the modified slice. +func Delete[S ~[]E, E isser](s S, i int) S { + return append(s[:i], s[i+1:]...) +} diff --git a/pkg/config/config.go b/pkg/config/config.go index f8581faff..df07a7daf 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -6,6 +6,38 @@ import ( "path/filepath" ) +type X509KeyPair struct { + KeyPath string `json:"keyPath"` + CertificatePath string `json:"certPath"` +} + +type ExternalKey struct { + ID string `json:"id"` + PluginName string `json:"pluginName"` +} + +// KeySuite is a named key suite. +type KeySuite struct { + Name string `json:"name"` + + *X509KeyPair + *ExternalKey +} + +func (k KeySuite) Is(name string) bool { + return k.Name == name +} + +// CertificateReference is a named file path. +type CertificateReference struct { + Name string `json:"name"` + Path string `json:"path"` +} + +func (c CertificateReference) Is(name string) bool { + return c.Name == name +} + // File reflects the config file. // Specification: https://github.com/notaryproject/notation/pull/76 type File struct { @@ -16,13 +48,13 @@ type File struct { // VerificationCertificates is a collection of public certs used for verification. type VerificationCertificates struct { - Certificates CertificateMap `json:"certs"` + Certificates []CertificateReference `json:"certs"` } // SigningKeys is a collection of signing keys. type SigningKeys struct { - Default string `json:"default"` - Keys KeyMap `json:"keys"` + Default string `json:"default"` + Keys []KeySuite `json:"keys"` } // New creates a new config file diff --git a/pkg/config/map.go b/pkg/config/map.go deleted file mode 100644 index cb269e8fa..000000000 --- a/pkg/config/map.go +++ /dev/null @@ -1,99 +0,0 @@ -package config - -// KeySuite is a named key suite with file paths. -type KeySuite struct { - Name string `json:"name"` - KeyPath string `json:"keyPath"` - CertificatePath string `json:"certPath"` -} - -// KeyMap is a set of KeySuite indexed by name. -// The overall performance is O(n) while the order of entries is persevered. -type KeyMap []KeySuite - -// Append appends a uniquely named KeySuite to the map. -// Return true if new values are appended. -func (m *KeyMap) Append(name, keyPath, certPath string) bool { - for _, ref := range *m { - if ref.Name == name { - return false - } - } - *m = append(*m, KeySuite{ - Name: name, - KeyPath: keyPath, - CertificatePath: certPath, - }) - return true -} - -// Remove removes a named path from the map. -// Return true if an entry is found and removed. -func (m *KeyMap) Remove(name string) bool { - for i, ref := range *m { - if ref.Name == name { - *m = append((*m)[:i], (*m)[i+1:]...) - return true - } - } - return false -} - -// Get return the paths of the given name. -// Return true if found. -func (m KeyMap) Get(name string) (string, string, bool) { - for _, ref := range m { - if ref.Name == name { - return ref.KeyPath, ref.CertificatePath, true - } - } - return "", "", false -} - -// CertificateReference is a named file path. -type CertificateReference struct { - Name string `json:"name"` - Path string `json:"path"` -} - -// CertificateMap is a set of CertificateReference indexed by name. -// The overall performance is O(n) while the order of entries is persevered. -type CertificateMap []CertificateReference - -// Append appends a uniquely named path to the map. -// Return true if new values are appended. -func (m *CertificateMap) Append(name, path string) bool { - for _, ref := range *m { - if ref.Name == name { - return false - } - } - *m = append(*m, CertificateReference{ - Name: name, - Path: path, - }) - return true -} - -// Remove removes a named path from the map. -// Return true if an entry is found and removed. -func (m *CertificateMap) Remove(name string) bool { - for i, ref := range *m { - if ref.Name == name { - *m = append((*m)[:i], (*m)[i+1:]...) - return true - } - } - return false -} - -// Get return the path of the given name. -// Return true if found. -func (m CertificateMap) Get(name string) (string, bool) { - for _, ref := range m { - if ref.Name == name { - return ref.Path, true - } - } - return "", false -} diff --git a/pkg/config/util.go b/pkg/config/util.go index 90961c5fa..4f7b82014 100644 --- a/pkg/config/util.go +++ b/pkg/config/util.go @@ -8,9 +8,6 @@ import ( var ( // ErrKeyNotFound indicates that the signing key is not found. ErrKeyNotFound = errors.New("signing key not found") - - // ErrCertificateNotFound indicates that the verification certificate is not found. - ErrCertificateNotFound = errors.New("verification certificate not found") ) // IsRegistryInsecure checks whether the registry is in the list of insecure registries. @@ -27,33 +24,20 @@ func IsRegistryInsecure(target string) bool { return false } -// ResolveKeyPath resolves the key path by name along with -// its corresponding certificate path. +// ResolveKey resolves the key by name. // The default key is attempted if name is empty. -func ResolveKeyPath(name string) (string, string, error) { +func ResolveKey(name string) (KeySuite, error) { config, err := LoadOrDefaultOnce() if err != nil { - return "", "", err + return KeySuite{}, err } if name == "" { name = config.SigningKeys.Default } - keyPath, certPath, ok := config.SigningKeys.Keys.Get(name) - if !ok { - return "", "", ErrKeyNotFound - } - return keyPath, certPath, nil -} - -// ResolveCertificatePath resolves the certificate path by name. -func ResolveCertificatePath(name string) (string, error) { - config, err := LoadOrDefaultOnce() - if err != nil { - return "", err - } - path, ok := config.VerificationCertificates.Certificates.Get(name) - if !ok { - return "", ErrCertificateNotFound + for _, key := range config.SigningKeys.Keys { + if key.Name == name { + return key, nil + } } - return path, nil + return KeySuite{}, ErrKeyNotFound } From 2ba1fcd129b697d20570cd6d40c2eec21fc52ea3 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Wed, 27 Apr 2022 17:49:14 +0200 Subject: [PATCH 02/14] bump CI to go 1.18 Signed-off-by: qmuntal --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 355ef202e..ba22a020d 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -11,7 +11,7 @@ jobs: runs-on: ubuntu-20.04 strategy: matrix: - go-version: [1.17] + go-version: [1.18] fail-fast: true steps: - name: Set up Go ${{ matrix.go-version }} From 3e3e4d8bb5a57cde1e4ff34a21d3b27e61835c7d Mon Sep 17 00:00:00 2001 From: qmuntal Date: Thu, 28 Apr 2022 09:40:19 +0200 Subject: [PATCH 03/14] upgrade notation-go Signed-off-by: qmuntal --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index a12da7016..ab4e203cd 100644 --- a/go.mod +++ b/go.mod @@ -26,4 +26,4 @@ require ( gotest.tools/v3 v3.0.3 // indirect ) -replace github.com/notaryproject/notation-go => github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220427071552-5bfff3353b2c +replace github.com/notaryproject/notation-go => github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220428073707-e1f2d4924cc0 diff --git a/go.sum b/go.sum index 0182afee6..f71737ddb 100644 --- a/go.sum +++ b/go.sum @@ -96,8 +96,8 @@ github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220427071552-5bfff3353b2c h1:azRrivHo78Nd3Gy5Z+48QjFwQiCZL8u0pIHFdwWU1ck= -github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220427071552-5bfff3353b2c/go.mod h1:B/JbgikwvLoD9gFeWYhFtxIEozRoFAs9q31mj3vz1i4= +github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220428073707-e1f2d4924cc0 h1:vKuDHBWEyYz2mFPAsQGQ91oQhR8p2K3LwRAoRJOIXXg= +github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220428073707-e1f2d4924cc0/go.mod h1:B/JbgikwvLoD9gFeWYhFtxIEozRoFAs9q31mj3vz1i4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= From 411cc3cc51786174c367ca7dd4d4743d25f44136 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Fri, 29 Apr 2022 17:41:01 +0200 Subject: [PATCH 04/14] update plugins branch Signed-off-by: qmuntal --- cmd/notation/key.go | 10 ++++------ cmd/notation/plugin.go | 10 ++++------ go.mod | 2 +- go.sum | 4 ++-- internal/ioutil/print.go | 4 ++-- pkg/signature/jws.go | 41 ++++++++++++++++++++-------------------- 6 files changed, 33 insertions(+), 38 deletions(-) diff --git a/cmd/notation/key.go b/cmd/notation/key.go index 995a520e4..6eb79976c 100644 --- a/cmd/notation/key.go +++ b/cmd/notation/key.go @@ -1,13 +1,14 @@ package main import ( + "context" "crypto/tls" "errors" "fmt" "os" "path/filepath" - "github.com/notaryproject/notation-go/plugin" + "github.com/notaryproject/notation-go/plugin/manager" "github.com/notaryproject/notation/internal/ioutil" "github.com/notaryproject/notation/internal/slices" "github.com/notaryproject/notation/pkg/config" @@ -127,11 +128,8 @@ func addExternalKey(ctx *cli.Context, pluginName string) (*config.KeySuite, erro if id == "" { return nil, errors.New("missing key id") } - mgr, err := plugin.NewManager() - if err != nil { - return nil, err - } - p, err := mgr.Get(pluginName) + mgr := manager.NewManager() + p, err := mgr.Get(context.Background(), pluginName) if err != nil { return nil, err } diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index b03aa676f..ebcc451f2 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -1,9 +1,10 @@ package main import ( + "context" "os" - "github.com/notaryproject/notation-go/plugin" + "github.com/notaryproject/notation-go/plugin/manager" "github.com/notaryproject/notation/internal/ioutil" "github.com/urfave/cli/v2" ) @@ -26,11 +27,8 @@ var ( ) func listPlugins(ctx *cli.Context) error { - mgr, err := plugin.NewManager() - if err != nil { - return err - } - plugins, err := mgr.List() + mgr := manager.NewManager() + plugins, err := mgr.List(context.Background()) if err != nil { return err } diff --git a/go.mod b/go.mod index ab4e203cd..10f24c8d6 100644 --- a/go.mod +++ b/go.mod @@ -26,4 +26,4 @@ require ( gotest.tools/v3 v3.0.3 // indirect ) -replace github.com/notaryproject/notation-go => github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220428073707-e1f2d4924cc0 +replace github.com/notaryproject/notation-go => github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220429152921-f0636e164767 diff --git a/go.sum b/go.sum index f71737ddb..216fa9e52 100644 --- a/go.sum +++ b/go.sum @@ -96,8 +96,8 @@ github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220428073707-e1f2d4924cc0 h1:vKuDHBWEyYz2mFPAsQGQ91oQhR8p2K3LwRAoRJOIXXg= -github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220428073707-e1f2d4924cc0/go.mod h1:B/JbgikwvLoD9gFeWYhFtxIEozRoFAs9q31mj3vz1i4= +github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220429152921-f0636e164767 h1:jgS3O1+FduH9ywKWadFSFcnNIcdbuJmqUV2RFMDCv30= +github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220429152921-f0636e164767/go.mod h1:B/JbgikwvLoD9gFeWYhFtxIEozRoFAs9q31mj3vz1i4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= diff --git a/internal/ioutil/print.go b/internal/ioutil/print.go index 6bb45540c..4318fdee5 100644 --- a/internal/ioutil/print.go +++ b/internal/ioutil/print.go @@ -5,7 +5,7 @@ import ( "io" "text/tabwriter" - "github.com/notaryproject/notation-go/plugin" + "github.com/notaryproject/notation-go/plugin/manager" "github.com/notaryproject/notation/pkg/config" ) @@ -13,7 +13,7 @@ func newTabWriter(w io.Writer) *tabwriter.Writer { return tabwriter.NewWriter(w, 0, 0, 3, ' ', 0) } -func PrintPlugins(w io.Writer, v []*plugin.Plugin) error { +func PrintPlugins(w io.Writer, v []*manager.Plugin) error { tw := newTabWriter(w) fmt.Fprintln(tw, "NAME\tDESCRIPTION\tVERSION\tURL\tSUPPORTED CONTRACTS\tCAPABILITIES\tERROR\tPATH\t") for _, p := range v { diff --git a/pkg/signature/jws.go b/pkg/signature/jws.go index 3db076355..8fb809e3c 100644 --- a/pkg/signature/jws.go +++ b/pkg/signature/jws.go @@ -4,9 +4,9 @@ import ( "crypto/tls" "crypto/x509" "errors" + "fmt" "os" - "github.com/notaryproject/notation-go/crypto/cryptoutil" "github.com/notaryproject/notation-go/signature/jws" ) @@ -20,26 +20,26 @@ func NewSignerFromFiles(keyPath, certPath string) (*jws.Signer, error) { } // read key / cert pair - keyPEM, err := os.ReadFile(keyPath) + cert, err := tls.LoadX509KeyPair(certPath, keyPath) if err != nil { return nil, err } - certPEM, err := os.ReadFile(certPath) - if err != nil { - return nil, err - } - keyPair, err := tls.X509KeyPair(certPEM, keyPEM) - if err != nil { - return nil, err - } - key := keyPair.PrivateKey - method, err := jws.SigningMethodFromKey(key) - if err != nil { - return nil, err + if len(cert.Certificate) == 0 { + return nil, errors.New("missing signer certificate chain") } // parse cert - certs, err := cryptoutil.ParseCertificatePEM(certPEM) + certs := make([]*x509.Certificate, len(cert.Certificate)) + for i, c := range cert.Certificate { + cert, err := x509.ParseCertificate(c) + if err != nil { + return nil, err + } + certs[i] = cert + } + + key := cert.PrivateKey + method, err := jws.SigningMethodFromKey(key) if err != nil { return nil, err } @@ -50,17 +50,16 @@ func NewSignerFromFiles(keyPath, certPath string) (*jws.Signer, error) { // NewSignerFromFiles creates a verifier from certificate files func NewVerifierFromFiles(certPaths []string) (*jws.Verifier, error) { - roots := x509.NewCertPool() + verifier := jws.NewVerifier() + verifier.VerifyOptions.Roots = x509.NewCertPool() for _, path := range certPaths { - bundledCerts, err := cryptoutil.ReadCertificateFile(path) + data, err := os.ReadFile(path) if err != nil { return nil, err } - for _, cert := range bundledCerts { - roots.AddCert(cert) + if !verifier.VerifyOptions.Roots.AppendCertsFromPEM(data) { + return nil, fmt.Errorf("failed to parse PEM certificate: %q", path) } } - verifier := jws.NewVerifier() - verifier.VerifyOptions.Roots = roots return verifier, nil } From db27288474b7b5139bb5345183a2c07d1444753f Mon Sep 17 00:00:00 2001 From: qmuntal Date: Tue, 3 May 2022 08:54:51 +0200 Subject: [PATCH 05/14] reduce plugin print verbosity Signed-off-by: qmuntal --- internal/ioutil/print.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/ioutil/print.go b/internal/ioutil/print.go index 4318fdee5..ec8530a25 100644 --- a/internal/ioutil/print.go +++ b/internal/ioutil/print.go @@ -15,10 +15,10 @@ func newTabWriter(w io.Writer) *tabwriter.Writer { func PrintPlugins(w io.Writer, v []*manager.Plugin) error { tw := newTabWriter(w) - fmt.Fprintln(tw, "NAME\tDESCRIPTION\tVERSION\tURL\tSUPPORTED CONTRACTS\tCAPABILITIES\tERROR\tPATH\t") + fmt.Fprintln(tw, "NAME\tDESCRIPTION\tVERSION\tCAPABILITIES\tERROR\t") for _, p := range v { - fmt.Fprintf(tw, "%s\t%s\t%s\t%s\t%v\t%v\t%v\t%s\t\n", - p.Name, p.Description, p.Version, p.URL, p.SupportedContractVersions, p.Capabilities, p.Err, p.Path) + fmt.Fprintf(tw, "%s\t%s\t%s\t%v\t%v\t\n", + p.Name, p.Description, p.Version, p.Capabilities, p.Err) } return tw.Flush() } From e9c7f8174dbe645ace2da8dfc56fd49b7d6fb841 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Thu, 5 May 2022 09:07:39 +0200 Subject: [PATCH 06/14] bump notation-go Signed-off-by: qmuntal --- go.mod | 6 ++---- go.sum | 8 ++++---- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/go.mod b/go.mod index 10f24c8d6..554a53806 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/distribution/distribution/v3 v3.0.0-20210804104954-38ab4c606ee3 github.com/docker/cli v20.10.14+incompatible - github.com/notaryproject/notation-go v0.7.0-alpha.1.0.20220422005131-96df588f2f6d + github.com/notaryproject/notation-go v0.8.0-alpha.1.0.20220504164459-182873bded16 github.com/opencontainers/go-digest v1.0.0 github.com/opencontainers/image-spec v1.0.2 github.com/oras-project/artifacts-spec v1.0.0-draft.1.1 @@ -17,7 +17,7 @@ require ( github.com/cpuguy83/go-md2man/v2 v2.0.1 // indirect github.com/docker/docker v20.10.8+incompatible // indirect github.com/docker/docker-credential-helpers v0.6.4 // indirect - github.com/golang-jwt/jwt/v4 v4.3.0 // indirect + github.com/golang-jwt/jwt/v4 v4.4.1 // indirect github.com/pkg/errors v0.9.1 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect github.com/sirupsen/logrus v1.8.1 // indirect @@ -25,5 +25,3 @@ require ( golang.org/x/sys v0.0.0-20211019181941-9d821ace8654 // indirect gotest.tools/v3 v3.0.3 // indirect ) - -replace github.com/notaryproject/notation-go => github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220429152921-f0636e164767 diff --git a/go.sum b/go.sum index 216fa9e52..ba8e80660 100644 --- a/go.sum +++ b/go.sum @@ -41,8 +41,8 @@ github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V github.com/go-sql-driver/mysql v1.5.0/go.mod h1:DCzpHaOWr8IXmIStZouvnhqoel9Qv2LBy8hT2VhHyBg= github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= -github.com/golang-jwt/jwt/v4 v4.3.0 h1:kHL1vqdqWNfATmA0FNMdmZNMyZI1U6O31X4rlIPoBog= -github.com/golang-jwt/jwt/v4 v4.3.0/go.mod h1:/xlHOz8bRuivTWchD4jCa+NbatV+wEUSzwAxVc6locg= +github.com/golang-jwt/jwt/v4 v4.4.1 h1:pC5DB52sCeK48Wlb9oPcdhnjkz1TKt1D/P7WKJ0kUcQ= +github.com/golang-jwt/jwt/v4 v4.4.1/go.mod h1:m21LjoU+eqJr34lmDMbreY2eSTRJ1cv77w39/MY0Ch0= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= @@ -73,6 +73,8 @@ github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lN github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/ncw/swift v1.0.47/go.mod h1:23YIA4yWVnGwv2dQlN4bB7egfYX6YLn0Yo/S6zZO/ZM= +github.com/notaryproject/notation-go v0.8.0-alpha.1.0.20220504164459-182873bded16 h1:pcT6WLHGv1iZ7Z/kflT2NJbuNIqLxuDj2qSfjxE5N3M= +github.com/notaryproject/notation-go v0.8.0-alpha.1.0.20220504164459-182873bded16/go.mod h1:KtNtijh22iUsC3y7KTzllwPoDKV7mJANYz/RunvOhqs= github.com/opencontainers/go-digest v1.0.0 h1:apOUWs51W5PlhuyGyz9FCeeBIOUDA/6nW8Oi/yOhh5U= github.com/opencontainers/go-digest v1.0.0/go.mod h1:0JzlMkj0TRzQZfJkVvzbP0HBR3IKzErnv2BNG4W4MAM= github.com/opencontainers/image-spec v1.0.1/go.mod h1:BtxoFyWECRxE4U/7sNtV5W15zMzWCbyJoFRP3s7yZA0= @@ -96,8 +98,6 @@ github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+ github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= github.com/prometheus/procfs v0.0.3/go.mod h1:4A/X28fw3Fc593LaREMrKMqOKvUAntwMDaekg4FpcdQ= -github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220429152921-f0636e164767 h1:jgS3O1+FduH9ywKWadFSFcnNIcdbuJmqUV2RFMDCv30= -github.com/qmuntal/notation-go v0.7.0-alpha.1.0.20220429152921-f0636e164767/go.mod h1:B/JbgikwvLoD9gFeWYhFtxIEozRoFAs9q31mj3vz1i4= github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk= github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM= github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= From d1bb9be0b6b1fa883bcfe850e2b6568bf8b6ae0e Mon Sep 17 00:00:00 2001 From: qmuntal Date: Fri, 6 May 2022 09:00:42 +0200 Subject: [PATCH 07/14] make key and cert name required Signed-off-by: qmuntal --- cmd/notation/cert.go | 19 ++++--------------- cmd/notation/key.go | 36 +++++++++++++++--------------------- 2 files changed, 19 insertions(+), 36 deletions(-) diff --git a/cmd/notation/cert.go b/cmd/notation/cert.go index 0ff235038..1c669d17a 100644 --- a/cmd/notation/cert.go +++ b/cmd/notation/cert.go @@ -62,9 +62,10 @@ var ( ArgsUsage: " ...", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "name", - Aliases: []string{"n"}, - Usage: "key and certificate name", + Name: "name", + Aliases: []string{"n"}, + Usage: "key and certificate name", + Required: true, }, &cli.IntFlag{ Name: "bits", @@ -99,9 +100,6 @@ func addCert(ctx *cli.Context) error { return err } name := ctx.String("name") - if name == "" { - name = nameFromPath(path) - } // check if the target path is a cert if _, err := cryptoutil.ReadCertificateFile(path); err != nil { @@ -180,12 +178,3 @@ func removeCerts(ctx *cli.Context) error { } return nil } - -func nameFromPath(path string) string { - base := filepath.Base(path) - name := base[:len(base)-len(filepath.Ext(base))] - if name == "" { - return base - } - return name -} diff --git a/cmd/notation/key.go b/cmd/notation/key.go index 6eb79976c..2f365f019 100644 --- a/cmd/notation/key.go +++ b/cmd/notation/key.go @@ -39,19 +39,20 @@ var ( ArgsUsage: "[ ]", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "name", - Aliases: []string{"n"}, - Usage: "key name (required if --plugin is set)", - }, - &cli.StringFlag{ - Name: "id", - Usage: "key id (required if --plugin is set)", + Name: "name", + Aliases: []string{"n"}, + Usage: "key name (required)", + Required: true, }, &cli.StringFlag{ Name: "plugin", Aliases: []string{"p"}, Usage: "signing plugin name", }, + &cli.StringFlag{ + Name: "id", + Usage: "key id (required if --plugin is set)", + }, keyDefaultFlag, }, Action: addKey, @@ -91,10 +92,11 @@ func addKey(ctx *cli.Context) error { } var key *config.KeySuite pluginName := ctx.String("plugin") + name := ctx.String("name") if pluginName != "" { - key, err = addExternalKey(ctx, pluginName) + key, err = addExternalKey(ctx, pluginName, name) } else { - key, err = newX509KeyPair(ctx) + key, err = newX509KeyPair(ctx, name) } if err != nil { return err @@ -119,11 +121,7 @@ func addKey(ctx *cli.Context) error { return nil } -func addExternalKey(ctx *cli.Context, pluginName string) (*config.KeySuite, error) { - name := ctx.String("name") - if name == "" { - return nil, errors.New("missing key name") - } +func addExternalKey(ctx *cli.Context, pluginName, keyName string) (*config.KeySuite, error) { id := ctx.String("id") if id == "" { return nil, errors.New("missing key id") @@ -137,12 +135,12 @@ func addExternalKey(ctx *cli.Context, pluginName string) (*config.KeySuite, erro return nil, fmt.Errorf("invalid plugin: %w", p.Err) } return &config.KeySuite{ - Name: name, + Name: keyName, ExternalKey: &config.ExternalKey{ID: id, PluginName: pluginName}, }, nil } -func newX509KeyPair(ctx *cli.Context) (*config.KeySuite, error) { +func newX509KeyPair(ctx *cli.Context, keyName string) (*config.KeySuite, error) { args := ctx.Args() switch args.Len() { case 0: @@ -159,17 +157,13 @@ func newX509KeyPair(ctx *cli.Context) (*config.KeySuite, error) { if err != nil { return nil, err } - name := ctx.String("name") - if name == "" { - name = nameFromPath(keyPath) - } // check key / cert pair if _, err := tls.LoadX509KeyPair(certPath, keyPath); err != nil { return nil, err } return &config.KeySuite{ - Name: name, + Name: keyName, X509KeyPair: &config.X509KeyPair{KeyPath: keyPath, CertificatePath: certPath}, }, nil } From 84b436c4756de6e6e7041e901ce43e30c17037fa Mon Sep 17 00:00:00 2001 From: qmuntal Date: Fri, 6 May 2022 09:36:52 +0200 Subject: [PATCH 08/14] simplify NewSignerFromFiles Signed-off-by: qmuntal --- pkg/signature/jws.go | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/pkg/signature/jws.go b/pkg/signature/jws.go index 8fb809e3c..53368804a 100644 --- a/pkg/signature/jws.go +++ b/pkg/signature/jws.go @@ -24,28 +24,18 @@ func NewSignerFromFiles(keyPath, certPath string) (*jws.Signer, error) { if err != nil { return nil, err } - if len(cert.Certificate) == 0 { - return nil, errors.New("missing signer certificate chain") - } // parse cert certs := make([]*x509.Certificate, len(cert.Certificate)) for i, c := range cert.Certificate { - cert, err := x509.ParseCertificate(c) + certs[i], err = x509.ParseCertificate(c) if err != nil { return nil, err } - certs[i] = cert - } - - key := cert.PrivateKey - method, err := jws.SigningMethodFromKey(key) - if err != nil { - return nil, err } // create signer - return jws.NewSignerWithCertificateChain(method, key, certs) + return jws.NewSigner(cert.PrivateKey, certs) } // NewSignerFromFiles creates a verifier from certificate files From 19b544cccc8118514ae6e835fa5da68b3af09d66 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Mon, 9 May 2022 10:01:58 +0200 Subject: [PATCH 09/14] Apply suggestions from code review Co-authored-by: Shiwei Zhang Signed-off-by: qmuntal --- cmd/notation/plugin.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index ebcc451f2..b2325fd68 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -28,7 +28,7 @@ var ( func listPlugins(ctx *cli.Context) error { mgr := manager.NewManager() - plugins, err := mgr.List(context.Background()) + plugins, err := mgr.List(ctx.Context) if err != nil { return err } From ada97860535ee2cdb8bb5b09a0f43ae669db5688 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Mon, 9 May 2022 10:05:40 +0200 Subject: [PATCH 10/14] pr feedback Signed-off-by: qmuntal --- cmd/notation/cert.go | 7 ++-- cmd/notation/key.go | 28 +++++++-------- internal/slices/slices_test.go | 65 ++++++++++++++++++++++++++++++++++ pkg/config/config.go | 11 +++--- pkg/config/util.go | 11 +++--- 5 files changed, 95 insertions(+), 27 deletions(-) create mode 100644 internal/slices/slices_test.go diff --git a/cmd/notation/cert.go b/cmd/notation/cert.go index 1c669d17a..71d14ecae 100644 --- a/cmd/notation/cert.go +++ b/cmd/notation/cert.go @@ -62,10 +62,9 @@ var ( ArgsUsage: " ...", Flags: []cli.Flag{ &cli.StringFlag{ - Name: "name", - Aliases: []string{"n"}, - Usage: "key and certificate name", - Required: true, + Name: "name", + Aliases: []string{"n"}, + Usage: "key and certificate name", }, &cli.IntFlag{ Name: "bits", diff --git a/cmd/notation/key.go b/cmd/notation/key.go index 2f365f019..d520275d3 100644 --- a/cmd/notation/key.go +++ b/cmd/notation/key.go @@ -90,7 +90,7 @@ func addKey(ctx *cli.Context) error { if err != nil { return err } - var key *config.KeySuite + var key config.KeySuite pluginName := ctx.String("plugin") name := ctx.String("name") if pluginName != "" { @@ -103,7 +103,7 @@ func addKey(ctx *cli.Context) error { } isDefault := ctx.Bool(keyDefaultFlag.Name) - err = addKeyCore(cfg, *key, isDefault) + err = addKeyCore(cfg, key, isDefault) if err != nil { return err } @@ -121,48 +121,48 @@ func addKey(ctx *cli.Context) error { return nil } -func addExternalKey(ctx *cli.Context, pluginName, keyName string) (*config.KeySuite, error) { +func addExternalKey(ctx *cli.Context, pluginName, keyName string) (config.KeySuite, error) { id := ctx.String("id") if id == "" { - return nil, errors.New("missing key id") + return config.KeySuite{}, errors.New("missing key id") } mgr := manager.NewManager() p, err := mgr.Get(context.Background(), pluginName) if err != nil { - return nil, err + return config.KeySuite{}, err } if p.Err != nil { - return nil, fmt.Errorf("invalid plugin: %w", p.Err) + return config.KeySuite{}, fmt.Errorf("invalid plugin: %w", p.Err) } - return &config.KeySuite{ + return config.KeySuite{ Name: keyName, ExternalKey: &config.ExternalKey{ID: id, PluginName: pluginName}, }, nil } -func newX509KeyPair(ctx *cli.Context, keyName string) (*config.KeySuite, error) { +func newX509KeyPair(ctx *cli.Context, keyName string) (config.KeySuite, error) { args := ctx.Args() switch args.Len() { case 0: - return nil, errors.New("missing key and certificate paths") + return config.KeySuite{}, errors.New("missing key and certificate paths") case 1: - return nil, errors.New("missing certificate path for the corresponding key") + return config.KeySuite{}, errors.New("missing certificate path for the corresponding key") } keyPath, err := filepath.Abs(args.Get(0)) if err != nil { - return nil, err + return config.KeySuite{}, err } certPath, err := filepath.Abs(args.Get(1)) if err != nil { - return nil, err + return config.KeySuite{}, err } // check key / cert pair if _, err := tls.LoadX509KeyPair(certPath, keyPath); err != nil { - return nil, err + return config.KeySuite{}, err } - return &config.KeySuite{ + return config.KeySuite{ Name: keyName, X509KeyPair: &config.X509KeyPair{KeyPath: keyPath, CertificatePath: certPath}, }, nil diff --git a/internal/slices/slices_test.go b/internal/slices/slices_test.go new file mode 100644 index 000000000..ae24e6313 --- /dev/null +++ b/internal/slices/slices_test.go @@ -0,0 +1,65 @@ +package slices + +import ( + "reflect" + "testing" +) + +type iss string + +func (i iss) Is(v string) bool { return string(i) == v } + +func TestIndex(t *testing.T) { + tests := []struct { + s []iss + v string + want int + }{ + {nil, "", -1}, + {[]iss{}, "", -1}, + {[]iss{"1", "2", "3"}, "2", 1}, + {[]iss{"1", "2", "2", "3"}, "2", 1}, + {[]iss{"1", "2", "3", "2"}, "2", 1}, + } + for _, tt := range tests { + if got := Index(tt.s, tt.v); got != tt.want { + t.Errorf("Index() = %v, want %v", got, tt.want) + } + } +} + +func TestContains(t *testing.T) { + tests := []struct { + s []iss + v string + want bool + }{ + {nil, "", false}, + {[]iss{}, "", false}, + {[]iss{"1", "2", "3"}, "2", true}, + {[]iss{"1", "2", "2", "3"}, "2", true}, + {[]iss{"1", "2", "3", "2"}, "2", true}, + } + for _, tt := range tests { + if got := Contains(tt.s, tt.v); got != tt.want { + t.Errorf("Index() = %v, want %v", got, tt.want) + } + } +} + +func TestDelete(t *testing.T) { + tests := []struct { + s []iss + i int + want []iss + }{ + {[]iss{"1", "2", "3"}, 1, []iss{"1", "3"}}, + {[]iss{"1", "2", "2", "3"}, 2, []iss{"1", "2", "3"}}, + {[]iss{"1", "2", "3", "2"}, 2, []iss{"1", "2", "2"}}, + } + for _, tt := range tests { + if got := Delete(tt.s, tt.i); !reflect.DeepEqual(got, tt.want) { + t.Errorf("Delete() = %v, want %v", got, tt.want) + } + } +} diff --git a/pkg/config/config.go b/pkg/config/config.go index df07a7daf..459fa7880 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -6,14 +6,17 @@ import ( "path/filepath" ) +// X509KeyPair contains the paths of a public/private key pair files. type X509KeyPair struct { - KeyPath string `json:"keyPath"` - CertificatePath string `json:"certPath"` + KeyPath string `json:"keyPath,omitempty"` + CertificatePath string `json:"certPath,omitempty"` } +// ExternalKey contains the necessary information to delegate +// the signing operation to the named plugin. type ExternalKey struct { - ID string `json:"id"` - PluginName string `json:"pluginName"` + ID string `json:"id,omitempty"` + PluginName string `json:"pluginName,omitempty"` } // KeySuite is a named key suite. diff --git a/pkg/config/util.go b/pkg/config/util.go index 4f7b82014..a1d3484ff 100644 --- a/pkg/config/util.go +++ b/pkg/config/util.go @@ -3,6 +3,8 @@ package config import ( "errors" "strings" + + "github.com/notaryproject/notation/internal/slices" ) var ( @@ -34,10 +36,9 @@ func ResolveKey(name string) (KeySuite, error) { if name == "" { name = config.SigningKeys.Default } - for _, key := range config.SigningKeys.Keys { - if key.Name == name { - return key, nil - } + idx := slices.Index(config.SigningKeys.Keys, name) + if idx < 0 { + return KeySuite{}, ErrKeyNotFound } - return KeySuite{}, ErrKeyNotFound + return config.SigningKeys.Keys[idx], ErrKeyNotFound } From 301a02fb5ccab4a40ba168636f7c2900d70da20a Mon Sep 17 00:00:00 2001 From: qmuntal Date: Fri, 13 May 2022 16:19:17 +0200 Subject: [PATCH 11/14] remove unused package Signed-off-by: qmuntal --- cmd/notation/plugin.go | 1 - 1 file changed, 1 deletion(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index b2325fd68..7416d0d72 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -1,7 +1,6 @@ package main import ( - "context" "os" "github.com/notaryproject/notation-go/plugin/manager" From 74b9c1fc71bd783aa02f7e269470689e122b8daf Mon Sep 17 00:00:00 2001 From: qmuntal Date: Mon, 16 May 2022 15:41:45 +0200 Subject: [PATCH 12/14] missing pr feedback Signed-off-by: qmuntal --- cmd/notation/key.go | 5 ++--- internal/cmd/signer.go | 2 ++ pkg/config/util.go | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/cmd/notation/key.go b/cmd/notation/key.go index d520275d3..0f44c872e 100644 --- a/cmd/notation/key.go +++ b/cmd/notation/key.go @@ -1,7 +1,6 @@ package main import ( - "context" "crypto/tls" "errors" "fmt" @@ -41,7 +40,7 @@ var ( &cli.StringFlag{ Name: "name", Aliases: []string{"n"}, - Usage: "key name (required)", + Usage: "key name", Required: true, }, &cli.StringFlag{ @@ -127,7 +126,7 @@ func addExternalKey(ctx *cli.Context, pluginName, keyName string) (config.KeySui return config.KeySuite{}, errors.New("missing key id") } mgr := manager.NewManager() - p, err := mgr.Get(context.Background(), pluginName) + p, err := mgr.Get(ctx.Context, pluginName) if err != nil { return config.KeySuite{}, err } diff --git a/internal/cmd/signer.go b/internal/cmd/signer.go index 71a429d1f..be315f7f7 100644 --- a/internal/cmd/signer.go +++ b/internal/cmd/signer.go @@ -26,6 +26,8 @@ func GetSigner(ctx *cli.Context) (notation.Signer, error) { if key.X509KeyPair == nil { return nil, errors.New("invalid key type") } + keyPath = key.KeyPath + certPath = key.CertificatePath } // construct signer diff --git a/pkg/config/util.go b/pkg/config/util.go index a1d3484ff..d429ef789 100644 --- a/pkg/config/util.go +++ b/pkg/config/util.go @@ -40,5 +40,5 @@ func ResolveKey(name string) (KeySuite, error) { if idx < 0 { return KeySuite{}, ErrKeyNotFound } - return config.SigningKeys.Keys[idx], ErrKeyNotFound + return config.SigningKeys.Keys[idx], nil } From f79462bce4ffd7a6b5247b1494abe32d6c10a159 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Mon, 16 May 2022 22:44:43 +0200 Subject: [PATCH 13/14] fix plugin aliases Signed-off-by: qmuntal --- cmd/notation/plugin.go | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cmd/notation/plugin.go b/cmd/notation/plugin.go index 7416d0d72..26554448c 100644 --- a/cmd/notation/plugin.go +++ b/cmd/notation/plugin.go @@ -10,18 +10,18 @@ import ( var ( pluginCommand = &cli.Command{ - Name: "plugin", - Aliases: []string{"ls"}, - Usage: "Manage plugins", + Name: "plugin", + Usage: "Manage plugins", Subcommands: []*cli.Command{ pluginListCommand, }, } pluginListCommand = &cli.Command{ - Name: "list", - Usage: "List registered plugins", - Action: listPlugins, + Name: "list", + Usage: "List registered plugins", + Aliases: []string{"ls"}, + Action: listPlugins, } ) From 47bffd42b49457f5c0c715e16a3bcf25baabee04 Mon Sep 17 00:00:00 2001 From: qmuntal Date: Tue, 17 May 2022 10:10:48 +0200 Subject: [PATCH 14/14] return printkey errors Signed-off-by: qmuntal --- cmd/notation/cert.go | 3 +-- cmd/notation/key.go | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/cmd/notation/cert.go b/cmd/notation/cert.go index 71d14ecae..0de44a6c0 100644 --- a/cmd/notation/cert.go +++ b/cmd/notation/cert.go @@ -141,8 +141,7 @@ func listCerts(ctx *cli.Context) error { } // write out - ioutil.PrintCertificateMap(os.Stdout, cfg.VerificationCertificates.Certificates) - return nil + return ioutil.PrintCertificateMap(os.Stdout, cfg.VerificationCertificates.Certificates) } func removeCerts(ctx *cli.Context) error { diff --git a/cmd/notation/key.go b/cmd/notation/key.go index 0f44c872e..5cbfe3eaf 100644 --- a/cmd/notation/key.go +++ b/cmd/notation/key.go @@ -216,8 +216,7 @@ func listKeys(ctx *cli.Context) error { } // write out - ioutil.PrintKeyMap(os.Stdout, cfg.SigningKeys.Default, cfg.SigningKeys.Keys) - return nil + return ioutil.PrintKeyMap(os.Stdout, cfg.SigningKeys.Default, cfg.SigningKeys.Keys) } func removeKeys(ctx *cli.Context) error {