DNS over TLS – Thoughts and Implementation
DNS over TLS - Thoughts and Implementation
Sep 8, 18Discussion on Hacker News.
A week or so I discovered that Android P has DNS over TLS
support! It piqued my curiousity - could it finally be that DNS encryption goes mainstream?
In this post we’ll survey DNS over TLS, implement a client and share some thoughts!

    
      
  
    
    Party like it's 1983
  
TL;DR
Sure, with DNS over TLS your DNS queries are encrypted - that’s a major step forward!  Nevertheless, the
majority of the web relies on SNI (Server Name Indication),
which sends the domain name in plaintext! (not for long?).
I built a DNS over TLS Node.js package, install with $ npm i dns-over-tls:

And a DNS over TLS command line tool, install with $ npm i -g dnstls:

Why DNS over TLS?
DNS is insecure. It allows
anyone with an active internet tap to view user queries and forge answers.
Over the years there’ve been many proposals on securing DNS. Below is a
high level description of each, just so we’re on the same page.

DNSCurve - proposed by Daniel J. Bernstein (@hashbreaker),
provides confidentiality (data transport is encrypted), integrity (data can’t be modified in an undetected manner) and
authenticity (the origin is verified to be who it claims to be)
between recursive DNS servers (e.g. Google’s 8.8.8.8) and authoritative
name servers (e.g. ns.ibm.com).
DNSCrypt - based on DNSCurve, provides confidentiality and integrity
between stub resolvers (e.g. Android phone) and recursive DNS servers (e.g. Google’s 8.8.8.8)
DNSSEC - provides authenticity and integrity,
between resolvers (stub, recursive) and authoritative name servers. There’s
a heated debate around DNSSEC,
mainly because to achieve authentication, a new PKI (public-key infrastructure) was deployed,
one which allows for partial government control of DNS (since some TLDs and ccTLDS
are controlled by governments).

Bottom line, technicalities aside, the adoption of all lies somewhere
between low to non-existent - leaving DNS a potent attack vector,
~35 years since it was created!
Moreover, evidence that DNS is actively tampered with is shown by a recent Usenix 2018
paper - Who Is Answering My Queries: Understanding and Characterizing Interception of the DNS Resolution Path.
Nevertheless, do not despair! Recently, adoption of both DNS over TLS (DoT) and DNS over HTTPS (DoH) has been gaining
momentum, as evident by Android 9 support for DoT
and Firefox Nightly support for DoH.
How does DNS over TLS Work?
Similarly to DNSCrypt, DNS over TLS encrypts the link between a stub resolver
and a recursive resolver (1 and 8 below).

      
  
    
That is, it ensures no passive sniffing or active tampering of DNS can happen on that
link (unless, of course, the underlying cryptography is somehow broken).
But what about the links 2 to 7?
Communication between recursive resolvers and other nameservers is likely
to remain not private, but with the rising adoption of DNSSEC we can at least
expect authenticity! (That is, passive sniffing on DNS requests from recursive resolvers
would be possible, but active tampering won’t).
What if a rogue CA issues a valid certificate for the recursive resolver?
It’s possible for resourceful adversaries to obtain valid certificates for
domains. For this reason, DNS over TLS’s RFC (RFC7858)
introduces SPKI (Subject Public Key Info) Pinning:

Upon successful TLS connection and handshake, the client computes the
SPKI Fingerprints for the public keys found in the validated server’s
certificate chain (or in the raw public key, if the server provides
that instead).  If a computed fingerprint exactly matches one of the
configured pins, the client continues with the connection as normal.
Otherwise, the client MUST treat the SPKI validation failure as a
non-recoverable error.

In simple words, when you get the details of your DNS over TLS resolver,
such as IP address and hostname, you should also get an SPKI pin that
your client can use to verify that this is the original server public key. For instance, check
out the list of DNS over TLS servers at dnsprivacy.org -
an SPKI pin is provided for each server.
The SPKI Pin (“fingerprint”) is the SHA256 of the public key part of the
recursive resolver’s X509 certificate. As an implementation reference, we can look on how
Android P calculates it.
Here’s an example that utilizes OpenSSL’s CLI to calculate the
SPKI pin of Cloudflare’s DNS over TLS server:
$ echo | openssl s_client -connect '1.1.1.1:853' 2>/dev/null | openssl x509 -pubkey -noout | openssl pkey -pubin -outform der | openssl dgst -sha256 -binary | openssl enc -base64
Implementing a DNS over TLS Client
DNS over TLS simply tunnels good-old DNS packets over TLS with a default TCP port of 853.
Once a TLS session is established, the client sends a regular
DNS query and the server responds with a message that is prefixed with a
two byte length field which gives the message length, excluding the two bytes
length field.
Here’s a client implementation:

One thing that I haven’t implemented yet is SPKI pinning. Why? The SPKI Pin
requires the raw public key DER of the server’s
certificate -  which is only available for Node.js  9 and 10. And while for
older Node.js versions you can actually get the DER of the entire certificate,
carving the public key DER out of it is a delicate art, which I didn’t feel like doing :) (at least for now).
Playing with DNS over TLS
DNS over TLS is fairly new and there aren’t many tools for it -
for this reason I made dnstls - a DNS over TLS command line tool:

It defaults to using Cloudflare’s DNS over TLS server (1.1.1.1).
Install with:

Usage is dig-like:
$ dnstls
Usage: dnstls name [type] [class] [@server] [-p<port>] [+tls-host=<host>]
Where:

name is the domain you’d like to resolve.
type is the record type you’re after - e.g. A (default), AAAA, NS ,TXT, MX, CNAME etc.
class is either IN (default), HSor CH.
port is the TCP port, defaults to 853.
server the address of the server, defaults to 1.1.1.1.
+tls-host the TLS hostname that is noted in the server’s certificate, defaults to cloudflare-dns.com.

Note: the server and +tls-host goes hand in hand - for instance, say
we’d like to use Quad9’s DNS over TLS server, we’d have to do:
$ dnstls @9.9.9.9 +tls-host=dns.quad9.net sagi.io
The output is a JSON of the response (maybe dig-like output in the future).
Example:
{
  "id": 42209,
  "type": "response",
  "flags": 384,
  "flag_qr": true,
  "opcode": "QUERY",
  "flag_aa": false,
  "flag_tc": false,
  "flag_rd": true,
  "flag_ra": true,
  "flag_z": false,
  "flag_ad": false,
  "flag_cd": false,
  "rcode": "NOERROR",
  "questions": [
    {
      "name": "sagi.io",
      "type": "A",
      "class": "IN"
    }
  ],
  "answers": [
    {
      "name": "sagi.io",
      "type": "A",
      "ttl": 101,
      "class": "IN",
      "flush": false,
      "data": "151.101.65.195"
    },
    {
      "name": "sagi.io",
      "type": "A",
      "ttl": 101,
      "class": "IN",
      "flush": false,
      "data": "151.101.1.195"
    }
  ],
  "authorities": [],
  "additionals": []
}
Thoughts
DNS over TLS is a major step forward towards a safer, more private, world.
Nevertheless, here’re some thoughts:
Not a Commonly-used Default Port
I developed both library and command line client while working from Google
Campus Tel Aviv - which unfortunately blocks
all outgoing TCP connections that aren’t using commonly used destination ports
(such as 443, for instance). I suspect that this is going to be an issue
for many networks.
Most Web DNS Traffic is Still Not Private
Sure, with DNS over TLS your DNS queries are encrypted - that’s a major step forward!  Nevertheless, the
majority of the web relies on SNI (Server Name Indication),
which sends the domain name in plaintext! (not for long?).
Summary
I’d like to thank the folks at the DNS Privacy Project
and the DPRIVE Working Group
for their efforts! I think it finally starts to pay off :)
If you’re interested in DNS privacy, there’s a wealth of information in dnsprivacy.org
and I invite you to watch NDSS 2018’s
DNS Privacy Workshop
sessions - very insightful.
If you spot an error / have any question please let me know so others may gain :)
Comments and thoughts are also welcome on this tweet:
DNS over TLS - Thoughts and Implementation #DNS #Privacy #NodeJS https://t.co/4OnlTu8WkQ— Sagi Kedmi (@SagiKedmi) September 8, 2018



