From 39f46d31b9cca6cda3ae2c5da02d03d6e6eb4d4f Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Mon, 23 Jan 2023 16:30:55 -0800 Subject: [PATCH] Remove deprecated binaries This commit removes the following deprecated binaries: - step-awskms-init - step-cloudkms-init - step-pkcs11-init - step-yubikey-init From now on step and step-kms-plugin should be used to initialize the PKI in AWS KMS, GCP KMS, PKCS#11 modules or YubiKeys. A future commit will add step-kms-plugin to the docker images of step-ca. Fixes #1046 --- CHANGELOG.md | 8 + Makefile | 45 +-- cmd/step-awskms-init/main.go | 248 --------------- cmd/step-cloudkms-init/main.go | 286 ----------------- cmd/step-pkcs11-init/main.go | 553 --------------------------------- cmd/step-yubikey-init/main.go | 355 --------------------- docker/Dockerfile.step-ca | 4 +- docker/Dockerfile.step-ca.hsm | 5 - 8 files changed, 11 insertions(+), 1493 deletions(-) delete mode 100644 cmd/step-awskms-init/main.go delete mode 100644 cmd/step-cloudkms-init/main.go delete mode 100644 cmd/step-pkcs11-init/main.go delete mode 100644 cmd/step-yubikey-init/main.go diff --git a/CHANGELOG.md b/CHANGELOG.md index 730c2066..fc6e8872 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -27,6 +27,14 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0. ## [Unreleased] +### Removed + +- The deprecated CLI utils `step-awskms-init`, `step-cloudkms-init`, + `step-pkcs11-init`, `step-yubikey-init` have been removed. + [`step`](https://github.com/smallstep/cli) and + [`step-kms-plugin`](https://github.com/smallstep/step-kms-plugin) should be + used instead. + ## [v0.23.1] - 2022-01-10 ### Added diff --git a/Makefile b/Makefile index 90e96993..6665b0cc 100644 --- a/Makefile +++ b/Makefile @@ -1,13 +1,5 @@ PKG?=github.com/smallstep/certificates/cmd/step-ca BINNAME?=step-ca -CLOUDKMS_BINNAME?=step-cloudkms-init -CLOUDKMS_PKG?=github.com/smallstep/certificates/cmd/step-cloudkms-init -AWSKMS_BINNAME?=step-awskms-init -AWSKMS_PKG?=github.com/smallstep/certificates/cmd/step-awskms-init -YUBIKEY_BINNAME?=step-yubikey-init -YUBIKEY_PKG?=github.com/smallstep/certificates/cmd/step-yubikey-init -PKCS11_BINNAME?=step-pkcs11-init -PKCS11_PKG?=github.com/smallstep/certificates/cmd/step-pkcs11-init # Set V to 1 for verbose output from the Makefile Q=$(if $V,,@) @@ -90,29 +82,13 @@ GOFLAGS := CGO_ENABLED=0 download: $Q go mod download -build: $(PREFIX)bin/$(BINNAME) $(PREFIX)bin/$(CLOUDKMS_BINNAME) $(PREFIX)bin/$(AWSKMS_BINNAME) $(PREFIX)bin/$(YUBIKEY_BINNAME) $(PREFIX)bin/$(PKCS11_BINNAME) +build: $(PREFIX)bin/$(BINNAME) @echo "Build Complete!" $(PREFIX)bin/$(BINNAME): download $(call rwildcard,*.go) $Q mkdir -p $(@D) $Q $(GOOS_OVERRIDE) $(GOFLAGS) go build -v -o $(PREFIX)bin/$(BINNAME) $(LDFLAGS) $(PKG) -$(PREFIX)bin/$(CLOUDKMS_BINNAME): download $(call rwildcard,*.go) - $Q mkdir -p $(@D) - $Q $(GOOS_OVERRIDE) $(GOFLAGS) go build -v -o $(PREFIX)bin/$(CLOUDKMS_BINNAME) $(LDFLAGS) $(CLOUDKMS_PKG) - -$(PREFIX)bin/$(AWSKMS_BINNAME): download $(call rwildcard,*.go) - $Q mkdir -p $(@D) - $Q $(GOOS_OVERRIDE) $(GOFLAGS) go build -v -o $(PREFIX)bin/$(AWSKMS_BINNAME) $(LDFLAGS) $(AWSKMS_PKG) - -$(PREFIX)bin/$(YUBIKEY_BINNAME): download $(call rwildcard,*.go) - $Q mkdir -p $(@D) - $Q $(GOOS_OVERRIDE) $(GOFLAGS) go build -v -o $(PREFIX)bin/$(YUBIKEY_BINNAME) $(LDFLAGS) $(YUBIKEY_PKG) - -$(PREFIX)bin/$(PKCS11_BINNAME): download $(call rwildcard,*.go) - $Q mkdir -p $(@D) - $Q $(GOOS_OVERRIDE) $(GOFLAGS) go build -v -o $(PREFIX)bin/$(PKCS11_BINNAME) $(LDFLAGS) $(PKCS11_PKG) - # Target to force a build of step-ca without running tests simple: build @@ -133,7 +109,6 @@ generate: test: $Q $(GOFLAGS) gotestsum -- -coverprofile=coverage.out -short -covermode=atomic ./... - testcgo: $Q gotestsum -- -coverprofile=coverage.out -short -covermode=atomic ./... @@ -166,15 +141,11 @@ lint: INSTALL_PREFIX?=/usr/ -install: $(PREFIX)bin/$(BINNAME) $(PREFIX)bin/$(CLOUDKMS_BINNAME) $(PREFIX)bin/$(AWSKMS_BINNAME) +install: $(PREFIX)bin/$(BINNAME) $Q install -D $(PREFIX)bin/$(BINNAME) $(DESTDIR)$(INSTALL_PREFIX)bin/$(BINNAME) - $Q install -D $(PREFIX)bin/$(CLOUDKMS_BINNAME) $(DESTDIR)$(INSTALL_PREFIX)bin/$(CLOUDKMS_BINNAME) - $Q install -D $(PREFIX)bin/$(AWSKMS_BINNAME) $(DESTDIR)$(INSTALL_PREFIX)bin/$(AWSKMS_BINNAME) uninstall: $Q rm -f $(DESTDIR)$(INSTALL_PREFIX)/bin/$(BINNAME) - $Q rm -f $(DESTDIR)$(INSTALL_PREFIX)/bin/$(CLOUDKMS_BINNAME) - $Q rm -f $(DESTDIR)$(INSTALL_PREFIX)/bin/$(AWSKMS_BINNAME) .PHONY: install uninstall @@ -186,18 +157,6 @@ clean: ifneq ($(BINNAME),"") $Q rm -f bin/$(BINNAME) endif -ifneq ($(CLOUDKMS_BINNAME),"") - $Q rm -f bin/$(CLOUDKMS_BINNAME) -endif -ifneq ($(AWSKMS_BINNAME),"") - $Q rm -f bin/$(AWSKMS_BINNAME) -endif -ifneq ($(YUBIKEY_BINNAME),"") - $Q rm -f bin/$(YUBIKEY_BINNAME) -endif -ifneq ($(PKCS11_BINNAME),"") - $Q rm -f bin/$(PKCS11_BINNAME) -endif .PHONY: clean diff --git a/cmd/step-awskms-init/main.go b/cmd/step-awskms-init/main.go deleted file mode 100644 index 81a91067..00000000 --- a/cmd/step-awskms-init/main.go +++ /dev/null @@ -1,248 +0,0 @@ -package main - -import ( - "context" - "crypto" - "crypto/rand" - "crypto/sha1" //nolint:gosec // used to create the Subject Key Identifier by RFC 5280 - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "flag" - "fmt" - "math/big" - "os" - "time" - - "go.step.sm/cli-utils/fileutil" - "go.step.sm/cli-utils/ui" - "go.step.sm/crypto/kms/apiv1" - "go.step.sm/crypto/kms/awskms" - "go.step.sm/crypto/pemutil" - "golang.org/x/crypto/ssh" -) - -func main() { - var credentialsFile, region string - var enableSSH bool - flag.StringVar(&credentialsFile, "credentials-file", "", "Path to the `file` containing the AWS KMS credentials.") - flag.StringVar(®ion, "region", "", "AWS KMS region name.") - flag.BoolVar(&enableSSH, "ssh", false, "Create SSH keys.") - flag.Usage = usage - flag.Parse() - - // Initialize windows terminal - ui.Init() - - ui.Println("⚠️ This command is deprecated and will be removed in future releases.") - ui.Println("⚠️ Please use https://github.com/smallstep/step-kms-plugin instead.") - - c, err := awskms.New(context.Background(), apiv1.Options{ - Type: apiv1.AmazonKMS, - Region: region, - CredentialsFile: credentialsFile, - }) - if err != nil { - fatal(err) - } - - if err := createX509(c); err != nil { - fatal(err) - } - - if enableSSH { - ui.Println() - if err := createSSH(c); err != nil { - fatal(err) - } - } - - // Reset windows terminal - ui.Reset() -} - -func fatal(err error) { - fmt.Fprintln(os.Stderr, err) - ui.Reset() - os.Exit(1) -} - -func usage() { - fmt.Fprintln(os.Stderr, "Usage: step-awskms-init") - fmt.Fprintln(os.Stderr, ` -The step-awskms-init command initializes a public key infrastructure (PKI) -to be used by step-ca. - -This tool is experimental and in the future it will be integrated in step cli. - -OPTIONS`) - fmt.Fprintln(os.Stderr) - flag.PrintDefaults() - fmt.Fprintf(os.Stderr, ` -COPYRIGHT - - (c) 2018-%d Smallstep Labs, Inc. -`, time.Now().Year()) - os.Exit(1) -} - -func createX509(c *awskms.KMS) error { - ui.Println("Creating X.509 PKI ...") - - // Root Certificate - resp, err := c.CreateKey(&apiv1.CreateKeyRequest{ - Name: "root", - SignatureAlgorithm: apiv1.ECDSAWithSHA256, - }) - if err != nil { - return err - } - - signer, err := c.CreateSigner(&resp.CreateSignerRequest) - if err != nil { - return err - } - - now := time.Now() - root := &x509.Certificate{ - IsCA: true, - NotBefore: now, - NotAfter: now.Add(time.Hour * 24 * 365 * 10), - KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, - BasicConstraintsValid: true, - MaxPathLen: 1, - MaxPathLenZero: false, - Issuer: pkix.Name{CommonName: "Smallstep Root"}, - Subject: pkix.Name{CommonName: "Smallstep Root"}, - SerialNumber: mustSerialNumber(), - SubjectKeyId: mustSubjectKeyID(resp.PublicKey), - AuthorityKeyId: mustSubjectKeyID(resp.PublicKey), - } - - b, err := x509.CreateCertificate(rand.Reader, root, root, resp.PublicKey, signer) - if err != nil { - return err - } - - if err := fileutil.WriteFile("root_ca.crt", pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: b, - }), 0600); err != nil { - return err - } - - ui.PrintSelected("Root Key", resp.Name) - ui.PrintSelected("Root Certificate", "root_ca.crt") - - root, err = pemutil.ReadCertificate("root_ca.crt") - if err != nil { - return err - } - - // Intermediate Certificate - resp, err = c.CreateKey(&apiv1.CreateKeyRequest{ - Name: "intermediate", - SignatureAlgorithm: apiv1.ECDSAWithSHA256, - }) - if err != nil { - return err - } - - intermediate := &x509.Certificate{ - IsCA: true, - NotBefore: now, - NotAfter: now.Add(time.Hour * 24 * 365 * 10), - KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, - BasicConstraintsValid: true, - MaxPathLen: 0, - MaxPathLenZero: true, - Issuer: root.Subject, - Subject: pkix.Name{CommonName: "Smallstep Intermediate"}, - SerialNumber: mustSerialNumber(), - SubjectKeyId: mustSubjectKeyID(resp.PublicKey), - } - - b, err = x509.CreateCertificate(rand.Reader, intermediate, root, resp.PublicKey, signer) - if err != nil { - return err - } - - if err := fileutil.WriteFile("intermediate_ca.crt", pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: b, - }), 0600); err != nil { - return err - } - - ui.PrintSelected("Intermediate Key", resp.Name) - ui.PrintSelected("Intermediate Certificate", "intermediate_ca.crt") - - return nil -} - -func createSSH(c *awskms.KMS) error { - ui.Println("Creating SSH Keys ...") - - // User Key - resp, err := c.CreateKey(&apiv1.CreateKeyRequest{ - Name: "ssh-user-key", - SignatureAlgorithm: apiv1.ECDSAWithSHA256, - }) - if err != nil { - return err - } - - key, err := ssh.NewPublicKey(resp.PublicKey) - if err != nil { - return err - } - - if err := fileutil.WriteFile("ssh_user_ca_key.pub", ssh.MarshalAuthorizedKey(key), 0600); err != nil { - return err - } - - ui.PrintSelected("SSH User Public Key", "ssh_user_ca_key.pub") - ui.PrintSelected("SSH User Private Key", resp.Name) - - // Host Key - resp, err = c.CreateKey(&apiv1.CreateKeyRequest{ - Name: "ssh-host-key", - SignatureAlgorithm: apiv1.ECDSAWithSHA256, - }) - if err != nil { - return err - } - - key, err = ssh.NewPublicKey(resp.PublicKey) - if err != nil { - return err - } - - if err := fileutil.WriteFile("ssh_host_ca_key.pub", ssh.MarshalAuthorizedKey(key), 0600); err != nil { - return err - } - - ui.PrintSelected("SSH Host Public Key", "ssh_host_ca_key.pub") - ui.PrintSelected("SSH Host Private Key", resp.Name) - - return nil -} - -func mustSerialNumber() *big.Int { - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) - sn, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - panic(err) - } - return sn -} - -func mustSubjectKeyID(key crypto.PublicKey) []byte { - b, err := x509.MarshalPKIXPublicKey(key) - if err != nil { - panic(err) - } - //nolint:gosec // used to create the Subject Key Identifier by RFC 5280 - hash := sha1.Sum(b) - return hash[:] -} diff --git a/cmd/step-cloudkms-init/main.go b/cmd/step-cloudkms-init/main.go deleted file mode 100644 index 6cc36adf..00000000 --- a/cmd/step-cloudkms-init/main.go +++ /dev/null @@ -1,286 +0,0 @@ -package main - -import ( - "context" - "crypto" - "crypto/rand" - "crypto/sha1" //nolint:gosec // used to create the Subject Key Identifier by RFC 5280 - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "flag" - "fmt" - "math/big" - "os" - "strings" - "time" - - "go.step.sm/cli-utils/fileutil" - "go.step.sm/cli-utils/ui" - "go.step.sm/crypto/kms/apiv1" - "go.step.sm/crypto/kms/cloudkms" - "go.step.sm/crypto/pemutil" - "golang.org/x/crypto/ssh" -) - -func main() { - var credentialsFile string - var project, location, ring string - var protectionLevelName string - var enableSSH bool - flag.StringVar(&credentialsFile, "credentials-file", "", "Path to the `file` containing the Google's Cloud KMS credentials.") - flag.StringVar(&project, "project", "", "Google Cloud Project ID.") - flag.StringVar(&location, "location", "global", "Cloud KMS location name.") - flag.StringVar(&ring, "ring", "pki", "Cloud KMS ring name.") - flag.StringVar(&protectionLevelName, "protection-level", "SOFTWARE", "Protection level to use, SOFTWARE or HSM.") - flag.BoolVar(&enableSSH, "ssh", false, "Create SSH keys.") - flag.Usage = usage - flag.Parse() - - switch { - case project == "": - usage() - case location == "": - fmt.Fprintln(os.Stderr, "flag `--location` is required") - os.Exit(1) - case ring == "": - fmt.Fprintln(os.Stderr, "flag `--ring` is required") - os.Exit(1) - case protectionLevelName == "": - fmt.Fprintln(os.Stderr, "flag `--protection-level` is required") - os.Exit(1) - } - - var protectionLevel apiv1.ProtectionLevel - switch strings.ToUpper(protectionLevelName) { - case "SOFTWARE": - protectionLevel = apiv1.Software - case "HSM": - protectionLevel = apiv1.HSM - default: - fmt.Fprintf(os.Stderr, "invalid value `%s` for flag `--protection-level`; options are `SOFTWARE` or `HSM`\n", protectionLevelName) - os.Exit(1) - } - - // Initialize windows terminal - ui.Init() - - ui.Println("⚠️ This command is deprecated and will be removed in future releases.") - ui.Println("⚠️ Please use https://github.com/smallstep/step-kms-plugin instead.") - - c, err := cloudkms.New(context.Background(), apiv1.Options{ - Type: apiv1.CloudKMS, - CredentialsFile: credentialsFile, - }) - if err != nil { - fatal(err) - } - - if err := createPKI(c, project, location, ring, protectionLevel); err != nil { - fatal(err) - } - - if enableSSH { - ui.Println() - if err := createSSH(c, project, location, ring, protectionLevel); err != nil { - fatal(err) - } - } - - // Reset windows terminal - ui.Reset() -} - -func fatal(err error) { - fmt.Fprintln(os.Stderr, err) - ui.Reset() - os.Exit(1) -} - -func usage() { - fmt.Fprintln(os.Stderr, "Usage: step-cloudkms-init --project ") - fmt.Fprintln(os.Stderr, ` -The step-cloudkms-init command initializes a public key infrastructure (PKI) -to be used by step-ca. - -This tool is experimental and in the future it will be integrated in step cli. - -OPTIONS`) - fmt.Fprintln(os.Stderr) - flag.PrintDefaults() - fmt.Fprintf(os.Stderr, ` -COPYRIGHT - - (c) 2018-%d Smallstep Labs, Inc. -`, time.Now().Year()) - os.Exit(1) -} - -func createPKI(c *cloudkms.CloudKMS, project, location, keyRing string, protectionLevel apiv1.ProtectionLevel) error { - ui.Println("Creating PKI ...") - - parent := "projects/" + project + "/locations/" + location + "/keyRings/" + keyRing + "/cryptoKeys" - - // Root Certificate - resp, err := c.CreateKey(&apiv1.CreateKeyRequest{ - Name: parent + "/root", - SignatureAlgorithm: apiv1.ECDSAWithSHA256, - ProtectionLevel: protectionLevel, - }) - if err != nil { - return err - } - - signer, err := c.CreateSigner(&resp.CreateSignerRequest) - if err != nil { - return err - } - - now := time.Now() - root := &x509.Certificate{ - IsCA: true, - NotBefore: now, - NotAfter: now.Add(time.Hour * 24 * 365 * 10), - KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, - BasicConstraintsValid: true, - MaxPathLen: 1, - MaxPathLenZero: false, - Issuer: pkix.Name{CommonName: "Smallstep Root"}, - Subject: pkix.Name{CommonName: "Smallstep Root"}, - SerialNumber: mustSerialNumber(), - SubjectKeyId: mustSubjectKeyID(resp.PublicKey), - AuthorityKeyId: mustSubjectKeyID(resp.PublicKey), - } - - b, err := x509.CreateCertificate(rand.Reader, root, root, resp.PublicKey, signer) - if err != nil { - return err - } - - if err := fileutil.WriteFile("root_ca.crt", pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: b, - }), 0600); err != nil { - return err - } - - ui.PrintSelected("Root Key", resp.Name) - ui.PrintSelected("Root Certificate", "root_ca.crt") - - root, err = pemutil.ReadCertificate("root_ca.crt") - if err != nil { - return err - } - - // Intermediate Certificate - resp, err = c.CreateKey(&apiv1.CreateKeyRequest{ - Name: parent + "/intermediate", - SignatureAlgorithm: apiv1.ECDSAWithSHA256, - ProtectionLevel: protectionLevel, - }) - if err != nil { - return err - } - - intermediate := &x509.Certificate{ - IsCA: true, - NotBefore: now, - NotAfter: now.Add(time.Hour * 24 * 365 * 10), - KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, - BasicConstraintsValid: true, - MaxPathLen: 0, - MaxPathLenZero: true, - Issuer: root.Subject, - Subject: pkix.Name{CommonName: "Smallstep Intermediate"}, - SerialNumber: mustSerialNumber(), - SubjectKeyId: mustSubjectKeyID(resp.PublicKey), - } - - b, err = x509.CreateCertificate(rand.Reader, intermediate, root, resp.PublicKey, signer) - if err != nil { - return err - } - - if err := fileutil.WriteFile("intermediate_ca.crt", pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: b, - }), 0600); err != nil { - return err - } - - ui.PrintSelected("Intermediate Key", resp.Name) - ui.PrintSelected("Intermediate Certificate", "intermediate_ca.crt") - - return nil -} - -func createSSH(c *cloudkms.CloudKMS, project, location, keyRing string, protectionLevel apiv1.ProtectionLevel) error { - ui.Println("Creating SSH Keys ...") - - parent := "projects/" + project + "/locations/" + location + "/keyRings/" + keyRing + "/cryptoKeys" - - // User Key - resp, err := c.CreateKey(&apiv1.CreateKeyRequest{ - Name: parent + "/ssh-user-key", - SignatureAlgorithm: apiv1.ECDSAWithSHA256, - ProtectionLevel: protectionLevel, - }) - if err != nil { - return err - } - - key, err := ssh.NewPublicKey(resp.PublicKey) - if err != nil { - return err - } - - if err := fileutil.WriteFile("ssh_user_ca_key.pub", ssh.MarshalAuthorizedKey(key), 0600); err != nil { - return err - } - - ui.PrintSelected("SSH User Public Key", "ssh_user_ca_key.pub") - ui.PrintSelected("SSH User Private Key", resp.Name) - - // Host Key - resp, err = c.CreateKey(&apiv1.CreateKeyRequest{ - Name: parent + "/ssh-host-key", - SignatureAlgorithm: apiv1.ECDSAWithSHA256, - ProtectionLevel: protectionLevel, - }) - if err != nil { - return err - } - - key, err = ssh.NewPublicKey(resp.PublicKey) - if err != nil { - return err - } - - if err := fileutil.WriteFile("ssh_host_ca_key.pub", ssh.MarshalAuthorizedKey(key), 0600); err != nil { - return err - } - - ui.PrintSelected("SSH Host Public Key", "ssh_host_ca_key.pub") - ui.PrintSelected("SSH Host Private Key", resp.Name) - - return nil -} - -func mustSerialNumber() *big.Int { - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) - sn, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - panic(err) - } - return sn -} - -func mustSubjectKeyID(key crypto.PublicKey) []byte { - b, err := x509.MarshalPKIXPublicKey(key) - if err != nil { - panic(err) - } - //nolint:gosec // used to create the Subject Key Identifier by RFC 5280 - hash := sha1.Sum(b) - return hash[:] -} diff --git a/cmd/step-pkcs11-init/main.go b/cmd/step-pkcs11-init/main.go deleted file mode 100644 index 30258cdd..00000000 --- a/cmd/step-pkcs11-init/main.go +++ /dev/null @@ -1,553 +0,0 @@ -package main - -import ( - "context" - "crypto" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/sha1" //nolint:gosec // used to create the Subject Key Identifier by RFC 5280 - "crypto/x509" - "crypto/x509/pkix" - "encoding/pem" - "flag" - "fmt" - "math/big" - "os" - "runtime" - "time" - - "github.com/pkg/errors" - "go.step.sm/cli-utils/fileutil" - "go.step.sm/cli-utils/ui" - "go.step.sm/crypto/kms" - "go.step.sm/crypto/kms/apiv1" - "go.step.sm/crypto/kms/uri" - "go.step.sm/crypto/pemutil" - - // Enable pkcs11. - _ "go.step.sm/crypto/kms/pkcs11" -) - -// Config is a mapping of the cli flags. -type Config struct { - KMS string - GenerateRoot bool - RootObject string - RootKeyObject string - RootSubject string - RootPath string - CrtObject string - CrtPath string - CrtKeyObject string - CrtSubject string - CrtKeyPath string - SSHHostKeyObject string - SSHUserKeyObject string - RootFile string - KeyFile string - Pin string - PinFile string - NoCerts bool - EnableSSH bool - Force bool - Extractable bool -} - -// Validate checks the flags in the config. -func (c *Config) Validate() error { - switch { - case c.KMS == "": - return errors.New("flag `--kms` is required") - case c.CrtPath == "": - return errors.New("flag `--crt-cert-path` is required") - case c.RootFile != "" && c.KeyFile == "": - return errors.New("flag `--root-cert-file` requires flag `--root-key-file`") - case c.KeyFile != "" && c.RootFile == "": - return errors.New("flag `--root-key-file` requires flag `--root-cert-file`") - case c.RootFile == "" && c.RootObject == "": - return errors.New("one of flag `--root-cert-file` or `--root-cert-obj` is required") - case c.KeyFile == "" && c.RootKeyObject == "": - return errors.New("one of flag `--root-key-file` or `--root-key-obj` is required") - case c.CrtKeyPath == "" && c.CrtKeyObject == "": - return errors.New("one of flag `--crt-key-path` or `--crt-key-obj` is required") - case c.RootFile == "" && c.GenerateRoot && c.RootKeyObject == "": - return errors.New("flag `--root-gen` requires flag `--root-key-obj`") - case c.RootFile == "" && c.GenerateRoot && c.RootPath == "": - return errors.New("flag `--root-gen` requires `--root-cert-path`") - case c.Pin != "" && c.PinFile != "": - return errors.New("Only set one of pin and pin-file") - default: - if c.RootFile != "" { - c.GenerateRoot = false - c.RootObject = "" - c.RootKeyObject = "" - } - if c.CrtKeyPath != "" { - c.CrtObject = "" - c.CrtKeyObject = "" - } - if !c.EnableSSH { - c.SSHHostKeyObject = "" - c.SSHUserKeyObject = "" - } - return nil - } -} - -func main() { - var kmsuri string - switch runtime.GOOS { - case "darwin": - kmsuri = "pkcs11:module-path=/usr/local/lib/pkcs11/yubihsm_pkcs11.dylib;token=YubiHSM" - case "linux": - kmsuri = "pkcs11:module-path=/usr/lib/x86_64-linux-gnu/pkcs11/yubihsm_pkcs11.so;token=YubiHSM" - case "windows": - if home, err := os.UserHomeDir(); err == nil { - kmsuri = "pkcs11:module-path=" + home + "\\yubihsm2-sdk\\bin\\yubihsm_pkcs11.dll" + ";token=YubiHSM" - } - } - - var c Config - flag.StringVar(&c.KMS, "kms", kmsuri, "PKCS #11 URI with the module-path and token to connect to the module.") - flag.StringVar(&c.Pin, "pin", "", "PKCS #11 PIN") - flag.StringVar(&c.PinFile, "pin-file", "", "PKCS #11 PIN File") - // Option 1: Generate new root - flag.BoolVar(&c.GenerateRoot, "root-gen", true, "Enable the generation of a root key.") - flag.StringVar(&c.RootSubject, "root-name", "PKCS #11 Smallstep Root", "Subject and Issuer of the root certificate.") - flag.StringVar(&c.RootObject, "root-cert-obj", "pkcs11:id=7330;object=root-cert", "PKCS #11 URI with object id and label to store the root certificate.") - flag.StringVar(&c.RootKeyObject, "root-key-obj", "pkcs11:id=7330;object=root-key", "PKCS #11 URI with object id and label to store the root key.") - // Option 2: Read root from disk and sign intermediate - flag.StringVar(&c.RootFile, "root-cert-file", "", "Path to the root certificate to use.") - flag.StringVar(&c.KeyFile, "root-key-file", "", "Path to the root key to use.") - // Option 3: Generate certificate signing request - flag.StringVar(&c.CrtSubject, "crt-name", "PKCS #11 Smallstep Intermediate", "Subject of the intermediate certificate.") - flag.StringVar(&c.CrtObject, "crt-cert-obj", "pkcs11:id=7331;object=intermediate-cert", "PKCS #11 URI with object id and label to store the intermediate certificate.") - flag.StringVar(&c.CrtKeyObject, "crt-key-obj", "pkcs11:id=7331;object=intermediate-key", "PKCS #11 URI with object id and label to store the intermediate certificate.") - // SSH certificates - flag.BoolVar(&c.EnableSSH, "ssh", false, "Enable the creation of ssh keys.") - flag.StringVar(&c.SSHHostKeyObject, "ssh-host-key", "pkcs11:id=7332;object=ssh-host-key", "PKCS #11 URI with object id and label to store the key used to sign SSH host certificates.") - flag.StringVar(&c.SSHUserKeyObject, "ssh-user-key", "pkcs11:id=7333;object=ssh-user-key", "PKCS #11 URI with object id and label to store the key used to sign SSH user certificates.") - // Output files - flag.StringVar(&c.RootPath, "root-cert-path", "root_ca.crt", "Location to write the root certificate.") - flag.StringVar(&c.CrtPath, "crt-cert-path", "intermediate_ca.crt", "Location to write the intermediate certificate.") - flag.StringVar(&c.CrtKeyPath, "crt-key-path", "", "Location to write the intermediate private key.") - // Others - flag.BoolVar(&c.NoCerts, "no-certs", false, "Do not store certificates in the module.") - flag.BoolVar(&c.Force, "force", false, "Force the delete of previous keys.") - flag.BoolVar(&c.Extractable, "extractable", false, "Allow export of private keys under wrap.") - flag.Usage = usage - flag.Parse() - - if err := c.Validate(); err != nil { - fatal(err) - } - - u, err := uri.ParseWithScheme("pkcs11", c.KMS) - if err != nil { - fatal(err) - } - - // Initialize windows terminal - ui.Init() - - ui.Println("⚠️ This command is deprecated and will be removed in future releases.") - ui.Println("⚠️ Please use https://github.com/smallstep/step-kms-plugin instead.") - - switch { - case u.Get("pin-value") != "": - case u.Get("pin-source") != "": - case c.Pin != "": - case c.PinFile != "": - content, err := os.ReadFile(c.PinFile) - if err != nil { - fatal(err) - } - c.Pin = string(content) - - default: - pin, err := ui.PromptPassword("What is the PKCS#11 PIN?") - if err != nil { - fatal(err) - } - c.Pin = string(pin) - } - - k, err := kms.New(context.Background(), apiv1.Options{ - Type: apiv1.PKCS11, - URI: c.KMS, - Pin: c.Pin, - }) - if err != nil { - fatal(err) - } - - defer func() { - _ = k.Close() - }() - - // Check if the slots are empty, fail if they are not - certUris := []string{ - c.RootObject, c.CrtObject, - } - keyUris := []string{ - c.RootKeyObject, c.CrtKeyObject, - c.SSHHostKeyObject, c.SSHUserKeyObject, - } - if !c.Force { - for _, u := range certUris { - if u != "" && !c.NoCerts { - checkObject(k, u) - checkCertificate(k, u) - } - } - for _, u := range keyUris { - if u != "" { - checkObject(k, u) - } - } - } else { - deleter, ok := k.(interface { - DeleteKey(uri string) error - DeleteCertificate(uri string) error - }) - if ok { - for _, u := range certUris { - if u != "" && !c.NoCerts { - // Some HSMs like Nitrokey will overwrite the key with the - // certificate label. - if err := deleter.DeleteKey(u); err != nil { - fatalClose(err, k) - } - if err := deleter.DeleteCertificate(u); err != nil { - fatalClose(err, k) - } - } - } - for _, u := range keyUris { - if u != "" { - if err := deleter.DeleteKey(u); err != nil { - fatalClose(err, k) - } - } - } - } - } - - if err := createPKI(k, c); err != nil { - fatalClose(err, k) - } - - // Reset windows terminal - ui.Reset() -} - -func fatal(err error) { - if os.Getenv("STEPDEBUG") == "1" { - fmt.Fprintf(os.Stderr, "%+v\n", err) - } else { - fmt.Fprintln(os.Stderr, err) - } - ui.Reset() - os.Exit(1) -} - -func fatalClose(err error, k kms.KeyManager) { - _ = k.Close() - fatal(err) -} - -func usage() { - fmt.Fprintln(os.Stderr, "Usage: step-pkcs11-init") - fmt.Fprintln(os.Stderr, ` -The step-pkcs11-init command initializes a public key infrastructure (PKI) -to be used by step-ca. - -This tool is experimental and in the future it will be integrated in step cli. - -OPTIONS`) - fmt.Fprintln(os.Stderr) - flag.PrintDefaults() - fmt.Fprintf(os.Stderr, ` -COPYRIGHT - - (c) 2018-%d Smallstep Labs, Inc. -`, time.Now().Year()) - os.Exit(1) -} - -func checkCertificate(k kms.KeyManager, rawuri string) { - if cm, ok := k.(kms.CertificateManager); ok { - if _, err := cm.LoadCertificate(&apiv1.LoadCertificateRequest{ - Name: rawuri, - }); err == nil { - fmt.Fprintf(os.Stderr, "⚠️ Your PKCS #11 module already has a certificate on %s.\n", rawuri) - fmt.Fprintln(os.Stderr, " If you want to delete it and start fresh, use `--force`.") - _ = k.Close() - os.Exit(1) - } - } -} - -func checkObject(k kms.KeyManager, rawuri string) { - if _, err := k.GetPublicKey(&apiv1.GetPublicKeyRequest{ - Name: rawuri, - }); err == nil { - fmt.Fprintf(os.Stderr, "⚠️ Your PKCS #11 module already has a key on %s.\n", rawuri) - fmt.Fprintln(os.Stderr, " If you want to delete it and start fresh, use `--force`.") - _ = k.Close() - os.Exit(1) - } -} - -func createPKI(k kms.KeyManager, c Config) error { - var err error - ui.Println("Creating PKI ...") - now := time.Now() - - // Root Certificate - var signer crypto.Signer - var root *x509.Certificate - switch { - case c.GenerateRoot: - resp, err := k.CreateKey(&apiv1.CreateKeyRequest{ - Name: c.RootKeyObject, - SignatureAlgorithm: apiv1.ECDSAWithSHA256, - Extractable: c.Extractable, - }) - if err != nil { - return err - } - - signer, err = k.CreateSigner(&resp.CreateSignerRequest) - if err != nil { - return err - } - - template := &x509.Certificate{ - IsCA: true, - NotBefore: now, - NotAfter: now.Add(time.Hour * 24 * 365 * 10), - KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, - BasicConstraintsValid: true, - MaxPathLen: 1, - MaxPathLenZero: false, - Issuer: pkix.Name{CommonName: c.RootSubject}, - Subject: pkix.Name{CommonName: c.RootSubject}, - SerialNumber: mustSerialNumber(), - SubjectKeyId: mustSubjectKeyID(resp.PublicKey), - AuthorityKeyId: mustSubjectKeyID(resp.PublicKey), - } - - b, err := x509.CreateCertificate(rand.Reader, template, template, resp.PublicKey, signer) - if err != nil { - return err - } - - root, err = x509.ParseCertificate(b) - if err != nil { - return errors.Wrap(err, "error parsing root certificate") - } - - if cm, ok := k.(kms.CertificateManager); ok && c.RootObject != "" && !c.NoCerts { - if err := cm.StoreCertificate(&apiv1.StoreCertificateRequest{ - Name: c.RootObject, - Certificate: root, - Extractable: c.Extractable, - }); err != nil { - return err - } - } else { - c.RootObject = "" - } - - if err := fileutil.WriteFile(c.RootPath, pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: b, - }), 0600); err != nil { - return err - } - - ui.PrintSelected("Root Key", resp.Name) - ui.PrintSelected("Root Certificate", c.RootPath) - if c.RootObject != "" { - ui.PrintSelected("Root Certificate Object", c.RootObject) - } - case c.RootFile != "" && c.KeyFile != "": // Read Root From File - root, err = pemutil.ReadCertificate(c.RootFile) - if err != nil { - return err - } - - key, err := pemutil.Read(c.KeyFile) - if err != nil { - return err - } - - var ok bool - if signer, ok = key.(crypto.Signer); !ok { - return errors.Errorf("key type '%T' does not implement a signer", key) - } - } - - // Intermediate Certificate - var keyName string - var publicKey crypto.PublicKey - var intSigner crypto.Signer - if c.CrtKeyPath != "" { - priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - return errors.Wrap(err, "error creating intermediate key") - } - - pass, err := ui.PromptPasswordGenerate("What do you want your password to be? [leave empty and we'll generate one]", - ui.WithRichPrompt()) - if err != nil { - return err - } - - _, err = pemutil.Serialize(priv, pemutil.WithPassword(pass), pemutil.ToFile(c.CrtKeyPath, 0600)) - if err != nil { - return err - } - - publicKey = priv.Public() - intSigner = priv - } else { - resp, err := k.CreateKey(&apiv1.CreateKeyRequest{ - Name: c.CrtKeyObject, - SignatureAlgorithm: apiv1.ECDSAWithSHA256, - Extractable: c.Extractable, - }) - if err != nil { - return err - } - publicKey = resp.PublicKey - keyName = resp.Name - - intSigner, err = k.CreateSigner(&resp.CreateSignerRequest) - if err != nil { - return err - } - } - - if root != nil { - template := &x509.Certificate{ - IsCA: true, - NotBefore: now, - NotAfter: now.Add(time.Hour * 24 * 365 * 10), - KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, - BasicConstraintsValid: true, - MaxPathLen: 0, - MaxPathLenZero: true, - Issuer: root.Subject, - Subject: pkix.Name{CommonName: c.CrtSubject}, - SerialNumber: mustSerialNumber(), - SubjectKeyId: mustSubjectKeyID(publicKey), - } - - b, err := x509.CreateCertificate(rand.Reader, template, root, publicKey, signer) - if err != nil { - return err - } - - intermediate, err := x509.ParseCertificate(b) - if err != nil { - return errors.Wrap(err, "error parsing intermediate certificate") - } - - if cm, ok := k.(kms.CertificateManager); ok && c.CrtObject != "" && !c.NoCerts { - if err := cm.StoreCertificate(&apiv1.StoreCertificateRequest{ - Name: c.CrtObject, - Certificate: intermediate, - Extractable: c.Extractable, - }); err != nil { - return err - } - } else { - c.CrtObject = "" - } - - if err := fileutil.WriteFile(c.CrtPath, pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: b, - }), 0600); err != nil { - return err - } - } else { - // No root available, generate CSR for external root. - csrTemplate := x509.CertificateRequest{ - Subject: pkix.Name{CommonName: c.CrtSubject}, - SignatureAlgorithm: x509.ECDSAWithSHA256, - } - // step: generate the csr request - csrCertificate, err := x509.CreateCertificateRequest(rand.Reader, &csrTemplate, intSigner) - if err != nil { - return err - } - if err := fileutil.WriteFile(c.CrtPath, pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE REQUEST", - Bytes: csrCertificate, - }), 0600); err != nil { - return err - } - } - - if c.CrtKeyPath != "" { - ui.PrintSelected("Intermediate Key", c.CrtKeyPath) - } else { - ui.PrintSelected("Intermediate Key", keyName) - } - - if root != nil { - ui.PrintSelected("Intermediate Certificate", c.CrtPath) - if c.CrtObject != "" { - ui.PrintSelected("Intermediate Certificate Object", c.CrtObject) - } - } else { - ui.PrintSelected("Intermediate Certificate Request", c.CrtPath) - } - - if c.SSHHostKeyObject != "" { - resp, err := k.CreateKey(&apiv1.CreateKeyRequest{ - Name: c.SSHHostKeyObject, - SignatureAlgorithm: apiv1.ECDSAWithSHA256, - }) - if err != nil { - return err - } - ui.PrintSelected("SSH Host Key", resp.Name) - } - - if c.SSHUserKeyObject != "" { - resp, err := k.CreateKey(&apiv1.CreateKeyRequest{ - Name: c.SSHUserKeyObject, - SignatureAlgorithm: apiv1.ECDSAWithSHA256, - }) - if err != nil { - return err - } - ui.PrintSelected("SSH User Key", resp.Name) - } - - return nil -} - -func mustSerialNumber() *big.Int { - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) - sn, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - panic(err) - } - return sn -} - -func mustSubjectKeyID(key crypto.PublicKey) []byte { - b, err := x509.MarshalPKIXPublicKey(key) - if err != nil { - panic(err) - } - //nolint:gosec // used to create the Subject Key Identifier by RFC 5280 - hash := sha1.Sum(b) - return hash[:] -} diff --git a/cmd/step-yubikey-init/main.go b/cmd/step-yubikey-init/main.go deleted file mode 100644 index cd6018cf..00000000 --- a/cmd/step-yubikey-init/main.go +++ /dev/null @@ -1,355 +0,0 @@ -package main - -import ( - "context" - "crypto" - "crypto/ecdsa" - "crypto/elliptic" - "crypto/rand" - "crypto/sha1" //nolint:gosec // used to create the Subject Key Identifier by RFC 5280 - "crypto/x509" - "crypto/x509/pkix" - "encoding/hex" - "encoding/pem" - "flag" - "fmt" - "math/big" - "os" - "time" - - "github.com/pkg/errors" - "go.step.sm/cli-utils/fileutil" - "go.step.sm/cli-utils/ui" - "go.step.sm/crypto/kms" - "go.step.sm/crypto/kms/apiv1" - "go.step.sm/crypto/pemutil" - - // Enable yubikey. - _ "go.step.sm/crypto/kms/yubikey" -) - -// Config is a mapping of the cli flags. -type Config struct { - RootOnly bool - RootSlot string - CrtSlot string - RootFile string - KeyFile string - Pin string - ManagementKey string - Force bool -} - -// Validate checks the flags in the config. -func (c *Config) Validate() error { - switch { - case c.ManagementKey != "" && len(c.ManagementKey) != 48: - return errors.New("flag `--management-key` must be 48 hexadecimal characters (24 bytes)") - case c.RootFile != "" && c.KeyFile == "": - return errors.New("flag `--root` requires flag `--key`") - case c.KeyFile != "" && c.RootFile == "": - return errors.New("flag `--key` requires flag `--root`") - case c.RootOnly && c.RootFile != "": - return errors.New("flag `--root-only` is incompatible with flag `--root`") - case c.RootSlot == c.CrtSlot: - return errors.New("flag `--root-slot` and flag `--crt-slot` cannot be the same") - case c.RootFile == "" && c.RootSlot == "": - return errors.New("one of flag `--root` or `--root-slot` is required") - default: - if c.RootFile != "" { - c.RootSlot = "" - } - if c.RootOnly { - c.CrtSlot = "" - } - if c.ManagementKey != "" { - if _, err := hex.DecodeString(c.ManagementKey); err != nil { - return errors.Wrap(err, "flag `--management-key` is not valid") - } - } - return nil - } -} - -func main() { - var c Config - flag.StringVar(&c.ManagementKey, "management-key", "", `Management key to use in hexadecimal format. (default "010203040506070801020304050607080102030405060708")`) - flag.BoolVar(&c.RootOnly, "root-only", false, "Slot only the root certificate and sign and intermediate.") - flag.StringVar(&c.RootSlot, "root-slot", "9a", "Slot to store the root certificate.") - flag.StringVar(&c.CrtSlot, "crt-slot", "9c", "Slot to store the intermediate certificate.") - flag.StringVar(&c.RootFile, "root", "", "Path to the root certificate to use.") - flag.StringVar(&c.KeyFile, "key", "", "Path to the root key to use.") - flag.BoolVar(&c.Force, "force", false, "Force the delete of previous keys.") - flag.Usage = usage - flag.Parse() - - if err := c.Validate(); err != nil { - fatal(err) - } - - // Initialize windows terminal - ui.Init() - - ui.Println("⚠️ This command is deprecated and will be removed in future releases.") - ui.Println("⚠️ Please use https://github.com/smallstep/step-kms-plugin instead.") - - pin, err := ui.PromptPassword("What is the YubiKey PIN?") - if err != nil { - fatal(err) - } - c.Pin = string(pin) - - k, err := kms.New(context.Background(), apiv1.Options{ - Type: apiv1.YubiKey, - Pin: c.Pin, - ManagementKey: c.ManagementKey, - }) - if err != nil { - fatal(err) - } - - // Check if the slots are empty, fail if they are not - if !c.Force { - switch { - case c.RootSlot != "": - checkSlot(k, c.RootSlot) - case c.CrtSlot != "": - checkSlot(k, c.CrtSlot) - } - } - - if err := createPKI(k, c); err != nil { - fatal(err) - } - - defer func() { - _ = k.Close() - }() - - // Reset windows terminal - ui.Reset() -} - -func fatal(err error) { - if os.Getenv("STEPDEBUG") == "1" { - fmt.Fprintf(os.Stderr, "%+v\n", err) - } else { - fmt.Fprintln(os.Stderr, err) - } - ui.Reset() - os.Exit(1) -} - -func usage() { - fmt.Fprintln(os.Stderr, "Usage: step-yubikey-init") - fmt.Fprintln(os.Stderr, ` -The step-yubikey-init command initializes a public key infrastructure (PKI) -to be used by step-ca. - -This tool is experimental and in the future it will be integrated in step cli. - -OPTIONS`) - fmt.Fprintln(os.Stderr) - flag.PrintDefaults() - fmt.Fprintf(os.Stderr, ` -COPYRIGHT - - (c) 2018-%d Smallstep Labs, Inc. -`, time.Now().Year()) - os.Exit(1) -} - -func checkSlot(k kms.KeyManager, slot string) { - if _, err := k.GetPublicKey(&apiv1.GetPublicKeyRequest{ - Name: slot, - }); err == nil { - fmt.Fprintf(os.Stderr, "⚠️ Your YubiKey already has a key in the slot %s.\n", slot) - fmt.Fprintln(os.Stderr, " If you want to delete it and start fresh, use `--force`.") - os.Exit(1) - } -} - -func createPKI(k kms.KeyManager, c Config) error { - var err error - ui.Println("Creating PKI ...") - now := time.Now() - - // Root Certificate - var signer crypto.Signer - var root *x509.Certificate - if c.RootFile != "" && c.KeyFile != "" { - root, err = pemutil.ReadCertificate(c.RootFile) - if err != nil { - return err - } - - key, err := pemutil.Read(c.KeyFile) - if err != nil { - return err - } - - var ok bool - if signer, ok = key.(crypto.Signer); !ok { - return errors.Errorf("key type '%T' does not implement a signer", key) - } - } else { - resp, err := k.CreateKey(&apiv1.CreateKeyRequest{ - Name: c.RootSlot, - SignatureAlgorithm: apiv1.ECDSAWithSHA256, - }) - if err != nil { - return err - } - - signer, err = k.CreateSigner(&resp.CreateSignerRequest) - if err != nil { - return err - } - - template := &x509.Certificate{ - IsCA: true, - NotBefore: now, - NotAfter: now.Add(time.Hour * 24 * 365 * 10), - KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, - BasicConstraintsValid: true, - MaxPathLen: 1, - MaxPathLenZero: false, - Issuer: pkix.Name{CommonName: "YubiKey Smallstep Root"}, - Subject: pkix.Name{CommonName: "YubiKey Smallstep Root"}, - SerialNumber: mustSerialNumber(), - SubjectKeyId: mustSubjectKeyID(resp.PublicKey), - AuthorityKeyId: mustSubjectKeyID(resp.PublicKey), - } - - b, err := x509.CreateCertificate(rand.Reader, template, template, resp.PublicKey, signer) - if err != nil { - return err - } - - root, err = x509.ParseCertificate(b) - if err != nil { - return errors.Wrap(err, "error parsing root certificate") - } - - if cm, ok := k.(kms.CertificateManager); ok { - if err := cm.StoreCertificate(&apiv1.StoreCertificateRequest{ - Name: c.RootSlot, - Certificate: root, - }); err != nil { - return err - } - } - - if err := fileutil.WriteFile("root_ca.crt", pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: b, - }), 0600); err != nil { - return err - } - - ui.PrintSelected("Root Key", resp.Name) - ui.PrintSelected("Root Certificate", "root_ca.crt") - } - - // Intermediate Certificate - var keyName string - var publicKey crypto.PublicKey - if c.RootOnly { - priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) - if err != nil { - return errors.Wrap(err, "error creating intermediate key") - } - - pass, err := ui.PromptPasswordGenerate("What do you want your password to be? [leave empty and we'll generate one]", - ui.WithRichPrompt()) - if err != nil { - return err - } - - _, err = pemutil.Serialize(priv, pemutil.WithPassword(pass), pemutil.ToFile("intermediate_ca_key", 0600)) - if err != nil { - return err - } - - publicKey = priv.Public() - } else { - resp, err := k.CreateKey(&apiv1.CreateKeyRequest{ - Name: c.CrtSlot, - SignatureAlgorithm: apiv1.ECDSAWithSHA256, - }) - if err != nil { - return err - } - publicKey = resp.PublicKey - keyName = resp.Name - } - - template := &x509.Certificate{ - IsCA: true, - NotBefore: now, - NotAfter: now.Add(time.Hour * 24 * 365 * 10), - KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageCRLSign, - BasicConstraintsValid: true, - MaxPathLen: 0, - MaxPathLenZero: true, - Issuer: root.Subject, - Subject: pkix.Name{CommonName: "YubiKey Smallstep Intermediate"}, - SerialNumber: mustSerialNumber(), - SubjectKeyId: mustSubjectKeyID(publicKey), - } - - b, err := x509.CreateCertificate(rand.Reader, template, root, publicKey, signer) - if err != nil { - return err - } - - intermediate, err := x509.ParseCertificate(b) - if err != nil { - return errors.Wrap(err, "error parsing intermediate certificate") - } - - if cm, ok := k.(kms.CertificateManager); ok { - if err := cm.StoreCertificate(&apiv1.StoreCertificateRequest{ - Name: c.CrtSlot, - Certificate: intermediate, - }); err != nil { - return err - } - } - - if err := fileutil.WriteFile("intermediate_ca.crt", pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: b, - }), 0600); err != nil { - return err - } - - if c.RootOnly { - ui.PrintSelected("Intermediate Key", "intermediate_ca_key") - } else { - ui.PrintSelected("Intermediate Key", keyName) - } - - ui.PrintSelected("Intermediate Certificate", "intermediate_ca.crt") - - return nil -} - -func mustSerialNumber() *big.Int { - serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128) - sn, err := rand.Int(rand.Reader, serialNumberLimit) - if err != nil { - panic(err) - } - return sn -} - -func mustSubjectKeyID(key crypto.PublicKey) []byte { - b, err := x509.MarshalPKIXPublicKey(key) - if err != nil { - panic(err) - } - //nolint:gosec // used to create the Subject Key Identifier by RFC 5280 - hash := sha1.Sum(b) - return hash[:] -} diff --git a/docker/Dockerfile.step-ca b/docker/Dockerfile.step-ca index 8cf918df..69ab449e 100644 --- a/docker/Dockerfile.step-ca +++ b/docker/Dockerfile.step-ca @@ -5,13 +5,11 @@ COPY . . RUN apk add --no-cache curl git make RUN make V=1 download -RUN make V=1 bin/step-ca bin/step-awskms-init bin/step-cloudkms-init +RUN make V=1 bin/step-ca FROM smallstep/step-cli:latest COPY --from=builder /src/bin/step-ca /usr/local/bin/step-ca -COPY --from=builder /src/bin/step-awskms-init /usr/local/bin/step-awskms-init -COPY --from=builder /src/bin/step-cloudkms-init /usr/local/bin/step-cloudkms-init USER root RUN apk add --no-cache libcap && setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/step-ca diff --git a/docker/Dockerfile.step-ca.hsm b/docker/Dockerfile.step-ca.hsm index 8f413cd7..e97b707a 100644 --- a/docker/Dockerfile.step-ca.hsm +++ b/docker/Dockerfile.step-ca.hsm @@ -8,14 +8,9 @@ RUN apk add --no-cache gcc musl-dev pkgconf pcsc-lite-dev RUN make V=1 download RUN make V=1 GOFLAGS="" build - FROM smallstep/step-cli:latest COPY --from=builder /src/bin/step-ca /usr/local/bin/step-ca -COPY --from=builder /src/bin/step-awskms-init /usr/local/bin/step-awskms-init -COPY --from=builder /src/bin/step-cloudkms-init /usr/local/bin/step-cloudkms-init -COPY --from=builder /src/bin/step-pkcs11-init /usr/local/bin/step-pkcs11-init -COPY --from=builder /src/bin/step-yubikey-init /usr/local/bin/step-yubikey-init USER root RUN apk add --no-cache libcap && setcap CAP_NET_BIND_SERVICE=+eip /usr/local/bin/step-ca