With the Step CLI

cd /tmp
wget https://dl.smallstep.com/cli/docs-cli-install/latest/step-cli_amd64.deb
dpkg -I /tmp/step-cli_amd64.deb
step ca bootstrap --ca-url https://ca.joshuabuxton.ca --fingerprint dd1f92d9f58b1d964afa0d35b6f0bd6962f9f6f2e21b45360225a0d9f0764421 --install
Actually resolves to
https://ca.joshuabuxton.ca/root/dd1f92d9f58b1d964afa0d35b6f0bd6962f9f6f2e21b45360225a0d9f0764421

macOS

#!/bin/bash

set -euo pipefail

ROOTS_URL="https://ca.joshuabuxton.ca/roots.pem"
EXPECTED_FP="dd1f92d9f58b1d964afa0d35b6f0bd6962f9f6f2e21b45360225a0d9f0764421"
OUT="/tmp/joshuabuxton-internal-root.crt"

tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

bundle="$tmpdir/roots.pem"
curl --insecure -fsSL "$ROOTS_URL" > "$bundle"

# Split bundle into cert files: cert-0001.pem, cert-0002.pem, ...
awk -v outdir="$tmpdir" '
  /-----BEGIN CERTIFICATE-----/ { n++; fn=sprintf("%s/cert-%04d.pem", outdir, n) }
  n>0 { print > fn }
  /-----END CERTIFICATE-----/ { close(fn) }
' "$bundle"

expected_norm="$(printf "%s" "$EXPECTED_FP" | tr -d ':\r\n' | tr '[:upper:]' '[:lower:]')"

found=""
for f in "$tmpdir"/cert-*.pem; do
  [ -s "$f" ] || continue

  fp="$(openssl x509 -in "$f" -noout -fingerprint -sha256 \
        | sed 's/^.*=//' | tr -d ':\r\n' \
        | tr '[:upper:]' '[:lower:]')"

  if [ "$fp" = "$expected_norm" ]; then
    cp "$f" "$OUT"
    found="yes"
    break
  fi
done

[ -n "$found" ] || { echo "Expected root fingerprint not found in roots.pem"; exit 1; }

sudo security add-trusted-cert -d -r trustRoot \
  -k /Library/Keychains/System.keychain \
  "$OUT"

echo "Installed and trusted: $OUT"

Linux

set -euo pipefail

ROOTS_URL="https://ca.joshuabuxton.ca/roots.pem"
EXPECTED_FP="dd1f92d9f58b1d964afa0d35b6f0bd6962f9f6f2e21b45360225a0d9f0764421"
OUT="/usr/local/share/ca-certificates/joshuabuxton-internal-root.crt"

tmpdir="$(mktemp -d)"
trap 'rm -rf "$tmpdir"' EXIT

bundle="$tmpdir/roots.pem"
curl -fsSL "$ROOTS_URL" > "$bundle"

# Split PEM bundle into chunks (one cert per file, plus maybe a preface chunk)
csplit -s -f "$tmpdir/cert-" "$bundle" '/-----BEGIN CERTIFICATE-----/' '{*}' || true

found=""
for f in "$tmpdir"/cert-*; do
  [ -s "$f" ] || continue
  # Skip chunks that aren't certs (preface chunk)
  grep -q "BEGIN CERTIFICATE" "$f" || continue

  fp="$(openssl x509 -in "$f" -noout -fingerprint -sha256 \
        | sed 's/^.*=//' | tr -d ':\r\n')"

  if [ "${fp,,}" = "${EXPECTED_FP,,}" ]; then
    sudo cp "$f" "$OUT"
    found="yes"
    break
  fi
done

[ -n "$found" ] || { echo "Expected root fingerprint not found in roots.pem"; exit 1; }

sudo update-ca-certificates
echo "Installed: $OUT"
Note: if you get the error
SecTrustSettingsSetTrustSettings: The authorization was denied since no user interaction was possible.
, run this from a fresh terminal window in a graphical session

windows