summaryrefslogtreecommitdiffstats
path: root/contrib/kasp/kasp2policy.py
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/kasp/kasp2policy.py')
-rw-r--r--contrib/kasp/kasp2policy.py209
1 files changed, 209 insertions, 0 deletions
diff --git a/contrib/kasp/kasp2policy.py b/contrib/kasp/kasp2policy.py
new file mode 100644
index 0000000..b78a968
--- /dev/null
+++ b/contrib/kasp/kasp2policy.py
@@ -0,0 +1,209 @@
+#!/usr/bin/python
+############################################################################
+# Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+#
+# Permission to use, copy, modify, and/or distribute this software for any
+# purpose with or without fee is hereby granted, provided that the above
+# copyright notice and this permission notice appear in all copies.
+#
+# THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+# REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+# AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+# INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+# LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+# OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+# PERFORMANCE OF THIS SOFTWARE.
+############################################################################
+# kasp2policy.py
+# This translates the Keys section of a KASP XML file into a dnssec.policy
+# file that can be used by dnssec-keymgr.
+############################################################################
+
+from xml.etree import cElementTree as ET
+from collections import defaultdict
+from isc import dnskey
+import ply.yacc as yacc
+import ply.lex as lex
+import re
+
+############################################################################
+# Translate KASP duration values into seconds
+############################################################################
+class kasptime:
+ class ktlex:
+ tokens = ( 'P', 'T', 'Y', 'M', 'D', 'H', 'S', 'NUM' )
+
+ t_P = r'(?i)P'
+ t_T = r'(?i)T'
+ t_Y = r'(?i)Y'
+ t_M = r'(?i)M'
+ t_D = r'(?i)D'
+ t_H = r'(?i)H'
+ t_S = r'(?i)S'
+
+ def t_NUM(self, t):
+ r'\d+'
+ t.value = int(t.value)
+ return t
+
+ def t_error(self, t):
+ print("Illegal character '%s'" % t.value[0])
+ t.lexer.skip(1)
+
+ def __init__(self):
+ self.lexer = lex.lex(object=self)
+
+ def __init__(self):
+ self.lexer = self.ktlex()
+ self.tokens = self.lexer.tokens
+ self.parser = yacc.yacc(debug=False, write_tables=False, module=self)
+
+ def parse(self, text):
+ self.lexer.lexer.lineno = 0
+ return self.parser.parse(text)
+
+ def p_ktime_4(self, p):
+ "ktime : P periods T times"
+ p[0] = p[2] + p[4]
+
+ def p_ktime_3(self, p):
+ "ktime : P T times"
+ p[0] = p[3]
+
+ def p_ktime_2(self, p):
+ "ktime : P periods"
+ p[0] = p[2]
+
+ def p_periods_1(self, p):
+ "periods : period"
+ p[0] = p[1]
+
+ def p_periods_2(self, p):
+ "periods : periods period"
+ p[0] = p[1] + p[2]
+
+ def p_times_1(self, p):
+ "times : time"
+ p[0] = p[1]
+
+ def p_times_2(self, p):
+ "times : times time"
+ p[0] = p[1] + p[2]
+
+ def p_period(self, p):
+ '''period : NUM Y
+ | NUM M
+ | NUM D'''
+ if p[2].lower() == 'y':
+ p[0] = int(p[1]) * 31536000
+ elif p[2].lower() == 'm':
+ p[0] = int(p[1]) * 2592000
+ elif p[2].lower() == 'd':
+ p[0] += int(p[1]) * 86400
+
+ def p_time(self, p):
+ '''time : NUM H
+ | NUM M
+ | NUM S'''
+ if p[2].lower() == 'h':
+ p[0] = int(p[1]) * 3600
+ elif p[2].lower() == 'm':
+ p[0] = int(p[1]) * 60
+ elif p[2].lower() == 's':
+ p[0] = int(p[1])
+
+ def p_error(self, p):
+ print("Syntax error")
+
+############################################################################
+# Load the contents of a KASP XML file as a python dictionary
+############################################################################
+class kasp():
+ @staticmethod
+ def _todict(t):
+ d = {t.tag: {} if t.attrib else None}
+ children = list(t)
+ if children:
+ dd = defaultdict(list)
+ for dc in map(kasp._todict, children):
+ for k, v in dc.iteritems():
+ dd[k].append(v)
+ d = {t.tag:
+ {k:v[0] if len(v) == 1 else v for k, v in dd.iteritems()}}
+ if t.attrib:
+ d[t.tag].update(('@' + k, v) for k, v in t.attrib.iteritems())
+ if t.text:
+ text = t.text.strip()
+ if children or t.attrib:
+ if text:
+ d[t.tag]['#text'] = text
+ else:
+ d[t.tag] = text
+ return d
+
+ def __init__(self, filename):
+ self._dict = kasp._todict(ET.parse(filename).getroot())
+
+ def __getitem__(self, key):
+ return self._dict[key]
+
+ def __len__(self):
+ return len(self._dict)
+
+ def __iter__(self):
+ return self._dict.__iter__()
+
+ def __repr__(self):
+ return repr(self._dict)
+
+############################################################################
+# Load the contents of a KASP XML file as a python dictionary
+############################################################################
+if __name__ == "__main__":
+ from pprint import *
+ import sys
+
+ if len(sys.argv) < 2:
+ print("Usage: kasp2policy <filename>")
+ exit(1)
+
+ try:
+ kinfo = kasp(sys.argv[1])
+ except:
+ print("%s: unable to load KASP file '%s'" % (sys.argv[0], sys.argv[1]))
+ exit(1)
+
+ kt = kasptime()
+ first = True
+
+ for p in kinfo['KASP']['Policy']:
+ if not p['@name'] or not p['Keys']: continue
+ if not first:
+ print("")
+ first = False
+ if p['Description']:
+ d = p['Description'].strip()
+ print("# %s" % re.sub(r"\n\s*", "\n# ", d))
+ print("policy %s {" % p['@name'])
+ ksk = p['Keys']['KSK']
+ zsk = p['Keys']['ZSK']
+ kalg = ksk['Algorithm']
+ zalg = zsk['Algorithm']
+ algnum = kalg['#text'] or zalg['#text']
+ if algnum:
+ print("\talgorithm %s;" % dnskey.algstr(int(algnum)))
+ if p['Keys']['TTL']:
+ print("\tkeyttl %d;" % kt.parse(p['Keys']['TTL']))
+ if kalg['@length']:
+ print("\tkey-size ksk %d;" % int(kalg['@length']))
+ if zalg['@length']:
+ print("\tkey-size zsk %d;" % int(zalg['@length']))
+ if ksk['Lifetime']:
+ print("\troll-period ksk %d;" % kt.parse(ksk['Lifetime']))
+ if zsk['Lifetime']:
+ print("\troll-period zsk %d;" % kt.parse(zsk['Lifetime']))
+ if ksk['Standby']:
+ print("\tstandby ksk %d;" % int(ksk['Standby']))
+ if zsk['Standby']:
+ print("\tstandby zsk %d;" % int(zsk['Standby']))
+ print("};")