from lxml import etree import sys import string import types import json def getReference(element, sec_id_map): """ Find all JSIG control IDs for a given test_name """ for child in element: tag = etree.QName(child.tag) attributes = dict(child.attrib) if str(tag.localname) == 'reference': for key, value in attributes.iteritems(): if key == 'href' and '800-53' in value and not isinstance(child.text, types.NoneType): if sec_id_map['800-53'] == '': sec_id_map['800-53'] = sec_id_map['800-53'] + child.text else: sec_id_map['800-53'] = sec_id_map['800-53'] + ',' + child.text elif str(tag.localname) == 'ident': if sec_id_map['cce'] == '': sec_id_map['cce'] = sec_id_map['cce'] + child.text else: sec_id_map['cce'] = sec_id_map['cce'] + ',' + child.text def jsonifyRules(tree): """ Create the following JSON payload from XML: { "test_map": { "test_name": [ { "800-53", }, { "cce", } ] } } Where: test_name = The SCAP rule ID = All associated JSIG controls = The CCE number from http://cce.mitre.org """ map = '' for child in tree.iter(tag=etree.Element): tag = etree.QName(child.tag) if str(tag.localname) == 'Rule': sec_id_map = {} sec_id_map['id'] = '' sec_id_map['800-53'] = '' sec_id_map['cce'] = '' sec_id_map['id'] = child.get("id") getReference(child, sec_id_map) if map == '': map = '{"test_map": [{"' + sec_id_map['id'] + '": {"800-53": "' + sec_id_map['800-53'] + '", "cce": "' + sec_id_map['cce'] + '"}}' else: map = map + ',{"' + sec_id_map['id'] + '": {"800-53": "' + sec_id_map['800-53'] + '", "cce": "' + sec_id_map['cce'] + '"}}' map = map + ']}' return json.loads(map) def modTitle(tree, table): """ Modify the title of the OSCAP results XML to include the rule ID """ for child in tree.iter(tag=etree.Element): tag = etree.QName(child.tag) if str(tag.localname) == 'Rule': for test in table['test_map']: for key in test.keys(): if child.get("id") == key: for gchild in child: if str(etree.QName(gchild.tag).localname) == 'title': currTitle = gchild.text gchild.text = key + ' - ' + currTitle def modResult(tree, table): """ Modify the rule detail security control reference to include JSIG controls """ for child in tree.iter(tag=etree.Element): tag = etree.QName(child.tag) if str(tag.localname) == 'rule-result': for test in table['test_map']: for key in test.keys(): if child.get("idref") == key: for gchild in child: if str(etree.QName(gchild.tag).localname) == 'ident': currIdent = gchild.text gchild.text = 'CCE: ' + currIdent + ' NIST 800-53: ' + test[key]['800-53'] tree = etree.parse(sys.argv[1]) root = tree.getroot() table = jsonifyRules(root) modTitle(root, table) modResult(root, table) tree.write(sys.argv[1])