Keyserver/security bug 1447 (and 1446 too)

Phil Pennock gnupg-devel at spodhuis.org
Mon Dec 3 04:55:54 CET 2012


On 2012-12-02 at 12:57 -0500, David Shaw wrote:
> On Dec 2, 2012, at 12:34 AM, Phil Pennock <gnupg-devel at spodhuis.org> wrote:
> > This first bug (1447) is a security-impacting bug; not too bad, since
> > PGP has message-level security, so the key data isn't impacted, but it
> > does permit MitM attacks for discerning what's happening.  GnuPG uses
> > data from insecure DNS for presenting to an HTTPS-enabled keyserver as
> > TLS SNI and for verifying certificates.  So if DNS responses are
> > tampered with, the injected bad server will verify fine for the client.
> 
> Allow me to restate the problem to make sure I understand what you're
> saying. GnuPG does a SRV lookup for hkps under (for example)
> my-hkps-pool.example.com, and resolves to
> some-keyserver-in-the-pool.example.net.  It then makes a https call to
> that host, but is using keyserver-in-the-pool.example.net as the SNI,
> as that matches the host name. You are arguing that it should have
> used my-hkps-pool.example.com as the SNI?

Correct.  That's the only verifiably trustworthy name available.  All
other names could have been tampered with, without detection (unless
DNSSEC is in use and verified).

> If that's the issue, I agree that is not ideal. It's sort of a side
> effect of how we're doing SRV with Curl. Since Curl doesn't do SRV at
> all, we have a wrapper around libcurl that does a minimal emulation of
> true SRV and then forces the URL to be what it should be, according to
> the SRV.

I hear you.  Sounds truly awkward with some kludging needed to fix.  As
an application maintainer who has to work around library awkwardness
myself, you have my sympathy.

> As far as I know, libcurl uses the host from the passed-in URL for SNI
> and there isn't a direct option to set the SNI to an arbitrary value,
> but looking at the options, CURLOPT_RESOLVE could be used to fix this
> by feeding in a record with the pool name and the address of the
> chosen server.

That matches what I've done on the curl(1) command-line to test the
setup in the past.  I concur, I can't find an API to hook into DNS
resolution to change things otherwise, nor to change the SNI presented.

Looks like CURLOPT_RESOLVE is the only available mechanism.

So, as I understand it, to handle SRV, ports and SNI in combination,
it's:
 * take the original hostname OHost
 * look for SRV record for _pgpkey-http/_pgpkey-https._tcp.$OHost,
   ignore this logic if neither SRV is found because we're connecting to
   something where the hostname resolves directly to what's neeeded
 * for each SRV record, take the hostname and port
   * resolve the per-srv-record hostname to IP addresses
   * iterate for each IP address:
     * construct a curl_slist, populate with one triple of
         $OHost:per-srv-record-Port:IP-Address
     * curl_easy_setopt() with CURLOPT_RESOLVE to set that triple
     * attempt to connect with curl, on the port from SRV, using the
       $OHost hostname
     * curl_easy_setopt()/CURLOPT_RESOLVE/ "-$OHost:per-srv-record-Port"

There doesn't appear to be a way to provide multiple IPs for one
hostname.

Curl_loadhostpairs() shows that the clean-up is overkill, but I'm not
confident in the resiliency of this API to a later change to permit
multiple records for one hostname, especially since some of the usage
comments don't even include the port field.

> Ideally, libcurl would handle SRVs internally,

Complete APIs from a library?  Any library?  Thou jesteth.

Sorry to have been the bearer of bad news about the size of the can of
worms you opened when adding SRV support.

-Phil



More information about the Gnupg-devel mailing list