Manually checking DNSSEC signatures

Written by Rick van Rein in category: Crypto, Procedures, Security, Technical

WikiMedia CommonsAt some point while running DNSSEC, you will wonder if the base64 blobs in RRSIG and DNSKEY records are actually correct. We specify a few procedures that we follow to have Python calculate signatures if that happens to us.

In what follows below, we are assuming that all your RSA public keys are in DNS; or otherwise, that you will be able to dig it up from your HSM. In fact, it is not so much the public key exponent as the modulus that matters — as the public key exponent is usually 65537 or hexadecimal 0x00010001.

Setting up Python

To get Python ready for action, start it up and give the following commands:

import base64

def str2int (s):
   r = 0
   for c in s:
      r = r * 256 + ord (c)
   return r

def int2str (i):
   s = ''
   while i > 0:
      s = chr (i % 256) + s
      i = i >> 8
   return s

You are now set to do some basic manipulations.

Determining the key tag of a DNSKEY record

Sometimes we need a key tag but only have the fullblown DNSKEY record. This is quickly solved if it is stored in a file, like /tmp/k1 with a simple commandline tool that comes with the LDNS library:

ldns-key2ds -n -f -2 /tmp/k1

The output will be printed on stdout and include the key tag. Note the use of -f to force it on ZSKs and not just request the information on KSKs.

Fetch RSA public keys from DNSKEY records

Using your favourite commandline tools, dig up the DNSKEY record that you need to work on. For instance:

ip4afrika.nl.		1229	IN	DNSKEY	256 3 8 AwEAAafyW...WVZCTZ3x

This is a ZSK (as shown by the 256 flag) using the RSA/SHA256 algorithm (the 8 identifier). The long rest of the line is the base64 makeup of the key itself. There will usually be more than one key, and DNS will round-robin the records. Usually, this means that it is possible to start counting after the last 257-flagged KSK (when checking a ZSK that signed an RRSIG).

k1 = base64.decodestring ('AwEAAafyW...WVZCTZ3x')
k1 [:4] == '\x03\x01\x00\x01'
(len (k1)-4) * 8
k1i = str2int (k1 [4:])

The first line assigns the binary content of the base64-encoded key to k1. The second line should print True if the public key exponent in use is indeed 65537, as is common for RSA. The third line should print the modulus length in bits, and the fourth line strips off the public key and returns the modulus as an integer in k1i.

We now have a key in k1i. It is usually practical to do the same for the other keys being checked. So you should repeat the procedure for k2, k3 and so on.

Fetch signature values from RRSIG records

Using your favourite commandline tool, dig up the RRSIG record that you are mistrusting. It may look like

ip4afrika.nl.   3600    IN      RRSIG   SOA 8 2 3600 (
                                20130915210712 20130901221420
                                30444 ip4afrika.nl.
                                toRxVPv...5q+rgaSs= )

We see a key tag 30444 suggesting what key should be used for checking, but the real meat is in the signature. We extract it in a procedure that resembles the key extraction:

s1 = base64.decodestring ('toRxVPv...5q+rgaSs=')
len (s1) * 8
s1i = str2int (s1)

The first line extracts the binary value from the base64 string. The second line should print the modulus length as the signature length (although it could be smaller if the signature happens to start with zeroes). The third line stores the signature in the s1i variable.

It is always good to also have an s2 with a known-good signature. Even if your signing process is failing, chances are that something older still exists, and could be used as a positive confirmation of the calculation procedures below.

Checking an RSA signature

Usually, problems in systems like these are related to public key handling. So what we are doing is to apply the RSA algorithm to a signature, to see if the outcome looks like it was properly padded. If not, then something about the key or signature is wrong, and trying other keys may be advisable. Also look for correct signatures, just to check your own procedures of getting here.

"%x" % pow (s1i, 65537, k1i)

This should print something that obviously starts with padding, and whose lower bytes constitute the hash, for instance:

'1fffffff...fffffff003031300...0512'

Making several of these calculations is easy, and it can be helpful to see if signature s1 was made with key k1 or another key.

Have fun!

2 Comments to “Manually checking DNSSEC signatures”

  1. Kim Minh Kaplan says:

    “The second line should print True if the public key in use is indeed 65537” should read “The second line should print True if the public key exponent in use is indeed 65537”

  2. Rick van Rein says:

    Thanks Kim, I changed it.

Respond

*