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 emailAddressemail@example.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 emailAddressfirstname.lastname@example.org [ 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 = email@example.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.
This has no password/passphrase on any private key. Also the CA should be on a secured server.