Forward Secrecy mit Debian/wheezy: postfix, dovecot, nginx

In letzter Zeit hat man ja in den Medien ziemlich viel von der NSA-Schnüffelei gelesen und die “knee-jerk reaction” der meisten Geeks war dann wohl zu sagen: “Wir brauchen mehr und stärkere Kryptographie.” Ich will jetzt nicht sagen, dass das verkehrt ist, denn im Prinzip ist es nie schlecht, noch mehr und noch stärkere Verschlüsselung einzusetzen. Meine Kritik an dieser Reaktion bezieht sich darauf, dass sie IMHO nicht weit genug geht: Zum einen ist für Überwacher sehr oft das interessant, was beschönigend als “Metadaten” (my ass!) bezeichnet wird, also die Information darüber, wer mit wem kommuniziert. Der Einsatz von noch so starker Kryptographie wird die Überwachenden seltenst daran hindern, diese Daten trotzdem zu sammeln. Zum anderen leben wir in einer Zeit, in der via Gerichtsbeschluss die Herausgabe von privaten Schlüsseln, Zertifikaten und Passwörtern verlangt werden kann (nicht in jedem Land, schon klar). Und damit ist die Wahrscheinlichkeit sehr groß, daß eine sogrsam aufgebaute, verschlüsselte Kommunikationsinfrastruktur trotz aller technischen Maßnahmen in sich zusammenfällt wie ein Kartenhaus. Vielleicht ist es einfach an der Zeit, zuzugeben, dass wir diese Rune im Kampf um den Schutz unserer Daten verloren haben und damit anzufangen, sich darüber Gedanken zu machen, wie wir in einer “post privacy”-Welt leben wollen. Allerdings soll es in diesem Artikel um andere Themen gehen.

Angesichts der z.B. von der NSA demonstrierten Datensammelkapazität leiden die meisten traditionell mit SSL/TLS eingesetzten Verschlüsselungsmechanismen unter einem sehr schwerwiegenden Problem: Wurde verschlüsselter Traffic aufgezeichnet, so ist es möglich, diesen im Nachhinein zu kompromittieren, sofern man - z.B. per Gerichtsbeschluss - den privaten Schlüssel des Servers erlangt, da der Austausch der Session Keys für eine SSL/TLS-Session meist mit genau diesem encrypted wird. Will man sich dagegen verteidigen, so müssen sich Server und Client auf Verschlüsselungskeys einigen, die aus Material stammen, dass nur für diese eine Sitzung verwendet wird, und danach muß das Material entsorgt werden. Der Fachbegriff dafür ist (Perfect) Forward Secrecy - und neben der Tatsache, dass die NSA-Affäre eine Diskussion in der Gesellschaft angestossen hat ist das einzig gute an der Sache, dass PFS in den Fokus der Öffentlichkeit gelangt ist.

Man erreicht PFS meistens durch den Einsatz des Diffie-Hellman-Protokolls und bezeichnet einen Schlüsselaustausch, der PFS über DH bietet, meistens als Ephemeral Diffie-Hellman oder auch DHE. Da das originale Protokoll recht rechenintensiv ist, gibt es eine Variation des Algorithmus, der auf Verschlüsselung mit elliptischen Kurven beruht und als “ECDHE” bezeichnet wird. Neben dem Schlüsselaustausch, der meist über RSA erfolgt, gibt es noch zwei (drei) weitere Komponenten einer für eine Verbindung relevanten Verschlüsselung. Zum einen ist dies der symetrische Verschlüsselungsalgorithmus selbst. Traditionell kommt hier meistens RC4 zum Einsatz, allerdings mehren sich in letzer Zeit die Hinweise darauf, dass dieses Protokoll wie es in SSL/TLS-Verbindungen eingesetzt wird, angreifbar ist. Als Alternative dazu, die leider in modernen Webbrowsern noch keine große Verbreitung findet, bietet sich AES an. Die zweite wichtige Komponente ist der Operation Mode, mit dem näher definiert wird, wie die gewählte Verschlüsselung innerhalb der Session eingesetzt wird. Als “state of the art” kann man hier guten Gewissens GCM bezeichnen. Zuletzt gilt es, einen Algorithmus zu finden, mit dem die Integrität der Nachrichten gesichert wird, und hier kommen meist Varianten von SHA zum Einsatz.

Die Liste der Verschlüsselungen, die wir haben wollen, sieht also ungefähr so aus:

  • ECDHE-RSA-AES256-GCM-SHA384
  • DHE-RSA-AES256-GCM-SHA384
  • DHE-RSA-AES256-SHA
  • DHE-RSA-AES128-SHA
  • andere Cipher

Alle Anmerkungen hier beziehen sich übrigens auf die mitgelieferten Versionen der Softwarepakete in Debian/wheezy - ich bin kein großer Freund davon, ohne Not Backports oder Third-Party-Pakete zu verwenden.

Für Postfix ist es zunächst einmal notwendig, zwei DH-Parameter-Files zu generieren, um die Nutzung von (EC)DHE-Verschlüsselungen zu ermöglichen (also es ist nicht 100%ig nötig, aber sonst verwendet man halt die Standard-Files, und die sind dann für alle Postfix-Installationen weltweit gleich):

openssl gendh -out /etc/postfix/dh_param_512.pem -2 512
openssl gendh -out /etc/postfix/dh_param_1024.pem -2 1024

Hat man diese erzeugt, so ist es trivial, (EC)DHE-Verschlüsselungen in Postfix in der Konfigurationsdatei /etc/postfix/main.cf zu aktivieren:

smtpd_tls_dh512_param_file = /etc/postfix/dh_param_512.pem
smtpd_tls_dh1024_param_file = /etc/postfix/dh_param_1024.pem
smtpd_tls_eecdh_grade = strong
smtpd_tls_protocols = !SSLv2
tls_preempt_cipherlist = yes

Update: Aufgrund eines Problems bei der Interoparabilität von Postfix und Exim und Exim kann es sinnvoll sein, wie in dem Link beschrieben, die 1024Bit-Parameter in Wirklichkeit 2048 Bit groß zu machen.

Der letzte Eintrag führt dazu, dass Postfix selbst die Cipher auswählt und kann in Verbindung mit schlecht programmierten Clients zu Problemen führen. In diesem Fall bietet es sich an, den Gegenstellen die Verwendung von STARTTLS ganz zu verbieten, bis der Postmaster das Problem behoben hat (via smtpd_discard_ehlo_keyword_address_maps). Setzt man in der Postfix-Konfiguration noch smtpd_tls_loglevel = 1, dann kann man mit folgendem Befehl, den ich schamlos von Ralf geklaut habe, überprüfen, ob die Änderungen erfolgreich waren:

$ zegrep "TLS connection established from.*with cipher" /var/log/mail.log | \
> awk '{printf("%s %s %s %s\n", $12, $13, $14, $15)}' | sort | uniq -c | sort -n
      1 SSLv3 with cipher DHE-RSA-AES256-SHA
     23 TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384
     60 TLSv1 with cipher ECDHE-RSA-AES256-SHA
    270 TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384
    335 TLSv1 with cipher DHE-RSA-AES256-SHA

Man sieht dass auf dem Mailserver nicht viel los ist und dass 100% aller Verbindungen PFS verwenden.

Für Dovecot ist keine weitere Konfiguration notwendig. Wer möchte kann explizit das Logging der verwendeten Ciphers über einen Eintrag in der Datei /etc/dovecot/conf.d/10-logging.conf aktivieren:

login_log_format_elements = "user=<%u> method=%m rip=%r lip=%l mpid=%e %c %k"

Update: Nachdem gerade mobile Clients sich nicht besonders geschickt bei der Wahl der Ciphers anstellen, kann es unter Umständen - falls man sicher ist, dass die Clients neu genug sind - die Liste der Ciphers in /etc/dovecot/conf.d/10-ssl.conf einschränken:

ssl_cipher_list = DHE-RSA-AES256-SHA:DHE-RSA-AES128-SHA:!aNULL:!eNULL:!LOW:!3DES:!MD5:!EXP:!CBC:!PSK:!SRP:!DSS:!SSLv2:!RC4

Was Webserver angeht, so ist in Debian/wheezy leider nur ein Apache 2.2 enthalten, und dessen mod_ssl kann diverse Ciphers nicht, die wir gerne hätten. Wer also für Webseiten auf PFS wert legt, der wird in den sauren Apfel beißen und einen nginx auspacken müssen. Wer nicht gleich ganz von Apache wegmigrieren will (dazu werde ich im Laufe der nächsten Woche evt. noch was bloggen), der kann nginx zumindest als Reverse-Proxy vor seinen Apache kleben. Die Konfiguration für PFS sieht in nginx folgendermaßen aus:

ssl_certificate         /etc/ssl/certs/example.com.crt.pem;
ssl_certificate_key     /etc/ssl/private/example.com.key.pem;

ssl_protocols                   SSLv3 TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers       on;
ssl_session_timeout             5m;
ssl_session_cache               builtin:1000 shared:SSL:10m;
ssl_ciphers "EECDH+ECDSA+AESGCM EECDH+aRSA+AESGCM EECDH+ECDSA+SHA384 EECDH+ECDSA+SHA256 EECDH+aRSA+SHA384 EECDH+aRSA+SHA256 EECDH+aRSA+RC4 EECDH EDH+aRSA RC4 !aNULL !eNULL !LOW !3DES !MD5 !EXP !PSK !SRP !DSS";

add_header Strict-Transport-Security "max-age=31536000; includeSubdomains";

Mit diesen Einstellungen sollte der nginx dann ebenfalls PFS können, das kann man dann z.B. via Qualys SSL Labs Server Test -Test überprüfen lassen.