I used to create self-signed certificates, but they have the problem that I have to accept them the first time when using a browser, and when openssl library connects, I have to disable the certificate verification in curl, Node.js etc.
The proper fix is to create your own CA which your computers trust. Then signing certificates with this CA makes your computer trust those certificates. Luckily creating a CA is simple.
Note that all this is very insecure and should only be used for home use. For the real Internet, use Let’s Encrypt . I wish I could use the same for local certificates, alas this is not supported as Let’s Encrypt verifies DNS ownership.
Here the steps. See the original instructions by mrkiril which this is based on. And OpenSSL’s ca command (check the Warning section!). Also this includes plenty examples including something about the Java keytool.
1. Create your CA
You need 3 config files. First one: config_ssl_ca.cnf is for the CA.
[ req ]
default_bits = 2048
prompt = no
distinguished_name=req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
countryName=JP
stateOrProvinceName=Tokyo
localityName=Tama
organizationName=root organisation
organizationalUnitName=root department
commonName=Harald Kubota
emailAddress=harald.kubota@gmail.com
[ alternate_names ]
DNS.1 = t620.lan
[ v3_req ]
keyUsage=digitalSignature
basicConstraints=CA:true
subjectKeyIdentifier = hash
subjectAltName = @alternate_names
And this is how to create your CA certificate (self-signed):
mkdir CA
openssl genrsa -out ./CA/CA.key 4096
openssl req -new -x509 -key ./CA/CA.key -out ./CA/CA.crt -days 3650 -config config_ssl_ca.cnf
2. Create a CSR
Next one config_ssl.cnf is for generating a certificate sign request. The alternate_names should match the URL you use:
[ req ]
default_bits = 2048
prompt = no
distinguished_name=req_distinguished_name
req_extensions = v3_req
[ req_distinguished_name ]
countryName=JP
stateOrProvinceName=Tokyo
localityName=Home
organizationName=MyOrg
organizationalUnitName=Tech Department
commonName=Harald Kubota
emailAddress=harald.kubota@gmail.com
[ alternate_names ]
DNS.1 = web.lan
DNS.2 = web.net
IP.1 = 192.168.2.84
[ v3_req ]
keyUsage=digitalSignature
basicConstraints=CA:false
subjectAltName = @alternate_names
subjectKeyIdentifier = hash
Below is how to create a CSR. Note that “$x” is just a filename. The DNS name is in the previously mentioned config_ssl.cnf.
export x=web.lan
openssl genrsa -out "$x.key" 2048
openssl req -new -sha256 -key "$x.key" -config ./config_ssl.cnf -out "$x.csr"
3. Sign the CSR
And the last one config_ca.cnf to sign the CSR:
# we use 'ca' as the default section because we're using the ca command
[ ca ]
default_ca = my_ca
[ my_ca ]
# a text file containing the next serial number to use in hex. Mandatory.
# This file must be present and contain a valid serial number.
serial = ./CA/CA.srl
# the text database file to use. Mandatory. This file must be present though
# initially it will be empty.
database = ./CA/index.txt
# specifies the directory where new certificates will be placed. Mandatory.
new_certs_dir = ./
# the file containing the CA certificate. Mandatory
certificate = ./CA/CA.crt
# the file contaning the CA private key. Mandatory
private_key = ./CA/CA.key
# the message digest algorithm. Remember to not use MD5
default_md = sha256
# for how many days will the signed certificate be valid
default_days = 365
# a section with a set of variables corresponding to DN fields
policy = my_policy
# MOST IMPORTANT PART OF THIS CONFIG
copy_extensions = copy
[ my_policy ]
# if the value is "match" then the field value must match the same field in the
# CA certificate. If the value is "supplied" then it must be present.
# Optional means it may be present. Any fields not mentioned are silently
# deleted.
countryName = match
stateOrProvinceName = supplied
organizationName = supplied
commonName = supplied
organizationalUnitName = optional
commonName = supplied
This is how to sign:
openssl ca -config ./config_ca.cnf -out "$x.crt" -in "$x.csr" -batch
Should you try to sign 2 certificates with the same DN, you’ll get this error:
ERROR:There is already a certificate for /C=JP/ST=Tokyo/O=MyOrg/OU=Tech Department/CN=Harald Kubota
The fix is to change ./CA/index.txt.attr to be
unique subject = no
4. Import CA to Ubuntu
Your machine should not yet trust your new CA certificate. Use above created certificate and present a web page or similar. Confirm via
openssl s_client -connect HOST:PORT
to connect to that process using your previously created host certificate. You should see something along those lines. Note line 4 and 7 with a “verify error” part.
❯ openssl s_client -connect web.lan:8443
CONNECTED(00000003)
depth=0 C = JP, ST = Tokyo, O = MyOrg, OU = Tech Department, CN = Harald Kubota
verify error:num=20:unable to get local issuer certificate
verify return:1
depth=0 C = JP, ST = Tokyo, O = MyOrg, OU = Tech Department, CN = Harald Kubota
verify error:num=21:unable to verify the first certificate
verify return:1
---
Certificate chain
[...]
To make OpenSSL trust the certificate, you have to make it trust your CA. This is how:
if [[ ! -d /usr/share/ca-certificates/extras ]] ; then
mkdir /usr/share/ca-certificates/extras
fi
cp CA.crt /usr/share/ca-certificates/extras/HaraldCA.crt
echo "extras/HaraldCA.crt" >>/etc/ca-certificates.conf
update-ca-certificates -v
and after updating the root certificates on your computer:
❯ openssl s_client -connect web.lan:8443
CONNECTED(00000003)
depth=1 C = JP, ST = Tokyo, L = Tama, O = root organisation, OU = root department, CN = Harald Kubota, emailAddress = harald.kubota@gmail.com
verify return:1
depth=0 C = JP, ST = Tokyo, O = MyOrg, OU = Tech Department, CN = Harald Kubota
verify return:1
---
Certificate chain
[...]
5. Import CA into your Browser
Browsers bring their own CA store, so you have to update those. Copy CA.crt into a directory you can access from the browser, and import it.
Firefox: Preferences → Privacy & Security → Certificates View Certificates → In the Authorities pane click on Import… and import your CA.crt
Chrome: Settings → Privacy and security → Click on More → Manage certificates → Authorities → Import and import your CA.crt
From now on if you go to any web page which is signed with your CA, you browser will not show a warning anymore.
Caveats
This has no password/passphrase on any private key. Also the CA should be on a secured server.