Remove All CAs From Linux Trust Store
On Security Now! podcast #951, Steve told us that 7 organizations in the PKI are responsible for minting upwards of 99% of all existing certificates. (Possible original source.)
His suggestion was that we can remove all CAs except for those 7 and
still be able to browse the web normally. I wanted to try that, so I
disabled almost all CAs in Firefox by hand (about:preferences#privacy
and then “View Certificates…”). After allowing some other CAs that I
encountered on web sites and that I thought were trustworthy, it worked
beautifully.
I wanted to do the same for curl
, wget
and other programs.
First I read the Arch Linux Wiki article on TLS certificates. Apparently, libraries can make use of the PKCS #11
interface exposed by Arch. I searched for it, but could not readily find
any programs that use this interface. From experimenting, I found that
curl
, wget
, openssl
and docker
all obtain their root store from
files in /etc/ca-certificates/
.
My tactic is: disallow all CAs, then go about my day, and enable those that I encounter and that seem trustworthy.
1. Check if you can securely connect to a remote host
$ H=nos.nl; echo Q | \
> openssl s_client -verify_return_error -servername $H $H:443
Connecting to 23.50.131.144
CONNECTED(00000003)
depth=2 C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA
verify return:1
depth=1 C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1
verify return:1
depth=0 C=BE, L=Antwerpen, O=DPG Media Services NV, CN=*.nu.nl
verify return:1
... snip ...
2. Disable All CAs
$ sudo ln /etc/ca-certificates/extracted/cadir/*.pem \
> /etc/ca-certificates/trust-source/blocklist/
$ sudo /usr/bin/update-ca-trust
3. Verify that remote host is now untrusted
$ H=nu.nl; echo Q | \
> openssl s_client -verify_return_error -servername $H $H:443
Connecting to 23.50.131.156
CONNECTED(00000003)
depth=1 C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1
verify error:num=20:unable to get local issuer certificate
40575E1A63700000:error:0A000086:SSL
routines:tls_post_process_server_certificate:certificate verify failed:ssl/statem/statem_clnt.c:2091:
---
Certificate chain
0 s:C=BE, L=Antwerpen, O=DPG Media Services NV, CN=*.nu.nl
i:C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1
a:PKEY: id-ecPublicKey, 256 (bit); sigalg: RSA-SHA256
v:NotBefore: Jun 2 00:00:00 2024 GMT; NotAfter: Jun 4 23:59:59 2025 GMT
1 s:C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1
i:C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA
a:PKEY: rsaEncryption, 2048 (bit); sigalg: RSA-SHA256
v:NotBefore: Apr 14 00:00:00 2021 GMT; NotAfter: Apr 13 23:59:59 2031 GMT
... snip ...
4. Allow CA if deemed trustworthy
If we look at the output under 3., we see that the issuer of the
intermediate certificate (s:C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1
) is DigiCert. To trust this root again:
$ find /etc/ca-certificates/trust-source/blocklist/ \
> -iname '*digicert*' -print -delete
./DigiCert_High_Assurance_EV_Root_CA.pem
./DigiCert_Global_Root_G2.pem
./DigiCert_TLS_RSA4096_Root_G5.pem
./DigiCert_Trusted_Root_G4.pem
./DigiCert_Assured_ID_Root_G2.pem
./DigiCert_Assured_ID_Root_G3.pem
./DigiCert_Global_Root_G3.pem
./DigiCert_TLS_ECC_P384_Root_G5.pem
./DigiCert_Assured_ID_Root_CA.pem
./DigiCert_Global_Root_CA.pem
$ /usr/bin/update-ca-trust
Sometimes, an application caches the blocklisted certs. In that case, you need to restart the application. Notably, the Docker daemon needs to be restarted whenever a change to the certificate store was made.
5. Check if domain gets validated again
$ H=nu.nl; echo Q | openssl s_client -verify_return_error -servername $H $H:443
Connecting to 23.50.131.156
CONNECTED(00000003)
depth=2 C=US, O=DigiCert Inc, OU=www.digicert.com, CN=DigiCert Global Root CA
verify return:1
depth=1 C=US, O=DigiCert Inc, CN=DigiCert TLS RSA SHA256 2020 CA1
verify return:1
depth=0 C=BE, L=Antwerpen, O=DPG Media Services NV, CN=*.nu.nl
verify return:1
... snip ...