Re: Re: [COMMITTERS] pgsql: Add support for matching wildcard server certificates to the new - Mailing list pgsql-hackers
From | Magnus Hagander |
---|---|
Subject | Re: Re: [COMMITTERS] pgsql: Add support for matching wildcard server certificates to the new |
Date | |
Msg-id | 49300AB2.8040307@hagander.net Whole thread Raw |
In response to | Re: Re: [COMMITTERS] pgsql: Add support for matching wildcard server certificates to the new (Peter Eisentraut <peter_e@gmx.net>) |
Responses |
Re: Re: [COMMITTERS] pgsql: Add support for matching wildcard server certificates to the new
Re: Re: [COMMITTERS] pgsql: Add support for matching wildcard server certificates to the new |
List | pgsql-hackers |
Peter Eisentraut wrote: > I wrote: >> Some more information on this: >> https://www.switch.ch/pki/meetings/2007-01/namebased_ssl_virtualhosts.pdf >> slide 5 lists the matching rules for email, HTTP, and LDAP over TLS, >> respectively, which are not all the same. Also note that these methods >> have rules for interpreting fields in the certificate other than the common >> name for the host name. >> >> I think it is safest and easiest to allow a * wildcard only as the first >> character and only when followed immediately by a dot. >> >> Maybe some DNS expert around here can offer advice on what a morally sound >> solution would be. > > This page summarizes the sadness pretty well: > > http://wiki.cacert.org/wiki/WildcardCertificates Yuck, that was certainly sad. I think the most reasonable thing is to match the way that "modern browsers" appear to do, which is that it matches * against subdomains as well. Matching *only* as the first character will make it impossible to make certificates for "www*.domain.com", which is AFAIK fairly popular - and one of the examples you'll find on CA sites. But it would be fairly easy to add this restriction if people feel that's a better way. See attached patch which takes out the parts of fnmatch that we're not interested in, and puts it directly in fe-secure.c. Obviously, if we go down that way, we can remove fnmatch.c from port again :-) Thoughts? //Magnus diff --git a/src/interfaces/libpq/fe-secure.c b/src/interfaces/libpq/fe-secure.c index 828e867..28e254f 100644 --- a/src/interfaces/libpq/fe-secure.c +++ b/src/interfaces/libpq/fe-secure.c @@ -55,6 +55,7 @@ #endif #ifdef USE_SSL + #include <openssl/ssl.h> #include <openssl/bio.h> #if (SSLEAY_VERSION_NUMBER >= 0x00907000L) @@ -64,16 +65,6 @@ #include <openssl/engine.h> #endif -/* fnmatch() needed for client certificate checking */ -#ifdef HAVE_FNMATCH -#include <fnmatch.h> -#else -#include "fnmatchstub.h" -#endif -#endif /* USE_SSL */ - - -#ifdef USE_SSL #ifndef WIN32 #define USER_CERT_FILE ".postgresql/postgresql.crt" @@ -444,6 +435,55 @@ verify_cb(int ok, X509_STORE_CTX *ctx) } /* + * Check if a wildcard certificate matches. This code is based on the + * NetBSD version of fnmatch(), but adapted to match wildcard certificates + * by removing much of the filename/directory specific functionality. + * Based on what "most others" do for https, we match the wildcard '*' to + * any part, *including* subdomains. This is contrary to RFC2818, but it is + * what most modern browsers match + * (see http://wiki.cacert.org/wiki/WildcardCertificates) + * + * Matching is always cone case-insensitive, since DNS is case insensitive. + */ +static int +wildcard_certificate_match(const char *pattern, const char *string) +{ + const char *stringstart; + char c, test; + + for (stringstart = string;;) + { + switch (c = tolower(*pattern++)) { + case '\0': + return (*string == '\0') ? 0 : 1; + case '*': + c = tolower(*pattern); + /* Collapse multiple stars. */ + while (c == '*') + c = tolower(*++pattern); + + if (c == '\0') + return 0; + + /* General case, use recursion. */ + while ((test = tolower(*string)) != '\0') + { + if (!wildcard_certificate_match(pattern, string)) + return 0; + ++string; + } + return 1; + default: + if (c != tolower(*string++)) + return 1; + break; + } + /* NOTREACHED */ + } +} + + +/* * Verify that common name resolves to peer. */ static bool @@ -472,7 +512,7 @@ verify_peer_name_matches_certificate(PGconn *conn) if (pg_strcasecmp(conn->peer_cn, conn->pghost) == 0) /* Exact name match */ return true; - else if (fnmatch(conn->peer_cn, conn->pghost, FNM_NOESCAPE/* | FNM_CASEFOLD*/) == 0) + else if (wildcard_certificate_match(conn->peer_cn, conn->pghost) == 0) /* Matched wildcard certificate */ return true; else
pgsql-hackers by date: