Skip to content

Instantly share code, notes, and snippets.

@tashian
Last active October 19, 2023 21:36
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tashian/c3bf24b40da614a6fe3c3d87ee5c286a to your computer and use it in GitHub Desktop.
Save tashian/c3bf24b40da614a6fe3c3d87ee5c286a to your computer and use it in GitHub Desktop.

How to create and import a root CA key and certificate onto multiple YubiKeys (for backup / cold storage purposes), and use the root CA to sign a new intermediate CA on a different YubiKey that will be used with step-ca for online leaf certificate signing.

You will need:

  • ykman
  • step
  • step-kms-plugin
  • At least three YubiKeys with PIV support. One will be used for an online intermediate CA, and the rest will be for offline root CA backups.

First, on an airgapped machine, generate a key pair on disk:

$ step crypto keypair root.pub root.priv --kty EC --curve P-384 --insecure --no-password
$ cat root.priv
-----BEGIN EC PRIVATE KEY-----
MIGkAgEBBDAF2rMNn98KPhH8VDr3HvyMAjSghnMkhTOSL0piQaiAKEOYJ1tvuudy
ADG1WKuc5ZegBwYFK4EEACKhZANiAAStX74Q9vp5yjA98r8tUo6bVVpjpYEQ5eu5
G5v8XGniFnxoKSibEykLz9sF8u1Yy7yba7rrxiu0/Y8KXatWRNSZ8DjtgX3ZivyD
+woDjW0+1zVf5eBs8lWqHkzpA5BNN84=
-----END EC PRIVATE KEY-----
$ cat root.pub
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAErV++EPb6ecowPfK/LVKOm1VaY6WBEOXr
uRub/Fxp4hZ8aCkomxMpC8/bBfLtWMu8m2u668YrtP2PCl2rVkTUmfA47YF92Yr8
g/sKA41tPtc1X+XgbPJVqh5M6QOQTTfO
-----END PUBLIC KEY-----

Generate a Root CA certificate:

$ step certificate create --profile root-ca "Smallstep Root CA" root_ca.crt --key root.priv
Your certificate has been saved in root_ca.crt.

For each root YubiKey, insert the key and run the following:

$ ykman piv keys import 82 root.priv
$ ykman piv certificates import 82 root_ca.crt

Your root CA has been backed up and you can now delete the private key:

$ shred -u root.priv

Let's now make an online intermediate CA. Switch to the Yubikey that you'll use for your online CA.

$ step kms create --crv P384 --touch-policy NEVER --kms 'yubikey:pin-value=123456' 'yubikey:slot-id=83' > intermediate.pub
$ cat intermediate.pub
-----BEGIN PUBLIC KEY-----
MHYwEAYHKoZIzj0CAQYFK4EEACIDYgAE5wGsd5nT74PhNpcToJMADrYF5DDSd3UT
geBDkLknghyhKVAZhpbRXUKRbj7C3aErYtbOUfVxiK5puln9EgWOgyEFI5ziwXI5
QTuvLHaR/W/oYA1Rj4ok8Qd7wbNg/nFh
-----END PUBLIC KEY-----
$ ykman piv certificates request 83 intermediate.pub intermediate.csr -s "Smallstep Intermediate CA"
$ step certificate inspect intermediate.csr
Certificate Request:
    Data:
        Version: 0 (0x0)
        Subject: CN=Smallstep Intermediate CA
        Subject Public Key Info:
            Public Key Algorithm: ECDSA
                Public-Key: (384 bit)
                X:
                    ad:5f:be:10:f6:fa:79:ca:30:3d:f2:bf:2d:52:8e:
                    9b:55:5a:63:a5:81:10:e5:eb:b9:1b:9b:fc:5c:69:
                    e2:16:7c:68:29:28:9b:13:29:0b:cf:db:05:f2:ed:
                    58:cb:bc
                Y:
                    9b:6b:ba:eb:c6:2b:b4:fd:8f:0a:5d:ab:56:44:d4:
                    99:f0:38:ed:81:7d:d9:8a:fc:83:fb:0a:03:8d:6d:
                    3e:d7:35:5f:e5:e0:6c:f2:55:aa:1e:4c:e9:03:90:
                    4d:37:ce
                Curve: P-384
    Signature Algorithm: ECDSA-SHA256
         30:65:02:30:55:21:ac:f9:4f:3a:b3:a8:0a:0a:f3:f0:a0:0a:
         15:08:6b:54:eb:8e:82:18:cb:2e:35:c4:ee:bb:0f:b6:b6:4c:
         b0:f6:68:fc:e3:1b:70:0f:a0:40:0b:57:a2:c4:77:20:02:31:
         00:e3:13:14:b3:ee:92:58:7e:40:84:1e:f0:dc:fb:ac:7d:9c:
         96:e8:09:a8:0a:e0:8b:35:9f:24:34:07:ed:b4:0b:6e:5e:a2:
         22:ab:dd:f1:39:03:87:0c:6b:4d:f8:25:1c

Now switch back to a root CA Yubikey, to sign the CSR for the intermediate:

$ step certificate sign --profile intermediate-ca --kms 'yubikey:pin-value=123456' intermediate.csr root_ca.crt 'yubikey:slot-id=82' > intermediate_ca.crt
$ step certificate inspect intermediate_ca.crt
Certificate:
    Data:
        Version: 3 (0x2)
        Serial Number: 29359969139228600868301666524100743019 (0x1616863d51a51a4d447edd37ebb6cf6b)
    Signature Algorithm: ECDSA-SHA384
        Issuer: CN=Smallstep Root CA
        Validity
            Not Before: Oct 19 21:06:56 2023 UTC
            Not After : Oct 16 21:06:56 2033 UTC
        Subject: CN=Smallstep Intermediate CA
        Subject Public Key Info:
            Public Key Algorithm: ECDSA
                Public-Key: (384 bit)
                X:
                    ad:5f:be:10:f6:fa:79:ca:30:3d:f2:bf:2d:52:8e:
                    9b:55:5a:63:a5:81:10:e5:eb:b9:1b:9b:fc:5c:69:
                    e2:16:7c:68:29:28:9b:13:29:0b:cf:db:05:f2:ed:
                    58:cb:bc
                Y:
                    9b:6b:ba:eb:c6:2b:b4:fd:8f:0a:5d:ab:56:44:d4:
                    99:f0:38:ed:81:7d:d9:8a:fc:83:fb:0a:03:8d:6d:
                    3e:d7:35:5f:e5:e0:6c:f2:55:aa:1e:4c:e9:03:90:
                    4d:37:ce
                Curve: P-384
        X509v3 extensions:
            X509v3 Key Usage: critical
                Certificate Sign, CRL Sign
            X509v3 Basic Constraints: critical
                CA:TRUE, pathlen:0
            X509v3 Subject Key Identifier:
                DC:5E:5B:91:EF:E1:42:9F:FE:D9:66:2B:42:ED:51:97:3E:8D:3A:86
            X509v3 Authority Key Identifier:
                keyid:DC:5E:5B:91:EF:E1:42:9F:FE:D9:66:2B:42:ED:51:97:3E:8D:3A:86
    Signature Algorithm: ECDSA-SHA384
         30:64:02:30:48:8a:a0:d9:74:ba:f5:1a:a0:bf:ee:93:2b:78:
         43:5d:2c:d1:d1:f1:02:0e:ac:02:85:8a:ff:f1:bd:4d:5c:a9:
         4f:17:62:46:57:8e:a6:74:5f:b2:4e:70:c3:d5:22:03:02:30:
         25:77:e7:cd:13:3d:4f:46:21:cb:e8:75:12:cd:26:80:38:d4:
         d8:61:af:44:86:7e:2c:38:a7:ae:0c:df:6d:4b:c2:38:89:21:
         be:1c:c0:9e:3f:3c:f3:eb:14:58:bf:14

Finally, return to the intermediate CA yubikey to import the intermediate certificate:

$ ykman piv certificates import 83 intermediate_ca.crt

Now, for your CA config, you'll want to use:

{
    "root": "/etc/step-ca/certs/root_ca.crt",
    "crt": "/etc/step-ca/certs/intermediate_ca.crt",
    "key": "yubikey:slot-id=83",
    "kms": {
        "type": "yubikey",
        "uri": "yubikey:management-key=01020304...?pin-value=123456"
    }
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment