aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Andree <matthias.andree@gmx.de>2010-08-27 21:33:04 +0200
committerMatthias Andree <matthias.andree@gmx.de>2010-08-27 21:33:04 +0200
commit8d10076819e41620147013c8446809c085b1e0bf (patch)
tree074eca4844c61409f42fcf0a093c9b7c4adba642
parent480b13c7e6d83543a82b2974a3af0c8864d7b6a7 (diff)
downloadfetchmail-8d10076819e41620147013c8446809c085b1e0bf.tar.gz
fetchmail-8d10076819e41620147013c8446809c085b1e0bf.tar.bz2
fetchmail-8d10076819e41620147013c8446809c085b1e0bf.zip
X.509 matching split out; disallow TLD wildcards.
-rw-r--r--Makefile.am2
-rw-r--r--NEWS1
-rw-r--r--fetchmail.h3
-rw-r--r--socket.c36
-rw-r--r--x509_name_match.c87
5 files changed, 92 insertions, 37 deletions
diff --git a/Makefile.am b/Makefile.am
index 0e597d05..6a12786b 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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 a63a3d9c..06e3f855 100644
--- 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
diff --git a/fetchmail.h b/fetchmail.h
index 0315a9da..9502d1e3 100644
--- a/fetchmail.h
+++ b/fetchmail.h
@@ -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)) \
diff --git a/socket.c b/socket.c
index d3cf90d7..2a3e1ba1 100644
--- 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
index 00000000..ddfee3eb
--- /dev/null
+++ b/x509_name_match.c
@@ -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