From 7232d3dccd88417639523e13a4dfcd2756f8f9c4 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Fri, 26 Aug 2022 12:48:21 -0700 Subject: [PATCH] Add step-kms-plugin attest command --- cmd/attest.go | 93 +++++++++++++++++++++++++++++++++++++++++++++++++++ cmd/key.go | 2 +- go.mod | 2 +- go.sum | 4 +-- 4 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 cmd/attest.go diff --git a/cmd/attest.go b/cmd/attest.go new file mode 100644 index 0000000..d747e22 --- /dev/null +++ b/cmd/attest.go @@ -0,0 +1,93 @@ +// Copyright 2022 Smallstep Labs, Inc. +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// http://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. +package cmd + +import ( + "context" + "encoding/pem" + "fmt" + "os" + + "github.com/smallstep/step-kms-plugin/internal/flagutil" + "github.com/spf13/cobra" + "go.step.sm/crypto/kms" + "go.step.sm/crypto/kms/apiv1" + "go.step.sm/crypto/pemutil" +) + +// attestCmd represents the attest command +var attestCmd = &cobra.Command{ + Use: "attest ", + Short: "create an attestation certificate", + Long: `This command, if the KMS supports it, it prints an attestation certificate or an endorsement key. + +Currently this command is only supported on YubiKeys.`, + Example: ` # Get the attestation certificate from a YubiKey: + step-kms-plugin attest "yubikey:slot-id=9c"`, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return showUsageErr(cmd) + } + + flags := cmd.Flags() + kuri := flagutil.MustString(flags, "kms") + if kuri == "" { + kuri = args[0] + } + + km, err := kms.New(context.Background(), apiv1.Options{ + URI: kuri, + }) + if err != nil { + return fmt.Errorf("failed to load key manager: %w", err) + } + defer km.Close() + + attester, ok := km.(apiv1.Attester) + if !ok { + return fmt.Errorf("%s does not implement an Attester", kuri) + } + + resp, err := attester.CreateAttestation(&apiv1.CreateAttestationRequest{ + Name: args[0], + }) + if err != nil { + return fmt.Errorf("failed to attest: %w", err) + } + + switch { + case resp.Certificate != nil: + return pem.Encode(os.Stdout, &pem.Block{ + Type: "CERTIFICATE", + Bytes: resp.Certificate.Raw, + }) + case resp.PublicKey != nil: + block, err := pemutil.Serialize(resp.PublicKey) + if err != nil { + return err + } + return pem.Encode(os.Stdout, block) + default: + return fmt.Errorf("failed to create attestation: unsupported response") + } + }, +} + +func init() { + rootCmd.AddCommand(attestCmd) + attestCmd.SilenceUsage = true + + flags := attestCmd.Flags() + flags.SortFlags = false +} diff --git a/cmd/key.go b/cmd/key.go index d1e8303..6dae08b 100644 --- a/cmd/key.go +++ b/cmd/key.go @@ -4,7 +4,7 @@ // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // -// http://www.apache.org/licenses/LICENSE-2.0 +// http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, diff --git a/go.mod b/go.mod index f9c2f32..a49f507 100644 --- a/go.mod +++ b/go.mod @@ -5,7 +5,7 @@ go 1.18 require ( github.com/spf13/cobra v1.5.0 github.com/spf13/pflag v1.0.5 - go.step.sm/crypto v0.17.0 + go.step.sm/crypto v0.18.1-0.20220826194421-b8cbff2a2b3e golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 ) diff --git a/go.sum b/go.sum index a5a008d..c253466 100644 --- a/go.sum +++ b/go.sum @@ -325,8 +325,8 @@ go.opentelemetry.io/proto/otlp v0.7.0/go.mod h1:PqfVotwruBrMGOCsRd/89rSnXhoiJIqe go.step.sm/cli-utils v0.7.3 h1:IA12IaiXVCI18yOFVQuvMpyvjL8wuwUn1yO+KhAVAr0= go.step.sm/cli-utils v0.7.3/go.mod h1:RJRwbBLqzs5nrepQLAV9FuT3fVpWz66tKzLIB7Izpfk= go.step.sm/crypto v0.9.0/go.mod h1:+CYG05Mek1YDqi5WK0ERc6cOpKly2i/a5aZmU1sfGj0= -go.step.sm/crypto v0.17.0 h1:qaLUbWygcMRMxrsz91jL5ytHIsIMABFYX6TkU+V8Pq8= -go.step.sm/crypto v0.17.0/go.mod h1:2oZdJ4ZUqPv5q8wz6yN4Qfsdcu2+eRaob4q1E5Azavs= +go.step.sm/crypto v0.18.1-0.20220826194421-b8cbff2a2b3e h1:aoy9vRtiegR+Afz0QcMkGr9NKQklDuuRyS1E8b5N6dw= +go.step.sm/crypto v0.18.1-0.20220826194421-b8cbff2a2b3e/go.mod h1:qZ+pNU1nV+THwP7TPTNCRMRr9xrRURhETTAK7U5psfw= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=