tl;dr: Over the past weeks, I’ve put together a Firefox add-on for SSL certificate pinning so I would notice if ever a man-in-the-middle would use forged certificates to spy on me when I interact with my home servers, banking websites, and so on. I feel a lot safer now again! You can find it here and the source code here.
Once upon a time…
When you surf the web you have to trust hundreds of certificate authorities to do their job right and not give out SSL certificates to anyone but the owner of those sites they protect. For the large part of my daily activities on the web I more or less do have this trust or just don’t care, really. However, there are a couple of websites, specifically my own and some banking websites, where I want to be absolutely certain that the certificate has not been tampered with. In some programs such as the ‘Conversations’ messaging app on Android I use and the Android DAVx5 calendar/address connector for Nextcloud, it is possible to pin the certificates. So when a certificate changes, communication is interrupted before secrets are exchanged and I have to confirm the use of the new certificate. As I update the certificates myself every three months I know very well when this happens and any alerts other then generated after my certificate changes would trigger more than just a raised eyebrow. Firefox also had an extension known as ‘Certificate Patrol‘ in the past to keep me save but it unfortunately stopped working when Mozilla retired their old add-on API I few years ago.
I then moved on to HPKP (HTTP Public Key Pinning) where the server could instruct the browser to pin certificates. I found this an interesting concept, but it requires that the public key remains the same or a previously announced backup key is used when a new certificate is generated. Unfortunately this didn’t play together well with the way Let’s Encrypt works, as their default implementation is to change the certificate and the public key every three months. There could be ways around it but the Let’s Encrypt update programs never much cared for it. Also, support on Firefox mobile was flawed and in the meantime, Google has announced that they will or already have removed HPKP support in Chrome. Not that I care too much about Chrome but the writing is on the wall.
Let’s Work on This
Germany has a great tradition of hacker festivals all year around. Over the past years I have started attending some of them and also giving some talks like recently at the GPN#19 to not only to learn new things from others there but to also give back to the community. When I go to such events I take a little project with me that I had in mind for some time already and for which I need some dedicated time and an inspiring environment. For GPN#19, my project was to see if there is an API (again) for add-ons to check SSL certificates when pages load. And indeed, to my great delight, Mozilla has added an API again at some point in 2018 so add-ons can look at certificates again! I then spent most of the two days at GPN to see how I could get to this information before session cookies and other secret information is sent to the other end, how to abort page loading if necessary and how to store data in Firefox permanently so any certificate pins the user would configure would not be lost after closing the browser. I haven’t written a Firefox add-on before so the process took a bit of time. But after the two days I had all basic concepts working and I spent much of my quality time since then to create a fully working add on with a reasonable UI. The add-on with the basic functionality is now finally done and it’s available in the Mozilla Add-on store here if you are interested and want to use it as well.
How To Use It
After installation a new icon will appear in the Firefox tool bar as shown above. Clicking on it reveals the options to pin- or unpin a website (if it is TLS protected) and to open a tab to show all sites that have previously been pinned. When the fingerprint of the certificate (or the public key to be precise) changes, the add-on will interrupt the loading process and issue a warning as shown in the second image. If things look fine, the new certificate can be accepted with a button at the bottom. Obviously, my approach is TNO (Trust No One) so I wouldn’t expect anything else from you, which is why I’ve made the source code available on Codeberg here. Comments and suggestions are very welcome, either here or in the ‘issues’ section on Codeberg. Enjoy!