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.py223
1 files changed, 223 insertions, 0 deletions
diff --git a/contrib/kasp/kasp2policy.py b/contrib/kasp/kasp2policy.py
new file mode 100644
index 0000000..a2536a7
--- /dev/null
+++ b/contrib/kasp/kasp2policy.py
@@ -0,0 +1,223 @@
+#!/usr/bin/python
+
+# Copyright (C) 2015 Internet Systems Consortium, Inc. ("ISC")
+# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
+#
+# SPDX-License-Identifier: MPL-2.0
+#
+# This Source Code Form is subject to the terms of the Mozilla Public
+# License, v. 2.0. If a copy of the MPL was not distributed with this
+# file, you can obtain one at https://mozilla.org/MPL/2.0/.
+#
+# See the COPYRIGHT file distributed with this work for additional
+# information regarding copyright ownership.
+
+from xml.etree import cElementTree as ET
+from collections import defaultdict
+import re
+from ply import yacc
+from ply import lex
+from isc import dnskey
+
+
+############################################################################
+# Translate KASP duration values into seconds
+############################################################################
+class KaspTime:
+ # pylint: disable=invalid-name
+ class KTLex:
+ # pylint: disable=invalid-name
+
+ 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"
+
+ @staticmethod
+ def t_NUM(t):
+ r"\d+"
+ t.value = int(t.value)
+ return t
+
+ @staticmethod
+ def t_error(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)
+
+ @staticmethod
+ def p_ktime_4(p):
+ "ktime : P periods T times"
+ p[0] = p[2] + p[4]
+
+ @staticmethod
+ def p_ktime_3(p):
+ "ktime : P T times"
+ p[0] = p[3]
+
+ @staticmethod
+ def p_ktime_2(p):
+ "ktime : P periods"
+ p[0] = p[2]
+
+ @staticmethod
+ def p_periods_1(p):
+ "periods : period"
+ p[0] = p[1]
+
+ @staticmethod
+ def p_periods_2(p):
+ "periods : periods period"
+ p[0] = p[1] + p[2]
+
+ @staticmethod
+ def p_times_1(p):
+ "times : time"
+ p[0] = p[1]
+
+ @staticmethod
+ def p_times_2(p):
+ "times : times time"
+ p[0] = p[1] + p[2]
+
+ @staticmethod
+ def p_period(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
+
+ @staticmethod
+ def p_time(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])
+
+ @staticmethod
+ def p_error():
+ print("Syntax error")
+
+
+############################################################################
+# Load the contents of a KASP XML file as a python dictionary
+############################################################################
+class Kasp:
+ # pylint: disable=invalid-name
+
+ @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)
+ k = {k: v[0] if len(v) == 1 else v for k, v in dd.items()}
+ d = {t.tag: k}
+ 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__":
+ import sys
+
+ if len(sys.argv) < 2:
+ print("Usage: kasp2policy <filename>")
+ sys.exit(1)
+
+ KINFO = Kasp(sys.argv[1])
+ try:
+ KINFO = Kasp(sys.argv[1])
+ except FileNotFoundError:
+ print("%s: unable to load KASP file '%s'" % (sys.argv[0], sys.argv[1]))
+ sys.exit(1)
+
+ KT = KaspTime()
+ FIRST = True
+
+ for policy in KINFO["KASP"]["Policy"]:
+ if not policy["@name"] or not policy["Keys"]:
+ continue
+ if not FIRST:
+ print("")
+ FIRST = False
+ if policy["Description"]:
+ desc = policy["Description"].strip()
+ print("# %s" % re.sub(r"\n\s*", "\n# ", desc))
+ print("policy %s {" % policy["@name"])
+ ksk = policy["Keys"]["KSK"]
+ zsk = policy["Keys"]["ZSK"]
+ kalg = ksk["Algorithm"]
+ zalg = zsk["Algorithm"]
+ algnum = kalg["#text"] or zalg["#text"]
+ if algnum:
+ print("\talgorithm %s;" % dnskey.algstr(int(algnum)))
+ if policy["Keys"]["TTL"]:
+ print("\tkeyttl %d;" % KT.parse(policy["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("};")