Howto create a Root CA certificate and sign your own web certificates - jbilander/HowTos GitHub Wiki
Howto create a Root CA certificate and sign your own (localhost) web certificates
Using OpenSSL:
- Create the private key for your Root CA:
jbilander@apollo:~$ sudo -s
root@apollo:~#
root@apollo:~# cd /etc/ssl/private/
root@apollo:/etc/ssl/private# openssl genrsa -des3 -out myCA.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
......+++++
............+++++
e is 65537 (0x010001)
Enter pass phrase for myCA.key:
Verifying - Enter pass phrase for myCA.key:
root@apollo:/etc/ssl/private#
root@apollo:/etc/ssl/private# ls -al
total 10
drwx--x--- 2 root ssl-cert 4 Dec 27 10:10 .
drwxr-xr-x 4 root root 5 Nov 2 20:27 ..
-rw------- 1 root root 1743 Dec 27 10:11 myCA.key
-rw-r----- 1 root ssl-cert 1708 Nov 28 2018 ssl-cert-snakeoil.key
- Generate a root certificate:
root@apollo:/etc/ssl/private# openssl req -x509 -new -nodes -key myCA.key -sha256 -days 7000 -out ../certs/myCA.pem
Enter pass phrase for myCA.key:
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) [AU]:SE
State or Province Name (full name) [Some-State]:Stockholm
Locality Name (eg, city) []:Stockholm
Organization Name (eg, company) [Internet Widgits Pty Ltd]:Local Ltd.
Organizational Unit Name (eg, section) []:Local Security Division
Common Name (e.g. server FQDN or YOUR name) []:Local Root CA
Email Address []:noreply@localhost
root@apollo:/etc/ssl/private#
- Verify the newly created root certificate looks ok:
root@apollo:/etc/ssl/private# openssl x509 -in ../certs/myCA.pem -text
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
3c:2c:c8:d4:c9:78:ac:91:e5:da:28:1f:1a:1b:58:1b:ff:8e:85:ab
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = SE, ST = Stockholm, L = Stockholm, O = Local Ltd., OU = Local Security Division, CN = Local Root CA, emailAddress = noreply@localhost
Validity
Not Before: Dec 27 09:30:26 2022 GMT
Not After : Feb 25 09:30:26 2042 GMT
Subject: C = SE, ST = Stockholm, L = Stockholm, O = Local Ltd., OU = Local Security Division, CN = Local Root CA, emailAddress = noreply@localhost
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:cc:4e:a7:d8:68:24:7e:66:c2:25:9e:8f:44:a7:
2c:03:47:8e:e5:9d:0d:bb:c9:7c:18:bc:09:fb:b6:
...
...
Congratulations, you’re now a CA.
Now we look at creating the certificate to be used with our website
- First create a configuration file to be used for our CSR (Certificate Signing Request)
Use Vim or Nano editor to create the file
certificate.cfg
, change the domain-names and IPs to whatever you want there. It should look similar to this when you are done:
root@apollo:/etc/ssl/private# more certificate.cfg
[req]
req_extensions = req_ext
distinguished_name = req_distinguished_name
prompt = no
[req_distinguished_name]
commonName=mydomainexample.org
[req_ext]
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = mydomainexample.org
DNS.3 = *.mydomainexample.org
IP.1 = 127.0.0.1
IP.2 = 192.168.1.19
IP.3 = 192.168.1.20
It should now look like this in your folder:
root@apollo:/etc/ssl/private# ls -al
total 23
drwx--x--- 2 root ssl-cert 5 Dec 28 10:04 .
drwxr-xr-x 4 root root 5 Nov 2 20:27 ..
-rw-r--r-- 1 root root 356 Dec 28 10:04 certificate.cfg
-rw------- 1 root root 1743 Dec 27 10:11 myCA.key
-rw-r----- 1 root ssl-cert 1708 Nov 28 2018 ssl-cert-snakeoil.key
root@apollo:/etc/ssl/private#
- Now create the certificate key:
root@apollo:/etc/ssl/private# openssl genrsa -out certificate.key 2048
or
root@apollo:/etc/ssl/private# openssl genrsa -des3 -out certificate.key 2048
note:
use -des3
flag if you want to encrypt the key, it's the recommended way to keep your key safe but can make config more challenging to get working since the pass-phrase must be handled by the server using the cert and key.
root@apollo:/etc/ssl/private# openssl genrsa -out certificate.key 2048
Generating RSA private key, 2048 bit long modulus (2 primes)
..............+++++
................................+++++
e is 65537 (0x010001)
root@apollo:/etc/ssl/private#
It should now look like this in your folder:
root@apollo:/etc/ssl/private# ls -al
total 27
drwx--x--- 2 root ssl-cert 6 Dec 28 10:27 .
drwxr-xr-x 4 root root 5 Nov 2 20:27 ..
-rw-r--r-- 1 root root 356 Dec 28 10:04 certificate.cfg
-rw------- 1 root root 1675 Dec 28 10:27 certificate.key
-rw------- 1 root root 1743 Dec 27 10:11 myCA.key
-rw-r----- 1 root ssl-cert 1708 Nov 28 2018 ssl-cert-snakeoil.key
root@apollo:/etc/ssl/private#
- Now create the CSR using the certificate.cfg
root@apollo:/etc/ssl/private# openssl req -config certificate.cfg -extensions req_ext -key certificate.key -new -out certificate.csr
It should now look something like this if you take a look at the csr-file:
root@apollo:/etc/ssl/private# more certificate.csr
-----BEGIN CERTIFICATE REQUEST-----
MIICyDCCAbACAQAwHjEcMBoGA1UEAwwTbXlkb21haW5leGFtcGxlLm9yZzCCASIw
DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAOFGOHnl0j5CQyAcM/WIQzAPpT4H
5dZYaipx9+jdjly4CiuCdW1a1rr0PA4LHNHC3dZMWudObMMQLSiwAU+zl3qyafct
yb/ol04R/TKk+wJBAKQM0riwgWJiBneNBDWOMCwMOIBsFe94yy38QHlvxzh1mC86
JQAwsjEQN4GyViA6kuoebwFLBuvUnY3aEiqp6bCcG4ipxjzZxhTbuunn43fEB691
XB3FriFLHbKVBGZLdbUMciyCus3Ogxizk7U+60bapfYNRXj/wWuDlXSrqLZsT53L
cFjMI2J4vcsxZLSNIPlI6AyENAwS7Df32g0n6GIMwbmwdQVF0DDAhBgtdRcCAwEA
AaBlMGMGCSqGSIb3DQEJDjFWMFQwUgYDVR0RBEswSYIJbG9jYWxob3N0ghNteWRv
bWFpbmV4YW1wbGUub3JnghUqLm15ZG9tYWluZXhhbXBsZS5vcmeHBH8AAAGHBMCo
AROHBMCoARQwDQYJKoZIhvcNAQELBQADggEBAI2/M1XcgGx3JxWCLno+O3GqnJhw
VYG1p7i7f/TYRsDS6SHtLeBx0O4PWEDa045eDTua4kRWqa3pmbFgWRRb0XOiGVfL
tnKg/bY1vKOaBovPueQL0q2UmfQsomQXrZ7WX3hymKAo9urS8YLpvL7wxpi2rhmg
KOYZYE9C8/aAMmLomfqarS5cW4OP+nXyIVAwUpKtNuj5NgIe1ClkEDCjjyP6ICNJ
US70wZqlifEq+n+PH+VBJDeYs6JoI3+cMoCR4aGcxPhjp90vhcPmKMI8ujR+0das
PyEXIWidvj6bO7vxlowzun7f4RF9t11iSRLvj9ITW/Oom3srWMQf3SY+Jl4=
-----END CERTIFICATE REQUEST-----
It should now look like this in your folder:
root@apollo:/etc/ssl/private# ls -al
total 32
drwx--x--- 2 root ssl-cert 7 Dec 28 10:37 .
drwxr-xr-x 4 root root 5 Nov 2 20:27 ..
-rw-r--r-- 1 root root 356 Dec 28 10:04 certificate.cfg
-rw-r--r-- 1 root root 1041 Dec 28 10:36 certificate.csr
-rw------- 1 root root 1675 Dec 28 10:27 certificate.key
-rw------- 1 root root 1743 Dec 27 10:11 myCA.key
-rw-r----- 1 root ssl-cert 1708 Nov 28 2018 ssl-cert-snakeoil.key
root@apollo:/etc/ssl/private#
- Now create a configuration file called
custom_openssl.cnf
that we will use when signing the CSR. Use Vim or Nano editor and put the content below in it... (change domain-names and IPs to whatever you want here):
root@apollo:/etc/ssl/private# more custom_openssl.cnf
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
extendedKeyUsage = serverAuth, clientAuth
subjectAltName = @alt_names
[alt_names]
DNS.1 = localhost
DNS.2 = mydomainexample.org
DNS.3 = *.mydomainexample.org
IP.1 = 127.0.0.1
IP.2 = 192.168.1.19
IP.3 = 192.168.1.20
- Now Sign the CSR with your Root CA cert:
root@apollo:/etc/ssl/private# openssl x509 -req -CA ../certs/myCA.pem -CAkey myCA.key -in certificate.csr -out certificate.crt -days 730 -CAcreateserial -extfile custom_openssl.cnf
Signature ok
subject=CN = mydomainexample.org
Getting CA Private Key
Enter pass phrase for myCA.key:
root@apollo:/etc/ssl/private#
Now take a look at the certificate we created and signed, and verify that it contains the X509v3 extensions with the Subject Alternative Names:
root@apollo:/etc/ssl/private# openssl x509 -in certificate.crt -text -noout
Certificate:
Data:
Version: 3 (0x2)
Serial Number:
74:05:65:92:2b:1b:65:67:93:8b:c2:f7:9b:dd:67:5f:0f:e5:57:1e
Signature Algorithm: sha256WithRSAEncryption
Issuer: C = SE, ST = Stockholm, L = Stockholm, O = Local Ltd., OU = Local Security Division, CN = Local Root CA, emailAddress = noreply@localhost
Validity
Not Before: Dec 28 10:42:32 2022 GMT
Not After : Dec 27 10:42:32 2024 GMT
Subject: CN = mydomainexample.org
Subject Public Key Info:
Public Key Algorithm: rsaEncryption
RSA Public-Key: (2048 bit)
Modulus:
00:e1:46:38:79:e5:d2:3e:42:43:20:1c:33:f5:88:
...
...
Exponent: 65537 (0x10001)
X509v3 extensions:
X509v3 Authority Key Identifier:
keyid:95:E4:62:D9:45:D0:4C:82:75:D5:E5:B8:40:B6:48:86:97:1A:E9:AF
X509v3 Basic Constraints:
CA:FALSE
X509v3 Key Usage:
Digital Signature, Non Repudiation, Key Encipherment, Data Encipherment
X509v3 Extended Key Usage:
TLS Web Server Authentication, TLS Web Client Authentication
X509v3 Subject Alternative Name:
DNS:localhost, DNS:mydomainexample.org, DNS:*.mydomainexample.org, IP Address:127.0.0.1, IP Address:192.168.1.19, IP Address:192.168.1.20
Signature Algorithm: sha256WithRSAEncryption
4f:26:88:99:b8:f7:37:c9:78:40:3e:28:43:9f:01:b0:62:9d:
...
...
It should now look like this in your folder:
root@apollo:/etc/ssl/private# ls -al
total 41
drwx--x--- 2 root ssl-cert 9 Dec 28 11:41 .
drwxr-xr-x 4 root root 5 Nov 2 20:27 ..
-rw-r--r-- 1 root root 356 Dec 28 10:04 certificate.cfg
-rw-r--r-- 1 root root 1452 Dec 28 11:42 certificate.crt
-rw-r--r-- 1 root root 1041 Dec 28 10:36 certificate.csr
-rw------- 1 root root 1675 Dec 28 10:27 certificate.key
-rw-r--r-- 1 root root 368 Dec 28 11:41 custom_openssl.cnf
-rw------- 1 root root 1743 Dec 27 10:11 myCA.key
-rw-r----- 1 root ssl-cert 1708 Nov 28 2018 ssl-cert-snakeoil.key
Certificate and its corresponding key ready to be used, let's copy them over together with the Root CA cert and try it in a Windows machine.
Make a folder certs
in your home folder so we can use scp to copy them with the WinSCP client:
root@apollo:/etc/ssl/private# mkdir /home/jbilander/certs
root@apollo:/etc/ssl/private# cp certificate.crt certificate.key ../certs/myCA.pem /home/jbilander/certs/
root@apollo:/etc/ssl/private# cd /home/jbilander/certs/
root@apollo:~/certs# ls -al
total 23
drwxr-xr-x 2 root root 5 Dec 28 11:48 .
drwxr-xr-x 16 jbilander jbilander 46 Dec 28 11:48 ..
-rw-r--r-- 1 root root 1452 Dec 28 11:48 certificate.crt
-rw------- 1 root root 1675 Dec 28 11:48 certificate.key
-rw-r--r-- 1 root root 1513 Dec 28 11:48 myCA.pem
Make sure you set the correct owner of the files so that we are allowed to copy them.
root@apollo:~/certs# chown jbilander:jbilander *
root@apollo:~/certs# ls -al
total 23
drwxr-xr-x 2 root root 5 Dec 28 11:48 .
drwxr-xr-x 16 jbilander jbilander 46 Dec 28 11:48 ..
-rw-r--r-- 1 jbilander jbilander 1452 Dec 28 11:48 certificate.crt
-rw------- 1 jbilander jbilander 1675 Dec 28 11:48 certificate.key
-rw-r--r-- 1 jbilander jbilander 1513 Dec 28 11:48 myCA.pem
root@apollo:~/certs#
Using WinSCP to copy the files to a Windows machine (requires SSH-server to be running on the linux box)

Install the Root Certificate in your browser, e.g. for firefox:
Procedure:
Open the browser.
Click the Open menu button in the upper right corner.
Choose Options.
Open Privacy & Security tab.
Scroll down till Certificates section.
Click View Certificates… button.
In Certificate Manager window click on Import… ...
Navigate to the folder where the downloaded myCA.pem certificate is stored.
Add Root CA cert to Windows using certmgr.msc:
You can also add the Root CA cert to your Python installation (this requires that you have copied the certs and key to this folder first):
(DjangoEnv) C:\Users\Jorgen\Projects\Django2022.3\first_project>python
Python 3.6.13 |Anaconda, Inc.| (default, Mar 16 2021, 11:37:27) [MSC v.1916 64 bit (AMD64)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> import certifi
>>> certifi.where()
'C:\\Users\\Jorgen\\AppData\\Local\\conda\\conda\\envs\\DjangoEnv\\lib\\site-packages\\certifi\\cacert.pem'
>>> exit()
(DjangoEnv) C:\Users\Jorgen\Projects\Django2022.3\first_project>type myCA.pem >> c:\Users\Jorgen\AppData\Local\conda\conda\envs\DjangoEnv\Lib\site-packages\certifi\cacert.pem
You can now start for example Django dev server by using the certificate and key this way:
(DjangoEnv) C:\Users\Jorgen\Projects\Django2022.3\first_project>python manage.py runserver_plus localhost:8443 --cert-file certificate.crt --key-file certificate.key
Django version 3.2.16, using settings 'first_project.settings'
Development server is running at https://localhost:8443/
Using the Werkzeug debugger (http://werkzeug.pocoo.org/)
Quit the server with CTRL-BREAK.
* Debugger is active!
* Debugger PIN: 441-272-188
* Running on https://localhost:8443/ (Press CTRL+C to quit)
127.0.0.1 - - [28/Dec/2022 11:53:34] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [28/Dec/2022 11:53:34] "GET /static/admin/css/fonts.css HTTP/1.1" 200 -
127.0.0.1 - - [28/Dec/2022 11:53:34] "GET /static/admin/fonts/Roboto-Bold-webfont.woff HTTP/1.1" 200 -
127.0.0.1 - - [28/Dec/2022 11:53:34] "GET /static/admin/fonts/Roboto-Light-webfont.woff HTTP/1.1" 200 -
127.0.0.1 - - [28/Dec/2022 11:53:34] "GET /static/admin/fonts/Roboto-Regular-webfont.woff HTTP/1.1" 200 -
This above requires some configuration first (see here: https://stackoverflow.com/a/28933593 )
Now we can see that https is working in Firefox without any warnings:
And if we look at the certificate info we can see the Subject Alt Names is in there:
That's all folks, Happy Hackin'