OPNsenseXXIV · PKI and CertificatesPKI and certificate management
Importing certificates and distributing the trust anchor
What you'll learn
- Import a CA certificate and an intermediate into the OPNsense trust store
- Import a leaf certificate and pair it with its private key
- Assign a certificate to a specific OPNsense service (GUI, IPsec, OpenVPN)
- Distribute the CA certificate to verifiers that need to trust the chain
- Diagnose chain-not-trusted failures using openssl and the trust store
Prerequisites
Verified against OPNsense 25.x · FreeBSD 14.x · PF (FreeBSD packet filter) FreeBSD 14.x · Unbound 1.20+ · Kea DHCP OPNsense 25.x plugin · WireGuard in-kernel + OPNsense plugin · strongSwan (IPsec plugin) OPNsense 25.x plugin · OpenVPN 2.6.x · Suricata 7.x · 2026-08-14
A certificate is useless until it reaches two places: the service that uses it (so the service can present it during a TLS handshake) and the verifier that needs to trust it (so the verifier can complete the chain). The CA certificate must reach the verifier’s trust store. The leaf certificate and its private key must reach the service.
This lesson covers how to import certificates and CA chains into OPNsense, how to pair a leaf certificate with its private key, how to assign certificates to specific services, how to distribute the CA certificate to verifiers, and how to diagnose the chain-not-trusted failure when it appears despite all of this being done.
Importing a CA certificate
OPNsense stores trusted CAs under System → Trust → Authorities.
A CA certificate can be imported in two shapes:
- Self-signed root. The CA certificate is its own issuer (subject equals issuer). The certificate is a trust anchor.
- Intermediate. The CA certificate is signed by another CA. The intermediate is not a trust anchor on its own; the parent root must also be in the trust store.
To import:
- Open
System → Trust → Authorities. - Click Import.
- Paste the PEM-encoded CA certificate into the Certificate data field. If the intermediate has been signed by a parent CA, paste the full chain (intermediate + root, in that order) into the same field.
- Set a descriptive name (e.g.
Example Internal Root CA). - Click Save.
OPNsense parses the PEM, identifies the certificates, and adds them to the trust store. The descriptive name is what subsequent certificate-issuance operations will reference.
$ openssl crl2pkcs7 -nocrl -certfile example-internal-intermediate.crt -certfile example-internal-root.crt | openssl pkcs7 -print_certs -nooutsubject=/O=Example Org/CN=Example Internal Intermediate CA
issuer=/O=Example Org/CN=Example Internal Root CA
subject=/O=Example Org/CN=Example Internal Root CA
issuer=/O=Example Org/CN=Example Internal Root CAIllustrative output
Importing a leaf certificate
Leaf certificates (and their private keys) live under
System → Trust → Certificates. To import a leaf that was
signed by an external CA:
- Open
System → Trust → Certificates. - Click Import.
- Paste the PEM-encoded leaf certificate into the Certificate data field.
- Paste the PEM-encoded private key into the Private key data field. The private key must match the public key in the certificate — see the previous lesson on verifying the match.
- If you have the CA chain (intermediate and root), paste it into the Certificate authority field. OPNsense stores it alongside the leaf for services that need it.
- Set a descriptive name (e.g.
fw.example.com cert). - Click Save.
OPNsense verifies that the private key matches the public key in the certificate. A mismatch is rejected at import time.
Assigning certificates to services
Once a certificate is imported, it can be assigned to the services that need it. The assignment lives in each service’s configuration screen.
- GUI:
System → Settings → Administration → SSL Certificate— select the certificate for the web UI. - IPsec:
VPN → IPsec → Tunnel → Child SA → Local Certificate— select the certificate presented by the firewall as the IPsec endpoint. - OpenVPN:
VPN → OpenVPN → Servers → Cryptographic Settings → Server Certificate— select the certificate for the OpenVPN server. - Captive portal:
Services → Captive Portal → [zone] → SSL Certificate— select the certificate for the captive portal HTTPS listener. - HAProxy / reverse proxy: select the certificate per frontend.
After assigning, the service must be reloaded or restarted. OPNsense offers an Apply action that triggers the reload.
$ openssl s_client -connect fw.example.com:443 -servername fw.example.com </dev/null 2>/dev/null | openssl x509 -noout -subject -issuer -ext subjectAltNamesubject=CN = fw.example.com
issuer=O = Example Org, CN = Example Internal Intermediate CA
X509v3 Subject Alternative Name:
DNS:fw.example.com, DNS:fw.internal.example.comIllustrative output
Distributing the trust anchor to verifiers
The CA certificate must reach every verifier that needs to trust the chain. The distribution depends on the verifier platform.
- Browser on operator workstation: deploy via Group Policy
(Windows), MDM (macOS), or
update-ca-certificates(Linux). - curl or wget: point to the CA file with
--cacertor set theSSL_CERT_FILEenvironment variable, or place the CA in the system trust store. - Java applications: import into the JVM trust store
(
$JAVA_HOME/lib/security/cacerts) usingkeytool. - Python requests: set
REQUESTS_CA_BUNDLEor place the CA in the system trust store. - OPNsense verifying an upstream service: import the
upstream CA into
System → Trust → Authoritiesso OPNsense trusts it.
Diagnosing chain-not-trusted failures
The chain-not-trusted failure is the most common certificate problem in production. The TLS handshake fails because the verifier cannot complete the chain to a trusted root. The diagnostic procedure:
- Confirm what the server is presenting. Use
openssl s_client -showcertsto dump the full chain. The output should contain the leaf, any intermediates the server is sending, and the root should be the last certificate (subject equals issuer). - Confirm what the verifier has in its trust store. The verifier’s root CAs must include the issuer of the intermediate the server is sending.
- Walk the chain by hand. Use
openssl verify -CAfileto verify the chain against an explicit trust anchor. - Check expiry and revocation. A chain can be perfect and still fail if any certificate in the chain is expired or revoked.
$ openssl verify -CAfile example-internal-root.crt -untrusted example-internal-intermediate.crt fw.example.com.crtfw.example.com.crt: OKIllustrative output
If openssl verify reports OK but the browser still shows
untrusted, the issue is the verifier’s trust store, not
the certificate. The browser has not received the CA
certificate. Distribution is the failure, not the chain.
Summary
- Import CA certificates into
System → Trust → Authorities. Paste the full chain (intermediate + root) when importing an intermediate. - Import leaf certificates into
System → Trust → Certificates. OPNsense verifies the private key matches the certificate. - Assign certificates to services (GUI, IPsec, OpenVPN, captive portal, HAProxy) in each service’s configuration.
- Distribute the CA certificate to verifiers that need to trust the chain. Each platform has its own trust-store mechanism.
- Diagnose chain failures with
openssl s_client -showcertsandopenssl verify. A chain that verifies with openssl but fails in the browser is a distribution problem, not a chain problem.
Knowledge check · 4 questions
Q1. You import an intermediate CA certificate into OPNsense but not the parent root. A leaf certificate signed by the intermediate chains to the root in openssl, but the OPNsense trust store cannot complete the chain. What is the fix?
Q2. A certificate that openssl verify reports as OK can still fail in a browser because the browser has a different trust store.
Q3. When importing a leaf certificate into OPNsense, which of the following checks does OPNsense perform automatically? Select all that apply.
Q4. After assigning a new certificate to the OPNsense GUI and clicking Apply, openssl s_client still shows the old certificate. What is the next step?
Passing score: 75%. Answers are checked in this browser.