diff --git a/Makefile b/Makefile index 1c81ff5..595d12e 100644 --- a/Makefile +++ b/Makefile @@ -99,7 +99,7 @@ test: ######################################### fmt: - $Q goimports --local github.com/smallstep/step-kms-plugin -l -w $(SRC) + $Q goimports --local github.com/smallstep/step-kms-plugin --local go.step.sm/crypto -l -w $(SRC) lint: golint govulncheck diff --git a/cmd/attest.go b/cmd/attest.go index a41496e..855464f 100644 --- a/cmd/attest.go +++ b/cmd/attest.go @@ -31,6 +31,7 @@ import ( "github.com/fxamacker/cbor/v2" "github.com/spf13/cobra" + "go.step.sm/crypto/kms/apiv1" "go.step.sm/crypto/pemutil" diff --git a/cmd/certificate.go b/cmd/certificate.go index 2406a61..cf64ff4 100644 --- a/cmd/certificate.go +++ b/cmd/certificate.go @@ -20,6 +20,7 @@ import ( "strings" "github.com/spf13/cobra" + "go.step.sm/crypto/kms" "go.step.sm/crypto/kms/apiv1" "go.step.sm/crypto/kms/uri" diff --git a/cmd/create.go b/cmd/create.go index 4de252e..373780b 100644 --- a/cmd/create.go +++ b/cmd/create.go @@ -23,6 +23,7 @@ import ( "strings" "github.com/spf13/cobra" + "go.step.sm/crypto/kms/apiv1" "go.step.sm/crypto/kms/softkms" "go.step.sm/crypto/kms/tpmkms" diff --git a/cmd/decrypt.go b/cmd/decrypt.go index f3dcd77..66073da 100644 --- a/cmd/decrypt.go +++ b/cmd/decrypt.go @@ -25,6 +25,7 @@ import ( "os" "github.com/spf13/cobra" + "go.step.sm/crypto/kms/apiv1" "github.com/smallstep/step-kms-plugin/internal/flagutil" diff --git a/cmd/encrypt.go b/cmd/encrypt.go index 8f4a4f3..03d77bb 100644 --- a/cmd/encrypt.go +++ b/cmd/encrypt.go @@ -24,6 +24,7 @@ import ( "os" "github.com/spf13/cobra" + "go.step.sm/crypto/kms/apiv1" "github.com/smallstep/step-kms-plugin/internal/flagutil" diff --git a/cmd/key.go b/cmd/key.go index f95a558..1e6b011 100644 --- a/cmd/key.go +++ b/cmd/key.go @@ -18,6 +18,7 @@ import ( "io/fs" "github.com/spf13/cobra" + "go.step.sm/crypto/kms" "github.com/smallstep/step-kms-plugin/internal/flagutil" diff --git a/cmd/root.go b/cmd/root.go index 77156a4..3237eb7 100644 --- a/cmd/root.go +++ b/cmd/root.go @@ -26,6 +26,7 @@ import ( "github.com/smallstep/cli-utils/step" "github.com/spf13/cobra" + "go.step.sm/crypto/kms" "go.step.sm/crypto/kms/apiv1" "go.step.sm/crypto/kms/uri" diff --git a/cmd/search.go b/cmd/search.go new file mode 100644 index 0000000..502ab75 --- /dev/null +++ b/cmd/search.go @@ -0,0 +1,140 @@ +package cmd + +import ( + "encoding/json" + "encoding/pem" + "fmt" + + "github.com/spf13/cobra" + + "go.step.sm/crypto/kms/apiv1" + "go.step.sm/crypto/pemutil" + + "github.com/smallstep/step-kms-plugin/internal/flagutil" +) + +var searchCmd = &cobra.Command{ + Use: "search ", + Short: "search for keys stored in a KMS and list their names or details", + Long: `Search for one or more keys stored in a Key Management System (KMS). + +OUTPUT FORMATS: + By default, this command prints a simple list of key names (URIs), one per line. + Use the --json flag to output detailed information in JSON format, including + each key's name and corresponding public key in PEM format. + +SUPPORTED KMS TYPES: + - mackms: macOS Keychain and Secure Enclave (Secure Enclave requires signed binaries) + - tpmkms: Trusted Platform Module (TPM) 2.0 + +URI SYNTAX: + The format is: :[query-params] + + Query parameters are optional and allow you to filter search results. + Multiple parameters can be combined using standard URI query syntax. + +QUERY PARAMETERS: + + TPM (tpmkms:) + - ak=true Search only attestation keys (AKs) + - ak=false Search only application keys (non-AKs) + - name= Search for a key with the specified name + - (no param) Search all keys (both AKs and application keys) + + macOS Keychain and Secure Enclave (mackms:) + - label= Search keys with the specified label/name + - hash= Search keys with the given hash (hexadecimal format) + - tag= Search keys with the given tag (default: com.smallstep.crypto) + - se=true Search only keys on the Secure Enclave (requires signed binary) + - (no param) Search all keys on both Keychain and Secure Enclave`, + Example: ` # Search all keys on macOS Keychain/Secure Enclave: + step-kms-plugin search mackms: + + # Search all keys with a custom tag: + step-kms-plugin search mackms:tag=com.example.crypto + + # Search all keys (application and attestation keys) on a TPM: + step-kms-plugin search tpmkms: + + # Search all keys on a TPM with a custom storage directory: + step-kms-plugin search tpmkms:storage-directory=/tmp/tpmobjects + + # Search only attestation keys (AKs) on a TPM: + step-kms-plugin search tpmkms:ak=true + + # Search only application keys (non-AKs) on a TPM: + step-kms-plugin search tpmkms:ak=false + + # Search TPM keys and output details in JSON format with public keys: + step-kms-plugin search --json tpmkms:ak=false`, + RunE: func(cmd *cobra.Command, args []string) error { + if len(args) != 1 { + return showErrUsage(cmd) + } + + flags := cmd.Flags() + + kuri, name, err := getURIAndNameForFS(flagutil.MustString(flags, "kms"), args[0]) + if err != nil { + return err + } + + km, err := openKMS(cmd.Context(), kuri) + if err != nil { + return fmt.Errorf("failed to load key manager: %w", err) + } + defer km.Close() + + searchKMS, ok := km.(interface { + SearchKeys(*apiv1.SearchKeysRequest) (*apiv1.SearchKeysResponse, error) + }) + if !ok { + return fmt.Errorf("the KMS does not implement the SearchKeys method") + } + + results, err := searchKMS.SearchKeys(&apiv1.SearchKeysRequest{ + Query: name, + }) + if err != nil { + return err + } + + if flagutil.MustBool(flags, "json") { + keys := []map[string]any{} + for _, r := range results.Results { + block, err := pemutil.Serialize(r.PublicKey) + if err != nil { + return fmt.Errorf("failed to serialize the public key: %w", err) + } + + keys = append(keys, map[string]any{ + "name": r.Name, + "publicKey": string(pem.EncodeToMemory(block)), + }) + } + + b, err := json.MarshalIndent(map[string]any{ + "keys": keys, + }, "", " ") + if err != nil { + return fmt.Errorf("failed to marshal: %w", err) + } + fmt.Println(string(b)) + } else { + for _, r := range results.Results { + fmt.Println(r.Name) + } + } + + return nil + }, +} + +func init() { + rootCmd.AddCommand(searchCmd) + searchCmd.SilenceUsage = true + + flags := searchCmd.Flags() + flags.SortFlags = false + flags.Bool("json", false, "Show the output using JSON") +} diff --git a/cmd/sign.go b/cmd/sign.go index 2164963..073af86 100644 --- a/cmd/sign.go +++ b/cmd/sign.go @@ -31,15 +31,16 @@ import ( "strings" "github.com/spf13/cobra" - "go.step.sm/crypto/kms" - "go.step.sm/crypto/kms/apiv1" - "go.step.sm/crypto/kms/pkcs11" - "go.step.sm/crypto/sshutil" "golang.org/x/crypto/cryptobyte" "golang.org/x/crypto/cryptobyte/asn1" "golang.org/x/crypto/ssh" "golang.org/x/crypto/ssh/agent" + "go.step.sm/crypto/kms" + "go.step.sm/crypto/kms/apiv1" + "go.step.sm/crypto/kms/pkcs11" + "go.step.sm/crypto/sshutil" + "github.com/smallstep/step-kms-plugin/internal/flagutil" )