#!/bin/sh # ───────────────────────────────────────────────────────────────────────────── # Installs the APPLEBEE-ROOT26 root certificate(s) into the system trust # store, and into the NSS store that Firefox and Chrome use. # # Each certificate is checked against a SHA-256 fingerprint baked in when this # script was generated. A mismatch aborts before anything is installed. # # ECDSA (P-256) # b1aa5115d3adbfb821e8ca6a7db14de180640eb4da3586066b13fe76aec1c762 # RSA (legacy compatibility) # 95fb9ab7db52c08b1084fc7756ed30c64dabe4cdc5dcb77847ccd6f7a8cf9d7b # # Run with: sudo sh install-root.sh # ───────────────────────────────────────────────────────────────────────────── set -eu PLATFORM='linux' die() { printf '\033[31merror:\033[0m %s\n' "$*" >&2; exit 1; } info() { printf '\033[36m==>\033[0m %s\n' "$*"; } warn() { printf '\033[33mwarn:\033[0m %s\n' "$*" >&2; } [ "$(id -u)" = 0 ] || die "run this with sudo" command -v openssl >/dev/null 2>&1 || die "openssl is required" fingerprint_of() { openssl x509 -in "$1" -outform DER 2>/dev/null | openssl dgst -sha256 -hex \ | sed 's/.*= *//' | tr -d ' \n' | tr 'A-Z' 'a-z' } install_root() { name=$1; label=$2; expected=$3 tmp=$(mktemp) cat > "$tmp" actual=$(fingerprint_of "$tmp") if [ "$actual" != "$expected" ]; then rm -f "$tmp" die "fingerprint mismatch for $label expected $expected got $actual Nothing was installed." fi info "$label" echo " sha256 $actual" case "$PLATFORM" in macos) install_macos "$tmp" "$label" ;; *) install_linux "$tmp" "$name" ;; esac install_nss "$tmp" "$label" rm -f "$tmp" } install_macos() { security add-trusted-cert -d -r trustRoot \ -k /Library/Keychains/System.keychain "$1" echo " added to the System keychain as a trusted root" } install_linux() { src=$1; name=$2 if [ -d /usr/local/share/ca-certificates ]; then # Debian, Ubuntu cp "$src" "/usr/local/share/ca-certificates/applebee-root26-$name.crt" update-ca-certificates >/dev/null echo " installed via update-ca-certificates" elif [ -d /etc/pki/ca-trust/source/anchors ]; then # RHEL, Fedora cp "$src" "/etc/pki/ca-trust/source/anchors/applebee-root26-$name.crt" update-ca-trust extract echo " installed via update-ca-trust" elif [ -d /etc/ca-certificates/trust-source/anchors ]; then # Arch cp "$src" "/etc/ca-certificates/trust-source/anchors/applebee-root26-$name.crt" trust extract-compat echo " installed via trust extract-compat" elif [ -d /usr/share/ca-certificates ]; then # Alpine, others cp "$src" "/usr/share/ca-certificates/applebee-root26-$name.crt" update-ca-certificates >/dev/null echo " installed via update-ca-certificates" else die "no recognised system trust store on this host" fi } # Firefox everywhere, and Chrome on Linux, read NSS rather than the system # store. Without this the certificate works in curl but not in the browser. install_nss() { src=$1; label=$2 if ! command -v certutil >/dev/null 2>&1; then warn "certutil not found — Firefox/Chrome will not trust this yet." warn " Debian/Ubuntu: apt install libnss3-tools" warn " Fedora/RHEL: dnf install nss-tools" warn " Arch: pacman -S nss" warn " macOS: brew install nss" warn "Then re-run this script." return 0 fi found=0 for home in /home/* /root /Users/*; do [ -d "$home" ] || continue for db in "$home"/.pki/nssdb "$home"/.mozilla/firefox/*.default* \ "$home"/Library/Application\ Support/Firefox/Profiles/*; do [ -d "$db" ] || continue certutil -A -n "$label" -t "C,," -i "$src" -d "sql:$db" 2>/dev/null \ && found=$((found + 1)) || true done done [ "$found" -gt 0 ] \ && echo " added to $found NSS profile(s)" \ || warn "no NSS profiles found — open Firefox once, then re-run" } install_root 'ecdsa' 'ECDSA (P-256)' 'b1aa5115d3adbfb821e8ca6a7db14de180640eb4da3586066b13fe76aec1c762' <<'CERT_ECDSA' -----BEGIN CERTIFICATE----- MIIBlDCCATugAwIBAgIQG+5TFqGka9S3fAOCeSZRkjAKBggqhkjOPQQDAjApMScw JQYDVQQDEx5BUFBMRUJFRSBORVRXT1JLUyBST09UIENBIChFQykwHhcNMjYwODMw MjAzMzE5WhcNNDYwODI1MjAzMzE5WjApMScwJQYDVQQDEx5BUFBMRUJFRSBORVRX T1JLUyBST09UIENBIChFQykwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATmJa/O 5s9/6WIhHyEMvWZhZtoCDxzGZaKWfmS4N7TZq1XjgKwu63ao0geH6Zrv8cL1YUlj xmQbkfMTI8IkJWg+o0UwQzAOBgNVHQ8BAf8EBAMCAQYwEgYDVR0TAQH/BAgwBgEB /wIBATAdBgNVHQ4EFgQU56c8a9PiOcRaVL0m9wh/raNx8pcwCgYIKoZIzj0EAwID RwAwRAIgeocPwAwwQieLq0f1aDbSrYexOXR6Gp/OiUBRLt4o71UCIEqcneuTF2oE pthfOPcdHVt0KYfkWpk+FTV3Y+TaaCyd -----END CERTIFICATE----- CERT_ECDSA install_root 'rsa' 'RSA (legacy compatibility)' '95fb9ab7db52c08b1084fc7756ed30c64dabe4cdc5dcb77847ccd6f7a8cf9d7b' <<'CERT_RSA' -----BEGIN CERTIFICATE----- MIIFIzCCAwugAwIBAgIQAwRrHoF11a6tJWi9AUwuCTANBgkqhkiG9w0BAQsFADAq MSgwJgYDVQQDEx9BUFBMRUJFRSBORVRXT1JLUyBST09UIENBIChSU0EpMB4XDTI2 MDgzMDIwMzMyN1oXDTQ2MDgyNTIwMzMyNVowKjEoMCYGA1UEAxMfQVBQTEVCRUUg TkVUV09SS1MgUk9PVCBDQSAoUlNBKTCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCC AgoCggIBAKBB4mIfbgHvPwK4KdnctVc9GnjtzW+I1ec6hRCI0H8hpX65QaZNGniy BKdKO/Qz1pz8rjXQi6/ZpNDxmHVJdXrH2K0PbsYcGTOkWNAZXcB4W287wu6/OKnE MSsbFlJfycdXTvSOsTiXyfA3EC8KfjzDmR1KNB2tsYWY7/VkT1yp/AQS9ZWSoB9U TPY6Cyh4EZfDFmEP3C7/uTeehnGKDXlzboY5f4EA5Xf5CrkYxJ2ugHKBD00psbnq OQl2xRnkcr0sGjy5HadvC7gvauHq3IFDcDj1fGpYQV9iT4ZkbRZRvqefIgwePXaO eucNyS1bSai+rZnAw9/Qnmox1Q85IDnsDL+fCcoteiRIgeqBviC5kuCgUITWEdLo z2pwtgaPQJYUEV2lBnsyyextTiOJmPI4LmgjnmIY4cjSU2qlt6vnX6rMvSDsvFcB ymrA8AHKJMLIyjbUBJHqAY020cBKAPXJH87TnXyC9cY3SDhz0iKr1Ze/ZpNQjjfk combPlyFuTQXrXPqvxpiPvfPYkt/OGWh//JXJyuIueFRlcg9vlEemkmIlYwlRpF4 ww5V481f05zaEtNfRabCtMR/23opUsiT+HoA48+LP/oj0pTex51I6kxqYFLUJnUJ C5rERmbMHT26MJ8Ryx+3HljC+VSrKlAzwaCRlWUpPeADsKsITrTfAgMBAAGjRTBD MA4GA1UdDwEB/wQEAwIBBjASBgNVHRMBAf8ECDAGAQH/AgEBMB0GA1UdDgQWBBQM IB22SD3wsAS6FWlQTAHaD91nVjANBgkqhkiG9w0BAQsFAAOCAgEAVFpvZAodmJTd Ui59yAALsfTDaDkuSLF28KVNBZoEGg/SOyvXNdSKTrU+B/mDHlteCPBE0E4tVIHT DjvZRGzdVInTBcV2ES9AEpX9uGN8w8g48LPWXejZaKrG2GNL3r/jFFXde+Zgy+GH 5GY34oLChxiXGttl81GSslpBCKtFkHaxIkc/noSbI6X7AWc6Sxpvjuv+5JZYRVDr DJAa+SPNGeDk53Ok7Y15IoKwf2UST6aD6KzhZQ36vJ3MSluIl1FCKRsa/T0hILIv g2g24I86SHQzRjXHILFIuMmuuCjEKwjbvu49eSSswMhyEL5Fou2/nHTWsdEXT3qj mlpvPpftW+jh6AbtFTgjG6Ec3SPoLZ0cby1JaipotoTBmE/B2OCJwQqyMnTpkP7I F5wiNcLm3M5XJf2ebk+71G5tKIbNi05TT7Kvc84BaJ9i0G1NNn+HIOyvWjBPno0c HmWQa5euE7EiVoBtLTONRqIFLUffdHF7hAPKnGSe6t64wRdauFnWXLbMm+5yPeWC LQZf0GCuKDmg9IMqYGuLOky8PvWlMzFRISxmgfCuMUg2EhQt1HesMO2uYsg0Js1W CUFX6FxcMIJbU9anis+0b1g0Fn0j5gNPyUUOSjGhAxJbhC0pKQs+Tc942TOBvHEY WrlN9TYQnHTom7dQkdrbPU0JnGdAs1w= -----END CERTIFICATE----- CERT_RSA printf '\n\033[32mDone.\033[0m Restart browsers to pick up the new trust anchor.\n'