[dns-operations] calculating DNSSEC keytags in awk
Joe Abley
jabley at hopcount.ca
Fri Dec 16 21:21:37 UTC 2011
Hi all,
I realise I'm probably the only person in the world who would ever want to do such a thing, but in case I'm wrong about that here's a function in standard awk (no GNUisms) to calculate a keytag from DNSKEY RDATA passed in canonical form, i.e. with the public key modulus base64-encoded, as you might see as output from dig.
It seems to generate the right keytags for the zones I have been playing with. Note that the function walks unashamedly over the arrays word[] and rdata[] and doesn't bother with local-scoping any other variables, because what fun would that be?
Joe
#!/usr/bin/awk -f
# Derive keytag from DNSKEY canonical presentation format data.
#
# e.g.
#
# tag = keytag(256, 3, 8, \
# "AwEAAdNW7YIhcTdqXrzgZjJJ35VjAFT1ArvnhAzXDm7AuGxSQqmGBRmj" \
# "JvBv0xS4gahB9mj6ekF0dVKoeZgLmNAjo8hj2JI7K281YTo2R5k3mKSc" \
# "4hOCP55hR22r5hIsPJoT19pv/VdZQfyTzZ96frQ16qRa9+/GSjzjtFfQ" \
# "v16FwE7R");
#
# Comments, complaints and howls of derisive laughter to jabley at hopcount.ca.
function keytag(flags, proto, alg, pubkey) {
BASE64 = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
# length of RDATA in octets, count as we go
rdlength = 0;
# DNSKEY fixed-field RDATA, RFC4034 section 2
rdata[rdlength++] = int(flags / 256);
rdata[rdlength++] = flags % 256;
rdata[rdlength++] = proto;
rdata[rdlength++] = alg;
# DNSKEY public key modulus, decode base64 and store
while (pubkey) {
# extract the next four base64 6-bit words into word[]
# padding characters will be stored as zeros
for (i = 1; i < 5; i++) {
w = index(BASE64, substr(pubkey, i, 1));
word[i] = (w ? w - 1 : 0);
}
# derive three octets from those four base64 6-bit words
rdata[rdlength++] = (word[1] * 4 + int(word[2] / 16));
rdata[rdlength++] = (word[2] * 16 + int(word[3] / 4)) % 256;
rdata[rdlength++] = (word[3] * 64 + word[4]) % 256;
# decrease incoming string by 4
pubkey = substr(pubkey, 5);
}
# calculate the keytag and return it
if (alg == 1) {
# algorithm 1 is special, see RFC 4034 appendix B.1
return 256*rdata[rdlength - 3] + rdata[rdlength - 2];
} else {
# for all other algorithms, follow RFC 4034 appendix B
ac = 0;
for (i = 0; i < rdlength; i++)
ac += (i % 2 ? rdata[i] : 256 * rdata[i]);
ac += int(ac / 65536) % 65536;
return ac % 65536;
}
}
More information about the dns-operations
mailing list