Now that we got NSS certutil reproducibly cross-compiled for Windows, initial testing has begun on tlsrestrict_nss_tool for Windows.

Besides the obvious and rather boring fail that tlsrestrict_nss_tool was trying to execute cp, which of course isn’t going to work on Windows (that particular code segment is a relic from quick prototyping that wasn’t ever intended to stay in the codebase), two more interesting issues were identified:

  1. rbm builds certutil with the Visual C++ 2010 runtime, so running certutil without that runtime installed produces an obvious error. However, in order to properly detect the built-in certificates (“CKBI”) that Firefox ships with, tlsrestrict_nss_tool makes certutil load the CKBI module that Firefox distributes (not the CKBI module that certutil was built with). This means that, when certutil is asked to load Firefox’s CKBI module, the Visual C++ runtime used by Firefox’s CKBI module also needs to be present. Which happens to be Visual C++ 2015. Without that, certutil looks like it’s working – but the moment the Firefox CKBI module is loaded into certutil, certutil exits with a missing DLL error. However, the situation is worsened by the fact that, as far as I can tell, a missing DLL error in Windows doesn’t impact the exit code. So tlsrestrict_nss_tool doesn’t actually know thet certutil encountered an error; it just thinks it succeeded, and happened to produce no output. What happens if certutil produces no output when dumping the CKBI list? Well, tlsrestrict_nss_tool just figures that you’re using a Firefox build that doesn’t have any default trusted CA’s! This is bad enough when you first run tlsrestrict_nss_tool, since it will basically be a no-op. But even worse, if you did have the Visual C++ dependency from Firefox, but then Firefox upgraded it, then the next time you try to run tlsrestrict_nss_tool, all of the name constraints that were previously added will get deleted, because tlsrestrict_nss_tool figures that those CA’s have vanished. How sad. The fix here is probably to make tlsrestrict_nss_tool explicitly error if the CKBI module appears to have 0 certificates in it. Such a scenario pretty much always indicates that something has gone horribly wrong involving the CKBI module, and it’s generally best to treat it as an error.
  2. certutil’s certificate dumping functions require selecting a certificate by its nickname. What’s a nickname? In practice, for the CKBI module it seems to be the CommonName of the certificate. The nickname is passed to certutil via a command line flag. What could possibly go wrong here? Certificate nicknames can be arbitrary text, including Unicode. What happens when you pass Unicode as a command line argument in Windows? Nothing good happens, that’s for sure. In my testing, Windows will corrupt all of the non-ASCII characters, which results in certutil receiving a corrupted nickname to look up (and it correctly replies that no such nickname exists in the database). The fix here is to use certutil’s “batch command” feature. certutil allows you to put a sequence of commands into a .txt file, and you can pass that .txt file’s path to certutil with a command line flag; certutil will then run all of those commands. Since the .txt file isn’t parsed by Windows’s broken command line text decoder, Unicode inside the .txt file passes through unharmed.

Now, I haven’t actually fixed these bugs yet. But, progress is progress. Hopefully fixes will be coming very soon.

This work was funded by NLnet Foundation’s Internet Hardening Fund.