Skip to content
Merged
Show file tree
Hide file tree
Changes from 5 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions command/ca/certificate.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,13 @@ Request a new certificate with an X5C provisioner:
$ step ca certificate foo.internal foo.crt foo.key --x5c-cert x5c.cert --x5c-key x5c.key
'''

Request a new certificate with an X5C using an certificate from a Yubikey:
Comment thread
maraino marked this conversation as resolved.
Outdated
'''
$ step ca certificate joe@example.com joe.crt joe.key \
--x5c-cert yubikey:slot-id=9a \
--x5c-key 'yubikey:slot-id=9a?pin=value=123456'
'''

**Certificate Templates** - With a provisioner configured with a custom
template we can use the **--set** flag to pass user variables:
'''
Expand Down
18 changes: 14 additions & 4 deletions command/ca/rekey.go
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,22 @@ Rekey a certificate forcing the overwrite of the previous certificate and key
$ step ca rekey --force internal.crt internal.key
'''

Rekey a certificate which key is in a KMS, with another from the same KMS:
Rekey a certificate using a KMS, with another from the same KMS:
'''
$ step ca rekey --private-key 'yubikey:slot-id=9a?pin-value=123456' \
yubikey.crt 'yubikey:slot-id=82?pin-value=123456'
'''

Rekey a certificate using a KMS with the <--kms> flag:
'''
$ step ca rekey \
--kms 'pkcs11:module-path=/usr/local/lib/softhsm/libsofthsm2.so;token=smallstep?pin-value=password' \
--private-key 'pkcs11:id=4002'
pkcs11.crt 'pkcs11:id=4001'
--private-key 'pkcs11:id=4002' pkcs11.crt 'pkcs11:id=4001'
'''

'''
$ step ca rekey --key yubikey:pin-value=123456 --private-key yubikey:slot-id=9a \
yubikey.crt 'yubikey:slot-id=82
'''

Rekey a certificate providing the <--ca-url> and <--root> flags:
Expand Down Expand Up @@ -239,7 +249,7 @@ func rekeyCertificateAction(ctx *cli.Context) error {
// For now, if the --kms flag is given, do not allow to generate a new key
// and write it on disk. We can't use the daemon mode because we
// cannot generate new keys.
if kmsURI != "" {
if kmsURI != "" || cryptoutil.IsKMS(keyFile) {
switch {
case givenPrivate == "":
return errs.RequiredWithFlag(ctx, "kms", "private-key")
Expand Down
5 changes: 5 additions & 0 deletions command/ca/renew.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,11 @@ $ step ca renew --mtls=false --force internal.crt internal.key

Renew a certificate which key is in a KMS:
'''
$ step ca renew yubikey.crt 'yubikey:slot-id=9a?pin-value=123456'
'''

Renew a certificate which key is in a KMS, using the <--kms> flag:
'''
$ step ca renew \
--kms 'pkcs11:module-path=/usr/local/lib/softhsm/libsofthsm2.so;token=smallstep?pin-value=password' \
pkcs11.crt 'pkcs11:id=4001'
Expand Down
5 changes: 3 additions & 2 deletions command/ca/token.go
Original file line number Diff line number Diff line change
Expand Up @@ -173,8 +173,9 @@ Generate an X5C provisioner token using a certificate in a YubiKey. Note that a
YubiKey does not support storing a certificate bundle. To make it work, you must
add the intermediate and the root in the provisioner configuration:
'''
$ step ca token --kms yubikey:pin-value=123456 \
--x5c-cert yubikey:slot-id=82 --x5c-key yubikey:slot-id=82 \
$ step ca token \
--x5c-cert yubikey:slot-id=82 \
--x5c-key 'yubikey:slot-id=82?pin=value=123456' \
internal.example.com
'''

Expand Down
10 changes: 10 additions & 0 deletions command/certificate/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -330,8 +330,18 @@ $ step certificate create --csr --template csr.tpl --san coyote@acme.corp \
"Wile E. Coyote" coyote.csr coyote.key
'''

Create a CSR using <step-kms-plugin>:
'''
$ step certificate create --csr --key 'yubikey:slot-id=9a?pin=value=123456' coyote@acme.corp coyote.csr
'''

Create a root certificate using <step-kms-plugin>:
'''
$ step certificate create --profile root-ca --key 'yubikey:slot-id=9a?pin=value=123456' 'KMS Root' root_ca.crt
'''

Create a root certificate using <step-kms-plugin> and the <--kms> flag:
'''
$ step kms create \
--kms 'pkcs11:module-path=/usr/local/lib/softhsm/libsofthsm2.so;token=smallstep?pin-value=password' \
'pkcs11:id=4000;object=root-key'
Expand Down
11 changes: 8 additions & 3 deletions command/certificate/sign.go
Original file line number Diff line number Diff line change
Expand Up @@ -167,7 +167,11 @@ $ step certificate sign \
--kms 'pkcs11:module-path=/usr/local/lib/softhsm/libsofthsm2.so;token=smallstep?pin-value=password' \
leaf.csr issuer.crt 'pkcs11:id=4001'
'''
`,

Sign a CSR using a certificate and a key stored in a KMS:
'''
$ step certificate sign leaf.csr yubikey-slot-id=9a 'yubikey-slot-id=9a?pin-value=123456'
'''`,
Flags: []cli.Flag{
flags.KMSUri,
cli.StringFlag{
Expand Down Expand Up @@ -238,6 +242,7 @@ func signAction(ctx *cli.Context) error {
csrFile := ctx.Args().Get(0)
crtFile := ctx.Args().Get(1)
keyFile := ctx.Args().Get(2)
kms := ctx.String("kms")

// Parse certificate request
csr, err := pemutil.ReadCertificateRequest(csrFile)
Expand All @@ -249,7 +254,7 @@ func signAction(ctx *cli.Context) error {
}

// Parse issuer and issuer key (at least one should be present)
issuers, err := pemutil.ReadCertificateBundle(crtFile)
issuers, err := cryptoutil.LoadCertificate(kms, crtFile)
if err != nil {
return err
}
Expand All @@ -265,7 +270,7 @@ func signAction(ctx *cli.Context) error {
opts = append(opts, pemutil.WithPasswordFile(passFile))
}

signer, err := cryptoutil.CreateSigner(ctx.String("kms"), keyFile, opts...)
signer, err := cryptoutil.CreateSigner(kms, keyFile, opts...)
if err != nil {
return err
}
Expand Down
24 changes: 15 additions & 9 deletions internal/cryptoutil/cryptoutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"errors"
"fmt"
"io"
"os"
"os/exec"
"strconv"
"strings"
Expand All @@ -22,15 +23,24 @@ import (
"go.step.sm/crypto/pemutil"
)

// IsKMS returns true if the given uri is a KMS URI.
// IsKMS returns true if the given uri is a KMS URI. It will return false if a
// file exists with the same name, even if the path matches a KMS uri pattern.
func IsKMS(rawuri string) bool {
if _, err := os.Stat(rawuri); err == nil {
return false
}

typ, err := kms.TypeOf(rawuri)
if err != nil || typ == apiv1.DefaultKMS {
return false
}
return true
}

func isFilename(kmsURI, name string) bool {
return kmsURI == "" && !IsKMS(name)
}

// Attestor is the interface implemented by step-kms-plugin using the key, sign,
// and attest commands.
type Attestor interface {
Expand All @@ -39,7 +49,7 @@ type Attestor interface {
}

func PublicKey(kmsURI, name string, opts ...pemutil.Options) (crypto.PublicKey, error) {
if kmsURI == "" {
if isFilename(kmsURI, name) {
s, err := pemutil.Read(name, opts...)
if err != nil {
return nil, err
Expand All @@ -61,7 +71,7 @@ func PublicKey(kmsURI, name string, opts ...pemutil.Options) (crypto.PublicKey,
// CreateSigner reads a key from a file with a given name or creates a signer
// with the given kms and name uri.
func CreateSigner(kmsURI, name string, opts ...pemutil.Options) (crypto.Signer, error) {
if kmsURI == "" || isSoftKMS(kmsURI) {
if isFilename(kmsURI, name) {
s, err := pemutil.Read(name, opts...)
if err != nil {
return nil, err
Expand All @@ -75,13 +85,9 @@ func CreateSigner(kmsURI, name string, opts ...pemutil.Options) (crypto.Signer,
return newKMSSigner(kmsURI, name)
}

func isSoftKMS(kmsURI string) bool {
return strings.HasPrefix(strings.ToLower(strings.TrimSpace(kmsURI)), "softkms")
}

// LoadCertificate returns a x509.Certificate from a kms or file
func LoadCertificate(kmsURI, certPath string) ([]*x509.Certificate, error) {
if kmsURI == "" {
if isFilename(kmsURI, certPath) {
s, err := pemutil.ReadCertificateBundle(certPath)
if err != nil {
return nil, fmt.Errorf("file %s does not contain a valid certificate: %w", certPath, err)
Expand Down Expand Up @@ -117,7 +123,7 @@ func LoadCertificate(kmsURI, certPath string) ([]*x509.Certificate, error) {

// LoadJSONWebKey returns a jose.JSONWebKey from a KMS or a file.
func LoadJSONWebKey(kmsURI, name string, opts ...jose.Option) (*jose.JSONWebKey, error) {
if kmsURI == "" {
if isFilename(kmsURI, name) {
return jose.ReadKey(name, opts...)
}

Expand Down