Überblick
- kurze Einführung in SSL
 - Stand der Unterstützung von SSL in Perl
 
 
was ist überhaupt SSL?
- "Secure Socket Layer", Nachfolger TLS (Transport Layer Security), welches
fast das gleiche ist
 - stellt verschlüsselte Verbindung zwischen zwei Endpunkten her
 - optionaler Austausch von Zertifikaten, um Identität zu überprüfen
 
 
was sind Zertifikate?
- "elektronischer Ausweis"
 - enthält Informationen über einen Endpunkt (z.B. Hostnamen, IP-Adressen...)
 - sollte (elektronisch) unterschrieben sein von einer glaubwürdigen Instanz
(CA = Certificate Agency, Herausgeber)
 - hat eine Gültigkeitsdauer
 - kann widerrufen werden
 - Spezialfall selbstsignierte Zertifikate: nur der Inhaber des Zertifikates
hat unterschrieben ("Glaube mir, ich bins")
 
 
Überprüfung von Zertifikaten
- passt das Zertifikat zu demjenigen, der es mir präsentiert (Identität)?
 - vertraue ich der CA (dem Herausgeber), die es unterschrieben hat?
Dazu haben die Browser eine Liste verbreiteter CAs eingebaut.
 - bei selbstsignierten Zertifikaten: Glaube ich, das der mir Unbekannte 
mich nicht anlügt?
 - ist das Zertifikat abgelaufen?
 - ist das Zertifikat widerrufen worden?
 
 
Hintergrund dieses Vortrages
- 11/07: CVE-2007-5162:
"Ruby Net::HTTPS library does not validate server certificate CN"
 - Perl macht es doch auch nicht anders und keiner regt sich auf? 
Wo ist das Problem? 
 - Perl-Workshop 02/2008: "Bist du der IO::Socket::SSL Maintainer?"
 - Ja, aber eigentlich ist das doch nicht die Aufgabe von IO::Socket::SSL
sondern des übergeordneten Layers (HTML, SMTP...)
 - Aber: die Nutzer von IO::Socket::SSL checken die Zertifikate selber nicht
 
 
Warum überhaupt überprüfen?
- "ich will doch nur verschlüsseln, warum brauche ich die Unterschrift einer
CA?" 
 - "Mozilla SSL policy bad for the Web":
Abschreckende Firefox3 Warnungen bei selbstsignierten Zertifikaten 
hindern Verbreitung von Verschlüsselung
 - Problem: kein Schutz vor Man-In-The-Middle Attacken ohne Überprüfung von
Zertifikaten
 
 
was ist Man-In-The-Middle?
- Endpunkte: Alice, Bob. Angreifer Mallory
 - Alice will SSL Verbindung zu Bob aufbauen, landet aber bei Mallory.
 - Mallory baut SSL Verbindung weiter zu Bob auf und bekommt von diesem
ein Zertifikat präsentiert.
 - Um die Verbindung unverschlüsselt lesen oder manipulieren zu können muss
er die Daten von Bob entschlüsseln und für Alice erneut verschlüsseln.
 - Da Mallory das Secret von Bobs Zertifikat nicht hat, erstellt er ein neues,
was wie Bobs aussieht (aber andere Unterschrift)
 - Nur wenn Alice das Zertifikat gründlich verifiziert findet sie die falsche
Unterschrift.
 
 
ist das wirklich eine Gefahr?
- Verbindungen umleiten mittels ARP Spoofing im lokalen Netz
 - Verbindungen umleiten mittels DNS Spoofing im Internet (z.B. CVE-2008-1447)
 - Exit Node im Tor Netzwerk
 - Tools wie z.B. Ettercap zur Automatisierung des Angriffs sind frei verfügbar
 - wird offensichtlich auch praktiziert:
Bugreport, der auf 
MITM in the wild schließen läßt
 
 
Überprüfung der Identität
- Check gegen commonName und/oder subjectAltNames
 - RFC2818 (http), RFC3920 (xmpp) - wenn subjectAltNames existieren wird
commonName nicht benutzt, subjectAltName kann auch Wildcard, zB
*.example.com aber auch host*.example.com sein.
 - RFC4513 (ldap), RFC2995 (pop,imap...), RFC4642 (nntp) - sowohl commonName
wie auch subjectAltName werden überprüft, subjectAltName kann auch
*.example.com sein, aber nicht host*.example.com
 - RFC3207 (smtp) - man soll checken ob man dem Zertifikat vertraut, ohne
Details zum Vorgang zu geben
 - RFC4217 (FTP über TLS) empfiehlt check wie RFC2818, legt sich aber nicht
wirklich fest
 
 
Zertifikate checken hilft nicht immer
 
Crypt::SSLeay/Net::SSL
- nur bei LWP benutzt
 - liefert bei Bedarf commonName zum Check
 - wird bei LWP genutzt um commonName gegen Hostname zu checken, sofern man
Pseudo-Header 'If-SSL-Cert-Subject' setzt
 - weitere Entwicklung wohl nur, um es compilierbar zu halten
 
 
IO::Socket::SSL
- basiert auf Net::SSLeay (d.h OpenSSL)
 - unterstützt 
- Checks gegen commonName und subjectAltNames 
 - Berücksichtigung von Wildcards
 - verschiedene Verifikationsschemas
 - internationale Domainnames
 - Checks gegen IP
 
 - checkt aber auch nichts, wenn nicht gesagt was genau gescheckt werden soll
(da keine klare Regel, wie in allen Fällen zu checken)
 - braucht daher offizielle Unterstützung im Caller oder Hacks, um diese
Unterstützung nachträglich einzubauen
 
 
IO::Socket::SSL Client
     # ohne Verifikation
     $cl = IO::Socket::SSL->new( 'signin.ebay.de:443' );
     # mit Verifikation
     $cl = IO::Socket::SSL->new(
       PeerAddr => 'signin.ebay.de:443',
       SSL_verify_mode => 1, 
       SSL_ca_path => '/etc/ssl/certs',
       SSL_verifycn_scheme => 'www',
     );
     print $cl "GET / HTTP/1.1\r\n...."
 
IO::Socket::SSL Server
     $srv = IO::Socket::SSL->new(
       LocalAddr => 'signin.ebay.de:443',
       Listen => 10,
       SSL_cert_file => ...,
       SSL_key_file => ...,
     );
     $cl = $srv->accept;
     <$cl>
 
weiterhin
- Crypt::NSS, Net::NSS::SSL Layer über Netscape Security Services (v0.4 11/08)
 - Crypt::MatrixSSL Layer über MatrixSSL.org Bibliothek (v1.86 01/09)
 
 
LWP (https)
- Problem: LWP nimmt via Net::SSL entweder Crypt::SSLeay oder IO::Socket::SSL, 
wobei es ersteres bevorzugt
 - Daher Hack: Net::SSLGlue::LWP 
- forciert Nutzung von IO::Socket::SSL, da nur dieses richtiges Zertifikatschecking bietet
 - forciert Zertifikatscheck entsprechende RFC2818
 - leider bietet LWP keinen Mechanismus Optionen an den Socket zu
übergeben, daher verbindungsspezifische Optionen nur über local
 
 
 
Net::SSLGlue::LWP - Beispiel
    use Net::SSLGlue::LWP SSL_ca_path => '/etc/ssl/certs';
    use LWP::Simple;
    get( 'https://signin.ebay.de' );
 
LWP und https Proxy
- LWP hat ein einzigartiges Verständnis von https_proxy
 - statt einem CONNECT wird ein plain text Request für eine https:// Resource
an den Proxy gesendet
 - die Verbindung mit dem Proxy ist dann unverschlüsselt
 - daher keine Verifikation von Zertifikaten möglich
 - nur wenige Proxies unterstützen das
 - Crypt::SSLeay/Net::SSL hatte Workaround mittels HTTPS_PROXY
Environmentvariable (dazu muss env_proxy in LWP aus sein)
 - IO::Socket::SSL hat diesen Workaround nicht
 - Net::SSLGlue::LWP fixt stattdessen https_proxy, sodaß die Variable wie in
anderen Programmen funktioniert
 
 
SSL und SMTP
- Net::SMTP::TLS, startet plain und macht dann mit STARTTLS weiter. 
- Seit 01/2006 keine Änderungen mehr (aber auch keine Bugreports), letzte 
Version 0.12. 
 - Nutzt IO::Socket::SSL, macht aber keine Zertifikatschecks und beruht
nicht auf Net::SMTP sondern reimplementiert alles :(
 
 - Net::SMTP::SSL, welches einfach die Abhängigkeit von IO::Socket::INET
gegen eine Abhängigkeit von IO::Socket::SSL austauscht und auch keine
Zertifikatschecks macht.
 - Daher Hack: Net::SSLGlue::SMTP 
- erweitert Net::SMTP um STARTTLS Kommando (wie Net::SMTP::TLS) 
 - und um SSL von Beginn an (wie Net::SMTP::SSL)
 - in beiden Fällen mit korrektem Zertifikatscheck
 
 
 
Net::SSLGlue::SMTP Beispiel
    use Net::SSLGlue::SMTP;
    $smtp_ssl = Net::SMTP->new( 
      'mail.gmx.net', SSL => 1 ); # SSL Port 465
    $smtp = Net::SMTP->new( 
       'mail.gmx.net' ); # Plain Port 25
    $smtp->startssl; # switch to SSL
- Achtung! Da für SMTP kein Standard für das Checken der Zertifikate
existiert akzeptieren Mailclients evtl. andere Zertifikate als
Net::SSLGlue::SMTP. In diesem Falle  SSL_verifycn_scheme  anpassen.
    # mail.gmx.de in subjectAltName, in cn mail.gmx.net
    $smtp = Net::SMTP->new( 'mail.gmx.de', 
       SSL => 1, 
       SSL_verifycn_scheme => 'http' )
 
 
Net::LDAP
- nur hier aufgenommen, weil der ursprüngliche Request zur Unterstützung sich auf
Net::LDAP bezog. 
 - nutzt IO::Socket::SSL, aber macht natürlich auch keinen Zertifikatscheck
 - Daher Hack: Net::SSLGlue::LDAP 
- forciert SSL_verify_scheme ldap, sofern über den Net::LDAP Mechanismus 
verify auf True gesetzt ist
 - ungetestet
 
 
 
weitere Module
- Net::POP, Net::NNTP könnte man analog zu Net::SMTP mit einem
Net::SSLGlue::* aufbohren
 - implicites FTPS (d.h Connection mittels SSL von Anfang an über speziellen
Port, analog zu HTTPS, Ports 990/989) könnte über Aufbohren von Net::FTP
gemacht werden, allerdings gibt es wohl keine RFC dazu und kein Schema, wie
das Zertifikat zu verifizieren ist.
 - explizites FTPS (RFC4217) ist wesentlich schwieriger, da hier einiges an
neuen Kommandos unterstützt werden muss. 
Es scheint einen Versuch Net::FTPSSL zu geben, der seit ein paar Jahren
mal wieder auflebt (v0.6, 02/09)
 
 
noch offene Fragen
- Standard-CAs
- unter Linux i.A. /etc/ssl/certs
 - unter BSD ähnlich
 - unter Windows ??
 
 - zurückgerufene Zertifikate
- kann mit heruntergeladenen CRLs umgehen
 - keine Unterstützung von OCSP, welches in den neueren Zertifikaten
benutzt wird
 
 
 
Ruby
- nach Fix wegen CVE-2007-5162 wird gewarnt, wenn keine Überprüfung gemacht
wird (das ist der Default)
 - Net::HTTPS benutzt OpenSSL::SSL::SSLSocket::post_connection_check, welcher 
das http scheme (RFC2818) implementiert.
 - Net::SMTP benutzt die gleiche Routine, d.h. es wird das http scheme zur
Verifikation bei SMTP benutzt.
 - Net::POP und Net::IMAP benutzen ebenfalls das http scheme, das ist falsch.
 
 
Python
- httplib, http.client: "This does not do any certificate verification!"
 - scheint nicht mal die Möglichkeit zu geben, einfach eigene Checks
einzubauen (d.h man kann zwar Clientzertifikat übergeben, aber nicht
beeinflussen, ob und wie Serverzertifikat verifiziert wird)
 - imaplib, poplib... scheinen ebenfalls keinerlei Checks vorzunehmen
 - ssl: stellt nötige Infos (subjectAltNames, commonName) zur Verfügung, macht
aber selber nichts damit und bietet auch keine Convinience Funktion zum
Check an
 
 
weitere Features von IO::Socket::SSL
- nonblocking Sockets
 - start_SSL (Upgrade von unverschlüsselt) und stop_SSL (Downgrade auf 
unverschlüsselt)
 - transparente IPv6 Unterstützung
- führt dazu, das evtl IPv6 bevorzugt wird, wenn DNS AAAA und A Records
liefert
 - kann Problem geben, wenn aber IPv6 Verbindung nicht funktioniert
oder DNS spinnt
 
 - Unterstützung für Windows (alle Tests laufen, aber keine 
Unterstützung für nonblocking Sockets)