Last active
July 29, 2016 21:14
-
-
Save chexum/d113d198405d9bece0ba3c0844e1a2fd to your computer and use it in GitHub Desktop.
Create DNSSEC style key files from RSA keys created by openssl.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/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) | |
####################################################################### | |
# 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