From 12e3dbcdafc1ffdf1489cb2d9954a5d6b841ee6f Mon Sep 17 00:00:00 2001 From: max furman Date: Mon, 15 Apr 2024 21:41:53 -0700 Subject: [PATCH] Fix certificate inspect --- command/certificate/inspect.go | 96 ++++++++++------------------------ go.mod | 18 +++---- go.sum | 12 +++++ 3 files changed, 49 insertions(+), 77 deletions(-) diff --git a/command/certificate/inspect.go b/command/certificate/inspect.go index 677820b00..339a25a59 100644 --- a/command/certificate/inspect.go +++ b/command/certificate/inspect.go @@ -1,7 +1,6 @@ package certificate import ( - "bytes" "crypto/x509" "encoding/json" "encoding/pem" @@ -12,10 +11,10 @@ import ( "github.com/pkg/errors" "github.com/smallstep/certinfo" "github.com/smallstep/cli/flags" - "github.com/smallstep/cli/utils" zx509 "github.com/smallstep/zcrypto/x509" "github.com/urfave/cli" "go.step.sm/cli-utils/errs" + "go.step.sm/crypto/pemutil" ) func inspectCommand() cli.Command { @@ -26,7 +25,7 @@ func inspectCommand() cli.Command { UsageText: `**step certificate inspect** [**--bundle**] [**--short**] [**--format**=] [**--roots**=] [**--servername**=]`, - Description: `**step certificate inspect** prints the details of the + Description: `**step certificate inspect** prints the details of the certificate or CSR in a human- or machine-readable format. Beware: Local certificates are never verified. Always verify a certificate (using **step certificate verify**) before relying on the output of this command. @@ -206,9 +205,6 @@ func inspectAction(ctx *cli.Context) error { return errs.IncompatibleFlagWithFlag(ctx, "short", "format json") } - var block *pem.Block - var blocks []*pem.Block - switch addr, isURL, err := trimURL(crtFile); { case err != nil: return err @@ -217,67 +213,34 @@ func inspectAction(ctx *cli.Context) error { if err != nil { return err } - for _, crt := range peerCertificates { - blocks = append(blocks, &pem.Block{ - Type: "CERTIFICATE", - Bytes: crt.Raw, - }) - } + return inspectCertificates(ctx, peerCertificates, os.Stdout) default: // is not URL - crtBytes, err := utils.ReadFile(crtFile) - if err != nil { - return errs.FileError(err, crtFile) - } - if bytes.Contains(crtBytes, []byte("-----BEGIN ")) { - for len(crtBytes) > 0 { - block, crtBytes = pem.Decode(crtBytes) - if block == nil { - break - } - if bundle && block.Type != "CERTIFICATE" { - return errors.Errorf("certificate bundle %q contains an unexpected PEM block of type %q\n\n expected type: CERTIFICATE", - crtFile, block.Type) - } - blocks = append(blocks, block) + crts, err := pemutil.ReadCertificateBundle(crtFile) + switch { + case errors.As(err, &pemutil.ErrNoValidPEMCert): + csr, err := pemutil.ReadCertificateRequest(crtFile) + if err != nil { + return errors.Errorf("file %s does not contain any valid CERTIFICATE or CERTIFICATE REQUEST blocks", crtFile) } - } else { - if block = derToPemBlock(crtBytes); block == nil { - return errors.Errorf("%q contains an invalid PEM block", crtFile) + return inspectCertificateRequest(ctx, csr) + case err != nil: + return err + default: + if bundle { + return inspectCertificates(ctx, crts, os.Stdout) } - blocks = append(blocks, block) - } - - // prevent index out of range errors - if len(blocks) == 0 { - return fmt.Errorf("%q does not contain valid PEM blocks", crtFile) + return inspectCertificates(ctx, crts[:1], os.Stdout) } } - - // Keep the first one if !bundle - if !bundle { - blocks = []*pem.Block{blocks[0]} - } - - switch blocks[0].Type { - case "CERTIFICATE": - return inspectCertificates(ctx, blocks, os.Stdout) - case "CERTIFICATE REQUEST", "NEW CERTIFICATE REQUEST": // only one is supported - return inspectCertificateRequest(ctx, blocks[0]) - default: - return errors.Errorf("Invalid PEM type in %q. Expected [CERTIFICATE|CERTIFICATE REQUEST] but got %q)", crtFile, block.Type) - } } -func inspectCertificates(ctx *cli.Context, blocks []*pem.Block, w io.Writer) error { +func inspectCertificates(ctx *cli.Context, crts []*x509.Certificate, w io.Writer) error { + var err error format, short := ctx.String("format"), ctx.Bool("short") switch format { case "text": var text string - for _, block := range blocks { - crt, err := x509.ParseCertificate(block.Bytes) - if err != nil { - return errors.WithStack(err) - } + for _, crt := range crts { if short { if text, err = certinfo.CertificateShortText(crt); err != nil { return err @@ -292,16 +255,16 @@ func inspectCertificates(ctx *cli.Context, blocks []*pem.Block, w io.Writer) err return nil case "json": var v interface{} - if len(blocks) == 1 { - zcrt, err := zx509.ParseCertificate(blocks[0].Bytes) + if len(crts) == 1 { + zcrt, err := zx509.ParseCertificate(crts[0].Raw) if err != nil { return errors.WithStack(err) } v = struct{ *zx509.Certificate }{zcrt} } else { var zcrts []*zx509.Certificate - for _, block := range blocks { - zcrt, err := zx509.ParseCertificate(block.Bytes) + for _, crt := range crts { + zcrt, err := zx509.ParseCertificate(crt.Raw) if err != nil { return errors.WithStack(err) } @@ -317,8 +280,8 @@ func inspectCertificates(ctx *cli.Context, blocks []*pem.Block, w io.Writer) err } return nil case "pem": - for _, block := range blocks { - err := pem.Encode(w, block) + for _, crt := range crts { + err := pem.Encode(w, &pem.Block{Type: "CERTIFICATE", Bytes: crt.Raw}) if err != nil { return errors.WithStack(err) } @@ -329,15 +292,12 @@ func inspectCertificates(ctx *cli.Context, blocks []*pem.Block, w io.Writer) err } } -func inspectCertificateRequest(ctx *cli.Context, block *pem.Block) error { +func inspectCertificateRequest(ctx *cli.Context, csr *x509.CertificateRequest) error { + var err error format, short := ctx.String("format"), ctx.Bool("short") switch format { case "text": var text string - csr, err := x509.ParseCertificateRequest(block.Bytes) - if err != nil { - return errors.WithStack(err) - } if short { text, err = certinfo.CertificateRequestShortText(csr) if err != nil { @@ -352,7 +312,7 @@ func inspectCertificateRequest(ctx *cli.Context, block *pem.Block) error { fmt.Print(text) return nil case "json": - zcsr, err := zx509.ParseCertificateRequest(block.Bytes) + zcsr, err := zx509.ParseCertificateRequest(csr.Raw) if err != nil { return errors.WithStack(err) } diff --git a/go.mod b/go.mod index fd9ef6a46..a06bcb313 100644 --- a/go.mod +++ b/go.mod @@ -26,11 +26,11 @@ require ( github.com/urfave/cli v1.22.14 go.mozilla.org/pkcs7 v0.0.0-20210826202110-33d05740a352 go.step.sm/cli-utils v0.9.0 - go.step.sm/crypto v0.44.2 + go.step.sm/crypto v0.44.5 go.step.sm/linkedca v0.20.1 - golang.org/x/crypto v0.21.0 - golang.org/x/sys v0.18.0 - golang.org/x/term v0.18.0 + golang.org/x/crypto v0.22.0 + golang.org/x/sys v0.19.0 + golang.org/x/term v0.19.0 google.golang.org/protobuf v1.33.0 software.sslmate.com/src/go-pkcs12 v0.4.0 ) @@ -44,7 +44,7 @@ require ( cloud.google.com/go/security v1.15.6 // indirect filippo.io/edwards25519 v1.1.0 // indirect github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 // indirect - github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 // indirect + github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 // indirect github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 // indirect github.com/Azure/azure-sdk-for-go/sdk/keyvault/azkeys v0.10.0 // indirect @@ -83,7 +83,7 @@ require ( github.com/golang/snappy v0.0.4 // indirect github.com/google/btree v1.1.2 // indirect github.com/google/certificate-transparency-go v1.1.7 // indirect - github.com/google/go-tpm-tools v0.4.3 // indirect + github.com/google/go-tpm-tools v0.4.4 // indirect github.com/google/go-tspi v0.3.0 // indirect github.com/google/s2a-go v0.1.7 // indirect github.com/googleapis/enterprise-certificate-proxy v0.3.2 // indirect @@ -136,17 +136,17 @@ require ( go.opentelemetry.io/otel/trace v1.24.0 // indirect golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc // indirect golang.org/x/mod v0.14.0 // indirect - golang.org/x/net v0.22.0 // indirect + golang.org/x/net v0.24.0 // indirect golang.org/x/oauth2 v0.18.0 // indirect golang.org/x/sync v0.6.0 // indirect golang.org/x/text v0.14.0 // indirect golang.org/x/time v0.5.0 // indirect golang.org/x/tools v0.16.0 // indirect - google.golang.org/api v0.171.0 // indirect + google.golang.org/api v0.172.0 // indirect google.golang.org/appengine v1.6.8 // indirect google.golang.org/genproto v0.0.0-20240213162025-012b6fc9bca9 // indirect google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 // indirect - google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c // indirect + google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237 // indirect google.golang.org/grpc v1.62.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect howett.net/plist v1.0.0 // indirect diff --git a/go.sum b/go.sum index cb3366399..830aab0d9 100644 --- a/go.sum +++ b/go.sum @@ -18,6 +18,7 @@ github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96 h1:cTp8I5+VIo github.com/AndreasBriese/bbloom v0.0.0-20190825152654-46b345b51c96/go.mod h1:bOvUY6CB00SOBii9/FifXqc0awNKxLFCL/+pkDPuyl8= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0 h1:n1DH8TPV4qqPTje2RcUBYwtrTWlabVp4n46+74X2pn4= github.com/Azure/azure-sdk-for-go/sdk/azcore v1.10.0/go.mod h1:HDcZnuGbiyppErN6lB+idp4CKhjbc8gwjto6OPpyggM= +github.com/Azure/azure-sdk-for-go/sdk/azcore v1.11.1/go.mod h1:a6xsAQUZg+VsS3TJ05SRp524Hs4pZ/AeFSr5ENf0Yjo= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1 h1:sO0/P7g68FrryJzljemN+6GTssUXdANk6aJ7T1ZxnsQ= github.com/Azure/azure-sdk-for-go/sdk/azidentity v1.5.1/go.mod h1:h8hyGFDsU5HMivxiS2iYFZsgDbU9OnnJ163x5UGVKYo= github.com/Azure/azure-sdk-for-go/sdk/internal v1.5.2 h1:LqbJ/WzJUwBf8UiaSzgX7aMclParm9/5Vgp+TY51uBQ= @@ -204,6 +205,7 @@ github.com/google/go-tpm v0.9.0 h1:sQF6YqWMi+SCXpsmS3fd21oPy/vSddwZry4JnmltHVk= github.com/google/go-tpm v0.9.0/go.mod h1:FkNVkc6C+IsvDI9Jw1OveJmxGZUUaKxtrpOS47QWKfU= github.com/google/go-tpm-tools v0.4.3 h1:L5dc34fttMIREoKRmnIJfv2NSZDSZ+RfBD+izN0EZoA= github.com/google/go-tpm-tools v0.4.3/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= +github.com/google/go-tpm-tools v0.4.4/go.mod h1:T8jXkp2s+eltnCDIsXR84/MTcVU9Ja7bh3Mit0pa4AY= github.com/google/go-tspi v0.3.0 h1:ADtq8RKfP+jrTyIWIZDIYcKOMecRqNJFOew2IT0Inus= github.com/google/go-tspi v0.3.0/go.mod h1:xfMGI3G0PhxCdNVcYr1C4C+EizojDg/TXuX5by8CiHI= github.com/google/logger v1.1.1 h1:+6Z2geNxc9G+4D4oDO9njjjn2d0wN5d7uOo0vOIW1NQ= @@ -451,6 +453,10 @@ go.step.sm/cli-utils v0.9.0 h1:55jYcsQbnArNqepZyAwcato6Zy2MoZDRkWW+jF+aPfQ= go.step.sm/cli-utils v0.9.0/go.mod h1:Y/CRoWl1FVR9j+7PnAewufAwKmBOTzR6l9+7EYGAnp8= go.step.sm/crypto v0.44.2 h1:t3p3uQ7raP2jp2ha9P6xkQF85TJZh+87xmjSLaib+jk= go.step.sm/crypto v0.44.2/go.mod h1:x1439EnFhadzhkuaGX7sz03LEMQ+jV4gRamf5LCZJQQ= +go.step.sm/crypto v0.44.4 h1:Ls5BOGM16AeZoMuiMbK9hbHbvdIEZIPjrrlpYPY5d94= +go.step.sm/crypto v0.44.4/go.mod h1:gGYw4D+5J8uFhBY6dzOBvDE8iwUo+gaOpKPFLcQwv9Q= +go.step.sm/crypto v0.44.5 h1:pgppm1g/RlNrKCDDNj/Dd7I42RCH95dL5HP2oL0ckDk= +go.step.sm/crypto v0.44.5/go.mod h1:gGYw4D+5J8uFhBY6dzOBvDE8iwUo+gaOpKPFLcQwv9Q= go.step.sm/linkedca v0.20.1 h1:bHDn1+UG1NgRrERkWbbCiAIvv4lD5NOFaswPDTyO5vU= go.step.sm/linkedca v0.20.1/go.mod h1:Vaq4+Umtjh7DLFI1KuIxeo598vfBzgSYZUjgVJ7Syxw= go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= @@ -480,6 +486,7 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4 golang.org/x/crypto v0.19.0/go.mod h1:Iy9bg/ha4yyC70EfRS8jz+B6ybOBKMaSxLj6P6oBDfU= golang.org/x/crypto v0.21.0 h1:X31++rzVUdKhX5sWmSOFZxx8UW/ldWx55cbf08iNAMA= golang.org/x/crypto v0.21.0/go.mod h1:0BP7YvVV9gBbVKyeTG0Gyn+gZm94bibOW5BjDEYAOMs= +golang.org/x/crypto v0.22.0/go.mod h1:vr6Su+7cTlO45qkww3VDJlzDn0ctJvRgYbC2NvXHt+M= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc h1:ao2WRsKSzW6KuUY9IWPwWahcHCgR0s52IfwutMfEbdM= golang.org/x/exp v0.0.0-20240103183307-be819d1f06fc/go.mod h1:iRJReGqOEeBhDZGkGbynYwcHlctCvnjTYIamk7uXpHI= @@ -509,6 +516,7 @@ golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg= golang.org/x/net v0.22.0 h1:9sGLhx7iRIHEiX0oAJ3MRZMUCElJgy7Br1nO+AMN3Tc= golang.org/x/net v0.22.0/go.mod h1:JKghWKKOSdJwpW2GEx0Ja7fmaKnMsbu+MWVZTokSYmg= +golang.org/x/net v0.24.0/go.mod h1:2Q7sJY5mzlzWjKtYUEXSlBWCdyaioyXzRB2RtU8KVE8= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.18.0 h1:09qnuIAgzdx1XplqJvW6CQqMCtGZykZWcXzPMPUusvI= golang.org/x/oauth2 v0.18.0/go.mod h1:Wf7knwG0MPoWIMMBgFlEaSUDaKskp0dCfrlJRJXbBi8= @@ -550,6 +558,7 @@ golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.17.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/sys v0.18.0 h1:DBdB3niSjOA/O0blCZBqDefyWNYveAYMNF1Wum0DYQ4= golang.org/x/sys v0.18.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= +golang.org/x/sys v0.19.0/go.mod h1:/VUhepiaJMQUp4+oa/7Zr1D23ma6VTLIYjOOTFZPUcA= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= @@ -559,6 +568,7 @@ golang.org/x/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo= golang.org/x/term v0.17.0/go.mod h1:lLRBjIVuehSbZlaOtGMbcMncT+aqLLLmKrsjNrUguwk= golang.org/x/term v0.18.0 h1:FcHjZXDMxI8mM3nwhX9HlKop4C0YQvCVCdwYl2wOtE8= golang.org/x/term v0.18.0/go.mod h1:ILwASektA3OnRv7amZ1xhE/KTR+u50pbXfZ03+6Nx58= +golang.org/x/term v0.19.0/go.mod h1:2CuTdWZ7KHSQwUzKva0cbMg6q2DMI3Mmxp+gKJbskEk= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ= @@ -597,6 +607,7 @@ golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8T golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.171.0 h1:w174hnBPqut76FzW5Qaupt7zY8Kql6fiVjgys4f58sU= google.golang.org/api v0.171.0/go.mod h1:Hnq5AHm4OTMt2BUVjael2CWZFD6vksJdWCWiUAmjC9o= +google.golang.org/api v0.172.0/go.mod h1:+fJZq6QXWfa9pXhnIzsjx4yI22d4aI9ZpLb58gvXjis= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.6.8 h1:IhEN5q69dyKagZPYMSdIjS2HqprW324FRQZJcGqPAsM= @@ -610,6 +621,7 @@ google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2 h1: google.golang.org/genproto/googleapis/api v0.0.0-20240311132316-a219d84964c2/go.mod h1:O1cOfN1Cy6QEYr7VxtjOyP5AdAuR0aJ/MYZaaof623Y= google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c h1:lfpJ/2rWPa/kJgxyyXM8PrNnfCzcmxJ265mADgwmvLI= google.golang.org/genproto/googleapis/rpc v0.0.0-20240314234333-6e1732d8331c/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= +google.golang.org/genproto/googleapis/rpc v0.0.0-20240318140521-94a12d6c2237/go.mod h1:WtryC6hu0hhx87FDGxWCDptyssuo68sk10vYjF+T9fY= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.25.1/go.mod h1:c3i+UQWmh7LiEpx4sFZnkU36qjEYZ0imhYfXVyQciAY=