In the section called “Easy Start Guide for Recursive Servers”, we used one line of configuration to turn on DNSSEC validation, the act of chasing down signatures and keys, making sure they are authentic. Now we are going to take a closer look at what it actually does, and some other options.
options { dnssec-validation auto; };
This “auto” line enables automatic DNSSEC trust anchor configuration using the managed-keys
feature. In this case, no manual key configuration is needed. There are three possible choices for the dnssec-validation
option:
Let's discuss the difference between yes
and auto
. If you set it to yes
(the default), the trust anchor will need to be manually defined and maintained using the trusted-keys
statement in the configuration file; if you set it to auto
(as shown in the example), then no further action should be required as BIND includes a copy[2] of the root key. When set to auto
, BIND will automatically keep the keys (also known as trust anchors, which we will look at in the section called “Trust Anchors”) up-to-date without intervention from the DNS administrator.
We recommend auto
unless you have a good reason for requiring a manual trust anchor. To learn more about trust anchors, please refer to the section called “Trusted Keys and Managed Keys”.
dnssec-enable
needs to be set to yes (default value is yes) in order for dnssec-validation
to be effective. So by now you've enabled validation on your recursive name server, and verified that it works. What exactly changed? In the section called “How Does DNSSEC Change DNS Lookup?” we looked at the very high level, simplified 12-steps of DNSSEC validation process. Let's revisit that process now and see what your validating resolver is doing in more detail. Again, we are using the example to lookup the A record for the domain name www.isc.org
(Figure 1.1, “DNSSEC Validation 12 Steps”):
isc.org
name servers for the A record of www.isc.org
. This query has the DNSSEC OK
(do
) bit set to 1, notifying the remote authoritative server that DNSSEC answers are desired.isc.org
is signed, and its name servers are DNSSEC-aware, thus it responds with the answer to the A record query plus the RRSIG for the A record.isc.org
.isc.org
name server responds with the DNSKEY and RRSIG records. The DNSKEY is used to verify the answers received in #2..org
) for the DS record for isc.org
..org
name server responds with the DS and RRSIG records. The DS record is used to verify the answers received in #4..org
..org
name server responds with DNSKEY and RRSIG. The DNSKEY is used to verify the answers received in #6..org
.After step #12, the validating resolver takes the DNSKEY received and compares to the key or keys it has configured, to decide whether or not the received key can be trusted. We will talk about these locally configured keys, or trust anchors, in the section called “Trust Anchors”.
As you can see here, with DNSSEC, every response includes not just the answer, but a digital signature (RRSIG) as well. This is so the validating resolver can verify the answer received, and that's what we will look at in the next section, the section called “How are Answers Verified?”.
So how exactly are DNSSEC answers verified? Before we can talk about how they are verified, let's first see how verifiable information is generated. On the authoritative server, each DNS record (or message) is run through a hash function, then this hashed value is encrypted by a private key. This encrypted hash value is the digital signature.
When the validating resolver queries for the resource record, it receives both the plain-text message and the digital signature(s). The validating resolver knows the hash function used (listed in the digital signature record itself), so it can take the plain-text message and run it through the same hash function to produce a hashed value, let's call it hash value X. The validating resolver can also obtain the public key (published as DNSKEY records), decrypt the digital signature, and get back the original hashed value produced by the authoritative server, let's call it hash value Y. If hash values X and Y are identical, and the time is correct (more on what this means below), the answer is verified, meaning we know this answer came from the authoritative server (authenticity), and the content remained intact during transit (integrity).
Take the A record www.isc.org
for example, the plain text is:
www.isc.org. 4 IN A 149.20.64.69
The digital signature portion is:
www.isc.org. 4 IN RRSIG A 5 3 60 ( 20141029233238 20140929233238
4521 isc.org. DX5BaGVd4KzU2AIH911Kar/UmdmkARyPhJVLr0oyPZaq 5zoobGqFI4efvzL0mcpncuUg3BSU5Q48WdBu92xinMdb E75zl+adgEBOsFgFQR/zqM3myt/8SngWm4+TQ3XFh9eN jqExHZZuZ268Ntlxqgf9OmKRRv8X8YigaPShuyU= )
When a validating resolver queries for the A record www.isc.org
, it receives both the A record and the RRSIG record. It runs the A record through a hash function (in this example, it would be SHA1 as indicated by the number 5, signifying RSA-SHA1) and produces hash value X. The resolver also fetches the appropriate DNSKEY record to decrypt the signature, and the result of the decryption is hash value Y.
But wait! There's more! Just because X equals Y doesn't mean everything is good. We still have to look at the time. Remember we mentioned a little earlier that we need to check if the time is correct? Well, look at the two highlighted timestamps in our example above, the two timestamps are:
This tells us that this signature was generated UTC September 29th, 2014, at 11:32:38PM (20140929233238), and it is good until UTC October 29th, 2014, 11:32:38PM (20141029233238). And the validating resolver's current system time needs to fall between these two timestamps. Otherwise the validation fails, because it could be an attacker replaying an old captured answer set from the past, or feeding us a crafted one with incorrect future timestamps.
If the answer passes both hash value check and timestamp check, it is validated, and the authenticated data (ad
) bit is set, and response is sent to the client; if it does not verify, a SERVFAIL is returned to the client.
[2] BIND technically includes two copies of the root key, one is in bind.keys.h
and is built into the executable, and one is in bind.keys
as a managed-keys
statement. The two copies of the key are identical.