DNS Security II : DNSSEC

Originally published in SysAdmin Magazine, October 2004

Contents

      Introduction
      Secure DNS Zones
      Testing DNSSEC secure zones
      Making use of Secure zones for non-DNSSEC clients
      Conclusion
      References

Introduction

This is the second of two articles examining the latest mechanisms for securing DNS. In the first article I looked at securing dynamic updates and zone transfers with TSIG keys, in this article I will be looking at the DNSSEC protocol for securing the zone data itself.

In conventional DNS usage there is no guarantee that the data received by a name server or client is authoritative, or that a name server is not maliciously providing false information. The DNSSEC system prevents clients from trusting information that is false. Under DNSSEC, all data must be authenticated and verified before it can be trusted. To prove that the data is authoritative and has not been tampered with an authoritative source must create and digitally sign the data.

In the examples below, I'm using ISC BIND version 9.3.0rc2 from www.isc.org - you will need to use version 9.3.0 of ISC BIND in order to usefully explore DNSSEC as previous versions used deprecated DNSSEC record types. If you are compiling this from the source, you will need to use to use the "--with-openssl" option to the ./configure command to enable the cryptographic functions, and you will also probably want to enable signature chasing support for the 'dig' command. The commands to build BIND with these options are:

     STD_CDEFINES="-DDIG_SIGCHASE=1"
     export STD_CDEFINES
     ./configure --with-openssl
     make
     make install
As with the previous article, my test systems have been setup to serve a test domain "domain.tld", and a reverse domain "1.168.192.in-addr.arpa".

Secure DNS Zones

Its fine making secure updates, but how do we ensure that the results from our DNS queries actually came from an authoritative server and haven't been modified in transit? The aim if the DNSSEC protocol extensions is to make sure DNS data comes from the correct server and cannot be changed.

To enable DNSSEC for a zone, we first generate 2 keys for the zone. These will become the key signing key ( KSK ) and the zone signing key ( ZSK ). For our test domain, use the following commands to generate the keys:

  cd /var/named
  dnssec-keygen -r /dev/urandom -a RSASHA1 -b 1024 -n ZONE domain.tld
  dnssec-keygen -r /dev/urandom -a RSASHA1 -b 2048 -n ZONE domain.tld
  dnssec-keygen -r /dev/urandom -a RSASHA1 -b 1024 -n ZONE 1.168.192.in-addr.arpa
  dnssec-keygen -r /dev/urandom -a RSASHA1 -b 2048 -n ZONE 1.168.192.in-addr.arpa
dnssec-keygen will generate the keys and put them into newly created key files with cryptic names such as Kdomain.tld.+005+14957.key. Here, we create a 1024-bit key which will be used as the ZSK, and a 2048-bit key for the KSK. The numbers in the key file names designate the algorithm used to create the key ( 005 for RSASHA1 ), and a random 5-digit number to represent a key ID.

Now we insert these keys into the zone files, and generate new signed zone files. Edit the domain.tld and 1.168.192.in-addr.arpa zone files and in each add the key file with $include statements. In the domain.tld file, add the following lines just after the SOA record :

  # 1024-bit ZSK:
  $include Kdomain.tld.+005+14957.key
  # 2048-bit KSK:
  $include Kdomain.tld.+005+61205.key
... and in the 1.168.192.in-addr.arpa file :
  # 1024-bit ZSK:
  $include K1.168.192.in-addr.arpa.+005+38921.key
  # 2048-bit KSK:
  $include K1.168.192.in-addr.arpa.+005+07571.key
Now, run the dnssec-signzone utility to sign the zone with the keys. This will take the zone file domain.tld and create a new, signed zone, in domain.tld.signed:
  dnssec-signzone -r /dev/urandom -t -k Kdomain.tld.+005+61205.key domain.tld \
    Kdomain.tld.+005+14957.key
  dnssec-signzone -r /dev/urandom -t -k K1.168.192.in-addr.arpa.+005+07571.key \
    1.168.192.in-addr.arpa K1.168.192.in-addr.arpa.+005+38921
We use the -k option to specify the 2048-bit KSK to dnssec-signzone. Note that the names of the zone files are the same as the name of the DNS zones. If they're different you need to specify extra options to dnssec-signzone.

If you take a look at the newly generated .signed files you'll see that they have been filled with lots of extra records, with types such as NSEC, RRSIG, and DNSKEY. The DNSKEY record contains a copy of the public key for the zone, RRSIG contains a digital signature for a resource record ( an RR ), and NSEC records are used to provide an authenticated denial of existence for queries to unknown records.

Now edit /etc/named.conf and change the name of the data file for the zones to refer to the signed zone file. In my example for domain.tld and 1.168.192.in-addr.arpa the named.conf entries become:

  zone "domain.tld" IN {
        type master;
        file "domain.tld.signed";
        allow-update { key update_key; };
        allow-transfer { key slave_xfers_key; };
  };

  zone "1.168.192.in-addr.arpa" IN {
        type master;
        file "1.168.192.in-addr.arpa.signed";
        allow-update { key update_key; };
        allow-transfer { key slave_xfers_key; };
  };
also add the option "dnssec-enable" into the options statement at the top of the named.conf file to enable the DNSSEC extensions:
  options {
        directory "/var/named";
        dnssec-enable yes;
  };
restart named and check syslog for any errors. You should see messages stating that the signed zone has been loaded, similar to these:
  named[910]: zone domain.tld/IN: loaded serial 4 (signed)
At this point you can also send dynamic updates to add & delete records in the signed zones. This method is much easier that editing the original zone file and re-signing the records.

Testing DNSSEC secure zones

You can use the "dig" utility which comes with BIND to check that your DNSSEC domain is functioning properly. By including the +dnssec option you should receive the additional RRSIG and DNSKEY records for your query:
  dig +dnssec @192.168.1.2 www.domain.tld
The client cannot verify the validity of the returned records unless it has a copy of the domain key. You can use the "+sigchase" dig option to perform this verification ( refer to the dig man page for details ).

Making use of Secure zones for non-DNSSEC clients

There is currently no client-side resolver libraries which perform verification of DNSSEC records. So then, how do client systems make use of the secure zones? The way to do it is to configure a forwarding DNS server which the client will use for lookups and which will perform the verification of signed records. Such a server should be "close" to the client, preferably on the same subnet.

To configure a forwarding server to utilise DNSSEC, simply add the public keys of the top-level zone of your DNSSEC tree into a "trusted-keys" section of named.conf and enable DNSSEC extensions in the options statement. For our test server, the entire named.conf for a verifying forwarder configuration is :

  options {
    directory "/var/named";
    pid-file "/var/named/named.pid";
    forward only;
    forwarders {
      192.168.1.3;
    };

    dnssec-enable yes;
    dnssec-must-be-secure "domain.tld" yes;
    dnssec-must-be-secure "1.168.192.in-addr.arpa" yes;
  };

  zone  "." {
    type hint;
    file  "named.ca";
  };

  trusted-keys {
    # public KSK:
    "domain.tld." 256 3 5 "AQPhlHNZPFlrY/evopm....";
    "1.168.192.in-addr.arpa." 256 3 5 AQOsRH9Bt9dbA....";
  };
I've truncated the data of the key data lines in this case. These can be quite long in practice. The syntax for the trusted-keys statement is:
trusted-keys {
  [domain] [flags] [protocol] [algorithm] [key-string];
};
where the key fields can be extracted from the public key file generated for the respective zone.

The dnssec-enable option is necessary to enable the DNSSEC functionality in the server. The dnssec-must-be-secure option says that the records for the "domain.tld" zone MUST be verified to be secure by the forwarding server. If the verification fails, the client will get a SERVFAIL error and no record data. If dnssec-must-be-secure is set to "no" then the client will get the query results even if the verification fails.

Restart your forwarding server after changing /etc/named.conf and check syslog for any error messages.

You should now be able to perform lookups against your forwarding server and get the server to verify the signatures that it receives from the authoritative master server. If the forwarder fails to validate responses from a zone which has trusted keys configured for it, the client should receive a "SERVFAIL" error and not be given invalid data which fails verification. You can test this by shutting down your master server, editing the ".signed" zone file and changing a record manually such as the IP address of an A record. After starting the master server again ( and restarting the forwarder to clear its cache ) queries for the modified record should receive an error response rather than valid record data.

Note that debugging DNSSEC operations can be difficult due to the cryptic logging messages. The papers on the Resources section below should provide help.

Conclusion

In this article I've shown briefly how to configure DNSSEC signed zones to ensure the security of DNS zone data. The full implementation of DNSSEC is really much more involved. To properly secure a zone, the parent zone should have copies of the child zone's public key which is then signed by the parent's key - and so on, up to the root zones which should have well-known public keys. This chain of trust is quite similar in structure to the chain of certificates used to secure web servers using the https protocol.

DNSSEC is still quite experimental and changes are still being finialised by the IETF. The BIND beta code is a little buggy, but from this you should be able to see how it can be utilised. Some users have commented that there may be risks in deploying DNSSEC in production systems as it is not as fault-tolerant as classical DNS. For example, if the zone keys expire then the entire zone may become inaccessible.

There have even been proposals for using DNSSEC protocols as a method of securely distributing keys to form a Public Key Infrastructure ( PKI ) system. Using DNSSEC to securely distribute public keys, such as PGP or ssh keys, is left as an exercise for the reader.

Some further things to note of when using DNSSEC is that the network packets are significantly larger than normal plain DNS, and that if the 512-byte packet size is exceeded systems will start using the TCP transport rather than UDP. Also, be careful of key expiry and be prepared to rollover keys, the papers in the References section below explain how to do this.

References

DNSSEC project web site - many useful resources
http://www.dnssec.net

BIND v9 ARM ( Administrators Reference Manual )
http://www.nominum.com/content/documents/bind9arm.pdf

DNSSEC Operations HOWTO
http://www.ripe.net/disi/Course/TechCourse.pdf

Nominum DNSSEC FAQ
http://www.nominum.com/getOpenSourceResource.php?id=8