From 28e9de28a4ef46090ad13152873747951a984bff Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Thu, 22 Jul 2021 22:27:52 +0200 Subject: [PATCH 01/52] Add 'eak add' command to beta ca --- command/ca/ca.go | 2 ++ command/ca/eak/add.go | 81 ++++++++++++++++++++++++++++++++++++++++++ command/ca/eak/eak.go | 49 +++++++++++++++++++++++++ command/ca/eak/list.go | 39 ++++++++++++++++++++ 4 files changed, 171 insertions(+) create mode 100644 command/ca/eak/add.go create mode 100644 command/ca/eak/eak.go create mode 100644 command/ca/eak/list.go diff --git a/command/ca/ca.go b/command/ca/ca.go index 0ee5ef22..14a08535 100644 --- a/command/ca/ca.go +++ b/command/ca/ca.go @@ -7,6 +7,7 @@ import ( "github.com/pkg/errors" "github.com/smallstep/cli/command" "github.com/smallstep/cli/command/ca/admin" + "github.com/smallstep/cli/command/ca/eak" "github.com/smallstep/cli/command/ca/provisioner" "github.com/smallstep/cli/command/ca/provisionerbeta" "github.com/urfave/cli" @@ -206,6 +207,7 @@ commands may change, disappear, or be promoted to a different subcommand in the Subcommands: cli.Commands{ admin.Command(), provisionerbeta.Command(), + eak.Command(), }, } } diff --git a/command/ca/eak/add.go b/command/ca/eak/add.go new file mode 100644 index 00000000..635eebe2 --- /dev/null +++ b/command/ca/eak/add.go @@ -0,0 +1,81 @@ +package eak + +import ( + "fmt" + "os" + "text/tabwriter" + + adminAPI "github.com/smallstep/certificates/authority/admin/api" + "github.com/smallstep/cli/errs" + "github.com/smallstep/cli/flags" + "github.com/smallstep/cli/utils/cautils" + "github.com/urfave/cli" +) + +func addCommand() cli.Command { + return cli.Command{ + Name: "add", + Action: cli.ActionFunc(addAction), + Usage: "add ACME External Account Key material", + UsageText: `**step beta ca eak add** `, + Flags: []cli.Flag{ + flags.AdminCert, + flags.AdminKey, + flags.AdminProvisioner, + flags.AdminSubject, + flags.PasswordFile, + flags.CaURL, + flags.Root, + }, + Description: `**step beta ca eak add** adds ACME External Account Key. + +## POSITIONAL ARGUMENTS + +## EXAMPLES + +Add an ACME External Account Key: +''' +$ step beta ca eak add some_name_or_reference +''' + +`, + } +} + +func addAction(ctx *cli.Context) (err error) { + if err := errs.NumberOfArguments(ctx, 1); err != nil { + return err + } + + args := ctx.Args() + name := args.Get(0) + + fmt.Println(name) + + client, err := cautils.NewAdminClient(ctx) + if err != nil { + return err + } + + eak, err := client.CreateExternalAccountKey(&adminAPI.CreateExternalAccountKeyRequest{ + Name: name, + }) + if err != nil { + return err + } + + cliEAK, err := toCLI(ctx, client, eak) + if err != nil { + return err + } + + w := new(tabwriter.Writer) + // Format in tab-separated columns with a tab stop of 8. + w.Init(os.Stdout, 0, 8, 1, '\t', 0) + + fmt.Fprintln(w, "Key ID\tName\tKey (base64, std)") + fmt.Fprintf(w, "%s\t%s \t%s\n", cliEAK.id, cliEAK.name, cliEAK.key) + w.Flush() + + return nil +} diff --git a/command/ca/eak/eak.go b/command/ca/eak/eak.go new file mode 100644 index 00000000..aa90e48e --- /dev/null +++ b/command/ca/eak/eak.go @@ -0,0 +1,49 @@ +package eak + +import ( + "encoding/base64" + + adminAPI "github.com/smallstep/certificates/authority/admin/api" + "github.com/smallstep/certificates/ca" + "github.com/urfave/cli" +) + +type cliEAK struct { + id string + name string + key string +} + +func toCLI(ctx *cli.Context, client *ca.AdminClient, eak *adminAPI.CreateExternalAccountKeyResponse) (*cliEAK, error) { + // TODO: more fields for other purposes, like including the createdat/boundat/account for listing? + return &cliEAK{id: eak.KeyID, name: eak.Name, key: base64.StdEncoding.EncodeToString(eak.Key)}, nil +} + +// Command returns the jwk subcommand. +func Command() cli.Command { + return cli.Command{ + Name: "eak", + Usage: "create and manage ACME External Account Key material", + UsageText: "**step beta ca eak** [arguments] [global-flags] [subcommand-flags]", + Subcommands: cli.Commands{ + listCommand(), + addCommand(), + // removeCommand(), + // updateCommand(), + }, + Description: `**step beta ca eak** command group provides facilities for managing ACME + External Account Keys. + +## EXAMPLES + +List the active ACME External Account Keys: +''' +$ step beta ca eak list +''' + +Add an ACME External Account Key: +''' +$ step beta ca eak add some_name_or_reference +'''`, + } +} diff --git a/command/ca/eak/list.go b/command/ca/eak/list.go new file mode 100644 index 00000000..b6f79f7d --- /dev/null +++ b/command/ca/eak/list.go @@ -0,0 +1,39 @@ +package eak + +import ( + "github.com/smallstep/cli/errs" + "github.com/smallstep/cli/flags" + "github.com/urfave/cli" +) + +func listCommand() cli.Command { + return cli.Command{ + Name: "list", + Action: cli.ActionFunc(listAction), + Usage: "list all ACME External Account Keys", + UsageText: `**step beta ca eak list** [**--ca-url**=] [**--root**=]`, + Flags: []cli.Flag{ + flags.CaURL, + flags.Root, + }, + Description: `**step beta ca eak list** lists all ACME External Account Keys. + +## EXAMPLES + +List all ACME External Account Keys: +''' +$ step beta ca eak list +''' +`, + } +} + +func listAction(ctx *cli.Context) (err error) { + if err := errs.NumberOfArguments(ctx, 0); err != nil { + return err + } + + // TODO: implementation for listing keys + + return nil +} From 93942b2a60bd7870081853d8e83784ca936e8e1c Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Fri, 23 Jul 2021 13:04:12 +0200 Subject: [PATCH 02/52] Move eab command under (new) acme command --- command/ca/acme/acme.go | 19 +++++++++++++++++ command/ca/{eak => acme/eab}/add.go | 21 +++++++++++-------- command/ca/{eak/eak.go => acme/eab/eab.go} | 24 ++++++++++------------ command/ca/{eak => acme/eab}/list.go | 12 +++++------ command/ca/ca.go | 4 ++-- 5 files changed, 50 insertions(+), 30 deletions(-) create mode 100644 command/ca/acme/acme.go rename command/ca/{eak => acme/eab}/add.go (73%) rename command/ca/{eak/eak.go => acme/eab/eab.go} (56%) rename command/ca/{eak => acme/eab}/list.go (59%) diff --git a/command/ca/acme/acme.go b/command/ca/acme/acme.go new file mode 100644 index 00000000..29a71f16 --- /dev/null +++ b/command/ca/acme/acme.go @@ -0,0 +1,19 @@ +package acme + +import ( + "github.com/smallstep/cli/command/ca/acme/eab" + "github.com/urfave/cli" +) + +// Command returns the acme subcommand. +func Command() cli.Command { + return cli.Command{ + Name: "acme", + Usage: "manage ACME EAB", + UsageText: "**step beta ca acme** [arguments] [global-flags] [subcommand-flags]", + Description: `**step beta ca acme** command group provides facilities for managing ACME EAB.`, + Subcommands: cli.Commands{ + eab.Command(), + }, + } +} diff --git a/command/ca/eak/add.go b/command/ca/acme/eab/add.go similarity index 73% rename from command/ca/eak/add.go rename to command/ca/acme/eab/add.go index 635eebe2..18155cca 100644 --- a/command/ca/eak/add.go +++ b/command/ca/acme/eab/add.go @@ -1,4 +1,4 @@ -package eak +package eab import ( "fmt" @@ -16,8 +16,8 @@ func addCommand() cli.Command { return cli.Command{ Name: "add", Action: cli.ActionFunc(addAction), - Usage: "add ACME External Account Key material", - UsageText: `**step beta ca eak add** `, + Usage: "add ACME External Account Binding Key", + UsageText: `**step beta ca acme eab add** `, Flags: []cli.Flag{ flags.AdminCert, flags.AdminKey, @@ -27,18 +27,19 @@ func addCommand() cli.Command { flags.CaURL, flags.Root, }, - Description: `**step beta ca eak add** adds ACME External Account Key. + Description: `**step beta ca acme eab add** adds ACME External Account Binding Key. ## POSITIONAL ARGUMENTS + +: Name or (external) reference for the key to be created + ## EXAMPLES -Add an ACME External Account Key: +Add an ACME External Account Binding Key: ''' -$ step beta ca eak add some_name_or_reference -''' - -`, +$ step beta ca acme eab add my_first_eab_key +'''`, } } @@ -69,6 +70,8 @@ func addAction(ctx *cli.Context) (err error) { return err } + // TODO: JSON output, so that executing this command can be more easily automated? + w := new(tabwriter.Writer) // Format in tab-separated columns with a tab stop of 8. w.Init(os.Stdout, 0, 8, 1, '\t', 0) diff --git a/command/ca/eak/eak.go b/command/ca/acme/eab/eab.go similarity index 56% rename from command/ca/eak/eak.go rename to command/ca/acme/eab/eab.go index aa90e48e..57d08070 100644 --- a/command/ca/eak/eak.go +++ b/command/ca/acme/eab/eab.go @@ -1,4 +1,4 @@ -package eak +package eab import ( "encoding/base64" @@ -19,31 +19,29 @@ func toCLI(ctx *cli.Context, client *ca.AdminClient, eak *adminAPI.CreateExterna return &cliEAK{id: eak.KeyID, name: eak.Name, key: base64.StdEncoding.EncodeToString(eak.Key)}, nil } -// Command returns the jwk subcommand. +// Command returns the eab subcommand. func Command() cli.Command { return cli.Command{ - Name: "eak", - Usage: "create and manage ACME External Account Key material", - UsageText: "**step beta ca eak** [arguments] [global-flags] [subcommand-flags]", + Name: "eab", + Usage: "create and manage ACME External Account Binding Keys", + UsageText: "**step beta ca acme eab** [arguments] [global-flags] [subcommand-flags]", Subcommands: cli.Commands{ listCommand(), addCommand(), - // removeCommand(), - // updateCommand(), }, - Description: `**step beta ca eak** command group provides facilities for managing ACME - External Account Keys. + Description: `**step beta ca acme eab** command group provides facilities for managing ACME + External Account Binding Keys. ## EXAMPLES -List the active ACME External Account Keys: +List the active ACME External Account Binding Keys: ''' -$ step beta ca eak list +$ step beta ca acme eab list ''' -Add an ACME External Account Key: +Add an ACME External Account Binding Key: ''' -$ step beta ca eak add some_name_or_reference +$ step beta ca acme eab add some_name_or_reference '''`, } } diff --git a/command/ca/eak/list.go b/command/ca/acme/eab/list.go similarity index 59% rename from command/ca/eak/list.go rename to command/ca/acme/eab/list.go index b6f79f7d..4024700a 100644 --- a/command/ca/eak/list.go +++ b/command/ca/acme/eab/list.go @@ -1,4 +1,4 @@ -package eak +package eab import ( "github.com/smallstep/cli/errs" @@ -10,19 +10,19 @@ func listCommand() cli.Command { return cli.Command{ Name: "list", Action: cli.ActionFunc(listAction), - Usage: "list all ACME External Account Keys", - UsageText: `**step beta ca eak list** [**--ca-url**=] [**--root**=]`, + Usage: "list all ACME External Account Binding Keys", + UsageText: `**step beta ca acme eab list** [**--ca-url**=] [**--root**=]`, Flags: []cli.Flag{ flags.CaURL, flags.Root, }, - Description: `**step beta ca eak list** lists all ACME External Account Keys. + Description: `**step beta ca acme eab list** lists all ACME External Account Binding Keys. ## EXAMPLES -List all ACME External Account Keys: +List all ACME External Account Binding Keys: ''' -$ step beta ca eak list +$ step beta ca acme eab list ''' `, } diff --git a/command/ca/ca.go b/command/ca/ca.go index 14a08535..2f45ee7a 100644 --- a/command/ca/ca.go +++ b/command/ca/ca.go @@ -6,8 +6,8 @@ import ( "github.com/pkg/errors" "github.com/smallstep/cli/command" + "github.com/smallstep/cli/command/ca/acme" "github.com/smallstep/cli/command/ca/admin" - "github.com/smallstep/cli/command/ca/eak" "github.com/smallstep/cli/command/ca/provisioner" "github.com/smallstep/cli/command/ca/provisionerbeta" "github.com/urfave/cli" @@ -207,7 +207,7 @@ commands may change, disappear, or be promoted to a different subcommand in the Subcommands: cli.Commands{ admin.Command(), provisionerbeta.Command(), - eak.Command(), + acme.Command(), }, } } From 6241e20e0e7aaf917d201b09b9a0e006ac8d8124 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Fri, 23 Jul 2021 14:17:00 +0200 Subject: [PATCH 03/52] Fix command description --- command/ca/acme/eab/add.go | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/command/ca/acme/eab/add.go b/command/ca/acme/eab/add.go index 18155cca..9f905346 100644 --- a/command/ca/acme/eab/add.go +++ b/command/ca/acme/eab/add.go @@ -17,7 +17,7 @@ func addCommand() cli.Command { Name: "add", Action: cli.ActionFunc(addAction), Usage: "add ACME External Account Binding Key", - UsageText: `**step beta ca acme eab add** `, + UsageText: `**step beta ca acme eab add** [**--ca-url**=] [**--root**=]`, Flags: []cli.Flag{ flags.AdminCert, flags.AdminKey, @@ -51,8 +51,6 @@ func addAction(ctx *cli.Context) (err error) { args := ctx.Args() name := args.Get(0) - fmt.Println(name) - client, err := cautils.NewAdminClient(ctx) if err != nil { return err From 22fa7b340cea95c987c0d7bb973b4b5ca911e493 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Sat, 7 Aug 2021 01:31:54 +0200 Subject: [PATCH 04/52] Add flags for requiring and disabling EAB for ACME provisioners --- command/ca/provisionerbeta/add.go | 11 +++++++++-- command/ca/provisionerbeta/provisioner.go | 8 ++++++++ command/ca/provisionerbeta/update.go | 20 +++++++++++++++++--- 3 files changed, 34 insertions(+), 5 deletions(-) diff --git a/command/ca/provisionerbeta/add.go b/command/ca/provisionerbeta/add.go index b01f64b8..9be10b68 100644 --- a/command/ca/provisionerbeta/add.go +++ b/command/ca/provisionerbeta/add.go @@ -56,7 +56,7 @@ func addCommand() cli.Command { [**--disable-custom-sans**] [**--disable-trust-on-first-use**] [**--ca-url**=] [**--root**=] -**step beta ca provisioner add** **--type**=ACME [**--force-cn**] +**step beta ca provisioner add** **--type**=ACME [**--force-cn**] [**--require-eab**] [**--ca-url**=] [**--root**=]`, Flags: []cli.Flag{ cli.StringFlag{ @@ -166,6 +166,7 @@ provisioning tokens.`, // ACME provisioner flags forceCNFlag, + requireEABFlag, // Cloud provisioner flags awsAccountFlag, @@ -228,6 +229,11 @@ Create an ACME provisioner: step beta ca provisioner add acme --type ACME ''' +Create an ACME provisioner, forcing a CN and requiring EAB: +''' +step beta ca provisioner add acme --type ACME --force-cn --require-eab +''' + Create an K8SSA provisioner: ''' step beta ca provisioner add kube --type K8SSA --ssh --public-key key.pub @@ -518,7 +524,8 @@ func createACMEDetails(ctx *cli.Context) (*linkedca.ProvisionerDetails, error) { return &linkedca.ProvisionerDetails{ Data: &linkedca.ProvisionerDetails_ACME{ ACME: &linkedca.ACMEProvisioner{ - ForceCn: ctx.Bool("force-cn"), + ForceCn: ctx.Bool("force-cn"), + RequireEab: ctx.Bool("require-eab"), }, }, }, nil diff --git a/command/ca/provisionerbeta/provisioner.go b/command/ca/provisionerbeta/provisioner.go index bb6b98a4..c7fb7b92 100644 --- a/command/ca/provisionerbeta/provisioner.go +++ b/command/ca/provisionerbeta/provisioner.go @@ -169,6 +169,14 @@ var ( Name: "force-cn", Usage: `Always set the common name in provisioned certificates.`, } + requireEABFlag = cli.BoolFlag{ + Name: "require-eab", + Usage: `Require (and enable) External Account Binding for Account creation.`, + } + disableEABFlag = cli.BoolFlag{ + Name: "disable-eab", + Usage: `Disable External Account Binding for Account creation.`, + } // Cloud provisioner flags awsAccountFlag = cli.StringSliceFlag{ diff --git a/command/ca/provisionerbeta/update.go b/command/ca/provisionerbeta/update.go index 7373ea9a..dfeedce6 100644 --- a/command/ca/provisionerbeta/update.go +++ b/command/ca/provisionerbeta/update.go @@ -37,7 +37,7 @@ func updateCommand() cli.Command { ACME -**step beta ca provisioner update** [**--force-cn**] +**step beta ca provisioner update** [**--force-cn**] [**--require-eab**] [**--disable-eab**] [**--ca-url**=] [**--root**=] OIDC @@ -151,8 +151,11 @@ Use the '--group' flag multiple times to configure multiple groups.`, Usage: `Root certificate (chain) used to validate the signature on X5C provisioning tokens.`, }, + // ACME provisioner flags forceCNFlag, + requireEABFlag, + disableEABFlag, // Cloud provisioner flags awsAccountFlag, @@ -219,7 +222,7 @@ step beta ca provisioner update x5c --x5c-root x5c_ca.crt Update an ACME provisioner: ''' -step beta ca provisioner update acme --force-cn +step beta ca provisioner update acme --force-cn --require-eab --disable-eab ''' Update an K8SSA provisioner: @@ -441,7 +444,7 @@ func updateClaims(ctx *cli.Context, p *linkedca.Provisioner) { func updateJWKDetails(ctx *cli.Context, p *linkedca.Provisioner) error { data, ok := p.Details.GetData().(*linkedca.ProvisionerDetails_JWK) if !ok { - return errors.New("error casting details to ACME type") + return errors.New("error casting details to JWK type") } details := data.JWK @@ -561,6 +564,17 @@ func updateACMEDetails(ctx *cli.Context, p *linkedca.Provisioner) error { if ctx.IsSet("force-cn") { details.ForceCn = ctx.Bool("force-cn") } + requireEABSet := ctx.IsSet("require-eab") + disableEABSet := ctx.IsSet("disable-eab") + if requireEABSet && disableEABSet { + return errors.New("cannot provide both --require-eab and --disable-eab") + } + if requireEABSet { + details.RequireEab = ctx.Bool("require-eab") + } + if disableEABSet { + details.RequireEab = false + } return nil } From 233dbcc366d8c39db4fc2809c1686abb61ea1a5b Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Sat, 7 Aug 2021 02:08:43 +0200 Subject: [PATCH 05/52] Make EAB keys link to a specific ACME provisioner --- command/ca/acme/eab/add.go | 16 +++++++++------- command/ca/acme/eab/eab.go | 11 ++++++----- command/ca/acme/eab/list.go | 20 +++++++++++++++++++- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/command/ca/acme/eab/add.go b/command/ca/acme/eab/add.go index 9f905346..583efe75 100644 --- a/command/ca/acme/eab/add.go +++ b/command/ca/acme/eab/add.go @@ -17,7 +17,7 @@ func addCommand() cli.Command { Name: "add", Action: cli.ActionFunc(addAction), Usage: "add ACME External Account Binding Key", - UsageText: `**step beta ca acme eab add** [**--ca-url**=] [**--root**=]`, + UsageText: `**step beta ca acme eab add** [**--ca-url**=] [**--root**=]`, Flags: []cli.Flag{ flags.AdminCert, flags.AdminKey, @@ -38,18 +38,19 @@ func addCommand() cli.Command { Add an ACME External Account Binding Key: ''' -$ step beta ca acme eab add my_first_eab_key +$ step beta ca acme eab add my_acme_provisioner my_first_eab_key '''`, } } func addAction(ctx *cli.Context) (err error) { - if err := errs.NumberOfArguments(ctx, 1); err != nil { + if err := errs.NumberOfArguments(ctx, 2); err != nil { return err } args := ctx.Args() - name := args.Get(0) + provisionerName := args.Get(0) + credentialName := args.Get(1) client, err := cautils.NewAdminClient(ctx) if err != nil { @@ -57,7 +58,8 @@ func addAction(ctx *cli.Context) (err error) { } eak, err := client.CreateExternalAccountKey(&adminAPI.CreateExternalAccountKeyRequest{ - Name: name, + ProvisionerName: provisionerName, + Name: credentialName, }) if err != nil { return err @@ -74,8 +76,8 @@ func addAction(ctx *cli.Context) (err error) { // Format in tab-separated columns with a tab stop of 8. w.Init(os.Stdout, 0, 8, 1, '\t', 0) - fmt.Fprintln(w, "Key ID\tName\tKey (base64, std)") - fmt.Fprintf(w, "%s\t%s \t%s\n", cliEAK.id, cliEAK.name, cliEAK.key) + fmt.Fprintln(w, "Key ID\tProvisioner\tName\tKey (base64, std)") + fmt.Fprintf(w, "%s\t%s \t %s \t%s\n", cliEAK.id, cliEAK.provisioner, cliEAK.name, cliEAK.key) w.Flush() return nil diff --git a/command/ca/acme/eab/eab.go b/command/ca/acme/eab/eab.go index 57d08070..571cd96b 100644 --- a/command/ca/acme/eab/eab.go +++ b/command/ca/acme/eab/eab.go @@ -9,14 +9,15 @@ import ( ) type cliEAK struct { - id string - name string - key string + id string + provisioner string + name string + key string } func toCLI(ctx *cli.Context, client *ca.AdminClient, eak *adminAPI.CreateExternalAccountKeyResponse) (*cliEAK, error) { // TODO: more fields for other purposes, like including the createdat/boundat/account for listing? - return &cliEAK{id: eak.KeyID, name: eak.Name, key: base64.StdEncoding.EncodeToString(eak.Key)}, nil + return &cliEAK{id: eak.KeyID, provisioner: eak.ProvisionerName, name: eak.Name, key: base64.StdEncoding.EncodeToString(eak.Key)}, nil } // Command returns the eab subcommand. @@ -41,7 +42,7 @@ $ step beta ca acme eab list Add an ACME External Account Binding Key: ''' -$ step beta ca acme eab add some_name_or_reference +$ step beta ca acme eab add provisioner_name some_name_or_reference '''`, } } diff --git a/command/ca/acme/eab/list.go b/command/ca/acme/eab/list.go index 4024700a..ae56724e 100644 --- a/command/ca/acme/eab/list.go +++ b/command/ca/acme/eab/list.go @@ -1,8 +1,11 @@ package eab import ( + "fmt" + "github.com/smallstep/cli/errs" "github.com/smallstep/cli/flags" + "github.com/smallstep/cli/utils/cautils" "github.com/urfave/cli" ) @@ -13,6 +16,11 @@ func listCommand() cli.Command { Usage: "list all ACME External Account Binding Keys", UsageText: `**step beta ca acme eab list** [**--ca-url**=] [**--root**=]`, Flags: []cli.Flag{ + flags.AdminCert, + flags.AdminKey, + flags.AdminProvisioner, + flags.AdminSubject, + flags.PasswordFile, flags.CaURL, flags.Root, }, @@ -33,7 +41,17 @@ func listAction(ctx *cli.Context) (err error) { return err } - // TODO: implementation for listing keys + client, err := cautils.NewAdminClient(ctx) + if err != nil { + return err + } + + eaks, err := client.GetExternalAccountKeys() + if err != nil { + return err + } + + fmt.Println(eaks) return nil } From 31452a49b469bc085bb23b6d3a9b8bc3e2b7b308 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Mon, 9 Aug 2021 10:39:56 +0200 Subject: [PATCH 06/52] Change base64 encoding to raw URL encoding for EAB keys --- command/ca/acme/eab/add.go | 2 +- command/ca/acme/eab/eab.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/command/ca/acme/eab/add.go b/command/ca/acme/eab/add.go index 583efe75..c5263e07 100644 --- a/command/ca/acme/eab/add.go +++ b/command/ca/acme/eab/add.go @@ -76,7 +76,7 @@ func addAction(ctx *cli.Context) (err error) { // Format in tab-separated columns with a tab stop of 8. w.Init(os.Stdout, 0, 8, 1, '\t', 0) - fmt.Fprintln(w, "Key ID\tProvisioner\tName\tKey (base64, std)") + fmt.Fprintln(w, "Key ID\tProvisioner\tName\tKey (base64, raw url encoded)") fmt.Fprintf(w, "%s\t%s \t %s \t%s\n", cliEAK.id, cliEAK.provisioner, cliEAK.name, cliEAK.key) w.Flush() diff --git a/command/ca/acme/eab/eab.go b/command/ca/acme/eab/eab.go index 571cd96b..7bcbd40d 100644 --- a/command/ca/acme/eab/eab.go +++ b/command/ca/acme/eab/eab.go @@ -17,7 +17,7 @@ type cliEAK struct { func toCLI(ctx *cli.Context, client *ca.AdminClient, eak *adminAPI.CreateExternalAccountKeyResponse) (*cliEAK, error) { // TODO: more fields for other purposes, like including the createdat/boundat/account for listing? - return &cliEAK{id: eak.KeyID, provisioner: eak.ProvisionerName, name: eak.Name, key: base64.StdEncoding.EncodeToString(eak.Key)}, nil + return &cliEAK{id: eak.KeyID, provisioner: eak.ProvisionerName, name: eak.Name, key: base64.RawURLEncoding.Strict().EncodeToString(eak.Key)}, nil } // Command returns the eab subcommand. From 570dbda23bd733a244b383328c54b55ada596501 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Fri, 27 Aug 2021 12:50:52 +0200 Subject: [PATCH 07/52] Use LinkedCA.EABKey type --- command/ca/acme/eab/add.go | 2 +- command/ca/acme/eab/eab.go | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/command/ca/acme/eab/add.go b/command/ca/acme/eab/add.go index c5263e07..9bdf9b80 100644 --- a/command/ca/acme/eab/add.go +++ b/command/ca/acme/eab/add.go @@ -77,7 +77,7 @@ func addAction(ctx *cli.Context) (err error) { w.Init(os.Stdout, 0, 8, 1, '\t', 0) fmt.Fprintln(w, "Key ID\tProvisioner\tName\tKey (base64, raw url encoded)") - fmt.Fprintf(w, "%s\t%s \t %s \t%s\n", cliEAK.id, cliEAK.provisioner, cliEAK.name, cliEAK.key) + fmt.Fprintf(w, "%s\t%s \t%s \t%s\n", cliEAK.id, cliEAK.provisioner, cliEAK.name, cliEAK.key) w.Flush() return nil diff --git a/command/ca/acme/eab/eab.go b/command/ca/acme/eab/eab.go index 7bcbd40d..a11ce34d 100644 --- a/command/ca/acme/eab/eab.go +++ b/command/ca/acme/eab/eab.go @@ -3,9 +3,9 @@ package eab import ( "encoding/base64" - adminAPI "github.com/smallstep/certificates/authority/admin/api" "github.com/smallstep/certificates/ca" "github.com/urfave/cli" + "go.step.sm/linkedca" ) type cliEAK struct { @@ -15,9 +15,9 @@ type cliEAK struct { key string } -func toCLI(ctx *cli.Context, client *ca.AdminClient, eak *adminAPI.CreateExternalAccountKeyResponse) (*cliEAK, error) { +func toCLI(ctx *cli.Context, client *ca.AdminClient, eak *linkedca.EABKey) (*cliEAK, error) { // TODO: more fields for other purposes, like including the createdat/boundat/account for listing? - return &cliEAK{id: eak.KeyID, provisioner: eak.ProvisionerName, name: eak.Name, key: base64.RawURLEncoding.Strict().EncodeToString(eak.Key)}, nil + return &cliEAK{id: eak.EabKid, provisioner: eak.ProvisionerName, name: eak.Name, key: base64.RawURLEncoding.Strict().EncodeToString(eak.EabHmacKey)}, nil } // Command returns the eab subcommand. From a06a9030a664fa459acf30a0b69194d44b728f33 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Fri, 27 Aug 2021 14:48:23 +0200 Subject: [PATCH 08/52] Add command to remove ACME EAB keys --- command/ca/acme/eab/eab.go | 9 ++++- command/ca/acme/eab/remove.go | 65 +++++++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 command/ca/acme/eab/remove.go diff --git a/command/ca/acme/eab/eab.go b/command/ca/acme/eab/eab.go index a11ce34d..51128852 100644 --- a/command/ca/acme/eab/eab.go +++ b/command/ca/acme/eab/eab.go @@ -29,6 +29,7 @@ func Command() cli.Command { Subcommands: cli.Commands{ listCommand(), addCommand(), + removeCommand(), }, Description: `**step beta ca acme eab** command group provides facilities for managing ACME External Account Binding Keys. @@ -43,6 +44,12 @@ $ step beta ca acme eab list Add an ACME External Account Binding Key: ''' $ step beta ca acme eab add provisioner_name some_name_or_reference -'''`, +''' + +Remove an ACME External Account Binding Key: +''' +$ step beta ca acme eab remove key_id +''' +`, } } diff --git a/command/ca/acme/eab/remove.go b/command/ca/acme/eab/remove.go new file mode 100644 index 00000000..3eff323d --- /dev/null +++ b/command/ca/acme/eab/remove.go @@ -0,0 +1,65 @@ +package eab + +import ( + "github.com/smallstep/cli/errs" + "github.com/smallstep/cli/flags" + "github.com/smallstep/cli/ui" + "github.com/smallstep/cli/utils/cautils" + "github.com/urfave/cli" +) + +func removeCommand() cli.Command { + return cli.Command{ + Name: "remove", + Action: cli.ActionFunc(removeAction), + Usage: "remove an ACME EAB Key from the CA", + UsageText: `**step beta ca acme eab remove** [**--ca-url**=] +[**--root**=]`, + Flags: []cli.Flag{ + flags.AdminCert, + flags.AdminKey, + flags.AdminProvisioner, + flags.AdminSubject, + flags.PasswordFile, + flags.CaURL, + flags.Root, + }, + Description: `**step beta ca acme eab remove** removes an ACME EAB Key from the CA. + +## POSITIONAL ARGUMENTS + + +: The ACME EAB Key ID to remove + +## EXAMPLES + +Remove ACME EAB Key with Key ID "zFGdKC1sHmNf3Wsx3OujY808chxwEdmr": +''' +$ step beta ca acme eab remove zFGdKC1sHmNf3Wsx3OujY808chxwEdmr +''' +`, + } +} + +func removeAction(ctx *cli.Context) error { + if err := errs.NumberOfArguments(ctx, 1); err != nil { + return err + } + + args := ctx.Args() + keyID := args.Get(0) + + client, err := cautils.NewAdminClient(ctx) + if err != nil { + return err + } + + err = client.RemoveExternalAccountKey(keyID) + if err != nil { + return err + } + + ui.Println("Key was deleted successfully!") + + return nil +} From ffceaaa15191aaf54e6e0a16f9b6f34ebc39c9a0 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Fri, 27 Aug 2021 16:51:01 +0200 Subject: [PATCH 09/52] Add support for listing ACME EAB keys --- command/ca/acme/eab/add.go | 3 +++ command/ca/acme/eab/eab.go | 19 +++++++++++++++++-- command/ca/acme/eab/list.go | 34 +++++++++++++++++++++++++++++----- 3 files changed, 49 insertions(+), 7 deletions(-) diff --git a/command/ca/acme/eab/add.go b/command/ca/acme/eab/add.go index 9bdf9b80..b892bf96 100644 --- a/command/ca/acme/eab/add.go +++ b/command/ca/acme/eab/add.go @@ -31,6 +31,9 @@ func addCommand() cli.Command { ## POSITIONAL ARGUMENTS + +: Name of the provisioner to add an ACME EAB key to + : Name or (external) reference for the key to be created diff --git a/command/ca/acme/eab/eab.go b/command/ca/acme/eab/eab.go index 51128852..afc8456c 100644 --- a/command/ca/acme/eab/eab.go +++ b/command/ca/acme/eab/eab.go @@ -2,6 +2,7 @@ package eab import ( "encoding/base64" + "time" "github.com/smallstep/certificates/ca" "github.com/urfave/cli" @@ -13,11 +14,25 @@ type cliEAK struct { provisioner string name string key string + createdAt time.Time + boundAt string + account string } func toCLI(ctx *cli.Context, client *ca.AdminClient, eak *linkedca.EABKey) (*cliEAK, error) { - // TODO: more fields for other purposes, like including the createdat/boundat/account for listing? - return &cliEAK{id: eak.EabKid, provisioner: eak.ProvisionerName, name: eak.Name, key: base64.RawURLEncoding.Strict().EncodeToString(eak.EabHmacKey)}, nil + boundAt := "" + if !eak.BoundAt.AsTime().IsZero() { + boundAt = eak.BoundAt.AsTime().Format("2006-01-02 15:04:05 -07:00") + } + return &cliEAK{ + id: eak.EabKid, + provisioner: eak.ProvisionerName, + name: eak.Name, + key: base64.RawURLEncoding.Strict().EncodeToString(eak.EabHmacKey), + createdAt: eak.CreatedAt.AsTime(), + boundAt: boundAt, + account: eak.Account, + }, nil } // Command returns the eab subcommand. diff --git a/command/ca/acme/eab/list.go b/command/ca/acme/eab/list.go index ae56724e..c74afc8f 100644 --- a/command/ca/acme/eab/list.go +++ b/command/ca/acme/eab/list.go @@ -2,6 +2,8 @@ package eab import ( "fmt" + "os" + "text/tabwriter" "github.com/smallstep/cli/errs" "github.com/smallstep/cli/flags" @@ -14,7 +16,7 @@ func listCommand() cli.Command { Name: "list", Action: cli.ActionFunc(listAction), Usage: "list all ACME External Account Binding Keys", - UsageText: `**step beta ca acme eab list** [**--ca-url**=] [**--root**=]`, + UsageText: `**step beta ca acme eab list** [**--ca-url**=] [**--root**=]`, Flags: []cli.Flag{ flags.AdminCert, flags.AdminKey, @@ -26,32 +28,54 @@ func listCommand() cli.Command { }, Description: `**step beta ca acme eab list** lists all ACME External Account Binding Keys. +## POSITIONAL ARGUMENTS + + +: Name of the provisioner to add an ACME EAB key to + ## EXAMPLES List all ACME External Account Binding Keys: ''' -$ step beta ca acme eab list +$ step beta ca acme eab list ''' `, } } func listAction(ctx *cli.Context) (err error) { - if err := errs.NumberOfArguments(ctx, 0); err != nil { + if err := errs.NumberOfArguments(ctx, 1); err != nil { return err } + args := ctx.Args() + provisionerName := args.Get(0) + client, err := cautils.NewAdminClient(ctx) if err != nil { return err } - eaks, err := client.GetExternalAccountKeys() + eaks, err := client.GetExternalAccountKeys(provisionerName) if err != nil { return err } - fmt.Println(eaks) + w := new(tabwriter.Writer) + // Format in tab-separated columns with a tab stop of 8. + w.Init(os.Stdout, 0, 8, 1, '\t', 0) + + fmt.Fprintln(w, "Key ID\tProvisioner\tName\tKey (masked)\tCreated At\tBound At\tAccount") + + for _, k := range eaks { + cliEAK, err := toCLI(ctx, client, k) + if err != nil { + return err + } + fmt.Fprintf(w, "%s\t%s \t%s \t%s \t%s \t%s \t%s\n", cliEAK.id, cliEAK.provisioner, cliEAK.name, "*****", cliEAK.createdAt.Format("2006-01-02 15:04:05 -07:00"), cliEAK.boundAt, cliEAK.account) + } + + w.Flush() return nil } From 6bd3a20f23a6a326db143bccc6241e6c608abdfb Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Thu, 16 Sep 2021 19:57:01 +0200 Subject: [PATCH 10/52] Address some PR comments --- command/ca/acme/eab/add.go | 2 +- command/ca/acme/eab/eab.go | 4 ++-- command/ca/provisionerbeta/update.go | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/command/ca/acme/eab/add.go b/command/ca/acme/eab/add.go index b892bf96..122966d2 100644 --- a/command/ca/acme/eab/add.go +++ b/command/ca/acme/eab/add.go @@ -35,7 +35,7 @@ func addCommand() cli.Command { : Name of the provisioner to add an ACME EAB key to -: Name or (external) reference for the key to be created +: Name or (external) reference for the key to be created ## EXAMPLES diff --git a/command/ca/acme/eab/eab.go b/command/ca/acme/eab/eab.go index afc8456c..66eb872d 100644 --- a/command/ca/acme/eab/eab.go +++ b/command/ca/acme/eab/eab.go @@ -25,10 +25,10 @@ func toCLI(ctx *cli.Context, client *ca.AdminClient, eak *linkedca.EABKey) (*cli boundAt = eak.BoundAt.AsTime().Format("2006-01-02 15:04:05 -07:00") } return &cliEAK{ - id: eak.EabKid, + id: eak.Id, provisioner: eak.ProvisionerName, name: eak.Name, - key: base64.RawURLEncoding.Strict().EncodeToString(eak.EabHmacKey), + key: base64.RawURLEncoding.Strict().EncodeToString(eak.HmacKey), createdAt: eak.CreatedAt.AsTime(), boundAt: boundAt, account: eak.Account, diff --git a/command/ca/provisionerbeta/update.go b/command/ca/provisionerbeta/update.go index ae673c09..d501099a 100644 --- a/command/ca/provisionerbeta/update.go +++ b/command/ca/provisionerbeta/update.go @@ -235,7 +235,7 @@ step beta ca provisioner update x5c --x5c-root x5c_ca.crt Update an ACME provisioner: ''' -step beta ca provisioner update acme --force-cn --require-eab --disable-eab +step beta ca provisioner update acme --force-cn --require-eab ''' Update an K8SSA provisioner: @@ -580,7 +580,7 @@ func updateACMEDetails(ctx *cli.Context, p *linkedca.Provisioner) error { requireEABSet := ctx.IsSet("require-eab") disableEABSet := ctx.IsSet("disable-eab") if requireEABSet && disableEABSet { - return errors.New("cannot provide both --require-eab and --disable-eab") + return errs.IncompatibleFlagWithFlag(ctx, "require-eab", "disable-eab") } if requireEABSet { details.RequireEab = ctx.Bool("require-eab") From aaa86563c6e2343b27178562c95d74e0837be221 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Thu, 16 Sep 2021 22:32:57 +0200 Subject: [PATCH 11/52] Change EAB parameter names to be more consistent --- command/ca/acme/eab/add.go | 29 ++++++++++++++++------------- command/ca/acme/eab/eab.go | 8 ++++---- command/ca/acme/eab/list.go | 21 ++++++++++++--------- command/ca/acme/eab/remove.go | 6 ++++-- 4 files changed, 36 insertions(+), 28 deletions(-) diff --git a/command/ca/acme/eab/add.go b/command/ca/acme/eab/add.go index 122966d2..45da0f46 100644 --- a/command/ca/acme/eab/add.go +++ b/command/ca/acme/eab/add.go @@ -14,10 +14,13 @@ import ( func addCommand() cli.Command { return cli.Command{ - Name: "add", - Action: cli.ActionFunc(addAction), - Usage: "add ACME External Account Binding Key", - UsageText: `**step beta ca acme eab add** [**--ca-url**=] [**--root**=]`, + Name: "add", + Action: cli.ActionFunc(addAction), + Usage: "add ACME External Account Binding Key", + UsageText: `**step beta ca acme eab add** +[**--admin-cert**=] [**--admin-key**=] +[**--admin-provisioner**=] [**--admin-subject**=] +[**--password-file**=] [**--ca-url**=] [**--root**=]`, Flags: []cli.Flag{ flags.AdminCert, flags.AdminKey, @@ -31,11 +34,11 @@ func addCommand() cli.Command { ## POSITIONAL ARGUMENTS - + : Name of the provisioner to add an ACME EAB key to - -: Name or (external) reference for the key to be created + +: Reference (from external system) for the key to be created ## EXAMPLES @@ -52,8 +55,8 @@ func addAction(ctx *cli.Context) (err error) { } args := ctx.Args() - provisionerName := args.Get(0) - credentialName := args.Get(1) + provisioner := args.Get(0) + reference := args.Get(1) client, err := cautils.NewAdminClient(ctx) if err != nil { @@ -61,8 +64,8 @@ func addAction(ctx *cli.Context) (err error) { } eak, err := client.CreateExternalAccountKey(&adminAPI.CreateExternalAccountKeyRequest{ - ProvisionerName: provisionerName, - Name: credentialName, + Provisioner: provisioner, + Reference: reference, }) if err != nil { return err @@ -79,8 +82,8 @@ func addAction(ctx *cli.Context) (err error) { // Format in tab-separated columns with a tab stop of 8. w.Init(os.Stdout, 0, 8, 1, '\t', 0) - fmt.Fprintln(w, "Key ID\tProvisioner\tName\tKey (base64, raw url encoded)") - fmt.Fprintf(w, "%s\t%s \t%s \t%s\n", cliEAK.id, cliEAK.provisioner, cliEAK.name, cliEAK.key) + fmt.Fprintln(w, "Key ID\tProvisioner\tReference\tKey (base64, raw url encoded)") + fmt.Fprintf(w, "%s\t%s \t%s \t%s\n", cliEAK.id, cliEAK.provisioner, cliEAK.reference, cliEAK.key) w.Flush() return nil diff --git a/command/ca/acme/eab/eab.go b/command/ca/acme/eab/eab.go index 66eb872d..ef9b4cc7 100644 --- a/command/ca/acme/eab/eab.go +++ b/command/ca/acme/eab/eab.go @@ -12,7 +12,7 @@ import ( type cliEAK struct { id string provisioner string - name string + reference string key string createdAt time.Time boundAt string @@ -26,8 +26,8 @@ func toCLI(ctx *cli.Context, client *ca.AdminClient, eak *linkedca.EABKey) (*cli } return &cliEAK{ id: eak.Id, - provisioner: eak.ProvisionerName, - name: eak.Name, + provisioner: eak.Provisioner, + reference: eak.Reference, key: base64.RawURLEncoding.Strict().EncodeToString(eak.HmacKey), createdAt: eak.CreatedAt.AsTime(), boundAt: boundAt, @@ -53,7 +53,7 @@ func Command() cli.Command { List the active ACME External Account Binding Keys: ''' -$ step beta ca acme eab list +$ step beta ca acme eab list ''' Add an ACME External Account Binding Key: diff --git a/command/ca/acme/eab/list.go b/command/ca/acme/eab/list.go index c74afc8f..9f95c423 100644 --- a/command/ca/acme/eab/list.go +++ b/command/ca/acme/eab/list.go @@ -13,10 +13,13 @@ import ( func listCommand() cli.Command { return cli.Command{ - Name: "list", - Action: cli.ActionFunc(listAction), - Usage: "list all ACME External Account Binding Keys", - UsageText: `**step beta ca acme eab list** [**--ca-url**=] [**--root**=]`, + Name: "list", + Action: cli.ActionFunc(listAction), + Usage: "list all ACME External Account Binding Keys", + UsageText: `**step beta ca acme eab list** +[**--admin-cert**=] [**--admin-key**=] +[**--admin-provisioner**=] [**--admin-subject**=] +[**--password-file**=] [**--ca-url**=] [**--root**=]`, Flags: []cli.Flag{ flags.AdminCert, flags.AdminKey, @@ -30,14 +33,14 @@ func listCommand() cli.Command { ## POSITIONAL ARGUMENTS - -: Name of the provisioner to add an ACME EAB key to + +: Name of the provisioner to list ACME EAB keys for ## EXAMPLES List all ACME External Account Binding Keys: ''' -$ step beta ca acme eab list +$ step beta ca acme eab list ''' `, } @@ -65,14 +68,14 @@ func listAction(ctx *cli.Context) (err error) { // Format in tab-separated columns with a tab stop of 8. w.Init(os.Stdout, 0, 8, 1, '\t', 0) - fmt.Fprintln(w, "Key ID\tProvisioner\tName\tKey (masked)\tCreated At\tBound At\tAccount") + fmt.Fprintln(w, "Key ID\tProvisioner\tReference\tKey (masked)\tCreated At\tBound At\tAccount") for _, k := range eaks { cliEAK, err := toCLI(ctx, client, k) if err != nil { return err } - fmt.Fprintf(w, "%s\t%s \t%s \t%s \t%s \t%s \t%s\n", cliEAK.id, cliEAK.provisioner, cliEAK.name, "*****", cliEAK.createdAt.Format("2006-01-02 15:04:05 -07:00"), cliEAK.boundAt, cliEAK.account) + fmt.Fprintf(w, "%s\t%s \t%s \t%s \t%s \t%s \t%s\n", cliEAK.id, cliEAK.provisioner, cliEAK.reference, "*****", cliEAK.createdAt.Format("2006-01-02 15:04:05 -07:00"), cliEAK.boundAt, cliEAK.account) } w.Flush() diff --git a/command/ca/acme/eab/remove.go b/command/ca/acme/eab/remove.go index 3eff323d..196c6049 100644 --- a/command/ca/acme/eab/remove.go +++ b/command/ca/acme/eab/remove.go @@ -13,8 +13,10 @@ func removeCommand() cli.Command { Name: "remove", Action: cli.ActionFunc(removeAction), Usage: "remove an ACME EAB Key from the CA", - UsageText: `**step beta ca acme eab remove** [**--ca-url**=] -[**--root**=]`, + UsageText: `**step beta ca acme eab remove** +[**--admin-cert**=] [**--admin-key**=] +[**--admin-provisioner**=] [**--admin-subject**=] +[**--password-file**=] [**--ca-url**=] [**--root**=]`, Flags: []cli.Flag{ flags.AdminCert, flags.AdminKey, From 469ac08c59b22f3a3c73e96c4e8916a6def2ef7a Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Fri, 17 Sep 2021 16:59:59 +0200 Subject: [PATCH 12/52] Support for the reference to be optional instead of required --- command/ca/acme/eab/add.go | 19 ++++++++++++++----- command/ca/acme/eab/list.go | 22 ++++++++++++++++++---- 2 files changed, 32 insertions(+), 9 deletions(-) diff --git a/command/ca/acme/eab/add.go b/command/ca/acme/eab/add.go index 45da0f46..3130a447 100644 --- a/command/ca/acme/eab/add.go +++ b/command/ca/acme/eab/add.go @@ -17,7 +17,7 @@ func addCommand() cli.Command { Name: "add", Action: cli.ActionFunc(addAction), Usage: "add ACME External Account Binding Key", - UsageText: `**step beta ca acme eab add** + UsageText: `**step beta ca acme eab add** [**--admin-cert**=] [**--admin-key**=] [**--admin-provisioner**=] [**--admin-subject**=] [**--password-file**=] [**--ca-url**=] [**--root**=]`, @@ -38,11 +38,16 @@ func addCommand() cli.Command { : Name of the provisioner to add an ACME EAB key to -: Reference (from external system) for the key to be created +: (Optional) reference (from external system) for the key to be created ## EXAMPLES -Add an ACME External Account Binding Key: +Add an ACME External Account Binding Key without reference: +''' +$ step beta ca acme eab add my_acme_provisioner +''' + +Add an ACME External Account Binding Key with reference: ''' $ step beta ca acme eab add my_acme_provisioner my_first_eab_key '''`, @@ -50,13 +55,17 @@ $ step beta ca acme eab add my_acme_provisioner my_first_eab_key } func addAction(ctx *cli.Context) (err error) { - if err := errs.NumberOfArguments(ctx, 2); err != nil { + if errs.MinMaxNumberOfArguments(ctx, 1, 2); err != nil { return err } args := ctx.Args() provisioner := args.Get(0) - reference := args.Get(1) + + reference := "" + if ctx.NArg() == 2 { + reference = args.Get(1) + } client, err := cautils.NewAdminClient(ctx) if err != nil { diff --git a/command/ca/acme/eab/list.go b/command/ca/acme/eab/list.go index 9f95c423..7fd113ff 100644 --- a/command/ca/acme/eab/list.go +++ b/command/ca/acme/eab/list.go @@ -16,7 +16,7 @@ func listCommand() cli.Command { Name: "list", Action: cli.ActionFunc(listAction), Usage: "list all ACME External Account Binding Keys", - UsageText: `**step beta ca acme eab list** + UsageText: `**step beta ca acme eab list** [**--admin-cert**=] [**--admin-key**=] [**--admin-provisioner**=] [**--admin-subject**=] [**--password-file**=] [**--ca-url**=] [**--root**=]`, @@ -36,30 +36,44 @@ func listCommand() cli.Command { : Name of the provisioner to list ACME EAB keys for + +: (Optional) Reference (from external system) for the key to be created + + ## EXAMPLES List all ACME External Account Binding Keys: ''' -$ step beta ca acme eab list +$ step beta ca acme eab list my_provisioner +''' + +Show ACME External Account Binding Key with specific reference: +''' +$ step beta ca acme eab list my_provisioner my_reference ''' `, } } func listAction(ctx *cli.Context) (err error) { - if err := errs.NumberOfArguments(ctx, 1); err != nil { + if err := errs.MinMaxNumberOfArguments(ctx, 1, 2); err != nil { return err } args := ctx.Args() provisionerName := args.Get(0) + reference := "" + if ctx.NArg() == 2 { + reference = args.Get(1) + } + client, err := cautils.NewAdminClient(ctx) if err != nil { return err } - eaks, err := client.GetExternalAccountKeys(provisionerName) + eaks, err := client.GetExternalAccountKeys(provisionerName, reference) if err != nil { return err } From 42acdb6c62a3395e7be4398fc370f39db4c4a908 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Fri, 17 Sep 2021 17:46:43 +0200 Subject: [PATCH 13/52] Add provisioner to the remove command --- command/ca/acme/eab/remove.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/command/ca/acme/eab/remove.go b/command/ca/acme/eab/remove.go index 196c6049..a6eb2c14 100644 --- a/command/ca/acme/eab/remove.go +++ b/command/ca/acme/eab/remove.go @@ -13,7 +13,7 @@ func removeCommand() cli.Command { Name: "remove", Action: cli.ActionFunc(removeAction), Usage: "remove an ACME EAB Key from the CA", - UsageText: `**step beta ca acme eab remove** + UsageText: `**step beta ca acme eab remove** [**--admin-cert**=] [**--admin-key**=] [**--admin-provisioner**=] [**--admin-subject**=] [**--password-file**=] [**--ca-url**=] [**--root**=]`, @@ -30,6 +30,9 @@ func removeCommand() cli.Command { ## POSITIONAL ARGUMENTS + +: Name of the provisioner to remove an ACME EAB key for + : The ACME EAB Key ID to remove @@ -44,19 +47,20 @@ $ step beta ca acme eab remove zFGdKC1sHmNf3Wsx3OujY808chxwEdmr } func removeAction(ctx *cli.Context) error { - if err := errs.NumberOfArguments(ctx, 1); err != nil { + if err := errs.NumberOfArguments(ctx, 2); err != nil { return err } args := ctx.Args() - keyID := args.Get(0) + provisioner := args.Get(0) + keyID := args.Get(1) client, err := cautils.NewAdminClient(ctx) if err != nil { return err } - err = client.RemoveExternalAccountKey(keyID) + err = client.RemoveExternalAccountKey(provisioner, keyID) if err != nil { return err } From 1bb9333ae85d8f412b098151423a068cd6069cd6 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Mon, 11 Oct 2021 23:39:23 +0200 Subject: [PATCH 14/52] Update API body and endpoints --- command/ca/acme/eab/add.go | 5 ++--- command/ca/acme/eab/list.go | 4 ++-- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/command/ca/acme/eab/add.go b/command/ca/acme/eab/add.go index 3130a447..779fab3a 100644 --- a/command/ca/acme/eab/add.go +++ b/command/ca/acme/eab/add.go @@ -72,9 +72,8 @@ func addAction(ctx *cli.Context) (err error) { return err } - eak, err := client.CreateExternalAccountKey(&adminAPI.CreateExternalAccountKeyRequest{ - Provisioner: provisioner, - Reference: reference, + eak, err := client.CreateExternalAccountKey(provisioner, &adminAPI.CreateExternalAccountKeyRequest{ + Reference: reference, }) if err != nil { return err diff --git a/command/ca/acme/eab/list.go b/command/ca/acme/eab/list.go index 7fd113ff..54483e92 100644 --- a/command/ca/acme/eab/list.go +++ b/command/ca/acme/eab/list.go @@ -61,7 +61,7 @@ func listAction(ctx *cli.Context) (err error) { } args := ctx.Args() - provisionerName := args.Get(0) + provisioner := args.Get(0) reference := "" if ctx.NArg() == 2 { @@ -73,7 +73,7 @@ func listAction(ctx *cli.Context) (err error) { return err } - eaks, err := client.GetExternalAccountKeys(provisionerName, reference) + eaks, err := client.GetExternalAccountKeys(provisioner, reference) if err != nil { return err } From 2e37ddb2976c7f93487a407c7a1bfc6f4c2e345d Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Mon, 11 Oct 2021 23:41:02 +0200 Subject: [PATCH 15/52] Update to go.step.sm/linkedca v0.8.0 --- go.mod | 2 +- go.sum | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 1fe018a1..f6ff33a4 100644 --- a/go.mod +++ b/go.mod @@ -26,7 +26,7 @@ require ( github.com/urfave/cli v1.22.5 go.mozilla.org/pkcs7 v0.0.0-20200128120323-432b2356ecb1 go.step.sm/crypto v0.9.2 - go.step.sm/linkedca v0.5.0 + go.step.sm/linkedca v0.8.0 golang.org/x/crypto v0.0.0-20210817164053-32db794688a5 golang.org/x/net v0.0.0-20210825183410-e898025ed96a golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c diff --git a/go.sum b/go.sum index c6c56e28..d2b5d883 100644 --- a/go.sum +++ b/go.sum @@ -918,6 +918,8 @@ go.step.sm/crypto v0.9.2 h1:UvQHE4brjAOdgcK2ob6zupL1iRzDd8+QiEvPOeQrm4E= go.step.sm/crypto v0.9.2/go.mod h1:F5OJyPDWntNa1SbuWPxuHJc9bLzu84NzYrrdzDuBugk= go.step.sm/linkedca v0.5.0 h1:oZVRSpElM7lAL1XN2YkjdHwI/oIZ+1ULOnuqYPM6xjY= go.step.sm/linkedca v0.5.0/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo= +go.step.sm/linkedca v0.8.0 h1:86DAufqUtUvFTJgYpgG0McKkpqnjXxg53FTXYyhs0HI= +go.step.sm/linkedca v0.8.0/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= From def58f9d4c11f355477382b4ee910982ae79c7b1 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Tue, 9 Nov 2021 21:35:31 +0100 Subject: [PATCH 16/52] Add support for IP SANS when using ACME provisioner Fixes #575 --- utils/cautils/acmeutils.go | 44 +++++++++++++++++++++++++++++--------- 1 file changed, 34 insertions(+), 10 deletions(-) diff --git a/utils/cautils/acmeutils.go b/utils/cautils/acmeutils.go index 57bca7a1..0506e1f5 100644 --- a/utils/cautils/acmeutils.go +++ b/utils/cautils/acmeutils.go @@ -9,6 +9,7 @@ import ( "encoding/pem" "fmt" "io/ioutil" + "net" "net/http" "os" "strings" @@ -267,18 +268,18 @@ func finalizeOrder(ac *ca.ACMEClient, o *acme.Order, csr *x509.CertificateReques return fo, nil } -func validateSANsForACME(sans []string) ([]string, error) { +func validateSANsForACME(sans []string) ([]string, []net.IP, error) { dnsNames, ips, emails, uris := splitSANs(sans) - if len(ips) > 0 || len(emails) > 0 || len(uris) > 0 { - return nil, errors.New("IP Address, Email Address, and URI SANs are not supported for ACME flow") + if len(emails) > 0 || len(uris) > 0 { + return nil, nil, errors.New("Email Address and URI SANs are not supported for ACME flow") } for _, dns := range dnsNames { if strings.Contains(dns, "*") { - return nil, errors.Errorf("wildcard dnsnames (%s) require dns validation, "+ + return nil, nil, errors.Errorf("wildcard dnsnames (%s) require dns validation, "+ "which is currently not implemented in this client", dns) } } - return dnsNames, nil + return dnsNames, ips, nil } type acmeFlowOp func(*acmeFlow) error @@ -361,7 +362,7 @@ func newACMEFlow(ctx *cli.Context, ops ...acmeFlowOp) (*acmeFlow, error) { } func (af *acmeFlow) GetCertificate() ([]*x509.Certificate, error) { - dnsNames, err := validateSANsForACME(af.sans) + dnsNames, ips, err := validateSANsForACME(af.sans) if err != nil { return nil, err } @@ -373,6 +374,12 @@ func (af *acmeFlow) GetCertificate() ([]*x509.Certificate, error) { Value: dns, }) } + for _, ip := range ips { + idents = append(idents, acme.Identifier{ + Type: "ip", + Value: ip.String(), + }) + } var ( orderPayload []byte @@ -423,7 +430,20 @@ func (af *acmeFlow) GetCertificate() ([]*x509.Certificate, error) { if err != nil { return nil, err } - + hasSubject := false + for _, n := range idents { + if n.Value == af.subject { + hasSubject = true + } + } + subjectIsNotAnIP := net.ParseIP(af.subject) == nil + if !hasSubject && subjectIsNotAnIP { + dnsNames = append(dnsNames, af.subject) + idents = append(idents, acme.Identifier{ + Type: "dns", + Value: af.subject, + }) + } nor := acmeAPI.NewOrderRequest{ Identifiers: idents, NotAfter: naf.Time(), @@ -461,10 +481,14 @@ func (af *acmeFlow) GetCertificate() ([]*x509.Certificate, error) { } _csr := &x509.CertificateRequest{ - Subject: pkix.Name{ + DNSNames: dnsNames, + IPAddresses: ips, + } + subjectIsNotAnIP := net.ParseIP(af.subject) == nil + if subjectIsNotAnIP { + _csr.Subject = pkix.Name{ CommonName: af.subject, - }, - DNSNames: dnsNames, + } } var csrBytes []byte csrBytes, err = x509.CreateCertificateRequest(rand.Reader, _csr, af.priv) From 722b1944edc306e93caf09a67f3de127e5fb0ce6 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Tue, 7 Dec 2021 16:17:28 +0100 Subject: [PATCH 17/52] Add context argument --- command/ca/acme/eab/add.go | 8 +++++--- command/ca/acme/eab/list.go | 4 +++- command/ca/acme/eab/remove.go | 4 +++- 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/command/ca/acme/eab/add.go b/command/ca/acme/eab/add.go index e7ae9d67..57fe225a 100644 --- a/command/ca/acme/eab/add.go +++ b/command/ca/acme/eab/add.go @@ -20,7 +20,8 @@ func addCommand() cli.Command { UsageText: `**step beta ca acme eab add** [**--admin-cert**=] [**--admin-key**=] [**--admin-provisioner**=] [**--admin-subject**=] -[**--password-file**=] [**--ca-url**=] [**--root**=]`, +[**--password-file**=] [**--ca-url**=] [**--root**=] +[**--context**=]`, Flags: []cli.Flag{ flags.AdminCert, flags.AdminKey, @@ -29,6 +30,7 @@ func addCommand() cli.Command { flags.PasswordFile, flags.CaURL, flags.Root, + flags.Context, }, Description: `**step beta ca acme eab add** adds ACME External Account Binding Key. @@ -55,7 +57,7 @@ $ step beta ca acme eab add my_acme_provisioner my_first_eab_key } func addAction(ctx *cli.Context) (err error) { - if errs.MinMaxNumberOfArguments(ctx, 1, 2); err != nil { + if err := errs.MinMaxNumberOfArguments(ctx, 1, 2); err != nil { return err } @@ -84,7 +86,7 @@ func addAction(ctx *cli.Context) (err error) { return err } - // TODO: JSON output, so that executing this command can be more easily automated? + // TODO(hs): JSON output, so that executing this command can be more easily automated? w := new(tabwriter.Writer) // Format in tab-separated columns with a tab stop of 8. diff --git a/command/ca/acme/eab/list.go b/command/ca/acme/eab/list.go index 82a780ed..b2719535 100644 --- a/command/ca/acme/eab/list.go +++ b/command/ca/acme/eab/list.go @@ -19,7 +19,8 @@ func listCommand() cli.Command { UsageText: `**step beta ca acme eab list** [**--admin-cert**=] [**--admin-key**=] [**--admin-provisioner**=] [**--admin-subject**=] -[**--password-file**=] [**--ca-url**=] [**--root**=]`, +[**--password-file**=] [**--ca-url**=] [**--root**=] +[**--context**=]`, Flags: []cli.Flag{ flags.AdminCert, flags.AdminKey, @@ -28,6 +29,7 @@ func listCommand() cli.Command { flags.PasswordFile, flags.CaURL, flags.Root, + flags.Context, }, Description: `**step beta ca acme eab list** lists all ACME External Account Binding Keys. diff --git a/command/ca/acme/eab/remove.go b/command/ca/acme/eab/remove.go index 7dcf29ac..9da54d05 100644 --- a/command/ca/acme/eab/remove.go +++ b/command/ca/acme/eab/remove.go @@ -16,7 +16,8 @@ func removeCommand() cli.Command { UsageText: `**step beta ca acme eab remove** [**--admin-cert**=] [**--admin-key**=] [**--admin-provisioner**=] [**--admin-subject**=] -[**--password-file**=] [**--ca-url**=] [**--root**=]`, +[**--password-file**=] [**--ca-url**=] [**--root**=] +[**--context**=]`, Flags: []cli.Flag{ flags.AdminCert, flags.AdminKey, @@ -25,6 +26,7 @@ func removeCommand() cli.Command { flags.PasswordFile, flags.CaURL, flags.Root, + flags.Context, }, Description: `**step beta ca acme eab remove** removes an ACME EAB Key from the CA. From d5ccc2760bb1e717b6ede508bae96def1953c248 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Mon, 13 Dec 2021 15:35:53 +0100 Subject: [PATCH 18/52] Allow IPs in the CSR subject We now allow IPs to be in the subject. The CLI also ensures that when a Subject Common Name can be parsed as an IP it is included in the Order, so that authorization can be performed by the CA. --- utils/cautils/acmeutils.go | 19 ++++++++++++------- 1 file changed, 12 insertions(+), 7 deletions(-) diff --git a/utils/cautils/acmeutils.go b/utils/cautils/acmeutils.go index 8e5b280a..554a2101 100644 --- a/utils/cautils/acmeutils.go +++ b/utils/cautils/acmeutils.go @@ -436,14 +436,22 @@ func (af *acmeFlow) GetCertificate() ([]*x509.Certificate, error) { hasSubject = true } } - subjectIsNotAnIP := net.ParseIP(af.subject) == nil - if !hasSubject && subjectIsNotAnIP { + subjectIsAnIP := net.ParseIP(af.subject) != nil + if !hasSubject && !subjectIsAnIP { dnsNames = append(dnsNames, af.subject) idents = append(idents, acme.Identifier{ Type: "dns", Value: af.subject, }) } + if !hasSubject && subjectIsAnIP { + ip := net.ParseIP(af.subject) + ips = append(ips, ip) + idents = append(idents, acme.Identifier{ + Type: "ip", + Value: ip.String(), + }) + } nor := acmeAPI.NewOrderRequest{ Identifiers: idents, NotAfter: naf.Time(), @@ -484,11 +492,8 @@ func (af *acmeFlow) GetCertificate() ([]*x509.Certificate, error) { DNSNames: dnsNames, IPAddresses: ips, } - subjectIsNotAnIP := net.ParseIP(af.subject) == nil - if subjectIsNotAnIP { - _csr.Subject = pkix.Name{ - CommonName: af.subject, - } + _csr.Subject = pkix.Name{ + CommonName: af.subject, } var csrBytes []byte csrBytes, err = x509.CreateCertificateRequest(rand.Reader, _csr, af.priv) From 444f1fcd07e582e8cff53eaae8645af8feaedb1c Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Mon, 13 Dec 2021 15:47:43 +0100 Subject: [PATCH 19/52] Clean up logic --- utils/cautils/acmeutils.go | 42 +++++++++++++++++++++++--------------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/utils/cautils/acmeutils.go b/utils/cautils/acmeutils.go index 554a2101..c9d26195 100644 --- a/utils/cautils/acmeutils.go +++ b/utils/cautils/acmeutils.go @@ -430,27 +430,35 @@ func (af *acmeFlow) GetCertificate() ([]*x509.Certificate, error) { if err != nil { return nil, err } + + // check if the list of identifiers for which to + // request a certificate already contains the subject hasSubject := false for _, n := range idents { if n.Value == af.subject { hasSubject = true } } - subjectIsAnIP := net.ParseIP(af.subject) != nil - if !hasSubject && !subjectIsAnIP { - dnsNames = append(dnsNames, af.subject) - idents = append(idents, acme.Identifier{ - Type: "dns", - Value: af.subject, - }) - } - if !hasSubject && subjectIsAnIP { + // if the subject is not yet included in the slice + // of identifiers, it is added to either the DNS names + // or IP addresses slice and the corresponding type of + // identifier is added to the slice of identifers. + if !hasSubject { ip := net.ParseIP(af.subject) - ips = append(ips, ip) - idents = append(idents, acme.Identifier{ - Type: "ip", - Value: ip.String(), - }) + subjectIsNotAnIP := ip == nil + if subjectIsNotAnIP { + dnsNames = append(dnsNames, af.subject) + idents = append(idents, acme.Identifier{ + Type: "dns", + Value: af.subject, + }) + } else { + ips = append(ips, ip) + idents = append(idents, acme.Identifier{ + Type: "ip", + Value: ip.String(), + }) + } } nor := acmeAPI.NewOrderRequest{ Identifiers: idents, @@ -489,12 +497,12 @@ func (af *acmeFlow) GetCertificate() ([]*x509.Certificate, error) { } _csr := &x509.CertificateRequest{ + Subject: pkix.Name{ + CommonName: af.subject, + }, DNSNames: dnsNames, IPAddresses: ips, } - _csr.Subject = pkix.Name{ - CommonName: af.subject, - } var csrBytes []byte csrBytes, err = x509.CreateCertificateRequest(rand.Reader, _csr, af.priv) if err != nil { From 7a1d616b2e1139c6b5c724530add3d1f84c58cc6 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Wed, 22 Dec 2021 11:00:04 +0100 Subject: [PATCH 20/52] Fix code style --- utils/cautils/acmeutils.go | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/utils/cautils/acmeutils.go b/utils/cautils/acmeutils.go index ecd8d910..c548fb13 100644 --- a/utils/cautils/acmeutils.go +++ b/utils/cautils/acmeutils.go @@ -444,20 +444,18 @@ func (af *acmeFlow) GetCertificate() ([]*x509.Certificate, error) { // or IP addresses slice and the corresponding type of // identifier is added to the slice of identifers. if !hasSubject { - ip := net.ParseIP(af.subject) - subjectIsNotAnIP := ip == nil - if subjectIsNotAnIP { - dnsNames = append(dnsNames, af.subject) - idents = append(idents, acme.Identifier{ - Type: "dns", - Value: af.subject, - }) - } else { + if ip := net.ParseIP(af.subject); ip != nil { ips = append(ips, ip) idents = append(idents, acme.Identifier{ Type: "ip", Value: ip.String(), }) + } else { + dnsNames = append(dnsNames, af.subject) + idents = append(idents, acme.Identifier{ + Type: "dns", + Value: af.subject, + }) } } nor := acmeAPI.NewOrderRequest{ From 219dbe6d12ce89aeb82d44727d8b791819fd91a6 Mon Sep 17 00:00:00 2001 From: Eli Young Date: Sun, 26 Dec 2021 18:27:33 -0800 Subject: [PATCH 21/52] Use alternatives system for RPMs This unifies the package scriptlets. Additionally, it changes the preremove scriptlet to a postremove script, as that's the more typical place to remove alternatives entries. --- .goreleaser.yml | 22 ++++++++-------------- debian/postinstall.sh | 14 -------------- debian/preremove.sh | 5 ----- scripts/postinstall.sh | 34 ++++++++++++++++++++++++++++++++++ scripts/postremove.sh | 34 ++++++++++++++++++++++++++++++++++ 5 files changed, 76 insertions(+), 33 deletions(-) delete mode 100644 debian/postinstall.sh delete mode 100644 debian/preremove.sh create mode 100644 scripts/postinstall.sh create mode 100644 scripts/postremove.sh diff --git a/.goreleaser.yml b/.goreleaser.yml index 08a0359a..694befe2 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -104,20 +104,14 @@ nfpms: dst: /usr/share/bash-completion/completions/step-cli - src: debian/copyright dst: /usr/share/doc/step-cli/copyright - overrides: - deb: - scripts: - postinstall: "debian/postinstall.sh" - preremove: "debian/preremove.sh" - rpm: - contents: - - src: autocomplete/bash_autocomplete - dst: /usr/share/bash-completion/completions/step-cli - - src: debian/copyright - dst: /usr/share/doc/step-cli/copyright - - src: /usr/bin/step-cli - dst: /usr/bin/step - type: "symlink" + # Ghost files are used for RPM and ignored elsewhere + - dst: /usr/bin/step + type: ghost + - dst: /usr/share/bash-completion/completions/step + type: ghost + scripts: + postinstall: scripts/postinstall.sh + postremove: scripts/postremove.sh source: diff --git a/debian/postinstall.sh b/debian/postinstall.sh deleted file mode 100644 index 40e825ee..00000000 --- a/debian/postinstall.sh +++ /dev/null @@ -1,14 +0,0 @@ -#!/bin/sh - -if [ "$1" = "configure" ]; then - if [ -f /usr/share/bash-completion/completions/step-cli ]; then - update-alternatives \ - --install /usr/bin/step step /usr/bin/step-cli 50 \ - --slave /usr/share/bash-completion/completions/step step.bash-completion /usr/share/bash-completion/completions/step-cli - fi - if [ -f /etc/bash_completion.d/step-cli ]; then - update-alternatives \ - --install /usr/bin/step step /usr/bin/step-cli 50 \ - --slave /etc/bash_completion.d/step step.bash-completion /etc/bash_completion.d/step-cli - fi -fi diff --git a/debian/preremove.sh b/debian/preremove.sh deleted file mode 100644 index 777ec5cd..00000000 --- a/debian/preremove.sh +++ /dev/null @@ -1,5 +0,0 @@ -#!/bin/sh - -if [ "$1" = "remove" ]; then - update-alternatives --remove step /usr/bin/step-cli -fi diff --git a/scripts/postinstall.sh b/scripts/postinstall.sh new file mode 100644 index 00000000..f7ac21b8 --- /dev/null +++ b/scripts/postinstall.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +updateAlternatives() { + update-alternatives \ + --install /usr/bin/step step /usr/bin/step-cli 50 \ + --slave /usr/share/bash-completion/completions/step step.bash-completion /usr/share/bash-completion/completions/step-cli +} + +cleanInstall() { + updateAlternatives +} + +upgrade() { + updateAlternatives +} + +action="$1" +if [ "$1" = "configure" ] && [ -z "$2" ]; then + action="install" +elif [ "$1" = "configure" ] && [ -n "$2" ]; then + action="upgrade" +fi + +case "$action" in + "1" | "install") + cleanInstall + ;; + "2" | "upgrade") + upgrade + ;; + *) + cleanInstall + ;; +esac diff --git a/scripts/postremove.sh b/scripts/postremove.sh new file mode 100644 index 00000000..1f5e7a4a --- /dev/null +++ b/scripts/postremove.sh @@ -0,0 +1,34 @@ +#!/bin/sh + +removeAlternatives() { + update-alternatives --remove step /usr/bin/step-cli +} + +upgrade() { + : +} + +remove() { + removeAlternatives +} + +action="$1" +if [ "$1" = "remove" ]; then + action="remove" +elif [ "$1" = "upgrade" ] && [ -n "$2" ]; then + action="upgrade" +elif [ "$1" = "disappear" ]; then + action="remove" +fi + +case "$action" in + "0" | "remove") + remove + ;; + "1" | "upgrade") + upgrade + ;; + *) + remove + ;; +esac From cede6e2a35370bb228f8911521663564abfaeff0 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Fri, 7 Jan 2022 16:43:04 -0800 Subject: [PATCH 22/52] Add initial implementation of `step crl inspect`. Current functionality supports to inspect a local crl or one a remote one server by HTTP(s) and print it in json, pem or a human representation. --- cmd/step/main.go | 1 + command/crl/crl.go | 22 ++ command/crl/crl_extensions.go | 211 ++++++++++++++++++ command/crl/inspect.go | 328 ++++++++++++++++++++++++++++ command/crl/signature_algorithms.go | 148 +++++++++++++ 5 files changed, 710 insertions(+) create mode 100644 command/crl/crl.go create mode 100644 command/crl/crl_extensions.go create mode 100644 command/crl/inspect.go create mode 100644 command/crl/signature_algorithms.go diff --git a/cmd/step/main.go b/cmd/step/main.go index 6fb2c820..0f9da0df 100644 --- a/cmd/step/main.go +++ b/cmd/step/main.go @@ -25,6 +25,7 @@ import ( _ "github.com/smallstep/cli/command/ca" _ "github.com/smallstep/cli/command/certificate" _ "github.com/smallstep/cli/command/context" + _ "github.com/smallstep/cli/command/crl" _ "github.com/smallstep/cli/command/crypto" _ "github.com/smallstep/cli/command/fileserver" _ "github.com/smallstep/cli/command/oauth" diff --git a/command/crl/crl.go b/command/crl/crl.go new file mode 100644 index 00000000..09e0e8c5 --- /dev/null +++ b/command/crl/crl.go @@ -0,0 +1,22 @@ +package crl + +import ( + "github.com/urfave/cli" + "go.step.sm/cli-utils/command" +) + +// init creates and registers the crl command +func init() { + cmd := cli.Command{ + Name: "crl", + Usage: "initialize and manage a certificate revocation list", + UsageText: "**step crl** [arguments] [global-flags] [subcommand-flags]", + Description: `**step crl** command group provides facilities to initialize manage a +certificate revocation list or CRL.`, + Subcommands: cli.Commands{ + inspectCommand(), + }, + } + + command.Register(cmd) +} diff --git a/command/crl/crl_extensions.go b/command/crl/crl_extensions.go new file mode 100644 index 00000000..2f44c31b --- /dev/null +++ b/command/crl/crl_extensions.go @@ -0,0 +1,211 @@ +package crl + +import ( + "bytes" + "crypto/x509/pkix" + "encoding/asn1" + "encoding/hex" + "encoding/json" + "fmt" + "math/big" + "strconv" +) + +var ( + oidExtensionReasonCode = asn1.ObjectIdentifier{2, 5, 29, 21} + oidExtensionCRLNumber = asn1.ObjectIdentifier{2, 5, 29, 20} + oidExtensionAuthorityKeyID = asn1.ObjectIdentifier{2, 5, 29, 35} + oidExtensionIssuingDistributionPoint = asn1.ObjectIdentifier{2, 5, 29, 28} +) + +func parseReasonCode(b []byte) string { + var reasonCode asn1.Enumerated + if _, err := asn1.Unmarshal(b, &reasonCode); err != nil { + return sanitizeBytes(b) + } + switch reasonCode { + case 0: + return "Unspecified" + case 1: + return "Key Compromise" + case 2: + return "CA Compromise" + case 3: + return "Affiliation Changed" + case 4: + return "Superseded" + case 5: + return "Cessation Of Operation" + case 6: + return "Certificate Hold" + case 8: + return "Remove From CRL" + case 9: + return "Privilege Withdrawn" + case 10: + return "AA Compromise" + default: + return fmt.Sprintf("ReasonCode(%d): unknown", reasonCode) + } +} + +// RFC 5280, 4.2.1.1 +type authorityKeyID struct { + ID []byte `asn1:"optional,tag:0"` +} + +// RFC 5280, 5.2.5 +type distributionPoint struct { + DistributionPoint distributionPointName `asn1:"optional,tag:0"` + OnlyContainsUserCerts bool `asn1:"optional,tag:1"` + OnlyContainsCACerts bool `asn1:"optional,tag:2"` + OnlySomeReasons asn1.BitString `asn1:"optional,tag:3"` + IndirectCRL bool `asn1:"optional,tag:4"` + OnlyContainsAttributeCerts bool `asn1:"optional,tag:5"` +} + +type distributionPointName struct { + FullName []asn1.RawValue `asn1:"optional,tag:0"` + RelativeName pkix.RDNSequence `asn1:"optional,tag:1"` +} + +func (d distributionPoint) FullNames() []string { + var names []string + for _, v := range d.DistributionPoint.FullName { + switch v.Class { + case 2: + names = append(names, fmt.Sprintf("URI:%s", v.Bytes)) + default: + names = append(names, fmt.Sprintf("Class(%d):%s", v.Class, v.Bytes)) + } + } + return names +} + +type Extension struct { + Name string `json:"-"` + Details []string `json:"-"` + json map[string]interface{} +} + +func (e *Extension) MarshalJSON() ([]byte, error) { + return json.Marshal(e.json) +} + +func (e *Extension) AddDetail(format string, args ...interface{}) { + e.Details = append(e.Details, fmt.Sprintf(format, args...)) +} + +func nexExtension(e pkix.Extension) Extension { + var ext Extension + switch { + case e.Id.Equal(oidExtensionReasonCode): + ext.Name = "X509v3 CRL Reason Code:" + value := parseReasonCode(e.Value) + ext.AddDetail(value) + ext.json = map[string]interface{}{ + "crl_reason_code": value, + } + + case e.Id.Equal(oidExtensionCRLNumber): + ext.Name = "X509v3 CRL Number:" + var n *big.Int + if _, err := asn1.Unmarshal(e.Value, &n); err == nil { + ext.AddDetail(n.String()) + ext.json = map[string]interface{}{ + "crl_number": n.String(), + } + } else { + ext.AddDetail(sanitizeBytes(e.Value)) + ext.json = map[string]interface{}{ + "crl_number": e.Value, + } + } + + case e.Id.Equal(oidExtensionAuthorityKeyID): + var v authorityKeyID + ext.Name = "X509v3 Authority Key Identifier:" + ext.json = map[string]interface{}{ + "authority_key_id": hex.EncodeToString(e.Value), + } + if _, err := asn1.Unmarshal(e.Value, &v); err == nil { + var s string + for _, b := range v.ID { + s += fmt.Sprintf(":%02X", b) + } + ext.AddDetail("keyid" + s) + } else { + ext.AddDetail(sanitizeBytes(e.Value)) + } + case e.Id.Equal(oidExtensionIssuingDistributionPoint): + ext.Name = "X509v3 Issuing Distribution Point:" + + var v distributionPoint + if _, err := asn1.Unmarshal(e.Value, &v); err != nil { + ext.AddDetail(sanitizeBytes(e.Value)) + ext.json = map[string]interface{}{ + "issuing_distribution_point": e.Value, + } + } else { + names := v.FullNames() + if len(names) > 0 { + ext.AddDetail("Full Name:") + for _, n := range names { + ext.AddDetail(" " + n) + } + } + js := map[string]interface{}{ + "full_names": names, + } + + // Only one of this should be set to true. But for inspect we + // will allow more than one. + if v.OnlyContainsUserCerts { + ext.AddDetail("Only User Certificates") + js["only_user_certificates"] = true + } + if v.OnlyContainsCACerts { + ext.AddDetail("Only CA Certificates") + js["only_ca_certificates"] = true + } + if v.OnlyContainsAttributeCerts { + ext.AddDetail("Only Attribute Certificates") + js["only_attribute_certificates"] = true + } + if len(v.OnlySomeReasons.Bytes) > 0 { + ext.AddDetail("Reasons: %x", v.OnlySomeReasons.Bytes) + js["only_some_reasons"] = v.OnlySomeReasons.Bytes + } + + ext.json = map[string]interface{}{ + "issuing_distribution_point": js, + } + } + default: + ext.Name = e.Id.String() + ext.AddDetail(sanitizeBytes(e.Value)) + ext.json = map[string]interface{}{ + ext.Name: e.Value, + } + } + + if e.Critical { + ext.Name += " critical" + ext.json["critical"] = true + } + + return ext +} + +func sanitizeBytes(b []byte) string { + value := bytes.Runes(b) + sanitized := make([]rune, len(value)) + for i, r := range value { + if strconv.IsPrint(r) && r != '�' { + sanitized[i] = r + } else { + sanitized[i] = '.' + } + } + return string(sanitized) +} diff --git a/command/crl/inspect.go b/command/crl/inspect.go new file mode 100644 index 00000000..582470e9 --- /dev/null +++ b/command/crl/inspect.go @@ -0,0 +1,328 @@ +package crl + +import ( + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" + "encoding/json" + "encoding/pem" + "fmt" + "io" + "net/http" + "os" + "strconv" + "strings" + "time" + + "github.com/pkg/errors" + "github.com/smallstep/cli/utils" + "github.com/urfave/cli" + "go.step.sm/cli-utils/command" + "go.step.sm/cli-utils/errs" +) + +func inspectCommand() cli.Command { + return cli.Command{ + Name: "inspect", + Action: command.ActionFunc(inspectAction), + Usage: "print certificate revocation list or CRL details in human readable format", + UsageText: `**step crl inspect** `, + Description: `**step crl inspect** prints the details of a certificate revocation list (CRL).`, + Flags: []cli.Flag{ + cli.StringFlag{ + Name: "format", + Value: "text", + Usage: `The output format for printing the introspection details. + + : is a string and must be one of: + + **text** + : Print output in unstructured text suitable for a human to read. + + **json** + : Print output in JSON format. + + **pem** + : Print output in PEM format.`, + }, + }, + } +} + +func inspectAction(ctx *cli.Context) error { + if err := errs.MinMaxNumberOfArguments(ctx, 0, 1); err != nil { + return err + } + + crlFile := ctx.Args().First() + if crlFile == "" { + crlFile = "-" + } + + var isURL bool + for _, p := range []string{"http://", "https://"} { + if strings.HasPrefix(strings.ToLower(crlFile), p) { + isURL = true + break + } + } + + var ( + b []byte + err error + ) + if isURL { + resp, err := http.Get(crlFile) + if err != nil { + return errors.Wrap(err, "error downloading crl") + } + if resp.StatusCode >= 400 { + return errors.Errorf("error downloading crl: status code %d", resp.StatusCode) + } + b, err = io.ReadAll(resp.Body) + if err != nil { + return errors.Wrap(err, "error downloading crl") + } + } else { + b, err = utils.ReadFile(crlFile) + if err != nil { + return err + } + } + + crl, err := ParseCRL(b) + if err != nil { + return errors.Wrap(err, "error parsing crl") + } + + switch ctx.String("format") { + case "json": + enc := json.NewEncoder(os.Stdout) + enc.SetIndent("", " ") + if err := enc.Encode(crl); err != nil { + return errors.Wrap(err, "error marshaling crl") + } + case "pem": + pem.Encode(os.Stdout, &pem.Block{ + Type: "X509 CRL", + Bytes: b, + }) + default: + printCRL(crl) + } + + return nil +} + +type CRL struct { + Version int `json:"version"` + SignatureAlgorithm SignatureAlgorithm `json:"signature_algorithm"` + Issuer DistinguisedName `json:"issuer"` + ThisUpdate time.Time `json:"this_update"` + NextUpdate time.Time `json:"next_update"` + RevokedCertificates []RevokedCertificate `json:"revoked_certificates"` + Extensions []Extension `json:"extensions,omitempty"` + Signature *Signature `json:"signature"` +} + +func ParseCRL(b []byte) (*CRL, error) { + crl, err := x509.ParseCRL(b) + if err != nil { + return nil, errors.Wrap(err, "error parsing crl") + } + tcrl := crl.TBSCertList + + certs := make([]RevokedCertificate, len(tcrl.RevokedCertificates)) + for i, c := range tcrl.RevokedCertificates { + certs[i] = newRevokedCertificate(c) + } + + extensions := make([]Extension, len(tcrl.Extensions)) + for i, e := range tcrl.Extensions { + extensions[i] = nexExtension(e) + } + + return &CRL{ + Version: tcrl.Version + 1, + SignatureAlgorithm: newSignatureAlgorithm(tcrl.Signature), + Issuer: newDistinguishedName(tcrl.Issuer), + ThisUpdate: tcrl.ThisUpdate, + NextUpdate: tcrl.NextUpdate, + RevokedCertificates: certs, + Extensions: extensions, + Signature: &Signature{ + SignatureAlgorithm: newSignatureAlgorithm(tcrl.Signature), + Value: crl.SignatureValue.Bytes, + Valid: false, + }, + }, nil +} + +func printCRL(crl *CRL) { + fmt.Println("Certificate Revocation List (CRL):") + fmt.Println(" Data:") + fmt.Printf(" Version: %d (0x%x)\n", crl.Version, crl.Version-1) + fmt.Println(" Signature algorithm:", crl.SignatureAlgorithm) + fmt.Println(" Issuer:", crl.Issuer) + fmt.Println(" Last Update:", crl.ThisUpdate.UTC()) + fmt.Println(" Next Update:", crl.NextUpdate.UTC()) + fmt.Println(" CRL Extensions:") + for _, e := range crl.Extensions { + fmt.Println(spacer(12) + e.Name) + for _, s := range e.Details { + fmt.Println(spacer(16) + s) + } + } + if len(crl.RevokedCertificates) == 0 { + fmt.Println(spacer(8) + "No Revoked Certificates.") + } else { + fmt.Println(spacer(8) + "Revoked Certificates:") + for _, crt := range crl.RevokedCertificates { + fmt.Printf(spacer(12)+"Serial Number: %s (0x%X)\n", crt.SerialNumber, crt.SerialNumberBytes) + fmt.Println(spacer(16)+"Revocation Date:", crt.RevocationTime.UTC()) + if len(crt.Extensions) > 0 { + fmt.Println(spacer(16) + "CRL Entry Extensions:") + for _, e := range crt.Extensions { + fmt.Println(spacer(20) + e.Name) + for _, s := range e.Details { + fmt.Println(spacer(24) + s) + } + } + } + } + } + + fmt.Println(" Signature Algorithm:", crl.Signature.SignatureAlgorithm) + fmt.Println(" Signature:") + printBytes(crl.Signature.Value, spacer(8)) +} + +type Signature struct { + SignatureAlgorithm SignatureAlgorithm `json:"signature_algorithm"` + Value []byte `json:"value"` + Valid bool `json:"valid"` +} + +type DistinguisedName struct { + Country []string `json:"country,omitempty"` + Organization []string `json:"organization,omitempty"` + OrganizationalUnit []string `json:"organizational_unit,omitempty"` + Locality []string `json:"locality,omitempty"` + Province []string `json:"province,omitempty"` + StreetAddress []string `json:"street_address,omitempty"` + PostalCode []string `json:"postal_code,omitempty"` + SerialNumber string `json:"serial_number,omitempty"` + CommonName string `json:"common_name,omitempty"` + ExtraNames map[string][]interface{} `json:"extra_names,omitempty"` + raw pkix.RDNSequence +} + +func (d DistinguisedName) String() string { + var parts []string + for _, dn := range d.raw { + v := strings.ReplaceAll(pkix.RDNSequence{dn}.String(), "\\,", ",") + parts = append(parts, v) + } + return strings.Join(parts, " ") +} + +func newDistinguishedName(seq pkix.RDNSequence) DistinguisedName { + var n pkix.Name + n.FillFromRDNSequence(&seq) + + var extraNames map[string][]interface{} + if len(n.ExtraNames) > 0 { + extraNames = make(map[string][]interface{}) + for _, tv := range n.ExtraNames { + oid := tv.Type.String() + if s, ok := tv.Value.(string); ok { + extraNames[oid] = append(extraNames[oid], s) + continue + } + if b, err := asn1.Marshal(tv.Value); err == nil { + extraNames[oid] = append(extraNames[oid], b) + continue + } + extraNames[oid] = append(extraNames[oid], escapeValue(tv.Value)) + } + } + + return DistinguisedName{ + Country: n.Country, + Organization: n.Organization, + OrganizationalUnit: n.OrganizationalUnit, + Locality: n.Locality, + Province: n.Province, + StreetAddress: n.StreetAddress, + PostalCode: n.PostalCode, + SerialNumber: n.SerialNumber, + CommonName: n.CommonName, + ExtraNames: extraNames, + raw: seq, + } +} + +type RevokedCertificate struct { + SerialNumber string `json:"serial_number"` + RevocationTime time.Time `json:"revocation_time"` + Extensions []Extension `json:"extensions,omitempty"` + SerialNumberBytes []byte `json:"-"` +} + +func newRevokedCertificate(c pkix.RevokedCertificate) RevokedCertificate { + var extensions []Extension + + return RevokedCertificate{ + SerialNumber: c.SerialNumber.String(), + RevocationTime: c.RevocationTime.UTC(), + Extensions: extensions, + SerialNumberBytes: c.SerialNumber.Bytes(), + } +} + +func spacer(i int) string { + return fmt.Sprintf("%"+strconv.Itoa(i)+"s", "") +} + +func printBytes(bs []byte, prefix string) { + for i, b := range bs { + if i == 0 { + fmt.Print(prefix) + } else if (i % 16) == 0 { + fmt.Print("\n" + prefix) + } + fmt.Printf("%02x", b) + if i != len(bs)-1 { + fmt.Print(":") + } + } + fmt.Println() +} + +func escapeValue(v interface{}) string { + s := fmt.Sprint(v) + escaped := make([]rune, 0, len(s)) + + for k, c := range s { + escape := false + + switch c { + case ',', '+', '"', '\\', '<', '>', ';': + escape = true + + case ' ': + escape = k == 0 || k == len(s)-1 + + case '#': + escape = k == 0 + } + + if escape { + escaped = append(escaped, '\\', c) + } else { + escaped = append(escaped, c) + } + } + + return string(escaped) +} diff --git a/command/crl/signature_algorithms.go b/command/crl/signature_algorithms.go new file mode 100644 index 00000000..47424b17 --- /dev/null +++ b/command/crl/signature_algorithms.go @@ -0,0 +1,148 @@ +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package crl + +import ( + "bytes" + "crypto/x509" + "crypto/x509/pkix" + "encoding/asn1" +) + +// OIDs for signature algorithms +var ( + oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2} + oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} + oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} + oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} + oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} + oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} + oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10} + oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} + oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2} + oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1} + oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} + oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} + oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} + oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} + + oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} + oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} + oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3} + + oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8} + + // oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA + // but it's specified by ISO. Microsoft's makecert.exe has been known + // to produce certificates with this OID. + oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29} +) + +var signatureAlgorithmDetails = []struct { + algo x509.SignatureAlgorithm + oid asn1.ObjectIdentifier +}{ + {x509.MD2WithRSA, oidSignatureMD2WithRSA}, + {x509.MD5WithRSA, oidSignatureMD5WithRSA}, + {x509.SHA1WithRSA, oidSignatureSHA1WithRSA}, + {x509.SHA1WithRSA, oidISOSignatureSHA1WithRSA}, + {x509.SHA256WithRSA, oidSignatureSHA256WithRSA}, + {x509.SHA384WithRSA, oidSignatureSHA384WithRSA}, + {x509.SHA512WithRSA, oidSignatureSHA512WithRSA}, + {x509.SHA256WithRSAPSS, oidSignatureRSAPSS}, + {x509.SHA384WithRSAPSS, oidSignatureRSAPSS}, + {x509.SHA512WithRSAPSS, oidSignatureRSAPSS}, + {x509.DSAWithSHA1, oidSignatureDSAWithSHA1}, + {x509.DSAWithSHA256, oidSignatureDSAWithSHA256}, + {x509.ECDSAWithSHA1, oidSignatureECDSAWithSHA1}, + {x509.ECDSAWithSHA256, oidSignatureECDSAWithSHA256}, + {x509.ECDSAWithSHA384, oidSignatureECDSAWithSHA384}, + {x509.ECDSAWithSHA512, oidSignatureECDSAWithSHA512}, + {x509.PureEd25519, oidSignatureEd25519}, +} + +type SignatureAlgorithm struct { + Name string `json:"name"` + OID string `json:"oid"` +} + +func (s SignatureAlgorithm) String() string { + if s.Name == "" { + return s.OID + } + return s.Name +} + +// pssParameters reflects the parameters in an AlgorithmIdentifier that +// specifies RSA PSS. See RFC 3447, Appendix A.2.3. +type pssParameters struct { + // The following three fields are not marked as + // optional because the default values specify SHA-1, + // which is no longer suitable for use in signatures. + Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"` + MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"` + SaltLength int `asn1:"explicit,tag:2"` + TrailerField int `asn1:"optional,explicit,tag:3,default:1"` +} + +func newSignatureAlgorithm(ai pkix.AlgorithmIdentifier) SignatureAlgorithm { + sa := SignatureAlgorithm{ + OID: ai.Algorithm.String(), + } + + if ai.Algorithm.Equal(oidSignatureEd25519) { + // RFC 8410, Section 3 + // > For all of the OIDs, the parameters MUST be absent. + if len(ai.Parameters.FullBytes) != 0 { + return sa + } + } + + if !ai.Algorithm.Equal(oidSignatureRSAPSS) { + for _, details := range signatureAlgorithmDetails { + if ai.Algorithm.Equal(details.oid) { + sa.Name = details.algo.String() + } + } + return sa + } + + // RSA PSS is special because it encodes important parameters + // in the Parameters. + + var params pssParameters + if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, ¶ms); err != nil { + return sa + } + + var mgf1HashFunc pkix.AlgorithmIdentifier + if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil { + return sa + } + + // PSS is greatly overburdened with options. This code forces them into + // three buckets by requiring that the MGF1 hash function always match the + // message hash function (as recommended in RFC 3447, Section 8.1), that the + // salt length matches the hash length, and that the trailer field has the + // default value. + if (len(params.Hash.Parameters.FullBytes) != 0 && !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes)) || + !params.MGF.Algorithm.Equal(oidMGF1) || + !mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) || + (len(mgf1HashFunc.Parameters.FullBytes) != 0 && !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes)) || + params.TrailerField != 1 { + return sa + } + + switch { + case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32: + sa.Name = x509.SHA256WithRSAPSS.String() + case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48: + sa.Name = x509.SHA384WithRSAPSS.String() + case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64: + sa.Name = x509.SHA512WithRSAPSS.String() + } + + return sa +} From acf9751f733143e53a034e591782b28fe53f243d Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Mon, 10 Jan 2022 16:10:24 -0800 Subject: [PATCH 23/52] Add crl validation using --ca or --from flags. Allow also the use of custom roots with --roots flag. --- command/crl/crl.go | 11 +- command/crl/inspect.go | 208 +++++++++++++++++++++++++++- command/crl/signature_algorithms.go | 46 +++--- 3 files changed, 239 insertions(+), 26 deletions(-) diff --git a/command/crl/crl.go b/command/crl/crl.go index 09e0e8c5..789bf8e9 100644 --- a/command/crl/crl.go +++ b/command/crl/crl.go @@ -11,8 +11,15 @@ func init() { Name: "crl", Usage: "initialize and manage a certificate revocation list", UsageText: "**step crl** [arguments] [global-flags] [subcommand-flags]", - Description: `**step crl** command group provides facilities to initialize manage a -certificate revocation list or CRL.`, + Description: `**step crl** command group provides facilities to create, manage and inspect a +certificate revocation list or CRL. + +## EXAMPLES + +Inspect a CRL: +''' +$ step crl inspect http://ca.example.com/crls/exampleca.crl +'''`, Subcommands: cli.Commands{ inspectCommand(), }, diff --git a/command/crl/inspect.go b/command/crl/inspect.go index 582470e9..4ebf9577 100644 --- a/command/crl/inspect.go +++ b/command/crl/inspect.go @@ -1,6 +1,12 @@ package crl import ( + "bytes" + "crypto" + "crypto/ecdsa" + "crypto/ed25519" + "crypto/rsa" + "crypto/tls" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" @@ -8,26 +14,59 @@ import ( "encoding/pem" "fmt" "io" + "net" "net/http" + "net/url" "os" "strconv" "strings" "time" "github.com/pkg/errors" + "github.com/smallstep/cli/flags" "github.com/smallstep/cli/utils" "github.com/urfave/cli" "go.step.sm/cli-utils/command" "go.step.sm/cli-utils/errs" + "go.step.sm/crypto/pemutil" + "go.step.sm/crypto/x509util" ) func inspectCommand() cli.Command { return cli.Command{ - Name: "inspect", - Action: command.ActionFunc(inspectAction), - Usage: "print certificate revocation list or CRL details in human readable format", - UsageText: `**step crl inspect** `, - Description: `**step crl inspect** prints the details of a certificate revocation list (CRL).`, + Name: "inspect", + Action: command.ActionFunc(inspectAction), + Usage: "print certificate revocation list or CRL details in human readable format", + UsageText: `**step crl inspect** `, + Description: `**step crl inspect** prints the details of a certificate revocation list (CRL). + +## POSITIONAL ARGUMENTS + + +: The file or URL where the CRL is. If <**--from**> is passed it will inspect +the certificate and extract the CRL distribution point from. + +## EXAMPLES + +Inspect a CRL: +''' +$ step crl inspect --insecure http://ca.example.com/crls/exampleca.crl +''' + +Inspect and validate a CRL in a file: +''' +$ step crl inspect -ca ca.crt exampleca.crl +''' + +Format the CRL in JSON: +''' +$ step crl inspect --insecure --format json exampleca.crl +''' + +Inspect the CRL from the CRL distribution point of a given url: +''' +$ step crl inspect --from https://www.google.com +'''`, Flags: []cli.Flag{ cli.StringFlag{ Name: "format", @@ -45,6 +84,31 @@ func inspectCommand() cli.Command { **pem** : Print output in PEM format.`, }, + cli.StringFlag{ + Name: "ca", + Usage: `The certificate used to validate the CRL.`, + }, + cli.BoolFlag{ + Name: "from", + Usage: `Extract CRL and CA from the URL passed as argument.`, + }, + cli.StringSliceFlag{ + Name: "roots", + Usage: `Root certificate(s) that will be used to verify the +authenticity of the remote server. + +: is a case-sensitive string and may be one of: + + **file** + : Relative or full path to a file. All certificates in the file will be used for path validation. + + **list of files** + : Comma-separated list of relative or full file paths. Every PEM encoded certificate from each file will be used for path validation. + + **directory** + : Relative or full path to a directory. Every PEM encoded certificate from each file in the directory will be used for path validation.`, + }, + flags.Insecure, }, } } @@ -54,6 +118,28 @@ func inspectAction(ctx *cli.Context) error { return err } + isFrom := ctx.Bool("from") + + // Require --insecure + if !isFrom && ctx.String("ca") == "" && !ctx.Bool("insecure") { + return errs.InsecureCommand(ctx) + } + + var tlsConfig *tls.Config + httpClient := http.Client{} + if roots := ctx.String("roots"); roots != "" { + pool, err := x509util.ReadCertPool(roots) + if err != nil { + return err + } + tlsConfig = &tls.Config{ + RootCAs: pool, + } + tr := http.DefaultTransport.(*http.Transport).Clone() + tr.TLSClientConfig = tlsConfig + httpClient.Transport = tr + } + crlFile := ctx.Args().First() if crlFile == "" { crlFile = "-" @@ -67,12 +153,58 @@ func inspectAction(ctx *cli.Context) error { } } + var caCerts []*x509.Certificate + if filename := ctx.String("ca"); filename != "" { + var err error + if caCerts, err = pemutil.ReadCertificateBundle(filename); err != nil { + return err + } + } + + if isFrom { + var bundle []*x509.Certificate + if isURL { + u, err := url.Parse(crlFile) + if err != nil { + return errors.Wrapf(err, "error parsing %s", crlFile) + } + if _, _, err := net.SplitHostPort(u.Host); err != nil { + u.Host = net.JoinHostPort(u.Host, "443") + } + conn, err := tls.Dial("tcp", u.Host, tlsConfig) + if err != nil { + return errors.Wrapf(err, "error connecting %s", crlFile) + } + bundle = conn.ConnectionState().PeerCertificates + } else { + var err error + if bundle, err = pemutil.ReadCertificateBundle(crlFile); err != nil { + return err + } + } + + isURL = true + if len(bundle[0].CRLDistributionPoints) == 0 { + return errors.Errorf("failed to get CRL distribution points from %s", crlFile) + } + + crlFile = bundle[0].CRLDistributionPoints[0] + if len(bundle) > 1 { + caCerts = append(caCerts, bundle[1:]...) + } + + if len(caCerts) == 0 && !ctx.Bool("insecure") { + println("foo") + return errs.InsecureCommand(ctx) + } + } + var ( b []byte err error ) if isURL { - resp, err := http.Get(crlFile) + resp, err := httpClient.Get(crlFile) if err != nil { return errors.Wrap(err, "error downloading crl") } @@ -95,6 +227,18 @@ func inspectAction(ctx *cli.Context) error { return errors.Wrap(err, "error parsing crl") } + if len(caCerts) > 0 { + for _, crt := range caCerts { + if (crt.KeyUsage&x509.KeyUsageCRLSign) == 0 || len(crt.SubjectKeyId) == 0 { + continue + } + if bytes.Equal(crt.SubjectKeyId, crl.authorityKeyID) { + crl.Signature.Valid = crl.Verify(crt) + break + } + } + } + switch ctx.String("format") { case "json": enc := json.NewEncoder(os.Stdout) @@ -114,6 +258,7 @@ func inspectAction(ctx *cli.Context) error { return nil } +// CRL is the JSON representation of a certificate revocation list. type CRL struct { Version int `json:"version"` SignatureAlgorithm SignatureAlgorithm `json:"signature_algorithm"` @@ -123,6 +268,8 @@ type CRL struct { RevokedCertificates []RevokedCertificate `json:"revoked_certificates"` Extensions []Extension `json:"extensions,omitempty"` Signature *Signature `json:"signature"` + authorityKeyID []byte + raw []byte } func ParseCRL(b []byte) (*CRL, error) { @@ -137,9 +284,16 @@ func ParseCRL(b []byte) (*CRL, error) { certs[i] = newRevokedCertificate(c) } + var issuerKeyID []byte extensions := make([]Extension, len(tcrl.Extensions)) for i, e := range tcrl.Extensions { extensions[i] = nexExtension(e) + if e.Id.Equal(oidExtensionAuthorityKeyID) { + var v authorityKeyID + if _, err := asn1.Unmarshal(e.Value, &v); err == nil { + issuerKeyID = v.ID + } + } } return &CRL{ @@ -155,12 +309,49 @@ func ParseCRL(b []byte) (*CRL, error) { Value: crl.SignatureValue.Bytes, Valid: false, }, + authorityKeyID: issuerKeyID, + raw: crl.TBSCertList.Raw, }, nil } +func (c *CRL) Verify(ca *x509.Certificate) bool { + now := time.Now() + if now.After(c.NextUpdate) || now.After(ca.NotAfter) { + return false + } + + var sum []byte + var hash crypto.Hash + if hash = c.SignatureAlgorithm.hash; hash > 0 { + h := hash.New() + h.Write(c.raw) + sum = h.Sum(nil) + } + + sig := c.Signature.Value + switch pub := ca.PublicKey.(type) { + case *ecdsa.PublicKey: + return ecdsa.VerifyASN1(pub, sum, sig) + case *rsa.PublicKey: + switch c.SignatureAlgorithm.algo { + case x509.SHA256WithRSAPSS, x509.SHA384WithRSAPSS, x509.SHA512WithRSAPSS: + return rsa.VerifyPSS(pub, hash, sum, sig, &rsa.PSSOptions{ + SaltLength: rsa.PSSSaltLengthAuto, + }) == nil + default: + return rsa.VerifyPKCS1v15(pub, hash, sum, sig) == nil + } + case ed25519.PublicKey: + return ed25519.Verify(pub, c.raw, sig) + default: + return false + } +} + func printCRL(crl *CRL) { fmt.Println("Certificate Revocation List (CRL):") fmt.Println(" Data:") + fmt.Printf(" Valid: %v\n", crl.Signature.Valid) fmt.Printf(" Version: %d (0x%x)\n", crl.Version, crl.Version-1) fmt.Println(" Signature algorithm:", crl.SignatureAlgorithm) fmt.Println(" Issuer:", crl.Issuer) @@ -193,16 +384,17 @@ func printCRL(crl *CRL) { } fmt.Println(" Signature Algorithm:", crl.Signature.SignatureAlgorithm) - fmt.Println(" Signature:") printBytes(crl.Signature.Value, spacer(8)) } +// Signature is the JSON representation of a CRL signature. type Signature struct { SignatureAlgorithm SignatureAlgorithm `json:"signature_algorithm"` Value []byte `json:"value"` Valid bool `json:"valid"` } +// DistinguisedName is the JSON representation of the CRL issuer. type DistinguisedName struct { Country []string `json:"country,omitempty"` Organization []string `json:"organization,omitempty"` @@ -217,6 +409,7 @@ type DistinguisedName struct { raw pkix.RDNSequence } +// String returns the one line representation of the distinguished name. func (d DistinguisedName) String() string { var parts []string for _, dn := range d.raw { @@ -262,6 +455,7 @@ func newDistinguishedName(seq pkix.RDNSequence) DistinguisedName { } } +// RevokedCertificate is the JSON representation of a certificate in a CRL. type RevokedCertificate struct { SerialNumber string `json:"serial_number"` RevocationTime time.Time `json:"revocation_time"` diff --git a/command/crl/signature_algorithms.go b/command/crl/signature_algorithms.go index 47424b17..0cfffd98 100644 --- a/command/crl/signature_algorithms.go +++ b/command/crl/signature_algorithms.go @@ -6,6 +6,7 @@ package crl import ( "bytes" + "crypto" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" @@ -43,29 +44,32 @@ var ( var signatureAlgorithmDetails = []struct { algo x509.SignatureAlgorithm oid asn1.ObjectIdentifier + hash crypto.Hash }{ - {x509.MD2WithRSA, oidSignatureMD2WithRSA}, - {x509.MD5WithRSA, oidSignatureMD5WithRSA}, - {x509.SHA1WithRSA, oidSignatureSHA1WithRSA}, - {x509.SHA1WithRSA, oidISOSignatureSHA1WithRSA}, - {x509.SHA256WithRSA, oidSignatureSHA256WithRSA}, - {x509.SHA384WithRSA, oidSignatureSHA384WithRSA}, - {x509.SHA512WithRSA, oidSignatureSHA512WithRSA}, - {x509.SHA256WithRSAPSS, oidSignatureRSAPSS}, - {x509.SHA384WithRSAPSS, oidSignatureRSAPSS}, - {x509.SHA512WithRSAPSS, oidSignatureRSAPSS}, - {x509.DSAWithSHA1, oidSignatureDSAWithSHA1}, - {x509.DSAWithSHA256, oidSignatureDSAWithSHA256}, - {x509.ECDSAWithSHA1, oidSignatureECDSAWithSHA1}, - {x509.ECDSAWithSHA256, oidSignatureECDSAWithSHA256}, - {x509.ECDSAWithSHA384, oidSignatureECDSAWithSHA384}, - {x509.ECDSAWithSHA512, oidSignatureECDSAWithSHA512}, - {x509.PureEd25519, oidSignatureEd25519}, + {x509.MD2WithRSA, oidSignatureMD2WithRSA, crypto.Hash(0)}, // no value for MD2 + {x509.MD5WithRSA, oidSignatureMD5WithRSA, crypto.MD5}, + {x509.SHA1WithRSA, oidSignatureSHA1WithRSA, crypto.SHA1}, + {x509.SHA1WithRSA, oidISOSignatureSHA1WithRSA, crypto.SHA1}, + {x509.SHA256WithRSA, oidSignatureSHA256WithRSA, crypto.SHA256}, + {x509.SHA384WithRSA, oidSignatureSHA384WithRSA, crypto.SHA384}, + {x509.SHA512WithRSA, oidSignatureSHA512WithRSA, crypto.SHA512}, + {x509.SHA256WithRSAPSS, oidSignatureRSAPSS, crypto.SHA256}, + {x509.SHA384WithRSAPSS, oidSignatureRSAPSS, crypto.SHA384}, + {x509.SHA512WithRSAPSS, oidSignatureRSAPSS, crypto.SHA512}, + {x509.DSAWithSHA1, oidSignatureDSAWithSHA1, crypto.SHA1}, + {x509.DSAWithSHA256, oidSignatureDSAWithSHA256, crypto.SHA256}, + {x509.ECDSAWithSHA1, oidSignatureECDSAWithSHA1, crypto.SHA1}, + {x509.ECDSAWithSHA256, oidSignatureECDSAWithSHA256, crypto.SHA256}, + {x509.ECDSAWithSHA384, oidSignatureECDSAWithSHA384, crypto.SHA384}, + {x509.ECDSAWithSHA512, oidSignatureECDSAWithSHA512, crypto.SHA512}, + {x509.PureEd25519, oidSignatureEd25519, crypto.Hash(0)}, } type SignatureAlgorithm struct { Name string `json:"name"` OID string `json:"oid"` + algo x509.SignatureAlgorithm + hash crypto.Hash } func (s SignatureAlgorithm) String() string { @@ -104,6 +108,8 @@ func newSignatureAlgorithm(ai pkix.AlgorithmIdentifier) SignatureAlgorithm { for _, details := range signatureAlgorithmDetails { if ai.Algorithm.Equal(details.oid) { sa.Name = details.algo.String() + sa.algo = details.algo + sa.hash = details.hash } } return sa @@ -138,10 +144,16 @@ func newSignatureAlgorithm(ai pkix.AlgorithmIdentifier) SignatureAlgorithm { switch { case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32: sa.Name = x509.SHA256WithRSAPSS.String() + sa.algo = x509.SHA256WithRSAPSS + sa.hash = crypto.SHA256 case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48: sa.Name = x509.SHA384WithRSAPSS.String() + sa.algo = x509.SHA384WithRSAPSS + sa.hash = crypto.SHA384 case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64: sa.Name = x509.SHA512WithRSAPSS.String() + sa.algo = x509.SHA512WithRSAPSS + sa.hash = crypto.SHA512 } return sa From 874e917cdb487694f00d18b9cc5eef2f15f127bd Mon Sep 17 00:00:00 2001 From: max furman Date: Mon, 10 Jan 2022 21:29:42 -0800 Subject: [PATCH 24/52] Update OIDC add error for duplicate ID - oidc uses only the clientID as the unique identifier. --- command/ca/provisioner/add.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/ca/provisioner/add.go b/command/ca/provisioner/add.go index 4ac44afa..000ae8f8 100644 --- a/command/ca/provisioner/add.go +++ b/command/ca/provisioner/add.go @@ -503,7 +503,7 @@ func addOIDCProvisioner(ctx *cli.Context, name string, provMap map[string]bool) if _, ok := provMap[p.GetID()]; !ok { provMap[p.GetID()] = true } else { - return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with name=%s and client-id=%s", p.GetName(), p.GetID()) + return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with client-id=%s", p.GetID()) } list = append(list, p) return From d3f5ff79bda4c6b60462aae3c6d2a7f80e3835f7 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Wed, 12 Jan 2022 11:11:51 -0800 Subject: [PATCH 25/52] Apply suggestions from code review Co-authored-by: Carl Tashian --- command/crl/crl.go | 2 +- command/crl/inspect.go | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/command/crl/crl.go b/command/crl/crl.go index 789bf8e9..1c5530f2 100644 --- a/command/crl/crl.go +++ b/command/crl/crl.go @@ -12,7 +12,7 @@ func init() { Usage: "initialize and manage a certificate revocation list", UsageText: "**step crl** [arguments] [global-flags] [subcommand-flags]", Description: `**step crl** command group provides facilities to create, manage and inspect a -certificate revocation list or CRL. +certificate revocation list (CRL). ## EXAMPLES diff --git a/command/crl/inspect.go b/command/crl/inspect.go index 4ebf9577..cef17344 100644 --- a/command/crl/inspect.go +++ b/command/crl/inspect.go @@ -36,9 +36,10 @@ func inspectCommand() cli.Command { return cli.Command{ Name: "inspect", Action: command.ActionFunc(inspectAction), - Usage: "print certificate revocation list or CRL details in human readable format", + Usage: "print certificate revocation list (CRL) details in human-readable format", UsageText: `**step crl inspect** `, - Description: `**step crl inspect** prints the details of a certificate revocation list (CRL). + Description: `**step crl inspect** validates and prints the details of a certificate revocation list (CRL). +A CRL is considered valid if its signature is valid, the CA is not expired, and the next update time is in the future. ## POSITIONAL ARGUMENTS From aaf870533b575c903228facd6547a7827f1ad873 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Wed, 12 Jan 2022 11:31:18 -0800 Subject: [PATCH 26/52] Fix format flag. --- command/crl/inspect.go | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/command/crl/inspect.go b/command/crl/inspect.go index cef17344..410e63fd 100644 --- a/command/crl/inspect.go +++ b/command/crl/inspect.go @@ -38,7 +38,7 @@ func inspectCommand() cli.Command { Action: command.ActionFunc(inspectAction), Usage: "print certificate revocation list (CRL) details in human-readable format", UsageText: `**step crl inspect** `, - Description: `**step crl inspect** validates and prints the details of a certificate revocation list (CRL). + Description: `**step crl inspect** validates and prints the details of a certificate revocation list (CRL). A CRL is considered valid if its signature is valid, the CA is not expired, and the next update time is in the future. ## POSITIONAL ARGUMENTS @@ -73,17 +73,17 @@ $ step crl inspect --from https://www.google.com Name: "format", Value: "text", Usage: `The output format for printing the introspection details. - - : is a string and must be one of: - - **text** - : Print output in unstructured text suitable for a human to read. - - **json** - : Print output in JSON format. - - **pem** - : Print output in PEM format.`, + +: is a string and must be one of: + + **text** + : Print output in unstructured text suitable for a human to read. + + **json** + : Print output in JSON format. + + **pem** + : Print output in PEM format.`, }, cli.StringFlag{ Name: "ca", From e1dc23ce7328f3200f1bd8133beb77ab5ad0946b Mon Sep 17 00:00:00 2001 From: Josef Johansson Date: Thu, 13 Jan 2022 10:13:15 +0100 Subject: [PATCH 27/52] utils/cautils/acmeutils.go: Allow system Root CA store on private CA Change the way Root CA is handled, make sure that private CA can use system Root CA as well, in case it's Root CA is provided via the system Root CA. Old behavior: If letsencrypt: Use system Root CAs Else Use either --root or .step/certs/root_ca.crt New behavior: If --acme If --root or .step/certs/root_ca.crt merge system Root CAs with local Root CA Else use system Root CAs Else If --root or .step/certs/root_ca.crt use local Root CA Else use system Root CAs Signed-off-by: Josef Johansson --- utils/cautils/acmeutils.go | 58 ++++++++++++++++++++++++++++++-------- 1 file changed, 47 insertions(+), 11 deletions(-) diff --git a/utils/cautils/acmeutils.go b/utils/cautils/acmeutils.go index c548fb13..aadd618e 100644 --- a/utils/cautils/acmeutils.go +++ b/utils/cautils/acmeutils.go @@ -3,11 +3,13 @@ package cautils import ( "context" "crypto/rand" + "crypto/tls" "crypto/x509" "crypto/x509/pkix" "encoding/json" "encoding/pem" "fmt" + "io/ioutil" "net" "net/http" "os" @@ -361,6 +363,43 @@ func newACMEFlow(ctx *cli.Context, ops ...acmeFlowOp) (*acmeFlow, error) { return af, nil } +func (af *acmeFlow) getRootCAs(mergeRootCAs bool) (ca.ClientOption, error) { + root := "" + if af.ctx.IsSet("root") { + root = af.ctx.String("root") + // If there's an error reading the local root ca, ignore the error and use the system store + } else if _, err := os.Stat(pki.GetRootCAPath()); err == nil { + root = pki.GetRootCAPath() + } + + // 1. Merge local RootCA with system store + if mergeRootCAs && len(root) > 0 { + rootCAs, err := x509.SystemCertPool() + if err != nil || rootCAs == nil { + rootCAs = x509.NewCertPool() + } + + cert, err := ioutil.ReadFile(root) + if err != nil { + return ca.WithRootFile(root), errors.Wrap(err, "failed to read local root ca") + } + + if ok := rootCAs.AppendCertsFromPEM(cert); !ok { + return ca.WithRootFile(root), errors.New("failed to append local root ca to system cert pool") + } + + return ca.WithTransport(&http.Transport{TLSClientConfig: &tls.Config{RootCAs: rootCAs}}), nil + } + + // Use local Root CA only + if len(root) > 0 { + return ca.WithRootFile(root), nil + } + + // Use system store only + return ca.WithTransport(http.DefaultTransport), nil +} + func (af *acmeFlow) GetCertificate() ([]*x509.Certificate, error) { dnsNames, ips, err := validateSANsForACME(af.sans) if err != nil { @@ -385,14 +424,20 @@ func (af *acmeFlow) GetCertificate() ([]*x509.Certificate, error) { orderPayload []byte clientOps []ca.ClientOption ) + + ops, err := af.getRootCAs(af.ctx.IsSet("acme")) + if err != nil { + return nil, err + } + + clientOps = append(clientOps, ops) + if strings.Contains(af.acmeDir, "letsencrypt") { // LetsEncrypt does not support NotBefore and NotAfter attributes in orders. if af.ctx.IsSet("not-before") || af.ctx.IsSet("not-after") { return nil, errors.New("LetsEncrypt public CA does not support NotBefore/NotAfter " + "attributes for certificates. Instead, each certificate has a default lifetime of 3 months.") } - // Use default transport for public CAs - clientOps = append(clientOps, ca.WithTransport(http.DefaultTransport)) // LetsEncrypt requires that the Common Name of the Certificate also be // represented as a DNSName in the SAN extension, and therefore must be // authorized as part of the ACME order. @@ -416,15 +461,6 @@ func (af *acmeFlow) GetCertificate() ([]*x509.Certificate, error) { return nil, errors.Wrap(err, "error marshaling new letsencrypt order request") } } else { - // If the CA is not public then a root file is required. - root := af.ctx.String("root") - if root == "" { - root = pki.GetRootCAPath() - if _, err := os.Stat(root); err != nil { - return nil, errs.RequiredFlag(af.ctx, "root") - } - } - clientOps = append(clientOps, ca.WithRootFile(root)) // parse times or durations nbf, naf, err := flags.ParseTimeDuration(af.ctx) if err != nil { From 82fec73d83f70366e72623500cf88961a89e930d Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 13 Jan 2022 13:45:08 -0800 Subject: [PATCH 28/52] A few style and linter fixes on truststore PR --- utils/cautils/acmeutils.go | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/utils/cautils/acmeutils.go b/utils/cautils/acmeutils.go index aadd618e..0eeb51d5 100644 --- a/utils/cautils/acmeutils.go +++ b/utils/cautils/acmeutils.go @@ -9,7 +9,6 @@ import ( "encoding/json" "encoding/pem" "fmt" - "io/ioutil" "net" "net/http" "os" @@ -363,7 +362,7 @@ func newACMEFlow(ctx *cli.Context, ops ...acmeFlowOp) (*acmeFlow, error) { return af, nil } -func (af *acmeFlow) getRootCAs(mergeRootCAs bool) (ca.ClientOption, error) { +func (af *acmeFlow) getClientTruststoreOption(mergeRootCAs bool) (ca.ClientOption, error) { root := "" if af.ctx.IsSet("root") { root = af.ctx.String("root") @@ -379,13 +378,13 @@ func (af *acmeFlow) getRootCAs(mergeRootCAs bool) (ca.ClientOption, error) { rootCAs = x509.NewCertPool() } - cert, err := ioutil.ReadFile(root) + cert, err := os.ReadFile(root) if err != nil { - return ca.WithRootFile(root), errors.Wrap(err, "failed to read local root ca") + return nil, errors.Wrap(err, "failed to read local root ca") } if ok := rootCAs.AppendCertsFromPEM(cert); !ok { - return ca.WithRootFile(root), errors.New("failed to append local root ca to system cert pool") + return nil, errors.New("failed to append local root ca to system cert pool") } return ca.WithTransport(&http.Transport{TLSClientConfig: &tls.Config{RootCAs: rootCAs}}), nil @@ -425,7 +424,7 @@ func (af *acmeFlow) GetCertificate() ([]*x509.Certificate, error) { clientOps []ca.ClientOption ) - ops, err := af.getRootCAs(af.ctx.IsSet("acme")) + ops, err := af.getClientTruststoreOption(af.ctx.IsSet("acme")) if err != nil { return nil, err } From 840d22f64b0a269512c3cb0ae47c13c31688d42e Mon Sep 17 00:00:00 2001 From: max furman Date: Mon, 17 Jan 2022 13:58:09 -0800 Subject: [PATCH 29/52] Add arm5 build to goreleaser --- .goreleaser.yml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.goreleaser.yml b/.goreleaser.yml index 694befe2..f54dbabb 100644 --- a/.goreleaser.yml +++ b/.goreleaser.yml @@ -9,7 +9,7 @@ before: # - go generate ./... builds: - - + - id: default env: - CGO_ENABLED=0 @@ -20,6 +20,7 @@ builds: - linux_386 - linux_amd64 - linux_arm64 + - linux_arm_5 - linux_arm_6 - linux_arm_7 - linux_mips @@ -78,7 +79,7 @@ nfpms: # Useful tools for debugging .debs: # List file contents: dpkg -c dist/step_...deb # Package metadata: dpkg --info dist/step_....deb - # + # - builds: - nfpm @@ -89,7 +90,7 @@ nfpms: maintainer: Smallstep description: > step-cli lets you build, operate, and automate Public Key Infrastructure (PKI) systems and workflows. - + It's a swiss army knife for authenticated encryption (X.509, TLS), single sign-on (OAuth OIDC, SAML), multi-factor authentication (OATH OTP, FIDO U2F), encryption mechanisms (JSON Web Encryption, NaCl), and verifiable claims (JWT, SAML assertions). license: Apache 2.0 section: utils From 0ef45eadff6f09b13e1e1f6b938528c3fff9f1b3 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Wed, 19 Jan 2022 15:28:09 -0800 Subject: [PATCH 30/52] Add clarification for the listen port in `step ca init --helm` Fixes smallstep/helm-charts#82 --- command/ca/init.go | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/command/ca/init.go b/command/ca/init.go index 5bcd6ded..71721ab5 100644 --- a/command/ca/init.go +++ b/command/ca/init.go @@ -512,7 +512,11 @@ func initAction(ctx *cli.Context) (err error) { } var address string - ui.Println("What IP and port will your new CA bind to?", ui.WithValue(ctx.String("address"))) + if helm { + ui.Println("What IP and port will your new CA bind to, it should match service.targetPort?", ui.WithValue(ctx.String("address"))) + } else { + ui.Println("What IP and port will your new CA bind to?", ui.WithValue(ctx.String("address"))) + } address, err = ui.Prompt("(e.g. :443 or 127.0.0.1:443)", ui.WithValidateFunc(ui.Address()), ui.WithValue(ctx.String("address"))) if err != nil { From 54bfd34689f56668d2acf1b689666d08681f92d5 Mon Sep 17 00:00:00 2001 From: Carl Tashian Date: Wed, 19 Jan 2022 15:50:38 -0800 Subject: [PATCH 31/52] Quick copy change --- command/ca/init.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/ca/init.go b/command/ca/init.go index 71721ab5..958a37b2 100644 --- a/command/ca/init.go +++ b/command/ca/init.go @@ -513,7 +513,7 @@ func initAction(ctx *cli.Context) (err error) { var address string if helm { - ui.Println("What IP and port will your new CA bind to, it should match service.targetPort?", ui.WithValue(ctx.String("address"))) + ui.Println("What IP and port will your new CA bind to (it should match service.targetPort)?", ui.WithValue(ctx.String("address"))) } else { ui.Println("What IP and port will your new CA bind to?", ui.WithValue(ctx.String("address"))) } From 3f451de030aa81edc3cb19d50a6bec09f42fbdd0 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Fri, 21 Jan 2022 00:15:09 +0100 Subject: [PATCH 32/52] Implement $PAGER for paging through ACME EAB keys --- command/ca/acme/eab/add.go | 24 +++++-------- command/ca/acme/eab/eab.go | 9 +++-- command/ca/acme/eab/list.go | 65 ++++++++++++++++++++++++++--------- command/ca/acme/eab/remove.go | 9 ++--- go.mod | 15 ++++---- go.sum | 63 +++++++++++++++++++++++++++++++++ 6 files changed, 137 insertions(+), 48 deletions(-) diff --git a/command/ca/acme/eab/add.go b/command/ca/acme/eab/add.go index 57fe225a..7bab7727 100644 --- a/command/ca/acme/eab/add.go +++ b/command/ca/acme/eab/add.go @@ -3,8 +3,8 @@ package eab import ( "fmt" "os" - "text/tabwriter" + "github.com/pkg/errors" adminAPI "github.com/smallstep/certificates/authority/admin/api" "github.com/smallstep/cli/flags" "github.com/smallstep/cli/utils/cautils" @@ -17,7 +17,7 @@ func addCommand() cli.Command { Name: "add", Action: cli.ActionFunc(addAction), Usage: "add ACME External Account Binding Key", - UsageText: `**step beta ca acme eab add** + UsageText: `**step beta ca acme eab add** [] [**--admin-cert**=] [**--admin-key**=] [**--admin-provisioner**=] [**--admin-subject**=] [**--password-file**=] [**--ca-url**=] [**--root**=] @@ -71,30 +71,24 @@ func addAction(ctx *cli.Context) (err error) { client, err := cautils.NewAdminClient(ctx) if err != nil { - return err + return errors.Wrap(err, "error creating admin client") } eak, err := client.CreateExternalAccountKey(provisioner, &adminAPI.CreateExternalAccountKeyRequest{ Reference: reference, }) if err != nil { - return err + return errors.Wrap(err, "error creating ACME EAB key") } - cliEAK, err := toCLI(ctx, client, eak) - if err != nil { - return err - } + cliEAK := toCLI(ctx, client, eak) // TODO(hs): JSON output, so that executing this command can be more easily automated? - w := new(tabwriter.Writer) - // Format in tab-separated columns with a tab stop of 8. - w.Init(os.Stdout, 0, 8, 1, '\t', 0) - - fmt.Fprintln(w, "Key ID\tProvisioner\tReference\tKey (base64, raw url encoded)") - fmt.Fprintf(w, "%s\t%s \t%s \t%s\n", cliEAK.id, cliEAK.provisioner, cliEAK.reference, cliEAK.key) - w.Flush() + out := os.Stdout + format := "%-36s%-28s%-48s%s\n" + fmt.Fprintf(out, format, "Key ID", "Provisioner", "Key (base64, raw url encoded)", "Reference") + fmt.Fprintf(out, format, cliEAK.id, cliEAK.provisioner, cliEAK.key, cliEAK.reference) return nil } diff --git a/command/ca/acme/eab/eab.go b/command/ca/acme/eab/eab.go index ef9b4cc7..5fecbcfb 100644 --- a/command/ca/acme/eab/eab.go +++ b/command/ca/acme/eab/eab.go @@ -2,7 +2,6 @@ package eab import ( "encoding/base64" - "time" "github.com/smallstep/certificates/ca" "github.com/urfave/cli" @@ -14,12 +13,12 @@ type cliEAK struct { provisioner string reference string key string - createdAt time.Time + createdAt string boundAt string account string } -func toCLI(ctx *cli.Context, client *ca.AdminClient, eak *linkedca.EABKey) (*cliEAK, error) { +func toCLI(ctx *cli.Context, client *ca.AdminClient, eak *linkedca.EABKey) *cliEAK { boundAt := "" if !eak.BoundAt.AsTime().IsZero() { boundAt = eak.BoundAt.AsTime().Format("2006-01-02 15:04:05 -07:00") @@ -29,10 +28,10 @@ func toCLI(ctx *cli.Context, client *ca.AdminClient, eak *linkedca.EABKey) (*cli provisioner: eak.Provisioner, reference: eak.Reference, key: base64.RawURLEncoding.Strict().EncodeToString(eak.HmacKey), - createdAt: eak.CreatedAt.AsTime(), + createdAt: eak.CreatedAt.AsTime().Format("2006-01-02 15:04:05 -07:00"), boundAt: boundAt, account: eak.Account, - }, nil + } } // Command returns the eab subcommand. diff --git a/command/ca/acme/eab/list.go b/command/ca/acme/eab/list.go index b2719535..ac89baee 100644 --- a/command/ca/acme/eab/list.go +++ b/command/ca/acme/eab/list.go @@ -2,9 +2,11 @@ package eab import ( "fmt" + "io" "os" - "text/tabwriter" + "os/exec" + "github.com/pkg/errors" "github.com/smallstep/cli/flags" "github.com/smallstep/cli/utils/cautils" "github.com/urfave/cli" @@ -16,7 +18,7 @@ func listCommand() cli.Command { Name: "list", Action: cli.ActionFunc(listAction), Usage: "list all ACME External Account Binding Keys", - UsageText: `**step beta ca acme eab list** + UsageText: `**step beta ca acme eab list** [] [**--admin-cert**=] [**--admin-key**=] [**--admin-provisioner**=] [**--admin-subject**=] [**--password-file**=] [**--ca-url**=] [**--root**=] @@ -31,7 +33,9 @@ func listCommand() cli.Command { flags.Root, flags.Context, }, - Description: `**step beta ca acme eab list** lists all ACME External Account Binding Keys. + Description: `**step beta ca acme eab list** lists all ACME External Account Binding (EAB) Keys. + +Output will go to stdout by default. If many EAB keys are stored in the ACME provisioner, output will be sent to $PAGER (when set). ## POSITIONAL ARGUMENTS @@ -39,19 +43,19 @@ func listCommand() cli.Command { : Name of the provisioner to list ACME EAB keys for -: (Optional) Reference (from external system) for the key to be created +: (Optional) reference (from external system) for the key to be listed ## EXAMPLES List all ACME External Account Binding Keys: ''' -$ step beta ca acme eab list my_provisioner +$ step beta ca acme eab list my_acme_provisioner ''' Show ACME External Account Binding Key with specific reference: ''' -$ step beta ca acme eab list my_provisioner my_reference +$ step beta ca acme eab list my_acme_provisioner my_reference ''' `, } @@ -72,29 +76,56 @@ func listAction(ctx *cli.Context) (err error) { client, err := cautils.NewAdminClient(ctx) if err != nil { - return err + return errors.Wrap(err, "error creating admin client") } eaks, err := client.GetExternalAccountKeys(provisioner, reference) if err != nil { - return err + return errors.Wrap(err, "error retrieving ACME EAB keys") } - w := new(tabwriter.Writer) - // Format in tab-separated columns with a tab stop of 8. - w.Init(os.Stdout, 0, 8, 1, '\t', 0) + if len(eaks) == 0 { + fmt.Printf("No ACME EAB keys stored for provisioner %s\n", provisioner) + return nil + } - fmt.Fprintln(w, "Key ID\tProvisioner\tReference\tKey (masked)\tCreated At\tBound At\tAccount") + var out io.WriteCloser + var cmd *exec.Cmd - for _, k := range eaks { - cliEAK, err := toCLI(ctx, client, k) + // prepare the $PAGER command to run + pager := os.Getenv("PAGER") + if pager != "" && len(eaks) > 15 { // use $PAGER only when more than 15 results are returned + cmd = exec.Command(pager) + var err error + out, err = cmd.StdinPipe() if err != nil { - return err + return errors.Wrap(err, "error setting stdin") } - fmt.Fprintf(w, "%s\t%s \t%s \t%s \t%s \t%s \t%s\n", cliEAK.id, cliEAK.provisioner, cliEAK.reference, "*****", cliEAK.createdAt.Format("2006-01-02 15:04:05 -07:00"), cliEAK.boundAt, cliEAK.account) + cmd.Stdout = os.Stdout + if err := cmd.Start(); err != nil { + return errors.Wrap(err, "unable to start $PAGER") + } + } else { + out = os.Stdout } - w.Flush() + format := "%-36s%-28s%-16s%-30s%-30s%-36s%s\n" + fmt.Fprintf(out, format, "Key ID", "Provisioner", "Key (masked)", "Created At", "Bound At", "Account", "Reference") + for _, k := range eaks { + cliEAK := toCLI(ctx, client, k) + _, err = fmt.Fprintf(out, format, cliEAK.id, cliEAK.provisioner, "*****", cliEAK.createdAt, cliEAK.boundAt, cliEAK.account, cliEAK.reference) + if err != nil { + return errors.Wrap(err, "error writing to output") + } + } + + out.Close() + + if cmd != nil { + if err := cmd.Wait(); err != nil { + return errors.Wrap(err, "error waiting for $PAGER") + } + } return nil } diff --git a/command/ca/acme/eab/remove.go b/command/ca/acme/eab/remove.go index 9da54d05..7a27281c 100644 --- a/command/ca/acme/eab/remove.go +++ b/command/ca/acme/eab/remove.go @@ -1,6 +1,7 @@ package eab import ( + "github.com/pkg/errors" "github.com/smallstep/cli/flags" "github.com/smallstep/cli/ui" "github.com/smallstep/cli/utils/cautils" @@ -40,9 +41,9 @@ func removeCommand() cli.Command { ## EXAMPLES -Remove ACME EAB Key with Key ID "zFGdKC1sHmNf3Wsx3OujY808chxwEdmr": +Remove ACME EAB Key with Key ID "zFGdKC1sHmNf3Wsx3OujY808chxwEdmr" from my_acme_provisioner: ''' -$ step beta ca acme eab remove zFGdKC1sHmNf3Wsx3OujY808chxwEdmr +$ step beta ca acme eab remove my_acme_provisioner zFGdKC1sHmNf3Wsx3OujY808chxwEdmr ''' `, } @@ -59,12 +60,12 @@ func removeAction(ctx *cli.Context) error { client, err := cautils.NewAdminClient(ctx) if err != nil { - return err + return errors.Wrap(err, "error creating admin client") } err = client.RemoveExternalAccountKey(provisioner, keyID) if err != nil { - return err + return errors.Wrap(err, "error removing ACME EAB key") } ui.Println("Key was deleted successfully!") diff --git a/go.mod b/go.mod index 67f0d750..71898b79 100644 --- a/go.mod +++ b/go.mod @@ -26,19 +26,20 @@ require ( github.com/urfave/cli v1.22.5 go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 go.step.sm/cli-utils v0.7.0 - go.step.sm/crypto v0.13.0 - go.step.sm/linkedca v0.8.0 - golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 - golang.org/x/net v0.0.0-20210913180222-943fd674d43e - golang.org/x/sys v0.0.0-20211031064116-611d5d643895 - golang.org/x/term v0.0.0-20210503060354-a79de5458b56 + go.step.sm/crypto v0.14.0 + go.step.sm/linkedca v0.9.0 + golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 + golang.org/x/net v0.0.0-20211216030914-fe4d6282115f + golang.org/x/sys v0.0.0-20211103235746-7861aae1554b + golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 google.golang.org/protobuf v1.27.1 gopkg.in/square/go-jose.v2 v2.6.0 howett.net/plist v1.0.0 // indirect software.sslmate.com/src/go-pkcs12 v0.0.0-20201103104416-57fc603b7f52 ) -// replace github.com/smallstep/certificates => ../certificates +replace github.com/smallstep/certificates => ../certificates + // replace github.com/smallstep/certinfo => ../certinfo // replace go.step.sm/linkedca => ../linkedca // replace go.step.sm/cli-utils => ../cli-utils diff --git a/go.sum b/go.sum index dfef62c8..15f6ec81 100644 --- a/go.sum +++ b/go.sum @@ -55,6 +55,8 @@ contrib.go.opencensus.io/exporter/stackdriver v0.13.7/go.mod h1:huNtlWx75MwO7qMs contrib.go.opencensus.io/integrations/ocsql v0.1.4/go.mod h1:8DsSdjz3F+APR+0z0WkU1aRorQCFfRxvqjUUPMbF3fE= contrib.go.opencensus.io/resource v0.1.1/go.mod h1:F361eGI91LCmW1I/Saf+rX0+OFcigGlFvXwEGEnkRLA= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +filippo.io/edwards25519 v1.0.0-rc.1 h1:m0VOOB23frXZvAOK44usCgLWvtsxIoMCTBGJZlpmGfU= +filippo.io/edwards25519 v1.0.0-rc.1/go.mod h1:N1IkdkCkiLB6tki+MYJoSx2JTY9NUlxZE7eHn5EwJns= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIoKjsnZuH8vjyaysT/ses3EvZeaV/1UkF2M= github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-amqp-common-go/v2 v2.1.0/go.mod h1:R8rea+gJRuJR6QxTir/XuEd+YuKoUiazDC/N96FiDEU= @@ -132,6 +134,7 @@ github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRF github.com/alecthomas/units v0.0.0-20190717042225-c3de453c63f4/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= github.com/alecthomas/units v0.0.0-20190924025748-f65c72e2690d/go.mod h1:rBZYJk541a8SKzHPHnH3zbiI+7dagKZ0cgpgrD7Fyho= github.com/anmitsu/go-shlex v0.0.0-20161002113705-648efa622239/go.mod h1:2FmKhYUyUczH0OGQWaF5ceTx0UBShxjsH6f8oGKYe2c= +github.com/anmitsu/go-shlex v0.0.0-20200514113438-38f4b401e2be/go.mod h1:ySMOLuWl6zY27l47sB3qLNK6tF2fkHG55UZxx8oIVo4= github.com/antihax/optional v1.0.0/go.mod h1:uupD/76wgC+ih3iEmQUL+0Ugr19nfwCT1kdvxnR2qWY= github.com/aokoli/goutils v1.0.1/go.mod h1:SijmP0QR8LtwsmDs8Yii5Z/S4trXFGFC2oO5g9DP+DQ= github.com/apache/beam v2.28.0+incompatible/go.mod h1:/8NX3Qi8vGstDLLaeaU7+lzVEu/ACaQhYjeefzQ0y1o= @@ -146,6 +149,7 @@ github.com/armon/circbuf v0.0.0-20150827004946-bbbad097214e/go.mod h1:3U/XgcO3hC github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/armon/go-metrics v0.0.0-20180917152333-f0300d1749da/go.mod h1:Q73ZrmVTwzkszR9V5SSuryQ31EELlFMUz1kKyl939pY= github.com/armon/go-radix v0.0.0-20180808171621-7fddfc383310/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= +github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8= github.com/armon/go-socks5 v0.0.0-20160902184237-e75332964ef5/go.mod h1:wHh0iHkYZB8zMSxRWpUBQtwG5a7fFgvEO+odwuTv2gs= github.com/aryann/difflib v0.0.0-20170710044230-e206f873d14a/go.mod h1:DAHtR1m6lCRdSC2Tm3DSWRPvIPr6xNKyeHdqDQSQT+A= github.com/asaskevich/govalidator v0.0.0-20180720115003-f9ffefc3facf h1:eg0MeVzsP1G42dRafH3vf+al2vQIJU0YHX+1Tw87oco= @@ -192,6 +196,8 @@ github.com/cespare/xxhash v1.1.0 h1:a6HrQnmkObjyL+Gs60czilIUGqrzKutQD6XZog3p+ko= github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= github.com/cespare/xxhash/v2 v2.1.1 h1:6MnRN8NT7+YBpUIWxHtefFZOKTAPgGjpQSxqLNn0+qY= github.com/cespare/xxhash/v2 v2.1.1/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= +github.com/cespare/xxhash/v2 v2.1.2 h1:YRXhKfTDauu4ajMg1TPgFO5jnlC2HCbmLXMcTG5cbYE= +github.com/cespare/xxhash/v2 v2.1.2/go.mod h1:VGX0DQ3Q6kWi7AoAeZDth3/j3BFtOZR5XLFGgcrjCOs= github.com/chzyer/logex v1.1.10 h1:Swpa1K6QvQznwJRcfTfQJmTE72DqScAa40E+fbHEXEE= github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e h1:fY5BOSpyZCqRo5OhCuC+XN+r/bBCmeuuJtjz+bCNIf8= @@ -241,6 +247,7 @@ github.com/creack/pty v1.1.7/go.mod h1:lj5s0c3V2DBrqTV7llrYr5NG6My20zk30Fl46Y7Do github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= github.com/creack/pty v1.1.11 h1:07n33Z8lZxZ2qwegKbObQohDhXDQxiMMz1NOUGYlesw= github.com/creack/pty v1.1.11/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E= +github.com/cyberdelia/go-metrics-graphite v0.0.0-20161219230853-39f87cc3b432/go.mod h1:xwIwAxMvYnVrGJPe2FKx5prTrnAjGOD8zvDOnxnrrkM= github.com/davecgh/go-spew v0.0.0-20161028175848-04cdfd42973b/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= @@ -287,6 +294,7 @@ github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5Kwzbycv github.com/fatih/color v1.9.0 h1:8xPHl4/q1VyqGIPif1F+1V3Y3lSmrq01EabUW3CoW5s= github.com/fatih/color v1.9.0/go.mod h1:eQcE1qtQxscV5RaZvpXrrb8Drkc3/DdQ+uUYCNjL+zU= github.com/flynn/go-shlex v0.0.0-20150515145356-3f9db97f8568/go.mod h1:xEzjJPgXI435gkrCt3MPfRiAkVrwSbHsst4LCFVfpJc= +github.com/flynn/noise v1.0.0/go.mod h1:xbMo+0i6+IGbYdJhF31t2eR1BIU0CYc12+BNAKwUTag= github.com/form3tech-oss/jwt-go v3.2.2+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= github.com/form3tech-oss/jwt-go v3.2.3+incompatible h1:7ZaBxOI7TMoYBfyA3cQHErNNyAWIKUMIwqxEtgHOs5c= github.com/form3tech-oss/jwt-go v3.2.3+incompatible/go.mod h1:pbq4aXjuKjdthFRnoDwaVPLA+WlJuPGy+QneDUgJi2k= @@ -405,6 +413,7 @@ github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO github.com/google/go-replayers/grpcreplay v0.1.0/go.mod h1:8Ig2Idjpr6gifRd6pNVggX6TC1Zw6Jx74AKp7QNH2QE= github.com/google/go-replayers/httpreplay v0.1.0/go.mod h1:YKZViNhiGgqdBlUbI2MwGpq4pXxNmhJLPHQ7cv2b5no= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= +github.com/google/gopacket v1.1.19/go.mod h1:iJ8V8n6KS+z2U1A8pUwu8bW5SyEMkXJB8Yo/Vo+TKTo= github.com/google/licenseclassifier v0.0.0-20210325184830-bb04aff29e72/go.mod h1:qsqn2hxC+vURpyBRygGUuinTO42MFRLcsmQ/P8v94+M= github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= github.com/google/martian v2.1.1-0.20190517191504-25dcb96d9e51+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= @@ -546,6 +555,7 @@ github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfV github.com/juju/ratelimit v1.0.1/go.mod h1:qapgC/Gy+xNh9UxzV13HGGl/6UXNN+ct+vwSgWNm/qk= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= +github.com/kardianos/service v1.2.0/go.mod h1:CIMRFEJVL+0DS1a3Nx06NaMn4Dz63Ng6O7dl0qH0zVM= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs= github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8= github.com/kevinburke/ssh_config v0.0.0-20190725054713-01f96b0aa0cd/go.mod h1:CT57kijsi8u/K/BOFA39wgDQJ9CxiF4nAY/ojJ6r6mM= @@ -574,6 +584,8 @@ github.com/letsencrypt/pkcs11key/v4 v4.0.0/go.mod h1:EFUvBDay26dErnNb70Nd0/VW3tJ github.com/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lightstep/lightstep-tracer-common/golang/gogo v0.0.0-20190605223551-bc2310a04743/go.mod h1:qklhhLq1aX+mtWk9cPHPzaBjWImj5ULL6C7HFJtXQMM= github.com/lightstep/lightstep-tracer-go v0.18.1/go.mod h1:jlF1pusYV4pidLvZ+XD0UBX0ZE6WURAspgAczcDHrL4= +github.com/lxn/walk v0.0.0-20210112085537-c389da54e794/go.mod h1:E23UucZGqpuUANJooIbHWCufXvOcT6E7Stq81gU+CSQ= +github.com/lxn/win v0.0.0-20210218163916-a377121e959e/go.mod h1:KxxjdtRkfNoYDCUP5ryK7XJJNTnpC8atvtmTheChOtk= github.com/lyft/protoc-gen-validate v0.0.13/go.mod h1:XbGvPuh87YZc5TdIa2/I4pLk0QoUACkjt2znoq26NVQ= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/magiconair/properties v1.8.1/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -608,6 +620,7 @@ github.com/mgutz/ansi v0.0.0-20200706080929-d51e80ef957d/go.mod h1:01TrycV0kFyex github.com/micromdm/scep/v2 v2.1.0 h1:2fS9Rla7qRR266hvUoEauBJ7J6FhgssEiq2OkSKXmaU= github.com/micromdm/scep/v2 v2.1.0/go.mod h1:BkF7TkPPhmgJAMtHfP+sFTKXmgzNJgLQlvvGoOExBcc= github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg= +github.com/miekg/dns v1.1.43/go.mod h1:+evo5L0630/F6ca/Z9+GAqzhjGyn8/c+TBaOyfEl0V4= github.com/miekg/pkcs11 v1.0.2/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3-0.20190429190417-a667d056470f/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= github.com/miekg/pkcs11 v1.0.3/go.mod h1:XsNlhZGX73bx86s2hdc/FuaLm2CPZJemRLMA+WTFxgs= @@ -646,6 +659,7 @@ github.com/nats-io/nats.go v1.9.1/go.mod h1:ZjDU1L/7fJ09jvUSRVBR2e7+RnLiiIQyqyzE github.com/nats-io/nkeys v0.1.0/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nkeys v0.1.3/go.mod h1:xpnFELMwJABBLVhffcfd1MZx6VsNRFpEugbxziKVo7w= github.com/nats-io/nuid v1.0.1/go.mod h1:19wcPz3Ph3q0Jbyiqsd0kePYG7A95tJPxeL+1OSON2c= +github.com/nbrownus/go-metrics-prometheus v0.0.0-20210712211119-974a6260965f/go.mod h1:nwPd6pDNId/Xi16qtKrFHrauSwMNuvk+zcjk89wrnlA= github.com/newrelic/go-agent v2.15.0+incompatible h1:IB0Fy+dClpBq9aEoIrLyQXzU34JyI1xVTanPLB/+jvU= github.com/newrelic/go-agent v2.15.0+incompatible/go.mod h1:a8Fv1b/fYhFSReoTU6HDkTYIMZeSVNffmoS726Y0LzQ= github.com/ngdinhtoan/glide-cleanup v0.2.0/go.mod h1:UQzsmiDOb8YV3nOsCxK/c9zPpCZVNoHScRE3EO9pVMM= @@ -723,6 +737,8 @@ github.com/prometheus/common v0.10.0/go.mod h1:Tlit/dnDKsSWFlCLTWaA1cyBgKHSMdTB8 github.com/prometheus/common v0.18.0/go.mod h1:U+gB1OBLb1lF3O42bTCL+FK18tX9Oar16Clt/msog/s= github.com/prometheus/common v0.26.0 h1:iMAkS2TDoNWnKM+Kopnx/8tnEStIfpYA0ur0xQzzhMQ= github.com/prometheus/common v0.26.0/go.mod h1:M7rCNAaPfAosfx8veZJCuw84e35h3Cfd9VFqTh1DIvc= +github.com/prometheus/common v0.32.1 h1:hWIdL3N2HoUx3B8j3YN9mWor0qhY/NlEKZEaXxuIRh4= +github.com/prometheus/common v0.32.1/go.mod h1:vu+V0TpY+O6vW9J44gczi3Ap/oXXR10b+M/gUGO4Hls= github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190117184657-bf6a532e95b1/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= github.com/prometheus/procfs v0.0.0-20190507164030-5867b95ac084/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= @@ -732,10 +748,13 @@ github.com/prometheus/procfs v0.1.3/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4O github.com/prometheus/procfs v0.2.0/go.mod h1:lV6e/gmhEcM9IjHGsFOCxxuZ+z1YqCvr4OA4YeYWdaU= github.com/prometheus/procfs v0.6.0 h1:mxy4L2jP6qMonqmq+aTtOx1ifVWUgG/TAmntgbh3xv4= github.com/prometheus/procfs v0.6.0/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= +github.com/prometheus/procfs v0.7.3 h1:4jVXhlkAyzOScmCkXBTOLRLTz8EeU+eyjrwB/EPq0VU= +github.com/prometheus/procfs v0.7.3/go.mod h1:cz+aTbrPOrUb4q7XlbU9ygM+/jj0fzG6c1xBZuNvfVA= github.com/prometheus/tsdb v0.7.1/go.mod h1:qhTCs0VvXwvX/y3TZrWD7rabWM+ijKTux40TwIPHuXU= github.com/pseudomuto/protoc-gen-doc v1.4.1/go.mod h1:exDTOVwqpp30eV/EDPFLZy3Pwr2sn6hBC1WIYH/UbIg= github.com/pseudomuto/protokit v0.2.0/go.mod h1:2PdH30hxVHsup8KpBTOXTBeMVhJZVio3Q8ViKSAXT0Q= github.com/rcrowley/go-metrics v0.0.0-20181016184325-3113b8401b8a/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= +github.com/rcrowley/go-metrics v0.0.0-20201227073835-cf1acfcdf475/go.mod h1:bCqnVzQkZxMG4s8nGwiZ5l3QUCyqpo9Y+/ZMZ9VjZe4= github.com/rogpeppe/fastuuid v0.0.0-20150106093220-6724a57986af/go.mod h1:XWv6SoW27p1b0cqNHllgS5HIMJraePCO15w5zCzIWYg= github.com/rogpeppe/fastuuid v1.1.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= github.com/rogpeppe/fastuuid v1.2.0/go.mod h1:jVj6XXZzXRy/MSR5jhDC/2q6DgLz+nrA6LYCDYWNEvQ= @@ -767,6 +786,11 @@ github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6Mwd github.com/sirupsen/logrus v1.6.0/go.mod h1:7uNnSEd1DgxDLC74fIahvMZmmYsHGZGEOFrfsX/uA88= github.com/sirupsen/logrus v1.7.0 h1:ShrD1U9pZB12TX0cVy0DtePoCH97K8EtX+mg7ZARUtM= github.com/sirupsen/logrus v1.7.0/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/sirupsen/logrus v1.8.1 h1:dJKuHgqk1NNQlqoA6BTlM1Wf9DOH3NBjQyu0h9+AZZE= +github.com/sirupsen/logrus v1.8.1/go.mod h1:yWOB1SBYBC5VeMP7gHvWumXLIWorT60ONWic61uBYv0= +github.com/skip2/go-qrcode v0.0.0-20200617195104-da1b6568686e/go.mod h1:XV66xRDqSt+GTGFMVlhk3ULuV0y9ZmzeVGR4mloJI3M= +github.com/slackhq/nebula v1.5.2 h1:wuIOHsOnrNw3rQx8yPxXiGu8wAtAxxtUI/K8W7Vj7EI= +github.com/slackhq/nebula v1.5.2/go.mod h1:xaCM6wqbFk/NRmmUe1bv88fWBm3a1UioXJVIpR52WlE= github.com/smallstep/assert v0.0.0-20180720014142-de77670473b5/go.mod h1:TC9A4+RjIOS+HyTH7wG17/gSqVv95uDw2J64dQZx7RE= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= @@ -791,6 +815,7 @@ github.com/soheilhy/cmux v0.1.4/go.mod h1:IM3LyeVVIOuxMH7sFAkER9+bJ4dT7Ms6E4xg4k github.com/soheilhy/cmux v0.1.5-0.20210205191134-5ec6847320e5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= github.com/soheilhy/cmux v0.1.5 h1:jjzc5WVemNEDTLwv9tlmemhC73tI08BNOIGwBOo10Js= github.com/soheilhy/cmux v0.1.5/go.mod h1:T7TcVDs9LWfQgPlPsdngu6I6QIoyIFZDDC6sNE1GqG0= +github.com/songgao/water v0.0.0-20200317203138-2b4b6d7c09d8/go.mod h1:P5HUIBuIWKbyjl083/loAegFkfbFNx5i2qEP4CNbm7E= github.com/sony/gobreaker v0.4.1/go.mod h1:ZKptC7FHNvhBz7dN2LGjPVBz2sZJmc0/PkyDJOjmxWY= github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= github.com/spaolacci/murmur3 v1.1.0 h1:7c1g84S4BPRrfL5Xrdp6fOJ206sU9y293DDHaoy0bLI= @@ -851,6 +876,9 @@ github.com/urfave/cli v1.22.2/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtX github.com/urfave/cli v1.22.4/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= github.com/urfave/cli v1.22.5 h1:lNq9sAHXK2qfdI8W+GRItjCEkI+2oR4d+MEHy1CKXoU= github.com/urfave/cli v1.22.5/go.mod h1:Gos4lmkARVdJ6EkW0WaNv/tZAAMe9V7XWyB60NtXRu0= +github.com/vishvananda/netlink v1.1.0/go.mod h1:cTgwzPIzzgDAYoQrMm0EdrjRUBkTqKYppBueQtXaqoE= +github.com/vishvananda/netns v0.0.0-20191106174202-0a2b9b5464df/go.mod h1:JP3t17pCcGlemwknint6hfoeCVQrEMVwxRLRjXpq+BU= +github.com/vishvananda/netns v0.0.0-20211101163701-50045581ed74/go.mod h1:DD4vA1DwXk04H54A1oHXtwZmA0grkVMdPxx/VGLCah0= github.com/weppos/publicsuffix-go v0.4.0 h1:YSnfg3V65LcCFKtIGKGoBhkyKolEd0hlipcXaOjdnQw= github.com/weppos/publicsuffix-go v0.4.0/go.mod h1:z3LCPQ38eedDQSwmsSRW4Y7t2L8Ln16JPQ02lHAdn5k= github.com/xanzy/go-gitlab v0.31.0/go.mod h1:sPLojNBn68fMUWSxIJtdVVIP8uSBYqesTfDUseX11Ug= @@ -864,6 +892,7 @@ github.com/yuin/goldmark v1.1.27/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9de github.com/yuin/goldmark v1.1.32/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.2.1/go.mod h1:3hX8gzYuyVAZsxl0MRgGTJEmQBFcNTphYh9decYSb74= github.com/yuin/goldmark v1.3.5/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= +github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k= github.com/zmap/rc2 v0.0.0-20131011165748-24b9757f5521/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/rc2 v0.0.0-20190804163417-abaa70531248/go.mod h1:3YZ9o3WnatTIZhuOtot4IcUfzoKVjUHqu6WALIyI0nE= github.com/zmap/zcertificate v0.0.0-20180516150559-0e3d58b1bac4/go.mod h1:5iU54tB79AMBcySS0R2XIyZBAVmeHranShAFELYx7is= @@ -950,8 +979,13 @@ go.step.sm/cli-utils v0.7.0/go.mod h1:Ur6bqA/yl636kCUJbp30J7Unv5JJ226eW2KqXPDwF/ go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0= go.step.sm/crypto v0.13.0 h1:mQuP9Uu2FNmqCJNO0OTbvolnYXzONy4wdUBtUVcP1s8= go.step.sm/crypto v0.13.0/go.mod h1:5YzQ85BujYBu6NH18jw7nFjwuRnDch35nLzH0ES5sKg= +go.step.sm/crypto v0.14.0 h1:HzSkUDwqKhODKpsTxevJz956U2xVDZ3sDdGQVwR6Ttw= +go.step.sm/crypto v0.14.0/go.mod h1:3G0yQr5lQqfEG0CMYz8apC/qMtjLRQlzflL2AxkcN+g= +go.step.sm/linkedca v0.7.0/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo= go.step.sm/linkedca v0.8.0 h1:86DAufqUtUvFTJgYpgG0McKkpqnjXxg53FTXYyhs0HI= go.step.sm/linkedca v0.8.0/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo= +go.step.sm/linkedca v0.9.0 h1:xKXZoRXy4B7LeGBZozq62IQ0p3v8dT33O9UOMpVtRtI= +go.step.sm/linkedca v0.9.0/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -988,9 +1022,14 @@ golang.org/x/crypto v0.0.0-20200414173820-0848c9571904/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20200728195943-123391ffb6de/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= +golang.org/x/crypto v0.0.0-20210322153248-0c34fe9e7dc2/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 h1:3erb+vDS8lU1sxfDHF4/hhWyaXnhIaO+7RgL4fDZORA= golang.org/x/crypto v0.0.0-20210915214749-c084706c2272/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20211202192323-5770296d904e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= +golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -1082,8 +1121,14 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210316092652-d523dce5a7f4/go.mod h1:RBQZq4jEuRlivfhVLdyRGr576XBO4/greRjx4P4O3yc= golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96bSt6lcn1PtDYWL6XObtHCRCNQM= golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210913180222-943fd674d43e h1:+b/22bPvDYt4NPDcy4xAGCmON713ONAWFeY3Z7I3tR8= golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= +golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1133,6 +1178,7 @@ golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606203320-7fc4e5ec1444/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190620070143-6f217b454f45/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190626221950-04f50cda93cb/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1150,6 +1196,7 @@ golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200122134326-e047566fdf82/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200202164722-d101bd2416d5/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200212091648-12a6c2dcc1e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200217220822-9197077df867/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200223170610-d5e6a3e2c0ae/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200302150141-5c8b2ff67527/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200323222414-85ca7c5b95cd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1166,12 +1213,15 @@ golang.org/x/sys v0.0.0-20200905004654-be1d3432aa8f/go.mod h1:h1NjWce9XRLGQEsW7w golang.org/x/sys v0.0.0-20200923182605-d9f96fdee20d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201009025420-dfb3f7c4e634/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201015000850-e3ed0017c211/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20201018230417-eeed37f84f13/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20201201145000-ef89a241ccb3/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210104204734-6f8348627aad/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210119212857-b64e53b001e4/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210124154548-22da62e12c0c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210220050731-9a76102bfb43/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20210303074136-134d130e1a04/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210305230114-8fe3ee5dd75b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210309074719-68d13333faf2/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20210315160823-c6e025ad8005/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -1186,12 +1236,18 @@ golang.org/x/sys v0.0.0-20210514084401-e8d321eab015/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210603125802-9665404d3644/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211025201205-69cdffdb9359/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211031064116-611d5d643895 h1:iaNpwpnrgL5jzWS0vCNnfa8HqzxveCFpFx3uC/X4Tps= golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b h1:1VkfZQv42XQlA/jchYumAnv1UPo6RgF9rJFkTgZIxO4= +golang.org/x/sys v0.0.0-20211103235746-7861aae1554b/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= +golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -1202,6 +1258,8 @@ golang.org/x/text v0.3.5/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= golang.org/x/text v0.3.7 h1:olpwvP2KacW1ZWvsR7uQhoyTYvKAupfQrRGBFM352Gk= golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ= +golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b h1:NXqSWXSRUSCaFuvitrWtU169I3876zRTalMRbfd6LL0= +golang.org/x/text v0.3.8-0.20211004125949-5bd84dd9b33b/go.mod h1:EFNZuWvGYxIRUEX+K8UmCFwYmZjqcrnq15ZuVldZkZ0= golang.org/x/time v0.0.0-20180412165947-fbb02b2291d2/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= @@ -1280,11 +1338,15 @@ golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.5 h1:ouewzE6p+/VEB31YYnTbEJdi8pFqKp4P4n85vwo3DHA= golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= +golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= +golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.zx2c4.com/wintun v0.0.0-20211104114900-415007cec224/go.mod h1:deeaetjYA+DHMHg+sMSMI58GrEteJUUzzw7en6TJQcI= +golang.zx2c4.com/wireguard/windows v0.5.1/go.mod h1:EApyTk/ZNrkbZjurHL1nleDYnsPpJYBO7LZEBCyDAHk= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= google.golang.org/api v0.5.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= @@ -1435,6 +1497,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q= gopkg.in/cheggaaa/pb.v1 v1.0.25/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= gopkg.in/cheggaaa/pb.v1 v1.0.28 h1:n1tBJnnK2r7g9OW2btFH91V92STTUevLXYFb8gy9EMk= gopkg.in/cheggaaa/pb.v1 v1.0.28/go.mod h1:V/YB90LKu/1FcN3WVnfiiE5oMCibMjukxqG/qStrOgw= From 9212e57d965c3aca45b7893d7cb7ca91b84c46f0 Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 20 Jan 2022 18:46:17 -0800 Subject: [PATCH 33/52] Add --auth-param flag to oauth command fixes #614 --- command/oauth/cmd.go | 47 ++++++++++++++++++++++++++++++++++++++------ 1 file changed, 41 insertions(+), 6 deletions(-) diff --git a/command/oauth/cmd.go b/command/oauth/cmd.go index cb00a340..991dc51d 100644 --- a/command/oauth/cmd.go +++ b/command/oauth/cmd.go @@ -67,21 +67,25 @@ func init() { Usage: "authorization and single sign-on using OAuth & OIDC", UsageText: `**step oauth** [**--provider**=] [**--client-id**= **--client-secret**=] -[**--scope**= ...] [**--bare** [**--oidc**]] [**--header** [**--oidc**]] [**--prompt**=] +[**--scope**= ...] [**--bare** [**--oidc**]] [**--header** [**--oidc**]] +[**--prompt**=] [**--auth-param**=] **step oauth** **--authorization-endpoint**= **--token-endpoint**= **--client-id**= **--client-secret**= -[**--scope**= ...] [**--bare** [**--oidc**]] [**--header** [**--oidc**]] [**--prompt**=] +[**--scope**= ...] [**--bare** [**--oidc**]] [**--header** [**--oidc**]] +[**--prompt**=] [**--auth-param**=] **step oauth** [**--account**=] [**--authorization-endpoint**=] [**--token-endpoint**=] -[**--scope**= ...] [**--bare** [**--oidc**]] [**--header** [**--oidc**]] [**--prompt**=] +[**--scope**= ...] [**--bare** [**--oidc**]] [**--header** [**--oidc**]] +[**--prompt**=] [**--auth-param**=] **step oauth** **--account**= **--jwt** -[**--scope**= ...] [**--header**] [**-bare**] [**--prompt**=]`, +[**--scope**= ...] [**--header**] [**-bare**] [**--prompt**=] +[**--auth-param**=]`, Description: `**step oauth** command implements the OAuth 2.0 authorization flow. OAuth is an open standard for access delegation, commonly used as a way for @@ -135,6 +139,12 @@ Use a custom OAuth2.0 server: ''' $ step oauth --client-id my-client-id --client-secret my-client-secret \ --provider https://example.org +''' + +Use additional authentication parameters: +''' +$ step oauth --client-id my-client-id --client-secret my-client-secret \ + --provider https://example.org --auth-param "access_type=offline" '''`, Flags: []cli.Flag{ cli.StringFlag{ @@ -186,6 +196,12 @@ $ step oauth --client-id my-client-id --client-secret my-client-secret \ Name: "scope", Usage: "OAuth scopes", }, + cli.StringSliceFlag{ + Name: "auth-param", + Usage: `OAuth additional authentication parameters to include as part of the URL query. +Use this flag multiple times to add multiple parameters. This flag expects a +'key' and 'value' in the format '--auth-param "key=value"'.`, + }, cli.StringFlag{ Name: "prompt", Usage: `Whether the Authorization Server prompts the End-User for reauthentication and consent. @@ -336,7 +352,20 @@ func oauthCmd(c *cli.Context) error { prompt = c.String("prompt") } - o, err := newOauth(opts.Provider, clientID, clientSecret, authzEp, tokenEp, scope, prompt, opts) + authParams := map[string]string{} + for _, keyval := range c.StringSlice("auth-param") { + parts := strings.Split(keyval, "=") + if len(parts) != 2 { + return errs.InvalidFlagValue(c, "auth-param", keyval, "") + } + k, v := parts[0], parts[1] + if k == "" || v == "" { + return errs.InvalidFlagValue(c, "auth-param", keyval, "") + } + authParams[k] = v + } + + o, err := newOauth(opts.Provider, clientID, clientSecret, authzEp, tokenEp, scope, prompt, authParams, opts) if err != nil { return err } @@ -438,11 +467,12 @@ type oauth struct { CallbackPath string terminalRedirect string browser string + authParams map[string]string errCh chan error tokCh chan *token } -func newOauth(provider, clientID, clientSecret, authzEp, tokenEp, scope, prompt string, opts *options) (*oauth, error) { +func newOauth(provider, clientID, clientSecret, authzEp, tokenEp, scope, prompt string, authParams map[string]string, opts *options) (*oauth, error) { state, err := randutil.Alphanumeric(32) if err != nil { return nil, err @@ -479,6 +509,7 @@ func newOauth(provider, clientID, clientSecret, authzEp, tokenEp, scope, prompt CallbackPath: opts.CallbackPath, terminalRedirect: opts.TerminalRedirect, browser: opts.Browser, + authParams: authParams, errCh: make(chan error), tokCh: make(chan *token), }, nil @@ -519,6 +550,7 @@ func newOauth(provider, clientID, clientSecret, authzEp, tokenEp, scope, prompt CallbackPath: opts.CallbackPath, terminalRedirect: opts.TerminalRedirect, browser: opts.Browser, + authParams: authParams, errCh: make(chan error), tokCh: make(chan *token), }, nil @@ -885,6 +917,9 @@ func (o *oauth) Auth() (string, error) { q := u.Query() q.Add("client_id", o.clientID) q.Add("redirect_uri", o.redirectURI) + for k, v := range o.authParams { + q.Add(k, v) + } if o.implicit { q.Add("response_type", "id_token token") } else { From b5de27049c4b54e976dd02fe6f5c3fdf02c82ecd Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 20 Jan 2022 18:55:56 -0800 Subject: [PATCH 34/52] Add non-db backed provisioner add methods should use GetIDForToken - GetID could be a randomly generated ID if we ever share these code pathways --- command/ca/provisioner/add.go | 50 +++++++++++++++++------------------ 1 file changed, 25 insertions(+), 25 deletions(-) diff --git a/command/ca/provisioner/add.go b/command/ca/provisioner/add.go index 000ae8f8..989d6351 100644 --- a/command/ca/provisioner/add.go +++ b/command/ca/provisioner/add.go @@ -332,7 +332,7 @@ func addAction(ctx *cli.Context) (err error) { provMap := make(map[string]bool) for _, p := range c.AuthorityConfig.Provisioners { - provMap[p.GetID()] = true + provMap[p.GetIDForToken()] = true } var list provisioner.List @@ -408,8 +408,8 @@ func addJWKProvisioner(ctx *cli.Context, name string, provMap map[string]bool) ( Claims: getClaims(ctx), } // Check for duplicates - if _, ok := provMap[p.GetID()]; !ok { - provMap[p.GetID()] = true + if _, ok := provMap[p.GetIDForToken()]; !ok { + provMap[p.GetIDForToken()] = true } else { return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with name=%s and kid=%s", name, jwk.KeyID) } @@ -448,8 +448,8 @@ func addJWKProvisioner(ctx *cli.Context, name string, provMap map[string]bool) ( Key: &key, Claims: getClaims(ctx), } - if _, ok := provMap[p.GetID()]; !ok { - provMap[p.GetID()] = true + if _, ok := provMap[p.GetIDForToken()]; !ok { + provMap[p.GetIDForToken()] = true } else { return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with name=%s and kid=%s", name, jwk.KeyID) } @@ -500,8 +500,8 @@ func addOIDCProvisioner(ctx *cli.Context, name string, provMap map[string]bool) ListenAddress: ctx.String("listen-address"), } // Check for duplicates - if _, ok := provMap[p.GetID()]; !ok { - provMap[p.GetID()] = true + if _, ok := provMap[p.GetIDForToken()]; !ok { + provMap[p.GetIDForToken()] = true } else { return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with client-id=%s", p.GetID()) } @@ -527,8 +527,8 @@ func addAWSProvisioner(ctx *cli.Context, name string, provMap map[string]bool) ( } // Check for duplicates - if _, ok := provMap[p.GetID()]; !ok { - provMap[p.GetID()] = true + if _, ok := provMap[p.GetIDForToken()]; !ok { + provMap[p.GetIDForToken()] = true } else { return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with type=AWS and name=%s", p.GetName()) } @@ -554,8 +554,8 @@ func addAzureProvisioner(ctx *cli.Context, name string, provMap map[string]bool) } // Check for duplicates - if _, ok := provMap[p.GetID()]; !ok { - provMap[p.GetID()] = true + if _, ok := provMap[p.GetIDForToken()]; !ok { + provMap[p.GetIDForToken()] = true } else { return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with type=Azure and name=%s", p.GetName()) } @@ -582,8 +582,8 @@ func addGCPProvisioner(ctx *cli.Context, name string, provMap map[string]bool) ( } // Check for duplicates - if _, ok := provMap[p.GetID()]; !ok { - provMap[p.GetID()] = true + if _, ok := provMap[p.GetIDForToken()]; !ok { + provMap[p.GetIDForToken()] = true } else { return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with type=GCP and name=%s", p.GetName()) } @@ -600,10 +600,10 @@ func addACMEProvisioner(ctx *cli.Context, name string, provMap map[string]bool) } // Check for duplicates - if _, ok := provMap[p.GetID()]; !ok { - provMap[p.GetID()] = true + if _, ok := provMap[p.GetIDForToken()]; !ok { + provMap[p.GetIDForToken()] = true } else { - return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with ID==%s", p.GetID()) + return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with ID==%s", p.GetIDForToken()) } list = append(list, p) @@ -641,10 +641,10 @@ func addX5CProvisioner(ctx *cli.Context, name string, provMap map[string]bool) ( } // Check for duplicates - if _, ok := provMap[p.GetID()]; !ok { - provMap[p.GetID()] = true + if _, ok := provMap[p.GetIDForToken()]; !ok { + provMap[p.GetIDForToken()] = true } else { - return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with ID=%s", p.GetID()) + return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with ID=%s", p.GetIDForToken()) } list = append(list, p) @@ -706,10 +706,10 @@ func addK8sSAProvisioner(ctx *cli.Context, name string, provMap map[string]bool) } // Check for duplicates - if _, ok := provMap[p.GetID()]; !ok { - provMap[p.GetID()] = true + if _, ok := provMap[p.GetIDForToken()]; !ok { + provMap[p.GetIDForToken()] = true } else { - return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with ID=%s", p.GetID()) + return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with ID=%s", p.GetIDForToken()) } list = append(list, p) @@ -726,10 +726,10 @@ func addSSHPOPProvisioner(ctx *cli.Context, name string, provMap map[string]bool } // Check for duplicates - if _, ok := provMap[p.GetID()]; !ok { - provMap[p.GetID()] = true + if _, ok := provMap[p.GetIDForToken()]; !ok { + provMap[p.GetIDForToken()] = true } else { - return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with ID=%s", p.GetID()) + return nil, errors.Errorf("duplicated provisioner: CA config already contains a provisioner with ID=%s", p.GetIDForToken()) } list = append(list, p) From ad5c6a8e0971c9b99606428510e236c2f9e91de6 Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 20 Jan 2022 23:24:11 -0800 Subject: [PATCH 35/52] Cleanup for PR comments --- command/oauth/cmd.go | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/command/oauth/cmd.go b/command/oauth/cmd.go index 991dc51d..3ed31e87 100644 --- a/command/oauth/cmd.go +++ b/command/oauth/cmd.go @@ -68,24 +68,24 @@ func init() { UsageText: `**step oauth** [**--provider**=] [**--client-id**= **--client-secret**=] [**--scope**= ...] [**--bare** [**--oidc**]] [**--header** [**--oidc**]] -[**--prompt**=] [**--auth-param**=] +[**--prompt**=] [**--auth-param**=] **step oauth** **--authorization-endpoint**= **--token-endpoint**= **--client-id**= **--client-secret**= [**--scope**= ...] [**--bare** [**--oidc**]] [**--header** [**--oidc**]] -[**--prompt**=] [**--auth-param**=] +[**--prompt**=] [**--auth-param**=] **step oauth** [**--account**=] [**--authorization-endpoint**=] [**--token-endpoint**=] [**--scope**= ...] [**--bare** [**--oidc**]] [**--header** [**--oidc**]] -[**--prompt**=] [**--auth-param**=] +[**--prompt**=] [**--auth-param**=] **step oauth** **--account**= **--jwt** [**--scope**= ...] [**--header**] [**-bare**] [**--prompt**=] -[**--auth-param**=]`, +[**--auth-param**=]`, Description: `**step oauth** command implements the OAuth 2.0 authorization flow. OAuth is an open standard for access delegation, commonly used as a way for @@ -352,17 +352,23 @@ func oauthCmd(c *cli.Context) error { prompt = c.String("prompt") } - authParams := map[string]string{} + authParams := url.Values{} for _, keyval := range c.StringSlice("auth-param") { - parts := strings.Split(keyval, "=") - if len(parts) != 2 { + parts := strings.SplitN(keyval, "=", 2) + var k, v string + switch len(parts) { + case 0: + return errs.InvalidFlagValue(c, "auth-param", keyval, "") + case 1: + k, v = parts[0], "" + authParams.Add(parts[0], "") + case 2: + k, v = parts[0], parts[1] + } + if k == "" { return errs.InvalidFlagValue(c, "auth-param", keyval, "") } - k, v := parts[0], parts[1] - if k == "" || v == "" { - return errs.InvalidFlagValue(c, "auth-param", keyval, "") - } - authParams[k] = v + authParams.Add(k, v) } o, err := newOauth(opts.Provider, clientID, clientSecret, authzEp, tokenEp, scope, prompt, authParams, opts) @@ -467,12 +473,12 @@ type oauth struct { CallbackPath string terminalRedirect string browser string - authParams map[string]string + authParams url.Values errCh chan error tokCh chan *token } -func newOauth(provider, clientID, clientSecret, authzEp, tokenEp, scope, prompt string, authParams map[string]string, opts *options) (*oauth, error) { +func newOauth(provider, clientID, clientSecret, authzEp, tokenEp, scope, prompt string, authParams url.Values, opts *options) (*oauth, error) { state, err := randutil.Alphanumeric(32) if err != nil { return nil, err @@ -917,9 +923,6 @@ func (o *oauth) Auth() (string, error) { q := u.Query() q.Add("client_id", o.clientID) q.Add("redirect_uri", o.redirectURI) - for k, v := range o.authParams { - q.Add(k, v) - } if o.implicit { q.Add("response_type", "id_token token") } else { @@ -937,7 +940,7 @@ func (o *oauth) Auth() (string, error) { if o.loginHint != "" { q.Add("login_hint", o.loginHint) } - u.RawQuery = q.Encode() + u.RawQuery = fmt.Sprintf("%s&%s", q.Encode(), o.authParams.Encode()) return u.String(), nil } From 0cbc66bee1359dedb98ea902b8db881437a48817 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Fri, 21 Jan 2022 16:10:23 +0100 Subject: [PATCH 36/52] Add SCEP (beta) provisioner support --- command/ca/provisionerbeta/add.go | 49 +++++++++++++++-- command/ca/provisionerbeta/provisioner.go | 31 ++++++++++- command/ca/provisionerbeta/update.go | 66 ++++++++++++++++++++--- go.mod | 8 +-- go.sum | 16 ++++++ 5 files changed, 153 insertions(+), 17 deletions(-) diff --git a/command/ca/provisionerbeta/add.go b/command/ca/provisionerbeta/add.go index ac48447a..76696d96 100644 --- a/command/ca/provisionerbeta/add.go +++ b/command/ca/provisionerbeta/add.go @@ -73,7 +73,13 @@ func addCommand() cli.Command { **step beta ca provisioner add** **--type**=ACME [**--force-cn**] [**--admin-cert**=] [**--admin-key**=] [**--admin-provisioner**=] [**--admin-subject**=] [**--password-file**=] [**--ca-url**=] -[**--root**=] [**--context**=]`, +[**--root**=] [**--context**=] + +**step beta ca provisioner add** **--type**=SCEP [**--force-cn**] [**--challenge**=] +[**--capabilities**=] [**--include-root**] [**--minimum-public-key-length**=] +[**--encryption-algorithm-identifier**=] [**--admin-cert**=] [**--admin-key**=] +[**--admin-provisioner**=] [**--admin-subject**=] [**--password-file**=] +[**--ca-url**=] [**--root**=] [**--context**=]`, Flags: []cli.Flag{ cli.StringFlag{ Name: "type", @@ -107,7 +113,10 @@ func addCommand() cli.Command { : Uses Kubernetes Service Account tokens. **SSHPOP** - : Uses an SSH Certificate / private key pair to sign provisioning tokens.`}, + : Uses an SSH Certificate / private key pair to sign provisioning tokens. + + **SCEP** + : Uses the SCEP protocol to create certificates.`}, x509TemplateFlag, x509TemplateDataFlag, sshTemplateFlag, @@ -183,6 +192,13 @@ provisioning tokens.`, // ACME provisioner flags forceCNFlag, + // SCEP provisioner flags + scepChallengeFlag, + scepCapabilitiesFlag, + scepIncludeRootFlag, + scepMinimumPublicKeyLengthFlag, + scepEncryptionAlgorithmIdentifierFlag, + // Cloud provisioner flags awsAccountFlag, azureTenantFlag, @@ -255,6 +271,11 @@ Create an SSHPOP provisioner for renewing SSH host certificates:") step beta ca provisioner add sshpop --type SSHPOP ''' +Create a SCEP provisioner with 'secret' challenge and AES-256-CBC: +''' +step beta ca provisioner add my_scep_provisioner --type SCEP --challenge secret --encryption-algorithm-identifier 2 +''' + Create an Azure provisioner with two service groups: ''' $ step beta ca provisioner add Azure --type Azure \ @@ -393,7 +414,10 @@ func addAction(ctx *cli.Context) (err error) { case linkedca.Provisioner_GCP.String(): p.Type = linkedca.Provisioner_GCP p.Details, err = createGCPDetails(ctx) - // TODO add SCEP provisioner support. + case linkedca.Provisioner_SCEP.String(): + p.Type = linkedca.Provisioner_SCEP + p.Details, err = createSCEPDetails(ctx) + // TODO: add Nebula support default: return fmt.Errorf("unsupported provisioner type %s", typ) } @@ -663,7 +687,7 @@ func createOIDCDetails(ctx *cli.Context) (*linkedca.ProvisionerDetails, error) { } func createAWSDetails(ctx *cli.Context) (*linkedca.ProvisionerDetails, error) { - d, err := parseIntaceAge(ctx) + d, err := parseInstanceAge(ctx) if err != nil { return nil, err } @@ -701,7 +725,7 @@ func createAzureDetails(ctx *cli.Context) (*linkedca.ProvisionerDetails, error) } func createGCPDetails(ctx *cli.Context) (*linkedca.ProvisionerDetails, error) { - d, err := parseIntaceAge(ctx) + d, err := parseInstanceAge(ctx) if err != nil { return nil, err } @@ -718,3 +742,18 @@ func createGCPDetails(ctx *cli.Context) (*linkedca.ProvisionerDetails, error) { }, }, nil } + +func createSCEPDetails(ctx *cli.Context) (*linkedca.ProvisionerDetails, error) { + return &linkedca.ProvisionerDetails{ + Data: &linkedca.ProvisionerDetails_SCEP{ + SCEP: &linkedca.SCEPProvisioner{ + ForceCn: ctx.Bool("force-cn"), + Challenge: ctx.String("challenge"), + Capabilities: ctx.StringSlice("capabilities"), + MinimumPublicKeyLength: int32(ctx.Int("minimum-public-key-length")), + IncludeRoot: ctx.Bool("include-root"), + EncryptionAlgorithmIdentifier: int32(ctx.Int("encryption-algorithm-identifier")), + }, + }, + }, nil +} diff --git a/command/ca/provisionerbeta/provisioner.go b/command/ca/provisionerbeta/provisioner.go index df8f7c51..d912fd52 100644 --- a/command/ca/provisionerbeta/provisioner.go +++ b/command/ca/provisionerbeta/provisioner.go @@ -69,7 +69,7 @@ $ step beta ca provisioner remove max@smallstep.com } } -func parseIntaceAge(ctx *cli.Context) (age string, err error) { +func parseInstanceAge(ctx *cli.Context) (age string, err error) { if !ctx.IsSet("instance-age") { return } @@ -170,6 +170,35 @@ var ( Usage: `Always set the common name in provisioned certificates.`, } + // SCEP provisioner flags + scepChallengeFlag = cli.StringFlag{ + Name: "challenge", + Usage: `A SCEP challenge`, + } + scepCapabilitiesFlag = cli.StringSliceFlag{ + Name: "capabilities", + Usage: `The SCEP capabilities to advertise`, + } + scepIncludeRootFlag = cli.BoolFlag{ + Name: "include-root", + Usage: `Include the CA root certificate in the SCEP CA certificate chain`, + } + scepMinimumPublicKeyLengthFlag = cli.IntFlag{ + Name: "minimum-public-key-length", + Usage: `The minimum public key length of the SCEP RSA encryption key`, + } + scepEncryptionAlgorithmIdentifierFlag = cli.IntFlag{ + Name: "encryption-algorithm-identifier", + Usage: `The identifier for the SCEP encryption algorithm to use. + Valid values are 0 - 4, inclusive. The values correspond to: + 0: DES-CBC, + 1: AES-128-CBC, + 2: AES-256-CBC, + 3: AES-128-GCM, + 4: AES-256-GCM. + Defaults to DES-CBC (0) for legacy clients.`, + } + // Cloud provisioner flags awsAccountFlag = cli.StringSliceFlag{ Name: "aws-account", diff --git a/command/ca/provisionerbeta/update.go b/command/ca/provisionerbeta/update.go index 69d0bae2..4cf39de7 100644 --- a/command/ca/provisionerbeta/update.go +++ b/command/ca/provisionerbeta/update.go @@ -81,7 +81,14 @@ IID (AWS/GCP/Azure) [**--disable-custom-sans**] [**--disable-trust-on-first-use**] [**--admin-cert**=] [**--admin-key**=] [**--admin-provisioner**=] [**--admin-subject**=] [**--password-file**=] [**--ca-url**=] -[**--root**=] [**--context**=]`, +[**--root**=] [**--context**=] + +**step beta ca provisioner update** [**--force-cn**] [**--challenge**=] +[**--capabilities**=] [**--include-root**] [**--minimum-public-key-length**=] +[**--encryption-algorithm-identifier**=] [**--admin-cert**=] [**--admin-key**=] +[**--admin-provisioner**=] [**--admin-subject**=] [**--password-file**=] +[**--ca-url**=] [**--root**=] [**--context**=] +`, Flags: []cli.Flag{ cli.StringFlag{ Name: "name", @@ -166,6 +173,13 @@ provisioning tokens.`, // ACME provisioner flags forceCNFlag, + // SCEP flags + scepChallengeFlag, + scepCapabilitiesFlag, + scepIncludeRootFlag, + scepMinimumPublicKeyLengthFlag, + scepEncryptionAlgorithmIdentifierFlag, + // Cloud provisioner flags awsAccountFlag, removeAWSAccountFlag, @@ -246,7 +260,7 @@ $ step beta ca provisioner update Azure \ --azure-resource-group identity --azure-resource-group accounting ''' -Update an GCP provisioner: +Update a GCP provisioner: ''' $ step beta ca provisioner update Google \ --disable-custom-sans --gcp-project internal --remove-gcp-project public @@ -255,6 +269,11 @@ $ step beta ca provisioner update Google \ Update an AWS provisioner: ''' $ step beta ca provisioner update Amazon --disable-custom-sans --disable-trust-on-first-use +''' + +Update a SCEP provisioner: +''' +step beta ca provisioner update my_scep_provisioner --force-cn '''`, } } @@ -305,7 +324,9 @@ func updateAction(ctx *cli.Context) (err error) { err = updateAzureDetails(ctx, p) case linkedca.Provisioner_GCP: err = updateGCPDetails(ctx, p) - // TODO add SCEP provisioner support. + case linkedca.Provisioner_SCEP: + err = updateSCEPDetails(ctx, p) + // TODO: add Nebula support default: return fmt.Errorf("unsupported provisioner type %s", p.Type.String()) } @@ -709,13 +730,13 @@ func updateOIDCDetails(ctx *cli.Context, p *linkedca.Provisioner) error { func updateAWSDetails(ctx *cli.Context, p *linkedca.Provisioner) error { data, ok := p.Details.GetData().(*linkedca.ProvisionerDetails_AWS) if !ok { - return errors.New("error casting details to OIDC type") + return errors.New("error casting details to AWS type") } details := data.AWS var err error if ctx.IsSet("instance-age") { - details.InstanceAge, err = parseIntaceAge(ctx) + details.InstanceAge, err = parseInstanceAge(ctx) if err != nil { return err } @@ -738,7 +759,7 @@ func updateAWSDetails(ctx *cli.Context, p *linkedca.Provisioner) error { func updateAzureDetails(ctx *cli.Context, p *linkedca.Provisioner) error { data, ok := p.Details.GetData().(*linkedca.ProvisionerDetails_Azure) if !ok { - return errors.New("error casting details to OIDC type") + return errors.New("error casting details to Azure type") } details := data.Azure @@ -763,13 +784,13 @@ func updateAzureDetails(ctx *cli.Context, p *linkedca.Provisioner) error { func updateGCPDetails(ctx *cli.Context, p *linkedca.Provisioner) error { data, ok := p.Details.GetData().(*linkedca.ProvisionerDetails_GCP) if !ok { - return errors.New("error casting details to OIDC type") + return errors.New("error casting details to GCP type") } details := data.GCP var err error if ctx.IsSet("instance-age") { - details.InstanceAge, err = parseIntaceAge(ctx) + details.InstanceAge, err = parseInstanceAge(ctx) if err != nil { return err } @@ -794,3 +815,32 @@ func updateGCPDetails(ctx *cli.Context, p *linkedca.Provisioner) error { } return nil } + +func updateSCEPDetails(ctx *cli.Context, p *linkedca.Provisioner) error { + data, ok := p.Details.GetData().(*linkedca.ProvisionerDetails_SCEP) + if !ok { + return errors.New("error casting details to SCEP type") + } + details := data.SCEP + + if ctx.IsSet("force-cn") { + details.ForceCn = ctx.Bool("force-cn") + } + if ctx.IsSet("challenge") { + details.Challenge = ctx.String("challenge") + } + if ctx.IsSet("capabilities") { + details.Capabilities = ctx.StringSlice("capabilities") + } + if ctx.IsSet("minimum-public-key-length") { + details.MinimumPublicKeyLength = int32(ctx.Int("minimum-public-key-length")) + } + if ctx.IsSet("include-root") { + details.IncludeRoot = ctx.Bool("include-root") + } + if ctx.IsSet("encryption-algorithm-identifier") { + details.EncryptionAlgorithmIdentifier = int32(ctx.Int("encryption-algorithm-identifier")) + } + + return nil +} diff --git a/go.mod b/go.mod index e36ddc37..a612caaa 100644 --- a/go.mod +++ b/go.mod @@ -26,11 +26,13 @@ require ( go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 go.step.sm/cli-utils v0.7.1 go.step.sm/crypto v0.13.0 - go.step.sm/linkedca v0.7.0 + go.step.sm/linkedca v0.9.2 golang.org/x/crypto v0.0.0-20210915214749-c084706c2272 - golang.org/x/net v0.0.0-20210913180222-943fd674d43e - golang.org/x/sys v0.0.0-20211031064116-611d5d643895 + golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d + golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 golang.org/x/term v0.0.0-20210503060354-a79de5458b56 + google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5 // indirect + google.golang.org/grpc v1.43.0 // indirect google.golang.org/protobuf v1.27.1 gopkg.in/square/go-jose.v2 v2.6.0 howett.net/plist v1.0.0 // indirect diff --git a/go.sum b/go.sum index 49cf1a8c..7f42ac84 100644 --- a/go.sum +++ b/go.sum @@ -204,8 +204,12 @@ github.com/cncf/udpa/go v0.0.0-20191209042840-269d4d468f6f/go.mod h1:M8M6+tZqaGX github.com/cncf/udpa/go v0.0.0-20200629203442-efcf912fb354/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403 h1:cqQfy1jclcSy/FwLjemeg3SR1yaINm74aQyupQ0Bl8M= github.com/cncf/udpa/go v0.0.0-20201120205902-5459f2c99403/go.mod h1:WmhPx2Nbnhtbo57+VJT5O0JRkEi1Wbu0z5j0R8u5Hbk= +github.com/cncf/udpa/go v0.0.0-20210930031921-04548b0d99d4/go.mod h1:6pvJx4me5XPnfI9Z40ddWsdw2W/uZgQLFXToKeRcDiI= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed h1:OZmjad4L3H8ncOIR8rnb5MREYqG8ixi5+WbeUsquF0c= github.com/cncf/xds/go v0.0.0-20210312221358-fbca930ec8ed/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210805033703-aa0b78936158/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20210922020428-25de7278fc84/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= +github.com/cncf/xds/go v0.0.0-20211011173535-cb28da3451f1/go.mod h1:eXthEFrGJvWHgFFCl3hGmgk+/aYT6PnTQLykKQRLhEs= github.com/cockroachdb/datadriven v0.0.0-20190809214429-80d97fb3cbaa/go.mod h1:zn76sxSg3SzpJ0PPJaLDCu+Bu0Lg3sKTORVIj19EIF8= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5 h1:xD/lrqdvwsc+O2bjSSi3YqY73Ke3LAiSCx49aCesA0E= github.com/cockroachdb/datadriven v0.0.0-20200714090401-bf6692d28da5/go.mod h1:h6jFvWxBdQXxjopDMZyH2UVceIRfR84bdzbkoKrsWNo= @@ -279,6 +283,7 @@ github.com/envoyproxy/go-control-plane v0.9.9-0.20201210154907-fd9021fe5dad/go.m github.com/envoyproxy/go-control-plane v0.9.9-0.20210217033140-668b12f5399d/go.mod h1:cXg6YxExXjJnVBQHBLXeUAgxn2UodCpnH306RInaBQk= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0 h1:dulLQAYQFYtG5MTplgNGHWuV2D+OBD+Z8lmDBmbLg+s= github.com/envoyproxy/go-control-plane v0.9.9-0.20210512163311-63b5d3c536b0/go.mod h1:hliV/p42l8fGbc6Y9bQ70uLwIvmJyVE5k4iMKlh8wCQ= +github.com/envoyproxy/go-control-plane v0.9.10-0.20210907150352-cf90f659a021/go.mod h1:AFq3mo9L8Lqqiid3OhADV3RfLJnjiw63cSpi+fDTRC0= github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= github.com/envoyproxy/protoc-gen-validate v0.3.0-java h1:bV5JGEB1ouEzZa0hgVDFFiClrUEuGWRaAc/3mxR2QK0= github.com/envoyproxy/protoc-gen-validate v0.3.0-java/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= @@ -953,6 +958,8 @@ go.step.sm/crypto v0.13.0 h1:mQuP9Uu2FNmqCJNO0OTbvolnYXzONy4wdUBtUVcP1s8= go.step.sm/crypto v0.13.0/go.mod h1:5YzQ85BujYBu6NH18jw7nFjwuRnDch35nLzH0ES5sKg= go.step.sm/linkedca v0.7.0 h1:ydYigs0CgLFkPGjOO4KJcAcAWbuPP8ECF1IsyHdftYc= go.step.sm/linkedca v0.7.0/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo= +go.step.sm/linkedca v0.9.2 h1:CpAkd174sLXFfrOZrbPEiTzik91QRj3+L0omsiwsiok= +go.step.sm/linkedca v0.9.2/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.4.0/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= go.uber.org/atomic v1.5.0/go.mod h1:sABNBOSYdrvTF6hTgEIbc7YasKWGhgEQZyfxyTvoXHQ= @@ -1087,6 +1094,8 @@ golang.org/x/net v0.0.0-20210405180319-a5a99cb37ef4/go.mod h1:p54w0d4576C0XHj96b golang.org/x/net v0.0.0-20210503060351-7fd8e65b6420/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210913180222-943fd674d43e h1:+b/22bPvDYt4NPDcy4xAGCmON713ONAWFeY3Z7I3tR8= golang.org/x/net v0.0.0-20210913180222-943fd674d43e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d h1:1n1fc535VhN8SYtD4cDUyNlfpAF2ROMM9+11equK3hs= +golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1193,6 +1202,8 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210915083310-ed5796bab164/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20211031064116-611d5d643895 h1:iaNpwpnrgL5jzWS0vCNnfa8HqzxveCFpFx3uC/X4Tps= golang.org/x/sys v0.0.0-20211031064116-611d5d643895/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 h1:XfKQ4OlFl8okEOr5UvAqFRVj8pY/4yfcXrddB8qAbU0= +golang.org/x/sys v0.0.0-20220114195835-da31bd327af9/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210503060354-a79de5458b56 h1:b8jxX3zqjpqb2LklXPzKSGJhzyxCOZSz8ncv8Nv+y7w= golang.org/x/term v0.0.0-20210503060354-a79de5458b56/go.mod h1:tfny5GFUkzUvx4ps4ajbZsCe5lw1metzhBm9T3x7oIY= @@ -1388,6 +1399,8 @@ google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxH google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210719143636-1d5a45f8e492 h1:7yQQsvnwjfEahbNNEKcBHv3mR+HnB1ctGY/z1JXzx8M= google.golang.org/genproto v0.0.0-20210719143636-1d5a45f8e492/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= +google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5 h1:zzNejm+EgrbLfDZ6lu9Uud2IVvHySPl8vQzf04laR5Q= +google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= google.golang.org/grpc v1.17.0/go.mod h1:6QZJwpn2B+Zp71q/5VxRsJ6NXXVCE5NRUHRo+f3cWCs= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= @@ -1419,6 +1432,9 @@ google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQ google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.39.0 h1:Klz8I9kdtkIN6EpHHUOMLCYhTn/2WAe5a0s1hcBkdTI= google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= +google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= +google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM= +google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= google.golang.org/grpc/cmd/protoc-gen-go-grpc v1.1.0/go.mod h1:6Kw0yEErY5E/yWrBtf03jp27GLLJujG4z/JK95pnjjw= google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= From f11d88abe1f99b6e9de6b88d4ff21424b07107ef Mon Sep 17 00:00:00 2001 From: max furman Date: Fri, 21 Jan 2022 18:18:21 -0800 Subject: [PATCH 37/52] Merge url.Values and update conditional logic --- command/oauth/cmd.go | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/command/oauth/cmd.go b/command/oauth/cmd.go index 3ed31e87..917ff116 100644 --- a/command/oauth/cmd.go +++ b/command/oauth/cmd.go @@ -357,13 +357,12 @@ func oauthCmd(c *cli.Context) error { parts := strings.SplitN(keyval, "=", 2) var k, v string switch len(parts) { - case 0: - return errs.InvalidFlagValue(c, "auth-param", keyval, "") case 1: k, v = parts[0], "" - authParams.Add(parts[0], "") case 2: k, v = parts[0], parts[1] + default: + return errs.InvalidFlagValue(c, "auth-param", keyval, "") } if k == "" { return errs.InvalidFlagValue(c, "auth-param", keyval, "") @@ -940,7 +939,12 @@ func (o *oauth) Auth() (string, error) { if o.loginHint != "" { q.Add("login_hint", o.loginHint) } - u.RawQuery = fmt.Sprintf("%s&%s", q.Encode(), o.authParams.Encode()) + for k, vs := range o.authParams { + for _, v := range vs { + q.Add(k, v) + } + } + u.RawQuery = q.Encode() return u.String(), nil } From b6b9068b272f49dcebce30e81897df652cf7bb70 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Mon, 24 Jan 2022 14:07:05 +0100 Subject: [PATCH 38/52] Add support for cursor/limit paging --- command/ca/acme/eab/list.go | 30 ++++++++++++++++++++++++++---- flags/flags.go | 6 ++++++ 2 files changed, 32 insertions(+), 4 deletions(-) diff --git a/command/ca/acme/eab/list.go b/command/ca/acme/eab/list.go index ac89baee..c419c486 100644 --- a/command/ca/acme/eab/list.go +++ b/command/ca/acme/eab/list.go @@ -7,10 +7,12 @@ import ( "os/exec" "github.com/pkg/errors" + "github.com/smallstep/certificates/ca" "github.com/smallstep/cli/flags" "github.com/smallstep/cli/utils/cautils" "github.com/urfave/cli" "go.step.sm/cli-utils/errs" + "go.step.sm/linkedca" ) func listCommand() cli.Command { @@ -19,11 +21,12 @@ func listCommand() cli.Command { Action: cli.ActionFunc(listAction), Usage: "list all ACME External Account Binding Keys", UsageText: `**step beta ca acme eab list** [] -[**--admin-cert**=] [**--admin-key**=] +[**--limit**=] [**--admin-cert**=] [**--admin-key**=] [**--admin-provisioner**=] [**--admin-subject**=] [**--password-file**=] [**--ca-url**=] [**--root**=] [**--context**=]`, Flags: []cli.Flag{ + flags.Limit, flags.AdminCert, flags.AdminKey, flags.AdminProvisioner, @@ -79,9 +82,28 @@ func listAction(ctx *cli.Context) (err error) { return errors.Wrap(err, "error creating admin client") } - eaks, err := client.GetExternalAccountKeys(provisioner, reference) - if err != nil { - return errors.Wrap(err, "error retrieving ACME EAB keys") + // default to API paging per 100 entities + limit := 100 + if ctx.IsSet("limit") { + limit = ctx.Int("limit") + } + + cursor := "" + eaks := []*linkedca.EABKey{} + for { + // simply get all entities from the CA first and keep them in memory; in the future we could + // make this more dynamic and load data in the background or only when a user actively pages + // through the results on the CLI. + options := []ca.AdminOption{ca.WithAdminCursor(cursor), ca.WithAdminLimit(limit)} + eaksResponse, err := client.GetExternalAccountKeysPaginate(provisioner, reference, options...) + if err != nil { + return errors.Wrap(err, "error retrieving ACME EAB keys") + } + eaks = append(eaks, eaksResponse.EAKs...) + if eaksResponse.NextCursor == "" { + break + } + cursor = eaksResponse.NextCursor } if len(eaks) == 0 { diff --git a/flags/flags.go b/flags/flags.go index df6146d5..7f870ab3 100644 --- a/flags/flags.go +++ b/flags/flags.go @@ -117,6 +117,12 @@ be written to disk unencrypted. This is not recommended. Requires **--insecure** certificate.`, } + // Limit is a cli.Flag used to limit the number of entities returned in API requests. + Limit = cli.IntFlag{ + Name: "limit", + Usage: `The number of entities to return per (paging) API request.`, + } + // NotBefore is a cli.Flag used to pass the start period of the certificate // validity. NotBefore = cli.StringFlag{ From a95b586dd0bbad8280e622908b3fa4e15d5dccc1 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Mon, 24 Jan 2022 14:43:09 +0100 Subject: [PATCH 39/52] Add --no-pager flag to disable usage of $PAGER --- command/ca/acme/eab/list.go | 8 +++++++- flags/flags.go | 6 ++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/command/ca/acme/eab/list.go b/command/ca/acme/eab/list.go index ed0dc000..8069ece5 100644 --- a/command/ca/acme/eab/list.go +++ b/command/ca/acme/eab/list.go @@ -28,6 +28,7 @@ func listCommand() cli.Command { [**--context**=]`, Flags: []cli.Flag{ flags.Limit, + flags.NoPager, flags.AdminCert, flags.AdminKey, flags.AdminProvisioner, @@ -115,9 +116,14 @@ func listAction(ctx *cli.Context) (err error) { var out io.WriteCloser var cmd *exec.Cmd + usePager := true + if ctx.IsSet("no-pager") { + usePager = !ctx.Bool("no-pager") + } + // prepare the $PAGER command to run pager := os.Getenv("PAGER") - if pager != "" && len(eaks) > 15 { // use $PAGER only when more than 15 results are returned + if usePager && pager != "" && len(eaks) > 15 { // use $PAGER only when not disabled and more than 15 results are returned cmd = exec.Command(pager) var err error out, err = cmd.StdinPipe() diff --git a/flags/flags.go b/flags/flags.go index 7f870ab3..7b1f8e7b 100644 --- a/flags/flags.go +++ b/flags/flags.go @@ -123,6 +123,12 @@ certificate.`, Usage: `The number of entities to return per (paging) API request.`, } + // NoPager is a cli.Flag used to disable usage of $PAGER for paging purposes. + NoPager = cli.BoolFlag{ + Name: "no-pager", + Usage: `Disables usage of $PAGER for paging purposes`, + } + // NotBefore is a cli.Flag used to pass the start period of the certificate // validity. NotBefore = cli.StringFlag{ From 11c8ff23ea6998d68809bb24244de43d82522508 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Mon, 24 Jan 2022 23:34:35 +0100 Subject: [PATCH 40/52] Change $PAGER looping logic The $PAGER will now only request more data from the CA when there's room in the buffer to do so. The result is that new results will be fetched dynamically when the user is scrolling through the list. --- command/ca/acme/eab/list.go | 108 ++++++++++++++++++++-------------- command/ca/acme/eab/remove.go | 5 +- flags/flags.go | 2 +- 3 files changed, 67 insertions(+), 48 deletions(-) diff --git a/command/ca/acme/eab/list.go b/command/ca/acme/eab/list.go index 8069ece5..ac7e2f18 100644 --- a/command/ca/acme/eab/list.go +++ b/command/ca/acme/eab/list.go @@ -5,6 +5,8 @@ import ( "io" "os" "os/exec" + "os/signal" + "syscall" "github.com/pkg/errors" "github.com/smallstep/certificates/ca" @@ -12,8 +14,6 @@ import ( "github.com/smallstep/cli/utils/cautils" "github.com/urfave/cli" "go.step.sm/cli-utils/errs" - "go.step.sm/cli-utils/ui" - "go.step.sm/linkedca" ) func listCommand() cli.Command { @@ -84,35 +84,6 @@ func listAction(ctx *cli.Context) (err error) { return errors.Wrap(err, "error creating admin client") } - // default to API paging per 100 entities - limit := 100 - if ctx.IsSet("limit") { - limit = ctx.Int("limit") - } - - cursor := "" - eaks := []*linkedca.EABKey{} - for { - // simply get all entities from the CA first and keep them in memory; in the future we could - // make this more dynamic and load data in the background or only when a user actively pages - // through the results on the CLI. - options := []ca.AdminOption{ca.WithAdminCursor(cursor), ca.WithAdminLimit(limit)} - eaksResponse, err := client.GetExternalAccountKeysPaginate(provisioner, reference, options...) - if err != nil { - return errors.Wrap(err, "error retrieving ACME EAB keys") - } - eaks = append(eaks, eaksResponse.EAKs...) - if eaksResponse.NextCursor == "" { - break - } - cursor = eaksResponse.NextCursor - } - - if len(eaks) == 0 { - ui.Println("No ACME EAB keys stored for provisioner %s\n", provisioner) - return nil - } - var out io.WriteCloser var cmd *exec.Cmd @@ -121,36 +92,73 @@ func listAction(ctx *cli.Context) (err error) { usePager = !ctx.Bool("no-pager") } - // prepare the $PAGER command to run + // the pipeSignalHandler goroutine ensures that the parent process is closed + // whenever one of its childs is killed. + go pipeSignalHandler() + + // prepare the $PAGER command to run when not disabled and when available pager := os.Getenv("PAGER") - if usePager && pager != "" && len(eaks) > 15 { // use $PAGER only when not disabled and more than 15 results are returned + if usePager && pager != "" { cmd = exec.Command(pager) var err error out, err = cmd.StdinPipe() if err != nil { return errors.Wrap(err, "error setting stdin") } + defer out.Close() cmd.Stdout = os.Stdout - if err := cmd.Start(); err != nil { - return errors.Wrap(err, "unable to start $PAGER") - } } else { out = os.Stdout } - format := "%-36s%-28s%-16s%-30s%-30s%-36s%s\n" - fmt.Fprintf(out, format, "Key ID", "Provisioner", "Key (masked)", "Created At", "Bound At", "Account", "Reference") - for _, k := range eaks { - cliEAK := toCLI(ctx, client, k) - _, err = fmt.Fprintf(out, format, cliEAK.id, cliEAK.provisioner, "*****", cliEAK.createdAt, cliEAK.boundAt, cliEAK.account, cliEAK.reference) - if err != nil { - return errors.Wrap(err, "error writing to output") - } + // default to API paging per 100 entities + limit := uint(0) + if ctx.IsSet("limit") { + limit = ctx.Uint("limit") } + cursor := "" + format := "%-36s%-28s%-16s%-30s%-30s%-36s%s\n" + firstIteration := true + startedPager := false + + for { + options := []ca.AdminOption{ca.WithAdminCursor(cursor), ca.WithAdminLimit(int(limit))} + eaksResponse, err := client.GetExternalAccountKeysPaginate(provisioner, reference, options...) + if err != nil { + return errors.Wrap(err, "error retrieving ACME EAB keys") + } + if firstIteration && len(eaksResponse.EAKs) == 0 { + fmt.Printf("No ACME EAB keys stored for provisioner %s\n", provisioner) + break + } + if firstIteration && cmd != nil { + if err := cmd.Start(); err != nil { + return errors.Wrap(err, "unable to start $PAGER") + } + startedPager = true + } + if firstIteration { + fmt.Fprintf(out, format, "Key ID", "Provisioner", "Key (masked)", "Created At", "Bound At", "Account", "Reference") + firstIteration = false + } + for _, k := range eaksResponse.EAKs { + cliEAK := toCLI(ctx, client, k) + _, err = fmt.Fprintf(out, format, cliEAK.id, cliEAK.provisioner, "*****", cliEAK.createdAt, cliEAK.boundAt, cliEAK.account, cliEAK.reference) + if err != nil { + return errors.Wrap(err, "error writing ACME EAB key to output") + } + } + if eaksResponse.NextCursor == "" { + break + } + cursor = eaksResponse.NextCursor + } + + // ensure closing the output when at the end of what needs to be output out.Close() - if cmd != nil { + if startedPager { if err := cmd.Wait(); err != nil { return errors.Wrap(err, "error waiting for $PAGER") } @@ -158,3 +166,13 @@ func listAction(ctx *cli.Context) (err error) { return nil } + +func pipeSignalHandler() { + signals := make(chan os.Signal, 1) + signal.Notify(signals, syscall.SIGCHLD) + defer signal.Stop(signals) + + for range signals { + os.Exit(0) + } +} diff --git a/command/ca/acme/eab/remove.go b/command/ca/acme/eab/remove.go index 9d4fc6f9..d39583ce 100644 --- a/command/ca/acme/eab/remove.go +++ b/command/ca/acme/eab/remove.go @@ -1,12 +1,13 @@ package eab import ( + "fmt" + "github.com/pkg/errors" "github.com/smallstep/cli/flags" "github.com/smallstep/cli/utils/cautils" "github.com/urfave/cli" "go.step.sm/cli-utils/errs" - "go.step.sm/cli-utils/ui" ) func removeCommand() cli.Command { @@ -68,7 +69,7 @@ func removeAction(ctx *cli.Context) error { return errors.Wrap(err, "error removing ACME EAB key") } - ui.Println("Key was deleted successfully!") + fmt.Println("Key was deleted successfully!") return nil } diff --git a/flags/flags.go b/flags/flags.go index 7b1f8e7b..0dfb09ae 100644 --- a/flags/flags.go +++ b/flags/flags.go @@ -118,7 +118,7 @@ certificate.`, } // Limit is a cli.Flag used to limit the number of entities returned in API requests. - Limit = cli.IntFlag{ + Limit = cli.UintFlag{ Name: "limit", Usage: `The number of entities to return per (paging) API request.`, } From f12eedf2914fbbba57b5fd74aebcd544da1858f4 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Mon, 24 Jan 2022 18:25:25 -0800 Subject: [PATCH 41/52] Fix help --- command/crl/inspect.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/crl/inspect.go b/command/crl/inspect.go index 410e63fd..374e1830 100644 --- a/command/crl/inspect.go +++ b/command/crl/inspect.go @@ -44,7 +44,7 @@ A CRL is considered valid if its signature is valid, the CA is not expired, and ## POSITIONAL ARGUMENTS -: The file or URL where the CRL is. If <**--from**> is passed it will inspect +: The file or URL where the CRL is. If <--from> is passed it will inspect the certificate and extract the CRL distribution point from. ## EXAMPLES From 41303708066aff35c136d9a90194338bd58019e8 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Tue, 25 Jan 2022 22:33:46 +0100 Subject: [PATCH 42/52] Bump github.com/smallstep/certinfo to v1.6.0 --- go.mod | 2 +- go.sum | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/go.mod b/go.mod index e36ddc37..8899b507 100644 --- a/go.mod +++ b/go.mod @@ -17,7 +17,7 @@ require ( github.com/shurcooL/sanitized_anchor_name v1.0.0 github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 github.com/smallstep/certificates v0.18.0 - github.com/smallstep/certinfo v1.5.2 + github.com/smallstep/certinfo v1.6.0 github.com/smallstep/truststore v0.10.1 github.com/smallstep/zcrypto v0.0.0-20210924233136-66c2600f6e71 github.com/smallstep/zlint v0.0.0-20180727184541-d84eaafe274f diff --git a/go.sum b/go.sum index 49cf1a8c..e1680d41 100644 --- a/go.sum +++ b/go.sum @@ -772,8 +772,8 @@ github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1 github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= github.com/smallstep/certificates v0.18.0 h1:Oqt3aVDPIrwN+ujLH0iyaUvoFC3deBlWwDvU6FgiDXY= github.com/smallstep/certificates v0.18.0/go.mod h1:8eHwHNg/bRWvNZo9S0uWFVMkS+LSpDYxM4//EgBhkFM= -github.com/smallstep/certinfo v1.5.2 h1:XO3f9krMkKFDRG4CJFdb3vVoLaXMDAhCn3g0padk9EI= -github.com/smallstep/certinfo v1.5.2/go.mod h1:gA7HBbue0Wwr3kD60P2UtgTIFfMAOC66D3rzYhI0GZ4= +github.com/smallstep/certinfo v1.6.0 h1:o1eS9+iE6OPLRdnRFiYqAtXYR2FioNUt8q4CIj7X3Nk= +github.com/smallstep/certinfo v1.6.0/go.mod h1:DsKAlSDLWsywdiVBCfqqVdRuny77wqiI+NFskLM7Ods= github.com/smallstep/nosql v0.3.9 h1:YPy5PR3PXClqmpFaVv0wfXDXDc7NXGBE1auyU2c87dc= github.com/smallstep/nosql v0.3.9/go.mod h1:X2qkYpNcW3yjLUvhEHfgGfClpKbFPapewvx7zo4TOFs= github.com/smallstep/truststore v0.10.1 h1:+0OUcVAfDzYXw5GUbdOz///6oMNrcPosnztITXLICS8= From 8606fdcf0560e56688309948f5c81d23f8588022 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Thu, 27 Jan 2022 22:29:08 +0100 Subject: [PATCH 43/52] Fix PR comments --- command/ca/provisionerbeta/add.go | 6 +++--- command/ca/provisionerbeta/provisioner.go | 10 +++++----- command/ca/provisionerbeta/update.go | 4 ++-- 3 files changed, 10 insertions(+), 10 deletions(-) diff --git a/command/ca/provisionerbeta/add.go b/command/ca/provisionerbeta/add.go index 76696d96..91aaf5c8 100644 --- a/command/ca/provisionerbeta/add.go +++ b/command/ca/provisionerbeta/add.go @@ -76,7 +76,7 @@ func addCommand() cli.Command { [**--root**=] [**--context**=] **step beta ca provisioner add** **--type**=SCEP [**--force-cn**] [**--challenge**=] -[**--capabilities**=] [**--include-root**] [**--minimum-public-key-length**=] +[**--capabilities**=] [**--include-root**] [**--min-public-key-length**=] [**--encryption-algorithm-identifier**=] [**--admin-cert**=] [**--admin-key**=] [**--admin-provisioner**=] [**--admin-subject**=] [**--password-file**=] [**--ca-url**=] [**--root**=] [**--context**=]`, @@ -271,7 +271,7 @@ Create an SSHPOP provisioner for renewing SSH host certificates:") step beta ca provisioner add sshpop --type SSHPOP ''' -Create a SCEP provisioner with 'secret' challenge and AES-256-CBC: +Create a SCEP provisioner with 'secret' challenge and AES-256-CBC encryption: ''' step beta ca provisioner add my_scep_provisioner --type SCEP --challenge secret --encryption-algorithm-identifier 2 ''' @@ -750,7 +750,7 @@ func createSCEPDetails(ctx *cli.Context) (*linkedca.ProvisionerDetails, error) { ForceCn: ctx.Bool("force-cn"), Challenge: ctx.String("challenge"), Capabilities: ctx.StringSlice("capabilities"), - MinimumPublicKeyLength: int32(ctx.Int("minimum-public-key-length")), + MinimumPublicKeyLength: int32(ctx.Int("min-public-key-length")), IncludeRoot: ctx.Bool("include-root"), EncryptionAlgorithmIdentifier: int32(ctx.Int("encryption-algorithm-identifier")), }, diff --git a/command/ca/provisionerbeta/provisioner.go b/command/ca/provisionerbeta/provisioner.go index d912fd52..504306e8 100644 --- a/command/ca/provisionerbeta/provisioner.go +++ b/command/ca/provisionerbeta/provisioner.go @@ -173,23 +173,23 @@ var ( // SCEP provisioner flags scepChallengeFlag = cli.StringFlag{ Name: "challenge", - Usage: `A SCEP challenge`, + Usage: `The SCEP to use as a shared secret between a client and the CA`, } scepCapabilitiesFlag = cli.StringSliceFlag{ Name: "capabilities", - Usage: `The SCEP capabilities to advertise`, + Usage: `The SCEP to advertise`, } scepIncludeRootFlag = cli.BoolFlag{ Name: "include-root", Usage: `Include the CA root certificate in the SCEP CA certificate chain`, } scepMinimumPublicKeyLengthFlag = cli.IntFlag{ - Name: "minimum-public-key-length", - Usage: `The minimum public key length of the SCEP RSA encryption key`, + Name: "min-public-key-length", + Usage: `The minimum public key of the SCEP RSA encryption key`, } scepEncryptionAlgorithmIdentifierFlag = cli.IntFlag{ Name: "encryption-algorithm-identifier", - Usage: `The identifier for the SCEP encryption algorithm to use. + Usage: `The for the SCEP encryption algorithm to use. Valid values are 0 - 4, inclusive. The values correspond to: 0: DES-CBC, 1: AES-128-CBC, diff --git a/command/ca/provisionerbeta/update.go b/command/ca/provisionerbeta/update.go index 4cf39de7..3824b41a 100644 --- a/command/ca/provisionerbeta/update.go +++ b/command/ca/provisionerbeta/update.go @@ -832,8 +832,8 @@ func updateSCEPDetails(ctx *cli.Context, p *linkedca.Provisioner) error { if ctx.IsSet("capabilities") { details.Capabilities = ctx.StringSlice("capabilities") } - if ctx.IsSet("minimum-public-key-length") { - details.MinimumPublicKeyLength = int32(ctx.Int("minimum-public-key-length")) + if ctx.IsSet("min-public-key-length") { + details.MinimumPublicKeyLength = int32(ctx.Int("min-public-key-length")) } if ctx.IsSet("include-root") { details.IncludeRoot = ctx.Bool("include-root") From 2302522e440382e6c7df5dc14fc4d11bad0fd2d0 Mon Sep 17 00:00:00 2001 From: Herman Slatman Date: Mon, 31 Jan 2022 13:37:13 +0100 Subject: [PATCH 44/52] Upgrade github.com/smallstep/certificates --- go.mod | 11 ++++------- go.sum | 13 ++++++------- 2 files changed, 10 insertions(+), 14 deletions(-) diff --git a/go.mod b/go.mod index d1017b85..dc72cd28 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/samfoo/ansi v0.0.0-20160124022901-b6bd2ded7189 github.com/shurcooL/sanitized_anchor_name v1.0.0 github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 - github.com/smallstep/certificates v0.18.0 + github.com/smallstep/certificates v0.18.1-rc1.0.20220131122744-4a0cfd24e568 github.com/smallstep/certinfo v1.6.0 github.com/smallstep/truststore v0.10.1 github.com/smallstep/zcrypto v0.0.0-20210924233136-66c2600f6e71 @@ -25,22 +25,19 @@ require ( github.com/urfave/cli v1.22.5 go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 go.step.sm/cli-utils v0.7.2 - go.step.sm/crypto v0.14.0 + go.step.sm/crypto v0.15.0 go.step.sm/linkedca v0.9.2 golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 - golang.org/x/net v0.0.0-20211216030914-fe4d6282115f + golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d golang.org/x/sys v0.0.0-20220114195835-da31bd327af9 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 - google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5 // indirect - google.golang.org/grpc v1.43.0 // indirect google.golang.org/protobuf v1.27.1 gopkg.in/square/go-jose.v2 v2.6.0 howett.net/plist v1.0.0 // indirect software.sslmate.com/src/go-pkcs12 v0.0.0-20201103104416-57fc603b7f52 ) -replace github.com/smallstep/certificates => ../certificates - +// replace github.com/smallstep/certificates => ../certificates // replace github.com/smallstep/certinfo => ../certinfo // replace go.step.sm/linkedca => ../linkedca // replace go.step.sm/cli-utils => ../cli-utils diff --git a/go.sum b/go.sum index 140319ef..6a3ede7b 100644 --- a/go.sum +++ b/go.sum @@ -794,6 +794,8 @@ github.com/slackhq/nebula v1.5.2/go.mod h1:xaCM6wqbFk/NRmmUe1bv88fWBm3a1UioXJVIp github.com/smallstep/assert v0.0.0-20180720014142-de77670473b5/go.mod h1:TC9A4+RjIOS+HyTH7wG17/gSqVv95uDw2J64dQZx7RE= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262 h1:unQFBIznI+VYD1/1fApl1A+9VcBk+9dcqGfnePY87LY= github.com/smallstep/assert v0.0.0-20200723003110-82e2b9b3b262/go.mod h1:MyOHs9Po2fbM1LHej6sBUT8ozbxmMOFG+E+rx/GSGuc= +github.com/smallstep/certificates v0.18.1-rc1.0.20220131122744-4a0cfd24e568 h1:RdjkWAbEbT/uAPogNTlu3KU/r7Lyo4fU0d/KGVgaDtQ= +github.com/smallstep/certificates v0.18.1-rc1.0.20220131122744-4a0cfd24e568/go.mod h1:1p5avcwsX+CYrFWD1OTUnpzi4b8wd7LbFYn/OEIH7Q4= github.com/smallstep/certinfo v1.6.0 h1:o1eS9+iE6OPLRdnRFiYqAtXYR2FioNUt8q4CIj7X3Nk= github.com/smallstep/certinfo v1.6.0/go.mod h1:DsKAlSDLWsywdiVBCfqqVdRuny77wqiI+NFskLM7Ods= github.com/smallstep/nosql v0.3.9 h1:YPy5PR3PXClqmpFaVv0wfXDXDc7NXGBE1auyU2c87dc= @@ -976,9 +978,8 @@ go.step.sm/cli-utils v0.7.0/go.mod h1:Ur6bqA/yl636kCUJbp30J7Unv5JJ226eW2KqXPDwF/ go.step.sm/cli-utils v0.7.2 h1:kUNNhGRWAad3bLkhvbLjVr3Dqs5DgxCZQcUspWaQCIQ= go.step.sm/cli-utils v0.7.2/go.mod h1:Ur6bqA/yl636kCUJbp30J7Unv5JJ226eW2KqXPDwF/E= go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0= -go.step.sm/crypto v0.14.0 h1:HzSkUDwqKhODKpsTxevJz956U2xVDZ3sDdGQVwR6Ttw= -go.step.sm/crypto v0.14.0/go.mod h1:3G0yQr5lQqfEG0CMYz8apC/qMtjLRQlzflL2AxkcN+g= -go.step.sm/linkedca v0.9.0/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo= +go.step.sm/crypto v0.15.0 h1:VioBln+x3+RoejgeBhvxkLGVYdWRy6PFiAaUUN29/E0= +go.step.sm/crypto v0.15.0/go.mod h1:3G0yQr5lQqfEG0CMYz8apC/qMtjLRQlzflL2AxkcN+g= go.step.sm/linkedca v0.9.2 h1:CpAkd174sLXFfrOZrbPEiTzik91QRj3+L0omsiwsiok= go.step.sm/linkedca v0.9.2/go.mod h1:5uTRjozEGSPAZal9xJqlaD38cvJcLe3o1VAFVjqcORo= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -1120,8 +1121,9 @@ golang.org/x/net v0.0.0-20210525063256-abc453219eb5/go.mod h1:9nx3DQGgdP8bBQD5qx golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211020060615-d418f374d309/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20211216030914-fe4d6282115f h1:hEYJvxw1lSnWIl8X9ofsYMklzaDs90JI2az5YMd4fPM= golang.org/x/net v0.0.0-20211216030914-fe4d6282115f/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d h1:1n1fc535VhN8SYtD4cDUyNlfpAF2ROMM9+11equK3hs= +golang.org/x/net v0.0.0-20220114011407-0dd24b26b47d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20181106182150-f42d05182288/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -1327,7 +1329,6 @@ golang.org/x/tools v0.1.0/go.mod h1:xkSsbof2nBLbhDlRMhhhyNLN/zl3eTqcnHD5viDpcZ0= golang.org/x/tools v0.1.1/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.2/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.3/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= -golang.org/x/tools v0.1.5/go.mod h1:o0xws9oXOQQZyjljx8fwUC0k7L1pTE6eaCbjGeHmOkk= golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ= golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -1434,7 +1435,6 @@ google.golang.org/genproto v0.0.0-20210429181445-86c259c2b4ab/go.mod h1:P3QM42oQ google.golang.org/genproto v0.0.0-20210513213006-bf773b8c8384/go.mod h1:P3QM42oQyzQSnHPnZ/vqoCdDmzH28fzWByN9asMeM8A= google.golang.org/genproto v0.0.0-20210602131652-f16073e35f0c/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= google.golang.org/genproto v0.0.0-20210604141403-392c879c8b08/go.mod h1:UODoCrxHCcBojKKwX1terBiRUaqAsFqJiF615XL43r0= -google.golang.org/genproto v0.0.0-20210719143636-1d5a45f8e492/go.mod h1:ob2IJxKrgPT52GcgX759i1sleT07tiKowYBGbczaW48= google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5 h1:zzNejm+EgrbLfDZ6lu9Uud2IVvHySPl8vQzf04laR5Q= google.golang.org/genproto v0.0.0-20220118154757-00ab72f36ad5/go.mod h1:5CzLGKJ67TSI2B9POpiiyGha0AjJvZIUgRMt1dSmuhc= google.golang.org/grpc v1.8.0/go.mod h1:yo6s7OP7yaDglbqo1J04qKzAhqBH6lvTonzMVmEdcZw= @@ -1466,7 +1466,6 @@ google.golang.org/grpc v1.36.1/go.mod h1:qjiiYl8FncCW8feJPdyg3v6XW24KsRHe+dy9BAG google.golang.org/grpc v1.37.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.37.1/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= google.golang.org/grpc v1.38.0/go.mod h1:NREThFqKR1f3iQ6oBuvc5LadQuXVGo9rkm5ZGrQdJfM= -google.golang.org/grpc v1.39.0/go.mod h1:PImNr+rS9TWYb2O4/emRugxiyHZ5JyHW5F+RPnDzfrE= google.golang.org/grpc v1.40.0/go.mod h1:ogyxbiOoUXAkP+4+xa6PZSE9DZgIHtSpzjDTB9KAK34= google.golang.org/grpc v1.43.0 h1:Eeu7bZtDZ2DpRCsLhUlcrLnvYaMK1Gz86a+hMVvELmM= google.golang.org/grpc v1.43.0/go.mod h1:k+4IHHFw41K8+bbowsex27ge2rCb65oeWqe4jJ590SU= From 3d6cd9e01d81685449f904e83b8ae0ae0b85d0a3 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Mon, 31 Jan 2022 11:59:19 -0800 Subject: [PATCH 45/52] Add entry to changelog. --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac0a0596..67cb8e80 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add `--format` flag to `step crypto key fingerprint`. - Add `--format` flag to `step ssh fingerprint`. - Add FreeBSD support to `step certificate install`. +- Add `step crl inspect` to inspect a certificate revocation list (CRL). ### Changed ### Deprecated ### Removed From df799eddf531d9ab3f17af06a52c60fb62c1a6f8 Mon Sep 17 00:00:00 2001 From: max furman Date: Mon, 31 Jan 2022 16:40:09 -0800 Subject: [PATCH 46/52] Add --no-agent flag to 'ssh certificate' command --- command/ssh/certificate.go | 29 ++++++++++++++++++++--------- 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/command/ssh/certificate.go b/command/ssh/certificate.go index 97e08c53..9bda53cd 100644 --- a/command/ssh/certificate.go +++ b/command/ssh/certificate.go @@ -40,8 +40,8 @@ func certificateCommand() cli.Command { [**--add-user**] [**--not-before**=] [**--not-after**=] [**--token**=] [**--issuer**=] [**--no-password**] [**--insecure**] [**--force**] [**--x5c-cert**=] -[**--x5c-key**=] [**--k8ssa-token-path**=] [**--ca-url**=] -[**--root**=] [**--context**=]`, +[**--x5c-key**=] [**--k8ssa-token-path**=] [**--no-agent**] +[**--ca-url**=] [**--root**=] [**--context**=]`, Description: `**step ssh certificate** command generates an SSH key pair and creates a certificate using [step certificates](https://github.com/smallstep/certificates). @@ -95,6 +95,11 @@ Generate a new SSH key pair and user certificate: $ step ssh certificate mariano@work id_ecdsa ''' +Generate a new SSH key pair and user certificate and do not add to SSH agent: +''' +$ step ssh certificate mariano@work id_ecdsa --no-agent +''' + Generate a new SSH key pair and user certificate and set the lifetime to 2hrs: ''' $ step ssh certificate mariano@work id_ecdsa --not-after 2h @@ -168,6 +173,10 @@ $ step ssh certificate --token $TOKEN mariano@work id_ecdsa flags.X5cCert, flags.X5cKey, flags.K8sSATokenPathFlag, + cli.BoolFlag{ + Name: "no-agent", + Usage: "Do not add the generated certificate and associated private key to the SSH agent.", + }, flags.CaConfig, flags.CaURL, flags.Root, @@ -460,15 +469,17 @@ func certificateAction(ctx *cli.Context) error { ui.PrintSelected("Certificate", crtFile) // Attempt to add key to agent if private key defined. - if priv != nil && certType == provisioner.SSHUserCert { - if agent, err := sshutil.DialAgent(); err != nil { - ui.Printf(`{{ "%s" | red }} {{ "SSH Agent:" | bold }} %v`+"\n", ui.IconBad, err) - } else { - defer agent.Close() - if err := agent.AddCertificate(subject, resp.Certificate.Certificate, priv); err != nil { + if !ctx.Bool("no-agent") { + if priv != nil && certType == provisioner.SSHUserCert { + if agent, err := sshutil.DialAgent(); err != nil { ui.Printf(`{{ "%s" | red }} {{ "SSH Agent:" | bold }} %v`+"\n", ui.IconBad, err) } else { - ui.PrintSelected("SSH Agent", "yes") + defer agent.Close() + if err := agent.AddCertificate(subject, resp.Certificate.Certificate, priv); err != nil { + ui.Printf(`{{ "%s" | red }} {{ "SSH Agent:" | bold }} %v`+"\n", ui.IconBad, err) + } else { + ui.PrintSelected("SSH Agent", "yes") + } } } } From 003eb885dcd28261172eee865d4e889e879a765b Mon Sep 17 00:00:00 2001 From: max furman Date: Mon, 31 Jan 2022 18:42:35 -0800 Subject: [PATCH 47/52] Update changelog --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index ac0a0596..e290f503 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,8 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. - Add `--format` flag to `step crypto key fingerprint`. - Add `--format` flag to `step ssh fingerprint`. - Add FreeBSD support to `step certificate install`. +- Add `--auth-param` flag to `step oauth` for adding args to query +- Add `--no-agent` flag to `step ssh certificate` to skip ssh-add ### Changed ### Deprecated ### Removed From 340cd41dd8eb9e00c3327bd45771d5e368a7e5e9 Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 1 Feb 2022 13:07:25 -0800 Subject: [PATCH 48/52] Merge if conditions --- command/ssh/certificate.go | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/command/ssh/certificate.go b/command/ssh/certificate.go index 9bda53cd..75495d29 100644 --- a/command/ssh/certificate.go +++ b/command/ssh/certificate.go @@ -469,17 +469,15 @@ func certificateAction(ctx *cli.Context) error { ui.PrintSelected("Certificate", crtFile) // Attempt to add key to agent if private key defined. - if !ctx.Bool("no-agent") { - if priv != nil && certType == provisioner.SSHUserCert { - if agent, err := sshutil.DialAgent(); err != nil { + if !ctx.Bool("no-agent") && priv != nil && certType == provisioner.SSHUserCert { + if agent, err := sshutil.DialAgent(); err != nil { + ui.Printf(`{{ "%s" | red }} {{ "SSH Agent:" | bold }} %v`+"\n", ui.IconBad, err) + } else { + defer agent.Close() + if err := agent.AddCertificate(subject, resp.Certificate.Certificate, priv); err != nil { ui.Printf(`{{ "%s" | red }} {{ "SSH Agent:" | bold }} %v`+"\n", ui.IconBad, err) } else { - defer agent.Close() - if err := agent.AddCertificate(subject, resp.Certificate.Certificate, priv); err != nil { - ui.Printf(`{{ "%s" | red }} {{ "SSH Agent:" | bold }} %v`+"\n", ui.IconBad, err) - } else { - ui.PrintSelected("SSH Agent", "yes") - } + ui.PrintSelected("SSH Agent", "yes") } } } From 84c641c64ef84cbbcb65008fbf2e1a76c2fd0663 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Tue, 1 Feb 2022 13:09:07 -0800 Subject: [PATCH 49/52] Fix typo. --- command/crl/crl_extensions.go | 2 +- command/crl/inspect.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/command/crl/crl_extensions.go b/command/crl/crl_extensions.go index 2f44c31b..dfa33b53 100644 --- a/command/crl/crl_extensions.go +++ b/command/crl/crl_extensions.go @@ -96,7 +96,7 @@ func (e *Extension) AddDetail(format string, args ...interface{}) { e.Details = append(e.Details, fmt.Sprintf(format, args...)) } -func nexExtension(e pkix.Extension) Extension { +func newExtension(e pkix.Extension) Extension { var ext Extension switch { case e.Id.Equal(oidExtensionReasonCode): diff --git a/command/crl/inspect.go b/command/crl/inspect.go index 374e1830..1f82502c 100644 --- a/command/crl/inspect.go +++ b/command/crl/inspect.go @@ -288,7 +288,7 @@ func ParseCRL(b []byte) (*CRL, error) { var issuerKeyID []byte extensions := make([]Extension, len(tcrl.Extensions)) for i, e := range tcrl.Extensions { - extensions[i] = nexExtension(e) + extensions[i] = newExtension(e) if e.Id.Equal(oidExtensionAuthorityKeyID) { var v authorityKeyID if _, err := asn1.Unmarshal(e.Value, &v); err == nil { From 117f1316bd9e663bc0b9a223a8bdd8c2eb4ee0ea Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Tue, 1 Feb 2022 13:12:18 -0800 Subject: [PATCH 50/52] Fix flag in help. --- command/crl/inspect.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/command/crl/inspect.go b/command/crl/inspect.go index 1f82502c..b2a5fd11 100644 --- a/command/crl/inspect.go +++ b/command/crl/inspect.go @@ -56,7 +56,7 @@ $ step crl inspect --insecure http://ca.example.com/crls/exampleca.crl Inspect and validate a CRL in a file: ''' -$ step crl inspect -ca ca.crt exampleca.crl +$ step crl inspect --ca ca.crt exampleca.crl ''' Format the CRL in JSON: From 2911198962d6a58bcbc99f92d0968a6493a62416 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Tue, 1 Feb 2022 13:13:01 -0800 Subject: [PATCH 51/52] Remove debug statement. --- command/crl/inspect.go | 1 - 1 file changed, 1 deletion(-) diff --git a/command/crl/inspect.go b/command/crl/inspect.go index b2a5fd11..a79f41e6 100644 --- a/command/crl/inspect.go +++ b/command/crl/inspect.go @@ -195,7 +195,6 @@ func inspectAction(ctx *cli.Context) error { } if len(caCerts) == 0 && !ctx.Bool("insecure") { - println("foo") return errs.InsecureCommand(ctx) } } From 4ac6c55613353bb726c48e3d61809d6dc9d5d06d Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Tue, 1 Feb 2022 13:17:05 -0800 Subject: [PATCH 52/52] Mention that text is the default format. --- command/crl/inspect.go | 1 + 1 file changed, 1 insertion(+) diff --git a/command/crl/inspect.go b/command/crl/inspect.go index a79f41e6..7eabe01a 100644 --- a/command/crl/inspect.go +++ b/command/crl/inspect.go @@ -78,6 +78,7 @@ $ step crl inspect --from https://www.google.com **text** : Print output in unstructured text suitable for a human to read. + This is the default format. **json** : Print output in JSON format.