While working on DNSSEC for PCextreme’s Aurora DNS I had to convert a DNSKEY to a DS-record which could be set in the parent zone for proper delegation.
The foundation for Aurora DNS is PowerDNS together with Python 3.
The API for Aurora DNS has to return the DS-records so that a end-user can use these in the parent zone. I had the DNSKEY, but I didn’t have the DS-record so I had to calculate it using Python 3.
I eventually ended up with this Python code which you can find on my Github Gists page.
""" Generate a DNSSEC DS record based on the incoming DNSKEY record The DNSKEY can be found using for example 'dig': $ dig DNSKEY secure.widodh.nl The output can then be parsed with the following code to generate a DS record for in the parent DNS zone Author: Wido den HollanderMany thanks to this blogpost: https://www.v13.gr/blog/?p=239 """ import struct import base64 import hashlib DOMAIN = 'secure.widodh.nl' DNSKEY = '257 3 8 AwEAAckZ+lfb0j6aHBW5AanV5A0V0IfF99vAKFZd6+fJfEChpZtjnItWDnJLPa3/LAFec/tUhLZ4jgmzaoEuX3EQQgI1V4kp9SYf8HMlFPP014eO+AnjkYFGLE2uqHPx/Tu7/pO3EyKwTXi5fMadROKuo/mfat5AEIhGjteGGO93DhnOa6kcqj5RHYJBh5OZ/GoZfbeYHK6Muur1T16hHiI12rYGoqJ6ZW5+njYprG6qwp6TZXxJyE7wF1JdD+Zhbjhf0Md4zMEysP22wBLghBaX6eDIBh/7jU7dw1Ob+I42YWk+X4NSiU3sRYPaq1R13JEK4zVqQtL++UVtgRPEbfj5RQ8=' def _calc_keyid(flags, protocol, algorithm, dnskey): st = struct.pack('!HBB', int(flags), int(protocol), int(algorithm)) st += base64.b64decode(dnskey) cnt = 0 for idx in range(len(st)): s = struct.unpack('B', st[idx:idx+1])[0] if (idx % 2) == 0: cnt += s << 8 else: cnt += s return ((cnt & 0xFFFF) + (cnt >> 16)) & 0xFFFF def _calc_ds(domain, flags, protocol, algorithm, dnskey): if domain.endswith('.') is False: domain += '.' signature = bytes() for i in domain.split('.'): signature += struct.pack('B', len(i)) + i.encode() signature += struct.pack('!HBB', int(flags), int(protocol), int(algorithm)) signature += base64.b64decode(dnskey) return { 'sha1': hashlib.sha1(signature).hexdigest().upper(), 'sha256': hashlib.sha256(signature).hexdigest().upper(), } def dnskey_to_ds(domain, dnskey): dnskeylist = dnskey.split(' ', 3) flags = dnskeylist[0] protocol = dnskeylist[1] algorithm = dnskeylist[2] key = dnskeylist[3].replace(' ', '') keyid = _calc_keyid(flags, protocol, algorithm, key) ds = _calc_ds(domain, flags, protocol, algorithm, key) ret = list() ret.append(str(keyid) + ' ' + str(algorithm) + ' ' + str(1) + ' ' + ds['sha1'].lower()) ret.append(str(keyid) + ' ' + str(algorithm) + ' ' + str(2) + ' ' + ds['sha256'].lower()) return ret print(dnskey_to_ds(DOMAIN, DNSKEY))