DNSSEC: Get it Right the First Time

Signing my first zone was quite difficult and needlessly so.

This post will give those familiar with operating a DNS server an intuition about DNSSEC by helping you sign your first zone correctly.

What's DNSSEC about, anyway?

DNSSEC is based on public key cryptography. You will be signing your zones with a private key and clients will verify the signatures against your public key.

When you “sign a zone” you are really signing every record in the zone and adding those signatures as new records in the zone. The standard specifies that the nameserver will include the signatures with the records in the response.

DNSSEC adds new record types, in addition to the common A, PTR, MX, CNAME, SOA, TXT, and SRV records we get:

Let's Sign a Zone

You have a zonefile, it should be named after your zone. It's not called nocko.se, but imagine it were or better yet just replace nocko.se with your zone name everywhere it occurs in this document. Here's how you sign your zone:

dnssec-keygen -3 -n ZONE nocko.se dnssec-keygen -3 -n ZONE -f KSK nocko.se dnssec-signzone -S -3 – nocko.se

That's it you're done. There are some new files in the directory with your zonefile. One of them is nocko.se.signed, just point bind or nsd at this file instead of the unsigned one and reload the config. That's it, You're hosting a DNSSEC signed zone!

Break it down

dnssec-keygen -3 -n ZONE nocko.se

Here you generated what's called the Zone Signing Key (ZSK). This is the key pair used to sign each record in the zone. The -3 flag tells the program to use an algorithm compatible with NSEC3 (see NSEC vs. NSEC3). -n ZONE alerts the program to generate a key suitable to for use with a zone (the keygen can generate other types of keys). Tack the zone name on the end so it knows what to call the keys. You'll two new files in the directory with odd names:

  1. Knocko.se.+007+XXXXX.key
  2. Knocko.se.+007+XXXXX.private

What does it all mean? The filename with a K, because that's how dnssec-keygen rolls. Then concatenate the zone name. This is followed by a numeric code that specifies what type of key you created (details). A five serial number used to identify this key in the zone. Finally the suffix .private is used to identify if this is the private key and .key for the public key.

dnssec-keygen -3 -n ZONE -f KSK nocko.se

This generates a Key Signing Key (KSK). The KSK is a new keypair similar in type, but independant of the ZSK. The KSK is only used to sign the ZSK. We simply added -f KSK to the previous command. You'll see that two new key files show up with similar filenames but different serial numbers. The KSK is also called the Secure Entry Point and Trust Anchor in the literature (see Why two keys? for details). It anchors the trust in the ZSK which signs everything else.

dnssec-signzone -S -3 – nocko.se

This is the moneymaker, it does all this:

  1. Takes the public keys from the Knocko.se.+007*key) and appends them as DNSKEY records to the zone. (This is what the -S flag does)
  2. Signs the DNSKEY record of the ZSK with the KSK
  3. Puts all the records in the zone in canonical (alphabetical) order
  4. Generates a NSEC3 records for each record and interleaves them into the ordered zonefile
  5. Creates RRSIG records (signatures) for all the records in the zone by signing them with the ZSK.

Easy, peasy. What's the -3 - about? The NSEC3 standard allows for the use of a salt when hashing these records to make pre-calculated dictionary attacks more difficult. The -3 flag is required to generate the newer NSEC3 tags and if you don't care to provide a salt, you can skip the salt by adding the hyphen.

Chain of Trust

So now you're signing your zone... you're still not doing a good job authenticating your zone! What if a rogue server serves up an evil copy of your zone with a set of valid signatures based on keys they generated? How can the client know your public key is the public key?

What you need to do is store your public key in the parent zone. Public keys are large, however, so a better idea is to hash the public key and store the hash in the parent zone... it's way smaller and still unique to the key.

Clients can verify the DNSKEY of a zone by checking for a DS key (containing a hash of the DNSKEY) at the parent that matches the DNSKEY in the zone. The parent zone completes a similar process, submitting it's public key hashs to it's parent and so forth all the way back to the DNS root. From your zone to the top of the chain, lots of crypto love.

Getting your DS record into your parent zone

If you are deep in a zone hierarchy you can start by emailing the contact email address in the SOA record of your parent zone. For example, if your zone is cs.engr.podunkstate.edu, try dig +short engr.podunkstate.edu SOA. The second field in the response is an email address (switch the first . to an @). Email this person and attach the dsset-nocko.se. file (it was automatically generated by dnssec-keygen when you made the KSK). It contains the exact records the parent needs to put in their zonefile.

If you have a zone on a TLD registered with a large registrar, they will have a form to fill out in their web management interface. Look for the only thing that says DNSSEC.

My current registrar is gandi.net. Their automated system wants you provide three pieces of information:

  1. The entire public key

    The public key is in the files ending in .key You'll have two of those, but you are only interested in the KSK. If you open the files you'll see that one is identified as a KSK in the comment section. You should also note that the number 257 should appear directly following DNSKEY in the file. You will only want to paste the garbled looking part after the 7 and including the final = into the first text box.

  2. Select the algorithm from the drop down box. You'll want 7, it's in the filename and in the file

  3. Specify the key type from the dropdown. The two options are ZSK (256) or KSK (257). The DS record is for your KSK so choose

    1. You could publish DS records for ZSKs.... it's not clear to me why this would be useful.

I've hosted domains with a GoDaddy reseller in the past. Their automated web form wants you to submit the DS records in chunks. Take a look at the dsset-nocko.se. file. The body of the records (part after DS) has four parts: 1. Key serial number 1. Algorithm type (7 if you've been following along) 1. Hash type (what type of hash, e.g. SHA-1, SHA-256, et. al) 1. The hash

GoDaddy's form has an input field for each of the above. The file has two hashes (two records) by default... they are both of the KSK, one is simply a SHA-1 hash and the other is SHA-256. Feel free to submit the form twice with both sets of info, but only one is required to authenticate your KSK.

Now you wait.

You can check to see if your DS records are live at your parent zone by running dig nocko.se ds. If you see a response that looks like your dsset file you're done. Check out the tests at DNSViz and DNS Check if you want confirmation that your zone is full of valid DNSSEC goodness.

You have to resign your zone

The signatures on your zonefile are good for 30days. Every (30 days - TTL of the zone) you need to sign the zone again. That's this command (from above):

dnssec-signzone -S -3 – nocko.se

Make a cron job to run this command periodically. Do it now... you won't remember later.

If you've come this far you have working DNSSEC on your zone.


Why two keys (ZSK & KSK), wouldn't one be simpler?

Yes. One would be simpler and largely accomplish the same goals.

However, there are known problems with using a key to sign lots of messages that are much shorter than the key. DNS records are very short messages. The ZSK signs every record in the zone, plus every NSEC record. The formula for signature count is akin to: (2 * numrecords * numzoneupdates) where numzone_updates is at least one per month. So the ZSK has a (potentially) large footprint for cryptoanalysis.

The KSK only signs the ZSK and so only reveals a small fraction of the number signatures as the ZSK. That limits its exposure, in turn making the KSK viable for a longer period of time than the ZSK.

Wait... My keys expire?

Keys don't expire, but they do have a shelf life. It's in your best interest to generate new keys on a regular schedule, especially ZSKs.

Current best practices recommend replacing the ZSK every one to three months (depending on how many records are in the zone). The KSK should be replaced every one to two years. The reason for the two key system is that it's much easier to update records in your zone than those in the parent. Using two keys allows those upstream changes to be safely postponed for a more realistic 1-2 years. Could you imagine having to coordinate with your parent zone every month?

So I don't have to change my keys?

No, but you should. There are software packages to automate rotation of DNSSEC keys and a really nice NIST DNSSEC deployment guide to help you rotate keys (see section 11.2).

Whats with the NSEC / NSEC3 thing?

With NSEC, when a name in the zone doesn't exist a NSEC record is returned that contains the next secure record name in it. This NSEC record is signed (which is great), but leaks other DNS record names (which is not ideal). An attacker could systematically walk the zone and enumerate all the hosts.

With NSEC3 the names returned in the NSEC records are hashed in such a way that proves there is no matching record without revealing the name of the surrounding records. It's been around since 2008, it's best practice for new deployments. If you've followed along with the commands above, you've already implemented it.

NSEC3 does take longer to sign a zone (all that extra hashing). With extremely large zones there may be an advantage to using NSEC.