Creating an offline certificate authority using OpenSSL and Creating trust with Group Policy

Build the system:

I use centos6 minimal CD.
I created an encrypted physical LVM to encompass /, /home, and the swap as described previously.
There is some hardening addition hardening that you can do later.

Offline vs. Online:

Due to the nature of what one can do with the power of a trusted CA, I am not a fan of online CAs. Others think that offline CAs an ancient idea.

I’m not going to become a victim of an argument focusing on how systems and active directory aren’t secure if someone can access your GPOs and push out trusted CAs to your clients; kerberos key distribution is already online; and what about AD in general… that has to be online, doesn’t it?

Offline === Offline. What’s the best risk reduction procedure? If something doesn’t exist then there is no risk. So just focus on physical security of the system, and the physical security of the CA private key and you are good to go!


Harden the install:
You may choose to do this before or after you have finished setting up the CA. The main purpose of this is to make sure that your private key is very secure.

Restrict root logons by physical console only:

echo "tty1" > /etc/securetty
chmod 700 /root

Set a logout timeout of one minutes:

echo "TMOUT=60" >> /etc/bashrc
echo "readonly TMOUT &> /dev/null" >> /etc/bashrc
echo "export TMOUT &> /dev/null" >> /etc/bashrc

Clear command history on logout:

echo "echo > ~/.bash_history" >> /etc/bash.bash_logout
echo "history -c" >> /etc/bash.bash_logout

Configure the CA directory structure and some configuration files:

mkdir -m 0700 /root/ca /root/ca/certs /root/ca/crl /root/ca/newcerts /root/ca/private
touch /root/ca/index.txt
echo 00 > /root/ca/crlnumber
echo 1000 > /root/ca/serial
sed s@"/etc/pki/CA"@"/root/ca"@g -i /etc/pki/tls/openssl.cnf
sed s@"$dir/crl.pem"@"$dir/crl/crl.pem"@g -i /etc/pki/tls/openssl.cnf
echo "crlDistributionPoints=URI:http://CRLSERVER/janus.crl" > /root/ca/opensslx509.conf

Generate the Root CA certificate/key pair:
The first step is to generate a private key and the public key. “Key” is synonymous with certificate.

openssl genrsa -des3 -out /root/ca/private/cakey.pem 4096
chmod 400 /root/ca/private/cakey.pem
openssl req -new -x509 -extensions v3_ca -key /root/ca/private/cakey.pem -out /root/ca/cacert.pem -days 3650 #ten year long Root CA public certificate

Securely backup /root/ca/private/cakey.pem. As in, guard it with your life. This is the stamp-of-approval for all certificates you are signing going forward. Some people store this on encrypted media, like a removable USB thumbdrive that is itself encrypted.

Creating a CRL distribution point:

One of the problems I came across when researching this implementation was that most of the technical write ups are not clear about a very important point, distributing the certificate revocation list. So, I will discuss CRLs and configuring a CRL distribution point before we generate our CA certificates.

If you were to roll out a CA on Windows server, you would see that there are two CRL distribution points:

One that’s served within the Active Directory LDAP, and is an octet string value (aka hex):


The other is via an HTTP URL:


I will simply be using HTTP and be presenting the CRL via a URL as http://CRLSERVER/ca.crl.
If you do not have an HTTP server, please configure one, or use `openssl s_server` (but not on this box, since it’s offline). It’s worth noting that it is up to the clients to check the CRL as they wish, but they hopefully will all time and the complete URI of your CRL should always be accessible. If the original server goes away, no worries; just use a CNAME and/or filter on HTTP HEADER content or some other magic. Just make sure that the CRL is available at the path you’ve described.
Note that the CRL is public knowledge and doesn’t need to be secured (not that I’m implying that the web server doesn’t, just the file itself).

We will be creating a very simple config file for use with the `openssl x509 -extfile` parameter.

echo "crlDistributionPoints=URI:http://CRLSERVER/ca.crl" > /root/ca/opensslx509.conf

Copy the public certificate to a DC to distribute via GPO:

1) Copy the /root/ca/certs/ca.cer or the contents to a DC.
2) Open gpmc.msc and navigate to:

Computer Configuration/Policies/Windows Settings/Security Settings/Public Key Policies/Trusted Root Certification Authorities

3) Right-click and import ca.cer into “Trusted Root Certification Authorities.” This will push the CA to the local stores of any target clients.

Sign a certificate request (producing a certificate which includes the CRL):

openssl ca -days 3650 -extfile /root/ca/opensslx509.conf -out /root/ca/certs/therequestorscert.cer -in ~/therequest.csr

Do not delete generated certificates from your server. Copy them to the destination.

Revoke a certificate and create a new CRL:
In order to maintain a proper CRL, all the issued certs should remain on your server.

openssl ca -revoke /root/ca/certs/therequestorscert.cer -keyfile /ca/private/cakey.pem -cert /root/ca/certs/ca.cer #revoke the certificate
if [[ $(cat /root/ca/crlnumber) =~ ^[0-9]+$ ]]; then export crlvernumber=$(/root/ca/crlnumber); fi # /root/ca/crlnumber contains the version of the CRL
openssl ca -gencrl -crl_reason [unspecified, keyCompromise, CACompromise, affiliationChanged, superseded, cessationOfOperation, certificateHold, removeFromCRL] -keyfile /root/ca/private/cakey.pem -cert /root/ca/certs/ca.cer > /root/ca/crl/crl.$(/root/ca/crlnumber)
if [[ $(cat /root/ca/crlnumber) =~ ^[0-9]+$ ]]; then echo $(($(cat /root/ca/crlnumber)+1)); else cat /root/ca/crlnumber; fi > /root/ca/crlnumber #increments /root/ca/crlnumber after to process as to avoid writing older CRLs

You can then copy the crl to the location issued within all the certificates: http://CRLSERVER/ca.crl
For more CRL generation settings, see the man page.


  1. Dave
    November 13, 2017 at 10:58 pm

    This is a nice write-up, thanks. I need to research the offline/online question. I have wanted to use the offline OpenSSL Root CA used to sign an online Windows Intermediate CA model for a while now, but I’ve been perplexed by the CRL question.

    How often do I need to update the CRL? Can it be internally accessible only or also FQDN resolvable when a laptop for example is outside of the LAN (I’ve seen that some folks publish their CRL on their domain to address this).

    Since this is a CA intended for signing internal hosts only, does publishing an internet accessible CRL leak data about how my internal LAN is configured? Paranoia or NBD?

    Finally does the CRL publishing need to be scheduled/automated somehow? I think the CRL needs to have a somewhat short lifespan based on some reading I’ve done so that if you do need to revoke a cert, systems will realize the old one is revoked in an “appropriate” amount of time; which of course appears to be on a case by case, as needed basis.

    If there ever was a process that resulted in “the devil being in the details”, THIS IS IT!!!

    • November 14, 2017 at 8:14 am

      Happy you found this useful. There’s a decent MSFT MVP blog post about offline CAs being a fallacy:

      Basically, the MVP is stating that whatever security mitigations that are provided by putting a CA offline are superseded with modern technology. I don’t agree, mostly, some what. Imagine the scenario where your Sub-CA gets compromised because it isn’t airgapped. If 99.9% of your trusted certs are issued from Sub-CA, then you’re in the same situation; so you must airgap all root CAs and Sub-CAs, or you may as well not airgap any (this is my opinion). But then again, I’m not a CA architecture scholar. Also, your Windows AD CA won’t sign certs requested by clients automatically if it’s inaccessible by those clients… maybe just restrict how you manage your CA, harden it down and audit access, and toss a HIDS on there, and review access logs.

      You’re asking about the security implications of publishing a CRL publicly: ‘A Certificate Revocation List (or CRL) is “a list of digital certificates that have been revoked by the issuing Certificate Authority (CA) before their scheduled expiration date and should no longer be trusted.”‘ ( No, it does not leak any information other than information you want it to leak, which is the List of Certificates that have been Revoked.

      Your CRL should be published when you make a change to it that you want reflected to clients that feel like checking the CRL. No publish == no sharing of the change. Also, consider what information is in the CRL (maybe certificates issued contain host names). Beyond that, MSFT CAs don’t like outdated CRLs.

      Checking CRLs, like checking the validity of certificates, is client optional.

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: