Trusting the root CA
Add the root CA to the system, Firefox and Java trust stores, so browsers, curl and JVMs accept the certificates issued under it.
Commands
$ homepki trust install -d runlocal.dev # every store available on this host
$ homepki trust install -d runlocal.dev --store nss,java # Firefox and Java only, no sudo
$ homepki trust status # every root CA in the workdir
$ homepki trust status -d runlocal.dev -o json
$ homepki trust uninstall -d runlocal.dev
install and uninstall require --domain. status takes it optionally; without it, every root CA in the workdir is reported. All three take --store, repeatable or comma-separated.
Trust stores
--store | Platform | Where the root goes | How |
|---|---|---|---|
system | macOS | /Library/Keychains/System.keychain | security add-trusted-cert -d -r trustRoot |
system | Fedora, RHEL, CentOS | /etc/pki/ca-trust/source/anchors/homepki-<root>.crt | then update-ca-trust extract |
system | Debian, Ubuntu, Alpine | /usr/local/share/ca-certificates/homepki-<root>.crt | then update-ca-certificates |
system | Arch | /etc/ca-certificates/trust-source/anchors/homepki-<root>.crt | then trust extract-compat |
system | openSUSE | /usr/share/pki/trust/anchors/homepki-<root>.crt | then update-ca-certificates |
nss | macOS, Linux | every Firefox profile; on Linux also the Chrome/Chromium database ~/.pki/nssdb | certutil -A -t C,,, nickname homepki <root> root CA |
java | macOS, Linux | $JAVA_HOME/lib/security/cacerts (jre/lib/security/cacerts on JDK 8) | keytool -importcert, alias homepki-<root> |
<root> is the root CA's literal name, for example runlocal-dev. On Linux the first anchor directory that exists, in the order above, is used.
NSS databases
homepki looks for databases in these places under your home directory, and uses those that hold cert9.db (or the legacy cert8.db):
Library/Application Support/Firefox/Profiles/*(Firefox on macOS).mozilla/firefox/*,snap/firefox/common/.mozilla/firefox/*,.var/app/org.mozilla.firefox/.mozilla/firefox/*(Firefox on Linux, snap, Flatpak).pki/nssdb,snap/chromium/current/.pki/nssdb(Chrome and Chromium on Linux)
certutil comes with NSS: brew install nss, apt install libnss3-tools or dnf install nss-tools. Restart Firefox after installing.
Which stores are used
Without --store, homepki uses every store available on the host:
- system on macOS, and on Linux when a known anchor directory exists;
- nss when at least one database is found and
certutilis installed; - java when
JAVA_HOMEis set and holdsbin/keytooland acacertskeystore.
An unavailable store is skipped with a note, for example Skipping nss: 1 Firefox/NSS database(s) found, but certutil is missing. No note is printed when there is simply no Firefox profile or no JAVA_HOME.
A store named with --store must be available, or the command fails:
$ homepki trust status -d runlocal.dev --store java
Error: --store java: JAVA_HOME is not set
When sudo is needed
| Store | Needs root |
|---|---|
system | yes, on install and uninstall |
nss | no: the databases belong to you |
java | only when your user cannot write cacerts |
homepki runs those commands under sudo, which may prompt for a password, unless it already runs as root (for example in a container). status never needs privileges and never prompts. In an unattended script, call install only when sudo is cached or passwordless, or use --store nss,java.
Install and uninstall
install is idempotent: a store that already trusts the root is reported and skipped. After adding the root to a store, homepki checks it again and fails if the store still does not trust it.
$ homepki trust install -d runlocal.dev --store nss,java
nss adding to ~/Library/Application Support/Firefox/Profiles/x1y2.default-release
java adding to /opt/homebrew/opt/openjdk/libexec/openjdk.jdk/Contents/Home/lib/security/cacerts
Certificate was added to keystore
Root CA for runlocal.dev is trusted in 2 store(s).
Restart Firefox and Java processes to pick it up.
Serve leaves with the intermediate chain file so clients can reach this root.
uninstall removes the root from each selected store and skips stores where it is not present. On macOS the certificate may remain in the System keychain without its trust setting; remove it with Keychain Access if you want it gone.
Status
$ homepki trust status -d runlocal.dev
Root CA trust:
runlocal-dev ✗ partly trusted
✓ system /Library/Keychains/System.keychain
✓ nss ~/Library/Application Support/Firefox/Profiles/x1y2.default-release
✗ java …/lib/security/cacerts (alias homepki-runlocal-dev not in the keystore)
On macOS the system store is checked with security verify-cert. On Linux homepki reads the CA bundle files the distribution builds from its anchors, so it reports what Go, curl and OpenSSL see.
JSON
$ homepki trust status -d runlocal.dev -o json
[
{
"name": "runlocal-dev",
"certificate": "~/.homepki/runlocal-dev/ca/runlocal-dev-root-ca.crt",
"trusted": false,
"detail": "system: Cert Verify Result: CSSMERR_TP_NOT_TRUSTED",
"stores": [
{
"store": "system",
"location": "/Library/Keychains/System.keychain",
"trusted": false,
"detail": "Cert Verify Result: CSSMERR_TP_NOT_TRUSTED"
},
{
"store": "nss",
"location": "~/Library/Application Support/Firefox/Profiles/x1y2.default-release",
"trusted": false,
"detail": "certutil: could not find certificate named \"homepki runlocal-dev root CA\": PR_FILE_NOT_FOUND_ERROR: File not found"
}
]
}
]
| Field | Content |
|---|---|
name | the root CA's literal name, as root-ca list reports it |
certificate | the root certificate that was checked |
trusted | true only when every store checked accepts the root |
detail | the first failing store and its reason |
stores[] | one entry per store: store, location, trusted, detail |
Pass the same --store to status that you used for install. Otherwise a store you never installed into, such as a Firefox profile, makes the top-level trusted false.
Script example
# install into Firefox only when it is not trusted there yet
homepki trust status -d runlocal.dev --store nss -o json | jq -e '.[0].trusted' >/dev/null \
|| homepki trust install -d runlocal.dev --store nss
Serve the chain file
Trusting the root is not enough on its own. A server must present the leaf followed by <intermediate>-intermediate-ca-chain.crt, or clients cannot build the path from the leaf to the trusted root. See Using the certificates.
Constrain the root first
A trusted root can vouch for any name. Restrict it to your own domain with a name constraint before installing it, so a leaked key cannot impersonate other sites.
Windows
Windows is not supported: homepki ships macOS and Linux binaries only, and trust has no Windows store.