From 29f5a35965c6b838a7c4eeb416507166e8f499e0 Mon Sep 17 00:00:00 2001 From: Gary Belvin Date: Fri, 12 Nov 2021 13:00:32 -0500 Subject: [PATCH 1/3] simplify flags --- cmd/step-pkcs11-init/main.go | 65 +++++++++++++++++++----------------- 1 file changed, 34 insertions(+), 31 deletions(-) diff --git a/cmd/step-pkcs11-init/main.go b/cmd/step-pkcs11-init/main.go index 0db1e4d9..53d27208 100644 --- a/cmd/step-pkcs11-init/main.go +++ b/cmd/step-pkcs11-init/main.go @@ -32,7 +32,7 @@ import ( // Config is a mapping of the cli flags. type Config struct { KMS string - RootOnly bool + GenerateRoot bool RootObject string RootKeyObject string RootSubject string @@ -59,11 +59,9 @@ func (c *Config) Validate() error { case c.KMS == "": return errors.New("flag `--kms` is required") case c.RootFile != "" && c.KeyFile == "": - return errors.New("flag `--root` requires flag `--key`") + return errors.New("flag `--root-cert-file` 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`") + return errors.New("flag `--key` requires flag `--root-cert-file`") case c.RootFile == "" && c.RootObject == "": return errors.New("one of flag `--root` or `--root-cert` is required") case c.RootFile == "" && c.RootKeyObject == "": @@ -73,7 +71,7 @@ func (c *Config) Validate() error { c.RootObject = "" c.RootKeyObject = "" } - if c.RootOnly { + if c.CrtKeyPath != "" { c.CrtObject = "" c.CrtKeyObject = "" } @@ -101,20 +99,24 @@ func main() { 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.RootObject, "root-cert", "pkcs11:id=7330;object=root-cert", "PKCS #11 URI with object id and label to store the root certificate.") - flag.StringVar(&c.RootPath, "root-cert-path", "root_ca.crt", "Location to write the root certificate.") - flag.StringVar(&c.RootKeyObject, "root-key", "pkcs11:id=7330;object=root-key", "PKCS #11 URI with object id and label to store the root key.") + // Option 1: Generate new root + flag.BoolVar(&c.GenerateRoot, "root-gen", true, "Enable the generation of a root key.") + flag.StringVar(&c.RootFile, "root-cert-file", "", "Path to the root certificate to use.") + 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.") flag.StringVar(&c.RootSubject, "root-name", "PKCS #11 Smallstep Root", "Subject and Issuer of the root certificate.") + // Option 2: Read root from disk and sign intermediate + flag.StringVar(&c.RootPath, "root-cert-path", "root_ca.crt", "Location to write the root certificate.") + flag.StringVar(&c.KeyFile, "root-key-file", "", "Path to the root key to use.") + // Option 3: Generate certificate signing request flag.StringVar(&c.CrtObject, "crt-cert", "pkcs11:id=7331;object=intermediate-cert", "PKCS #11 URI with object id and label to store the intermediate certificate.") flag.StringVar(&c.CrtPath, "crt-cert-path", "intermediate_ca.crt", "Location to write the intermediate certificate.") flag.StringVar(&c.CrtKeyObject, "crt-key", "pkcs11:id=7331;object=intermediate-key", "PKCS #11 URI with object id and label to store the intermediate certificate.") flag.StringVar(&c.CrtSubject, "crt-name", "PKCS #11 Smallstep Intermediate", "Subject of the intermediate certificate.") - flag.StringVar(&c.CrtKeyPath, "crt-key-path", "intermediate_ca_key", "Location to write the intermediate private key.") + flag.StringVar(&c.CrtKeyPath, "crt-key-path", "", "Location to write the intermediate private key.") 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.") - flag.BoolVar(&c.RootOnly, "root-only", false, "Store only only the root certificate and sign and intermediate.") - 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.EnableSSH, "ssh", false, "Enable the creation of ssh keys.") 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.") @@ -276,22 +278,8 @@ func createPKI(k kms.KeyManager, c Config) error { // 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 { + switch { + case c.GenerateRoot: resp, err := k.CreateKey(&apiv1.CreateKeyRequest{ Name: c.RootKeyObject, SignatureAlgorithm: apiv1.ECDSAWithSHA256, @@ -350,12 +338,27 @@ func createPKI(k kms.KeyManager, c Config) error { ui.PrintSelected("Root Key", resp.Name) ui.PrintSelected("Root Certificate", c.RootPath) + 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 - if c.RootOnly { + if c.CrtKeyPath != "" { priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) if err != nil { return errors.Wrap(err, "error creating intermediate key") @@ -427,7 +430,7 @@ func createPKI(k kms.KeyManager, c Config) error { return err } - if c.RootOnly { + if c.CrtKeyPath != "" { ui.PrintSelected("Intermediate Key", c.CrtKeyPath) } else { ui.PrintSelected("Intermediate Key", keyName) From bbb327c8c526aaf3b16fb595975c53774c1c5d84 Mon Sep 17 00:00:00 2001 From: Gary Belvin Date: Fri, 12 Nov 2021 14:09:17 -0500 Subject: [PATCH 2/3] Make a csr if there's not a root --- cmd/step-pkcs11-init/main.go | 93 +++++++++++++++++++++++------------- 1 file changed, 59 insertions(+), 34 deletions(-) diff --git a/cmd/step-pkcs11-init/main.go b/cmd/step-pkcs11-init/main.go index 53d27208..613b8208 100644 --- a/cmd/step-pkcs11-init/main.go +++ b/cmd/step-pkcs11-init/main.go @@ -358,6 +358,7 @@ func createPKI(k kms.KeyManager, c Config) error { // 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 { @@ -376,6 +377,7 @@ func createPKI(k kms.KeyManager, c Config) error { } publicKey = priv.Public() + intSigner = priv } else { resp, err := k.CreateKey(&apiv1.CreateKeyRequest{ Name: c.CrtKeyObject, @@ -387,47 +389,70 @@ func createPKI(k kms.KeyManager, c Config) error { } 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: c.CrtSubject}, - SerialNumber: mustSerialNumber(), - SubjectKeyId: mustSubjectKeyID(publicKey), - } - b, err := x509.CreateCertificate(rand.Reader, template, root, publicKey, signer) - if err != nil { - return err + intSigner, err = k.CreateSigner(&resp.CreateSignerRequest) + if err != nil { + return err + } } - intermediate, err := x509.ParseCertificate(b) - if err != nil { - return errors.Wrap(err, "error parsing intermediate certificate") - } + 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), + } - if cm, ok := k.(kms.CertificateManager); ok && !c.NoCerts { - if err := cm.StoreCertificate(&apiv1.StoreCertificateRequest{ - Name: c.CrtObject, - Certificate: intermediate, - Extractable: c.Extractable, - }); err != nil { + b, err := x509.CreateCertificate(rand.Reader, template, root, publicKey, signer) + if err != nil { return err } - } - if err := fileutil.WriteFile(c.CrtPath, pem.EncodeToMemory(&pem.Block{ - Type: "CERTIFICATE", - Bytes: b, - }), 0600); 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.NoCerts { + if err := cm.StoreCertificate(&apiv1.StoreCertificateRequest{ + Name: c.CrtObject, + Certificate: intermediate, + Extractable: c.Extractable, + }); err != nil { + return err + } + } + + 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 != "" { From febb6198823b070f1d26e9e8c6207b4a1c5a8d97 Mon Sep 17 00:00:00 2001 From: Mariano Cano Date: Wed, 17 Nov 2021 15:48:52 -0800 Subject: [PATCH 3/3] Add some extra validation and print certificate objects This commit also changes the following flags for consistency: - --crt-cert to --crt-cert-obj - --crt-key to --crt-key-obj --- cmd/step-pkcs11-init/main.go | 62 +++++++++++++++++++++++++----------- 1 file changed, 44 insertions(+), 18 deletions(-) diff --git a/cmd/step-pkcs11-init/main.go b/cmd/step-pkcs11-init/main.go index 613b8208..5fadf10d 100644 --- a/cmd/step-pkcs11-init/main.go +++ b/cmd/step-pkcs11-init/main.go @@ -58,16 +58,25 @@ 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 `--key`") + return errors.New("flag `--root-cert-file` requires flag `--root-key-file`") case c.KeyFile != "" && c.RootFile == "": - return errors.New("flag `--key` requires flag `--root-cert-file`") + return errors.New("flag `--root-key-file` requires flag `--root-cert-file`") case c.RootFile == "" && c.RootObject == "": - return errors.New("one of flag `--root` or `--root-cert` is required") - case c.RootFile == "" && c.RootKeyObject == "": - return errors.New("one of flag `--root` or `--root-key` is required") + 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`") default: if c.RootFile != "" { + c.GenerateRoot = false c.RootObject = "" c.RootKeyObject = "" } @@ -101,23 +110,25 @@ func main() { flag.StringVar(&c.Pin, "pin", "", "PKCS #11 PIN") // Option 1: Generate new root flag.BoolVar(&c.GenerateRoot, "root-gen", true, "Enable the generation of a root key.") - flag.StringVar(&c.RootFile, "root-cert-file", "", "Path to the root certificate to use.") + 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.") - flag.StringVar(&c.RootSubject, "root-name", "PKCS #11 Smallstep Root", "Subject and Issuer of the root certificate.") // Option 2: Read root from disk and sign intermediate - flag.StringVar(&c.RootPath, "root-cert-path", "root_ca.crt", "Location to write the root certificate.") + 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.CrtObject, "crt-cert", "pkcs11:id=7331;object=intermediate-cert", "PKCS #11 URI with object id and label to store the intermediate certificate.") - flag.StringVar(&c.CrtPath, "crt-cert-path", "intermediate_ca.crt", "Location to write the intermediate certificate.") - flag.StringVar(&c.CrtKeyObject, "crt-key", "pkcs11:id=7331;object=intermediate-key", "PKCS #11 URI with object id and label to store the intermediate certificate.") flag.StringVar(&c.CrtSubject, "crt-name", "PKCS #11 Smallstep Intermediate", "Subject of the intermediate certificate.") - flag.StringVar(&c.CrtKeyPath, "crt-key-path", "", "Location to write the intermediate private key.") + 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.") - - flag.BoolVar(&c.EnableSSH, "ssh", false, "Enable the creation of ssh keys.") + // 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.") @@ -319,7 +330,7 @@ func createPKI(k kms.KeyManager, c Config) error { return errors.Wrap(err, "error parsing root certificate") } - if cm, ok := k.(kms.CertificateManager); ok && !c.NoCerts { + if cm, ok := k.(kms.CertificateManager); ok && c.RootObject != "" && !c.NoCerts { if err := cm.StoreCertificate(&apiv1.StoreCertificateRequest{ Name: c.RootObject, Certificate: root, @@ -327,6 +338,8 @@ func createPKI(k kms.KeyManager, c Config) error { }); err != nil { return err } + } else { + c.RootObject = "" } if err := fileutil.WriteFile(c.RootPath, pem.EncodeToMemory(&pem.Block{ @@ -338,6 +351,9 @@ func createPKI(k kms.KeyManager, c Config) error { 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 { @@ -421,7 +437,7 @@ func createPKI(k kms.KeyManager, c Config) error { return errors.Wrap(err, "error parsing intermediate certificate") } - if cm, ok := k.(kms.CertificateManager); ok && !c.NoCerts { + if cm, ok := k.(kms.CertificateManager); ok && c.CrtObject != "" && !c.NoCerts { if err := cm.StoreCertificate(&apiv1.StoreCertificateRequest{ Name: c.CrtObject, Certificate: intermediate, @@ -429,6 +445,8 @@ func createPKI(k kms.KeyManager, c Config) error { }); err != nil { return err } + } else { + c.CrtObject = "" } if err := fileutil.WriteFile(c.CrtPath, pem.EncodeToMemory(&pem.Block{ @@ -437,7 +455,8 @@ func createPKI(k kms.KeyManager, c Config) error { }), 0600); err != nil { return err } - } else { // No root available, generate CSR for external root. + } else { + // No root available, generate CSR for external root. csrTemplate := x509.CertificateRequest{ Subject: pkix.Name{CommonName: c.CrtSubject}, SignatureAlgorithm: x509.ECDSAWithSHA256, @@ -461,7 +480,14 @@ func createPKI(k kms.KeyManager, c Config) error { ui.PrintSelected("Intermediate Key", keyName) } - ui.PrintSelected("Intermediate Certificate", c.CrtPath) + 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{