From 62acd57d67fff935e1c8a1796853e911869ee9f8 Mon Sep 17 00:00:00 2001 From: Matthias Andree Date: Tue, 4 Aug 2009 09:27:10 +0000 Subject: [PATCH] Abort verification if Subject CommonName/AltName contains NUL. svn path=/branches/BRANCH_6-3/; revision=5389 --- NEWS | 5 ++++ po/de.po | 77 +++++++++++++++++++++++++++++++++----------------------- socket.c | 27 ++++++++++++++------ 3 files changed, 70 insertions(+), 39 deletions(-) diff --git a/NEWS b/NEWS index edab25a3..701339a2 100644 --- a/NEWS +++ b/NEWS @@ -51,6 +51,11 @@ removed from a 6.4.0 or newer release.) fetchmail 6.3.11 (released XXXX-XX-XX - i. e. not yet): +# SECURITY BUGFIXES +* Fetchmail checks the Subject CommonName and Subject AltName X.509 certificate + fields for embedded NUL characters and aborts certificate verification to + counter recent SSL certificate verification attacks. Untested. + # BUGFIXES * Remove the spurious message "message delimiter found while scanning headers". RFC-5322 syntax states that the delimiter is part of the body, and the body is diff --git a/po/de.po b/po/de.po index 9ce1ccc7..843e3c41 100644 --- a/po/de.po +++ b/po/de.po @@ -8,7 +8,7 @@ msgid "" msgstr "" "Project-Id-Version: fetchmail 6.3.10-beta1\n" "Report-Msgid-Bugs-To: fetchmail-devel@lists.berlios.de\n" -"POT-Creation-Date: 2009-07-02 21:34+0200\n" +"POT-Creation-Date: 2009-08-04 11:24+0200\n" "PO-Revision-Date: 2009-05-26 00:53+0200\n" "Last-Translator: Matthias Andree \n" "Language-Team: Deutsch \n" @@ -2935,79 +2935,93 @@ msgstr "Server-CommonName: %s\n" msgid "Bad certificate: Subject CommonName too long!\n" msgstr "Ungültiges Zertifikat: Server-CommonName zu lang!\n" -#: socket.c:678 +#: socket.c:638 +msgid "Bad certificate: Subject CommonName contains NUL, aborting!\n" +msgstr "Ungültiges Zertifikat: Subject-CommonName enthält NUL, breche ab!\n" + +#: socket.c:661 +msgid "Bad certificate: Subject Alternative Name contains NUL, aborting!\n" +msgstr "" +"Ungültiges Zertifikat: Subject-Alternative-Name enthält NUL, breche ab!\n" + +#: socket.c:666 +#, c-format +msgid "Subject Alternative Name: %s\n" +msgstr "\"Subject Alternative Name\": %s\n" + +#: socket.c:691 #, c-format msgid "Server CommonName mismatch: %s != %s\n" msgstr "Server-CommonName stimmt nicht überein: %s != %s\n" -#: socket.c:684 +#: socket.c:697 msgid "Server name not set, could not verify certificate!\n" msgstr "Server-Name nicht gesetzt, konnte Zertifikat nicht verifizieren!\n" -#: socket.c:689 +#: socket.c:702 msgid "Unknown Server CommonName\n" msgstr "Unbekannter Server-CommonName\n" -#: socket.c:691 +#: socket.c:704 msgid "Server name not specified in certificate!\n" msgstr "Server-Name nicht in Zertifikat spezifiziert!\n" -#: socket.c:703 +#: socket.c:716 msgid "EVP_md5() failed!\n" msgstr "EVP_md5() fehlgeschlagen!\n" -#: socket.c:707 +#: socket.c:720 msgid "Out of memory!\n" msgstr "Kein Speicher mehr frei!\n" -#: socket.c:715 +#: socket.c:728 msgid "Digest text buffer too small!\n" msgstr "Textpuffer für Digest zu klein!\n" -#: socket.c:721 +#: socket.c:734 #, c-format msgid "%s key fingerprint: %s\n" msgstr "%s-Schlüssel-Fingerabdruck: %s\n" -#: socket.c:725 +#: socket.c:738 #, c-format msgid "%s fingerprints match.\n" msgstr "%s-Fingerabdrücke stimmen überein.\n" -#: socket.c:727 +#: socket.c:740 #, c-format msgid "%s fingerprints do not match!\n" msgstr "%s-Fingerabdrücke stimmen nicht überein!\n" -#: socket.c:736 +#: socket.c:749 #, c-format msgid "Server certificate verification error: %s\n" msgstr "Fehler bei Server-Zertifikat-Überprüfung: %s\n" -#: socket.c:742 +#: socket.c:755 #, c-format msgid "unknown issuer (first %d characters): %s\n" msgstr "unbekannter Herausgeber (erste %d Zeichen): %s\n" -#: socket.c:829 +#: socket.c:842 msgid "File descriptor out of range for SSL" msgstr "Datei-Deskriptor außerhalb des Bereichs für SSL" -#: socket.c:845 +#: socket.c:858 #, c-format msgid "Invalid SSL protocol '%s' specified, using default (SSLv23).\n" msgstr "" "Ungültiges SSL-Protokoll „%s“ angegeben, benutze Voreinstellung (SSLv23).\n" -#: socket.c:921 +#: socket.c:934 msgid "Certificate/fingerprint verification was somehow skipped!\n" msgstr "Zertifikat-/Fingerabdruck-Überprüfung wurde irgendwie übersprungen!\n" -#: socket.c:999 +#: socket.c:1012 msgid "Cygwin socket read retry\n" msgstr "Cygwin-Socket-Lese-Wiederholung\n" -#: socket.c:1002 +#: socket.c:1015 msgid "Cygwin socket read retry failed!\n" msgstr "Cygwin-Socket-Lese-Wiederholung fehlgeschlagen!\n" @@ -3054,50 +3068,46 @@ msgstr "keine „Received“-Adresse gefunden\n" msgid "found Received address `%s'\n" msgstr "„Received“-Adresse „%s“ gefunden\n" -#: transact.c:566 -msgid "message delimiter found while scanning headers\n" -msgstr "Nachrichtentrenner gefunden beim Scannen der Kopfzeilen\n" - -#: transact.c:597 +#: transact.c:592 msgid "incorrect header line found while scanning headers\n" msgstr "inkorrekte Kopfzeile gefunden beim Scannen der Kopfzeilen\n" -#: transact.c:599 +#: transact.c:594 #, c-format msgid "line: %s" msgstr "Zeile: %s" -#: transact.c:1138 +#: transact.c:1133 #, c-format msgid "no local matches, forwarding to %s\n" msgstr "keine lokalen Übereinstimmungen, Weiterleitung an %s\n" -#: transact.c:1153 +#: transact.c:1148 msgid "forwarding and deletion suppressed due to DNS errors\n" msgstr "Weiterleiten und Löschen wegen DNS-Fehlern unterdrückt\n" -#: transact.c:1263 +#: transact.c:1258 msgid "writing RFC822 msgblk.headers\n" msgstr "schreibe RFC822 msgblk.headers\n" -#: transact.c:1282 +#: transact.c:1277 msgid "no recipient addresses matched declared local names" msgstr "keine Empfängeradresse stimmt mit deklarierten lokalen Namen überein" -#: transact.c:1289 +#: transact.c:1284 #, c-format msgid "recipient address %s didn't match any local name" msgstr "Empfängeradresse %s stimmt mit keinem lokalen Namen überein" -#: transact.c:1298 +#: transact.c:1293 msgid "message has embedded NULs" msgstr "Nachricht hat eingebettete NUL-Zeichen" -#: transact.c:1306 +#: transact.c:1301 msgid "SMTP listener rejected local recipient addresses: " msgstr "SMTP-Server lehnte Adressen mit lokalem Empfänger ab: " -#: transact.c:1445 +#: transact.c:1440 msgid "error writing message text\n" msgstr "Fehler beim Schreiben des Nachrichtentextes\n" @@ -3172,3 +3182,6 @@ msgstr "malloc fehlgeschlagen\n" #: xmalloc.c:47 msgid "realloc failed\n" msgstr "realloc fehlgeschlagen\n" + +#~ msgid "message delimiter found while scanning headers\n" +#~ msgstr "Nachrichtentrenner gefunden beim Scannen der Kopfzeilen\n" diff --git a/socket.c b/socket.c index 474928d0..45f03a6b 100644 --- a/socket.c +++ b/socket.c @@ -608,7 +608,7 @@ static int SSL_verify_callback( int ok_return, X509_STORE_CTX *ctx, int strict ) if (depth == 0 && !_depth0ck) { _depth0ck = 1; - + if (outlevel >= O_VERBOSE) { if ((i = X509_NAME_get_text_by_NID(issuer, NID_organizationName, buf, sizeof(buf))) != -1) { report(stdout, GT_("Issuer Organization: %s\n"), buf); @@ -632,6 +632,12 @@ static int SSL_verify_callback( int ok_return, X509_STORE_CTX *ctx, int strict ) report(stderr, GT_("Bad certificate: Subject CommonName too long!\n")); return (0); } + if ((size_t)i > strlen(buf)) { + /* Name contains embedded NUL characters, so we complain. This is likely + * a certificate spoofing attack. */ + report(stderr, GT_("Bad certificate: Subject CommonName contains NUL, aborting!\n")); + return 0; + } if (_ssl_server_cname != NULL) { char *p1 = buf; char *p2 = _ssl_server_cname; @@ -643,14 +649,21 @@ static int SSL_verify_callback( int ok_return, X509_STORE_CTX *ctx, int strict ) * first find a match among alternative names */ gens = (STACK_OF(GENERAL_NAME) *)X509_get_ext_d2i(x509_cert, NID_subject_alt_name, NULL, NULL); if (gens) { - int i, r; - for (i = 0, r = sk_GENERAL_NAME_num(gens); i < r; ++i) { - const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, i); + int j, r; + for (j = 0, r = sk_GENERAL_NAME_num(gens); j < r; ++j) { + const GENERAL_NAME *gn = sk_GENERAL_NAME_value(gens, j); if (gn->type == GEN_DNS) { char *p1 = (char *)gn->d.ia5->data; char *p2 = _ssl_server_cname; + /* Name contains embedded NUL characters, so we complain. This + * is likely a certificate spoofing attack. */ + if ((size_t)gn->d.ia5->length != strlen(p1)) { + report(stderr, GT_("Bad certificate: Subject Alternative Name contains NUL, aborting!\n")); + sk_GENERAL_NAME_free(gens); + return 0; + } if (outlevel >= O_VERBOSE) - report(stderr, "Subject Alternative Name: %s\n", p1); + report(stdout, GT_("Subject Alternative Name: %s\n"), p1); if (*p1 == '*') { ++p1; n = strlen(p2) - strlen(p1); @@ -669,9 +682,9 @@ static int SSL_verify_callback( int ok_return, X509_STORE_CTX *ctx, int strict ) n = strlen(p2) - strlen(p1); if (n >= 0) p2 += n; - } + } if (0 == strcasecmp(p1, p2)) { - matched = 1; + matched = 1; } if (!matched) { report(stderr, -- 2.43.2