Designing a DNSSEC application API
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:
.setDnssecMode(DnssecMode dnssecMode); ConnectionConfiguration
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.