An introduction to DNSSEC

DNSSEC

DNS (Domain Name System) is the “phone book” of the internet – meaning that it translates a human-readable domain name (like ovhcloud.com) into a computer-readable IP (54.39.46.56).

DNS request

The DNS was designed when the internet first started. At that time, the Internet was not as big, or critical as it is today.
DNS, therefore, was designed on a principle of trust. As a result, DNS is not really secure and has vulnerabilities; such as DNS cache poisoning.

This kind of attack allows the attacker to enter invalid information into a DNS resolver cache, so that following DNS queries
return invalid data. This enables the attacker to redirect you to a fake website.

To secure the DNS zone, the DNSSEC (Domain Name System Security Extensions) has been designed – based on public key encryption – to verify and validate the integrity and the origin of DNS data.

How DNSSEC works

The goal of DNSSEC is to allow resolvers to check the origin and integrity of a DNS answer. DNSSEC has been
designed with the following constraints:

  • It has to be an extension of DNS so a non-DNSSEC client can work with a DNSSEC server and vice-versa.
  • The data is protected, but the communication channels are not.
  • It must be based on public key encryption

Since DNSSEC, by design, should not change the DNS protocol, new types of DNS records, Resource Records, have been added to handle cryptography.

RRSIG

RRSIG contains the cryptographic signature of a record set. With DNSSEC, each record set is followed by a RRSIG containing,
among others, the signature in base64 of the record set.


For example:

$ dig A +dnssec dnstests.ovh
dnstests.ovh.        3600    IN  A   213.186.33.5
dnstests.ovh.        3600    IN  RRSIG   A 8 2 3600 20200925080215 20200826080215 50238 dnstests.ovh. AUz7u4Sq0EkSUq5kR0beowmMuscbzGdb3NI/OhCG8Ow0Z3CqgG0/94eR     6pbG7YJwvCFBU1bQDklLYEfc4mg41VeAVY4xPSv0O76/hEZsVKcBOGlT nKy3wV4ft8ykV1Jl+5q2eJAaZRoBSvHuRItbM2HCyghhDW0gKBy5rqOq BlM=

The RRSIG record contains common DNS fields (domain name, ttl, etc.), but also other fields

  • A: Type covered
  • 8: Algorithm used to sign
  • 2: Number of labels of the RRSET (here 2: 1 for dnstests and 1 for OVH)
  • 3600: Original TTL
  • 20200925080215: Signature expiration date
  • 20200826080215: Signature inception date
  • 50238: KeyTag (non uniq indentifier)
  • dnstests.ovh.: Signer’s name
  • AUz7u4Sq0EkSUq5k…: => The Signature

RRSIG signature

The signature is calculated according to the following formula:

signature = sign( RRSIG_RDATA | RR(1) | RR(2)... )

where

|  is used for concatenation
RRSIG_RDATA is the RRSIG in wire format
RR(*) = owner | type | class | TTL | RDATA length | RDATA

DNSKEY

In order to validate, a RRSIG resolver needs to know the public key used to sign the record set.

This is stored in a record named DNSKEY

$ dig DNSKEY +multi dnstests.ovh
dnstests.ovh.        3458 IN DNSKEY 256 3 8 (
                    AwEAAc9juwZVMUrdjPIxMPuOk+ZnVhv+i16B3TTxj1Ft
                    5ABDEbiXyfljJopTCQgmJ4EcNDubhZKezTqGsbpaErw8
                    8yqFwzviv2/U9Mw+Vq1zbS29Hl6XzyWPlnYryXcyVDEw
                    OZlsK0hw6d7A6Xcjjf2srnxpQHpO9pG+etFZxSSEV49j
                    ) ; ZSK; alg = RSASHA256 ; key id = 50238
dnstests.ovh.        3458 IN DNSKEY 257 3 8 (
                    AwEAAZ5F0TSR8PWTrADtdlTcuGWBZ1ehOHy7RtX/ZyA6
                    WQSU+59I8PFWQ6ddD4FX7LfNcaPSd10vjZKmGT9fB8uf
                    IY9xHHrH2zGc6jEI7TkqDOjutVRsBhhis+AO/HDjL9i0
                    tpyoCX3/wHVZ9U0iOIHaR4+vlVJfja6EvuL4s0zhzaY0
                    amP1R8af0E1Rcvyi9S6fFOtECZOrqKlwI9OPQneQ2gD4
                    uXWg97o1kuBvxSg/Ze5NsAIsJu3oShxBPUNmW6hwP8FM
                    tbmft4MqpJ3xiI03FN2t2PwgO3cvCYlyBJRZqo9nqLAz
                    yYheVdoMuBP024bXF1HFDo2n7jZMuDrW7mMfPK8=
                    ) ; KSK; alg = RSASHA256 ; key id = 44329

DNSKEY record contains common DNS fields (domain name, ttl, etc.), but also other fields.

  • 256 or 257: Flags. A value of 256 indicates that the DNSKEY contains a ZSK and a value of 257 indicates that it contains a KSK.
  • 3: Protocol (Must be equal to 3 otherwise record is not valid)
  • 8: Algorithm
  • AwEAAc9…; Public key

In summary, when a resolver requests a given record type, it receives the set of records and the associated RRSIG. It then had to request the DNSKEY to validate the response.

ZSK

Each zone signed with DNSSEC has a key named ZSK used to sign the whole record set.

If we trust the ZSK, we know that we can trust all records in the zone. But how do we validate the ZSK?

KSK

In the same way that the ZSK is used to sign the record set, the DNSSEC use another key – the KSK (Key Signing Key) – which is used to sign the ZSK DNSKEY.

So let’s imagine we want to retrieve and validate an A record for domain name dnstests.ovh.

First we ask for A:

$ dig A +dnssec dnstests.ovh
dnstests.ovh.        3283    IN  A   213.186.33.5
dnstests.ovh.        3283    IN  RRSIG   A 8 2 3600 20200925080215 20200826080215 50238 dnstests.ovh. AUz7u4Sq0EkSUq5kR0beowmMuscbzGdb3NI/OhCG8Ow0Z3CqgG0/94eR 6pbG7YJwvCFBU1bQDklLYEfc4mg41VeAVY4xPSv0O76/hEZsVKcBOGlT nKy3wV4ft8ykV1Jl+5q2eJAaZRoBSvHuRItbM2HCyghhDW0gKBy5rqOq BlM=

Then we ask for DNSKEY:

$ dig DNSKEY +multi +dnssec dnstests.ovh
dnstests.ovh.        2954 IN DNSKEY 257 3 8 (
                AwEAAZ5F0TSR8PWTrADtdlTcuGWBZ1ehOHy7RtX/ZyA6
                WQSU+59I8PFWQ6ddD4FX7LfNcaPSd10vjZKmGT9fB8uf
                IY9xHHrH2zGc6jEI7TkqDOjutVRsBhhis+AO/HDjL9i0
                tpyoCX3/wHVZ9U0iOIHaR4+vlVJfja6EvuL4s0zhzaY0
                amP1R8af0E1Rcvyi9S6fFOtECZOrqKlwI9OPQneQ2gD4
                uXWg97o1kuBvxSg/Ze5NsAIsJu3oShxBPUNmW6hwP8FM
                tbmft4MqpJ3xiI03FN2t2PwgO3cvCYlyBJRZqo9nqLAz
                yYheVdoMuBP024bXF1HFDo2n7jZMuDrW7mMfPK8=
                ) ; KSK; alg = RSASHA256 ; key id = 44329
dnstests.ovh.        2954 IN DNSKEY 256 3 8 (
                AwEAAc9juwZVMUrdjPIxMPuOk+ZnVhv+i16B3TTxj1Ft
                5ABDEbiXyfljJopTCQgmJ4EcNDubhZKezTqGsbpaErw8
                8yqFwzviv2/U9Mw+Vq1zbS29Hl6XzyWPlnYryXcyVDEw
                OZlsK0hw6d7A6Xcjjf2srnxpQHpO9pG+etFZxSSEV49j
                ) ; ZSK; alg = RSASHA256 ; key id = 50238
dnstests.ovh.        2954 IN RRSIG DNSKEY 8 2 3600 (
                20200925080215 20200826080215 44329 dnstests.ovh.
                k/huKVd5Skc8PE1CgHl1/MCEjZs6hH1DlLYGHZxG97YK
                YBSwvWQoXGG6ObZKJYCWVqDJWvdz81K7XHLvK34g3AwB
                NyI62Aw00GiaJzpFCkKU+jTVPeVvDKpAKGQxPziWCL/4
                Buj230YyDm38V4amxAeBOz5FcvD8eDu6XYMx4ygvJ3XF
                M7zojtsbqwg7IBJPJUURNfpQi8MbJivelXbh2CJACteB
                8zd2dsj0eZRTLulC15qr7R7zBQqJ8CVuPAVHBYfy2Nu/
                VE2QSe2Q4zzns9TUH/6/g9f8RDMNDhT+Z1lbsaJg9EzH
                x4bqLfjEjnqhrzdS/Fc02e7bILe9YGQ5SQ== )
dnstests.ovh.        2954 IN RRSIG DNSKEY 8 2 3600 (
                20200925080215 20200826080215 50238 dnstests.ovh.
                nrA3yOddNl3695pl8JAwDkjV8oL5VdKyJO2fIrOPSFVr
                EbEVHHxwxSXqlvhV8J2NmB80oV4mM+bzzZUToIWbKd0p
                XOUDz38lu7Ye4uYrJi4/tMSqMy2HUP96xGQUze96riMo
                hiGmOJp6jd+J3LRmO4dOLXW7WB+Q9dwEANjH4/M= )

We are able to validate the record set with RRSIG and ZSK DNSKEY, then we are able to validate ZSK DNSKEY with RRSIG and KSK DNSKEY.

We are now able to trust records from our DNS zone, but we need to be able to transfer the trust of our child zone to its parent.

Delegation Signer Records

An essential characteristic of DNS is its hierarchical structure. DNSSEC uses this particularity to transfer trust from parent
zone to child zone. This record, named DS (Delegation Signer) contains the hash: KSK DNSKEY.
If the resolver finds DS records in the parent zone, they know that the child-zone must be DNSSEC signed, and will be able to validate
DNSSKEY on the child zone using the DS record.

$ dig DS dnstests.ovh
dnstests.ovh.        172800  IN  DS  44329 8 2 6BDEC6C046B608077A198E19F2C241EB6B05565DE9B0C63DA718DCA2 8F012979

DS records contains common DNS fields (domain name, ttl, etc) but also other fields.

  • 44329: KeyTag
  • 8: Algorithm
  • 2: Digest Type
  • 6BDEC6…: Digest

DS Digest

digest = digest_algorithm( DNSKEY owner name | DNSKEY RDATA);

where

| is used for concatenation
DNSKEY RDATA = Flags | Protocol | Algorithm | Public Key

The Chain of Trust

We are now able to fully validate a DNS answer, up to the root DNS servers:

DNSSEC - Chain of Trust

Denial of existence

Imagine we want to resolve “doesnotexist.dnstests.ovh.”. The resolver will send us back to: domain doesn’t exist. So, how can we
validate this denial of existence?

DNSSEC solves this problem by adding two new types of record: NSEC and NSEC3.

Let’s imaging our dnstests.ovh. has this content

$TTL 3600
@    IN SOA dns10.ovh.net. tech.ovh.net. (2020082603 86400 3600 3600000 60)
        IN NS     ns10.ovh.net.
        IN NS     dns10.ovh.net.
        IN A      213.186.33.5
subdomain        IN A      213.186.33.5
subdomain        IN TXT      dnssec
www        IN A      213.186.33.5

NSEC

NSEC works by returning the “next secure” record.

$ dig A +dnssec doesnotexist.dnstests.ovh
;; status: NXDOMAIN
dnstests.ovh.        18  IN  NSEC    subdomain.dnstests.ovh. A NS SOA RRSIG NSEC DNSKEY

The NSEC record contains common DNS fields (domain name, ttl, etc), but also other fields:

  • subdomain.dnstests.ovh: next domain name (in alphabetical order)
  • A NS SOA RRSIG NSEC DNSKEY: types associated with the current request. It tells us that a current domain name
    dnstests.ovh. only have A NS SOA RRSIG NSEC DNSKEY records.

The problem with NSEC is that it’s possible to enumerate all entries in a zone. Let’s have a look:

$ dig A +dnssec a.dnstests.ovh
dnstests.ovh.        60  IN  NSEC    subdomain.dnstests.ovh. A NS SOA RRSIG NSEC DNSKEY

It tells us that the next subdomain is subdomain.dnstests.ovh., so we can get the next subdomain by adding a letter to the subdomain.

$ dig A +dnssec subdomaina.dnstests.ovh
subdomain.dnstests.ovh.        60  IN  NSEC    www.dnstests.ovh. A TXT RRSIG NSEC

In this way, we can obtain the complete contents of the zone.

NSEC3

NSEC3 was added to prevent an attacker from walking the zone. It works the same way as the NSEC, but it constructs a chain of hashed and not plain text resource records. In the case of NXDOMAIN, it returns the hash before and after (in alphanumerical order) the hash of a requested domain name.

$ dig A +dnssec doesnotexist.dnstests.ovh.
;; status: NXDOMAIN
dnstests.ovh.        60  IN  SOA dns10.ovh.net. tech.ovh.net. 2020082604 86400 3600 3600000 60
E9NLBQ2G28AO5L4JR8UBJR3QODN9PE63.dnstests.ovh. 60 IN NSEC3 1 0 8 1981905ED56A6CE2 SA9BM55PF37IOPN95F1PCIG733K2SQIJ A TXT RRSIG
SA9BM55PF37IOPN95F1PCIG733K2SQIJ.dnstests.ovh. 60 IN NSEC3 1 0 8 1981905ED56A6CE2 BKF3VT8D74NQJVTR798OI8E6TP8C70F2 A NS SOA RRSIG DNSKEY NSEC3PARAM

NSEC3 record contains common DNS fields (domain name, ttl, etc), but also other fields:

  • 1: Hash algorithm
  • 0: Flags
  • 5: Number of iterations for hash
  • C149E2F3213D3F51: Salt value
  • SA9BM55PF37IOPN95F1PCIG733K2SQIJ: Next hashed domain name
  • A TXT RRSIG: Types associated with current request

When a resolver asks for a domain and received a NXDOMAIN they can compute the hash of the requested domain and compare it (alphanumerically) to the hashes received in NSEC3.

For example, for dnstests.ovh. we have:

hash(dnstests.ovh.) = SA9BM55PF37IOPN95F1PCIG733K2SQIJ
hash(www.dnstests.ovh.) = BKF3VT8D74NQJVTR798OI8E6TP8C70F2
hash(subdomain.dnstests.ovh.) = E9NLBQ2G28AO5L4JR8UBJR3QODN9PE63
hash(doesnotexist.dnstests.ovh.) = KSR3B14N7QTGS3536MR6N1AOA97LORK3

If we look at NSEC3 records we got during dig:

E9NLBQ2G28AO5L4JR8UBJR3QODN9PE63.dnstests.ovh. 60 IN NSEC3 1 0 8 1981905ED56A6CE2 SA9BM55PF37IOPN95F1PCIG733K2SQIJ A TXT RRSIG

Means than subdomain.dnstests.ovh. has A, TXT and RRSIG record types and that next subdomain is dnstests.ovh.

SA9BM55PF37IOPN95F1PCIG733K2SQIJ.dnstests.ovh. 60 IN NSEC3 1 0 8 1981905ED56A6CE2 BKF3VT8D74NQJVTR798OI8E6TP8C70F2 A NS SOA RRSIG DNSKEY NSEC3PARAM

Means than dnstests.ovh. has A, NS, SOA, RRSIG, DNSKEY and NSEC3PARAM record types and that next subdomain is www.dnstests.ovh.

So we have received the information telling us that doesnotexist.dnstests.ovh. does not exist (NXDOMAIN),
the hash just before (in alphanumeric order): E9NLBQ2G28AO5L4JR8UBJR3QODN9PE63, the hash just after SA9BM55PF37IOPN95F1PCIG733K2SQIJ, so we know that NXDOMAIN is valid.

To conclude

DNSSEC is an extension of the DNS used to secure the DNS data, not the communication channel. It means that DNSSEC does not encrypt the zone, but it ensures that the received zone was sent, and has not been modified, by its owner. DNS records are cryptographically signed, so DNSSEC introduces the new DNS record types for cryptography.

One of the biggest advantages of DNSSEC is that it’s compatible with the DNS – but to be secure the whole chain of trust must mean using the DNSSEC from child to root.

Developer @ DNS Squad