A longstanding GnuTLS certificate validation botch

This article brought to you by LWN subscribers Subscribers to LWN.net made this article — and everything that surrounds it — possible. If you appreciate our content, please buy a subscription and make the next set of articles possible.

Something rather reminiscent of Apple's " goto fail; " bug has been found, but this time it hits rather closer to home for the free software community since it lives in GnuTLS. Certificate validation for SSL/TLS has been under some scrutiny lately, evidently to good effect. But this bug is arguably much worse than Apple's, as it has allowed crafted certificates to evade validation checks for all versions of GnuTLS ever released since that project got started in late 2000.

Perhaps the biggest irony is that the fix changes a handful of " goto cleanup; " lines to " goto fail; ". It also made other changes to the code (including adding a " fail " label), but the resemblance to the Apple bug is too obvious to ignore. While the two bugs are actually not that similar, other than both being in the certificate validation logic, the timing and look of the new bug does give one pause.

The problem boils down to incorrect return values from a function when there are errors in the certificate. The check_if_ca() function is supposed to return true (any non-zero value in C) or false (zero) depending on whether the issuer of the certificate is a certificate authority (CA). A true return should mean that the certificate passed muster and can be used further, but the bug meant that error returns were misinterpreted as certificate validations.

Prior to the fix, check_if_ca() would return error codes (which are negative numbers) when it encountered a problem, which would be interpreted as a true value by the caller. The fix was made in two places. First, ensuring that check_if_ca() returned zero (false) when there were errors, and second, also testing the return value in verify_crt() for != 1 rather than == 0 .

It is hard to say how far back this bug goes, as the code has been restructured several times over the years, but the GnuTLS advisory warns that all versions are affected. There are a lot of applications that use GnuTLS for their SSL/TLS secure communication needs. This thread at Hacker News mentions a few, including Emacs, wget, NetworkManager, VLC, Git, and others. On my Fedora 20 system, attempting to remove GnuTLS results in Yum wanting to remove 309 dependent packages, including all of KDE, Gnucash, Calligra, LibreOffice, libvirt, QEMU, Wine, and more.

GnuTLS came about partly because the OpenSSL license is problematic for GPL-licensed programs. OpenSSL has a BSD-style license, but still includes the (in)famous "advertising clause". The license has been a source of problems before, so GPL programs often avoid it. One would hope that the OpenSSL developers are diligently auditing their code for problems similar to what we have seen from Apple and GnuTLS.

It was a code audit done by GnuTLS founder Nikos Mavrogiannopoulos (at the request of Red Hat, his employer) that discovered the bug. He may well have been the one to introduce it long ago, as he has done much of the work on the project—and the file in question ( lib/x509/verify.c ). He described it as "an important (and at the same time embarrassing) bug". It is clearly that, but it is certainly a good thing that it has at last been found and fixed.

Several commenters in various places have focused on the " goto " statement as somehow being a part of the problem for both Apple and GnuTLS. That concern seems misplaced. While, in both cases, a goto statement was located at the point where the bug was fixed, the real problem was twofold: botched error handling and incomplete testing. While Edsger Dijkstra's advice on goto and its harmful effects on the structure of programs is cogent, it isn't completely applicable here. Handling error conditions in C functions is commonly done using goto and, if it is done right, goto actually adds to the readability of the code. Neither Apple nor GnuTLS's flaw can really be laid at the feet of goto .

In something of a replay of the admonishments in last week's article on the Apple flaw: all security software needs to be better tested. We are telling our users that we are protecting their communications with the latest and greatest encryption, but we are far too often failing them with implementation errors. Testing with bad certificates would seem to be a must; some presumably was done for both code bases, but obviously some possibilities of badly formed or signed certificates were skipped. More (and better) testing is indicated.

[ Thanks to Paul Sladen for the heads-up about this bug. ]

