Create your own Certificate Authority
This how-to is based on jamielinux.com.
Attachments can be downloaded here
Steps described in this document:
- Creating a new, self-signed root CA from scratch
- Create an intermediate CA using the root CA
- Sign a server certificate
- Sign a client certificate
- Create a certificate revocation list (CRL)
- Setup an OCSP responder behind an Apache proxy
- Deploy certificates onto Apache webserver
- Perform a number of tests using a browser
Setup Root CA
The root CA certificate only to sign other certificate authority certificates.
Prepare the Root CA directory
Setup a directory where everything related to the CA is managed.
mkdir -p /root/DemoCA/root
cd /root/DemoCA/root
mkdir certs csr crl newcerts private
chmod 700 private
touch index.txt
echo 1000 > serial
wget -O openssl.cnf "https://andre.bytesare.us/ca-demo-files/root-openssl.cnf"
Self-sign the root ca certificate
Using our openssl.cnf’s [ v3_ca ]
extension:
cd /root/DemoCA/root
openssl genrsa -aes256 -out private/ca.key.pem 4096
openssl req -config openssl.cnf -key private/ca.key.pem -new -x509 -days 7300 -sha256 -extensions v3_ca -out certs/ca.cert.pem
# Subject: `C = AT, ST = Vienna, O = BytesAreUs GmbH, OU = BytesAreUs GmbH Certificate Authority, CN = BytesAreUs GmbH Root CA`
# Check:
openssl x509 -noout -text -in certs/ca.cert.pem
Setup an intermediate CA
Used for signing end-user certs.
Prepare the intermediate CA directory as below.
mkdir /root/DemoCA/intermediate-1
cd /root/DemoCA/intermediate-1
mkdir certs crl csr newcerts private
chmod 700 private
touch index.txt
touch index.txt.attr
echo 1000 > serial
echo 1000 > crlnumber
wget -O openssl.cnf "https://andre.bytesare.us/ca-demo-files/intermediate-openssl.cnf"
Add/Modify these lines to the [ server_cert ] section in /root/ca/intermediate/openssl.cnf
to specify CRL and OCSP Urls.
crlDistributionPoints = URI:http://ca-demo.bytesare.us/intermediate-1.crl.pem
authorityInfoAccess = OCSP;URI:http://ca-demo.bytesare.us/ocsp/intermediate-1
Create the intermediate certificate
Using our openssl.cnf’s [ v3_intermediate_ca ]
extension:
# Create csr:
cd /root/DemoCA/intermediate-1
openssl genrsa -aes256 -out private/intermediate-1.key.pem 4096
openssl req -config openssl.cnf -new -sha256 -key private/intermediate-1.key.pem -out csr/intermediate-1.csr.pem
# Subject: `C = AT, ST = Vienna, O = BytesAreUs GmbH, OU = BytesAreUs GmbH Certificate Authority, CN = BytesAreUs GmbH Intermediate CA 1`
# Sign csr with the root CA:
cd /root/DemoCA/root
openssl ca -config openssl.cnf -extensions v3_intermediate_ca -days 3650 -notext -md sha256 -in ../intermediate-1/csr/intermediate-1.csr.pem -out ../intermediate-1/certs/intermediate-1.cert.pem
# Check:
cd /root/DemoCA/intermediate-1
openssl x509 -noout -text -in certs/intermediate-1.cert.pem # check manually
openssl verify -CAfile ../root/certs/ca.cert.pem certs/intermediate-1.cert.pem
cat certs/intermediate-1.cert.pem ../root/certs/ca.cert.pem > certs/ca-chain.cert.pem
Create a server certificate
Using our openssl.cnf’s [ server_cert ]
extension:
cd /root/DemoCA/intermediate-1
openssl genrsa -aes256 -out private/ca-demo.bytesare.us.key.pem 2048
openssl req -config openssl.cnf -key private/ca-demo.bytesare.us.key.pem -new -sha256 -out csr/ca-demo.bytesare.us.csr.pem
# Subject: `C = AT, ST = Vienna, O = BytesAreUs GmbH, OU = Web Services, CN = ca-demo.bytesare.us`
openssl ca -config openssl.cnf -extensions server_cert -days 375 -notext -md sha256 -in csr/ca-demo.bytesare.us.csr.pem -out certs/ca-demo.bytesare.us.cert.pem
# Check:
openssl x509 -noout -text -in certs/ca-demo.bytesare.us.cert.pem
openssl verify -CAfile certs/ca-chain.cert.pem certs/ca-demo.bytesare.us.cert.pem
(Optional) Create and revoke another server certificate
For testing purposes, create a new server certificate with the same
name like the existing one. It is needed later to test the OCSP responder.
cd /root/DemoCA/intermediate-1
openssl genrsa -aes256 -out private/revoked.ca-demo.bytesare.us.key.pem 2048
openssl req -config openssl.cnf -key private/revoked.ca-demo.bytesare.us.key.pem -new -sha256 -out csr/revoked.ca-demo.bytesare.us.csr.pem
# Subject: `C = AT, ST = Vienna, O = BytesAreUs GmbH, OU = Web Services, CN = ca-demo.bytesare.us`
openssl ca -config openssl.cnf -extensions server_cert -days 375 -notext -md sha256 -in csr/revoked.ca-demo.bytesare.us.csr.pem -out certs/revoked.ca-demo.bytesare.us.cert.pem
# Check:
openssl x509 -noout -text -in certs/revoked.ca-demo.bytesare.us.cert.pem
openssl verify -CAfile certs/ca-chain.cert.pem certs/revoked.ca-demo.bytesare.us.cert.pem
Revoke the server cert:
cd /root/DemoCA/intermediate-1
openssl ca -config openssl.cnf -revoke certs/revoked.ca-demo.bytesare.us.cert.pem
Sign a client certificate
The client cert should be created in three steps without sending the key over the wire:
-
Client creates a CSR:
# mkdir /home/carl cd /home/carl openssl genrsa -out
This email address is being protected from spambots. You need JavaScript enabled to view it. 2048 openssl req -new -keyThis email address is being protected from spambots. You need JavaScript enabled to view it. -outThis email address is being protected from spambots. You need JavaScript enabled to view it. Subject: `C= AT, ST = Tirol, L = Innsbruck, CN = Carl the tester, emailAddress =This email address is being protected from spambots. You need JavaScript enabled to view it. ` cpThis email address is being protected from spambots. You need JavaScript enabled to view it. /tmp/ -
Then, client sends the CSR to the intermediate CA, who signs it.
Using our openssl.cnf’s
[ usr_cert ]
extension:cd /root/DemoCA/intermediate-1 cp /tmp/
This email address is being protected from spambots. You need JavaScript enabled to view it. csr/ openssl ca -config openssl.cnf -extensions usr_cert -notext -md sha256 -in csr/This email address is being protected from spambots. You need JavaScript enabled to view it. -out certs/This email address is being protected from spambots. You need JavaScript enabled to view it. cp certs/This email address is being protected from spambots. You need JavaScript enabled to view it. certs/ca-chain.cert.pem /tmp/ # Check: openssl verify -CAfile certs/ca-chain.cert.pem certs/This email address is being protected from spambots. You need JavaScript enabled to view it. -
CA returns certificate and chain to client
Who converts it into pkcs12 format to import it to his browser:
cd /home/carl cp /tmp/ca-chain.cert.pem /tmp/
This email address is being protected from spambots. You need JavaScript enabled to view it. . catThis email address is being protected from spambots. You need JavaScript enabled to view it. ca-chain.cert.pem >This email address is being protected from spambots. You need JavaScript enabled to view it. openssl pkcs12 -export -inkeyThis email address is being protected from spambots. You need JavaScript enabled to view it. -inThis email address is being protected from spambots. You need JavaScript enabled to view it. -outThis email address is being protected from spambots. You need JavaScript enabled to view it.
(Optional) Create and revoke another client cert
For negative testing the CRL later, sign another client cert and revoke it.
# mkdir /home/luzifer
cd /home/luzifer
openssl genrsa -out This email address is being protected from spambots. You need JavaScript enabled to view it. 2048
openssl req -new -key This email address is being protected from spambots. You need JavaScript enabled to view it. -out This email address is being protected from spambots. You need JavaScript enabled to view it.
Subject: `C= AT, ST = Tirol, L = Innsbruck, CN = Luzifer the Evil, emailAddress = This email address is being protected from spambots. You need JavaScript enabled to view it. `
cp This email address is being protected from spambots. You need JavaScript enabled to view it. /tmp/
cd /root/DemoCA/intermediate-1
cp /tmp/This email address is being protected from spambots. You need JavaScript enabled to view it. csr/
openssl ca -config openssl.cnf -extensions usr_cert -notext -md sha256 -in csr/This email address is being protected from spambots. You need JavaScript enabled to view it. -out certs/This email address is being protected from spambots. You need JavaScript enabled to view it.
cp certs/This email address is being protected from spambots. You need JavaScript enabled to view it. certs/ca-chain.cert.pem /tmp/
# Check:
openssl verify -CAfile certs/ca-chain.cert.pem certs/This email address is being protected from spambots. You need JavaScript enabled to view it.
cd /home/luzifer
cp /tmp/ca-chain.cert.pem /tmp/This email address is being protected from spambots. You need JavaScript enabled to view it. .
cat This email address is being protected from spambots. You need JavaScript enabled to view it. ca-chain.cert.pem > This email address is being protected from spambots. You need JavaScript enabled to view it.
openssl pkcs12 -export -inkey This email address is being protected from spambots. You need JavaScript enabled to view it. -in This email address is being protected from spambots. You need JavaScript enabled to view it. -out This email address is being protected from spambots. You need JavaScript enabled to view it.
Now, revoke luzifer’s certificate:
cd /root/DemoCA/intermediate-1
openssl ca -config openssl.cnf -revoke certs/This email address is being protected from spambots. You need JavaScript enabled to view it.
Create a CRL
CRL files are used to check if a certificate has been revoked (offline).
cd /root/DemoCA/intermediate-1
openssl ca -config openssl.cnf -gencrl -out crl/intermediate-1.crl.pem
# Check:
openssl crl -in crl/intermediate-1.crl.pem -text
cat certs/ca-chain.cert.pem crl/intermediate-1.crl.pem > /tmp/chain+crl.pem
openssl verify -crl_check -CAfile /tmp/chain+crl.pem certs/ca-demo.bytesare.us.cert.pem
openssl verify -crl_check -CAfile /tmp/chain+crl.pem certs/revoked.ca-demo.bytesare.us.cert.pem
Create an OCSP responder certificate
OCSP is used for online checking the revocation status of a certificate.
Create a signer certificate to sign the OCSP responses:
cd /root/DemoCA/intermediate-1
openssl genrsa -aes256 -out private/ocsp.key.pem 4096
openssl req -config openssl.cnf -new -sha256 -key private/ocsp.key.pem -out csr/ocsp.csr.pem
# Subject: `C = AT, ST = Vienna, O = BytesAreUs GmbH, OU = BytesAreUs GmbH Certificate Authority, CN = BytesAreUs OCSP Signer CA 1`
openssl ca -config openssl.cnf -extensions ocsp -days 375 -md sha256 -in csr/ocsp.csr.pem -out certs/ocsp.cert.pem
# Check:
openssl verify -CAfile certs/ca-chain.cert.pem certs/ocsp.cert.pem
openssl ocsp -url http://localhost:2560/ocsp -text -rmd sha256 -index index.txt -CA certs/ca-chain.cert.pem -rkey private/ocsp.key.pem -rsigner certs/ocsp.cert.pem -nrequest 2 | grep -e "Serial Number:" -e "Cert Status:" -e "Update:"
# (using a 2nd terminal)
cd /root/DemoCA/intermediate-1
openssl ocsp -CAfile certs/ca-chain.cert.pem -url http://localhost:2560/ocsp -issuer certs/intermediate-1.cert.pem -cert certs/ca-demo.bytesare.us.cert.pem
openssl ocsp -CAfile certs/ca-chain.cert.pem -url http://localhost:2560/ocsp -issuer certs/intermediate-1.cert.pem -cert certs/revoked.ca-demo.bytesare.us.cert.pem
Deploy and test the setup
To demonstrate the use of our CA, setup Apache with
- the server certificate
- an OCSP responder proxy for checking the server certificate
- a location that requires a client certificate
- a CRL file to check client certificates
Apache Configuration
Copy certificate material to a directory that apache user can access.
cd /root/DemoCA/intermediate-1
mkdir /etc/ssl/test-certs
cp certs/ca-chain.cert.pem certs/ca-demo.bytesare.us.cert.pem certs/revoked.ca-demo.bytesare.us.cert.pem private/ca-demo.bytesare.us.key.pem private/revoked.ca-demo.bytesare.us.key.pem crl/intermediate-1.crl.pem /etc/ssl/test-certs/
Apache needs the private key converted without a password,
otherwise the password has to be entered at every start.
cd /etc/ssl/test-certs/
openssl rsa -in ca-demo.bytesare.us.key.pem -out ca-demo.bytesare.us.nopass.key.pem
openssl rsa -in revoked.ca-demo.bytesare.us.key.pem -out revoked.ca-demo.bytesare.us.nopass.key.pem
chown root:www-data -R .
chmod 640 *
cp intermediate-1.crl.pem /var/www/html/
Setup your local system
We pretend to be ca-demo.bytesare.us
, and try it on the local machine.
Add the following line to your hosts file:
127.0.0.1 ca-demo.bytesare.us
Setup Apache
The proxy for the OCSP responder is set up on port 80
in /etc/apache2/sites-enabled/000-default.conf
:
<VirtualHost *:80>
ServerName ca-demo.bytesare.us
DocumentRoot /var/www/html
LogLevel info
ErrorLog ${APACHE_LOG_DIR}/demo-ca.http.error.log
CustomLog ${APACHE_LOG_DIR}/demo-ca.http.access.log combined
<Location /ocsp/intermediate-1>
ProxyPass http://127.0.0.1:2560/
</Location>
</VirtualHost>
The server certificate and the client crl and trusted ca is configured
in /etc/apache2/sites-enabled/default-ssl.conf
:
<IfModule mod_ssl.c>
<VirtualHost *:443>
ServerName ca-demo.bytesare.us
DocumentRoot /var/www/html-ssl
LogLevel info ssl:debug
ErrorLog ${APACHE_LOG_DIR}/demo-ca.ssl.error.log
CustomLog ${APACHE_LOG_DIR}/demo-ca.ssl.access.log combined
# Server certificate configuration:
SSLEngine on
SSLCertificateChainFile /etc/ssl/test-certs/ca-chain.cert.pem
#SSLCertificateFile /etc/ssl/test-certs/ca-demo.bytesare.us.cert.pem
#SSLCertificateKeyFile /etc/ssl/test-certs/ca-demo.bytesare.us.nopass.key.pem
SSLCertificateFile /etc/ssl/test-certs/revoked.ca-demo.bytesare.us.cert.pem
SSLCertificateKeyFile /etc/ssl/test-certs/revoked.ca-demo.bytesare.us.nopass.key.pem
# Client certificate configuration:
SSLCACertificateFile /etc/ssl/test-certs/ca-chain.cert.pem
SSLCARevocationFile /etc/ssl/test-certs/intermediate-1.crl.pem
SSLCARevocationCheck leaf
# Require a client cert (only) in /protected-area:
SSLVerifyClient none
<Location /protected-area>
SSLVerifyClient require
SSLVerifyDepth 10
</Location>
</VirtualHost>
</IfModule>
Restart apache
After the configuration has been changed.
apachectl configtest
systemctl restart apache2
Start the OCSP Responder process
And test the responder using the ca-demo.bytesare.us
domain routed through the Apache listenting on localhost.
cd /root/DemoCA/intermediate-1
openssl ocsp -url http://localhost:2560/ocsp -text -rmd sha256 -index index.txt -CA certs/ca-chain.cert.pem -rkey private/ocsp.key.pem -rsigner certs/ocsp.cert.pem > /var/log/apache2/demo-ca.ocsp.log
# Check if apache proxies ocsp correctly (in a second terminal)
cd /root/DemoCA/intermediate-1
openssl ocsp -CAfile /etc/ssl/test-certs/ca-chain.cert.pem -url http://ca-demo.bytesare.us/ocsp/intermediate-1 -issuer /etc/ssl/test-certs/ca-chain.cert.pem -cert /etc/ssl/test-certs/ca-demo.bytesare.us.cert.pem
Import the Intermediate CA certificate to a browser
In a company environment, the client administrator sets the root CA as trusted,
in our test case we will do this by hand in our browser only.
Copy cert chain to a readable location:
cd /root/DemoCA/intermediate-1
cp certs/ca-chain.cert.pem /tmp/
chmod +r /tmp/ca-chain.cert.pem
In firefox, open Settings
, goto Privacy and Security
, click on View Certificates
and open the tab Authorities
.
Then, import the ca-chain.pem
file to accept our CA. Check if the Intermediate CA has been added to the list after the import.
Import the client certificate to a browser
Copy client certs to a readable location:
cp /home/carl/This email address is being protected from spambots. You need JavaScript enabled to view it. /home/luzifer/This email address is being protected from spambots. You need JavaScript enabled to view it. /tmp/
chmod +r /tmp/*.cert.p12
In firefox, open Settings
, goto Privacy and Security
, click on View Certificates
and open the tab Your Certificates
.
Then, import the
file. Check if the client cert has been added to the list after the import.
Optionally, import the
file. Check if the client cert has been added to the list after the import.
Showtime: Perform connection tests with your browser
Look at the Apache logs while doing this:
tail -fn0 /var/log/apache2/demo-ca*.log /var/log/apache2/ocsp.log
1. Check the browser connection to the https page
Open up the test page, it should load without errors.
Check the server certificate next to the address bar visually.
You should see in your apache logs, that the browser has also sent an OCSP request to our responder.
==> /var/log/apache2/demo-ca.http.access.log <==
127.0.0.1 - - [22/Mar/2019:20:11:17 +0100] "POST /ocsp/intermediate-1 HTTP/1.1" 200 2594 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0"
==> /var/log/apache2/demo-ca.ssl.access.log <==
127.0.0.1 - - [22/Mar/2019:20:11:17 +0100] "GET / HTTP/1.1" 200 6163 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0"
2. Check browser connection with client cert
Open up the location that requires client authentication and use the imported client certificate named carl.
The logs show the successful CRL check:
==> /var/log/apache2/demo-ca.ssl.error.log <==
[Fri Mar 22 20:32:09.087400 2019] [ssl:debug] [pid 30421:tid 140481960511232] ssl_engine_kernel.c(1585): [client 127.0.0.1:36704] AH02275: Certificate Verification, depth 0, CRL checking mode: leaf (1) [subject: emailAddress=This email address is being protected from spambots. You need JavaScript enabled to view it. ,CN=Carl der Tester,L=Innsbruck,ST=Tirol,C=AT / issuer: CN=BytesAreUs GmbH Intermediate CA 1,OU=BytesAreUs GmbH Certificate Authority,O=BytesAreUs GmbH,ST=Vienna,C=AT / serial: 1001 / notbefore: Mar 22 16:13:37 2019 GMT / notafter: Mar 31 16:13:37 2020 GMT]
==> /var/log/apache2/demo-ca.ssl.access.log <==
127.0.0.1 - - [22/Mar/2019:20:32:06 +0100] "GET /protected-area/ HTTP/1.1" 200 13479 "https://ca-demo.bytesare.us/" "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0"
3. Check browser connection with a revoked client cert
Open up the location that requires client authentication and use the imported client certificate named luzifer.
The Browser refuses access indicating the revocation:
Secure Connection Failed
An error occurred during a connection to ca-demo.bytesare.us.
SSL peer rejected your certificate as revoked.
Error code: SSL_ERROR_REVOKED_CERT_ALERT
The server logs show an error 403 and the revocation error:
==> /var/log/apache2/demo-ca.ssl.error.log <==
[Fri Mar 22 20:36:53.040334 2019] [ssl:info] [pid 30421:tid 140481728079616] [client 127.0.0.1:36716] AH02276: Certificate Verification: Error (23): certificate revoked [subject: emailAddress=This email address is being protected from spambots. You need JavaScript enabled to view it. ,CN=Luzifer der Teufel,L=Innsbruck,ST=Tirol,C=AT / issuer: CN=BytesAreUs GmbH Intermediate CA 1,OU=BytesAreUs GmbH Certificate Authority,O=BytesAreUs GmbH,ST=Vienna,C=AT / serial: 1002 / notbefore: Mar 22 16:20:39 2019 GMT / notafter: Mar 31 16:20:39 2020 GMT]
[Fri Mar 22 20:36:53.040622 2019] [ssl:error] [pid 30421:tid 140481728079616] SSL Library Error: error:1417C086:SSL routines:tls_process_client_certificate:certificate verify failed
==> /var/log/apache2/demo-ca.ssl.access.log <==
127.0.0.1 - - [22/Mar/2019:20:36:49 +0100] "GET /protected-area/ HTTP/1.1" 403 11114 "https://ca-demo.bytesare.us/" "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0"
4. Check browser connection to a page with a revoked server cert
If you use the revoked server certificate on apache,
(just uncomment the two revoked.
lines in the apache config file and restart the server)
the browser will reject access because of the negative OCSP query.
Secure Connection Failed
An error occurred during a connection to
ca-demo.bytesare.us
.
Peer’s Certificate has been revoked.
Error code: SEC_ERROR_REVOKED_CERTIFICATE
The server logs show the start of a TLS handshake, then the negative OCSP Response.
No actual https response shows up, because the browser terminated the handshake:
==> /var/log/apache2/demo-ca.ssl.error.log <==
[Fri Mar 22 20:50:17.207959 2019] [ssl:info] [pid 32219:tid 140240362641152] [client 127.0.0.1:36828] AH01964: Connection to child 8 established (server ca-demo.bytesare.us:443)
[Fri Mar 22 20:50:17.224830 2019] [ssl:debug] [pid 32219:tid 140240362641152] ssl_engine_kernel.c(2067): [client 127.0.0.1:36828] AH02041: Protocol: TLSv1.2, Cipher: ECDHE-RSA-AES128-GCM-SHA256 (128/128 bits)
==> /var/log/apache2/demo-ca.http.access.log <==
127.0.0.1 - - [22/Mar/2019:20:50:17 +0100] "POST /ocsp/intermediate-1 HTTP/1.1" 200 2612 "-" "Mozilla/5.0 (X11; Linux x86_64; rv:67.0) Gecko/20100101 Firefox/67.0"
==> /var/log/apache2/demo-ca.ocsp.log <==
OCSP Response Data:
Produced At: Mar 22 19:50:17 2019 GMT
Certificate ID:
Serial Number: 1003
Cert Status: revoked
Revocation Time: Mar 22 16:25:49 2019 GMT
==> /var/log/apache2/demo-ca.ssl.error.log <==
[Fri Mar 22 20:50:17.262845 2019] [ssl:debug] [pid 32219:tid 140240362641152] ssl_engine_io.c(1103): [client 127.0.0.1:36828] AH02001: Connection closed to child 8 with standard shutdown (server ca-demo.bytesare.us:443)