Bug 658 - unbound using TLS in a forwarding configuration does not verify the server's certificate
unbound using TLS in a forwarding configuration does not verify the server's ...
Status: RESOLVED FIXED
Product: unbound
Classification: Unclassified
Component: server
unspecified
x86_64 Linux
: P5 enhancement
Assigned To: unbound team
Depends on:
Blocks:
  Show dependency treegraph
 
Reported: 2015-03-25 01:16 CET by Daniel Kahn Gillmor
Modified: 2018-04-23 16:20 CEST (History)
5 users (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Daniel Kahn Gillmor 2015-03-25 01:16:34 CET
(this is for unbound 1.5.3, but i don't see it in the list above)

I have the following unbound.conf to act as forwarder to another TLS-over-TCP unbound implementation:


--------
forward-zone:
 name: "."
 forward-addr: 192.0.2.3@443
server:
 ssl-upstream: yes
 tcp-upstream: yes
 do-daemonize: no
 logfile: ""
 verbosity: 10
--------

However, there appears to be no verification of the server's certificate -- the server i'm speaking to has a self-signed certificate, and unbound has no way to know about it initially, so i don't see how it could possibly be verifying the cert.

how to verify the cert itself is an interesting question, though:  you can't identify the remote host by name (because we don't want to have to have DNS to do the lookup), and we generally discourage X.509 certs with an IP address in the subjectAltNames.

So i think the configuration mechanism should be one of the following options (maybe we can offer :

A)
 * forward-fingerprint: an sha256 sum of the Subject Public Key Info of the server's certificate

B)
 * forward-name: the name of upstream server (this is like forward-host, except that it is only used for cert validation, and not looked-up before connection)
 * forward-cafile: a file containing the certificates of the root certification authorities allowed to issue certs for the forwarded server; (the verification mechanism looks for a valid cert for forward-name (if present) or forward-host).
Comment 1 Wouter Wijngaards 2015-03-25 08:57:50 CET
Hi Daniel,

Yes the ssl-upstream feature wraps traffic in tls, but does not verify certificates.  It's documented.  For authentication, perhaps we could see what the dprive IETF WG comes up with in their standardisation?  They are currently working on dns over tls.  I would not want to pre-empt their solution.

I would recommend to use DNSSEC to authenticate the data across this connection.

Best regards,
   Wouter
Comment 2 Daniel Kahn Gillmor 2015-04-06 22:34:04 CEST
(In reply to Wouter Wijngaards from comment #1)

> Yes the ssl-upstream feature wraps traffic in tls, but does not verify
> certificates.  It's documented.

Hm, the documentation of this gap wasn't clear to me.  I did not see any mention of lack of verification in unbound.conf (i inferred it from the behavior of the tool)

> For authentication, perhaps we could see
> what the dprive IETF WG comes up with in their standardisation?  They are
> currently working on dns over tls.  I would not want to pre-empt their
> solution.

Please do not wait on output from dprive; You will not pre-empt anything.  If anything, dprive needs input from real-world deployments (which unbound can provide) to drive its decision-making process.

> I would recommend to use DNSSEC to authenticate the data across this
> connection.

That would be a great step as well, though it is perhaps a chicken-and-egg solution (how do we get the DNSSEC info if all we have is a TLS connection to the upstream server?).

Getting started with something simple like (A) or (B) proposed above would be much more straightforward, and could be overridden by a DNSSEC-verification mechanism (maybe via a TLS extension?) in the future.

Would you be interested in a patch for proposal (A)?
Comment 3 Matt 2017-11-04 12:23:34 CET
There is some additional information in authenticating dns over tls servers here:
https://tools.ietf.org/html/draft-ietf-dprive-dtls-and-tls-profiles-01#section-5

In particular, they propose using SRV records, as long as DNSSEC is verified, or spki's to, if I am understanding correctly, verify the certificate's name.
Comment 4 Matt 2017-11-04 12:28:30 CET
There is some additional info on authentication here:https://tools.ietf.org/html/draft-ietf-dprive-dtls-and-tls-profiles-01#section-5

In particular, they propose using srv records to authenticate the hosts on the certificate or spki
Example service records (for TLS and DTLS respectively):

      _domain-s._tcp.dns.example.com.  SRV 0 1 853 dns1.example.com.
      _domain-s._tcp.dns.example.com.  SRV 0 1 853 dns2.example.com.

      _domain-s._udp.dns.example.com.  SRV 0 1 853 dns3.example.com.
Comment 5 Wouter Wijngaards 2017-11-06 09:30:26 CET
Hi Matt, Daniel,

The issue is that there is no good proposal in that list in that document.  All of them require some sort of pre-distributed keys (hard-coded keys are a recipe for failure), or in fact pre-coded something else (what you use to look up that DNSSEC stuff).  All of that only works for hardcoded 'use this public resolver' and not actually for the normal resolving cases.

I would like to have code that implements authentication.  Preferably in a good way (eg. won't cause further problems, I mean keys can change, you know, like X509 certificates allow key changes).  It is just that all the current proposals are bad, and a lot a similar, they simply fail to be usable.  Because they are all similarly bad, eg. only for public resolvers, not enabled by default, not for 10.0.0.0/8 resolvers, and so on.  I don't want to move ahead of the vetted 'this is the correct solution', because I cannot choose and I do not want to choose a bad security solution.

So, anyway, that stuff is in progress.  And in the document the actual problem changed to 'public resolver', 'fixed destination' and 'pre-configured parameters'.  Which is vastly different from the workgroup mission, DNS privacy, which starts somewhere when you log on.  And this has mostly 10.0.0.0/8 (LAN) DNS, with no authenticated components.

So, in summary, I want good security too, but the proposals are bad, and I don't want to implement 'too early' a bad solution.

Best regards, Wouter
Comment 6 Martin 2018-03-24 22:07:19 CET
For the record, here is how stubby does. It provides the following configuration for SPKI pinsets:

tls_pubkey_pinset:
  - digest: "sha256"
  - value: 62lKu9HsDVbyiPenApnc4sfmSYTHOVfFgL3pyB+cBL4=

This is used in strict mode:  "In 'Strict' mode authentication information (e.g. an authentication name or a SPKI pinset) MUST be provided for each nameserver and DNS queries will only be sent if Stubby can authenticate the namerserver using this information."

If you decide to go for this solution, I guess that a similar configuration option could be added in unbound, eg "forward-ssl-tls-pubkey-pinset"

Best regards, --Martin
Comment 7 Daniel Kahn Gillmor 2018-04-10 16:35:54 CEST
i recommend starting by offering the name of the upstream resolver as an authentication mechanism, and only afterward implementing spki pinsets if you think they offer some sort of concrete advantage.

https://tools.ietf.org/html/rfc8310 recommends authentication based on name in several forms.

note that the two largest DNS-over-TLS deployments today offer valid X.509 certificates for their names:

  9.9.9.9 → dns.quad9.net
  1.1.1.1 → cloudflare-dns.com
Comment 8 Martin 2018-04-11 21:26:44 CEST
On this topic, I've just written a post that may be of interest for you: https://www.monperrus.net/martin/randomization-encryption-dns-requests
Comment 9 Wouter Wijngaards 2018-04-19 14:42:58 CEST
Hi Daniel,

The current code repository implements TLS authentication for forwarders.

The syntax is forward-addr: <IP-address>[@port][#tls-authentication-name]
And the ca bundle can be set with: tls-cert-bundle: "ca-bundle.pem"
(or the ca-bundle.crt file).

Example
server:
  tls-cert-bundle: "/etc/pki/tls/certs/ca-bundle.crt"
forward-zone:
  name: "."
  forward-tls-upstream: yes
  forward-addr: 9.9.9.9@853#dns.quad9.net
  forward-addr: 1.1.1.1@853#cloudflare-dns.com

The hashtag name trick makes it so that the tls authentication name can also be set for eg. stub-zones and with unbound-control forward control commands.  It was also easier in the code.  There should be no spaces around the '@' and '#'.

The port number is really optional, but defaults to port 53 right now (like for ordinary DNS).

When I tested, the servers for dns.quad9 and cloudflare-dns work.

The code looks easy to change for having tls authentication for authority servers (it probably already works using configuration with stub-addr).

Best regards, Wouter
Comment 10 Wouter Wijngaards 2018-04-19 16:24:28 CEST
Hi Daniel, Martin,

Fixed the default, which is now port 853 when you specify a tls authname.  (And still 53 for others).

So the examples can be simplified like this
  forward-addr: 9.9.9.9#dns.quad9.net
  forward-addr: 1.1.1.1#cloudflare-dns.com

Best regards, Wouter
Comment 11 Martin 2018-04-20 08:42:07 CEST
Thanks a lot Wouter.

Do you know a reference list of DNS-over-TLS servers that we can trust?

--Martin
Comment 12 Wouter Wijngaards 2018-04-20 08:55:06 CEST
Hi Martin,

I don't know how to get a list of trusted servers.  You could try asking the unbound-users mail list to see if other users know them.  Two public resolvers are listed in above entries that support DNS-over-TLS.

Best regards, Wouter
Comment 13 ilf+nlnetlabs.nl 2018-04-20 11:09:20 CEST
There is a list of servers at https://dnsprivacy.org/wiki/display/DP/DNS+Privacy+Test+Servers, but that doesn't say anything about "trust".
Comment 14 Wouter Wijngaards 2018-04-23 16:20:47 CEST
Hi,

I guess this resolves the bugreport, thanks for the persistence.

Best regards, Wouter