Server keys with pfSense CA
Created: 12 Jul 2025.
A more recent approach that I have decided to go with is to let pfSense generate the CA cert and then I use that to generate the required server and client certs.
I decided to use this method as I needed the hostname and IP address of the server included in the Subject Alternate Name (SAN) for the cert.
The directory structure I used before any certs are generated, is as shown below:

Directory tree structure for server client key creation
BigTomCA.key: The primary CA cert key downloaded from pfSense
BigTomCA.crt: The certificate request CA file
certs: The folder to hold the generated server and client keys
genCert.sh: The key generation file whose contents are shown below
1#!/bin/bash
2
3# Define directories and filenames
4CERT_DIR="/home/thomas-pk/Documents/batch jobs/bigtom.local-pki"
5CA_KEY="${CERT_DIR}/BigTomCA.key"
6CA_CERT="${CERT_DIR}/BigTomCA.crt"
7CLIENT_KEY="${CERT_DIR}/certs/client.key"
8CLIENT_CSR="${CERT_DIR}/certs/client.csr"
9CLIENT_CERT="${CERT_DIR}/certs/client.crt"
10SERVER_KEY="${CERT_DIR}/certs/server.key"
11SERVER_CSR="${CERT_DIR}/certs/server.csr"
12SERVER_CERT="${CERT_DIR}/certs/server.crt"
13
14# Create the certs directory if it doesn't exist
15[[ ! -d "$CERT_DIR" ]] && mkdir -p "$CERT_DIR"
16
17# Generate server private key and CSR
18openssl req -new -sha512 -nodes -out "$SERVER_CSR" -newkey rsa:4096 -keyout "$SERVER_KEY" -subj "/C=SG/ST=Singapore/L=Hougang/O=BigTomLocal/OU=Admin/CN=tom-ldap"
19
20# Define OpenSSL configuration file for server extensions
21SERVER_EXT_CONF="${CERT_DIR}/server_ext.cnf"
22cat > "$SERVER_EXT_CONF" << 'EOF'
23[ v3_req ]
24basicConstraints = CA:FALSE
25keyUsage = critical, digitalSignature, keyEncipherment
26extendedKeyUsage = serverAuth, clientAuth
27subjectAltName = @alt_names
28subjectKeyIdentifier = hash
29authorityKeyIdentifier = keyid:always,issuer
30
31[ alt_names ]
32DNS.1 = tom-ldap.bigtom.local
33IP.1 = 192.168.1.12
34EOF
35
36# Generate server certificate with the correct extensions
37openssl x509 -req -in "$SERVER_CSR" -CA "$CA_CERT" -CAkey "$CA_KEY" -CAcreateserial -out "$SERVER_CERT" -days 3650 -sha512 -extfile "$SERVER_EXT_CONF" -extensions v3_req
38
39# Generate client private key and CSR
40openssl req -new -sha512 -nodes -out "$CLIENT_CSR" -newkey rsa:4096 -keyout "$CLIENT_KEY" -subj "/C=SG/ST=Singapore/L=Hougang/O=BigTomLocal/OU=Admin/CN=ldap-client"
41
42# Generate client certificate
43openssl x509 -req -in "$CLIENT_CSR" -CA "$CA_CERT" -CAkey "$CA_KEY" -CAcreateserial -out "$CLIENT_CERT" -days 3650 -sha512
44
45echo "Certificates generated successfully."
Once the script shown above is run, the output would be as shown below:

Directory tree structure with generated keys under certs
To check whether the alternate name has been created in the cert, we can run the following command:
openssl x509 -noout -text -in ./TomLdap_server.crt | grep -A2 "X509v3 Subject Alternative"

Verification of SAN entry for the server cert
I then generally rename these certs with a prefix and move it to another folder for safe-keeping with a simple command like that given below.
for filename in *.*; do mv "$filename" "TomLdap_${filename}"; done;