From abfcda25b780f9e1829699d2e5d4605db7c28ae0 Mon Sep 17 00:00:00 2001 From: jibin george Date: Fri, 26 Jul 2019 19:47:47 +0530 Subject: [PATCH 01/29] Added configurable callback listener Add cli flag to configure callback listener's port. default 127.0.0.1:8080 --- command/oauth/cmd.go | 44 +++++++++++++++++++++++++++++++++++--------- 1 file changed, 35 insertions(+), 9 deletions(-) diff --git a/command/oauth/cmd.go b/command/oauth/cmd.go index 87d6e789..027b23b2 100644 --- a/command/oauth/cmd.go +++ b/command/oauth/cmd.go @@ -9,6 +9,7 @@ import ( "encoding/pem" "fmt" "io/ioutil" + "net" "net/http" "net/http/httptest" "net/url" @@ -129,6 +130,11 @@ func init() { Name: "jwt", Usage: "Generate a JWT Auth token instead of an OAuth Token (only works with service accounts)", }, + cli.StringFlag{ + Name: "listen", + Value: "127.0.0.1:8080", + Usage: "Callback listener URL (default: 127.0.0.1:8080)", + }, cli.BoolFlag{ Name: "implicit", Usage: "Uses the implicit flow to authenticate the user. Requires **--insecure** and **--client-id** flags.", @@ -148,10 +154,11 @@ func init() { func oauthCmd(c *cli.Context) error { opts := &options{ - Provider: c.String("provider"), - Email: c.String("email"), - Console: c.Bool("console"), - Implicit: c.Bool("implicit"), + Provider: c.String("provider"), + Email: c.String("email"), + Console: c.Bool("console"), + Implicit: c.Bool("implicit"), + CallbackListener: c.String("listen"), } if err := opts.Validate(); err != nil { return err @@ -274,10 +281,11 @@ func oauthCmd(c *cli.Context) error { } type options struct { - Provider string - Email string - Console bool - Implicit bool + Provider string + Email string + Console bool + Implicit bool + CallbackListener string } // Validate validates the options. @@ -302,6 +310,7 @@ type oauth struct { codeChallenge string nonce string implicit bool + CallbackListener string errCh chan error tokCh chan *token } @@ -337,6 +346,7 @@ func newOauth(provider, clientID, clientSecret, authzEp, tokenEp, scope string, codeChallenge: challenge, nonce: nonce, implicit: opts.Implicit, + CallbackListener: opts.CallbackListener, errCh: make(chan error), tokCh: make(chan *token), }, nil @@ -371,6 +381,7 @@ func newOauth(provider, clientID, clientSecret, authzEp, tokenEp, scope string, codeChallenge: challenge, nonce: nonce, implicit: opts.Implicit, + CallbackListener: opts.CallbackListener, errCh: make(chan error), tokCh: make(chan *token), }, nil @@ -404,11 +415,26 @@ func disco(provider string) (map[string]interface{}, error) { return details, err } +func (o *oauth) NewServer() (*httptest.Server, error) { + l, err := net.Listen("tcp", o.CallbackListener) + if err != nil { + return nil, err + } + srv := httptest.NewUnstartedServer(o) + srv.Listener.Close() + srv.Listener = l + srv.Start() + return srv, nil +} + // DoLoopbackAuthorization performs the log in into the identity provider // opening a browser and using a redirect_uri in a loopback IP address // (http://127.0.0.1:port or http://[::1]:port). func (o *oauth) DoLoopbackAuthorization() (*token, error) { - srv := httptest.NewServer(o) + srv, err := o.NewServer() + if err != nil { + return nil, err + } o.redirectURI = srv.URL defer srv.Close() From 8ba584f772cf4661c604b3cfc87a5f8dbbf07782 Mon Sep 17 00:00:00 2001 From: jibin george Date: Sat, 27 Jul 2019 07:59:31 +0530 Subject: [PATCH 02/29] review changes --- command/oauth/cmd.go | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/command/oauth/cmd.go b/command/oauth/cmd.go index 027b23b2..31b5e089 100644 --- a/command/oauth/cmd.go +++ b/command/oauth/cmd.go @@ -132,8 +132,7 @@ func init() { }, cli.StringFlag{ Name: "listen", - Value: "127.0.0.1:8080", - Usage: "Callback listener URL (default: 127.0.0.1:8080)", + Usage: "Callback listener URL", }, cli.BoolFlag{ Name: "implicit", @@ -415,14 +414,19 @@ func disco(provider string) (map[string]interface{}, error) { return details, err } +// NewServer creates http server func (o *oauth) NewServer() (*httptest.Server, error) { + if o.CallbackListener == "" { + return httptest.NewServer(o), nil + } l, err := net.Listen("tcp", o.CallbackListener) if err != nil { - return nil, err + return nil, errors.Wrapf(err, "error listening on %s", o.CallbackListener) + } + srv := &httptest.Server{ + Listener: l, + Config: &http.Server{Handler: o}, } - srv := httptest.NewUnstartedServer(o) - srv.Listener.Close() - srv.Listener = l srv.Start() return srv, nil } From 60085840deaefa56d89e656443fb794d23ee3fa6 Mon Sep 17 00:00:00 2001 From: max furman Date: Fri, 9 Aug 2019 12:17:02 -0700 Subject: [PATCH 03/29] Add a self-signed x509 profile and enable created from cli --- command/certificate/create.go | 28 ++++++++++++++++++++++++++-- crypto/x509util/leafProfile.go | 14 ++++++++++++++ 2 files changed, 40 insertions(+), 2 deletions(-) diff --git a/command/certificate/create.go b/command/certificate/create.go index f396fddd..88bb8a00 100644 --- a/command/certificate/create.go +++ b/command/certificate/create.go @@ -113,6 +113,12 @@ $ step certificate create foo foo.crt foo.key --profile leaf \ --not-before 24h --not-after 2160h ''' +Create a self-signed leaf certificate and key: + +''' +$ step certificate create self-signed-leaf.local leaf.crt leaf.key --profile self-signed --subtle +''' + Create a root certificate and key with underlying OKP Ed25519: ''' @@ -179,7 +185,12 @@ recommended. Requires **--insecure** flag.`, : Generate a certificate that can be used to sign additional leaf or intermediate certificates. **root-ca** - : Generate a new self-signed root certificate suitable for use as a root CA.`, + : Generate a new self-signed root certificate suitable for use as a root CA. + + **self-signed** + : Generate a new self-signed leaf certificate suitable for use with TLS. + This profile requires the **--subtle** flag because the use of self-signed leaf + certificates is discouraged unless absolutely necessary.`, }, cli.StringFlag{ Name: "kty", @@ -247,6 +258,7 @@ unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", flag multiple times to configure multiple SANs.`, }, flags.Force, + flags.Subtle, }, } } @@ -389,8 +401,20 @@ func createAction(ctx *cli.Context) error { if err != nil { return errors.WithStack(err) } + case "self-signed": + if !ctx.Bool("subtle") { + return errs.RequiredWithFlagValue(ctx, "profile", "self-signed", "subtle") + } + profile, err = x509util.NewSelfSignedLeafProfile(subject, + x509util.GenerateKeyPair(kty, crv, size), + x509util.WithNotBeforeAfterDuration(notBefore, notAfter, 0), + x509util.WithDNSNames(dnsNames), + x509util.WithIPAddresses(ips)) + if err != nil { + return errors.WithStack(err) + } default: - return errs.InvalidFlagValue(ctx, "profile", prof, "leaf, intermediate-ca, root-ca") + return errs.InvalidFlagValue(ctx, "profile", prof, "leaf, intermediate-ca, root-ca, self-signed") } crtBytes, err := profile.CreateCertificate() if err != nil { diff --git a/crypto/x509util/leafProfile.go b/crypto/x509util/leafProfile.go index 603d57ce..3710f566 100644 --- a/crypto/x509util/leafProfile.go +++ b/crypto/x509util/leafProfile.go @@ -31,6 +31,20 @@ func NewLeafProfile(cn string, iss *x509.Certificate, issPriv crypto.PrivateKey, return newProfile(&Leaf{}, sub, iss, issPriv, withOps...) } +// NewSelfSignedLeafProfile returns a new leaf x509 Certificate profile. +// A new public/private key pair will be generated for the Profile if +// not set in the `withOps` profile modifiers. +func NewSelfSignedLeafProfile(cn string, withOps ...WithOption) (Profile, error) { + sub := defaultLeafTemplate(pkix.Name{CommonName: cn}, pkix.Name{CommonName: cn}) + p, err := newProfile(&Leaf{}, sub, sub, nil, withOps...) + if err != nil { + return nil, err + } + // self-signed certificate + p.SetIssuerPrivateKey(p.SubjectPrivateKey()) + return p, nil +} + // NewLeafProfileWithCSR returns a new leaf x509 Certificate Profile with // Subject Certificate fields populated directly from the CSR. // A public/private keypair **WILL NOT** be generated for this profile because From 4648f3bde16d70e23d7b989cb607e6d1832bf500 Mon Sep 17 00:00:00 2001 From: max furman Date: Mon, 12 Aug 2019 17:40:58 -0400 Subject: [PATCH 04/29] Add enhancement issue template --- .github/ISSUE_TEMPLATE/enhancement.md | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/enhancement.md diff --git a/.github/ISSUE_TEMPLATE/enhancement.md b/.github/ISSUE_TEMPLATE/enhancement.md new file mode 100644 index 00000000..01ad40d1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/enhancement.md @@ -0,0 +1,11 @@ +--- +name: CLI Enhancement +about: Suggest an enhancement to step cli +labels: area/cert-management enhancement +--- + +### What would you like to be added + + +### Why this is needed + From 4e65e79a7ac5445c11f70d7d94199d5deb971741 Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 13 Aug 2019 12:57:10 -0400 Subject: [PATCH 05/29] wip --- command/certificate/create.go | 28 ++++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/command/certificate/create.go b/command/certificate/create.go index 88bb8a00..82df6146 100644 --- a/command/certificate/create.go +++ b/command/certificate/create.go @@ -256,6 +256,11 @@ unit suffix, such as "300ms", "-1.5h" or "2h45m". Valid time units are "ns", Name: "san", Usage: `Add DNS or IP Address Subjective Alternative Names (SANs). Use the '--san' flag multiple times to configure multiple SANs.`, + }, + cli.BoolFlag{ + Name: "bundle", + Usage: `Bundle the new leaf certificate with the signing certificate. This flag requires +the **--ca** flag.`, }, flags.Force, flags.Subtle, @@ -313,11 +318,15 @@ func createAction(ctx *cli.Context) error { var ( priv interface{} - pubPEM *pem.Block + pubPEMs []*pem.Block outputType string + bundle = ctx.Bool("bundle") ) switch typ { case "x509-csr": + if bundle { + return errs.IncompatibleFlagWithFlag(ctx, "bundle", "csr") + } if ctx.IsSet("profile") { return errs.IncompatibleFlagWithFlag(ctx, "profile", "csr") } @@ -338,11 +347,11 @@ func createAction(ctx *cli.Context) error { return errors.WithStack(err) } - pubPEM = &pem.Block{ + pubPEMs = []*pem.Block{&pem.Block{ Type: "CERTIFICATE REQUEST", Bytes: csrBytes, Headers: map[string]string{}, - } + }} outputType = "certificate signing request" case "x509": var ( @@ -352,6 +361,9 @@ func createAction(ctx *cli.Context) error { caKeyPath = ctx.String("ca-key") profile x509util.Profile ) + if bundle && prof != "leaf" { + return errs.IncompatibleFlagValue(ctx, "bundle", "profile", prof) + } switch prof { case "leaf", "intermediate-ca": if caPath == "" { @@ -420,18 +432,22 @@ func createAction(ctx *cli.Context) error { if err != nil { return errors.WithStack(err) } - pubPEM = &pem.Block{ + pubPEMs = []*pem.Block{&pem.Block{ Type: "CERTIFICATE", Bytes: crtBytes, Headers: map[string]string{}, - } + }} priv = profile.SubjectPrivateKey() outputType = "certificate" default: return errs.NewError("unexpected type: %s", typ) } - if err := utils.WriteFile(crtFile, pem.EncodeToMemory(pubPEM), 0600); err != nil { + pubBytes := []byte{} + for _, pp := range pubPEMs { + pubBytes = append(pubBytes, pem.EncodeToMemory(pp)...) + } + if err := utils.WriteFile(crtFile, pubBytes, 0600); err != nil { return errs.FileError(err, crtFile) } From 82d32aee4438ef2e5889459ccfce98194f672631 Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 14 Aug 2019 12:43:58 -0400 Subject: [PATCH 06/29] Add bundle option to 'certificate [sign|create]' * Fixes #126 --- command/certificate/create.go | 17 +++++++++++------ command/certificate/sign.go | 36 +++++++++++++++++++++++++++++------ 2 files changed, 41 insertions(+), 12 deletions(-) diff --git a/command/certificate/create.go b/command/certificate/create.go index 82df6146..f57bec25 100644 --- a/command/certificate/create.go +++ b/command/certificate/create.go @@ -26,7 +26,7 @@ func createCommand() cli.Command { UsageText: `**step certificate create** [**ca**=] [**ca-key**=] [**--csr**] [**--curve**=] [**no-password**] [**--profile**=] -[**--size**=] [**--type**=] [**--san**=]`, +[**--size**=] [**--type**=] [**--san**=] [**--bundle**]`, Description: `**step certificate create** generates a certificate or a certificate signing requests (CSR) that can be signed later using 'step certificates sign' (or some other tool) to produce a certificate. @@ -347,7 +347,7 @@ func createAction(ctx *cli.Context) error { return errors.WithStack(err) } - pubPEMs = []*pem.Block{&pem.Block{ + pubPEMs = []*pem.Block{{ Type: "CERTIFICATE REQUEST", Bytes: csrBytes, Headers: map[string]string{}, @@ -432,11 +432,16 @@ func createAction(ctx *cli.Context) error { if err != nil { return errors.WithStack(err) } - pubPEMs = []*pem.Block{&pem.Block{ - Type: "CERTIFICATE", - Bytes: crtBytes, - Headers: map[string]string{}, + pubPEMs = []*pem.Block{{ + Type: "CERTIFICATE", + Bytes: crtBytes, }} + if bundle { + pubPEMs = append(pubPEMs, &pem.Block{ + Type: "CERTIFICATE", + Bytes: profile.Issuer().Raw, + }) + } priv = profile.SubjectPrivateKey() outputType = "certificate" default: diff --git a/command/certificate/sign.go b/command/certificate/sign.go index e5aa7f70..1283e27c 100644 --- a/command/certificate/sign.go +++ b/command/certificate/sign.go @@ -13,10 +13,11 @@ import ( func signCommand() cli.Command { return cli.Command{ - Name: "sign", - Action: cli.ActionFunc(signAction), - Usage: "sign a certificate signing request (CSR)", - UsageText: `**step certificate sign** `, + Name: "sign", + Action: cli.ActionFunc(signAction), + Usage: "sign a certificate signing request (CSR)", + UsageText: `**step certificate sign** +[**--bundle**]`, Description: `**step certificate sign** generates a signed certificate from a certificate signing request (CSR). @@ -43,7 +44,20 @@ Sign a certificate signing request: $ step certificate sign ./certificate-signing-request.csr \ ./issuer-certificate.crt ./issuer-private-key.priv ''' + +Sign a certificate signing request and bundle the new certificate with the issuer: + +''' +$ step certificate sign ./certificate-signing-request.csr \ +./issuer-certificate.crt ./issuer-private-key.priv --bundle +''' `, + Flags: []cli.Flag{ + cli.BoolFlag{ + Name: "bundle", + Usage: `Bundle the new leaf certificate with the signing certificate.`, + }, + }, } } @@ -83,11 +97,21 @@ func signAction(ctx *cli.Context) error { if err != nil { return errors.Wrapf(err, "failure creating new leaf certificate from input csr") } - block := &pem.Block{ + pubPEMs := []*pem.Block{{ Type: "CERTIFICATE", Bytes: crtBytes, + }} + if ctx.Bool("bundle") { + pubPEMs = append(pubPEMs, &pem.Block{ + Type: "CERTIFICATE", + Bytes: issuerIdentity.Crt.Raw, + }) } - fmt.Printf("%s", string(pem.EncodeToMemory(block))) + pubBytes := []byte{} + for _, pp := range pubPEMs { + pubBytes = append(pubBytes, pem.EncodeToMemory(pp)...) + } + fmt.Printf("%s", string(pubBytes)) return nil } From 34396e2e322024a8c67235553e5e24adf30a9e30 Mon Sep 17 00:00:00 2001 From: Sebastian Tiedtke Date: Mon, 19 Aug 2019 12:44:38 -0700 Subject: [PATCH 07/29] Seb/new website frontmatter (#128) Add hugo compatibility for docs --- usage/help.go | 4 ++++ usage/html.go | 25 ++++++++++++++++++------- usage/printer.go | 20 +++++++++++++++++--- 3 files changed, 39 insertions(+), 10 deletions(-) diff --git a/usage/help.go b/usage/help.go index 4ded437f..c32a877c 100644 --- a/usage/help.go +++ b/usage/help.go @@ -41,6 +41,10 @@ func HelpCommand() cli.Command { Name: "report", Usage: "Writes a JSON report to the HTML docs directory.", }, + cli.BoolFlag{ + Name: "hugo", + Usage: "Writes hugo (vs jekyll) compatible markdown files", + }, }, } } diff --git a/usage/html.go b/usage/html.go index 07a11561..596965af 100644 --- a/usage/html.go +++ b/usage/html.go @@ -36,46 +36,57 @@ func markdownHelpAction(ctx *cli.Context) error { if err != nil { return errs.FileError(err, index) } - markdownHelpPrinter(w, mdAppHelpTemplate, ctx.App) + markdownHelpPrinter(w, mdAppHelpTemplate, "", ctx.App) if err := w.Close(); err != nil { return errs.FileError(err, index) } + // preserve jekyll compatibility for transition period + fileName := "index.md" + if ctx.Bool("hugo") { + fileName = "_index.md" + } + // Subcommands for _, cmd := range ctx.App.Commands { - if err := markdownHelpCommand(ctx.App, cmd, path.Join(dir, cmd.Name)); err != nil { + if err := markdownHelpCommand(ctx.App, cmd, cmd, path.Join(dir, cmd.Name), fileName); err != nil { return err } } return nil } -func markdownHelpCommand(app *cli.App, cmd cli.Command, base string) error { +func markdownHelpCommand(app *cli.App, cmd cli.Command, parent cli.Command, base string, fileName string) error { if err := os.MkdirAll(base, 0755); err != nil { return errs.FileError(err, base) } - index := path.Join(base, "index.md") + index := path.Join(base, fileName) w, err := os.Create(index) if err != nil { return errs.FileError(err, index) } + parentName := parent.HelpName + if cmd.HelpName == parent.HelpName { + parentName = "step" + } + if len(cmd.Subcommands) == 0 { - markdownHelpPrinter(w, mdCommandHelpTemplate, cmd) + markdownHelpPrinter(w, mdCommandHelpTemplate, parentName, cmd) return errs.FileError(w.Close(), index) } ctx := cli.NewContext(app, nil, nil) ctx.App = createCliApp(ctx, cmd) - markdownHelpPrinter(w, mdSubcommandHelpTemplate, ctx.App) + markdownHelpPrinter(w, mdSubcommandHelpTemplate, parentName, ctx.App) if err := w.Close(); err != nil { return errs.FileError(err, index) } for _, sub := range cmd.Subcommands { sub.HelpName = fmt.Sprintf("%s %s", cmd.HelpName, sub.Name) - if err := markdownHelpCommand(app, sub, path.Join(base, sub.Name)); err != nil { + if err := markdownHelpCommand(app, sub, cmd, path.Join(base, sub.Name), fileName); err != nil { return err } } diff --git a/usage/printer.go b/usage/printer.go index c68598c2..cf853e06 100644 --- a/usage/printer.go +++ b/usage/printer.go @@ -16,6 +16,11 @@ var sectionRe = regexp.MustCompile(`(?m:^##)`) //var sectionRe = regexp.MustCompile(`^## [^\n]*$`) +type frontmatterData struct { + Data interface{} + Parent string +} + // HelpPrinter overwrites cli.HelpPrinter and prints the formatted help to the terminal. func HelpPrinter(w io.Writer, templ string, data interface{}) { b := helpPreprocessor(w, templ, data) @@ -34,11 +39,20 @@ func htmlHelpPrinter(w io.Writer, templ string, data interface{}) []byte { return html } -func markdownHelpPrinter(w io.Writer, templ string, data interface{}) { +func markdownHelpPrinter(w io.Writer, templ string, parent string, data interface{}) { b := helpPreprocessor(w, templ, data) + + frontmatter := frontmatterData{ + Data: data, + Parent: parent, + } + var frontMatterTemplate = `--- layout: auto-doc -title: {{.HelpName}} +title: {{.Data.HelpName}}{{if .Parent}} +menu: + docs: + parent: {{.Parent}}{{end}} --- ` @@ -46,7 +60,7 @@ title: {{.HelpName}} if err != nil { panic(err) } - err = t.Execute(w, data) + err = t.Execute(w, frontmatter) if err != nil { panic(err) } From cfb7030e52eecb943a375c5696a94ab8e9b51085 Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 20 Aug 2019 20:48:50 -0700 Subject: [PATCH 08/29] dep update zrypto and certinfo --- Gopkg.lock | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 3dca3300..3b667430 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -410,11 +410,11 @@ [[projects]] branch = "master" - digest = "1:c3207093bfee46dc9f408a55408d6fa6ed59431bdeb54df2ab89ffa1d8e1bfaf" + digest = "1:f4d37f61cbbd5adb7066017d7e5f303b722a39c3408b41d46a5ea04f81adba8c" name = "github.com/smallstep/certinfo" packages = ["."] pruneopts = "UT" - revision = "fef09aeb6b3b6451151ae248670cf020454c0d5b" + revision = "203093530c86c19d79cfe5ce9ad0b8897e3cce9b" [[projects]] branch = "master" @@ -440,7 +440,7 @@ [[projects]] branch = "master" - digest = "1:167fb96bb586d7abc0714a63d5bd30f24563d369012b295268db4d64008c4f7d" + digest = "1:822ad7c8c41fe68fb9c9c95ad7e77a1172e216d9e3e527451819927448b6dee6" name = "github.com/smallstep/zcrypto" packages = [ "json", @@ -449,7 +449,7 @@ "x509/pkix", ] pruneopts = "UT" - revision = "0eaa490bf930eb2c8f1fd0dec8750619588aadae" + revision = "6bab21fcaafc3d150cf793b6d5f25fe32f49c80e" [[projects]] branch = "master" From c05a035f0f26685c4f301a2a10db0555afbdd587 Mon Sep 17 00:00:00 2001 From: Sebastian Tiedtke Date: Tue, 20 Aug 2019 13:46:25 -0700 Subject: [PATCH 09/29] Hugo wants underscores in dirs with subdirs only --- usage/html.go | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/usage/html.go b/usage/html.go index 596965af..2d0827ff 100644 --- a/usage/html.go +++ b/usage/html.go @@ -30,6 +30,8 @@ func markdownHelpAction(ctx *cli.Context) error { return errs.FileError(err, dir) } + isHugo := ctx.Bool("hugo") + // app index index := path.Join(dir, "step.md") w, err := os.Create(index) @@ -41,26 +43,26 @@ func markdownHelpAction(ctx *cli.Context) error { return errs.FileError(err, index) } - // preserve jekyll compatibility for transition period - fileName := "index.md" - if ctx.Bool("hugo") { - fileName = "_index.md" - } - // Subcommands for _, cmd := range ctx.App.Commands { - if err := markdownHelpCommand(ctx.App, cmd, cmd, path.Join(dir, cmd.Name), fileName); err != nil { + if err := markdownHelpCommand(ctx.App, cmd, cmd, path.Join(dir, cmd.Name), isHugo); err != nil { return err } } return nil } -func markdownHelpCommand(app *cli.App, cmd cli.Command, parent cli.Command, base string, fileName string) error { +func markdownHelpCommand(app *cli.App, cmd cli.Command, parent cli.Command, base string, isHugo bool) error { if err := os.MkdirAll(base, 0755); err != nil { return errs.FileError(err, base) } + fileName := "index.md" + // preserve jekyll compatibility for transition period + if isHugo && len(cmd.Subcommands) > 0 { + fileName = "_index.md" + } + index := path.Join(base, fileName) w, err := os.Create(index) if err != nil { @@ -86,7 +88,7 @@ func markdownHelpCommand(app *cli.App, cmd cli.Command, parent cli.Command, base for _, sub := range cmd.Subcommands { sub.HelpName = fmt.Sprintf("%s %s", cmd.HelpName, sub.Name) - if err := markdownHelpCommand(app, sub, cmd, path.Join(base, sub.Name), fileName); err != nil { + if err := markdownHelpCommand(app, sub, cmd, path.Join(base, sub.Name), isHugo); err != nil { return err } } From 3fe62163c6f077f8e1b0e51b71eba97af7e2b1ce Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 21 Aug 2019 12:58:17 -0700 Subject: [PATCH 10/29] Dep change golang/lint due to vendoring issue * golang/lint deleted the branch and commit that we were previously relying on. Master is broken (for our purposes), so needed to go back in time to find a commit that works. --- Gopkg.lock | 18 +++++++++++------- Gopkg.toml | 4 ++++ 2 files changed, 15 insertions(+), 7 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 3b667430..a19db527 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -135,15 +135,11 @@ version = "v1.4.1" [[projects]] - branch = "travis-1.9" - digest = "1:e8f5d9c09a7209c740e769713376abda388c41b777ba8e9ed52767e21acf379f" + digest = "1:4ee452f8994700dcab9e816aef1cb9eb2317218734c6ccf5135746e6c19f3dce" name = "github.com/golang/lint" - packages = [ - ".", - "golint", - ] + packages = ["golint"] pruneopts = "UT" - revision = "883fe33ffc4344bad1ecd881f61afd5ec5d80e0a" + revision = "06c8688daad7faa9da5a0c2f163a3d14aac986ca" [[projects]] digest = "1:318f1c959a8a740366fce4b1e1eb2fd914036b4af58fbd0a003349b305f118ad" @@ -535,6 +531,14 @@ pruneopts = "UT" revision = "4d3f4d9ffa16a13f451c3b2999e9c49e9750bf06" +[[projects]] + branch = "master" + digest = "1:0824a2eb250dd552f41daaf471266d085e8e8cabdbff9e4294bc799076e00da7" + name = "golang.org/x/lint" + packages = ["."] + pruneopts = "UT" + revision = "959b441ac422379a43da2230f62be024250818b0" + [[projects]] branch = "master" digest = "1:2f7468b0b3fd7d926072f0dcbb6ec81e337278b4e5de639d017e54f785f0b475" diff --git a/Gopkg.toml b/Gopkg.toml index 09ab76a6..77bc5adb 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -31,6 +31,10 @@ required = [ "github.com/tsenart/deadcode", ] +[[constraint]] + name = "github.com/golang/lint" + revision = "06c8688daad7faa9da5a0c2f163a3d14aac986ca" + [[constraint]] name = "github.com/alecthomas/gometalinter" revision = "bae2f1293d092fd8167939d5108d1b025eaef9de" From 7add520a419ed64fc889002758ee8c097b8562ff Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 21 Aug 2019 18:19:31 -0700 Subject: [PATCH 11/29] linting --- command/certificate/create.go | 3 --- crypto/pki/pki.go | 19 +++++++++---------- 2 files changed, 9 insertions(+), 13 deletions(-) diff --git a/command/certificate/create.go b/command/certificate/create.go index f57bec25..c1eb8146 100644 --- a/command/certificate/create.go +++ b/command/certificate/create.go @@ -391,9 +391,6 @@ func createAction(ctx *cli.Context) error { if err != nil { return errors.WithStack(err) } - if err != nil { - return errors.WithStack(err) - } profile, err = x509util.NewIntermediateProfile(subject, issIdentity.Crt, issIdentity.Key, x509util.GenerateKeyPair(kty, crv, size), diff --git a/crypto/pki/pki.go b/crypto/pki/pki.go index 93b7801d..976efd2e 100644 --- a/crypto/pki/pki.go +++ b/crypto/pki/pki.go @@ -121,16 +121,15 @@ func GetProvisionerKey(caURL, rootFile, kid string) (string, error) { // PKI represents the Public Key Infrastructure used by a certificate authority. type PKI struct { - root, rootKey, rootFingerprint string - intermediate, intermediateKey string - country, locality, organization string - config, defaults string - ottPublicKey *jose.JSONWebKey - ottPrivateKey *jose.JSONWebEncryption - provisioner string - address string - dnsNames []string - caURL string + root, rootKey, rootFingerprint string + intermediate, intermediateKey string + config, defaults string + ottPublicKey *jose.JSONWebKey + ottPrivateKey *jose.JSONWebEncryption + provisioner string + address string + dnsNames []string + caURL string } // New creates a new PKI configuration. From 723e28f502ba37d79f4e64b40235e5104a6e1603 Mon Sep 17 00:00:00 2001 From: Sebastian Tiedtke Date: Wed, 21 Aug 2019 12:12:22 -0700 Subject: [PATCH 12/29] Add frontmatter for top-level --- usage/printer.go | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/usage/printer.go b/usage/printer.go index cf853e06..654a3e7f 100644 --- a/usage/printer.go +++ b/usage/printer.go @@ -49,10 +49,14 @@ func markdownHelpPrinter(w io.Writer, templ string, parent string, data interfac var frontMatterTemplate = `--- layout: auto-doc -title: {{.Data.HelpName}}{{if .Parent}} -menu: +title: {{.Data.HelpName}} +menu:{{if .Parent}} docs: - parent: {{.Parent}}{{end}} + parent: {{.Parent}}{{else}} + main: + name: "Reference" + parent: "Documentation" + weight: 300{{end}} --- ` From c986fb1d00c97a3e726d1ecdc2b1999de3898d1f Mon Sep 17 00:00:00 2001 From: max furman Date: Fri, 23 Aug 2019 11:56:51 -0700 Subject: [PATCH 13/29] Add emails sans to `ca [sign|certificate]` and `certificate create` * x509util.SplitSANs now finds emails as well --- Gopkg.lock | 6 +++--- command/ca/certificate.go | 20 ++++++++++---------- command/ca/sign.go | 6 ++++++ command/certificate/create.go | 19 ++++++++++++------- crypto/x509util/crt.go | 7 +++++-- crypto/x509util/crt_test.go | 35 +++++++++++++++++++++++++++++++++++ crypto/x509util/profile.go | 10 ++++++++++ 7 files changed, 81 insertions(+), 22 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index a19db527..c837a80c 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -388,8 +388,8 @@ revision = "de77670473b5492f5d0bce155b5c01534c2d13f7" [[projects]] - branch = "master" - digest = "1:12f34131d2a21014b4c0d1d3c8b99aecdc83c8e3f216a85cdad00a8e5a231586" + branch = "email" + digest = "1:9f0a1fa1a057c51070e0eaf141de1546c740f39a5c471d159254dee006904a89" name = "github.com/smallstep/certificates" packages = [ "api", @@ -402,7 +402,7 @@ "server", ] pruneopts = "UT" - revision = "5356bce4d84ecbf8e3b4ff08eb3e5045b2fcec2d" + revision = "067c2eb84a203f2cde9b5ab018d8ae61e0be84fa" [[projects]] branch = "master" diff --git a/command/ca/certificate.go b/command/ca/certificate.go index 70d68ef2..191765b4 100644 --- a/command/ca/certificate.go +++ b/command/ca/certificate.go @@ -342,12 +342,7 @@ func (f *certificateFlow) CreateSignRequest(tok, subject string, sans []string) return nil, nil, err } - var emails []string - dnsNames, ips := splitSANs(sans, jwt.Payload.SANs) - if jwt.Payload.Email != "" { - emails = append(emails, jwt.Payload.Email) - } - + dnsNames, ips, emails := splitSANs(sans, jwt.Payload.SANs) switch jwt.Payload.Type() { case token.AWS: doc := jwt.Payload.Amazon.InstanceIdentityDocument @@ -359,7 +354,7 @@ func (f *certificateFlow) CreateSignRequest(tok, subject string, sans []string) if !sharedContext.DisableCustomSANs { defaultSANs = append(defaultSANs, subject) } - dnsNames, ips = splitSANs(defaultSANs) + dnsNames, ips, emails = splitSANs(defaultSANs) } case token.GCP: ce := jwt.Payload.Google.ComputeEngine @@ -371,7 +366,7 @@ func (f *certificateFlow) CreateSignRequest(tok, subject string, sans []string) if !sharedContext.DisableCustomSANs { defaultSANs = append(defaultSANs, subject) } - dnsNames, ips = splitSANs(defaultSANs) + dnsNames, ips, emails = splitSANs(defaultSANs) } case token.Azure: if len(ips) == 0 && len(dnsNames) == 0 { @@ -381,8 +376,13 @@ func (f *certificateFlow) CreateSignRequest(tok, subject string, sans []string) if !sharedContext.DisableCustomSANs { defaultSANs = append(defaultSANs, subject) } - dnsNames, ips = splitSANs(defaultSANs) + dnsNames, ips, emails = splitSANs(defaultSANs) } + case token.OIDC: + if jwt.Payload.Email != "" { + emails = append(emails, jwt.Payload.Email) + } + subject = jwt.Payload.Subject default: // Use common name in the token subject = jwt.Payload.Subject } @@ -416,7 +416,7 @@ func (f *certificateFlow) CreateSignRequest(tok, subject string, sans []string) // splitSANs unifies the SAN collections passed as arguments and returns a list // of DNS names and a list of IP addresses. -func splitSANs(args ...[]string) (dnsNames []string, ipAddresses []net.IP) { +func splitSANs(args ...[]string) (dnsNames []string, ipAddresses []net.IP, email []string) { m := make(map[string]bool) var unique []string for _, sans := range args { diff --git a/command/ca/sign.go b/command/ca/sign.go index 10992e60..07c4f3b3 100644 --- a/command/ca/sign.go +++ b/command/ca/sign.go @@ -139,5 +139,11 @@ func mergeSans(ctx *cli.Context, csr *x509.CertificateRequest) []string { m[s] = true } } + for _, s := range csr.EmailAddresses { + if _, ok := m[s]; !ok { + uniq = append(uniq, s) + m[s] = true + } + } return uniq } diff --git a/command/certificate/create.go b/command/certificate/create.go index c1eb8146..5f3a2eb3 100644 --- a/command/certificate/create.go +++ b/command/certificate/create.go @@ -314,7 +314,7 @@ func createAction(ctx *cli.Context) error { if len(sans) == 0 { sans = []string{subject} } - dnsNames, ips := x509util.SplitSANs(sans) + dnsNames, ips, emails := x509util.SplitSANs(sans) var ( priv interface{} @@ -339,8 +339,9 @@ func createAction(ctx *cli.Context) error { Subject: pkix.Name{ CommonName: subject, }, - DNSNames: dnsNames, - IPAddresses: ips, + DNSNames: dnsNames, + IPAddresses: ips, + EmailAddresses: emails, } csrBytes, err := stepx509.CreateCertificateRequest(rand.Reader, _csr, priv) if err != nil { @@ -382,7 +383,8 @@ func createAction(ctx *cli.Context) error { issIdentity.Key, x509util.GenerateKeyPair(kty, crv, size), x509util.WithNotBeforeAfterDuration(notBefore, notAfter, 0), x509util.WithDNSNames(dnsNames), - x509util.WithIPAddresses(ips)) + x509util.WithIPAddresses(ips), + x509util.WithEmailAddresses(emails)) if err != nil { return errors.WithStack(err) } @@ -396,7 +398,8 @@ func createAction(ctx *cli.Context) error { x509util.GenerateKeyPair(kty, crv, size), x509util.WithNotBeforeAfterDuration(notBefore, notAfter, 0), x509util.WithDNSNames(dnsNames), - x509util.WithIPAddresses(ips)) + x509util.WithIPAddresses(ips), + x509util.WithEmailAddresses(emails)) if err != nil { return errors.WithStack(err) } @@ -406,7 +409,8 @@ func createAction(ctx *cli.Context) error { x509util.GenerateKeyPair(kty, crv, size), x509util.WithNotBeforeAfterDuration(notBefore, notAfter, 0), x509util.WithDNSNames(dnsNames), - x509util.WithIPAddresses(ips)) + x509util.WithIPAddresses(ips), + x509util.WithEmailAddresses(emails)) if err != nil { return errors.WithStack(err) } @@ -418,7 +422,8 @@ func createAction(ctx *cli.Context) error { x509util.GenerateKeyPair(kty, crv, size), x509util.WithNotBeforeAfterDuration(notBefore, notAfter, 0), x509util.WithDNSNames(dnsNames), - x509util.WithIPAddresses(ips)) + x509util.WithIPAddresses(ips), + x509util.WithEmailAddresses(emails)) if err != nil { return errors.WithStack(err) } diff --git a/crypto/x509util/crt.go b/crypto/x509util/crt.go index ae415779..a8571738 100644 --- a/crypto/x509util/crt.go +++ b/crypto/x509util/crt.go @@ -24,14 +24,17 @@ func Fingerprint(cert *x509.Certificate) string { // SplitSANs splits a slice of Subject Alternative Names into slices of // IP Addresses and DNS Names. If an element is not an IP address, then it // is bucketed as a DNS Name. -func SplitSANs(sans []string) (dnsNames []string, ips []net.IP) { +func SplitSANs(sans []string) (dnsNames []string, ips []net.IP, emails []string) { dnsNames = []string{} ips = []net.IP{} + emails = []string{} if sans == nil { return } for _, san := range sans { - if ip := net.ParseIP(san); ip != nil { + if strings.Contains(san, "@") { + emails = append(emails, san) + } else if ip := net.ParseIP(san); ip != nil { ips = append(ips, ip) } else { // If not IP then assume DNSName. diff --git a/crypto/x509util/crt_test.go b/crypto/x509util/crt_test.go index dc6a7b31..d5c65491 100644 --- a/crypto/x509util/crt_test.go +++ b/crypto/x509util/crt_test.go @@ -4,7 +4,10 @@ import ( "crypto/x509" "encoding/pem" "io/ioutil" + "net" "testing" + + "github.com/smallstep/assert" ) func TestFingerprint(t *testing.T) { @@ -40,3 +43,35 @@ func mustParseCertificate(t *testing.T, filename string) *x509.Certificate { } return cert } + +func TestSplitSANs(t *testing.T) { + tests := []struct { + name string + sans, dns, emails []string + ips []net.IP + }{ + {name: "empty"}, + {name: "all-dns", sans: []string{"foo.internal", "bar.internal"}, dns: []string{"foo.internal", "bar.internal"}}, + {name: "all-ip", sans: []string{"0.0.0.0", "127.0.0.1"}, ips: []net.IP{net.ParseIP("0.0.0.0"), net.ParseIP("127.0.0.1")}}, + { + name: "all-email", + sans: []string{"max@smallstep.com", "mariano@smallstep.com"}, + emails: []string{"max@smallstep.com", "mariano@smallstep.com"}, + }, + { + name: "mix", + sans: []string{"foo.internal", "max@smallstep.com", "mariano@smallstep.com", "1.1.1.1", "bar.internal"}, + dns: []string{"foo.internal", "bar.internal"}, + ips: []net.IP{net.ParseIP("1.1.1.1")}, + emails: []string{"max@smallstep.com", "mariano@smallstep.com"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + dns, ips, emails := SplitSANs(tt.sans) + assert.Equals(t, dns, tt.dns) + assert.Equals(t, ips, tt.ips) + assert.Equals(t, emails, tt.emails) + }) + } +} diff --git a/crypto/x509util/profile.go b/crypto/x509util/profile.go index 1a2c3e02..3edc053c 100644 --- a/crypto/x509util/profile.go +++ b/crypto/x509util/profile.go @@ -190,6 +190,16 @@ func WithIPAddresses(ips []net.IP) WithOption { } } +// WithEmailAddresses returns a Profile modifier which sets the Email Addresses +// that will be bound to the subject alternative name extension of the Certificate. +func WithEmailAddresses(emails []string) WithOption { + return func(p Profile) error { + crt := p.Subject() + crt.EmailAddresses = emails + return nil + } +} + // WithHosts returns a Profile modifier which sets the DNS Names and IP Addresses // that will be bound to the subject Certificate. // From 60c9e9cea2e247ad90b11ce5b5c4639dfc783eff Mon Sep 17 00:00:00 2001 From: max furman Date: Fri, 23 Aug 2019 16:20:09 -0700 Subject: [PATCH 14/29] dep update certificates for email sans --- Gopkg.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index c837a80c..3b14ada0 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -388,7 +388,7 @@ revision = "de77670473b5492f5d0bce155b5c01534c2d13f7" [[projects]] - branch = "email" + branch = "master" digest = "1:9f0a1fa1a057c51070e0eaf141de1546c740f39a5c471d159254dee006904a89" name = "github.com/smallstep/certificates" packages = [ @@ -402,7 +402,7 @@ "server", ] pruneopts = "UT" - revision = "067c2eb84a203f2cde9b5ab018d8ae61e0be84fa" + revision = "27d89c21dc9b331c784d4458a558c01d3a693c98" [[projects]] branch = "master" From 697a9dd0cc6b0abbddc10ab7eadca34a8e47a36f Mon Sep 17 00:00:00 2001 From: max furman Date: Fri, 23 Aug 2019 16:53:47 -0700 Subject: [PATCH 15/29] fix SplitSANs test --- crypto/x509util/crt_test.go | 20 +++++++++++++++++--- 1 file changed, 17 insertions(+), 3 deletions(-) diff --git a/crypto/x509util/crt_test.go b/crypto/x509util/crt_test.go index d5c65491..afef7f93 100644 --- a/crypto/x509util/crt_test.go +++ b/crypto/x509util/crt_test.go @@ -50,12 +50,26 @@ func TestSplitSANs(t *testing.T) { sans, dns, emails []string ips []net.IP }{ - {name: "empty"}, - {name: "all-dns", sans: []string{"foo.internal", "bar.internal"}, dns: []string{"foo.internal", "bar.internal"}}, - {name: "all-ip", sans: []string{"0.0.0.0", "127.0.0.1"}, ips: []net.IP{net.ParseIP("0.0.0.0"), net.ParseIP("127.0.0.1")}}, + {name: "empty", sans: []string{}, dns: []string{}, ips: []net.IP{}, emails: []string{}}, + { + name: "all-dns", + sans: []string{"foo.internal", "bar.internal"}, + dns: []string{"foo.internal", "bar.internal"}, + ips: []net.IP{}, + emails: []string{}, + }, + { + name: "all-ip", + sans: []string{"0.0.0.0", "127.0.0.1"}, + dns: []string{}, + ips: []net.IP{net.ParseIP("0.0.0.0"), net.ParseIP("127.0.0.1")}, + emails: []string{}, + }, { name: "all-email", sans: []string{"max@smallstep.com", "mariano@smallstep.com"}, + dns: []string{}, + ips: []net.IP{}, emails: []string{"max@smallstep.com", "mariano@smallstep.com"}, }, { From b47a0b91109f070c5d3537b678c50d9fd6aea02a Mon Sep 17 00:00:00 2001 From: max furman Date: Mon, 26 Aug 2019 13:38:52 -0700 Subject: [PATCH 16/29] Add kty|crv|size options to 'step ca certificate' Fixes #133 --- command/ca/certificate.go | 26 +++++++++++------- command/certificate/create.go | 51 ++++------------------------------- command/crypto/jwk/create.go | 28 ++----------------- command/crypto/keypair.go | 47 +++----------------------------- flags/flags.go | 48 +++++++++++++++++++++++++++++++++ 5 files changed, 74 insertions(+), 126 deletions(-) diff --git a/command/ca/certificate.go b/command/ca/certificate.go index 191765b4..d381b8ed 100644 --- a/command/ca/certificate.go +++ b/command/ca/certificate.go @@ -34,9 +34,9 @@ func certificateCommand() cli.Command { Action: command.ActionFunc(certificateAction), Usage: "generate a new private key and certificate signed by the root certificate", UsageText: `**step ca certificate** - [**--token**=] [**--issuer**=] [**--ca-url**=] [**--root**=] - [**--not-before**=] [**--not-after**=] - [**--san**=]`, +[**--token**=] [**--issuer**=] [**--ca-url**=] [**--root**=] +[**--not-before**=] [**--not-after**=] [**--san**=] +[**--kty**=] [**--curve**=] [**--size**=]`, Description: `**step ca certificate** command generates a new certificate pair ## POSITIONAL ARGUMENTS @@ -105,6 +105,9 @@ flag are mutually exlusive.`, offlineFlag, caConfigFlag, flags.Force, + flags.KTY, + flags.Size, + flags.Curve, }, } } @@ -139,7 +142,7 @@ func certificateAction(ctx *cli.Context) error { } } - req, pk, err := flow.CreateSignRequest(tok, subject, sans) + req, pk, err := flow.CreateSignRequest(ctx, tok, subject, sans) if err != nil { return err } @@ -331,13 +334,17 @@ func (f *certificateFlow) Sign(ctx *cli.Context, token string, csr api.Certifica // CreateSignRequest is a helper function that given an x509 OTT returns a // simple but secure sign request as well as the private key used. -func (f *certificateFlow) CreateSignRequest(tok, subject string, sans []string) (*api.SignRequest, crypto.PrivateKey, error) { +func (f *certificateFlow) CreateSignRequest(ctx *cli.Context, tok, subject string, sans []string) (*api.SignRequest, crypto.PrivateKey, error) { jwt, err := token.ParseInsecure(tok) if err != nil { return nil, nil, err } - pk, err := keys.GenerateDefaultKey() + kty, crv, size, err := utils.GetKeyDetailsFromCLI(ctx, false, "kty", "curve", "size") + if err != nil { + return nil, nil, err + } + pk, err := keys.GenerateKey(kty, crv, size) if err != nil { return nil, nil, err } @@ -391,10 +398,9 @@ func (f *certificateFlow) CreateSignRequest(tok, subject string, sans []string) Subject: pkix.Name{ CommonName: subject, }, - SignatureAlgorithm: keys.DefaultSignatureAlgorithm, - DNSNames: dnsNames, - IPAddresses: ips, - EmailAddresses: emails, + DNSNames: dnsNames, + IPAddresses: ips, + EmailAddresses: emails, } csr, err := x509.CreateCertificateRequest(rand.Reader, template, pk) diff --git a/command/certificate/create.go b/command/certificate/create.go index 5f3a2eb3..f9b17e84 100644 --- a/command/certificate/create.go +++ b/command/certificate/create.go @@ -25,8 +25,8 @@ func createCommand() cli.Command { Usage: "create a certificate or certificate signing request", UsageText: `**step certificate create** [**ca**=] [**ca-key**=] [**--csr**] -[**--curve**=] [**no-password**] [**--profile**=] -[**--size**=] [**--type**=] [**--san**=] [**--bundle**]`, +[**no-password**] [**--profile**=] [**--san**=] [**--bundle**] +[**--kty**=] [**--curve**=] [**--size**=]`, Description: `**step certificate create** generates a certificate or a certificate signing requests (CSR) that can be signed later using 'step certificates sign' (or some other tool) to produce a certificate. @@ -191,50 +191,6 @@ recommended. Requires **--insecure** flag.`, : Generate a new self-signed leaf certificate suitable for use with TLS. This profile requires the **--subtle** flag because the use of self-signed leaf certificates is discouraged unless absolutely necessary.`, - }, - cli.StringFlag{ - Name: "kty", - Value: "EC", - Usage: `The to build the certificate upon. -If unset, default is EC. - -: is a case-sensitive string and must be one of: - - **EC** - : Create an **elliptic curve** keypair - - **OKP** - : Create an octet key pair (for **"Ed25519"** curve) - - **RSA** - : Create an **RSA** keypair -`, - }, - cli.IntFlag{ - Name: "size", - Usage: `The (in bits) of the key for RSA and oct key types. RSA keys require a -minimum key size of 2048 bits. If unset, default is 2048 bits for RSA keys and 128 bits for oct keys.`, - }, - cli.StringFlag{ - Name: "crv, curve", - Usage: `The elliptic to use for EC and OKP key types. Corresponds -to the **"crv"** JWK parameter. Valid curves are defined in JWA [RFC7518]. If -unset, default is P-256 for EC keys and Ed25519 for OKP keys. - -: is a case-sensitive string and must be one of: - - **P-256** - : NIST P-256 Curve - - **P-384** - : NIST P-384 Curve - - **P-521** - : NIST P-521 Curve - - **Ed25519** - : Ed25519 Curve -`, }, cli.StringFlag{ Name: "not-before", @@ -262,6 +218,9 @@ flag multiple times to configure multiple SANs.`, Usage: `Bundle the new leaf certificate with the signing certificate. This flag requires the **--ca** flag.`, }, + flags.KTY, + flags.Size, + flags.Curve, flags.Force, flags.Subtle, }, diff --git a/command/crypto/jwk/create.go b/command/crypto/jwk/create.go index e6ebbc46..cad5b862 100644 --- a/command/crypto/jwk/create.go +++ b/command/crypto/jwk/create.go @@ -177,32 +177,8 @@ If unset, default is EC. : Create an **RSA** keypair `, }, - cli.IntFlag{ - Name: "size", - Usage: `The (in bits) of the key for RSA and oct key types. RSA keys require a -minimum key size of 2048 bits. If unset, default is 2048 bits for RSA keys and 128 bits for oct keys.`, - }, - cli.StringFlag{ - Name: "crv, curve", - Usage: `The elliptic to use for EC and OKP key types. Corresponds -to the **"crv"** JWK parameter. Valid curves are defined in JWA [RFC7518]. If -unset, default is P-256 for EC keys and Ed25519 for OKP keys. - -: is a case-sensitive string and must be one of: - - **P-256** - : NIST P-256 Curve - - **P-384** - : NIST P-384 Curve - - **P-521** - : NIST P-521 Curve - - **Ed25519** - : Ed25519 Curve -`, - }, + flags.Size, + flags.Curve, cli.StringFlag{ Name: "alg, algorithm", Usage: `The intended for use with this key. Corresponds to the diff --git a/command/crypto/keypair.go b/command/crypto/keypair.go index 5493c8ff..658bce9f 100644 --- a/command/crypto/keypair.go +++ b/command/crypto/keypair.go @@ -76,50 +76,9 @@ $ step crypto keypair foo.pub foo.key --kty OKP --curve Ed25519 ''' `, Flags: []cli.Flag{ - cli.StringFlag{ - Name: "kty", - Value: "EC", - Usage: `The (key type) to create. -If unset, default is EC. - -: is a case-sensitive string and must be one of: - - **EC** - : Create an **elliptic curve** keypair - - **OKP** - : Create an octet key pair (for **"Ed25519"** curve) - - **RSA** - : Create an **RSA** keypair -`, - }, - cli.IntFlag{ - Name: "size", - Usage: `The (in bits) of the key for RSA and oct key types. RSA keys require a -minimum key size of 2048 bits. If unset, default is 2048 bits for RSA keys and 128 bits for oct keys.`, - }, - cli.StringFlag{ - Name: "crv, curve", - Usage: `The elliptic to use for EC and OKP key types. Corresponds -to the **"crv"** JWK parameter. Valid curves are defined in JWA [RFC7518]. If -unset, default is P-256 for EC keys and Ed25519 for OKP keys. - -: is a case-sensitive string and must be one of: - - **P-256** - : NIST P-256 Curve - - **P-384** - : NIST P-384 Curve - - **P-521** - : NIST P-521 Curve - - **Ed25519** - : Ed25519 Curve -`, - }, + flags.KTY, + flags.Size, + flags.Curve, cli.StringFlag{ Name: "from-jwk", Usage: `Create a PEM representing the key encoded in an diff --git a/flags/flags.go b/flags/flags.go index 2802a103..b914081b 100644 --- a/flags/flags.go +++ b/flags/flags.go @@ -6,6 +6,54 @@ import ( "github.com/urfave/cli" ) +// KTY is the flag to set the key type. +var KTY = cli.StringFlag{ + Name: "kty", + Value: "EC", + Usage: `The to build the certificate upon. +If unset, default is EC. + +: is a case-sensitive string and must be one of: + + **EC** + : Create an **elliptic curve** keypair + + **OKP** + : Create an octet key pair (for **"Ed25519"** curve) + + **RSA** + : Create an **RSA** keypair`, +} + +// Size is the flag to set the key size. +var Size = cli.IntFlag{ + Name: "size", + Usage: `The (in bits) of the key for RSA and oct key types. RSA keys require a +minimum key size of 2048 bits. If unset, default is 2048 bits for RSA keys and 128 bits for oct keys.`, +} + +// Curve is the flag to se the key curve. +var Curve = cli.StringFlag{ + Name: "crv, curve", + Usage: `The elliptic to use for EC and OKP key types. Corresponds +to the **"crv"** JWK parameter. Valid curves are defined in JWA [RFC7518]. If +unset, default is P-256 for EC keys and Ed25519 for OKP keys. + +: is a case-sensitive string and must be one of: + + **P-256** + : NIST P-256 Curve + + **P-384** + : NIST P-384 Curve + + **P-521** + : NIST P-521 Curve + + **Ed25519** + : Ed25519 Curve`, +} + // Subtle is the flag required for delicate operations. var Subtle = cli.BoolFlag{ Name: "subtle", From e8e50f4f5948eb8350c7636ec6a8d8db87035336 Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 21 Aug 2019 13:33:07 -0700 Subject: [PATCH 17/29] switch to golangci-lint --- .travis.yml | 1 + Gopkg.lock | 64 ++------------------------------------------------ Gopkg.toml | 5 ---- make/common.mk | 8 +++---- 4 files changed, 7 insertions(+), 71 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6982c6f2..452f804f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ env: - V=1 before_script: - make bootstrap +- go install github.com/golangci/golangci-lint/cmd/golangci-lint@1.17.1 script: - make - make artifacts diff --git a/Gopkg.lock b/Gopkg.lock index 3b14ada0..fcdc0566 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -25,21 +25,6 @@ pruneopts = "UT" revision = "5482f03509440585d13d8f648989e05903001842" -[[projects]] - digest = "1:304cb78c285eaf02ab529ad02a257cad9b4845022915e6c82f87860ac53222d8" - name = "github.com/alecthomas/gometalinter" - packages = ["."] - pruneopts = "UT" - revision = "bae2f1293d092fd8167939d5108d1b025eaef9de" - -[[projects]] - branch = "master" - digest = "1:c198fdc381e898e8fb62b8eb62758195091c313ad18e52a3067366e1dda2fb3c" - name = "github.com/alecthomas/units" - packages = ["."] - pruneopts = "UT" - revision = "2efee857e7cfd4f3d0138cc3cbb1b4966962b93a" - [[projects]] digest = "1:320e7ead93de9fd2b0e59b50fd92a4d50c1f8ab455d96bc2eb083267453a9709" name = "github.com/asaskevich/govalidator" @@ -167,19 +152,11 @@ [[projects]] branch = "master" - digest = "1:750e747d0aad97b79f4a4e00034bae415c2ea793fd9e61438d966ee9c79579bf" - name = "github.com/google/shlex" - packages = ["."] - pruneopts = "UT" - revision = "6f45313302b9c56850fc17f99e40caebce98c716" - -[[projects]] - branch = "master" - digest = "1:824d147914b40e56e9e1eebd602bc6bb9761989d52fd8e4a498428467980eb17" + digest = "1:00d592bdacdeb0412b09f8eb2f98c6cc04470c4b72150f20733511e0821225c1" name = "github.com/gordonklaus/ineffassign" packages = ["."] pruneopts = "UT" - revision = "1003c8bd00dc2869cb5ca5282e6ce33834fed514" + revision = "ed7b1b5ee0f816bbc0ff35bf7c6fdb4f53b6c59a" [[projects]] branch = "master" @@ -298,27 +275,6 @@ revision = "f5bce3387232559bcbe6a5f8227c4bf508dac1ba" version = "v1.11.0" -[[projects]] - digest = "1:07140002dbf37da92090f731b46fa47be4820b82fe5c14a035203b0e813d0ec2" - name = "github.com/nicksnyder/go-i18n" - packages = [ - "i18n", - "i18n/bundle", - "i18n/language", - "i18n/translation", - ] - pruneopts = "UT" - revision = "0dc1626d56435e9d605a29875701721c54bc9bbd" - version = "v1.10.0" - -[[projects]] - digest = "1:95741de3af260a92cc5c7f3f3061e85273f5a81b5db20d4bd68da74bd521675e" - name = "github.com/pelletier/go-toml" - packages = ["."] - pruneopts = "UT" - revision = "c01d1270ff3e442a8a57cddc1c92dc1138598194" - version = "v1.2.0" - [[projects]] digest = "1:cf31692c14422fa27c83a05292eb5cbe0fb2775972e8f1f8446a71549bd8980b" name = "github.com/pkg/errors" @@ -618,13 +574,6 @@ revision = "54a98f90d1c46b7731eb8fb305d2a321c30ef610" version = "v1.5.0" -[[projects]] - digest = "1:39efb07a0d773dc09785b237ada4e10b5f28646eb6505d97bc18f8d2ff439362" - name = "gopkg.in/alecthomas/kingpin.v3-unstable" - packages = ["."] - pruneopts = "UT" - revision = "63abe20a23e29e80bbef8089bd3dee3ac25e5306" - [[projects]] digest = "1:9593bab40e981b1f90b7e07faeab0d09b75fe338880d08880f986a9d3283c53f" name = "gopkg.in/square/go-jose.v2" @@ -638,20 +587,11 @@ revision = "730df5f748271903322feb182be83b43ebbbe27d" version = "v2.3.1" -[[projects]] - digest = "1:342378ac4dcb378a5448dd723f0784ae519383532f5e70ade24132c4c8693202" - name = "gopkg.in/yaml.v2" - packages = ["."] - pruneopts = "UT" - revision = "5420a8b6744d3b0345ab293f6fcba19c978f1183" - version = "v2.2.1" - [solve-meta] analyzer-name = "dep" analyzer-version = 1 input-imports = [ "github.com/ThomasRooney/gexpect", - "github.com/alecthomas/gometalinter", "github.com/chzyer/readline", "github.com/client9/misspell/cmd/misspell", "github.com/golang/lint/golint", diff --git a/Gopkg.toml b/Gopkg.toml index 77bc5adb..39805755 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -24,7 +24,6 @@ # go-tests = true # unused-packages = true required = [ - "github.com/alecthomas/gometalinter", "github.com/golang/lint/golint", "github.com/client9/misspell/cmd/misspell", "github.com/gordonklaus/ineffassign", @@ -35,10 +34,6 @@ required = [ name = "github.com/golang/lint" revision = "06c8688daad7faa9da5a0c2f163a3d14aac986ca" -[[constraint]] - name = "github.com/alecthomas/gometalinter" - revision = "bae2f1293d092fd8167939d5108d1b025eaef9de" - [[override]] name = "gopkg.in/alecthomas/kingpin.v3-unstable" revision = "63abe20a23e29e80bbef8089bd3dee3ac25e5306" diff --git a/make/common.mk b/make/common.mk index faa2c0ff..7cb1be28 100644 --- a/make/common.mk +++ b/make/common.mk @@ -29,7 +29,7 @@ BOOTSTRAP=\ github.com/client9/misspell/cmd/misspell \ github.com/gordonklaus/ineffassign \ github.com/tsenart/deadcode \ - github.com/alecthomas/gometalinter + github.com/golangci/golangci-lint define VENDOR_BIN_TMPL vendor/bin/$(notdir $(1)): vendor @@ -132,9 +132,9 @@ LINTERS=\ $(patsubst %,%-bin,$(filter-out gofmt vet,$(LINTERS))): %-bin: vendor/bin/% gofmt-bin vet-bin: -$(LINTERS): %: vendor/bin/gometalinter %-bin vendor - $Q PATH=`pwd`/vendor/bin:$$PATH gometalinter --tests --disable-all --vendor \ - --deadline=5m -s data -s pkg --enable $@ ./... +$(LINTERS): %: %-bin vendor + $Q PATH=`pwd`/vendor/bin:$$PATH golangci-lint run --disable-all \ + --deadline=5m --skip-dirs pkg --enable $@ ./... fmt: $Q gofmt -l -w $(SRC) From e49b733fbf8fd7a9a5bb66302401f1caa0aad4db Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 21 Aug 2019 16:15:12 -0700 Subject: [PATCH 18/29] switch to golangci-lint and fix lots of linting errors --- .golangci.yml | 66 ++++++++++++++++++++++++++++++++ .travis.yml | 2 +- Gopkg.lock | 20 +++++----- command/ca/bootstrap.go | 6 +-- command/ca/certificate.go | 2 +- command/ca/init.go | 18 +++++---- command/ca/offline.go | 9 +++-- command/ca/revoke.go | 14 ++++--- command/ca/token.go | 14 ++++--- command/certificate/create.go | 18 +++++---- command/certificate/sign.go | 2 +- command/certificate/verify.go | 2 +- command/crypto/hash/hash.go | 3 +- command/crypto/jwe/decrypt.go | 2 +- command/crypto/jwe/encrypt.go | 2 +- command/crypto/jwk/create.go | 28 ++++++++------ command/crypto/jwk/keyset.go | 2 +- command/crypto/jwk/public.go | 2 +- command/crypto/jwk/thumbprint.go | 2 +- command/crypto/jws/sign.go | 2 +- command/crypto/jws/verify.go | 2 +- command/crypto/jwt/sign.go | 2 +- command/crypto/keypair.go | 14 +++++-- command/crypto/nacl/box.go | 2 +- command/oauth/cmd.go | 6 +-- crypto/pemutil/pem.go | 14 +++++-- crypto/pemutil/pem_test.go | 15 +++++--- crypto/pemutil/pkcs8.go | 10 ++--- crypto/pki/pki.go | 16 ++++---- crypto/x509util/profile.go | 2 +- jose/parse.go | 2 +- make/common.mk | 32 ++-------------- 32 files changed, 207 insertions(+), 126 deletions(-) create mode 100644 .golangci.yml diff --git a/.golangci.yml b/.golangci.yml new file mode 100644 index 00000000..7beba1cc --- /dev/null +++ b/.golangci.yml @@ -0,0 +1,66 @@ +linters-settings: + govet: + check-shadowing: true + settings: + printf: + funcs: + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Infof + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Errorf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Warnf + - (github.com/golangci/golangci-lint/pkg/logutils.Log).Fatalf + golint: + min-confidence: 0 + gocyclo: + min-complexity: 10 + maligned: + suggest-new: true + dupl: + threshold: 100 + goconst: + min-len: 2 + min-occurrences: 2 + depguard: + list-type: blacklist + packages: + # logging is allowed only by logutils.Log, logrus + # is allowed to use only in logutils package + - github.com/sirupsen/logrus + misspell: + locale: US + lll: + line-length: 140 + goimports: + local-prefixes: github.com/golangci/golangci-lint + gocritic: + enabled-tags: + - performance + - style + - experimental + disabled-checks: + - wrapperFunc + - dupImport # https://github.com/go-critic/go-critic/issues/845 + +linters: + disable-all: true + enable: + - gofmt + - golint + - vet + - misspell + - ineffassign + - deadcode + +run: + skip-dirs: + - pkg + +issues: + exclude: + - can't lint + - declaration of "err" shadows declaration at line +# golangci.com configuration +# https://github.com/golangci/golangci/wiki/Configuration +service: + golangci-lint-version: 1.17.x # use the fixed version to not introduce new linters unexpectedly + prepare: + - echo "here I can run custom commands, but no preparation needed for this repo" diff --git a/.travis.yml b/.travis.yml index 452f804f..33961857 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ env: - V=1 before_script: - make bootstrap -- go install github.com/golangci/golangci-lint/cmd/golangci-lint@1.17.1 +- go get github.com/golangci/golangci-lint/cmd/golangci-lint script: - make - make artifacts diff --git a/Gopkg.lock b/Gopkg.lock index fcdc0566..0ba90fcc 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -9,14 +9,6 @@ pruneopts = "UT" revision = "e2d15f34fcf99d5dbb871c820ec73f710fca9815" -[[projects]] - branch = "master" - digest = "1:c10265d5a71326618d37e97169eddb3582f78e8ac7dcf87403b4cf619efd519a" - name = "github.com/DHowett/go-plist" - packages = ["."] - pruneopts = "UT" - revision = "591f970eefbbeb04d7b37f334a0c4c3256e32876" - [[projects]] branch = "master" digest = "1:655f3b07160fbe90713062296ef215c096ad4308bdc0081620cacd9b9d46dce5" @@ -384,11 +376,11 @@ [[projects]] branch = "master" - digest = "1:4bde64565730a308d3cebca9b93f19c8e1137f9ba5b57174669ad0f732dec044" + digest = "1:f41de3b55032e81c12f4d109e6c5222e1cff573197a3652b800ca8ac2aaada35" name = "github.com/smallstep/truststore" packages = ["."] pruneopts = "UT" - revision = "b8300b931ab584b7aa01fe43b3c92d5a61cf2ce3" + revision = "8418f8a7d0b74e79026254b4ad23c67dd77fe5f0" [[projects]] branch = "master" @@ -587,6 +579,14 @@ revision = "730df5f748271903322feb182be83b43ebbbe27d" version = "v2.3.1" +[[projects]] + branch = "master" + digest = "1:c10265d5a71326618d37e97169eddb3582f78e8ac7dcf87403b4cf619efd519a" + name = "howett.net/plist" + packages = ["."] + pruneopts = "UT" + revision = "591f970eefbbeb04d7b37f334a0c4c3256e32876" + [solve-meta] analyzer-name = "dep" analyzer-version = 1 diff --git a/command/ca/bootstrap.go b/command/ca/bootstrap.go index 7069522b..4a61c359 100644 --- a/command/ca/bootstrap.go +++ b/command/ca/bootstrap.go @@ -32,7 +32,7 @@ Bootstrap will store the root certificate in <$STEPPATH/certs/root_ca.crt> and create a configuration file in <$STEPPATH/configs/defaults.json> with the CA url, the root certificate location and its fingerprint. -After the bootstrap, ca commands do not need to specify the flags +After the bootstrap, ca commands do not need to specify the flags --ca-url, --root or --fingerprint if we want to use the same environment.`, Flags: []cli.Flag{ caURLFlag, @@ -76,11 +76,11 @@ func bootstrapAction(ctx *cli.Context) error { return errors.Wrap(err, "error downloading root certificate") } - if err := os.MkdirAll(filepath.Dir(rootFile), 0700); err != nil { + if err = os.MkdirAll(filepath.Dir(rootFile), 0700); err != nil { return errs.FileError(err, rootFile) } - if err := os.MkdirAll(filepath.Dir(configFile), 0700); err != nil { + if err = os.MkdirAll(filepath.Dir(configFile), 0700); err != nil { return errs.FileError(err, configFile) } diff --git a/command/ca/certificate.go b/command/ca/certificate.go index 191765b4..62497d7f 100644 --- a/command/ca/certificate.go +++ b/command/ca/certificate.go @@ -171,7 +171,7 @@ func certificateAction(ctx *cli.Context) error { return errors.New("token is not supported") } - if err := flow.Sign(ctx, tok, req.CsrPEM, crtFile); err != nil { + if err = flow.Sign(ctx, tok, req.CsrPEM, crtFile); err != nil { return err } diff --git a/command/ca/init.go b/command/ca/init.go index 109f8e53..210dce4d 100644 --- a/command/ca/init.go +++ b/command/ca/init.go @@ -80,7 +80,7 @@ func initCommand() cli.Command { } func initAction(ctx *cli.Context) (err error) { - if err := assertCryptoRand(); err != nil { + if err = assertCryptoRand(); err != nil { return err } @@ -96,7 +96,6 @@ func initAction(ctx *cli.Context) (err error) { case len(root) == 0 && len(key) > 0: return errs.RequiredWithFlag(ctx, "key", "root") case len(root) > 0 && len(key) > 0: - var err error if rootCrt, err = pemutil.ReadCertificate(root); err != nil { return err } @@ -141,7 +140,8 @@ func initAction(ctx *cli.Context) (err error) { } if configure { - names, err := ui.Prompt("What DNS names or IP addresses would you like to add to your new CA? (e.g. ca.smallstep.com[,1.1.1.1,etc.])", + var names string + names, err = ui.Prompt("What DNS names or IP addresses would you like to add to your new CA? (e.g. ca.smallstep.com[,1.1.1.1,etc.])", ui.WithValidateFunc(ui.DNS()), ui.WithValue(ctx.String("dns"))) if err != nil { return err @@ -156,13 +156,15 @@ func initAction(ctx *cli.Context) (err error) { dnsNames = append(dnsNames, strings.TrimSpace(name)) } - address, err := ui.Prompt("What address will your new CA listen at? (e.g. :443)", + var address string + address, err = ui.Prompt("What address will your new CA listen at? (e.g. :443)", ui.WithValidateFunc(ui.Address()), ui.WithValue(ctx.String("address"))) if err != nil { return err } - provisioner, err := ui.Prompt("What would you like to name the first provisioner for your new CA? (e.g. you@smallstep.com)", + var provisioner string + provisioner, err = ui.Prompt("What would you like to name the first provisioner for your new CA? (e.g. you@smallstep.com)", ui.WithValidateNotEmpty(), ui.WithValue(ctx.String("provisioner"))) if err != nil { return err @@ -183,11 +185,11 @@ func initAction(ctx *cli.Context) (err error) { if configure { // Generate provisioner key pairs. if len(provisionerPassword) > 0 { - if err := p.GenerateKeyPairs(provisionerPassword); err != nil { + if err = p.GenerateKeyPairs(provisionerPassword); err != nil { return err } } else { - if err := p.GenerateKeyPairs(pass); err != nil { + if err = p.GenerateKeyPairs(pass); err != nil { return err } } @@ -207,7 +209,7 @@ func initAction(ctx *cli.Context) (err error) { } else { fmt.Println() fmt.Print("Copying root certificate... \n") - if err := p.WriteRootCertificate(rootCrt, rootKey, pass); err != nil { + if err = p.WriteRootCertificate(rootCrt, rootKey, pass); err != nil { return err } fmt.Println("all done!") diff --git a/command/ca/offline.go b/command/ca/offline.go index dc09a1e9..22475680 100644 --- a/command/ca/offline.go +++ b/command/ca/offline.go @@ -45,7 +45,7 @@ func newOfflineCA(configFile string) (*offlineCA, error) { } var config authority.Config - if err := json.Unmarshal(b, &config); err != nil { + if err = json.Unmarshal(b, &config); err != nil { return nil, errors.Wrapf(err, "error reading %s", configFile) } @@ -86,7 +86,7 @@ func (c *offlineCA) VerifyClientCert(certFile, keyFile string) error { return err } // Validate that the certificate and key match - if _, err := tls.X509KeyPair(pem.EncodeToMemory(certPem), pem.EncodeToMemory(keyPem)); err != nil { + if _, err = tls.X509KeyPair(pem.EncodeToMemory(certPem), pem.EncodeToMemory(keyPem)); err != nil { return errors.Wrap(err, "error loading x509 key pair") } @@ -104,7 +104,7 @@ func (c *offlineCA) VerifyClientCert(certFile, keyFile string) error { Intermediates: intermediatePool, } - if _, err := cert.Verify(opts); err != nil { + if _, err = cert.Verify(opts); err != nil { return errors.Wrapf(err, "failed to verify certificate") } @@ -231,7 +231,8 @@ func (c *offlineCA) GenerateToken(ctx *cli.Context, typ int, subject string, san switch p := p.(type) { case *provisioner.OIDC: // Run step oauth - out, err := exec.Step("oauth", "--oidc", "--bare", + var out []byte + out, err = exec.Step("oauth", "--oidc", "--bare", "--provider", p.ConfigurationEndpoint, "--client-id", p.ClientID, "--client-secret", p.ClientSecret) if err != nil { diff --git a/command/ca/revoke.go b/command/ca/revoke.go index 7b72afce..e4866072 100644 --- a/command/ca/revoke.go +++ b/command/ca/revoke.go @@ -2,6 +2,7 @@ package ca import ( "crypto/tls" + "crypto/x509" "net/http" "os" "strconv" @@ -232,14 +233,15 @@ func revokeCertificateAction(ctx *cli.Context) error { if len(serial) > 0 { errs.IncompatibleFlagWithFlag(ctx, "cert", "serial") } - cert, err := pemutil.ReadCertificateBundle(certFile) + var cert []*x509.Certificate + cert, err = pemutil.ReadCertificateBundle(certFile) if err != nil { return err } serial = cert[0].SerialNumber.String() } else { // Must be using serial number so verify that only 1 command line args was given. - if err := errs.NumberOfArguments(ctx, 1); err != nil { + if err = errs.NumberOfArguments(ctx, 1); err != nil { return err } if len(token) == 0 { @@ -396,7 +398,8 @@ func (f *revokeFlow) Revoke(ctx *cli.Context, serial, token string) error { certFile, keyFile := ctx.String("cert"), ctx.String("key") // If there is no token then we must be doing a Revoke over mTLS. - cert, err := tls.LoadX509KeyPair(certFile, keyFile) + var cert tls.Certificate + cert, err = tls.LoadX509KeyPair(certFile, keyFile) if err != nil { return errors.Wrap(err, "error loading certificates") } @@ -406,11 +409,12 @@ func (f *revokeFlow) Revoke(ctx *cli.Context, serial, token string) error { root := ctx.String("root") if len(root) == 0 { root = pki.GetRootCAPath() - if _, err := os.Stat(root); err != nil { + if _, err = os.Stat(root); err != nil { return errs.RequiredUnlessFlag(ctx, "root", "token") } } - rootCAs, err := x509util.ReadCertPool(root) + var rootCAs *x509.CertPool + rootCAs, err = x509util.ReadCertPool(root) if err != nil { return err } diff --git a/command/ca/token.go b/command/ca/token.go index d874ad9f..82d3e1ce 100644 --- a/command/ca/token.go +++ b/command/ca/token.go @@ -342,7 +342,8 @@ func newTokenFlow(ctx *cli.Context, typ int, subject string, sans []string, caUR switch p := p.(type) { case *provisioner.OIDC: // Run step oauth - out, err := exec.Step("oauth", "--oidc", "--bare", + var out []byte + out, err = exec.Step("oauth", "--oidc", "--bare", "--provider", p.ConfigurationEndpoint, "--client-id", p.ClientID, "--client-secret", p.ClientSecret) if err != nil { @@ -377,7 +378,8 @@ func newTokenFlow(ctx *cli.Context, typ int, subject string, sans []string, caUR var jwk *jose.JSONWebKey if keyFile := ctx.String("key"); len(keyFile) == 0 { // Get private key from CA - encrypted, err := pki.GetProvisionerKey(caURL, root, kid) + var encrypted string + encrypted, err = pki.GetProvisionerKey(caURL, root, kid) if err != nil { return "", err } @@ -387,13 +389,14 @@ func newTokenFlow(ctx *cli.Context, typ int, subject string, sans []string, caUR ui.WithPromptTemplates(ui.PromptTemplates()), )) - decrypted, err := jose.Decrypt("Please enter the password to decrypt the provisioner key", []byte(encrypted), opts...) + var decrypted []byte + decrypted, err = jose.Decrypt("Please enter the password to decrypt the provisioner key", []byte(encrypted), opts...) if err != nil { return "", err } jwk = new(jose.JSONWebKey) - if err := json.Unmarshal(decrypted, jwk); err != nil { + if err = json.Unmarshal(decrypted, jwk); err != nil { return "", errors.Wrap(err, "error unmarshalling provisioning key") } } else { @@ -424,7 +427,8 @@ func offlineTokenFlow(ctx *cli.Context, typ int, subject string, sans []string) // Using the offline CA if utils.FileExists(caConfig) { - offlineCA, err := newOfflineCA(caConfig) + var offlineCA *offlineCA + offlineCA, err = newOfflineCA(caConfig) if err != nil { return "", err } diff --git a/command/certificate/create.go b/command/certificate/create.go index 5f3a2eb3..b0da2e28 100644 --- a/command/certificate/create.go +++ b/command/certificate/create.go @@ -343,7 +343,8 @@ func createAction(ctx *cli.Context) error { IPAddresses: ips, EmailAddresses: emails, } - csrBytes, err := stepx509.CreateCertificateRequest(rand.Reader, _csr, priv) + var csrBytes []byte + csrBytes, err = stepx509.CreateCertificateRequest(rand.Reader, _csr, priv) if err != nil { return errors.WithStack(err) } @@ -356,7 +357,6 @@ func createAction(ctx *cli.Context) error { outputType = "certificate signing request" case "x509": var ( - err error prof = ctx.String("profile") caPath = ctx.String("ca") caKeyPath = ctx.String("ca-key") @@ -375,7 +375,8 @@ func createAction(ctx *cli.Context) error { } switch prof { case "leaf": - issIdentity, err := loadIssuerIdentity(ctx, prof, caPath, caKeyPath) + var issIdentity *x509util.Identity + issIdentity, err = loadIssuerIdentity(ctx, prof, caPath, caKeyPath) if err != nil { return errors.WithStack(err) } @@ -389,7 +390,8 @@ func createAction(ctx *cli.Context) error { return errors.WithStack(err) } case "intermediate-ca": - issIdentity, err := loadIssuerIdentity(ctx, prof, caPath, caKeyPath) + var issIdentity *x509util.Identity + issIdentity, err = loadIssuerIdentity(ctx, prof, caPath, caKeyPath) if err != nil { return errors.WithStack(err) } @@ -430,7 +432,8 @@ func createAction(ctx *cli.Context) error { default: return errs.InvalidFlagValue(ctx, "profile", prof, "leaf, intermediate-ca, root-ca, self-signed") } - crtBytes, err := profile.CreateCertificate() + var crtBytes []byte + crtBytes, err = profile.CreateCertificate() if err != nil { return errors.WithStack(err) } @@ -454,7 +457,7 @@ func createAction(ctx *cli.Context) error { for _, pp := range pubPEMs { pubBytes = append(pubBytes, pem.EncodeToMemory(pp)...) } - if err := utils.WriteFile(crtFile, pubBytes, 0600); err != nil { + if err = utils.WriteFile(crtFile, pubBytes, 0600); err != nil { return errs.FileError(err, crtFile) } @@ -464,7 +467,8 @@ func createAction(ctx *cli.Context) error { return errors.WithStack(err) } } else { - pass, err := ui.PromptPassword("Please enter the password to encrypt the private key") + var pass []byte + pass, err = ui.PromptPassword("Please enter the password to encrypt the private key") if err != nil { return errors.Wrap(err, "error reading password") } diff --git a/command/certificate/sign.go b/command/certificate/sign.go index 1283e27c..7fbe39a2 100644 --- a/command/certificate/sign.go +++ b/command/certificate/sign.go @@ -78,7 +78,7 @@ func signAction(ctx *cli.Context) error { if err != nil { return errors.WithStack(err) } - if err := x509util.CheckCertificateRequestSignature(csr); err != nil { + if err = x509util.CheckCertificateRequestSignature(csr); err != nil { return errors.Wrapf(err, "Certificate Request has invalid signature") } diff --git a/command/certificate/verify.go b/command/certificate/verify.go index b477cc17..3eb59b7e 100644 --- a/command/certificate/verify.go +++ b/command/certificate/verify.go @@ -96,7 +96,6 @@ func verifyAction(ctx *cli.Context) error { } var ( - err error crtFile = ctx.Args().Get(0) host = ctx.String("host") roots = ctx.String("roots") @@ -153,6 +152,7 @@ func verifyAction(ctx *cli.Context) error { } if roots != "" { + var err error rootPool, err = x509util.ReadCertPool(roots) if err != nil { errors.Wrapf(err, "failure to load root certificate pool from input path '%s'", roots) diff --git a/command/crypto/hash/hash.go b/command/crypto/hash/hash.go index b9e8fc70..0a258429 100644 --- a/command/crypto/hash/hash.go +++ b/command/crypto/hash/hash.go @@ -203,7 +203,8 @@ func digestAction(ctx *cli.Context) error { } for _, filename := range ctx.Args() { - st, err := os.Stat(filename) + var st os.FileInfo + st, err = os.Stat(filename) if err != nil { return errs.FileError(err, filename) } diff --git a/command/crypto/jwe/decrypt.go b/command/crypto/jwe/decrypt.go index f63060c0..f4a78db0 100644 --- a/command/crypto/jwe/decrypt.go +++ b/command/crypto/jwe/decrypt.go @@ -129,7 +129,7 @@ func decryptAction(ctx *cli.Context) error { } // Validate jwk - if err := jose.ValidateJWK(jwk); err != nil { + if err = jose.ValidateJWK(jwk); err != nil { return err } diff --git a/command/crypto/jwe/encrypt.go b/command/crypto/jwe/encrypt.go index 1dbcf8f9..68375e88 100644 --- a/command/crypto/jwe/encrypt.go +++ b/command/crypto/jwe/encrypt.go @@ -249,7 +249,7 @@ func encryptAction(ctx *cli.Context) error { } // Validate jwk - if err := jose.ValidateJWK(jwk); err != nil { + if err = jose.ValidateJWK(jwk); err != nil { return err } diff --git a/command/crypto/jwk/create.go b/command/crypto/jwk/create.go index e6ebbc46..a8a92b42 100644 --- a/command/crypto/jwk/create.go +++ b/command/crypto/jwk/create.go @@ -404,7 +404,7 @@ existing instead of creating a new key.`, func createAction(ctx *cli.Context) (err error) { // require public and private files - if err := errs.NumberOfArguments(ctx, 2); err != nil { + if err = errs.NumberOfArguments(ctx, 2); err != nil { return err } @@ -502,7 +502,8 @@ func createAction(ctx *cli.Context) (err error) { } else { // A hash of a symmetric key can leak information, so we only thumbprint asymmetric keys. if kty != "oct" { - hash, err := jwk.Thumbprint(crypto.SHA256) + var hash []byte + hash, err = jwk.Thumbprint(crypto.SHA256) if err != nil { return errors.Wrap(err, "error generating JWK thumbprint") } @@ -515,7 +516,7 @@ func createAction(ctx *cli.Context) (err error) { jwk.Algorithm = alg } - if err := jose.ValidateJWK(jwk); err != nil { + if err = jose.ValidateJWK(jwk); err != nil { return err } @@ -531,7 +532,7 @@ func createAction(ctx *cli.Context) (err error) { if err != nil { return errors.Wrap(err, "error marshaling JWK") } - if err := utils.WriteFile(pubFile, b, 0600); err != nil { + if err = utils.WriteFile(pubFile, b, 0600); err != nil { return errs.FileError(err, pubFile) } @@ -547,12 +548,14 @@ func createAction(ctx *cli.Context) (err error) { var rcpt jose.Recipient // Generate JWE encryption key. if jose.SupportsPBKDF2 { - key, err := ui.PromptPassword("Please enter the password to encrypt the private JWK", ui.WithValue(password)) + var key []byte + key, err = ui.PromptPassword("Please enter the password to encrypt the private JWK", ui.WithValue(password)) if err != nil { return errors.Wrap(err, "error reading password") } - salt, err := randutil.Salt(pbkdf2SaltSize) + var salt []byte + salt, err = randutil.Salt(pbkdf2SaltSize) if err != nil { return err } @@ -564,7 +567,8 @@ func createAction(ctx *cli.Context) (err error) { PBES2Salt: salt, } } else { - key, err := randutil.Alphanumeric(32) + var key string + key, err = randutil.Alphanumeric(32) if err != nil { return errors.Wrap(err, "error generating password") } @@ -579,18 +583,20 @@ func createAction(ctx *cli.Context) (err error) { opts := new(jose.EncrypterOptions) opts.WithContentType(jose.ContentType("jwk+json")) - encrypter, err := jose.NewEncrypter(jose.DefaultEncAlgorithm, rcpt, opts) + var encrypter jose.Encrypter + encrypter, err = jose.NewEncrypter(jose.DefaultEncAlgorithm, rcpt, opts) if err != nil { return errors.Wrap(err, "error creating cipher") } - obj, err := encrypter.Encrypt(b) + var obj *jose.JSONWebEncryption + obj, err = encrypter.Encrypt(b) if err != nil { return errors.Wrap(err, "error encrypting JWK") } var out bytes.Buffer - if err := json.Indent(&out, []byte(obj.FullSerialize()), "", " "); err != nil { + if err = json.Indent(&out, []byte(obj.FullSerialize()), "", " "); err != nil { return errors.Wrap(err, "error formatting JSON") } b = out.Bytes() @@ -600,7 +606,7 @@ func createAction(ctx *cli.Context) (err error) { return errors.Wrap(err, "error marshaling JWK") } } - if err := utils.WriteFile(privFile, b, 0600); err != nil { + if err = utils.WriteFile(privFile, b, 0600); err != nil { return errs.FileError(err, privFile) } diff --git a/command/crypto/jwk/keyset.go b/command/crypto/jwk/keyset.go index ed3d5faa..62b0a9f7 100644 --- a/command/crypto/jwk/keyset.go +++ b/command/crypto/jwk/keyset.go @@ -135,7 +135,7 @@ func keysetAddAction(ctx *cli.Context) error { // Unmarshal the plain (or decrypted JWK) var jwk jose.JSONWebKey - if err := json.Unmarshal(b, &jwk); err != nil { + if err = json.Unmarshal(b, &jwk); err != nil { return errors.New("error reading JWK: unsupported format") } diff --git a/command/crypto/jwk/public.go b/command/crypto/jwk/public.go index 00a98201..8417f913 100644 --- a/command/crypto/jwk/public.go +++ b/command/crypto/jwk/public.go @@ -37,7 +37,7 @@ func publicAction(ctx *cli.Context) error { } // Unmarshal the plain (or decrypted JWK) - if err := json.Unmarshal(b, jwk); err != nil { + if err = json.Unmarshal(b, jwk); err != nil { return errors.New("error reading JWK: unsupported format") } diff --git a/command/crypto/jwk/thumbprint.go b/command/crypto/jwk/thumbprint.go index d9f5859a..e7d6d931 100644 --- a/command/crypto/jwk/thumbprint.go +++ b/command/crypto/jwk/thumbprint.go @@ -40,7 +40,7 @@ func thumbprintAction(ctx *cli.Context) error { } // Unmarshal the plain (or decrypted JWK) - if err := json.Unmarshal(b, jwk); err != nil { + if err = json.Unmarshal(b, jwk); err != nil { return errors.New("error reading JWK: unsupported format") } diff --git a/command/crypto/jws/sign.go b/command/crypto/jws/sign.go index e28c6115..16a0583a 100644 --- a/command/crypto/jws/sign.go +++ b/command/crypto/jws/sign.go @@ -238,7 +238,7 @@ func signAction(ctx *cli.Context) error { if jwk.Algorithm == "" { return errors.New("flag '--alg' is required with the given key") } - if err := jose.ValidateJWK(jwk); err != nil { + if err = jose.ValidateJWK(jwk); err != nil { return err } diff --git a/command/crypto/jws/verify.go b/command/crypto/jws/verify.go index e14d1c5c..ed505a58 100644 --- a/command/crypto/jws/verify.go +++ b/command/crypto/jws/verify.go @@ -158,7 +158,7 @@ func verifyAction(ctx *cli.Context) error { if jwk.Algorithm == "" { return errors.New("flag '--alg' is required with the given key") } - if err := jose.ValidateJWK(jwk); err != nil { + if err = jose.ValidateJWK(jwk); err != nil { return err } diff --git a/command/crypto/jwt/sign.go b/command/crypto/jwt/sign.go index 74b75438..8b31e48f 100644 --- a/command/crypto/jwt/sign.go +++ b/command/crypto/jwt/sign.go @@ -285,7 +285,7 @@ func signAction(ctx *cli.Context) error { if jwk.Algorithm == "" { return errors.New("flag '--alg' is required with the given key") } - if err := jose.ValidateJWK(jwk); err != nil { + if err = jose.ValidateJWK(jwk); err != nil { return err } diff --git a/command/crypto/keypair.go b/command/crypto/keypair.go index 5493c8ff..82a45a64 100644 --- a/command/crypto/keypair.go +++ b/command/crypto/keypair.go @@ -134,7 +134,7 @@ existing instead of creating a new key.`, } func createAction(ctx *cli.Context) (err error) { - if err := errs.NumberOfArguments(ctx, 2); err != nil { + if err = errs.NumberOfArguments(ctx, 2); err != nil { return err } @@ -175,7 +175,8 @@ func createAction(ctx *cli.Context) (err error) { return errs.IncompatibleFlagWithFlag(ctx, "from-jwk", "size") } - jwk, err := jose.ParseKey(fromJWK) + var jwk *jose.JSONWebKey + jwk, err = jose.ParseKey(fromJWK) if err != nil { return err } @@ -187,7 +188,11 @@ func createAction(ctx *cli.Context) (err error) { priv = jwk.Key } } else { - kty, crv, size, err := utils.GetKeyDetailsFromCLI(ctx, insecure, "kty", + var ( + kty, crv string + size int + ) + kty, crv, size, err = utils.GetKeyDetailsFromCLI(ctx, insecure, "kty", "curve", "size") if err != nil { return err @@ -217,7 +222,8 @@ func createAction(ctx *cli.Context) (err error) { return err } } else { - pass, err := ui.PromptPassword("Please enter the password to encrypt the private key", ui.WithValue(password)) + var pass []byte + pass, err = ui.PromptPassword("Please enter the password to encrypt the private key", ui.WithValue(password)) if err != nil { return errors.Wrap(err, "error reading password") } diff --git a/command/crypto/nacl/box.go b/command/crypto/nacl/box.go index d023f2be..8500f728 100644 --- a/command/crypto/nacl/box.go +++ b/command/crypto/nacl/box.go @@ -29,7 +29,7 @@ NaCl crypto_box function is designed to meet the standard notions of privacy and third-party unforgeability for a public-key authenticated-encryption scheme using nonces. For formal definitions see, e.g., Jee Hea An, "Authenticated encryption in the public-key setting: security notions and -analyses," https://eprint.iacr.org/2001/079. Distinct messages between the same +analyzes," https://eprint.iacr.org/2001/079. Distinct messages between the same {sender, receiver} set are required to have distinct nonces. For example, the lexicographically smaller public key can use nonce 1 for its first message to the other key, nonce 3 for its second message, nonce 5 for its third message, diff --git a/command/oauth/cmd.go b/command/oauth/cmd.go index 31b5e089..24e0d9f9 100644 --- a/command/oauth/cmd.go +++ b/command/oauth/cmd.go @@ -205,7 +205,7 @@ func oauthCmd(c *cli.Context) error { return errors.Wrapf(err, "error reading account from %s", filename) } account := make(map[string]interface{}) - if err := json.Unmarshal(b, &account); err != nil { + if err = json.Unmarshal(b, &account); err != nil { return errors.Wrapf(err, "error reading %s: unsupported format", filename) } @@ -290,7 +290,7 @@ type options struct { // Validate validates the options. func (o *options) Validate() error { if o.Provider != "google" && !strings.HasPrefix(o.Provider, "https://") { - return errors.New("Use a valid provider: google") + return errors.New("use a valid provider: google") } return nil } @@ -408,7 +408,7 @@ func disco(provider string) (map[string]interface{}, error) { return nil, errors.Wrapf(err, "error retrieving %s", url.String()) } details := make(map[string]interface{}) - if err := json.Unmarshal(b, &details); err != nil { + if err = json.Unmarshal(b, &details); err != nil { return nil, errors.Wrapf(err, "error reading %s: unsupported format", url.String()) } return details, err diff --git a/crypto/pemutil/pem.go b/crypto/pemutil/pem.go index c6a8f0c0..118444cb 100644 --- a/crypto/pemutil/pem.go +++ b/crypto/pemutil/pem.go @@ -148,7 +148,8 @@ func ReadCertificate(filename string, opts ...Options) (*x509.Certificate, error // PEM format if bytes.HasPrefix(b, []byte("-----BEGIN ")) { - crt, err := Read(filename, opts...) + var crt interface{} + crt, err = Read(filename, opts...) if err != nil { return nil, err } @@ -186,7 +187,8 @@ func ReadCertificateBundle(filename string) ([]*x509.Certificate, error) { if block.Type != "CERTIFICATE" { return nil, errors.Errorf("error decoding PEM: file '%s' is not a certificate bundle", filename) } - crt, err := x509.ParseCertificate(block.Bytes) + var crt *x509.Certificate + crt, err = x509.ParseCertificate(block.Bytes) if err != nil { return nil, errors.Wrapf(err, "error parsing %s", filename) } @@ -216,7 +218,8 @@ func ReadStepCertificate(filename string) (*stepx509.Certificate, error) { // PEM format if bytes.HasPrefix(b, []byte("-----BEGIN ")) { - crt, err := Read(filename, []Options{WithStepCrypto()}...) + var crt interface{} + crt, err = Read(filename, []Options{WithStepCrypto()}...) if err != nil { return nil, err } @@ -331,12 +334,13 @@ func Read(filename string, opts ...Options) (interface{}, error) { // Serialize will serialize the input to a PEM formatted block and apply // modifiers. -func Serialize(in interface{}, opts ...Options) (p *pem.Block, err error) { +func Serialize(in interface{}, opts ...Options) (*pem.Block, error) { ctx := new(context) if err := ctx.apply(opts); err != nil { return nil, err } + var p *pem.Block switch k := in.(type) { case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey: b, err := MarshalPKIXPublicKey(k) @@ -420,11 +424,13 @@ func Serialize(in interface{}, opts ...Options) (p *pem.Block, err error) { // Apply options on the PEM blocks. if ctx.password != nil { if _, ok := in.(crypto.PrivateKey); ok && ctx.pkcs8 { + var err error p, err = EncryptPKCS8PrivateKey(rand.Reader, p.Bytes, ctx.password, DefaultEncCipher) if err != nil { return nil, err } } else { + var err error p, err = x509.EncryptPEMBlock(rand.Reader, p.Type, p.Bytes, ctx.password, DefaultEncCipher) if err != nil { return nil, errors.Wrap(err, "failed to serialze to PEM") diff --git a/crypto/pemutil/pem_test.go b/crypto/pemutil/pem_test.go index bdb9555d..7f9770f1 100644 --- a/crypto/pemutil/pem_test.go +++ b/crypto/pemutil/pem_test.go @@ -450,7 +450,8 @@ func TestSerialize(t *testing.T) { assert.Equals(t, p.Type, "RSA PRIVATE KEY") assert.Equals(t, p.Headers["Proc-Type"], "4,ENCRYPTED") - der, err := x509.DecryptPEMBlock(p, []byte(test.pass)) + var der []byte + der, err = x509.DecryptPEMBlock(p, []byte(test.pass)) assert.FatalError(t, err) assert.Equals(t, der, x509.MarshalPKCS1PrivateKey(k)) } @@ -458,7 +459,8 @@ func TestSerialize(t *testing.T) { assert.False(t, x509.IsEncryptedPEMBlock(p)) assert.Equals(t, p.Type, "PUBLIC KEY") - b, err := x509.MarshalPKIXPublicKey(k) + var b []byte + b, err = x509.MarshalPKIXPublicKey(k) assert.FatalError(t, err) assert.Equals(t, p.Bytes, b) case *ecdsa.PrivateKey: @@ -474,17 +476,20 @@ func TestSerialize(t *testing.T) { actualBytes, err = x509.DecryptPEMBlock(p, []byte(test.pass)) assert.FatalError(t, err) } - expectedBytes, err := x509.MarshalECPrivateKey(k) + var expectedBytes []byte + expectedBytes, err = x509.MarshalECPrivateKey(k) assert.FatalError(t, err) assert.Equals(t, actualBytes, expectedBytes) if test.file != "" { // Check key permissions - fileInfo, err := os.Stat(test.file) + var fileInfo os.FileInfo + fileInfo, err = os.Stat(test.file) assert.FatalError(t, err) assert.Equals(t, fileInfo.Mode(), os.FileMode(0600)) // Verify that key written to file is correct - keyFileBytes, err := ioutil.ReadFile(test.file) + var keyFileBytes []byte + keyFileBytes, err = ioutil.ReadFile(test.file) assert.FatalError(t, err) pemKey, _ := pem.Decode(keyFileBytes) assert.Equals(t, pemKey.Type, "EC PRIVATE KEY") diff --git a/crypto/pemutil/pkcs8.go b/crypto/pemutil/pkcs8.go index e5c8b4d6..69ac7672 100644 --- a/crypto/pemutil/pkcs8.go +++ b/crypto/pemutil/pkcs8.go @@ -238,7 +238,7 @@ func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) { } } -// MarshalPKIXPublicKey serialises a public key to DER-encoded PKIX format. The +// MarshalPKIXPublicKey serializes a public key to DER-encoded PKIX format. The // following key types are supported: *rsa.PublicKey, *ecdsa.PublicKey, // ed25519.Publickey. Unsupported key types result in an error. func MarshalPKIXPublicKey(pub interface{}) ([]byte, error) { @@ -265,7 +265,7 @@ func MarshalPKCS8PrivateKey(key interface{}) ([]byte, error) { switch k := key.(type) { case *rsa.PrivateKey, *ecdsa.PrivateKey: b, err := x509.MarshalPKCS8PrivateKey(key) - return b, errors.Wrap(err, "error marshalling PKCS#8") + return b, errors.Wrap(err, "error marshaling PKCS#8") case ed25519.PrivateKey: var priv pkcs8 priv.PrivateKey = append([]byte{4, 32}, k.Seed()...)[:34] @@ -273,9 +273,9 @@ func MarshalPKCS8PrivateKey(key interface{}) ([]byte, error) { Algorithm: asn1.ObjectIdentifier{1, 3, 101, 112}, } b, err := asn1.Marshal(priv) - return b, errors.Wrap(err, "error marshalling PKCS#8") + return b, errors.Wrap(err, "error marshaling PKCS#8") default: - return nil, errors.Errorf("x509: unknown key type while marshalling PKCS#8: %T", key) + return nil, errors.Errorf("x509: unknown key type while marshaling PKCS#8: %T", key) } } @@ -428,7 +428,7 @@ func EncryptPKCS8PrivateKey(rand io.Reader, data, password []byte, alg x509.PEMC b, err := asn1.Marshal(pki) if err != nil { - return nil, errors.Wrap(err, "error marshalling encrypted key") + return nil, errors.Wrap(err, "error marshaling encrypted key") } return &pem.Block{ Type: "ENCRYPTED PRIVATE KEY", diff --git a/crypto/pki/pki.go b/crypto/pki/pki.go index 976efd2e..224c5efb 100644 --- a/crypto/pki/pki.go +++ b/crypto/pki/pki.go @@ -134,20 +134,18 @@ type PKI struct { // New creates a new PKI configuration. func New(public, private, config string) (*PKI, error) { - var err error - - if _, err = os.Stat(public); os.IsNotExist(err) { + if _, err := os.Stat(public); os.IsNotExist(err) { if err = os.MkdirAll(public, 0700); err != nil { return nil, errs.FileError(err, public) } } - if _, err = os.Stat(private); os.IsNotExist(err) { + if _, err := os.Stat(private); os.IsNotExist(err) { if err = os.MkdirAll(private, 0700); err != nil { return nil, errs.FileError(err, private) } } if len(config) > 0 { - if _, err = os.Stat(config); os.IsNotExist(err) { + if _, err := os.Stat(config); os.IsNotExist(err) { if err = os.MkdirAll(config, 0700); err != nil { return nil, errs.FileError(err, config) } @@ -160,6 +158,7 @@ func New(public, private, config string) (*PKI, error) { return s, errors.Wrapf(err, "error getting absolute path for %s", name) } + var err error p := &PKI{ provisioner: "step-cli", address: "127.0.0.1:9000", @@ -359,7 +358,7 @@ func (p *PKI) Save(opt ...Option) error { b, err := json.MarshalIndent(config, "", " ") if err != nil { - return errors.Wrapf(err, "error marshalling %s", p.config) + return errors.Wrapf(err, "error marshaling %s", p.config) } if err = utils.WriteFile(p.config, b, 0666); err != nil { return errs.FileError(err, p.config) @@ -368,7 +367,8 @@ func (p *PKI) Save(opt ...Option) error { // Generate the CA URL. if p.caURL == "" { p.caURL = p.dnsNames[0] - _, port, err := net.SplitHostPort(p.address) + var port string + _, port, err = net.SplitHostPort(p.address) if err != nil { return errors.Wrapf(err, "error parsing %s", p.address) } @@ -387,7 +387,7 @@ func (p *PKI) Save(opt ...Option) error { } b, err = json.MarshalIndent(defaults, "", " ") if err != nil { - return errors.Wrapf(err, "error marshalling %s", p.defaults) + return errors.Wrapf(err, "error marshaling %s", p.defaults) } if err = utils.WriteFile(p.defaults, b, 0666); err != nil { return errs.FileError(err, p.defaults) diff --git a/crypto/x509util/profile.go b/crypto/x509util/profile.go index 3edc053c..f9733333 100644 --- a/crypto/x509util/profile.go +++ b/crypto/x509util/profile.go @@ -361,7 +361,7 @@ func (b *base) CreateWriteCertificate(crtOut, keyOut, pass string) ([]byte, erro if err != nil { return nil, errors.WithStack(err) } - if err := utils.WriteFile(crtOut, pem.EncodeToMemory(&pem.Block{ + if err = utils.WriteFile(crtOut, pem.EncodeToMemory(&pem.Block{ Type: "CERTIFICATE", Bytes: crtBytes, }), 0600); err != nil { diff --git a/jose/parse.go b/jose/parse.go index 93c9ea40..644af6e9 100644 --- a/jose/parse.go +++ b/jose/parse.go @@ -87,7 +87,7 @@ func ParseKey(filename string, opts ...Option) (*JSONWebKey, error) { } // Unmarshal the plain (or decrypted JWK) - if err := json.Unmarshal(b, jwk); err != nil { + if err = json.Unmarshal(b, jwk); err != nil { return nil, errors.Errorf("error reading %s: unsupported format", filename) } case pemKeyType: diff --git a/make/common.mk b/make/common.mk index 7cb1be28..bb7876e5 100644 --- a/make/common.mk +++ b/make/common.mk @@ -20,25 +20,17 @@ SHELL := /bin/bash bootstra%: $Q which dep || go get github.com/golang/dep/cmd/dep $Q dep ensure + $Q GO111MODULE=on go get github.com/golangci/golangci-lint/cmd/golangci-lint@v1.17.1 vendor: Gopkg.lock $Q dep ensure -BOOTSTRAP=\ - github.com/golang/lint/golint \ - github.com/client9/misspell/cmd/misspell \ - github.com/gordonklaus/ineffassign \ - github.com/tsenart/deadcode \ - github.com/golangci/golangci-lint - define VENDOR_BIN_TMPL vendor/bin/$(notdir $(1)): vendor $Q go build -o $$@ ./vendor/$(1) VENDOR_BINS += vendor/bin/$(notdir $(1)) endef -$(foreach pkg,$(BOOTSTRAP),$(eval $(call VENDOR_BIN_TMPL,$(pkg)))) - .PHONY: bootstra% vendor ################################################# @@ -121,26 +113,10 @@ integration: bin/$(BINNAME) # Linting ######################################### -LINTERS=\ - gofmt \ - golint \ - vet \ - misspell \ - ineffassign \ - deadcode +lint: + $Q LOG_LEVEL=error golangci-lint run -$(patsubst %,%-bin,$(filter-out gofmt vet,$(LINTERS))): %-bin: vendor/bin/% -gofmt-bin vet-bin: - -$(LINTERS): %: %-bin vendor - $Q PATH=`pwd`/vendor/bin:$$PATH golangci-lint run --disable-all \ - --deadline=5m --skip-dirs pkg --enable $@ ./... -fmt: - $Q gofmt -l -w $(SRC) - -lint: $(LINTERS) - -.PHONY: $(LINTERS) lint fmt +.PHONY: lint ######################################### # Install From 4fcf70192ffc5c9a9ed31d7c795cbef204013601 Mon Sep 17 00:00:00 2001 From: max furman Date: Mon, 26 Aug 2019 12:39:33 -0700 Subject: [PATCH 19/29] Support console mode in `step ca [sign|certificate]` * Fixes #132 --- .golangci.yml | 1 + command/ca/certificate.go | 21 +++++++++++++++------ command/ca/sign.go | 9 +++++++-- command/ca/token.go | 9 ++++++--- command/oauth/cmd.go | 3 +-- exec/exec.go | 25 ++++++++++++++++++------- 6 files changed, 48 insertions(+), 20 deletions(-) diff --git a/.golangci.yml b/.golangci.yml index 7beba1cc..fa27f581 100644 --- a/.golangci.yml +++ b/.golangci.yml @@ -58,6 +58,7 @@ issues: exclude: - can't lint - declaration of "err" shadows declaration at line + - should have a package comment, unless it's in another file for this package # golangci.com configuration # https://github.com/golangci/golangci/wiki/Configuration service: diff --git a/command/ca/certificate.go b/command/ca/certificate.go index f8cd04b4..632bc079 100644 --- a/command/ca/certificate.go +++ b/command/ca/certificate.go @@ -36,7 +36,7 @@ func certificateCommand() cli.Command { UsageText: `**step ca certificate** [**--token**=] [**--issuer**=] [**--ca-url**=] [**--root**=] [**--not-before**=] [**--not-after**=] [**--san**=] -[**--kty**=] [**--curve**=] [**--size**=]`, +[**--kty**=] [**--curve**=] [**--size**=] [**--console**]`, Description: `**step ca certificate** command generates a new certificate pair ## POSITIONAL ARGUMENTS @@ -86,6 +86,11 @@ $ step ca certificate --offline internal.example.com internal.crt internal.key Request a new certificate using an OIDC provisioner: ''' $ step ca certificate --token $(step oauth --oidc --bare) joe@example.com joe.crt joe.key +''' + +Request a new certificate using an OIDC provisioner while remaining in the console: +''' +$ step ca certificate joe@example.com joe.crt joe.key --issuer Google --console '''`, Flags: []cli.Flag{ tokenFlag, @@ -96,14 +101,18 @@ $ step ca certificate --token $(step oauth --oidc --bare) joe@example.com joe.cr notAfterFlag, cli.StringSliceFlag{ Name: "san", - Usage: `Add DNS or IP Address Subjective Alternative Names (SANs) that the token is -authorized to request. A certificate signing request using this token must match -the complete set of subjective alternative names in the token 1:1. Use the '--san' -flag multiple times to configure multiple SANs. The '--san' flag and the '--token' -flag are mutually exlusive.`, + Usage: `Add DNS Name, IP Address, or Email Address Subjective Alternative Names (SANs) +that the token is authorized to request. A certificate signing request using +this token must match the complete set of subjective alternative names in the +token 1:1. Use the '--san' flag multiple times to configure multiple SANs. The +'--san' flag and the '--token' flag are mutually exlusive.`, }, offlineFlag, caConfigFlag, + cli.BoolFlag{ + Name: "console", + Usage: "Complete the flow while remaining inside the terminal", + }, flags.Force, flags.KTY, flags.Size, diff --git a/command/ca/sign.go b/command/ca/sign.go index 07c4f3b3..c37778f1 100644 --- a/command/ca/sign.go +++ b/command/ca/sign.go @@ -19,8 +19,9 @@ func signCertificateCommand() cli.Command { Action: command.ActionFunc(signCertificateAction), Usage: "generate a new certificate signing a certificate request", UsageText: `**step ca sign** - [**--token**=] [**--issuer**=] [**--ca-url**=] [**--root**=] - [**--not-before**=] [**--not-after**=]`, +[**--token**=] [**--issuer**=] [**--ca-url**=] [**--root**=] +[**--not-before**=] [**--not-after**=] +[**--console**]`, Description: `**step ca sign** command signs the given csr and generates a new certificate. ## POSITIONAL ARGUMENTS @@ -60,6 +61,10 @@ $ step ca sign --offline internal internal.csr internal.crt offlineFlag, caConfigFlag, flags.Force, + cli.BoolFlag{ + Name: "console", + Usage: "Complete the flow while remaining inside the terminal", + }, }, } } diff --git a/command/ca/token.go b/command/ca/token.go index 82d3e1ce..eae64ab6 100644 --- a/command/ca/token.go +++ b/command/ca/token.go @@ -342,10 +342,13 @@ func newTokenFlow(ctx *cli.Context, typ int, subject string, sans []string, caUR switch p := p.(type) { case *provisioner.OIDC: // Run step oauth - var out []byte - out, err = exec.Step("oauth", "--oidc", "--bare", + args := []string{"oauth", "--oidc", "--bare", "--provider", p.ConfigurationEndpoint, - "--client-id", p.ClientID, "--client-secret", p.ClientSecret) + "--client-id", p.ClientID, "--client-secret", p.ClientSecret} + if ctx.IsSet("console") { + args = append(args, "--console") + } + out, err := exec.Step(args...) if err != nil { return "", err } diff --git a/command/oauth/cmd.go b/command/oauth/cmd.go index 24e0d9f9..26604ae4 100644 --- a/command/oauth/cmd.go +++ b/command/oauth/cmd.go @@ -395,7 +395,7 @@ func disco(provider string) (map[string]interface{}, error) { // TODO: OIDC and OAuth specify two different ways of constructing this // URL. This is the OIDC way. Probably want to try both. See // https://tools.ietf.org/html/rfc8414#section-5 - if strings.Index(url.Path, "/.well-known/openid-configuration") == -1 { + if !strings.Contains(url.Path, "/.well-known/openid-configuration") { url.Path = path.Join(url.Path, "/.well-known/openid-configuration") } resp, err := http.Get(url.String()) @@ -716,7 +716,6 @@ func (o *oauth) implicitHandler(w http.ResponseWriter, req *http.Request) { w.Write([]byte(`Success
`)) w.Write([]byte(`Click here if your browser does not automatically redirect you`)) w.Write([]byte(`

`)) - return } // Auth returns the OAuth 2.0 authentication url. diff --git a/exec/exec.go b/exec/exec.go index abced481..8f0f31d4 100644 --- a/exec/exec.go +++ b/exec/exec.go @@ -96,14 +96,20 @@ func OpenInBrowser(url string) error { // Step executes step with the given commands and returns the standard output. func Step(args ...string) ([]byte, error) { - var stderr bytes.Buffer + var stdout bytes.Buffer cmd := exec.Command(os.Args[0], args...) - cmd.Stderr = &stderr - out, err := cmd.Output() - if err != nil { - return nil, errors.Wrapf(err, "error running %s %s:\n%s", os.Args[0], strings.Join(args, " "), stderr.String()) + cmd.Stdin = os.Stdin + cmd.Stderr = os.Stderr + cmd.Stdout = &stdout + + if err := cmd.Start(); nil != err { + return nil, errors.Wrapf(err, "error starting: %s %s", os.Args[0], strings.Join(args, " ")) } - return out, nil + if err := cmd.Wait(); nil != err { + return nil, errors.Wrapf(err, "error running: %s %s", os.Args[0], strings.Join(args, " ")) + } + + return stdout.Bytes(), nil } // Command executes the given command with it's arguments and returns the @@ -158,7 +164,12 @@ func errorAndExit(name string, err error) { // signalHandler forwards all the signals to the cmd. func signalHandler(cmd *exec.Cmd, exitCh chan int) { - signals := make(chan os.Signal) + // signal.Notify prefers a buffered channel. From documentation: "For a + // channel used for notification of just one signal value, a buffer of size + // 1 is sufficient." As we do not know how many signal values the cmd is + // expecting we select 1 as a sane default. In the future maybe we can make + // this value configurable. + signals := make(chan os.Signal, 1) signal.Notify(signals) defer signal.Stop(signals) for { From 028ab7d86817444a489b9788a24184f1a654f1b8 Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 27 Aug 2019 15:05:46 -0700 Subject: [PATCH 20/29] Remove all linter requirements from Gopkg.toml * ignore go.mod and go.sum until switch to go modules --- .gitignore | 4 ++++ Gopkg.lock | 46 ---------------------------------------------- Gopkg.toml | 11 ----------- 3 files changed, 4 insertions(+), 57 deletions(-) diff --git a/.gitignore b/.gitignore index 515d07fd..50d71a24 100644 --- a/.gitignore +++ b/.gitignore @@ -19,3 +19,7 @@ coverage.txt output vendor step + +# Ignore modules until switch from gopkg +go.mod +go.sum diff --git a/Gopkg.lock b/Gopkg.lock index 0ba90fcc..67e58a0b 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -45,17 +45,6 @@ pruneopts = "UT" revision = "2972be24d48e78746da79ba8e24e8b488c9880de" -[[projects]] - digest = "1:848ef40f818e59905140552cc49ff3dc1a15f955e4b56d1c5c2cc4b54dbadf0c" - name = "github.com/client9/misspell" - packages = [ - ".", - "cmd/misspell", - ] - pruneopts = "UT" - revision = "b90dc15cfd220ecf8bbc9043ecb928cef381f011" - version = "v0.3.4" - [[projects]] branch = "master" digest = "1:cc439e1d9d8cff3d575642f5401033b00f2b8d0cd9f859db45604701c990879a" @@ -111,13 +100,6 @@ revision = "72cd26f257d44c1114970e19afddcd812016007e" version = "v1.4.1" -[[projects]] - digest = "1:4ee452f8994700dcab9e816aef1cb9eb2317218734c6ccf5135746e6c19f3dce" - name = "github.com/golang/lint" - packages = ["golint"] - pruneopts = "UT" - revision = "06c8688daad7faa9da5a0c2f163a3d14aac986ca" - [[projects]] digest = "1:318f1c959a8a740366fce4b1e1eb2fd914036b4af58fbd0a003349b305f118ad" name = "github.com/golang/protobuf" @@ -142,14 +124,6 @@ revision = "3629d6846518309d22c16fee15d1007262a459d2" version = "v1.0.21" -[[projects]] - branch = "master" - digest = "1:00d592bdacdeb0412b09f8eb2f98c6cc04470c4b72150f20733511e0821225c1" - name = "github.com/gordonklaus/ineffassign" - packages = ["."] - pruneopts = "UT" - revision = "ed7b1b5ee0f816bbc0ff35bf7c6fdb4f53b6c59a" - [[projects]] branch = "master" digest = "1:22725c01ecd8ed0c0f0078944305a57053340d92878b02db925c660cc4accf64" @@ -418,14 +392,6 @@ revision = "f35b8ab0b5a2cef36673838d662e249dd9c94686" version = "v1.2.2" -[[projects]] - branch = "master" - digest = "1:ba52e5a5fb800ce55108b7a5f181bb809aab71c16736051312b0aa969f82ad39" - name = "github.com/tsenart/deadcode" - packages = ["."] - pruneopts = "UT" - revision = "210d2dc333e90c7e3eedf4f2242507a8e83ed4ab" - [[projects]] branch = "master" digest = "1:6743b69de0d73e91004e4e201cf4965b59a0fa5caf6f0ffbe0cb9ee8807738a7" @@ -479,14 +445,6 @@ pruneopts = "UT" revision = "4d3f4d9ffa16a13f451c3b2999e9c49e9750bf06" -[[projects]] - branch = "master" - digest = "1:0824a2eb250dd552f41daaf471266d085e8e8cabdbff9e4294bc799076e00da7" - name = "golang.org/x/lint" - packages = ["."] - pruneopts = "UT" - revision = "959b441ac422379a43da2230f62be024250818b0" - [[projects]] branch = "master" digest = "1:2f7468b0b3fd7d926072f0dcbb6ec81e337278b4e5de639d017e54f785f0b475" @@ -593,9 +551,6 @@ input-imports = [ "github.com/ThomasRooney/gexpect", "github.com/chzyer/readline", - "github.com/client9/misspell/cmd/misspell", - "github.com/golang/lint/golint", - "github.com/gordonklaus/ineffassign", "github.com/icrowley/fake", "github.com/manifoldco/promptui", "github.com/pkg/errors", @@ -615,7 +570,6 @@ "github.com/smallstep/zlint", "github.com/stretchr/testify/assert", "github.com/stretchr/testify/require", - "github.com/tsenart/deadcode", "github.com/urfave/cli", "golang.org/x/crypto/argon2", "golang.org/x/crypto/bcrypt", diff --git a/Gopkg.toml b/Gopkg.toml index 39805755..bc58b627 100644 --- a/Gopkg.toml +++ b/Gopkg.toml @@ -23,17 +23,6 @@ # non-go = false # go-tests = true # unused-packages = true -required = [ - "github.com/golang/lint/golint", - "github.com/client9/misspell/cmd/misspell", - "github.com/gordonklaus/ineffassign", - "github.com/tsenart/deadcode", -] - -[[constraint]] - name = "github.com/golang/lint" - revision = "06c8688daad7faa9da5a0c2f163a3d14aac986ca" - [[override]] name = "gopkg.in/alecthomas/kingpin.v3-unstable" revision = "63abe20a23e29e80bbef8089bd3dee3ac25e5306" From 4a334f640b1e75ef1cf406823f05915c6e6c955b Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 27 Aug 2019 16:44:53 -0700 Subject: [PATCH 21/29] Remove unnecessary before_script download in travis yml * Already downloading golangci in `make bootstrap` --- .travis.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 33961857..6982c6f2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,6 @@ env: - V=1 before_script: - make bootstrap -- go get github.com/golangci/golangci-lint/cmd/golangci-lint script: - make - make artifacts From 043a79a76c8a453fd3098a9826a18bcfcacecb73 Mon Sep 17 00:00:00 2001 From: max furman Date: Wed, 28 Aug 2019 18:15:42 -0700 Subject: [PATCH 22/29] Add example for `step ca certificate` with RSA pub key --- command/ca/certificate.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/command/ca/certificate.go b/command/ca/certificate.go index 632bc079..14c26d32 100644 --- a/command/ca/certificate.go +++ b/command/ca/certificate.go @@ -91,6 +91,11 @@ $ step ca certificate --token $(step oauth --oidc --bare) joe@example.com joe.cr Request a new certificate using an OIDC provisioner while remaining in the console: ''' $ step ca certificate joe@example.com joe.crt joe.key --issuer Google --console +''' + +Request a new certificate with an RSA public key (default is ECDSA256): +''' +$ step ca certificate foo.internal foo.crt foo.key --kty RSA --size 4096 '''`, Flags: []cli.Flag{ tokenFlag, From ad0e89fd56023fcd241d81c67824343d968d783c Mon Sep 17 00:00:00 2001 From: max furman Date: Tue, 27 Aug 2019 18:11:09 -0700 Subject: [PATCH 23/29] Solicit feedback from users * step * step help * step ca init --- command/ca/init.go | 2 +- crypto/pki/pki.go | 23 ++++++++++++++++++++++- usage/usage.go | 11 +++++++++++ 3 files changed, 34 insertions(+), 2 deletions(-) diff --git a/command/ca/init.go b/command/ca/init.go index 210dce4d..f1aec4af 100644 --- a/command/ca/init.go +++ b/command/ca/init.go @@ -22,7 +22,7 @@ func initCommand() cli.Command { Action: cli.ActionFunc(initAction), Usage: "initialize the CA PKI", UsageText: `**step ca init** - [**--root**=] [**--key**=] [**--pki**] [**--name**=] +[**--root**=] [**--key**=] [**--pki**] [**--name**=] [**dns**=] [**address**=
] [**provisioner**=] [**provisioner-password-file**=] [**password-file**=] [**with-ca-url**=] [**no-db**]`, diff --git a/crypto/pki/pki.go b/crypto/pki/pki.go index 224c5efb..476785a1 100644 --- a/crypto/pki/pki.go +++ b/crypto/pki/pki.go @@ -7,9 +7,11 @@ import ( "encoding/json" "encoding/pem" "fmt" + "html" "net" "os" "path/filepath" + "strconv" "strings" "github.com/pkg/errors" @@ -270,10 +272,27 @@ func (p *PKI) GenerateIntermediateCertificate(name string, rootCrt *x509.Certifi return err } +func (p *PKI) askFeedback() { + ui.Println() + ui.Printf("\033[1mFEEDBACK\033[0m %s %s\n", + html.UnescapeString("&#"+strconv.Itoa(128525)+";"), + html.UnescapeString("&#"+strconv.Itoa(127867)+";")) + ui.Println(" The \033[1mstep\033[0m utility is not instrumented for usage statistics. It does not") + ui.Println(" phone home. But your feedback is extremely valuable. Any information you") + ui.Println(" can provide regarding how you’re using `step` helps. Please send us a") + ui.Println(" sentence or two, good or bad: \033[1mfeedback@smallstep.com\033[0m or join") + ui.Println(" \033[1mhttps://gitter.im/smallstep/community\033[0m.") +} + // TellPKI outputs the locations of public and private keys generated // generated for a new PKI. Generally this will consist of a root certificate // and key and an intermediate certificate and key. func (p *PKI) TellPKI() { + p.tellPKI() + p.askFeedback() +} + +func (p *PKI) tellPKI() { ui.Println() ui.PrintSelected("Root certificate", p.root) ui.PrintSelected("Root private key", p.rootKey) @@ -316,7 +335,7 @@ func WithoutDB() Option { // Save stores the pki on a json file that will be used as the certificate // authority configuration. func (p *PKI) Save(opt ...Option) error { - p.TellPKI() + p.tellPKI() key, err := p.ottPrivateKey.CompactSerialize() if err != nil { @@ -401,5 +420,7 @@ func (p *PKI) Save(opt ...Option) error { ui.Println() ui.Println("Your PKI is ready to go. To generate certificates for individual services see 'step help ca'.") + p.askFeedback() + return nil } diff --git a/usage/usage.go b/usage/usage.go index d097161b..0c65b765 100644 --- a/usage/usage.go +++ b/usage/usage.go @@ -3,6 +3,8 @@ package usage import ( "bytes" "fmt" + "html" + "strconv" "strings" "text/template" ) @@ -116,6 +118,15 @@ This documentation is available online at https://smallstep.com/docs/cli ## COPYRIGHT {{.Copyright}} + +## FEEDBACK ` + + html.UnescapeString("&#"+strconv.Itoa(128525)+";") + " " + + html.UnescapeString("&#"+strconv.Itoa(127867)+";") + + ` + +The **step** utility is not instrumented for usage statistics. It does not phone home. +But your feedback is extremely valuable. Any information you can provide regarding how you’re using 'step' helps. +Please send us a sentence or two, good or bad: **feedback@smallstep.com** or join https://gitter.im/smallstep/community. {{end}} ` From f433bbeb798423ad34e68b07f23c367638bfed89 Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 29 Aug 2019 11:02:55 -0700 Subject: [PATCH 24/29] dep update certificates --- Gopkg.lock | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Gopkg.lock b/Gopkg.lock index 67e58a0b..b99fd94c 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -311,7 +311,7 @@ [[projects]] branch = "master" - digest = "1:9f0a1fa1a057c51070e0eaf141de1546c740f39a5c471d159254dee006904a89" + digest = "1:ff01f6a3e431fa98b75ea2e7fa30cf1805e10c54fc85eb8742e9db852f7306c3" name = "github.com/smallstep/certificates" packages = [ "api", @@ -324,7 +324,7 @@ "server", ] pruneopts = "UT" - revision = "27d89c21dc9b331c784d4458a558c01d3a693c98" + revision = "8516ea2fc6b33ae59bc0a731e2c8a52c7d914931" [[projects]] branch = "master" From 3254c70079f798ee5f269c98fe27abd9a11c4aad Mon Sep 17 00:00:00 2001 From: max furman Date: Thu, 29 Aug 2019 15:58:40 -0700 Subject: [PATCH 25/29] Small change to feedback solicitation --- usage/usage.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/usage/usage.go b/usage/usage.go index 0c65b765..e352def9 100644 --- a/usage/usage.go +++ b/usage/usage.go @@ -125,7 +125,7 @@ This documentation is available online at https://smallstep.com/docs/cli ` The **step** utility is not instrumented for usage statistics. It does not phone home. -But your feedback is extremely valuable. Any information you can provide regarding how you’re using 'step' helps. +But your feedback is extremely valuable. Any information you can provide regarding how you’re using **step** helps. Please send us a sentence or two, good or bad: **feedback@smallstep.com** or join https://gitter.im/smallstep/community. {{end}} ` From d750b883b68fb9c1a25a6d7fc920f7e10e743d42 Mon Sep 17 00:00:00 2001 From: Michael Malone Date: Fri, 30 Aug 2019 17:04:31 -0700 Subject: [PATCH 26/29] Added features list to README.md --- README.md | 53 +++++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 47 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index a381a7f1..92f8ffaa 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,6 @@ # Step CLI -`step` is a zero trust swiss army knife. It's an easy-to-use and hard-to-misuse -utility for building, operating, and automating systems that use zero trust -technologies like 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). +`step` is a zero trust swiss army knife that integrates with [`step-ca`](https://github.com/smallstep/certificates) for automated certificate management. It's an easy-to-use and hard-to-misuse utility for building, operating, and automating systems that use zero trust technologies like 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). [Website](https://smallstep.com) | [Documentation](https://smallstep.com/docs/cli) | @@ -26,6 +21,52 @@ claims (JWT, SAML assertions). ![Animated terminal showing step in practice](https://smallstep.com/images/blog/2018-08-07-unfurl.gif) +## Features + +`step` is a powerful security tool that's been carefully designed to be safe and easy to use, even if you don't have a favorite elliptic curve or if you're inclined to forget to check the `aud` when you verify a JWT. + +- Safe and sane defaults everywhere encourage best practices by making the right thing easy +- Insecure or subtle operations are gated with flags to prevent accidental misuse +- In-depth help with examples is available via `step help` + +### Work with [JWTs](https://jwt.io) ([RFC7519](https://tools.ietf.org/html/rfc7519)) and [other JOSE constructs](https://datatracker.ietf.org/wg/jose/documents/) + +- [Sign](https://smallstep.com/docs/cli/crypto/jwt/sign), [verify](https://smallstep.com/docs/cli/crypto/jwt/verify), and [inspect](https://smallstep.com/docs/cli/crypto/jwt/inspect) JSON Web Tokens (JWTs) +- [Sign](https://smallstep.com/docs/cli/crypto/jws/sign), [verify](https://smallstep.com/docs/cli/crypto/jws/verify), and [inspect](https://smallstep.com/docs/cli/crypto/jws/inspect/) arbitrary data using JSON Web Signature (JWS) +- [Encrypt](https://smallstep.com/docs/cli/crypto/jwe/encrypt/) and [decrypt](https://smallstep.com/docs/cli/crypto/jwe/decrypt/) data and wrap private keys using JSON Web Encryption (JWE) +- [Create JWKs](https://smallstep.com/docs/cli/crypto/jwk/create/) and [manage key sets](https://smallstep.com/docs/cli/crypto/jwk/keyset) for use with JWT, JWE, and JWS + +### Work with X.509 (TLS/HTTPS) certificates + +- Create key pairs (RSA, ECDSA, EdDSA) and certificate signing requests (CSRs) +- Create [RFC5280](https://tools.ietf.org/html/rfc5280) and [CA/Browser Forum](https://cabforum.org/baseline-requirements-documents/) compliant X.509 certificates that work **for TLS and HTTPS** +- [Create](https://smallstep.com/docs/cli/certificate/create/) root and intermediate signing certificates (CA certificates) +- Create self-signed & CA-signed certificates, and [sign CSRs](https://smallstep.com/docs/cli/certificate/sign/) +- [Inspect](https://smallstep.com/docs/cli/certificate/inspect/) and [lint](https://smallstep.com/docs/cli/certificate/lint/) certificates on disk or in use by a remote server +- [Install root certificates](https://smallstep.com/docs/cli/certificate/install/) so your CA is trusted by default (issue development certificates **that [work in browsers](https://smallstep.com/blog/step-v0-8-6-valid-HTTPS-certificates-for-dev-pre-prod.html)**) +- Get certificates from any ACME compliant CA (*coming soon*) + +### Connect to [`step-ca`](https://github.com/smallstep/certificates) and get certificates from your own private certificate authority + +- [Authenticate and obtain a certificate](https://smallstep.com/docs/cli/ca/certificate/) using any enrollment mechanism supported by `step-ca` +- Securely [distribute root certificates](https://smallstep.com/docs/cli/ca/root/) and [bootstrap](https://smallstep.com/docs/cli/ca/bootstrap/) PKI relying parties +- [Renew](https://smallstep.com/docs/cli/ca/renew/) and [revoke](https://smallstep.com/docs/cli/ca/revoke/) certificates issued by `step-ca` +- [Submit CSRs](https://smallstep.com/docs/cli/ca/sign/) to be signed by `step-ca` + +### Command line OAuth and MFA + +- [Get OAuth access tokens](https://smallstep.com/docs/cli/oauth/) and OIDC identity tokens at the command line from any provider +- Supports OAuth authorization code, implicit, OOB, jwt-bearer, and refresh token flows +- Automatically launch browser to complete OAuth flow (or use console flow) +- Verify OIDC identity tokens (using `step crypt jwt verify`) +- [Generate and verify](https://smallstep.com/docs/cli/crypto/otp/) TOTP tokens + +### NaCl and other crypto utilities + +- [Work with NaCl](https://smallstep.com/docs/cli/crypto/nacl/) box, secretbox, and sign constructs +- [Apply key derivation functions](https://smallstep.com/docs/cli/crypto/kdf/) (KDFs) and [verify passwords](https://smallstep.com/docs/cli/crypto/kdf/compare/) using `scrypt`, `bcrypt`, and `argo2` +- Generate and check [file hashes](https://smallstep.com/docs/cli/crypto/hash/) + ## Installation Guide These instructions will install an OS specific version of the `step` binary on From 5e1b7414586ef79f17514ec4c7edcf78b8d0788e Mon Sep 17 00:00:00 2001 From: Michael Malone Date: Fri, 30 Aug 2019 17:47:44 -0700 Subject: [PATCH 27/29] Added step-ca example to README & fixed formatting --- README.md | 154 +++++++++++++++++++++++++++++++++--------------------- 1 file changed, 93 insertions(+), 61 deletions(-) diff --git a/README.md b/README.md index 92f8ffaa..7d3d162b 100644 --- a/README.md +++ b/README.md @@ -77,17 +77,13 @@ development](docs/local-development.md) below. Install `step` via [Homebrew](https://brew.sh/): -

-$ brew install step
-
+
$ brew install step
> Note: If you have installed `step` previously through the `smallstep/smallstep` > tap you will need to run the following commands before installing: - -

-$ brew untap smallstep/smallstep
-$ brew uninstall step
-
+> +>
$ brew untap smallstep/smallstep
+> $ brew uninstall step
### Linux @@ -95,12 +91,10 @@ Install `step` via [Homebrew](https://brew.sh/): Download and install the latest Debian package from [releases](https://github.com/smallstep/cli/releases): -

-$ wget https://github.com/smallstep/cli/releases/download/X.Y.Z/step_X.Y.Z_amd64.deb
+
$ wget https://github.com/smallstep/cli/releases/download/X.Y.Z/step_X.Y.Z_amd64.deb
 
 # Install the Debian package:
-$ sudo dpkg -i step_X.Y.Z_amd64.deb
-
+$ sudo dpkg -i step_X.Y.Z_amd64.deb
#### Arch Linux @@ -114,8 +108,7 @@ a sibling repository) can be found [here](https://aur.archlinux.org/packages/ste You can use [pacman](https://www.archlinux.org/pacman/) to install the packages. ### Test -

-$ step certificate inspect https://smallstep.com
+
$ step certificate inspect https://smallstep.com
 Certificate:
     Data:
         Version: 3 (0x2)
@@ -126,18 +119,86 @@ Certificate:
             Not Before: Feb 8 13:07:44 2019 UTC
             Not After : May 9 13:07:44 2019 UTC
         Subject: CN=smallstep.com
-[...]
-
+[...]
## Examples +### X.509 Certificates from `step-ca` + +This example assumes you already have [`step-ca`](https://github.com/smallstep/certificates) running at `https://ca.local`. + +Get your root certificate fingerprint from the machine running `step-ca`: + +
ca$ step certificate fingerprint $(step path)/certs/root_ca.crt
+0eea955785796f0a103637df88f29d8dfc8c1f4260f35c8e744be155f06fd82d
+ +Bootstrap a new machine to trust and connect to `step-ca`: + +
$ step ca bootstrap --ca-url https://ca.local \
+                    --fingerprint 0eea955785796f0a103637df88f29d8dfc8c1f4260f35c8e744be155f06fd82d
+ +Create a key pair, generate a CSR, and get a certificate from `step-ca`: + +
$ step ca certificate foo.local foo.crt foo.key
+Use the arrow keys to navigate: ↓ ↑ → ←
+What provisioner key do you want to use?
+  ▸ bob@smallstep.com (JWK) [kid: XXX]
+    Google (OIDC) [client: XXX.apps.googleusercontent.com]
+    Auth0 (OIDC) [client: XXX]
+    AWS IID Provisioner (AWS)
+✔ CA: https://ca.local
+✔ Certificate: foo.crt
+✔ Private Key: foo.key
+ + +Use `step certificate inspect` to check our work: + +
$ step certificate inspect --short foo.crt
+X.509v3 TLS Certificate (ECDSA P-256) [Serial: 2982...2760]
+  Subject:     foo.local
+  Issuer:      Intermediate CA
+  Provisioner: bob@smallstep.com [ID: EVct...2B-I]
+  Valid from:  2019-08-31T00:14:50Z
+          to:  2019-09-01T00:14:50Z
+ +Renew certificate: + +
$ step ca renew foo.crt foo.key --force
+Your certificate has been saved in foo.crt.
+ +Revoke certificate: + +
$ step ca revoke --cert foo.crt --key foo.key
+✔ CA: https://ca.local
+Certificate with Serial Number 202784089649824696691681223134769107758 has been revoked.
+
+$ step ca renew foo.crt foo.key --force
+error renewing certificate: Unauthorized
+ +You can install your root certificate locally: + +
$ step certificate install $(step path)/certs/root_ca.crt
+ +And issued certificates will work in your browser and with tools like `curl`. See [our blog post](https://smallstep.com/blog/step-v0-8-6-valid-HTTPS-certificates-for-dev-pre-prod.html) for more info. + +![Browser demo of HTTPS working without warnings](https://smallstep.com/images/blog/2019-02-25-localhost-tls.png) + +Alternatively, for internal service-to-service communication, you can [configure your code and infrastructure to trust your root certificate](https://github.com/smallstep/certificates/tree/master/autocert/examples/hello-mtls). + ### X.509 Certificates +The `step certificate` command group can also be used to create an offline CA and self-signed certificates. + +Create a self-signed certificate: + +
$ step certificate create foo.local foo.crt foo.key --profile self-signed --subtle
+Your certificate has been saved in foo.crt.
+Your private key has been saved in foo.key.
+ Create a root CA, an intermediate, and a leaf X.509 certificate. Bundle the leaf with the intermediate for use with TLS: -

-$ step certificate create --profile root-ca \
+
$ step certificate create --profile root-ca \
      "Example Root CA" root-ca.crt root-ca.key
 Please enter the password to encrypt the private key:
 Your certificate has been saved in root-ca.crt.
@@ -161,41 +222,23 @@ Your private key has been saved in example.com.key.
 
 $ step certificate bundle \
      example.com.crt intermediate-ca.crt example.com-bundle.crt
-Your certificate has been saved in example.com-bundle.crt.
-
+Your certificate has been saved in example.com-bundle.crt.
Extract the expiration date from a certificate (requires [`jq`](https://stedolan.github.io/jq/)): -

-$ step certificate inspect example.com.crt --format json | jq -r .validity.end
+
$ step certificate inspect example.com.crt --format json | jq -r .validity.end
 2019-02-28T17:46:16Z
 
 $ step certificate inspect https://smallstep.com --format json | jq -r .validity.end
-2019-05-09T13:07:44Z
-
- -You can install your root certificate locally: - -``` -$ step certificate install root-ca.crt -``` - -And issued certificates will work in your browser and with tools like `curl`. See [our blog post](https://smallstep.com/blog/step-v0-8-6-valid-HTTPS-certificates-for-dev-pre-prod.html) for more info. - -![Browser demo of HTTPS working without warnings](https://smallstep.com/images/blog/2019-02-25-localhost-tls.png) - -Alternatively, for internal service-to-service communication, you can [configure your code and infrastructure to trust your root certificate](https://github.com/smallstep/certificates/tree/master/autocert/examples/hello-mtls). - -If you need certificates for your microservices, containers, or other internal services see [step certificates](https://github.com/smallstep/certificates), a sub-project that adds an online certificate authority and automated certificate management tools to `step`. +2019-05-09T13:07:44Z
### JSON Object Signing & Encryption (JOSE) Create a [JSON Web Key](https://tools.ietf.org/html/rfc7517) (JWK), add the public key to a keyset, and sign a [JSON Web Token](https://tools.ietf.org/html/rfc7519) (JWT): -

-$ step crypto jwk create pub.json key.json
+
$ step crypto jwk create pub.json key.json
 Please enter the password to encrypt the private JWK:
 Your public key has been saved in pub.json.
 Your private key has been saved in key.json.
@@ -228,16 +271,14 @@ Please enter the password to decrypt key.json:
     "sub": "subject@example.com"
   },
   "signature": "JU7fPGqBJcIfauJHA7KP9Wp292g_G9s4bLMVLyRgEQDpL5faaG-3teJ81_igPz1zP7IjHmz8D6Gigt7kbnlasw"
-}
-
+}
### Single Sign-On Login with Google, get an access token, and use it to make a request to Google's APIs: -

-$ curl -H"$(step oauth --header)" https://www.googleapis.com/oauth2/v3/userinfo
+
$ curl -H"$(step oauth --header)" https://www.googleapis.com/oauth2/v3/userinfo
 Your default web browser has been opened to visit:
 
 https://accounts.google.com/o/oauth2/v2/auth?client_id=1087160488420-AAAAAAAAAAAAAAA.apps.googleusercontent.com&code_challenge=XXXXX
@@ -248,13 +289,11 @@ https://accounts.google.com/o/oauth2/v2/auth?client_id=1087160488420-AAAAAAAAAAA
   "email": "bob@smallstep.com",
   "email_verified": true,
   "hd": "smallstep.com"
-}
-
+}
Login with Google and obtain an OAuth OIDC identity token for single sign-on: -

-$ step oauth \
+
$ step oauth \
     --provider https://accounts.google.com \
     --client-id 1087160488420-8qt7bavg3qesdhs6it824mhnfgcfe8il.apps.googleusercontent.com \
     --client-secret udTrOT3gzrO7W9fDPgZQLfYJ \
@@ -263,13 +302,11 @@ Your default web browser has been opened to visit:
 
 https://accounts.google.com/o/oauth2/v2/auth?client_id=[...]
 
-xxx-google-xxx.yyy-oauth-yyy.zzz-token-zzz
-
+xxx-google-xxx.yyy-oauth-yyy.zzz-token-zzz
Obtain and verify a Google-issued OAuth OIDC identity token: -

-$ step oauth \
+
$ step oauth \
      --provider https://accounts.google.com \
      --client-id 1087160488420-8qt7bavg3qesdhs6it824mhnfgcfe8il.apps.googleusercontent.com \
      --client-secret udTrOT3gzrO7W9fDPgZQLfYJ \
@@ -301,26 +338,21 @@ https://accounts.google.com/o/oauth2/v2/auth?client_id=[...]
     "exp": 1551296734
   },
   "signature": "[...]"
-}
-
+}
### Multi-factor Authentication Generate a [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm) token and a QR code: -

-$ step crypto otp generate \
+
$ step crypto otp generate \
     --issuer smallstep.com --account name@smallstep.com \
-    --qr smallstep.png > smallstep.totp
-
+ --qr smallstep.png > smallstep.totp
Scan the QR Code (`smallstep.png`) using Google Authenticator, Authy or similar software and use it to verify the TOTP token: -

-$ step crypto otp verify --secret smallstep.totp
-
+
$ step crypto otp verify --secret smallstep.totp
## Documentation From 0b9afdec6d3b3a440a08be4c6d98235ca62f417f Mon Sep 17 00:00:00 2001 From: Michael Malone Date: Fri, 30 Aug 2019 19:43:12 -0700 Subject: [PATCH 28/29] Fixed link in README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7d3d162b..87c5cf2d 100644 --- a/README.md +++ b/README.md @@ -183,7 +183,7 @@ And issued certificates will work in your browser and with tools like `curl`. Se ![Browser demo of HTTPS working without warnings](https://smallstep.com/images/blog/2019-02-25-localhost-tls.png) -Alternatively, for internal service-to-service communication, you can [configure your code and infrastructure to trust your root certificate](https://github.com/smallstep/certificates/tree/master/autocert/examples/hello-mtls). +Alternatively, for internal service-to-service communication, you can [configure your code and infrastructure to trust your root certificate](https://github.com/smallstep/autocert/tree/master/examples/hello-mtls). ### X.509 Certificates From 2d4d5a052764ddb4930cd2a4411fa7ac84280d1c Mon Sep 17 00:00:00 2001 From: max furman Date: Fri, 30 Aug 2019 15:40:22 -0700 Subject: [PATCH 29/29] Add ability to set no password when using change-pass --- command/crypto/change-pass.go | 70 +++++++++++++++++++++++++++-------- 1 file changed, 54 insertions(+), 16 deletions(-) diff --git a/command/crypto/change-pass.go b/command/crypto/change-pass.go index 4ff09ea4..a4006bf1 100644 --- a/command/crypto/change-pass.go +++ b/command/crypto/change-pass.go @@ -20,13 +20,14 @@ import ( func changePassCommand() cli.Command { return cli.Command{ - Name: "change-pass", - Action: command.ActionFunc(changePassAction), - Usage: "change password of an encrypted private key (PEM or JWK format)", - UsageText: `**step crypto change-pass** [**--out**=]`, - Description: `**step crypto change-pass** extracts the private key from -a file and encrypts disk using a new password by either overwriting the original -encrypted key or writing a new file to disk. + Name: "change-pass", + Action: command.ActionFunc(changePassAction), + Usage: "change password of an encrypted private key (PEM or JWK format)", + UsageText: `**step crypto change-pass** +[**--out**=] [**--insecure**] [**--no-password**]`, + Description: `**step crypto change-pass** extracts and decrypts +the private key from a file and encrypts and serializes the key to disk using a +new password. ## POSITIONAL ARGUMENTS @@ -40,6 +41,11 @@ Change password for PEM formatted key: $ step crypto change-pass key.pem ''' +Remove password for PEM formatted key: +''' +$ step crypto change-pass key.pem --no-password --insecure +''' + Change password for PEM formatted key and write encrypted key to different file: ''' $ step crypto change-pass key.pem --out new-key.pem @@ -50,6 +56,11 @@ Change password for JWK formatted key: $ step crypto change-pass key.jwk ''' +Removed password for JWK formatted key: +''' +$ step crypto change-pass key.jwk --no-password --insecure +''' + Change password for JWK formatted key: ''' $ step crypto change-pass key.jwk --out new-key.jwk @@ -60,6 +71,13 @@ $ step crypto change-pass key.jwk --out new-key.jwk Usage: "The new encrypted key path. Default to overwriting the positional argument", }, flags.Force, + flags.Insecure, + cli.BoolFlag{ + Name: "no-password", + Usage: `Do not ask for a password to encrypt the private key. +Sensitive key material will be written to disk unencrypted. This is not +recommended. Requires **--insecure** flag.`, + }, }, } } @@ -72,8 +90,14 @@ func changePassAction(ctx *cli.Context) error { if err := errs.NumberOfArguments(ctx, 1); err != nil { return err } - keyPath := ctx.Args().Get(0) + insecure := ctx.Bool("insecure") + noPass := ctx.Bool("no-password") + if noPass && !insecure { + return errs.RequiredWithFlag(ctx, "insecure", "no-password") + } + + keyPath := ctx.Args().Get(0) newKeyPath := ctx.String("out") if len(newKeyPath) == 0 { newKeyPath = keyPath @@ -89,11 +113,16 @@ func changePassAction(ctx *cli.Context) error { if err != nil { return err } - pass, err := ui.PromptPassword(fmt.Sprintf("Please enter the password to encrypt %s", newKeyPath)) - if err != nil { - return errors.Wrap(err, "error reading password") + var opts []pemutil.Options + if !noPass { + pass, err := ui.PromptPassword(fmt.Sprintf("Please enter the password to encrypt %s", newKeyPath)) + if err != nil { + return errors.Wrap(err, "error reading password") + } + opts = append(opts, pemutil.WithPassword(pass)) } - if _, err := pemutil.Serialize(key, pemutil.WithPassword(pass), pemutil.ToFile(newKeyPath, 0644)); err != nil { + opts = append(opts, pemutil.ToFile(newKeyPath, 0644)) + if _, err := pemutil.Serialize(key, opts...); err != nil { return err } } else { @@ -101,12 +130,21 @@ func changePassAction(ctx *cli.Context) error { if err != nil { return err } - jwe, err := jose.EncryptJWK(jwk) - if err != nil { - return err + var b []byte + if noPass { + b, err = jwk.MarshalJSON() + if err != nil { + return err + } + } else { + jwe, err := jose.EncryptJWK(jwk) + if err != nil { + return err + } + b = []byte(jwe.FullSerialize()) } var out bytes.Buffer - if err := json.Indent(&out, []byte(jwe.FullSerialize()), "", " "); err != nil { + if err := json.Indent(&out, b, "", " "); err != nil { return errors.Wrap(err, "error formatting JSON") } if err := utils.WriteFile(newKeyPath, out.Bytes(), 0600); err != nil {