At 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
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:
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.