Skip to content

Instantly share code, notes, and snippets.

@chexum
Last active July 29, 2016 21:14
Show Gist options
  • Save chexum/d113d198405d9bece0ba3c0844e1a2fd to your computer and use it in GitHub Desktop.
Save chexum/d113d198405d9bece0ba3c0844e1a2fd to your computer and use it in GitHub Desktop.
Create DNSSEC style key files from RSA keys created by openssl.
#!/usr/bin/env python
"""
openssl genrsa -out example.com.rsa 1280
dnssec-keyfromrsa example.com.rsa >Kexample.com.+008+33333.private
"""
from subprocess import Popen,PIPE
import sys,StringIO,re,base64
import struct
import argparse
# only these make sense with RSA keys
algdict={
'1':'RSAMD5',
'5':'RSASHA1',
'8':'RSASHA256',
'10':'RSASHA512',
}
sepdict={
'256':'ZSK',
'257':'KSK',
}
#######################################################################
dnssecproto = 3
dnssecflags = None
dnskeytag = None
parser = argparse.ArgumentParser(
description='Create DNSSEC style key files from RSA keys created by openssl.')
parser.add_argument('-t',action='store',type=int,metavar='N', dest='ttl',
help='DNSKEY ttl',default=86400)
flags = parser.add_mutually_exclusive_group()
flags.add_argument('-z',action='store_const', dest='flags', const='256',
help='set flags as ZSK')
flags.add_argument('-k',action='store_const', dest='flags', const='257',
help='set flags as KSK')
parser.add_argument('-a',action='store', dest='algo', default=8,
help='DNSSEC algorithm number')
parser.add_argument('-o',action='store', dest='origin', default='example.com',
help='location of key, owner/apex')
parser.add_argument('rsafile', type=argparse.FileType('r'),
help='RSA file')
args = parser.parse_args()
print args
#######################################################################
rsaparser=Popen(["openssl","rsa","-text","-noout"],stdin=args.rsafile,stdout=PIPE)
(output,outerr)=rsaparser.communicate()
#######################################################################
# parse openssl RSA output into dict
rsadict={}
rsaitem=None
for l in StringIO.StringIO(output):
l = l.strip('\n\r')
if l[0:5] == '-----':
break
m = re.match('^([A-Za-z0-9-]+):\s*(.*?)\s*$',l)
if m:
rsaitem=m.group(1).lower()
rsaline=m.group(2)
q = re.search(' \(0x([0-9a-fA-F]+)\)',rsaline)
if q:
rsaline = q.group(1)
# publicExponent: 65537 (0x10001)
if len(rsaline)%2 == 1:
rsaline = '0'+rsaline
rsadict[rsaitem]=rsaline
continue
l = l.strip(' ')
if rsaitem:
rsadict[rsaitem] = rsadict[rsaitem] + l.translate(None,':')
#######################################################################
for k in ['publicexponent','modulus']:
vhex = rsadict[k]
while vhex[0:2] == '00':
vhex = vhex[2:]
rsadict[k] = vhex
#######################################################################
# quick ugly hack - if bitsize >= 1600, assume ksk
if args.flags is None:
if len(rsadict['modulus']) >= 1600/8*2:
dnssecflags=257
else:
dnssecflags=256
else:
dnssecflags = int(args.flags)
#######################################################################
# DNSKEY RRDATA on-wire format to calculate key tag
#01 00 03 08 03 01 00 01>c2 ff 6d
#^256
# ^3
# ^8
# ^pubexp ^pubkey/modulus
dnskey='{:02x}{}{}'.format(
len(rsadict['publicexponent'])/2,rsadict['publicexponent'],
rsadict['modulus'])
dnswire=struct.pack('!HBB',int(dnssecflags),int(dnssecproto),int(args.algo))+dnskey.decode('hex')
# this is wrong for RSAMD5 (which is not recommended these days)
ac=0;i=0
for c in dnswire:
i=8-i
ac = ((ord(c)&255)<<i)+ac
ac = (ac+(ac>>16)&65535)&65535
dnskeytag = ac
#######################################################################
print "### K{}.+{:03d}+{:05d}.key".format(args.origin,args.algo,dnskeytag)
print "{}. {} DNSKEY {} {} {} {}; tag = {}".format(
args.origin,args.ttl,
dnssecflags,dnssecproto,args.algo,base64.b64encode(dnskey.decode('hex')),dnskeytag)
print
#######################################################################
# show the dict in the desired format
print "### K{}.+{:03d}+{:05d}.private".format(args.origin,args.algo,dnskeytag)
for k in ['Private-key-format','Algorithm','Modulus',
'PublicExponent','PrivateExponent','Prime1','Prime2',
'Exponent1','Exponent2','Coefficient']:
if k == 'Private-key-format':
v = 'v1.2'
elif k == 'Algorithm':
v = '%s (%s)'%(args.algo,algdict[str(args.algo)])
else:
vhex=rsadict[k.lower()]
v = base64.b64encode(vhex.decode('hex'))
print '%s: %s'%(k,v)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment