The GnuTLS trac installation is in a poor shape. To fix that, I looked into alternatives and found Redmine. Redmine appears to do most things that I liked in Trac (wiki, roadmap and issue tracking) plus it supports more than one project (would come in handy for my other projects) and has built-in git support. I would like to see better spam handling and OpenID support, but it is good enough for our purposes now, and there are similar concerns with trac.

However, getting it up and running with lighttpd on a modern debian lenny installation was not trivial, and I needed some help from #redmine (thanks stbuehler). After finally getting it up and running, I made a copy of the machine using rsync and rsnapshot, so I could re-create a working configuration if I get stuck, and then re-installed the virtual machine.

The notes below are the steps required to set up Redmine using Lighttpd and MySQL on a Debian Lenny. I’m posting this to help others searching for the error messages I got, and to help my own memory in case I need to re-install the server sometime.
I assume you have installed Debian Lenny, and have root access to it. You need to install some dependencies:

Starting the lighttpd server at this point results in an error message:

li37-61:~# /etc/init.d/lighttpd restart
Stopping web server: lighttpd.
Starting web server: lighttpd.
li37-61:~#
2008-10-17 04:50:03: (mod_fastcgi.c.1047) the fastcgi-backend /home/redmine/redmine/public/dispatch.fcgi failed to start:
2008-10-17 04:50:03: (mod_fastcgi.c.1051) child exited with status 9 /home/redmine/redmine/public/dispatch.fcgi
2008-10-17 04:50:03: (mod_fastcgi.c.1054) If you’re trying to run PHP as a FastCGI backend, make sure you’re using the FastCGI-enabled version.
You can find out if it is the right one by executing ‘php -v’ and it should display ‘(cgi-fcgi)’ in the output, NOT ‘(cgi)’ NOR ‘(cli)’.
For more information, check http://trac.lighttpd.net/trac/wiki/Docs%3AModFastCGI#preparing-php-as-a-fastcgi-programIf this is PHP on Gentoo, add ‘fastcgi’ to the USE flags.
2008-10-17 04:50:03: (mod_fastcgi.c.1358) [ERROR]: spawning fcgi failed.
2008-10-17 04:50:03: (server.c.908) Configuration of plugins failed. Going down.

FastCGI modules are not installed by default, so you will need to install them:

li37-61:~# apt-get install libfcgi-ruby1.8

Restarting the server again, and accessing dispatch.fcgi using your browser, will result in errors like:

The Free Software & Culture conference FSCONS is held in Gothenburg October 24-26th. Having been there and given talks last year, I can recommend it for anyway interested in what’s going on the free software and culture world.

I’m happy and proud to notice that I have been nominated for their award, for my work on security packages for the GNU project. Too bad I cannot make it to the conference this year.

Using OpenWRT with WPA-PSK 2 on Broadcom WLAN routers have been stuck on a quite old bug. Recently someone suggested that it may have been fixed in trunk, which caused me to test it. And it works!

It took some time to work out the details here. To save myself time to reconstruct the commands, and hopefully save you some time too, I wrote down how to use OpenWRT with two Asus WL-500g Premium linked together wirelessly using WDS and PSK2 encryption.

This post describe the process of identifying and profiling an inefficient part of GnuTLS. The tool I’m using is callgrind. I won’t describe the tool in detail since I’m not a callgrind expert, instead the focus is on the methodology in finding and fixing a problem. My hope is that this is useful as an insight to how maintainers go about fixing a performance-related problem. It also demonstrates how immensely useful tools like valgrind and callgrind are.

Today I stumbled over something as rare as a post that contains example code to reproduce a problem. The post was written by Edgar Fuß on the openldap list: link to edgars post. First, there is something to be learned here: if there hadn’t been code in that post, I would most likely have ignored it because it is too much trouble for me to understand and duplicate the problem. Especially when this isn’t a real GnuTLS bug report, but just discussion on a non-GnuTLS mailing list. By posting such example code, it was easy for me to compile and run it. As it turned out, the code was very slow and my curiosity peeked. Edgar’s bug triggering code was (somewhat modified for readability):

If you aren’t familiar with GnuTLS, I’ll describe what the code is intended to do. The code will iterate over all files in /etc/ssl/certs/ and calls gnutls_certificate_set_x509_trust_file for each file. That function will read one or more X.509 CA certificates stored in the file, and add it to the CA trust store inside GnuTLS. The files are typically small (1-2kb) but contain base64 encoded ASN.1 data which is decoded by GnuTLS. The CA trust store is used to determine whether to trust a client or server’s certificate or not. While this is typically only done at startup, and not during each TLS connection, it is not particulary performance critical. Still, if it is excessively slow it will slow down application startup.

On my system (x86 Debian testing) the /etc/ssl/certs directory contains 206 files. I compiled the test code and ran it:

40 seconds! Delaying startup of an application by that amount is pretty significant, so I understand this was considered a problem.

I became curious how much memory the process was using. If my machine had started paging (unlikely with 2GB but you never know), I could understand if it was this slow. However, the top output was relatively stable:

PID USER PR NI VIRT RES SHR …
6538 jas 20 0 5548 3668 752 …

In other words, the virtual size was about 6MB, which seemed normal. My next step was to run the binary under valgrind, to possibly detect any memory corruption or other problem that might explain the slowness. Valgrind slows down execution significantly, and after around 7 minutes I gave up and modified the code slightly so that it only iterated over the first couple of files. After running valgrind once, I discovered that the code didn’t call the needed gnutls_certificate_free_credentials() and gnutls_global_deinit(). You can download the updated example code gnutls-callgrind.c. The valgrind suppressions file to shut up some known libgcrypt internal memory leaks is available as libgcrypt.supp.

Nice! No memory leaks. We can now be relatively certain that the problem is really with the intention of the code, rather than some memory related bug. Given that we use C here, you want to rule out such problems early on because they are a nightmare to debug.

Now for the performance tuning session. Let’s run callgrind on the application. First, we must make sure we use a GnuTLS compiled with debugging information. The easiest way to do this is to compile it against the static libgnutls. Proceed as follows.

As you can see, execution time is even slower than with valgrind. The profile data output file is quite small. Running kcachegrind yields this output (click to enlarge):

The amount of information in kcachegrind can be overwhelming at first. However, the interesting values are in the percentages and call counts columns to the left. It tells us that gnutls_certificate_set_x509_trust_file() was invoked 22 times, and that 98% of the time is spent there. (If you are surprised by the 22, look at the code, the variable i starts at 0, and the loop is run until it is larger than 20, i.e., it is 21, which makes for 22 iterations in the loop.) The code for that function looks like:

The callgrind output tells us that 96% of the programs time is spent inside the 22 calls to generate_rdn_seq(), which in turn call gnutls_x509_crt_get_raw_dn a total of 506 times. The calls to gnutls_x509_crt_get_raw_dn make up 95% of the program’s execution time.

We can now conclude that the problem is inside the generate_rdn_seq() function, and not in the rest of the gnutls_certificate_set_x509_trust_file() function body. Given that 95% of the time is actually in a function that generate_rdn_seq calls (i.e., gnutls_x509_crt_get_raw_dn), the problem is either that the function is called too many times or that it is too slow.

Some words about what generate_rdn_seq() is intended to do: it pre-computes a list of names of the CA certificates. In TLS servers, this list of names of trusted CAs is sent to clients. The list is used by the client to find a client certificate issued by a CA that the server recognize. To avoid computing the list every time it is needed (i.e., for every connection), GnuTLS pre-computes this and store it in the credential structure. One credential structure can be associated with one or more TLS sessions.

Take some time to read and understand this code. Really. I’ll be here waiting to explain it when you are finished.

The res->x509_ca_list variable contains the entire list of CA’s stored in memory so far. It is initially empty. After reading the first file, it will contain one certificate. After reading the second file, it will contain two certificates, and so on.

What is happening here is that FOR EVERY certificate to add, the entire list of certificates is iterated, not just once but twice! The computational complexity of invoking the function is O(2*n^2) where n is the number of certificate names to be added. The first iteration is to compute the size of the string to hold the CA names. The actual data is discarded. The second iteration calls the same function, for the same data, but now store the output in the appropriate place.

The first step to optimize this is to realize that you don’t need to iterate through all CAs every time a new one has been added. Adding the name for the most recently added certificate should be sufficient. Since more than one CA can be added at each time, the function needs to take another parameter: the number of recently added CAs for which to pre-compute the names for.

I changed the function name, to reflect that it now just update the list of names for a set of recently added certificates. That also helps to find and update all callers of the old function.

As you can see, this function should be of complexity O(n) instead, since it just adds the name of the most recently added CA’s.

But is it faster in practice? Let’s check it! First, remove the if (i++ > 20) break; statement in the test code, so that we do the full test. First link against our old libgnutls.a and run the old test case again, for illustrative purposes.

Wow! Down from 40 seconds to 0.3 seconds. Let’s take a look at the callgrind output now.

The code now spends around 60 % of the time in add_new_crt_to_rdn_seq() which seems reasonable. There are 206 files in /etc/ssl/certs, which explains the call count. Some of the files actually contain several CA certificates (in particular /etc/ssl/certs/ca-certificates.crt contains a lot of certificates), which explains why gnutls_x509_crt_get_raw_dn is called 408 times.

In a bug report against libidn, Erik van der Poel gives an example of an internationalized domain name that is handled differently by different implementation. Another example of one such string is:

‘räksmörgås’ U+2024 ‘com’

If your browser supports Unicode, the string is: räksmörgås․com. Use cut’n'paste of the string into your browser and see what it tries to lookup (please let me know what you notice!).

The problem with this string is that it is on the form “[non-ASCII][DOT-Like code point]com”. Here ‘räksmörgås’ represents the non-ASCII string, which can be any non-ASCII string. Further, the U+2024 represent one character which looks like a dot, there are others that also contain dot-like characters.

The IDNA algorithm (section 3.1) implies that applications should treat the string as one label. The U+2024 character is not one of the dot-like characters that needs to be treated as a label separator. The ASCII string which is output after applying the IDNA algorithm is:

xn--rksmrgs.com-l8as9u

Note that the string contains an ASCII dot ‘.’ (0×0E). If applications are not careful how they resolv the name in the DNS, they will request information in a non-existing top-level domain ‘com-l8as9u’. This is because the DNS do not use ‘.’ to separate labels, but instead uses a length-value pair for each label. Thus the wrong string to lookup would be:

(11)xn--rksmrgs(10)com-l8as9u

Whereas the right string to lookup would be:

(22)xn--rksmrgs.com-l8as9u

Using DNS master file syntax, the name to lookup is xn--rksmrgs\.com-l8as9u.

What’s interesting here is that some implementations, such as Microsoft Internet Explorer and Firefox implements IDNA not according to the standard. Instead, they compute the following string:

As the maintainer of GNU Libidn, I’m not yet sure about what to do about the situation. The conservative approach is to do nothing until the RFCs are updated. I have come up with a patch to add a new IDNA flag that treat U+2024 as a dot-like character early on. This would at least make it possible to produce the same (RFC non-conforming) output that MSIE/Firefox computes.

During the autumn, in Yubico, we have been working on a PAM module for the Yubikey. It allows you to use the Yubikey to login to your machine, to unlock the screensaver, and so on. I decided to let Google Code host this project, which is the first time I’ve used them. It will be interesting to see how working with their site is going to turn out.

Marc Haber blogs about GnuTLS in Exim4, and it suggests there is a long list of technical issues in GnuTLS. Given my involvement in GnuTLS, I decided to analyze each bug to see what we can learn and possibly improve.

I looked at the all bugs tagged with gnutls in the exim4 bug tracker. My impression is that Marc Haber has done a very good job as Exim4 maintainer in dealing with these GnuTLS related problems. Some of the frustration seems to be because submitters don’t respond to questions. Also it seems different problems are discussed at the same time, which makes it very difficult to help isolate and solve the problem. The only serious problem I’ve identified is the entropy depletion problem, and the GnuTLS team will try to address it. To me, the concern seems more of a volunteer time issue than a technical one.

Quick Summary

Bug #348046 is so complex that I cannot judge it. If the submitters are willing, it may be best to re-submit each problem separately. The problem with TheBat is interesting, but given the non-free status of TheBat and no other reports, it doesn’t seem serious. To reduce entropy consumption is something we should work on, but it is a ‘wishlist’ kind of bug, and to some extent may have already been solved by removing the DH generation code which depleats the entropy pool quickly. The rest appears to be already solved or should be tagged as ‘wontfix’.

When the email client TheBat talks with exim4 4.50-8, gnutls (in exim4) will log (gnutls_handshake): An error was encountered at the TLS Finished packet calculation. Other clients than TheBat reportedly works. An older version of Exim4, specifically 4.32-2, worked though. It is unclear whether the version of GnuTLS changed when exim4 was upgraded from 4.32-2 to 4.50-8. There is no discussion of whether changing to OpenSSL would solve the problem.

Conclusion: The problem with TheBat warrants debugging. However, this do not seem to be a widely reported problem. Further, TheBat is not free software so we cannot help debug it.

Questions: The reported said earlier versions worked, which GnuTLS versions was this? Can the problem be pin-pointed to a specific GnuTLS release or Exim4 release? Does the problem go away with OpenSSL?

This is a long bug report by several submitters. The initial report from Martin A. Brooks is stalled when he doesn’t respond to the (appropriate and relevant) questions that Marc Haber asks. The problem that Ian Zimmerman reports seems to be different, now GnuTLS clients work fine but OpenSSL clients fail to connect to the Exim4/GnuTLS server. The OpenSSL errors may suggest it only wants to talk SSLv2 for some reason (local configuration?). Debugging the OpenSSL problem further would be the appropriate response, and should likely be treated as an OpenSSL bug (!) until more evidence can be gathered. Later, Andrew McGlashan reports a problem where neither GnuTLS and OpenSSL works against the ‘Incredimail’ MUA.

Conclusion: The bug should really be forked into several problems, one for the initial reports where the submitter stopped responding, one for the OpenSSL problem, and one for the Incredimail problem (and as Incredimail isn’t a Debian package, it’s not Debian’s problem). Caveat: I may have missunderstood some parts of this bug report because different problems are discussed at the same time. Once that is done we can try to address each problem separetely.

Appears to be triggered by GnuTLS implementing MAC padding to solve a security problem in TLS. OpenSSL reportedly does not implement the same work around, and would thus appear to be vulnerable to that problem.

Conclusion: Appears to be a ‘wontfix’ bug. Personally, I think GnuTLS could provide a simpler mechanism to disable MAC padding if applications deem this necessary. Someone could double check how important the MAC padding security concern is.

Appears to be an unreprodicible problem with a specific certificate/key which the user cannot reveal. Another certificate/key from the same CA works fine. Theory: could it be CRLF problems? Other non-ASCII characters in the file? Nothing indicates a real GnuTLS problem here.

There is two technical claims here: that GnuTLS consumes too much entropy, and this would be a wishlist item that we could work on. The other claim is that ‘openssl actually supports full certificate chain lookups, so you can be guaranteed that this cert was signed was signed by that ca. gnutls does not, to the best of my knowledge.’. As far as I can understand with Stephen Gran refers to, that is simply false. It is suggested that GnuTLS’ performce is worse than OpenSSL, but there is no measurements to support that.

A free software conference in Sweden? That’s a rare one. Organized by the FSFE and Henrik Sandklef, it will be held on the 7-8 December 2007. I hope we’ll see more of this in Sweden. I’m proud to have been invited to talk about both GnuTLS and OpenID. I’m happy to see that there is a OpenMoko talk as well. If you want to participate, there is an early bird discount if you register now. If someone is going and would like to chat, drop me an email.