]> Pileus Git - ~andy/fetchmail/commitdiff
X.509 matching split out; disallow TLD wildcards.
authorMatthias Andree <matthias.andree@gmx.de>
Fri, 27 Aug 2010 19:33:04 +0000 (21:33 +0200)
committerMatthias Andree <matthias.andree@gmx.de>
Fri, 27 Aug 2010 19:33:04 +0000 (21:33 +0200)
Makefile.am
NEWS
fetchmail.h
socket.c
x509_name_match.c [new file with mode: 0644]

index 0e597d05080653ebb4b07d85769510e9ebedc003..6a12786b66596e04347ed4f53b474326a032e7b2 100644 (file)
@@ -38,7 +38,7 @@ libfm_a_SOURCES=      xmalloc.c base64.c rfc822.c report.c rfc2047e.c \
                        smbencrypt.h smbdes.c smbencrypt.c smbmd4.c smbutil.c \
                        libesmtp/gethostbyname.h libesmtp/gethostbyname.c \
                        smbtypes.h fm_getaddrinfo.c tls.c rfc822valid.c \
-                       xmalloc.h sdump.h sdump.c
+                       xmalloc.h sdump.h sdump.c x509_name_match.c
 libfm_a_LIBADD=                $(EXTRAOBJ)
 libfm_a_DEPENDENCIES=  $(EXTRAOBJ)
 LDADD  =               libfm.a @LIBINTL@ $(LIBOBJS)
diff --git a/NEWS b/NEWS
index a63a3d9ca47d9773b8c6d5bc1b46d8b07d1aba94..06e3f855246ee6b8a79db7bd517de3d5805c9bce 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -63,6 +63,7 @@ fetchmail-6.3.18 (not yet released):
   The test is overly picky and triggers if the pattern (after skipping the
   initial wildcard "*") or domain consist solely of digits and dots and matches
   more than needed.
+* Fetchmail now disallows wildcarding top-level domains.
 
 # BUG FIXES
 * Fetchmail would warn about insecure SSL/TLS connections even if a matching
index 0315a9da49f883953f6973e09a317dd0a871ad58..9502d1e33444307cdb39eeef212aea53351eb1af 100644 (file)
@@ -772,6 +772,9 @@ int must_tls(struct query *ctl);
 /* prototype from rfc822valid.c */
 int rfc822_valid_msgid(const unsigned char *);
 
+/* prototype from x509_name_match.c */
+int name_match(const char *p1, const char *p2);
+
 /* macro to determine if we want to spam progress to stdout */
 #define want_progress() \
        ((outlevel >= O_VERBOSE || (outlevel > O_SILENT && run.showdots)) \
index d3cf90d7efb0ce5fddf766b3854be96716658010..2a3e1ba1d3503eb03f073cdda200f08a560dbb35 100644 (file)
--- a/socket.c
+++ b/socket.c
@@ -593,42 +593,6 @@ SSL *SSLGetContext( int sock )
        return _ssl_context[sock];
 }
 
-/** A picky certificate name check:
- * check if the pattern or string in s1 (from a certificate) matches the
- * hostname (in s2), returns true if matched.
- *
- * The only place where a wildcard is allowed is in the leftmost
- * position of p1. */
-static int name_match(const char *p1, const char *p2) {
-    const char *const dom = "0123456789.";
-    int wildcard_ok = 1;
-
-    /* blank patterns never match */
-    if (p1[0] == '\0')
-       return 0;
-
-    /* disallow wildcards in certificates for domain literals
-     * (10.9.8.7-like) */
-    if (strspn(p1+(*p1 == '*' ? 1 : 0), dom) == strlen(p1))
-       wildcard_ok = 0;
-
-    /* disallow wildcards for domain literals */
-    if (strspn(p2, dom) == strlen(p2))
-       wildcard_ok = 0;
-
-    if (wildcard_ok && p1[0] == '*' && p1[1] == '.') {
-       size_t l1, l2;
-
-       ++p1;
-       l1 = strlen(p1);
-       l2 = strlen(p2);
-       if (l2 > l1)
-           p2 += l2 - l1;
-    }
-
-    return (0 == strcasecmp(p1, p2));
-}
-
 /* ok_return (preverify_ok) is 1 if this stage of certificate verification
    passed, or 0 if it failed. This callback lets us display informative
    errors, and perform additional validation (e.g. CN matches) */
diff --git a/x509_name_match.c b/x509_name_match.c
new file mode 100644 (file)
index 0000000..ddfee3e
--- /dev/null
@@ -0,0 +1,87 @@
+#include "fetchmail.h"
+
+#include <string.h>
+#include <strings.h>
+
+/** A picky certificate name check:
+ * check if the pattern or string in s1 (from a certificate) matches the
+ * hostname (in s2), returns true if matched.
+ *
+ * The only place where a wildcard is allowed is in the leftmost
+ * position of p1. */
+int name_match(const char *p1, const char *p2) {
+    const char *const dom = "0123456789.";
+    int wildcard_ok = 1;
+
+    /* blank patterns never match */
+    if (p1[0] == '\0')
+       return 0;
+
+    /* disallow wildcards in certificates for domain literals
+     * (10.9.8.7-like) */
+    if (strspn(p1+(*p1 == '*' ? 1 : 0), dom) == strlen(p1))
+       wildcard_ok = 0;
+
+    /* disallow wildcards for domain literals */
+    if (strspn(p2, dom) == strlen(p2))
+       wildcard_ok = 0;
+
+    if (wildcard_ok && p1[0] == '*' && p1[1] == '.') {
+       size_t l1, l2;
+       int number_dots = 0;
+       const char *tmp;
+
+       ++p1;
+       /* make sure CAs don't wildcard top-level domains by requiring there
+        * are at least two dots in wildcarded X.509 CN/SANs */
+
+       for(tmp = p1; *tmp; tmp += strcspn(tmp, ".")) {
+           if (*tmp == '.') {
+               ++number_dots;
+               ++tmp;
+           }
+       }
+
+       if (number_dots >= 2) {
+           l1 = strlen(p1);
+           l2 = strlen(p2);
+           if (l2 > l1)
+               p2 += l2 - l1;
+       }
+    }
+
+    return (0 == strcasecmp(p1, p2));
+}
+
+#ifdef TEST
+#include <stdlib.h>
+#include <stdio.h>
+
+static int verbose;
+
+/* print test and return true on failure */
+static int test(const char *p1, const char *p2, int expect) {
+    int match = name_match(p1, p2);
+    if (verbose)
+       printf("name_match(\"%s\", \"%s\") == %d (%d expected)\n", p1, p2, match, expect);
+    return expect != match;
+}
+
+int main(int argc, const char **argv) {
+    int rc = 0;
+
+    if (argc > 1 && 0 == strcmp(argv[1], "-v"))
+       verbose = 1;
+
+    rc |= test("example.org", "example.org", 1);
+    rc |= test("*example.org", "foo.example.org", 0);
+    rc |= test("*.example.org", "foo.example.org", 1);
+    rc |= test("*.168.23.23", "192.168.23.23", 0);
+    rc |= test("*.com", "example.com", 0);
+    if (verbose) {
+       printf("x509_name_match: ");
+       puts(rc ? "FAIL" : "PASS");
+    }
+    return rc;
+}
+#endif