Client and Server Certificates
Now that we have our IntermediateCA properly configured, we can start using it to issue certificates.
Notes:
- You should use no less than half the bits used on the CA for keys
- The server’s CN should be its FQDN
- A server certificate needs to have the same FQDN repeated on the SAN information
- The client certificate’s CN can be anything, it’s not important.
- Certificates must be signed by the IntermediateCA
- Certificates usually last a year (365 days) and the maximum, since July 2019, is 824 days (+1)
- OpenSSL command for server certificate:
-extensions server_cert
- OpenSSL command for client certificate:
-extensions usr_cert
- Only if
copy_extensions = copy
or= all
is on the[ca_default]
section ofintermediate/openssl.conf
can the CSR’s SAN information be transferred to the signed certificate; otherwise, the SAN information has to be reinserted when using the commandx509
to sign the CSR, so that it reaches the signed certificate. - 4 servers will be used:
- offline: has the RootCA
- server: has the CRLDistribution of the RootCA, the IntermediateCA and its certificates, and the IntermediateCA’s OCSP Responder
- www: will have an HTML server certified by the IntermediateCA
- client: will access the site on www
Example of server certificate: the PKI server’s own certificate
Start by creating a key; in this case you should omit the -aes256
or the -passout
option to avoid creating a password.
If there is a password, it will be necessary to introduce it whenever the webserver is started…
|
|
Generating RSA private key, 4096 bit long modulus (2 primes) ...............................................................................................................++++ ........................................................++++ e is 65537 (0x010001)
|
|
Create SAN information
It’s especially useful when the FQDN is fake or not available (e.g, there are no DNS records and you have to certify by IP address), but it’s become mandatory because now the certificates for Web Servers must to have the FQDN in a SAN entry, and having it only in the CN is no longer enough…
To do so, we have to create an extra .CNF file, containing only this information (which will be different for each server)
|
|
[req]
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no
[req_distinguished_name]
C = PT
ST = Lisboa
L = Lisboa
O = Tiago Joao Silva
OU = TJS
CN = server.tjs.lan
[req_ext]
subjectAltName = @alt_names
[alt_names]
IP.1 = 192.168.1.70
DNS.1 = server.tjs.lan
DNS.2 = dns.tjs.lan
DNS.3 = chat.tjs.lan
DNS.4 = mail.tjs.lan
Create the CSR
|
|
Confirm that the CSR has the SAN info:
|
|
X509v3 Subject Alternative Name: IP Address:192.168.1.70, DNS:server.tjs.lan, DNS:dns.tjs.lan, DNS:chat.tjs.lan, DNS:mail.tjs.lan
Sign the CSR
In case there’s no copy\_extensions = copy
or = all
in inter-ca/openssl.cnf
, you will need to reinsert SAN the information with the options -extensions req_ext
and -extfile aaa-san.cnf
|
|
Otherwise, if copy\_extensions = copy
or = all
is in inter-ca/openssl.cnf
, it’s a lot easier:
|
|
Using configuration from /root/ca/inter-ca/openssl.cnf Check that the request matches the signature Signature ok Certificate Details: Serial Number: 4100 (0x1004) Validity Not Before: Aug 22 23:54:31 2021 GMT Not After : Nov 23 23:54:31 2023 GMT Subject: countryName = PT stateOrProvinceName = Lisboa localityName = Lisboa organizationName = Tiago Joao Silva organizationalUnitName = TJS commonName = server.tjs.lan X509v3 extensions: X509v3 Basic Constraints: CA:FALSE Netscape Cert Type: SSL Server Netscape Comment: OpenSSL Generated Server Certificate X509v3 Subject Key Identifier: 94:00:E3:58:4F:BA:20:85:F7:9C:DC:47:3C:68:A1:46:8B:78:10:AF X509v3 Authority Key Identifier: keyid:E3:75:25:D7:74:08:0B:23:F0:AF:E4:EC:D0:D4:52:CB:5A:3A:10:2E DirName:/C=PT/ST=Lisboa/L=Lisboa/O=TiagoJoaoSilva/OU=TJS/CN=ca-tjs-1/emailAddress=bofh@tjs.lan serial:10:03 X509v3 Key Usage: critical Digital Signature, Key Encipherment X509v3 Extended Key Usage: TLS Web Server Authentication Authority Information Access: OCSP - URI:http://ocsp.tjs.lan:7888 Certificate is to be certified until Nov 23 23:54:31 2023 GMT (823 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
|
|
Verify the ChainOfTrust with the CA-CHAIN certificate
|
|
/root/ca/inter-ca/certs/server.tjs.lan.cert.pem: OK
Create a Chain/Bundle certificate for the webserver
Splice the Server certificate and the CA-CHAIN certificate:
|
|
Testing the CA
Set up a webserver
We need to create a new certificate for the webserver. Its IP will be 192.168.1.77
and its hostname www
|
|
[req]
distinguished_name = req_distinguished_name
req_extensions = req_ext
prompt = no
[req_distinguished_name]
C = PT
ST = Lisboa
L = Lisboa
O = Tiago Joao Silva
OU = TJS
CN = www.tjs.lan
[req_ext]
subjectAltName = @alt_names
[alt_names]
IP.1 = 192.168.1.77
DNS.1 = www.tjs.lan
|
|
To test, install a new Debian 11 system without GUI.
Edit the configuration of the desired interface (enp0s3
is the primary interface on VirtualBox; on VMware it’s ens33
)
|
|
iface enp0s3 inet static
address 192.168.1.77/24
gateway 192.168.1.1
|
|
Edit /etc/hosts
; in the second line, change to:
127.0.1.1 www.tjs.lan www
Verify:
|
|
www tjs.lan www.tjs.lan
Install the NGINX server
|
|
Check if the default page is being served:
|
|
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
body {
width: 35em;
margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif;
}
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br>/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Bring the webserver’s Chain/Bundle certificate to the webserver e put it on a place that is not affected by system updates, like a local-certs
folder in /etc/ssl/
|
|
Also bring the private key associated with the webserver’s certificate and put it in /etc/ssl/private/
|
|
Change the NGINX configuration to automatically redirect port 80 (HTTP) requests to port 443 (https), and point to the the webserver’s certificate and key
|
|
From line 21:
|
|
Note that we haven’t closed the braces, because the default configuration continues for a few more lines and the braces close below this point.
|
|
--2021-08-24 21:45:45-- http://localhost/ Resolving localhost (localhost)... ::1, 127.0.0.1 Connecting to localhost (localhost)|::1|:80... connected. HTTP request sent, awaiting response... 301 Moved Permanently Location: https://www.tjs.lan/ [following] --2021-08-24 21:45:45-- https://www.tjs.lan/ Resolving www.tjs.lan (www.tjs.lan)... 127.0.1.1 Connecting to www.tjs.lan (www.tjs.lan)|127.0.1.1|:443... connected. ERROR: The certificate of ‘www.tjs.lan’ is not trusted. ERROR: The certificate of ‘www.tjs.lan’ doesn't have a known issuer.
wget
to www.tjs.lan
doesn’t trust the server certificate because it’s doesn’t know the RootCA’s certificate.
Open ports 80 and 443 on the firewall
|
|
Test the WebServer
Set up a GUI client (for example, a Debian 11 with MATE).
Name resolution
As we don’t have a DNS server with the tjs.lan zone nor records for all these systems, add the following to the /etc/hosts
on the three systems (server, www and client)
# printf "\
#tjs.lan\n\
192.168.1.70 server.tjs.lan server\n\
192.168.1.70 ocsp.tjs.lan ocsp\n\
192.168.1.77 www.tjs.lan www \n" \
>> /etc/hosts
Install the root certificate on the end-user
Import the RootCA’s certificate to the current user’s home.
Open Firefox, Preferences, Privacy and Security, View Certificates…
Or (about:preferences#privacy)
Import…
Pick the RootCA’s certificate, Open
✓ Trust this CA to identify websites
✓ Trust this CA to identify email users (optional)
OK
Clicking on View, the certificate’s details are shown
The Root Authority has been imported, OK
Test the site
Open http://www.tjs.lan
(it may be necessary to tell Firefox that we really want to go to that address), and we have an SSL connection protected with our certificate:
Configure OCSP Stapling
Source: https://www.digitalocean.com/community/tutorials/how-to-configure-ocsp-stapling-on-apache-and-nginx
Bring the RootCA’s certificate to the webserver:
|
|
Add the following lines to NGINX’s active site (we were using /etc/nginx/sites-available/default
), below ssl_certificate_key
:
|
|
Testing
From the client, test the OCSP stapling process with the following command, not forgetting to indicate the CA certificate (which we left in the user’s homefolder when we imported it into Firefox); if you deleted it, you need to bring it back to the client so that it can be used now:
|
|
Revocation with OSCP Responder
Stapling usually has a validity of 7 days, where the server caches the response and no longer contacts the OCSP to obtain signed confirmation of the validity of its certificate, and immediatly sends the previous response to the client.
This means that if we revoke the certificate now, only after 7 days will the customer refuse the WebServer’s certificate.
Unless, of course, the WebServer is restarted and loses any memory of the OCSP response …
Let’s revoke the WebServer’s certificate:
|
|
Using configuration from /root/ca/inter-ca/openssl.cnf Revoking Certificate 1007. Data Base Updated
Restart the ocsp service, so that it updates itself with the new CRL
|
|
Restart the nginx service on www, to drop the OCSP Stapling cache
|
|
|
|
CONNECTED(00000003) depth=2 C = PT, ST = Lisboa, L = Lisboa, O = TiagoJoaoSilva, OU = TJS, CN = ca-tjs-1, emailAddress = bofh@tjs.lan verify return:1 depth=1 C = PT, ST = Lisboa, O = TiagoJoaoSilva, OU = TJS, CN = inter-ca-tjs-2, emailAddress = bofh@tjs.lan verify return:1 depth=0 C = PT, ST = Lisboa, L = Lisboa, O = Tiago Joao Silva, OU = TJS, CN = www.tjs.lan verify return:1 OCSP response: no response sent
Check that clients read the certificate as revoked
When we try to load www.tjs.lan
on Firefox, we’re told that the certificate was revoked:
Issue a new certificate to replace the revoked one
If you are following the tutorial in order, it’s best to issue a new certificate for www.tjs.lan
before proceeding.
www
server information changed, your CSR remains valid, and so it’s only necessary to repeat the steps from the CSR signature onwards. If the private key had been compromised, it would be necessary to issue a new certificate for www
from scratch.
Put it in the appropriate place on www.tjs.lan
, restart NGINX, and test again if the client can access the server’s webpage:
Revoke the IntermediateCA
To revoke the IntermediateCA (let’s assume that someone left the private key of the IntermediateCA in a public GitHub repository), we have to go back to the RootCA, which is offline, and follow the steps described in the corresponding section:
|
|
Using configuration from /root/ca/openssl.cnf Revoking Certificate 1003. Data Base Updated
Update the CRL and convert it to DER, following the previously shown steps:
|
|
You can see the updated CRL has a new entry:
|
|
Certificate Revocation List (CRL): Version 2 (0x1) Signature Algorithm: sha512WithRSAEncryption Issuer: C = PT, ST = Lisboa, L = Lisboa, O = TiagoJoaoSilva, OU = TJS, CN = ca-tjs-1, emailAddress = bofh@tjs.lan Last Update: Aug 25 20:50:52 2021 GMT Next Update: Sep 14 20:50:52 2022 GMT CRL extensions: X509v3 Authority Key Identifier: keyid:01:F2:CC:54:E0:F2:58:AC:E2:14:8E:2B:DB:6D:B6:FF:5C:25:41:A0 X509v3 CRL Number: 4098 Revoked Certificates: Serial Number: 1001 Revocation Date: Aug 13 22:11:25 2021 GMT CRL entry extensions: X509v3 CRL Reason Code: Unspecified Serial Number: 1002 Revocation Date: Aug 13 23:41:51 2021 GMT CRL entry extensions: X509v3 CRL Reason Code: Superseded Serial Number: 1003 Revocation Date: Aug 25 20:45:54 2021 GMT CRL entry extensions: X509v3 CRL Reason Code: Key Compromise
Bring the updated CRL from offline to online
Using a safe medium that doesn’t break the airgapping of the RootCA’s system, take the CRL file to the server hosting the RootCA’s CRLDistribution:
|
|
To empty the OCSP Stapling’s cache, restart the webserver if we want the revocation to be immediately recognized:
|
|
Test the IntermediateCA’s revocation
On modern browsers (fails)
The site is still considered trusted, because apparently browsers do not bother to check the entire chain of certificates (not even by OCSP), relying only on the internal lists of RootCAs and CRLs distributed with browser updates.
The only exception seemed to be good old Internet Explorer, may it rest in pieces, which we’ll try right away.
https://news.netcraft.com/archives/2013/05/13/how-certificate-revocation-doesnt-work-in-practice.html
And I can’t find an openssl verify
command that can indicate that the certificate chain www.tjs.lan.cert_chain.pem
is broken by the revocation of the IntermediateCA
(https://stackoverflow.com/questions/25482199/verify-a-certificate-chain-using-openssl-verify)
PKI usage in browsers takes many shortcuts, or so it seems…
On Internet Explorer
To test with Internet Explorer, we need a Windows client, so I provisioned a Windows 7 VM.
Import the RootCA’s Certificate:
Bring the RootCA’s certificate to the Windows client and save it as ca.cert.cer
)
Win+R, certmgr.msc
Select Trusted Root Certification Authorities/Certificates
All Tasks > Import…
Pick the certificate (Browse…)
Confirm that we want to install in Trusted Root
Yes
And it’s installed.
hosts file
Now we need to put the same information in the hosts
file because we still don’t have DNS:
Open Notepad as Administrator (right-click on Notepad, Run as administrator)
Open the %SystemRoot%\System32\drivers\etc\hosts
file
Paste:
#tjs.lan
192.168.1.70 server.tjs.lan server
192.168.1.70 ocsp.tjs.lan ocsp
192.168.1.77 www.tjs.lan www
Save the file and close Notepad.
Opening our site on IE
Now we can test if IE checks whether the InterCA that signed the certificate of our site was revoked:
And the answer is yes, Internet Explorer queries and respects an internal PKI, instead of just trusting the public PKI information used on the Internet at large.