OPNsenseXXIV · PKI and CertificatesPKI and certificate management
Certificate signing requests — what a CSR really contains
What you'll learn
- Explain what a CSR contains and why a CA cannot read private keys
- Generate a CSR with OpenSSL or OPNsense for a specific service hostname
- Decode and inspect a CSR before submitting it to a CA
- Match a CSR to the matching private key to detect mismatches
- Identify the CSR mistakes that lead to invalid or rejected certificates
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 signing request is a small, signed file that asks a certificate authority to issue a certificate. The CSR contains the public key, the identity the certificate should bind, and a self-signature proving the requester holds the private key corresponding to the public key. The CA reads the CSR, signs the public key and identity with its own private key, and returns a certificate.
This lesson covers what a CSR contains at the field level, how to generate one for an OPNsense service, how to decode a CSR before submitting it to a CA, and the production mistakes that lead to invalid certificates — wrong SAN, mismatched private key, deprecated signature algorithm, and the rest.
What a CSR is
The CSR is defined by PKCS#10 (RFC 2986). The data structure:
CertificationRequest:
certificationRequestInfo:
version: 0 (PKCS#10 v1)
subject: the identity being certified (CN, O, C, ...)
subjectPKInfo: the public key and algorithm
attributes: extensions (SAN, key usage, ...)
signatureAlgorithm: the algorithm signing the CSR
signature: signature over certificationRequestInfo
The CSR is signed with the private key corresponding to the public key in the CSR. This is the proof that the requester holds the private key — the CA never sees the private key, only the public key embedded in the CSR. The CA verifies the signature, confirms the requester is allowed a certificate, attaches its own signature, and returns a certificate.
The CSR is usually encoded as PEM (base64 with BEGIN/END markers), sometimes as DER (raw ASN.1 binary). The OPNsense CA manager and most public CAs accept PEM.
-----BEGIN CERTIFICATE REQUEST-----
MIICjDCCAXQCAQAwGTEXMBUGA1UEAwwOZi5leGFtcGxlLmNvbTCCASAwDQYJ
KoZIhvcNAQEBBQADggENADCCAQgCggEBAKvV0pD+exampleCSRbody...
-----END CERTIFICATE REQUEST-----
Generating a CSR
OPNsense generates the CSR for you under
System → Trust → Certificates. The workflow:
- Add a certificate.
- Choose Create a Certificate Signing Request.
- Select the key type, size, and the CA that should eventually sign it (this only matters if OPNsense will sign it; if the CSR is going to an external CA, leave it blank or pick any CA, the field is not part of the CSR).
- Set the Common Name, Organisation, Country, and other DN fields.
- Add the Subject Alternative Names. This is the part that matters for hostname validation.
- Click Save.
OPNsense generates the private key, builds the CSR, and stores
both. The CSR is exported from the certificate list as a .csr
file.
For a CLI-only generation (the same flow, by hand):
$ openssl req -new -newkey rsa:3072 -nodes -keyout fw.example.com.key -out fw.example.com.csr -subj "/CN=fw.example.com/O=Example Org/C=GB" -addext "subjectAltName=DNS:fw.example.com,DNS:fw.internal.example.com" -addext "keyUsage=digitalSignature,keyEncipherment" -addext "extendedKeyUsage=serverAuth"Generating a RSA private key
...........................................................................++++
writing new private key to 'fw.example.com.key'
-----Illustrative output
The -nodes flag stores the private key unencrypted. This is
required for services that start without operator input (the
firewall GUI, IPsec daemons). For an offline signing key (such
as the CA root), -nodes should not be used — passphrase-
protect the offline key.
Decoding and inspecting a CSR
Before sending a CSR to a CA, decode it. The verification catches mistakes that would otherwise produce an unusable certificate.
$ openssl req -in fw.example.com.csr -noout -text -reqopt ext_subjected,ext_extensionsCertificate Request:
Data:
Version: 1 (0x0)
Subject: CN = fw.example.com, O = Example Org, C = GB
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (3072 bit)
Modulus:
00:c1:9a:...
Exponent: 65537 (0x10001)
Attributes:
Requested Extensions:
X509v3 Subject Alternative Name:
DNS:fw.example.com, DNS:fw.internal.example.com
X509v3 Key Usage:
Digital Signature, Key Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication
Signature Algorithm: sha256WithRSAEncryption
a3:51:c9:...Illustrative output
The fields to inspect, in order:
- Subject DN: the Common Name must match the primary hostname. The Organisation, Country, etc. should be correct.
- Subject Alternative Name: must list every hostname the service will be reached at. This is what the verifier checks at TLS time.
- Public Key Algorithm: must be modern (RSA 2048+, ECDSA P-256+, Ed25519). Avoid RSA 1024 or smaller.
- Signature Algorithm: must be SHA-256 or stronger. Avoid SHA-1 (deprecated, rejected by modern CAs).
- Requested Extensions: Key Usage and Extended Key Usage should match the purpose (serverAuth for TLS servers, clientAuth for TLS clients).
Matching CSR to private key
A CSR is a public object, sent to a CA. The private key stays with the requester. After the CA returns the certificate, the requester must verify that the certificate’s public key matches the private key they kept. A mismatched key pair produces a certificate the requester cannot use.
$ diff <(openssl req -in fw.example.com.csr -noout -pubkey) <(openssl x509 -in fw.example.com.crt -noout -pubkey)Illustrative output
Common CSR mistakes in production
Five mistakes appear repeatedly.
- Missing SAN. The CSR has a CN but no SAN. The CA issues a certificate with no SAN. Modern clients refuse to validate the hostname. The service is broken until the CSR is regenerated.
- Wrong hostname. The CN and SAN list
fw.example.combut the service is reached asfirewall.example.com. The TLS handshake fails for clients using the real hostname. - Deprecated signature algorithm. SHA-1 with RSA. The CA refuses to sign. Modern CAs reject SHA-1 CSRs outright.
- Mismatched private key. The CSR was regenerated, but the operator kept the old private key. The CA issues the certificate from the new CSR, the new public key does not match the old private key, the service is broken.
- Passphrase-protected private key for an auto-start service. The service starts unattended and cannot type the passphrase. The service fails to start, or starts in a broken state.
Summary
- A CSR carries the public key, the subject identity, the SAN, and a self-signature proving the requester holds the private key. The CA never sees the private key.
- Generate CSRs with OPNsense or OpenSSL. Include the SAN; modern clients do not match the CN.
- Decode the CSR with
openssl req -textbefore submitting it to the CA. Verify subject, SAN, key algorithm, signature algorithm, and extensions. - After the CA returns the certificate, verify the public key matches the private key on disk.
- Never regenerate a CSR without informing the CA. A lost CSR plus a submitted CSR produces an unusable certificate.
Knowledge check · 4 questions
Q1. Why does the CSR protocol work without the CA ever seeing the private key?
Q2. A CSR with Common Name "fw.example.com" but no Subject Alternative Name extension is acceptable for a TLS server certificate because the Common Name will be matched by modern clients.
Q3. After receiving a certificate from a CA, which of the following checks must the operator perform? Select all that apply.
Q4. You generate a CSR, submit it to the CA, and then realise the SAN was missing a hostname. You regenerate the CSR with the correct SAN and submit it. What happens to the certificate issued from the first CSR?
Passing score: 75%. Answers are checked in this browser.