pfSense is a neat firewall based on the FreeBSD operating system. The firewall will by default act as a CA (Certificate Authority) issuing certificates to firewall users and services. Certificates typically used by “internal” VPN clients and for running a secure https management session to the firewall. But you may have external boxes that needs certificates too. The most common way to issue and install a certificate on a device, are to generate a certificate signing request on the device that needs a certificate, “paste” the certificate request to a CA, save the issued certificate as a file and install it on the device.
The pfSense firewall have however no menu option for issuing certificates. I have searched pfSense discussion forums, but can´t find any useful information about issuing certificates to external systems.
To sign a certificate, we need a CA certificate, it´s private key and a tool to sign the certificate request.
(If you have not created a CA certificate on your pfSense firewall yet, you need to do this now selecting System > Cert manager > Ca´s, click the + button and select method: Create an internal Certificate Authority.)
Both the pfSense´s CA certificate and the CA private key can be downloaded using the pfSense WEB management interface. You can download it from System > Cert Manager > CAs. One down-arrow button will download the CA Certificate and another button will download the private key. It´s saved to PEM formatted base64 encoded files. Now we need a tool/program for signing new certificates.
One nice and common tool for handling certificates, is the OpenSSL command line tool. The OpenSSL library is in fact used by pfSense for it´s certificate operations. We can use the openssl command line tool on the pfSense firewall or optionally download and install the tool on a PC.
The OpenSSL syntax for issuing a certificate from a CSR (certificate signing request), is:
openssl ca -keyfile <ca-private-key-file> -cert <ca-certificate-file> -extensions usr_cert -notext -md sha256 -in <cert-signing-request-file> -out <certificate-file>
When we are using openssl on the pfSense firewall, we need to use the command line interface. Let´s star by running a ssh session to the firewall and select option 8) shell.
We need to check if openssl is present and find the openssl executable and it´s configuration file:
[2.2.4-RELEASE][x@fw.lan.x]/root: find / -name openssl –ls 1625226 1056 -r-xr-xr-x 1 root wheel 512864 Jul 26 03:17 /usr/bin/openssl 1742987 4 drwxr-xr-x 2 root wheel 512 Aug 7 09:25 /usr/local/openssl [2.2.4-RELEASE][x@fw.lan.x]/root: find / -name openssl.cnf –ls 1884422 20 -rw-r--r-- 1 root wheel 9925 Jul 26 02:59 /etc/ssl/openssl.cnf 1742997 0 lrwxr-xr-x 1 root wheel 28 Jul 26 02:59 /usr/local/openssl/ openssl.cnf -> ../../../etc/ssl/openssl.cnf
The executable is located in /usr/bin and config file is located in /etc/ssl.
Let´s check the openssl configuration file and look at the default directories:
[2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: more openssl.cnf : [ CA_default ] dir = ./demoCA # Where everything is kept certs = $dir/certs # Where the issued certs are kept crl_dir = $dir/crl # Where the issued crl are kept database = $dir/index.txt # database index file. #unique_subject = no # Set to 'no' to allow creation of #several ctificates with same subject. new_certs_dir = $dir/newcerts # default place for new certs. certificate = $dir/cacert.pem # The CA certificate serial = $dir/serial # The current serial number #crlnumber = $dir/crlnumber # the current crl number # must be commented out to leave a V1 CRL crl = $dir/crl.pem # The current CRL private_key = $dir/private/cakey.pem# The private key RANDFILE = $dir/private/.rand # private random number file :
This config file describes the default installation of openssl with demoCA as “root” catalogue for the openssl files. Let´s not mess to much with the default installation, and make a new openssl root catalogue we can call myca. We can comment out the line dir = ./demoCA and adding a new line dir=./myCA
#dir = ./demoCA # Where everything is kept dir = ./myca # Where everything is kept
Then create the necessary openssl directories:
[2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: mkdir myca [2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: mkdir myca/newcerts [2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: mkdir myca/private
We need to create an empty index.txt file and a new serial file:
[2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: touch myca/index.txt [2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: echo '1001' >myca/serial
Now we need to download the pfSense firewall CA certificate and CA private key to a local drive. Select System > Cert Manager > CAs and click the down arrow buttons and save it to the local drive. Then we need to copy the files back to the firewall to store them in our new myca folder structure. Select Diagnostics > Command prompt > Upload and select the local CA files. These files are uploaded to the firewalls /tmp directory. After they are uploaded to the firewalls tmp directory, we need to move them to the correct openssl myca directories.
[2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: mv /tmp/myCA.crt myca [2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: mv /tmp/myCA.key myca/private
If we look in the openssl.cnf file, the CA cert is expected to be named cacert.pem and the private key named cakey.pem.
[2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: mv myca/myCA.crt myca/cacert.pem [2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: mv myca/private/myCA.key myca/private/cakey.pem
Just to make extra sure the private key is kept safe:
[2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: chmod 0700 myca/private/cakey.pem
Now we are ready to use openssl. Let´s start to look at the structure of our CA certificate file (I have x´ed and zeroed out information in the output):
[2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: openssl x509 -in myca/cacert.pem -text -noout Certificate: Data: Version: 3 (0x2) Serial Number: 0 (0x0) Signature Algorithm: sha256WithRSAEncryption Issuer: C=XX, ST=Xxx, L=Xxxx, O=Xxx/emailAddress=x@x.x, CN=ca.x.x Validity Not Before: Jun 12 16:08:42 2014 GMT Not After : Jun 9 16:08:42 2024 GMT Subject: C=XX, ST=Xxx, L=Xxx, O=Xxx/emailAddress=x@x.x, CN=ca.x.x Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (2048 bit) Modulus: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 Exponent: 65537 (0x10001) X509v3 extensions: X509v3 Subject Key Identifier: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 X509v3 Authority Key Identifier: keyid:00:00:00:00:00:00:00:00:00:00:00:00:00:00:00 DirName:/C=XX/ST=Xxx/L=Xxx/O=Xxx/emailAddress=x@x.x/CN=ca.x.x serial:00 X509v3 Basic Constraints: CA:TRUE Signature Algorithm: sha256WithRSAEncryption 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00: 00:00:00:00:00:00:00:00:00:00:00:00:00:00:00
Let´s try to issue a certificate / sign a certificate request (CSR).
I have generated a cert signing request (.CSR) at a Cisco switch, saved it as certreq.csr on my local computer, uploaded the file to the tmp directory on the firewall and moved it to the myca directory.
The CSR file have the format below (It´s not the true cert request displayed):
[2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: mv /tmp/certreq.csr . [2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: more certreq.csr -----BEGIN CERTIFICATE REQUEST----- MIIBsDCsdfjsadfkqwrjh23y8rfasdjh238ryhwfsdvjkcuwFGAGUISDUIWAefr823riHwERYHWUIAETHAHEG823TU HWEGAHIF923t4uwegoisdv09342qthciovjergsadfUJKDSKJSFMAFJHUTIEGKNDSKNUTJKEDPKFIJEDYUGEYIY89Y FDTSDFKj89YSFOISDHFSDoGUHGYw==u597y6FtGTuFD2ShtJEU18rI+CYw== -----END CERTIFICATE REQUEST-----
This CSR is problematic because the request have no line shifts. OpenSSL expects a maximum line length of 64 characters. Vi need to format the request using a command like fold or just edit the file in vi and insert line shifts manually. I inserted line shifts after 40 characters to make it more visible in this tutorial.
-----BEGIN CERTIFICATE REQUEST----- MIIBsDCsdfjsadfkqwrjh23y8rfasdjh238ryhwf sdvjkcuwFGAGUISDUIWAefr823riHwERYHWUIAET HAHEG823TUHWEGAHIF923t4uwegoisdv09342qth ciovjergsadfUJKDSKJSFMAFJHUTIEGKNDSKNUTJ KEDPKFIJEDYUGEYIY89YFDTSDFKj89YSFOISDHFS DoGUHGYw==u597y6FtGTuFD2ShtJEU18rI+CYw== -----END CERTIFICATE REQUEST-----
Let´s issue the certificate, i.e. sign the certificate signing request/CSR.
[2.2.4-RELEASE][x@fw.lan.x]/etc/ssl: openssl ca -extensions usr_cert -notext -md sha256 -in certreq.csr -out newcert.pem Using configuration from /etc/ssl/openssl.cnf Check that the request matches the signature Signature ok Certificate Details: Serial Number: 4097 (0x1001) Validity Not Before: Nov 1 08:40:41 2015 GMT Not After : Oct 31 08:40:41 2016 GMT Subject: countryName = NO stateOrProvinceName = Xx organizationName = Xx organizationalUnitName = Xx commonName = sw1.lan.x.x X509v3 extensions: X509v3 Basic Constraints: CA:FALSE X509v3 Key Usage: Digital Signature, Non Repudiation, Key Encipherment Netscape Comment: OpenSSL Generated User Certificate X509v3 Subject Key Identifier: AA:74:CE:32:31:9E:01:12:CE:D0:51:FC:CE:46:40:6A:A1:75:45:0D X509v3 Authority Key Identifier: keyid:FF:CE:28:43:01:85:EF:27:CE:73:99:18:04:99:3E:AE:7C:D4:B7:4A DirName:/C=XX/ST=Xx/L=Xx/O=Xx/emailAddress=x@x.x/CN=ca.x.x serial:00 X509v3 Extended Key Usage: TLS Web Client Authentication Certificate is to be certified until Oct 31 08:40:41 2016 GMT (365 days) Sign the certificate? [y/n]:y 1 out of 1 certificate requests certified, commit? [y/n]y Write out database with 1 new entries Data Base Updated
That´s it. We have managed to issue a new certificate and stored it in the file newcert.pem. This certificate can be downloaded from the firewall and installed on the Cisco switch.
If you are getting errors issuing a certificate, it´s usually that directory and/or filenames don´t match with the configuration in the openssl.cnf file.Or the CSR file have lines longer than 64 characters. Or you are violating the policy match in the openssl.cnf file. Like requesting a certificate for country=NO and the CA have Country=US and the configuration have match for countryName.
# For the CA policy [ policy_match ] countryName = match stateOrProvinceName = match organizationName = match organizationalUnitName = optional commonName = supplied emailAddress = optional
You can check the content of any CSR, with the command:
openssl req -text -noout -verify -in <csr file>
This command is nice to use if you need to issue a public certificate from a trusted root CA provider. Check the request before you commit it and paying for the certificate.
And you can check a base64 encoded certificate file with the command:
openssl x509 -in <cert-file> -text -noout
PS. Since this “tutorial” describes unsupported pfSense use, openssl.cnf and demoCA folder may be overwritten when the firewall software is updated. The only change we made however, is basically changing the pointer to the openssl base directory. It´s easy to change it back if the file is overwritten. But if you are doing more alterations in the configuration file, make a backup copy. The directory myca, or what you may call it, should not be deleted during the firewall updates.
If you choose to install openssl locally on your computer, it’s the same procedure and configuration. Even on the Microsoft Windows platform, the configuration file using the slash / as a directory delimiter.
And remember, your CA is not a trusted CA on your devices. To trust certificates issued by your CA, your CA certificate needs to be imported on your devices as a trusted root CA.