Designing a DNSSEC application API

Posted on October 26, 2016
Tags: dnssec, xmpp

I’m intending to apply a patch adding DNSSEC support to Smack, a XMPP client library, in the near feature. And since DNSSEC support in application protocol libraries is still uncommon, I thought it might be a good idea to share the principles how the API was designed.

DNSSEC

DNSSEC authenticates DNS answers, positive and negative ones. This means that if a DNS response secured by DNSSEC turns out to be authentic, then you can be sure that the domain either exists, and that the returned resource records (RRs) are the ones the domain owner authorized, or that the domain does not exists and that nobody tried to fake its non existence.

The tricky part is that an application using DNSSEC can not determine whether a domain uses DNSSEC, does not use DNSSEC or if someone downgraded your DNS query using DNSSEC to a response without DNSSEC.

Smack’s DNSSEC API

I like to keep APIs I design as simple as possible to use for the user. Thus Smack’s DNSSEC API simply extends the already existing ConnectionConfiguration used to – you guessed it – configure XMPP connections by a single method:

ConnectionConfiguration.setDnssecMode(DnssecMode dnssecMode);

where DnssecMode is an enum defined as follows:

enum DnssecMode {
  disabled,
  needsDnssec,
  needsDnssecAndDane,
}

The user simply calls config.setDnssecMode(DnssecMode.needsDnssec) and Smack will only connect to an XMPP service if all involved DNS resource recordes could be verified using DNSSEC.

You may noticed the ...AndDane variant of the enum. If this mode is used, then Smack will not only require DNSSEC, but also require DANE (RFC 6598) in order to verify the service’s TLS certificate.

Desiging for a good UI and UX

The Issue

The issue with the DnssecMode API exposed by Smack is that an application should never have to ask the end-user if it’s XMPP account is secured by DNSSEC. There should be no questionare, checkbox or whatever about this feature. The best UI regarding a option is if there is none, i.e., if it just works out of the box.

A possible solution

So what should applications do? The answer is simple and similar to “HTTP Strict Transport Security” (HSTS, RFC 6797) used for HTTP(S) connections. Instead of asking the user if DNSSEC is available, they should check for DNSSEC support on every connection attempt. Once DNSSEC support has been discovered, the application uses the needsDnssec mode for all future connection attempts.

An analysis

Of course this scheme is not without drawbacks. First, it is possible that an attacker downgrades the DNS responses to non-DNSSEC. Depending on where the attacker sits in the path between the user and its service, this may always be possible for the attacker or only if the user’s device uses a certain network. The downgrade attack also becomes impossible with this scheme after the application was at least once able to connect to the service using DNSSEC.

Furthermore, if the user’s service needs to drop DNSSEC support for whatever reason (technical, political, …), then the user possible gets a message that the connection failed because something named “DNSSEC” was not avaialble. As with most security concepts, it is hard for the average user to asses situation and take the approbiate action. Of course, the application could ask the user to contact the service provider and ask if DNSSEC was indeed disabled before continuing the connection attempt.

But ideally, service providers would never drop DNSSEC support and the application would simply start a new connection attempt after a failed one caused by the lack of DNSSEC. This is similar to how most applications would (or should) treat a STARTTLS downgrade attack: Simply retry until the demanded security gurantees are fullfiled. Then the user doesn’t have to deal with technical error messages.

Note that the exact same scheme can be used with the needsDnssecAndDane mode. Once DNSSEC and a TLSA RR has been discovered for the service and was successfully used to verify the TLS connection, the application should always use the needsDnssecAndDane mode.

Why not in Smack?

The attentive reader may wonder why I did not implement the described mechanism in Smack, instead of having the application deal with it. I’d really love to do so, but Smack has no API and mechanism for saving a connection state to persistent storage. This would be required for the described scheme. Such a mechanism planned to come with Smack 4.3 though.