How-to guide · Trust a CA

How to trust a private root CA on macOS

In one sentence

Your Mac, or every managed Mac, trusts your organisation's private root CA in the System keychain, and you know which apps need their own setting.

Task
Trust a CA
Platforms
  • macOS
Who it is for
Level
Practitioner · 5 steps
On this page
  1. Before you start
  2. Steps
  3. 1. Check the file before you trust it
  4. 2. Add it with Keychain Access
  5. 3. Or add it from the Terminal
  6. 4. Or roll it out with MDM
  7. 5. Point the apps that ignore the keychain
  8. Check it worked
  9. If something goes wrong
  10. Why this works
  11. Go deeper

Before you start

  • The root certificate of your private CA as a .cer, .crt or .pem file (DER or PEM). Only the public certificate, never a .p12 or a private key.
  • Its SHA-256 fingerprint, from a channel you trust (your PKI team’s HTTPS intranet page, a signed ticket), not from the message that carried the file.
  • An administrator account on the Mac. macOS asks for an administrator’s password to change trust; sudo alone is not enough.
  • For a fleet: a device management (MDM) service.

Why it matters: a trusted root can vouch for any name in Safari, Chrome and every app that asks macOS to check certificates. Add only roots your organisation controls.

Steps

1. Check the file before you trust it

Compute the fingerprint and compare it with the published value. Hashing the DER form gives the certificate’s fingerprint, and works with the LibreSSL openssl that ships with macOS:

openssl x509 -in corp-root.crt -outform DER | shasum -a 256
bc02a4f5dc68b3fdcdc478030e308cb59d6da0845aa0b4333660788e96c22e01  -

Then check that it really is a root CA: subject and issuer are the same, and the CA flag is set. With OpenSSL 3 (for example from Homebrew) the output for our throwaway test root is:

openssl x509 -in corp-root.crt -noout -subject -issuer -enddate -ext basicConstraints
subject=C=BE, O=Example Corp, CN=Example Corp Root CA
issuer=C=BE, O=Example Corp, CN=Example Corp Root CA
notAfter=Oct 17 01:43:50 2036 GMT
X509v3 Basic Constraints: critical
    CA:TRUE

The decoder below shows the same fields, in your browser. Paste certificates only, never a private key.

Try it: Certificate decoderOpen the full tool

Runs in your browser. Nothing you paste is sent anywhere.

PEM text, several PEM blocks, or a .pem, .crt, .cer or .der file (drop it on the box). Certificates are public, so they are safe to paste.

2. Add it with Keychain Access

This follows Apple’s Keychain Access guide:

  1. Open Keychain Access (search for it with Spotlight).
  2. Select the System keychain, so the root applies to every account on the Mac. The login keychain covers only you.
  3. Drag the certificate file onto the Keychain Access window, and type an administrator’s name and password.
  4. Double-click the certificate, click the arrow next to Trust, and set When using this certificate to Always Trust (changing trust settings). Close the window and enter the password again.

Adding the certificate is not enough on its own: until its trust setting says Always Trust, macOS treats it as an ordinary, untrusted certificate.

3. Or add it from the Terminal

The security command adds the certificate and its trust setting in one step. -d writes the admin trust settings (for all users), -r trustRoot marks it as a trusted root, and -k names the keychain:

sudo security add-trusted-cert -d -r trustRoot -k /Library/Keychains/System.keychain corp-root.crt

Since macOS Big Sur, this still opens a dialog for an administrator’s password. Apple’s Big Sur release notes say “Running as the root user alone is no longer sufficient to modify certificate trust”. So the command cannot run unattended from a script; use MDM for that (step 4).

For your own account only, leave out sudo and -d and name your login keychain:

security add-trusted-cert -r trustRoot -k ~/Library/Keychains/login.keychain-db corp-root.crt

4. Or roll it out with MDM

On managed Macs, put the root in a Certificates payload of a configuration profile. Apple’s Certificates payload settings say a certificate gets full trust automatically when it is “Automatically installed from a supported device management service”, or by a payload in an MDM enrollment profile. Apple also advises: “avoid having users manually install certificates”.

The same profile works for iPhone and iPad. A root that a user installs by hand there also needs Settings > General > About > Certificate Trust Settings (Apple).

5. Point the apps that ignore the keychain

Program Uses the macOS trust settings? What to do
Safari, Mail, apps using Apple’s networking Yes Nothing
Chrome, Edge Yes: roots in the System and login keychains marked Always Trust (Chrome Root Store FAQ) Restart the browser
Firefox Yes, by default since Firefox 120 (Mozilla) Restart Firefox
Node.js, npm No node --use-system-ca reads the keychain (Node.js), or NODE_EXTRA_CA_CERTS: see Python, Node.js and npm
pip 24.2 and later Yes, in addition to its own bundle Nothing
Python requests, python.org’s Python No, they use the certifi bundle See Python, Node.js and npm
Java No, it uses cacerts See Java trust stores
Homebrew’s OpenSSL and the tools built on it Only from a snapshot After adding the root to the System keychain, run brew postinstall ca-certificates to rebuild Homebrew’s bundle
Docker containers No, they are Linux See Linux

Check it worked

List the admin trust settings. Your root should appear with its name:

security dump-trust-settings -d

Confirm which certificate is in the System keychain, by fingerprint:

security find-certificate -a -c "Example Corp Root CA" -Z /Library/Keychains/System.keychain | grep SHA-256

Then let macOS’s own trust evaluation check a real internal server. Given a URL, security verify-cert connects and checks the server’s chain against the SSL server policy (security(1)):

security verify-cert https://intranet.example.com/

A successful verification means the chain reaches your root. Finally, open the site in Safari and in Chrome.

If something goes wrong

  • Safari or Chrome still show NET::ERR_CERT_AUTHORITY_INVALID. The certificate is in a keychain but not set to Always Trust, it went to the login keychain of another user, or the server’s chain ends at a different root. Compare the issuer in the browser’s certificate viewer with your file.
  • Firefox says SEC_ERROR_UNKNOWN_ISSUER. Check that security.enterprise_roots.enabled is true in about:config, or that your Firefox policy does not turn it off.
  • The browser works, but the command line fails with self-signed certificate in certificate chain or CERTIFICATE_VERIFY_FAILED. That tool reads its own bundle: see step 5.
  • The command line works, but some clients report “unable to get local issuer certificate”. The server leaves out its intermediate. Fix the server: build the full chain file and see verify error 21.
  • add-trusted-cert fails in a script or over SSH. That is the Big Sur change in step 3: it needs an administrator to authenticate in a dialog. Use an MDM profile.

Why this works

macOS keeps certificates in keychains and decides trust separately, through trust settings in a user, admin or system domain. When an app asks macOS to check a server, it builds a certificate chain and accepts it only if it ends at a certificate whose trust setting says Always Trust. Being self-signed does not make your root trustworthy; the trust setting does (Who do we trust?). How the chain is checked is in Certificate chains and path validation, and how to design a private CA worth trusting is in A CA of your own.

Go deeper

Early edition. Checked against the standards; an independent expert review is in progress. Found a mistake? Tell us.

Last reviewed Edition 0.9