Offline Root Certificate Authority - Linux
Every organization that has an Active Directory structure, or any other service that uses SSL/TLS services (ie. HTTPS, RDP, etc.), should have a certificate authority. This certificate authority is used to verify that you are indeed talking directly with the server you think you are and that the connection is secure. Having a certificate authority is also required to enable secure LDAP (LDAPS), though this can also be done with an external certificate authority.
Choosing to host your offline root CA on a Linux-based system, rather than Windows Server, will save you from licensing a server that will rarely be turned on.
Why have an offline Root CA?
If a root CA is in some way compromised (broken into, hacked, stolen, or accessed by an unauthorized or malicious person), then all of the certificates that were issued by that CA are also compromised. Since certificates are used for data protection, identification, and authorization, the compromise of a CA could compromise the security of an entire organizational network. For that reason, many organizations that run internal PKIs install their root CA offline. That is, the CA is never connected to the company network, which makes the root CA an offline root CA. Make sure that you keep all CAs in secure areas with limited access.1
– Microsoft TechNet
System Requirements
- Linux-based, single-purpose physical server
- You will need to be able to transfer files to and from this device via USB drive.
- We’ll be using Ubuntu 22.04 LTS Server for this example.
- This system will be used as an offline root CA, therefore it will be powered off after we’re done.
- USB drive formatted with ExFAT or FAT32 file system
Ensure OpenSSL is Installed
- Update the server
1
sudo apt update && sudo apt dist-upgrade -y
- Install OpenSSL (likely already installed)
1
sudo apt install -y openssl
At this point, there is no need for the server to be connected to the network. You should remove the network cable from the ethernet port. If this is a device with a wireless card, ensure it is not connected to the wireless or even remove the WLAN card.
Create Certificate Authority Directory Structure
- Create all directories that will be needed
1 2 3
cd /etc/ssl sudo mkdir -p root-ca/{private,newcerts,certs,crl,csr} sudo chmod 700 root-ca/private
-p
Create the parent directories if they don’t exist700
Set the permissions so that only the file owner can read/write(rwx------)
- Create needed database files
1 2 3 4
cd root-ca sudo openssl rand -out serial -hex 16 sudo openssl rand -out crlnumber -hex 16 sudo touch index
- Create the configuration file
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
sudo echo '[ca]
#/etc/ssl/root-ca/openssl.cnf
#see man ca
default_ca = CA_default
[CA_default]
dir = /etc/ssl/root-ca
certs = $dir/certs
crl_dir = $dir/crl
new_certs_dir = $dir/newcerts
database = $dir/index
serial = $dir/serial
RANDFILE = $dir/private/.rand
private_key = $dir/private/ca.key
certificate = $dir/certs/ca.crt
crlnumber = $dir/crlnumber
crl = $dir/crl/ca.crl
crl_extensions = crl_ext
default_crl_days = 397
default_md = sha256
name_opt = ca_default
cert_opt = ca_default
default_days = 397
preserve = no
policy = policy_loose
[ policy_strict ]
countryName = match
stateOrProvinceName = match
organizationName = match
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ policy_loose ]
countryName = optional
stateOrProvinceName = optional
localityName = optional
organizationName = optional
organizationalUnitName = optional
commonName = supplied
emailAddress = optional
[ req ]
# Options for the req tool, man req.
default_bits = 2048
distinguished_name = req_distinguished_name
string_mask = utf8only
default_md = sha256
# Extension to add when the -x509 option is used.
x509_extensions = v3_ca
[ req_distinguished_name ]
countryName = Country Name (2 letter code)
stateOrProvinceName = State or Province Name
localityName = Locality Name (City or Town)
0.organizationName = Organization Name (Company Name)
organizationalUnitName = Organizational Unit Name (Department)
commonName = Common Name (Descriptive Name)
emailAddress = Email Address
[ v3_ca ]
# Extensions to apply when createing root ca
# Extensions for a typical CA, man x509v3_config
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
basicConstraints = critical, CA:true
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ v3_intermediate_ca ]
# Extensions to apply when creating intermediate or sub-ca
# Extensions for a typical intermediate CA, same man as above
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid:always,issuer
# pathlen:0 ensures no more sub-ca can be created below an intermediate
basicConstraints = critical, CA:true, pathlen:0
keyUsage = critical, digitalSignature, cRLSign, keyCertSign
[ server_cert ]
# Extensions for server certificates
basicConstraints = CA:FALSE
nsCertType = server
nsComment = "OpenSSL Generated Server Certificate"
subjectKeyIdentifier = hash
authorityKeyIdentifier = keyid,issuer:always
keyUsage = critical, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth
[ crl_ext ]
# CRL extensions.
# Only issuerAltName and authorityKeyIdentifier make any sense in a CRL.
authorityKeyIdentifier=keyid:always' | sudo tee openssl.cnf
Create the Root CA Certificate
- Generate the new private key and certificate for the root CA
1
sudo openssl req -new -newkey rsa:4096 -x509 -config /etc/ssl/root-ca/openssl.cnf -extensions v3_ca -days 7300 -out certs/ca.crt -keyout private/ca.key
req
This is a certificate request-new
This is a new request for a certificate-newkey
The new private key will be a 4096-bit RSA key-x509
Generate a certificate (self-signed) instead of a certificate request-config
Location of the config file to use-extensions
Name of the extention to use (defined in the config file)-days
Length of certificate life in days (7300 days = 20 years)-out
Location of the new root CA certificate file-keyout
Location of the private key file for the root CA (Keep this safe!)
- Provide a password for the new root CA key (document this) and provide DN information. Only the Common Name field is required, but all are recommended.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
Enter PEM pass phrase: Verifying - Enter PEM pass phrase: ----- You are about to be asked to enter information that will be incorporated into your certificate request. What you are about to enter is what is called a Distinguished Name or a DN. There are quite a few fields but you can leave some blank For some fields there will be a default value, If you enter '.', the field will be left blank. ----- Country Name (2 letter code) []:US State or Province Name []:Full State Name Locality Name (City or Town) []:Your city Organization Name (Company Name) []:Your Organization Name Organizational Unit Name (Department) []:Your Department Name Common Name (Descriptive Name) []:Your Org Root CA Email Address []:
Do not lose the
ca.key
file or the password to it - Review the certificate you’ve created.
1
openssl x509 -in certs/ca.crt -text -noout
x509
This is a x509 certificate operation-in
The certficate file we’re examining-text
Display the certificate in text form-noout
Don’t display the certificate in base64 form
- The output of the above command should look similar to this:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19
Certificate: Data: Version: 3 (0x2) Serial Number: 2b:06:96:df:af:57:e8:c4:5e:74:0a:fc:24:c4:da:88:ae:42:21:a3 Signature Algorithm: sha256WithRSAEncryption Issuer: C = US, ST = North Carolina, L = RTP, O = MCNC, OU = CNE, CN = MCNC Root CA Validity Not Before: Jul 3 22:43:56 2022 GMT Not After : Jun 28 22:43:56 2042 GMT Subject: C = US, ST = North Carolina, L = RTP, O = MCNC, OU = CNE, CN = MCNC Root CA Subject Public Key Info: Public Key Algorithm: rsaEncryption Public-Key: (4096 bit) Modulus: 00:9c:2b:3f:e5:02:ee:4c:f4:ba:61:07:f0:63:a7: f7:30:26:5f:32:af:c8:38:20:93:1d:62:35:98:5e: 20:d4:17:e1:3f:db:86:c8:99:e3:69:75:1c:d2:99: ...
Generate the Certificate Revocation List
- Create the CRL and sign it using the root CA private
1
sudo openssl ca -config /etc/ssl/root-ca/openssl.cnf -gencrl -out crl/ca.crl
ca
This CA operation-config
Location of the config file to use-gencrl
Generate a certificate revocation list signed by the private key-out
File to save the CRL to
- You will be asked to provide the password for the root CA private key
1 2
Using configuration from /etc/ssl/root-ca/openssl.cnf Enter pass phrase for /etc/ssl/root-ca/private/ca.key:
Copy the Root CA Certificate and CRL from the Server
- Insert your USB drive
- Find the path to your device (all devices in Linux are represented by files)
1
sudo sfdisk -l
-l
List all devices
- My device was
/dev/sdb1
1 2 3 4 5 6 7 8 9 10
Disk /dev/sdb: 7.52 GiB, 8058306560 bytes, 15738880 sectors Disk model: USB Disk Units: sectors of 1 * 512 = 512 bytes Sector size (logical/physical): 512 bytes / 512 bytes I/O size (minimum/optimal): 512 bytes / 512 bytes Disklabel type: gpt Disk identifier: 730CBDED-473E-4991-9AF8-A6910A72F498 Device Start End Sectors Size Type /dev/sdb1 2048 15736831 15734784 7.5G Microsoft basic data
- Mount the USB Drive to the
/media
directory1
sudo mount /dev/sdb1 /media
- Copy the root CA certificate and CRL to the drive
1
sudo cp /etc/ssl/root-ca/certs/ca.crt /etc/ssl/root-ca/crl/ca.crl /media
- Unmount the USB drive before removing it
1
sudo umount /media
If creating a Windows Enterprise Subordinate CA, you will need both the
ca.crl
andca.crt
files to import into Active Directory
Shutdown and Store the Machine
You may now shutdown the server and store it. The only times the server will be needed are when you stand up a new subordinate (intermediate) certificate authority, or when a sub-CA needs its certificate renewed. Sub-CA’s should renew their certificates every ten years or so.