SSL Cert for localhost w/o errors

 
Written By Sanjir Habib On May-29th, 2021

The common solution

  • Create a self signed certificate using openssl.
  • Add the Root certificate to your OS CA cert list.
  • Sign a bunch of certs for any domain you wish.
  • And the certs to your apache server on your machine.
  • Also add DNS entries in /etc/hosts to redirect the named host your localhost

Where it fails

curl still complains. Certificate Invalid, Self signed certificate. That's because when curl sees a root certificate directly signing a host certificate, it marks it as self signed, invalid.

The solution is to create an intermediate certificate authority in the middle and then sign your host certificate with that.

The openssl scripts

Here's the steps to doing so.
echo localca.pem : CA
openssl req -new -x509 -subj "/CN=Local Root CA" -extensions v3_ca -days 36500 -key ~/.ssh/id_rsa -sha256 -out localca.pem -config localhost.cnf
echo inter.pem : intermediate private key
openssl genrsa -out interkey.pem 2048
echo inter.csr : intermediate certificate signing request
openssl req -subj "/CN=Local Intermediate CA" -extensions v3_ca -sha256 -new -key interkey.pem -out inter.csr
echo inter.pem : signing intermediate. [used by apache]
openssl x509 -req -extensions v3_ca -days 36500 -sha256 -in inter.csr -CA localca.pem -CAkey ~/.ssh/id_rsa -CAcreateserial -out inter.pem -extfile localhost.cnf
echo privkey.pem : localhost private key, [used by apache]
openssl genrsa -out privkey.pem 2048
echo generating certificate request file
openssl req -subj "/CN=localhost" -extensions v3_req -sha256 -new -key privkey.pem -out localhost.csr
echo cert.pem : signing request [used by apache]
openssl x509 -req -extensions v3_req -days 36500 -sha256 -in localhost.csr -CA inter.pem -CAkey interkey.pem -CAcreateserial -out cert.pem -extfile localhost.cnf
echo chain.pem : [used by apache]
cat inter.pem > chain.pem
cat localca.pem >> chain.pem
echo Displaying certificate
openssl x509 -in cert.pem -text -noout

The commands create a self signed certificate for your host that's signed by an Intermediate CA. Therefore isn't rejected by curl.

Input files for it are you rsa key from ~/.ssh/id_rsa to create the Root CA. You can also generate it, but I guess it's better to use your real certificate.

The other input file is localhost.cnf.

localhost.cnf

To create it start by first copying /etc/ssl/openssl.cnf file from your OS. You can also opt to edit it in place and use that file directly in the commands instead of your local copy. But whatever.

Two edits are needed for it to work.

In [v3_ca] section. The following keyUsage line is commented. Uncomment it.

[ v3_ca ]
# left out by default.
keyUsage = cRLSign, keyCertSign

And also add a new section called [alt_names]. Add all the domain or wild card domains you need to redirect to to localhost.

[ alt_names ]
DNS.1 = local
DNS.2 = localhost
DNS.3 = com.local
DNS.4 = *.com.local
DNS.5 = www.facebook.com
DNS.6 = facebook.com
DNS.7 = m.facebook.com
DNS.8 = mbasic.facebook.com

Wild card domains

Wild card domains only work on host names. Therefore *.localdomain.localhost is valid. But *.localhost will not work.

Installing the certificates

sudo cp habibur.com/cert.pem /etc/pki/tls/certs/localhost.crt
sudo cp privkey.pem /etc/pki/tls/private/localhost.key
sudo cp chain.pem /etc/pki/tls/certs/server-chain.crt
sudo cp localca.pem /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust enable
sudo update-ca-trust

Next edit /etc/httpd/conf.d/ssl.conf and uncomment the following lines.

SSLCertificateFile /etc/pki/tls/certs/localhost.crt
SSLCertificateKeyFile /etc/pki/tls/private/localhost.key
SSLCertificateChainFile /etc/pki/tls/certs/server-chain.crt

Don't forget to add the hosts you want to assign to localhost into /etc/hosts file

127.0.0.1	www.facebook.com
127.0.0.1 facebook.com
127.0.0.1 facebook.com.local

Restart your httpd server and you are done.

sudo systemctl restart httpd

Now Test

Visiting for example www.facebook.com now should hit your local web server. And also curl should not complain even when run without the -k option.