Basic Crypto Operations Using step

Description

You don't need to run an online Certificate Authority to create certificates and perform basic crypto operations using the step CLI tool. This document gives some examples of things you can do with the step command by itself.

Overview

Here's a few common uses of the step command:

Requirements

Create and work with X.509 certificates

Let's take a look at the step certificate command group. This command group is a Swiss Army knife for working with certificates. You can use it to create certificate signing requests (CSRs), sign CSRs, create self-signed certificates (e.g., a root certificate authority), create leaf or intermediate CA certificates, validate and inspect certificates, renew certificates, generate certificate bundles, and to key-wrap private keys.

Shall we try it out?

Create a Certificate Authority

Create a Root CA:

step certificate create --profile root-ca "Example Root CA" root_ca.crt root_ca.key

Typically you will also want an intermediate CA. Create an Intermediate CA that is signed by your Root CA:

step certificate create "Example Intermediate CA 1" \
    intermediate_ca.crt intermediate_ca.key \
    --profile intermediate-ca --ca ./root_ca.crt --ca-key ./root_ca.key

Now you can store your root_ca.key in a safe place offline, because you'll only need the intermediate CA key to issue TLS leaf certificates.

Issue a Leaf Certificate Bundle

Use your intermediate CA to sign leaf (end entity) certificates for your servers.

Create a leaf TLS certificate for example.com, valid for a year:

step certificate create example.com example.com.crt example.com.key \\
    --profile leaf --not-after=8760h \\
    --ca ./intermediate_ca.crt --ca-key ./intermediate_ca.key --bundle

By using the --bundle flag we automatically bundle the new leaf certificate with the signing intermediate certificate. TLS-based services will require the bundle in order to verify the full chain.

$ step certificate verify example.com.crt --roots root_ca.crt
(no output - certificate is valid)

Inspect an X.509 Certificate

To inspect the certificate you just made, run:

$ step certificate inspect example.com.crt --short
  Subject:     example.com
  Issuer:      Example Intermediate CA 1
  Valid from:  2020-09-02T20:48:41Z
          to:  2021-09-02T20:48:40Z

You can get a certificate in JSON format by calling step certificate inspect with --format json. This example uses jq to parse the JSON and extract a specific value:

$ step certificate inspect example.com.crt --format json | jq -r .validity.end
2020-09-03T20:48:41Z

You can also inspect the TLS certificate for any URL:

$ step certificate inspect https://smallstep.com --format json | jq -r .validity.end
2020-11-13T07:09:47Z

Get a TLS Certificate From Let's Encrypt

step is a full-fledged ACME client (the protocol used by Let's Encrypt. Unlike other ACME clients, step connects to a configured step-ca daemon by default. To use it with Let's Encrypt or another ACME server instead, you can pass an --acme endpoint:

step ca certificate example.com example.com.crt example.com.key \
    --acme https://acme-v02.api.letsencrypt.org/directory

This command will:

If you don't want step to run a standalone server to respond to the ACME challenge, you can pass --webroot <path> to specify a path where step will place the .well-known/acme-challenge/<TOKEN> token file.

For a dry run, you can use Let's Encrypt's staging server URL: https://acme-staging-v02.api.letsencrypt.org/directory

Generate JSON Web Tokens (JWTs) and JSON Web Keys (JWKs)

The following command groups work with JOSE objects like JWTs and JWEs:

In this example, you'll create a JSON Web Key (JWK), add the public key to a keyset, and sign a JSON Web Token (JWT) that expires in 15 minutes:

$ step crypto jwk create pub.json key.json
$ cat pub.json | step crypto jwk keyset add keys.json
$ JWT=$(step crypto jwt sign \
    --key key.json \
    --iss "issuer@example.com" \
    --aud "audience@example.com" \
    --sub "subject@example.com" \
    --exp $(date -v+15M +"%s"))

We can then verify the JWT and return the payload:

$ echo $JWT | step crypto jwt verify --jwks keys.json --iss "issuer@example.com" --aud "audience@example.com"
{
  "header": {
    "alg": "ES256",
    "kid": "pwNr_RwEMFPxxfpUgsSHcCEP-CVIFQ_maI9UiHljqt0",
    "typ": "JWT"
  },
  "payload": {
    "aud": "audience@example.com",
    "exp": 1599086725,
    "iat": 1599085826,
    "iss": "issuer@example.com",
    "jti": "5681b0ad0e624c2c6da4ad610e298ba4f54c2e0c8f2731698b214126c5e780c9",
    "nbf": 1599085826,
    "sub": "subject@example.com"
  },
  "signature": "wco1X1ue14D9wmgH_DXIbTZXIg_McXRMlV80O1JDPo12j8zhHIWQikYxUBvbxfME2VbNO5WRKUB9H9WjX2FlnQ"
}

Obtain and Work With OAuth Tokens

This command group requires that you supply your own OAuth provider URL, client ID, and client secret.

Obtain OAuth OIDC Identity Tokens

In this example, we'll sign into Google and get an OIDC identity token. Replace the --client-id and --client-secret with your own values obtained from Google Cloud Console's APIs & Services menu.

$ TOKEN=$(step oauth \
  --provider https://accounts.google.com \
  --client-id 1087160488420-8qt7bavg3qesdhs6it824mhnfgcfe8il.apps.googleusercontent.com \
  --client-secret udTrOT3gzrO7W9fDPgZQLfYJ \
  --bare --oidc)

The --provider URL must have a discovery endpoint, created by appending /.well-known/openid-configuration to the URL. This is a JSON file describing endpoints and keys for OpenID Connect. For example, see https://accounts.google.com/.well-known/openid-configuration.

Once you have an OIDC identity token, you can verify it. The --jwks value comes from the jwks_uri value at the OpenID discovery endpoint.

$ echo $TOKEN | step crypto jwt verify \
  --jwks https://www.googleapis.com/oauth2/v3/certs \
  --iss https://accounts.google.com \
  --aud 1087160488420-8qt7bavg3qesdhs6it824mhnfgcfe8il.apps.googleusercontent.com

Miscellaneous Tools (TOTP Tokens, NaCl, SSH Certificates)

Generate TOTP Tokens for Multi-Factor Authentication (MFA)

step crypto otp generate \
         --issuer smallstep.com --account name@smallstep.com \
         --qr smallstep.png > smallstep.totp

Scan the QR Code using Google Authenticator, Authy, or similar software and use it to verify the TOTP token:

step crypto otp verify --secret smallstep.totp

Sign and Encrypt Arbitrary Data

Work with SSH Certificates

The step ssh command group is usually used in conjunction with step-ca's SSH CA functionality. But not all the subcommands require an SSH CA. You can inspect an SSH certificate:

$ step ssh inspect < mycert.crt
-:
        Type: ecdsa-sha2-nistp256-cert-v01@openssh.com user certificate
        Public key: ECDSA-CERT SHA256:5Zu0dV5Q0DLtXTBs6UWtvNNzg1gqUVTfvogzKyPcKPs
        Signing CA: ECDSA SHA256:PxHk36T6v70LP+wfD/RB1IbmA9I4EpyLq72F0eOH5hE
        Key ID: "carl@example.com"
        Serial: 2937319031419699911
        Valid: from 2020-09-08T17:07:53 to 2020-09-09T09:08:53
        Principals:
                carl
				carl@example.com
        Critical Options: (none)
        Extensions:
                permit-X11-forwarding
                permit-agent-forwarding
                permit-port-forwarding
                permit-pty
                permit-user-rc

And you can get the fingerprint of an SSH certificate or public key:

$ step ssh fingerprint < mycert.crt
256 SHA256:CQ6+r7ccb/wqoWK1ror10c44nNvvYXp2mgbPrsTmCbw c (ECDSA-CERT)