Skip to content

Commit

Permalink
Merge pull request #107 from smallstep/mariano/tss2
Browse files Browse the repository at this point in the history
Add TSS2 support
  • Loading branch information
maraino authored Dec 4, 2023
2 parents 4d6a4a7 + f7a9002 commit 862e0d8
Show file tree
Hide file tree
Showing 11 changed files with 221 additions and 63 deletions.
10 changes: 7 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -98,12 +98,16 @@ test:
fmt:
$Q goimports --local github.com/smallstep/step-kms-plugin -l -w $(SRC)

lint: SHELL:=/bin/bash
lint:
lint: golint govulncheck

golint: SHELL:=/bin/bash
golint:
$Q LOG_LEVEL=error golangci-lint run --config <(curl -s https://raw.githubusercontent.com/smallstep/workflows/master/.golangci.yml) --timeout=30m

govulncheck:
$Q govulncheck ./...

.PHONY: fmt lint
.PHONY: fmt lint golint govulncheck

#########################################
# Release
Expand Down
5 changes: 1 addition & 4 deletions cmd/attest.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ import (

"github.com/fxamacker/cbor/v2"
"github.com/spf13/cobra"
"go.step.sm/crypto/kms"
"go.step.sm/crypto/kms/apiv1"
"go.step.sm/crypto/pemutil"

Expand Down Expand Up @@ -94,9 +93,7 @@ account key fingerprint separated by a "." character:
kuri = name
}

km, err := kms.New(cmd.Context(), apiv1.Options{
URI: kuri,
})
km, err := openKMS(cmd.Context(), kuri)
if err != nil {
return fmt.Errorf("failed to load key manager: %w", err)
}
Expand Down
15 changes: 5 additions & 10 deletions cmd/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -59,22 +59,19 @@ var certificateCmd = &cobra.Command{
return showErrUsage(cmd)
}

name := args[0]
flags := cmd.Flags()
certFile := flagutil.MustString(flags, "import")
bundle := flagutil.MustBool(flags, "bundle")

kuri := ensureSchemePrefix(flagutil.MustString(flags, "kms"))
if kuri == "" {
kuri = name
kuri, name, err := getURIAndNameForFS(flagutil.MustString(flags, "kms"), args[0])
if err != nil {
return err
}

// Read a certificate using the CertFS.
if certFile == "" {
if bundle {
km, err := kms.New(cmd.Context(), apiv1.Options{
URI: kuri,
})
km, err := openKMS(cmd.Context(), kuri)
if err != nil {
return fmt.Errorf("failed to load key manager: %w", err)
}
Expand Down Expand Up @@ -122,9 +119,7 @@ var certificateCmd = &cobra.Command{
}
cert := certs[0]

km, err := kms.New(cmd.Context(), apiv1.Options{
URI: kuri,
})
km, err := openKMS(cmd.Context(), kuri)
if err != nil {
return fmt.Errorf("failed to load key manager: %w", err)
}
Expand Down
94 changes: 72 additions & 22 deletions cmd/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,16 +14,20 @@
package cmd

import (
"crypto/rsa"
"crypto/x509"
"encoding/json"
"encoding/pem"
"fmt"
"net/url"
"strings"

"github.com/spf13/cobra"
"go.step.sm/crypto/kms"
"go.step.sm/crypto/kms/apiv1"
"go.step.sm/crypto/kms/softkms"
"go.step.sm/crypto/kms/tpmkms"
"go.step.sm/crypto/pemutil"
"go.step.sm/crypto/tpm/tss2"

"github.com/smallstep/step-kms-plugin/internal/flagutil"
"github.com/smallstep/step-kms-plugin/internal/termutil"
Expand All @@ -37,8 +41,8 @@ var createCmd = &cobra.Command{
This command creates a new asymmetric key pair on the KMS. By default,
it creates an EC P-256 key, but the --kty, --crv and --size flags can be
combined to adjust the key properties. RSA and EC keys are boardly
supported, but as of mid-2022 Ed25519 (OKP) support is very limited.
combined to adjust the key properties. RSA and EC keys are broadly
supported, but as of 2023 Ed25519 (OKP) support is very limited.
For keys in AWS KMS, we recommend using --json for output, as you will need the
generated key-id.
Expand Down Expand Up @@ -82,8 +86,8 @@ Keys in a PKCS #11 module requires an id in hexadecimal as well as a label
# Create an Attestation Key (AK) in the default TPM KMS:
step-kms-plugin create 'tpmkms:name=my-ak;ak=true' --kty RSA --size 2048
# Create an EC P-256 private key in the default TPM KMS:
step-kms-plugin create tpmkms:name=my-ec-key
# Create an EC P-256 private key in the default TPM KMS and print it using the TSS2 PEM format:
step-kms-plugin create --format TSS2 tpmkms:name=my-ec-key
# Create an EC P-256 private key in the TPM KMS, backed by /tmp/tpmobjects:
step-kms-plugin create my-tmp-ec-key --kms tpmkms:storage-directory=/tmp/tpmobjects
Expand Down Expand Up @@ -126,7 +130,7 @@ Keys in a PKCS #11 module requires an id in hexadecimal as well as a label

protectionLevel := getProtectionLevel(pl)
if protectionLevel == apiv1.UnspecifiedProtectionLevel {
return fmt.Errorf("unsupported protection level: %q", pl)
return fmt.Errorf("unsupported protection level %q", pl)
}

kuri := ensureSchemePrefix(flagutil.MustString(flags, "kms"))
Expand All @@ -135,14 +139,21 @@ Keys in a PKCS #11 module requires an id in hexadecimal as well as a label
}

cmd.SilenceUsage = true
km, err := kms.New(cmd.Context(), apiv1.Options{
URI: kuri,
})
km, err := openKMS(cmd.Context(), kuri)
if err != nil {
return fmt.Errorf("failed to load key manager: %w", err)
}
defer km.Close()

if _, ok := km.(*tpmkms.TPMKMS); ok {
if flagutil.MustString(flags, "format") == "TSS2" {
name, err = changeURI(name, url.Values{"tss2": []string{"true"}})
if err != nil {
return fmt.Errorf("failed to parse %q: %w", name, err)
}
}
}

resp, err := km.CreateKey(&apiv1.CreateKeyRequest{
Name: name,
SignatureAlgorithm: signatureAlgorithm,
Expand All @@ -168,27 +179,64 @@ Keys in a PKCS #11 module requires an id in hexadecimal as well as a label
}
}

// Print the public key
return printCreateKeyResponse(cmd, resp)
},
}

func printCreateKeyResponse(cmd *cobra.Command, resp *apiv1.CreateKeyResponse) error {
var (
s string
isPrivateKey bool
flags = cmd.Flags()
)

switch flagutil.MustString(flags, "format") {
case "PKCS1":
if key, ok := resp.PublicKey.(*rsa.PublicKey); ok {
s = string(pem.EncodeToMemory(&pem.Block{
Type: "RSA PUBLIC KEY", Bytes: x509.MarshalPKCS1PublicKey(key),
}))
}
case "TSS2":
if key, ok := resp.PrivateKey.(*tss2.TPMKey); ok {
b, err := key.EncodeToMemory()
if err != nil {
return fmt.Errorf("failed to serialize the private key: %w", err)
}
s = string(b)
isPrivateKey = true
}
}

// Encode public key using PKIX format
if s == "" {
block, err := pemutil.Serialize(resp.PublicKey)
if err != nil {
return fmt.Errorf("failed to serialize the public key: %w", err)
}
s = string(pem.EncodeToMemory(block))
}

if flagutil.MustBool(flags, "json") {
b, err := json.MarshalIndent(map[string]string{
"name": resp.Name,
"publicKey": string(pem.EncodeToMemory(block)),
}, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal: %w", err)
}
fmt.Println(string(b))
if flagutil.MustBool(flags, "json") {
m := map[string]string{
"name": resp.Name,
}
if isPrivateKey {
m["privateKey"] = s
} else {
fmt.Print(string(pem.EncodeToMemory(block)))
m["publicKey"] = s
}

return nil
},
b, err := json.MarshalIndent(m, "", " ")
if err != nil {
return fmt.Errorf("failed to marshal: %w", err)
}
fmt.Println(string(b))
} else {
fmt.Print(s)
}

return nil
}

type rsaParams struct {
Expand Down Expand Up @@ -274,6 +322,7 @@ func init() {
kty := flagutil.UpperValue("kty", []string{"EC", "RSA", "OKP"}, "EC")
crv := flagutil.NormalizedValue("crv", []string{"P256", "P384", "P521", "Ed25519"}, "P256")
alg := flagutil.NormalizedValue("alg", []string{"SHA256", "SHA384", "SHA512"}, "SHA256")
format := flagutil.NormalizedValue("format", []string{"PKIX", "PKCS1", "TSS2"}, "PKIX")
protectionLevel := flagutil.UpperValue("protection-level", []string{"SOFTWARE", "HSM"}, "SOFTWARE")
pinPolicy := flagutil.UpperValue("pin-policy", []string{"NEVER", "ALWAYS", "ONCE"}, "")
touchPolicy := flagutil.UpperValue("touch-policy", []string{"NEVER", "ALWAYS", "CACHED"}, "")
Expand All @@ -287,5 +336,6 @@ func init() {
flags.Var(touchPolicy, "touch-policy", "The touch `policy` used on YubiKey KMS.\nOptions are NEVER, ALWAYS or CACHED")
flags.Bool("pss", false, "Use RSA-PSS signature scheme instead of PKCS #1")
flags.Bool("extractable", false, "Mark the new key as extractable")
flags.Var(format, "format", "The `format` to use in the output.\nOptions are PKIX, PKCS1 or TSS2")
flags.Bool("json", false, "Show the output using JSON")
}
5 changes: 1 addition & 4 deletions cmd/decrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ import (
"os"

"github.com/spf13/cobra"
"go.step.sm/crypto/kms"
"go.step.sm/crypto/kms/apiv1"

"github.com/smallstep/step-kms-plugin/internal/flagutil"
Expand Down Expand Up @@ -130,9 +129,7 @@ Cloud KMS.`,
data = data[:n]
}

km, err := kms.New(cmd.Context(), apiv1.Options{
URI: kuri,
})
km, err := openKMS(cmd.Context(), kuri)
if err != nil {
return fmt.Errorf("failed to load key manager: %w", err)
}
Expand Down
5 changes: 1 addition & 4 deletions cmd/encrypt.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"os"

"github.com/spf13/cobra"
"go.step.sm/crypto/kms"
"go.step.sm/crypto/kms/apiv1"

"github.com/smallstep/step-kms-plugin/internal/flagutil"
Expand Down Expand Up @@ -119,9 +118,7 @@ Cloud KMS.`,
}
}

km, err := kms.New(cmd.Context(), apiv1.Options{
URI: kuri,
})
km, err := openKMS(cmd.Context(), kuri)
if err != nil {
return fmt.Errorf("failed to load key manager: %w", err)
}
Expand Down
11 changes: 7 additions & 4 deletions cmd/key.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,21 @@ var keyCmd = &cobra.Command{
# Get a key from the default TPM KMS:
step-kms-plugin key tpmkms:name=my-key
# Get a key from the TSS2 PEM file:
step-kms-plugin key tpmkms:path=tss2.pem
# Get an AK public key from the default TPM KMS:
step-kms-plugin key 'tpmkms:name=my-ak;ak=true'`,
RunE: func(cmd *cobra.Command, args []string) error {
if len(args) != 1 {
return showErrUsage(cmd)
}

name := args[0]
flags := cmd.Flags()
kuri := ensureSchemePrefix(flagutil.MustString(flags, "kms"))
if kuri == "" {
kuri = name

kuri, name, err := getURIAndNameForFS(flagutil.MustString(flags, "kms"), args[0])
if err != nil {
return err
}

fsys, err := kms.KeyFS(cmd.Context(), kuri)
Expand Down
Loading

0 comments on commit 862e0d8

Please sign in to comment.