mod_ssl vs mod_gnutls

This page will contain all information needed to set up an Apache2 environment for benchmarking mod_ssl vs mod_gnutls.

Environment

All testing is performed on a Debian machine, running the following software which should be the latest available when this was written (2008-03-05). Note that we don't build anything ourselves, we use the Debian packages for everything. The benchmarking tool we will use is Siege. The reasons for chosing it was that it was packaged for Debian and was easy to use. We should definitely consider other benchmarking tools as well, suggestions are welcome.

ii  libssl0.9.8                          0.9.8g-4                     SSL shared libraries
ii  openssl                              0.9.8g-4                     Secure Socket Layer (SSL) binary and related cryptographic tools
ii  ssl-cert                             1.0.16                       simple debconf wrapper for OpenSSL
ii  apache2                              2.2.8-1                      Next generation, scalable, extendable web server
ii  apache2-mpm-worker                   2.2.8-1                      High speed threaded model for Apache HTTPD
ii  apache2-utils                        2.2.8-1                      utility programs for webservers
ii  apache2.2-common                     2.2.8-1                      Next generation, scalable, extendable web server
ii  libapache2-mod-gnutls                0.5.0-alpha-1                Apache2 module for SSL and TLS encryption using GnuTLS
ii  siege                                2.65-4                       Http regression testing and benchmarking utility

Apache configuration

It doesn't seem possible to have the mod_ssl and the mod_gnutls modules loaded at the same time. I didn't look into why. Instead, we will change configurations and re-start Apache with mod_ssl or mod_gnutls as we want to test each. This may help to reduce the chance that we mix up results for mod_ssl with mod_gnutls.

GnuTLS configuration

Copy the following into /etc/apache2/sites-available/gnutls.

Listen 443
NameVirtualHost *:443
<VirtualHost *:443>
        GnuTLSEnable on
	GnuTLSCertificateFile /etc/apache2/ssl/apache.pem
	GnuTLSKeyFile /etc/apache2/ssl/apache.pem
	GnuTLSClientCAFile /etc/apache2/ssl/apache.pem
	GnuTLSDHFile /etc/apache2/ssl/dh.pem
	GnuTLSPriorities NORMAL

	ServerAdmin simon@josefsson.org
	DocumentRoot /var/www/
	<Directory />
		Options FollowSymLinks
		AllowOverride None
	</Directory>
	<Directory /var/www/>
		DirectoryIndex index.html
		Options Indexes FollowSymLinks MultiViews +ExecCGI
		AllowOverride None
		Order allow,deny
		allow from all
	</Directory>

	ErrorLog /var/log/apache2/mod_gnutls-error.log
	LogLevel warn

	CustomLog /var/log/apache2/mod_gnutls-access.log combined
	ServerSignature On

    Alias /doc/ "/usr/share/doc/"
    <Directory "/usr/share/doc/">
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Order deny,allow
        Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    </Directory>

</VirtualHost>

OpenSSL configuration

Copy the following into /etc/apache2/sites-available/openssl.

NameVirtualHost *:443
<VirtualHost *:443>
	SSLEngine on
	SSLCertificateFile /etc/apache2/ssl/apache.pem
	SSLCertificateKeyFile /etc/apache2/ssl/apache.pem
	SSLCACertificateFile /etc/apache2/ssl/apache.pem

	ServerAdmin simon@josefsson.org
	DocumentRoot /var/www/
	<Directory />
		Options FollowSymLinks
		AllowOverride None
	</Directory>
	<Directory /var/www/>
		DirectoryIndex index.html
		Options Indexes FollowSymLinks MultiViews +ExecCGI
		AllowOverride None
		Order allow,deny
		allow from all
	</Directory>

	ErrorLog /var/log/apache2/mod_ssl-error.log
	LogLevel warn

	CustomLog /var/log/apache2/mod_ssl-access.log combined
	ServerSignature On

    Alias /doc/ "/usr/share/doc/"
    <Directory "/usr/share/doc/">
        Options Indexes MultiViews FollowSymLinks
        AllowOverride None
        Order deny,allow
        Deny from all
        Allow from 127.0.0.0/255.0.0.0 ::1/128
    </Directory>

</VirtualHost>

The reason why the OpenSSL configuration does not need a Listen predicate is because Debian's /etc/apache2/ports.conf contains:

<IfModule mod_ssl.c>
    Listen 443
</IfModule>

Credentials

Put the following into /etc/apache2/ssl/apache.pem.

-----BEGIN RSA PRIVATE KEY-----
MIICXAIBAAKBgQDqT2PuFCtcJvZNDZz983g9KaNVuMViEdegs3CgTku34quoIPTH
jQegumBJxPs4xKs15CF6GQmbh0t8xQRnWqC9VtHfVIxkLytZOlmgRioaS2ba4KiQ
tON5vgL6jRj/jhUCtYWlBklVm3dLiqEwEYR5ag8I4ePqSHCQ7T0bq1yKdQIDAQAB
AoGAOw1ZLRaOOwJiztage2xSIHAPBzqzHF1Mz+aJew1gje6lvpDXwDct9fci71Si
0BLY55MgUMpgnn8BqmdpDbdMjRAQ/ZtDjEESnzcSj43Pzyq5QbQmDbx2qOQi+ILT
JShnRa7h7aUThtzGm9lpq+Ff2D9CFM+7xvD2YZfdFI7LW70CQQD2x8CF4+thfu2g
h/GO2zVDzlcH7s6sRIMDoRwY98c8zGzY+FYCEkj2vJNizMtWwd9jYNZR1XwFg4vL
cexaIW63AkEA8xBfH/rbhgnIbiFenEmYIUV2ul3RjkuWkwQ6db88A2iyx9XqBhKA
1g5T6BLN3BppEAV46pft0uCUwlbbYCxkMwJALxOQAHqoLmMeRZ9pT0017gdwxsyh
lG9FZu3XBFRQJ6L/qKxHDAIc9SSoIRLcP2KgkL6qY9YL4Kllg5vp8I+sJQJAYA7c
SRsunm5HU57EcSd0g9Gb9lMVehLNUxScteP5p6882FTlw7iUSgQnjNPBn3aghsBi
5PNd/bTblWIWGI/ymQJBAPSuA8HO2J9SAm/8WStXnU9In4Yoq1GWGi1MpxxfWc6m
1XxvgL9py3OLnv2vk4tQZWEZbNzlPNZUN596v8x1LNo=
-----END RSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIBnzCCAQgCCQDxhYuQFNIXaDANBgkqhkiG9w0BAQUFADAUMRIwEAYDVQQDEwls
b2NhbGhvc3QwHhcNMDgwMjI3MTMzNzExWhcNMTgwMjI0MTMzNzExWjAUMRIwEAYD
VQQDEwlsb2NhbGhvc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAOpPY+4U
K1wm9k0NnP3zeD0po1W4xWIR16CzcKBOS7fiq6gg9MeNB6C6YEnE+zjEqzXkIXoZ
CZuHS3zFBGdaoL1W0d9UjGQvK1k6WaBGKhpLZtrgqJC043m+AvqNGP+OFQK1haUG
SVWbd0uKoTARhHlqDwjh4+pIcJDtPRurXIp1AgMBAAEwDQYJKoZIhvcNAQEFBQAD
gYEAbuSa+V6HS1DIOFLGyEET6uNymgJYVCNc3+rVMFFcrlmEeSyaePIg60uGMlpB
Do4M2zOvh7bK1bTIHUWmvzT6TukGKBGwrGfTq7HVguzC2qTPWN/Q+Apf3YN3o0xB
QzUPkFBbxtOsriRaN/OqB0AW5uWa6l07WHBRucW/rsVgx1I=
-----END CERTIFICATE-----

The key/certificate was generated using OpenSSL by invoking:

mkdir /etc/apache2/ssl
/usr/sbin/make-ssl-cert /usr/share/ssl-cert/ssleay.cnf /etc/apache2/ssl/apache.pem

Put the following in /etc/apache2/ssl/dh.pem:

-----BEGIN DH PARAMETERS-----
MIGHAoGBANZ95EDLu9wZNtaT00r9CtUMhNI5pF9SC7iBdMuYvOlRhJ+RLmOccvsT
tLTXF34W1VrBebpCCyop/jJKRnpjXoH/WQE3e+3c/TMWikYarTty2uiGAHgEWwen
28p4dAh9FRDqn8yd3TMFB91i24iuqnR94PTW4r1osOc5Pg8kIY6zAgEC
-----END DH PARAMETERS-----

This is the Diffie-Hellman parameters extracted from mod_ssl. The file is only used by mod_gnutls. See ModSSLDHParams for more information.

Put the following into /etc/apache2/ssl/apache-dsa.pem:

-----BEGIN DSA PRIVATE KEY-----
MIIBugIBAAKBgQC5hPVagb4aDcWKc48Mmy+btg5Lw3Qaf2StnfMoxaBHvJtXVvGX
1X43A+nyTPTji38wo10vu6GiN8LqNY8fsV+mol8B8SM2K+RPLy3dndU6pjmvelF8
0iWOl3TPHsV7S3ZDgQcfBhS4blgS4ZDiN2/SG+xoxVji5jDgal4sY3jsBwIVAJ9W
jEhkL/6NqnptltsEXRbvCKVxAoGAYgZ+5Fx2CLdGGl3Xl9QqIfsfMcnS9Po52CfR
m/wnXacKpxr8U8EvQ8I3yIV/PUyrXYEy+x1eHlQRFiDGgFrZjJtD8N1roPTD8oqc
OdIcew/v+iiTj9KhIuvc4IqLrSgOz+8Jhek2vYt6UNV79yUNbGARxO9wkM/WG+u7
jsY+OpcCgYAPiodX8tHC3KzfS4sPi7op9+ED5FX6spgH1v0SsYC89bq0UNR/oA5D
55/JeBFf5eQMLGtqpDXcvVTlYDaaMdGKWW5rHLq9LrrrfIfv2sjdoeukg+aLrfr6
jlvXN8gyPpbCPvRD2n2RAg+3vPjvj/dBAF6W3w8IltzqsukGgq/SLwIUS5/r/2ya
AoNBXjeBjgCGMei2m8E=
-----END DSA PRIVATE KEY-----
-----BEGIN CERTIFICATE-----
MIIDbzCCAtqgAwIBAgIERiYdRTALBgkqhkiG9w0BAQUwGTEXMBUGA1UEAxMOR251
VExTIHRlc3QgQ0EwHhcNMDcwNDE4MTMyOTQxWhcNMDgwNDE3MTMyOTQxWjA3MRsw
GQYDVQQKExJHbnVUTFMgdGVzdCBzZXJ2ZXIxGDAWBgNVBAMTD3Rlc3QuZ251dGxz
Lm9yZzCCAbQwggEpBgcqhkjOOAQBMIIBHAKBgLmE9VqBvhoNxYpzjwybL5u2DkvD
dBp/ZK2d8yjFoEe8m1dW8ZfVfjcD6fJM9OOLfzCjXS+7oaI3wuo1jx+xX6aiXwHx
IzYr5E8vLd2d1TqmOa96UXzSJY6XdM8exXtLdkOBBx8GFLhuWBLhkOI3b9Ib7GjF
WOLmMOBqXixjeOwHAhSfVoxIZC/+jap6bZbbBF0W7wilcQKBgGIGfuRcdgi3Rhpd
15fUKiH7HzHJ0vT6Odgn0Zv8J12nCqca/FPBL0PCN8iFfz1Mq12BMvsdXh5UERYg
xoBa2YybQ/Dda6D0w/KKnDnSHHsP7/ook4/SoSLr3OCKi60oDs/vCYXpNr2LelDV
e/clDWxgEcTvcJDP1hvru47GPjqXA4GEAAKBgA+Kh1fy0cLcrN9Liw+Luin34QPk
VfqymAfW/RKxgLz1urRQ1H+gDkPnn8l4EV/l5Awsa2qkNdy9VOVgNpox0YpZbmsc
ur0uuut8h+/ayN2h66SD5out+vqOW9c3yDI+lsI+9EPafZECD7e8+O+P90EAXpbf
DwiW3Oqy6QaCr9Ivo4GTMIGQMAwGA1UdEwEB/wQCMAAwGgYDVR0RBBMwEYIPdGVz
dC5nbnV0bHMub3JnMBMGA1UdJQQMMAoGCCsGAQUFBwMBMA8GA1UdDwEB/wQFAwMH
gAAwHQYDVR0OBBYEFL/su87Y6HtwVuzz0SuS1tSZClvzMB8GA1UdIwQYMBaAFOk8
HPutkm7mBqRWLKLhwFMnyPKVMAsGCSqGSIb3DQEBBQOBgQBCsrnfD1xzh8/Eih1f
x+M0lPoX1Re5L2ElHI6DJpHYOBPwf9glwxnet2+avzgUQDUFwUSxOhodpyeaACXD
o0gGVpcH8sOBTQ+aTdM37hGkPxoXjtIkR/LgG5nP2H2JRd5TkW8l13JdM4MJFB4W
QcDzQ8REwidsfh9uKAluk1c/KQ==
-----END CERTIFICATE-----

This was generated using GnuTLS, and is in fact part of our set of test credential.

Factors influencing performance

A number of non-implementation related factors that influence benchmarking have been identified:

The TLS cipher suite used

Generally, all DHE ciphers are slower than their corresponding non-DHE cipher suite. Make sure you confirm the chosen cipher by using tools like Wireshark.

The size of the Diffie-Hellman parameters used

Unfortunately, mod_ssl does not allow users to configure the DH parameters to use. To make sure the comparison is fair, we configure GnuTLS to use the same hard-coded DH parameter as used by mod_ssl. See ModSSLDHParams for more information.

The size of the downloaded file

This shouldn't be a surprise. When we begin comparing compression support, the content of the data will matter too.

Bugs in mod_gnutls

Mod_gnutls is experimental code, so you should expect bugs. One thing I've noticed are related to TLS session caching with DBM. The logs will contain:

[Wed Mar 05 17:04:02 2008] [notice] (89025)Error string not specified yet: [gnutls_cache] error storing in cache '/var/cache/apache2/gnutls_cache'
PANIC: Invalid argument
PANIC: fatal region error detected; run recovery
/var/cache/apache2/gnutls_cache page 25 is on free list with type 13

UPDATE: This was because the session DB grew huge and due to limitations of the default apache dbm database new insertions were prevented with this error. This error is suppressed in newer versions of mod_gnutls.

Since we won't do any TLS resumption in these benchmarks, you could disable such caching for mod_gnutls by making sure your /etc/apache2/mods-available/gnutls.conf looks like:

# mod_gnutls can optionaly use a memcached server to store SSL sessions.  This                                                         
# is useful in a cluster environment, where you want all your servers to share                                                         
# a single SSL session cache.                                                                                                          
#GnuTLSCache memcache "127.0.0.1 server2.example.com server3.example.com"                                                              

# The default method is to use a DBM backed cache.  It is not super fast, but                                                          
# it is portable and does not require another server to be running like                                                                
# memcached.                                                                                                                           
#GnuTLSCache dbm /var/cache/apache2/gnutls_cache                                                                                       

GnuTLSCache none none

Helper scripts

For switching between GnuTLS and OpenSSL configurations, I have written two small scripts. The first is apache-gnutls and restarts apache configured with mod_gnutls:

#!/bin/sh
sudo a2dissite openssl
sudo a2dismod ssl
sudo a2ensite gnutls
sudo a2enmod gnutls
sudo /etc/init.d/apache2 stop
sleep 2
sudo /etc/init.d/apache2 stop
sudo rm -f /var/cache/apache2/gnutls_cache
ps auxww|grep -i -e htt -e apa|grep -v tail|grep -v grep
sudo /etc/init.d/apache2 start
sleep 3
curl --insecure https://localhost/doc/ 2>&1 |tail -2|head -1

The second is apache-openssl which restarts apache configured for mod_ssl:

#!/bin/sh
sudo a2dissite gnutls
sudo a2dismod gnutls
sudo a2ensite openssl
sudo a2enmod ssl
sudo /etc/init.d/apache2 stop
sleep 2
sudo /etc/init.d/apache2 stop
ps auxww|grep -i -e htt -e apa|grep -v tail|grep -v grep
sudo /etc/init.d/apache2 start
curl --insecure https://localhost/doc/ 2>&1 |tail -2|head -1

Chosing another cipher suite

To use the TLS_RSA_WITH_AES_128_CBC_SHA (0x002f) add the following to the mod_ssl configuration:

	SSLCipherSuite AES128-SHA

And to the mod_gnutls configuration:

	GnuTLSPriorities NONE:+VERS-TLS1.0:+AES-128-CBC:+RSA:+SHA1:+COMP-NULL

To use the TLS_RSA_WITH_3DES_EDE_CBC_SHA (0x000a) ciphersuite, use the following configuration for mod_ssl:

	SSLCipherSuite DES-CBC3-SHA

And the following for mod_gnutls:

	GnuTLSPriorities NONE:+VERS-TLS1.0:+3DES-CBC:+RSA:+SHA1:+COMP-NULL

To use TLS_DHE_DSS_WITH_RSA_128_CBC_SHA (0x0032) you need to load the DSA certificate instead, and then use for mod_ssl:

	SSLCipherSuite DHE-DSS-AES128-SHA

And for gnutls:

	GnuTLSPriorities NONE:+VERS-TLS1.0:+AES-128-CBC:+DHE-DSS:+SHA1:+COMP-NULL

Note that you have to replace the key/certificate with the DSA version, so the configuration should look like, for mod_ssl:

	SSLCertificateFile /etc/apache2/ssl/apache-dsa.pem
	SSLCertificateKeyFile /etc/apache2/ssl/apache-dsa.pem
	SSLCACertificateFile /etc/apache2/ssl/apache-dsa.pem

And for mod_gnutls:

	GnuTLSCertificateFile /etc/apache2/ssl/apache-dsa.pem
	GnuTLSKeyFile /etc/apache2/ssl/apache-dsa.pem
	GnuTLSClientCAFile /etc/apache2/ssl/apache-dsa.pem

Results

Benchmark results are collected on a separate page, see BenchmarkingModGnuTLSResults.