From Fedora Project Wiki

DNSSEC overview

Make various man-in-the-middle attacks *automatically* detectable - without any user interaction. Especially we want to get rid of dialogs like "Site www.gmail.com is using certificate issued for xxx.porn and certificate's validity ended 10 years ago. Do you want to continue? [YES] [YES] [YES]".

Tools

To achieve this goal we need to do DNSSEC validation on every client machine (ignoring Docker for a moment, see below) and allow applications to use DNS as trusted source of sensitive data (certificate fingerprints, SSH fingerprints, etc.).

DNSSEC allows all parties to publish their fingerprints in DNS and gives us a secure way to get the data and to detect that someone prevents us from getting the data.

First step: DNSSEC validation

Contemporary networks are full of broken DNS proxies so we need to jump through various hoops to get non-faked DNSSEC data for DNSSEC validation.

The goal of this step is to get *cryptographical* proof that the data we received are the same as DNS zone owner published.

Second problem: API for applications

(this second step is not part of the F23 feature but it is worth discussing) Applications and crypto libraries need "an" interface to get DNS data which are either 100 % correct or declared as not trusted. False positive (trusted) answers are simply unacceptable because that would allow serious attacks.

Imagine that OpenSSH client is verifying server's fingerprint against the value obtained from DNS *instead of asking the user*. If the client accepted a fake response with faked server's fingerprint then everything is doomed.


The proposal https://sourceware.org/ml/libc-alpha/2014-11/msg00426.html on glibc mailing list is to extend getaddr API with flag which says 'secure answers only'. This will return an answer only if DNSSEC validation for given answer was successful and the answer was properly signed.

The assumption here is that something like dnssec-trigger properly configures local resolver (using the information from DHCP + applying all the necessary workarounds) to do DNSSEC validation locally so we are 100 % sure that the fake answer can be detected.

The open question is how to pass the information about security status to all the parties. The mechanism needs to be simple so other resolver libraries like e.g. python-dns can follow the same rules and use the same logic as Glibc.

Possible states:

a) We are in hot-spot sign-on mode or validating resolver is unavailable for some reason (early boot, resource constraints, Docker container [finally!], and so on):

In this case *nothing* can be trusted. Resolver might return faked answers and we have no means to check if declared trustworthiness is correct or not. Again, we need to be 100 % sure from the cryptographical point of view.

=> Application MUST NOT receive any answer marked as "secure"/"trusted" if we are in this mode.


b) Validating resolver is up, running, properly configured, and the path to the resolver is trusted - it might be running on localhost or we are in Docker container and we trust the host and so on.

In this case we trust to the result of validation indicated by AD bit. Application will receive the answer marked as trusted if the resolver tells us to do so by AD bit in the DNS reply.

Please read the post on Glibc mailing list for more details.

Any suggestions how to do that are more than welcome!


Configuration requirements

Option is either to implement all the checks and workarounds in all the projects over and over or to implement all the logic in one place - dnssec-trigger might be such place.

Anyone who is going to write to resolv.conf needs to check for captive portals, find a DNSSEC-enabled DNS server, and deal with VPN-provided DNS servers and domains.

NetworkManager operations

The main network configuration tool is NetworkManager. When using DNSSEC it is combined with dnssec-trigger via a script shipped in the dnssec-trigger package.

Common operations

With or without DNSSEC, NetworkManager gathers the list of recursive name servers from DHCP and/or configuration. The purpose of those name servers is to answer DNS queries including those for DNSSEC records. Those name servers are not meant to be trusted for anything else than attempting to answer the queries and especially not for performing DNSSEC validation.

Without DNSSEC

When DNSSEC is not in use, the easiest way to handle the list of name servers is to put them into /etc/resolv.conf so that the stub resolver can do its job.

As /etc/resolv.conf doesn't support advanced configuration, it is often useful to instead configure a local recursive DNS server (e.g dnsmasq or unbound) with the name server list and point the stub resolver to the local host using /etc/resolv.conf.

With DNSSEC

When DNSSEC is in use, after gathering the recursive nameservers, NetworkManager reconfigures a local unbound instance using dnssec-trigger. In this case the stub resolver should point to the local unbound instance and it should be instructed that the local unbound instance is not just an ordinary recursive name server but also a trusted DNSSEC validator.

Notes

Problem: There is currently no way to distinguish ordinary recursive name servers and trusted DNSSEC validators in the stub resolver configuration, see later.

Mobility challenges

Captive portals (aka hotspots)

Captive portal detection needs to allow the user to log into the captive portal without being restricted by DNSSEC validation. The user might also want to access the hotspot resources even after logging also without being restricted by DNSSEC validation if the hotspot uses a hijacked domain name that is not designated as insecure in the global DNS tree.

All of the above has to be done in a way that doesn't allow an attacker to compromise security.

Broken networks

Some networks are so broken that even without captive portal they are not able to deliver DNSSEC data to the clients. In that case will try tunnel to other DNS servers on the Internet (Fedora Infra or public DNS root) and use them. Naturally, local/internal domains need to be available.

These sub-problems (including VPN handling an so on) are solved by dnssec-trigger with tweaks by Tomas Hozza and Pavel Simerda.

Interesting packages

  • NetworkManager
  • initscripts
  • dhclient
  • libreswan ?
  • resolved ?
  • connman ?

Stub resolver requirements / API for applications

Applications and cryptographic libraries need an interface to get DNS data that is either verified using a trusted DNSSEC validator (e.g. a local unbound instance) or declared as not trusted (not verified using DNSSEC). False positive answers are unacceptable because treating ordinary DNS data as DNSSEC secure data would allow attacks on applications that use DNSSEC secure data for security purposes.

Example: SSH server fingerprint verification

Imagine that OpenSSH client is verifying server's fingerprint against the value obtained from DNS instead of asking the user. If the client accepted a fake response with faked server's fingerprint then everything is doomed.

Overview

The assumption here is that (something like) dnssec-trigger properly configures local resolver to do DNSSEC validation locally so that a fake DNS answer is detected and never gets it to the application and a DNSSEC secure DNS data is distingushed from DNS insecure data. The open question is how to pass the information about security status to all the parties. The mechanism needs to be simple so other resolver libraries like e.g. python-dns can follow the same rules and use the same logic as Glibc.

Expected behavior

Those distribution policies have been correct for ages. Before DNSSEC was created, noone would question them.

We were looking for a solution where:

1) Application or security library can trust the data from glibc resolver including security information.

2) Resolver can provide unauthenticated DNS data when in non-DNSSEC mode and the list of recursive name servers is configured by a system administrator or an automated tool.

3) Resolver can provide autenticated DNS data when in DNSSEC mode andthe list of trusted resolvers is provided by the system administrator (rarely) or by an automated tool (in most cases giving just 127.0.0.1).

The most important thing is that the application never receives autenticated data that were only verified by an ordinary recursive server. That would mean an implicit trust in an unauthorized and unexpected DNSSEC validator.

Note that a recursive name server is typically a host on the local network announced by DHCP while a trusted validator is typically the local machine which itself is talking to a recursive name server.

Case: Captive portal, broken DNSSEC or DNSSEC turned off

We are in hot-spot sign-on mode or validating resolver is unavailable for some reason (early boot, resource constraints, Docker container [finally!], and so on):

In this case *nothing* can be trusted. Resolver might return faked answers and we have no means to check if declared trustworthiness is correct or not. Again, we need to be 100 % sure from the cryptographical point of view. Application must not recieve any DNS answer marked as DNSSEC secure in this mode.

Case: DNSSEC fully configured

Validating resolver is up, running, properly configured, and the path to the resolver is trusted - it might be running on localhost or we are in Docker container and we trust the host and so on.

In this case we trust to the result of validation indicated by AD bit. Application will receive the answer marked as trusted if the resolver tells us to do so by AD bit in the DNS reply.

Current status

The current implementation in glibc doesn't achieve the goals stated above and doesn't prevent the security problem of implicitly using foreign recursive name servers as trusted DNSSEC validators.

We have an experimental implementation using '/etc/resolv-secure.conf' that solves the problem. I'm looking forward to see any alternatives. The issue has been holding back DNSSEC deployment for long and might cause a lot of damage.

Solution: Separate file where all DNS servers are DNSSEC validators

We have an experimental solution that relies on a separate resolv-secure.conf file. As opposed to /etc/resolv.conf typically containing the list of recursive name servers, resolv-secure.conf contains a list of trusted DNSSEC validators in form of validating DNSSEC servers. The list typically includes a single DNSSEC validator which is running on the local host.

See also:

Advantages

  • The file can be separately protected using mandatory access control. The whole stub resolver configuration is protected.
  • The syntax is identical to /etc/resolv.conf. On a DNSSEC enabled system, /etc/resolv.conf can be just a symlink to /etc/resolv.conf.

Alternative solution: option secure-nameserver

Use a special

Risks

  • The configuration file could not be protected by mandatory access control while at the same time allowing tools to write a /etc/resolv.conf configuration when not using DNSSEC.

Alternative solution: option secure-dns

(or for example option trust-dnssec-validation)

Mark /etc/resolv.conf configuration as secure when providing the list of secure DNSSEC validators.

Risks

  • An existing tool might rewrite the list of name servers and keep the unknown options including option secure-dns.

Alternative solution: option insecure-dns

Mark /etc/resolv.conf configuration explicitly as insecure unless providing the list of secure DNSSEC validators.

Risks

  • Existing /etc/resolv.conf files would be wrongly considered secure for DNSSEC validation.
  • Existing tools would generate such files.

FAQ

Why is it wrong to implicitly trust the AD flag from recursive name servers

AD flag is how a validating name server informs the requester that the returned DNS data have been successfully validated using the DNSSEC mechanism.

There is a huge difference between using an untrusted recursive name server to retrieve DNS data and using an untrusted DNSSEC validator. DNSSEC works well with untrusted recursive name servers but its security is jeopardized by using them as DNSSEC validators. Applications may attribute additional trust to the validated data especially when they contain security keys for TLS, SSH and other authenticated protocols.

Trusting a random DNSSEC validator is like trusting a random security certificate.

Does DNSSEC work on untrusted or public networks?

Yes. There is no such concept as trusted or untrusted network in DNSSEC. The confusion comes from the distinction between a recursive name server (used by the system to retrieve DNS data) and a DNSSEC validator (which is typically a validating name server running on the local host).

For DNSSEC, all we need is to never implicitly use recursive name servers as trusted DNSSEC validators. In our opinion, the preferred way to implement that is to avoid passing security information from ordinary recursive name servers (not configured as trusted DNSSEC validators).

Does NetworkManager need to keep track of trusted DNSSEC validators

No. When working with dnssec-trigger, NetworkManager only needs to keep track of learnt and configured recursive name servers. The list of trusted DNSSEC validators always contains a single unbound instance running on the local host.

TODO

Some terms might need to be improved, especially recursive name server doesn't really say what we want to say which is a name server that is used by the system to gather necessary DNS data.

Resources

User:pavlix wrote most if this site using mostly sources of his own and those written by User:thozza and User:pspacek.