Stop using old SHA-1 SSL certificates

Last updated by Henry

Retiring Broken SHA1

The word is out on SHA-1 secure hashing algorithm which has been broken by Google using AlphaGo, artificial intelligence (AI) that runs on Google Cloud, Google Photo.

image

Starting with version 56, Chrome browsers mark SHA1-signed certificates as unsafe. Other browsers are giving similar warnings. When we started seeing the above warning on our virtual intranet (a fake internal network of virtual machines with made-up host and domain names), we thought something was wrong. No, it was just the old software that created our certificates was signing them with SHA1.

Wildcard SSL Certificate Authority

It was time to upgrade the certificates on our intranet. While we were at it, we decided to create our own certificate authority and use it to build our own little top-level domain (TLD). In retrospect, having a TLD, even a fake intranet internal company TLD, is not much of an advantage.

With the usual second-level domain, such as MyCompany.com, the whole intranet can get away with using a single wildcard certificate covering myhost.MyCompany.com and yourhost.MyCompany.com, etc. That is probably why it is easier to go with the standard practice and set up a domain (usually a second-level domain like a normal company would use) and have other computers on the network join that domain. It's the default setup, and it's how everybody does it.

But we're different. We have an ego the size of Alaska and we are going to set up a TLD anyway.

Setting Up a Top-Level Domain

With a top-level domain (.K) we are going to have to create a new certificate for every host on the network. Why? Because for security reasons, browsers hard-coded wildcard certificates not to work across a swath of second-level domains. The standard wildcard certificate not only will not work on our network, it will never work.

So let's outline how we set up a TLD on our Fedora server.

Setting up dnsmasq. Dnsmasq is a DNS server that comes pre-installed. We just have to set up dnsmasq.conf to create the .K TLD pointing to localhost, 127.0.0.1
listen-address=127.0.0.1
port=53
bind-interfaces
pid-file=/var/run/dnsmasq.pid
domain-needed
bogus-priv
no-hosts
dns-forward-max=150
cache-size=1000
neg-ttl=3600
no-poll
address=/k/127.0.0.1

Enable the dnsmasq service

systemctl enable dnsmasq.service

Every host is now a second-level domain and needs a separate certificate. No big deal. We can issue each of them a wildcard certificate covering all their subhosts. We can have a miniature internet in a box.

Create a folder to hold the scripts and create v3.ext
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, nonRepudiation, keyEncipherment, dataEncipherment
subjectAltName = @alt_names
[alt_names]
DNS.1 = %%DOMAIN%%
DNS.2 = *.%%DOMAIN%

Next, we created three scripts to create our certificate authority (CA) and issue certificates for each domain.

1_mkroot.sh
echo Generate CA key & certificate
echo Common Name (CN) may be 127.0.0.1 or localhost
openssl genrsa -out rootCA.key 4096 -cy authority
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 1024 -out rootCA.pem

Now we have to make a script to use our CA to sign a certificate for each made-up domain on the network.

2_mkcert.sh
#!/bin/bash
: ${1?"Create certificate
Usage: $0 domain.com "}
# Generate client key & certificate signing request
openssl genrsa -out $1.key 2048

DOMAIN=$1
COMMON_NAME=${2:-*.$1}
SUBJECT="/C=CA/ST=None/L=NB/O=$DOMAIN/CN=$COMMON_NAME"
NUM_OF_DAYS=999
openssl req -new -newkey rsa:2048 -sha256 -nodes -key $1.key -subj "$SUBJECT" -out $1.csr
cat v3.ext | sed s/%%DOMAIN%%/$DOMAIN/g > /tmp/xv3.ext
openssl x509 -req -in $1.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial 

# Generate client certificate
openssl x509 -req -in $1.csr -CA rootCA.pem -CAkey rootCA.key -CAcreateserial -out $1.crt -days 1024 -sha256 -extfile /tmp/xv3.ext
rm -f $1-chain.crt
cat $1.crt rootCA.pem > $1-chain.crt
chmod 400 $1-chain.crt

Finally, we need a script to install the certificate into the system so browsers recognize the CA.

3_install.sh
#!/bin/bash
# "Install" certificates somewhere for apache conf to find them later
sudo cp *.crt *.pem /etc/pki/tls/certs/
sudo cp *.key /etc/pki/tls/private/
sudo cp /etc/pki/tls/certs/rootCA.pem /etc/pki/ca-trust/source/anchors/
sudo update-ca-trust
sudo apachectl restart
# note: If the certificate is in OpenSSL’s extended BEGIN TRUSTED CERTIFICATE format, place it in /etc/pki/ca-trust/source
cat <<DOC
Certificates installed!
Our rootCA.crt certificate should be showing up in the browser's configuration, e.g. Chrome->Manage certificates->AUTHORITIES
Configure Apache's /etc/httpd/conf.d/ssl.conf with the server's Common Name (CN) files:
SSLCertificateFile /etc/pki/tls/certs/CN.crt
SSLCertificateKeyFile /etc/pki/tls/private/CN.key
SSLCertificateChainFile /etc/pki/tls/certs/CN-chain.crt
SSLCACertificateFile /etc/pki/tls/certs/rootCA.pem
Then, restart apache
apachectl restart
Navigate to chrome://restart
DOC

After creating the scripts and running them, we should now have certificates for each domain. We can serve up multiple secure domains on Apache 2.0 by editing ssl.conf

Listen 443 https
SSLPassPhraseDialog exec:/usr/libexec/httpd-ssl-pass-dialog
SSLSessionCache         shmcb:/run/httpd/sslcache(512000)
SSLSessionCacheTimeout  300
SSLRandomSeed startup file:/dev/urandom  256
SSLRandomSeed connect builtin
SSLCryptoDevice builtin
<VirtualHost _default_:443>
DocumentRoot "/var/www/html"
ServerName localhost:443
ErrorLog logs/ssl_error_log
TransferLog logs/ssl_access_log
LogLevel warn
SSLEngine on
SSLProtocol all -SSLv3
SSLProxyProtocol all -SSLv3
SSLHonorCipherOrder on
SSLCipherSuite PROFILE=SYSTEM
SSLProxyCipherSuite PROFILE=SYSTEM
SSLCertificateFile /etc/pki/tls/certs/k.crt
SSLCertificateKeyFile /etc/pki/tls/private/k.key
SSLCertificateChainFile /etc/pki/tls/certs/k-chain.crt
SSLCACertificateFile /etc/pki/tls/certs/rootCA.pem
SSLVerifyClient none
<FilesMatch "\.(cgi|shtml|phtml|php)$">
    SSLOptions +StdEnvVars
</FilesMatch>
<Directory "/var/www/cgi-bin">
    SSLOptions +StdEnvVars
</Directory>
BrowserMatch "MSIE [2-5]" \
         nokeepalive ssl-unclean-shutdown \
         downgrade-1.0 force-response-1.0
CustomLog logs/ssl_request_log \
          "%t %h %{SSL_PROTOCOL}x %{SSL_CIPHER}x \"%r\" %b"
</VirtualHost>

And for each domain

 

<VirtualHost *:*>
ServerName MyDomain.k
ServerAlias *.MyDomain.k
DocumentRoot "/var/www/html/mydomain"
</VirtualHost>
<VirtualHost *:443>
ServerName MyDomain.k
ServerAlias *.MyDomain.k
DocumentRoot "/var/www/html/mydomain"
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/MyDomain.k.crt
SSLCertificateKeyFile /etc/pki/tls/private/MyDomain.k.key
SSLCertificateChainFile /etc/pki/tls/certs/MyDomain.k-chain.crt
SSLCACertificateFile /etc/pki/tls/certs/rootCA.pem
</VirtualHost>

<VirtualHost *:*>
ServerName MyOtherDomain.k
ServerAlias *.MyOtherDomain.k
DocumentRoot "/var/www/html/myotherdomain"
</VirtualHost>
<VirtualHost *:443>
ServerName MyOtherDomain.k
ServerAlias *.MyOtherDomain.k
DocumentRoot "/var/www/html/myotherdomain"
SSLEngine on
SSLCertificateFile /etc/pki/tls/certs/MyOtherDomain.k.crt
SSLCertificateKeyFile /etc/pki/tls/private/MyOtherDomain.k.key
SSLCertificateChainFile /etc/pki/tls/certs/MyOtherDomain.k-chain.crt
SSLCACertificateFile /etc/pki/tls/certs/rootCA.pem
</VirtualHost>

To be continued as time permits...

 

 

 

 

Reference Links

Create a self-signed CA & client certificate
https://kb.op5.com/pages/viewpage.action?pageId=19073746

CREATE A SELF-SIGNED (WILDCARD) CERTIFICATE
https://blog.celogeek.com/201209/209/how-to-create-a-self-signed-wildcard-certificate/

Trusting additional CAs in Fedora / RHEL / CentOS
https://www.happyassassin.net/2015/01/14/trusting-additional-cas-in-fedora-rhel-centos-dont-append-to-etcpkitlscertsca-bundle-crt-or-etcpkitlscert-pem/

Apache SSL Certificate Installation
https://www.digicert.com/ssl-certificate-installation-apache.htm

add -cy authority to the switches when creating the cert authority
https://stackoverflow.com/a/2511287

add -extfile v3.ext to the switches
https://stackoverflow.com/questions/43665243/chrome-invalid-self-signed-ssl-cert-subject-alternative-name-missing/43665244#43665244

Getting Chrome to accept self-signed localhost certificate
https://stackoverflow.com/questions/7580508/getting-chrome-to-accept-self-signed-localhost-certificate#

Can a wildcard SSL certificate be issued for a second level domain?
https://security.stackexchange.com/questions/6873/can-a-wildcard-ssl-certificate-be-issued-for-a-second-level-domain