Certificate handling with embedded chromium

Chromium have started to become the standard if you want to include a webview in your application or your embedded device. In the application case certificate handling is probably not a big issue, as you would just use the system defaults. On an embedded device however you might want to give the decision to the customer what certificate authorities (CAs) should be trusted, or even allow them to upload their own CAs.

Most of the documentation on how to do this for chromium on Linux just tells you that chromium uses an NSS database. And you can control your CAs by adding and removing CAs from that database. I quickly found out that I could add my own CAs using that documentation, but removing CAs was another story.

The hope was that not-adding the CA to the database would disable it, which did not work. To remove it I had to add the CA as prohibited. This seems fine, until you realize that this means the CA needs to already be in the database to begin with. NSS comes with a pre-built CA list from Mozilla, so to give 100% control of the CA list to your customers, you have to be able to disable all of these certificates. NSS does not come with a way of querying and dumping the pre-built CA list, so making sure all of them are disabled through every upgrade of NSS would be a nightmare.

Luckily we build NSS as part of our build pipeline, giving us full control over what version we build, and what patches are added to the repo. The solution to gain full control over the certificates available to chromium also requires us to patch NSS itself. The NSS repo contains a file: nss/lib/ckfw/builtins/certdata.txt, which is the file we need to patch. To remove the builtin CA list completely, you can just delete everything below the line: CKA_LABEL UTF8 "Mozilla Builtin Roots". This removes all of the CAs from libnss, which means that at this point we will not accept a single HTTPS request.

After doing this the easiest way to add/remove certificates would be to watch a folder for changes, and add/remove the certificates you want to enable/disable. To watch the folder you can use something like inotify or a systemd path file if you are working on a systemd system, which will trigger a script that ends up doing certutil -A -a -t "C" -n "dbkey" -i "<path to cert file>" -d "sql:<path to database>" on added certificates and certutil -D -n "dbkey" -d "sql:<path to database>" on removed certificates.