Keyserver/security bug 1447 (and 1446 too)
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,
* 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
* curl_easy_setopt() with CURLOPT_RESOLVE to set that triple
* attempt to connect with curl, on the port from SRV, using the
* curl_easy_setopt()/CURLOPT_RESOLVE/ "-$OHost:per-srv-record-Port"
There doesn't appear to be a way to provide multiple IPs for one
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.
More information about the Gnupg-devel