diff options
author | William Roberts <w.roberts@sta.samsung.com> | 2012-12-06 05:45:15 +0900 |
---|---|---|
committer | William Roberts <w.roberts@sta.samsung.com> | 2012-12-08 09:26:37 +0900 |
commit | 22fc04103b70dd5a1cb1b5a8309ef20461e06289 (patch) | |
tree | b60629ea7ee7eb90b6e56a3663add3aac6ef305b /tools/insertkeys.py | |
parent | 2c8a55dcf4e571c198118dd4459d62894f6378f3 (diff) | |
download | android_external_sepolicy-22fc04103b70dd5a1cb1b5a8309ef20461e06289.tar.gz android_external_sepolicy-22fc04103b70dd5a1cb1b5a8309ef20461e06289.tar.bz2 android_external_sepolicy-22fc04103b70dd5a1cb1b5a8309ef20461e06289.zip |
Dynamic insertion of pubkey to mac_permissions.xml
Support the inseretion of the public key from pem
files into the mac_permissions.xml file at build
time.
Change-Id: Ia42b6cba39bf93723ed3fb85236eb8f80a08962a
Diffstat (limited to 'tools/insertkeys.py')
-rwxr-xr-x | tools/insertkeys.py | 208 |
1 files changed, 208 insertions, 0 deletions
diff --git a/tools/insertkeys.py b/tools/insertkeys.py new file mode 100755 index 0000000..e4eeb43 --- /dev/null +++ b/tools/insertkeys.py @@ -0,0 +1,208 @@ +#!/usr/bin/env python + +from xml.sax import saxutils, handler, make_parser +from optparse import OptionParser +import ConfigParser +import logging +import base64 +import sys +import os + +__VERSION = (0, 1) + +''' +This tool reads a mac_permissions.xml and replaces keywords in the signature +clause with keys provided by pem files. +''' + +class GenerateKeys(object): + def __init__(self, path): + ''' + Generates an object with Base16 and Base64 encoded versions of the keys + found in the supplied pem file argument. PEM files can contain multiple + certs, however this seems to be unused in Android as pkg manager grabs + the first cert in the APK. This will however support multiple certs in + the resulting generation with index[0] being the first cert in the pem + file. + ''' + + self._base64Key = list() + self._base16Key = list() + + if not os.path.isfile(path): + sys.exit("Path " + path + " does not exist or is not a file!") + + pkFile = open(path, 'rb').readlines() + base64Key = "" + inCert = False + for line in pkFile: + if line.startswith("-"): + inCert = not inCert + continue + + base64Key += line.strip() + + # Base 64 includes uppercase. DO NOT tolower() + self._base64Key.append(base64Key) + + # Pkgmanager and setool see hex strings with lowercase, lets be consistent. + self._base16Key.append(base64.b16encode(base64.b64decode(base64Key)).lower()) + + def __len__(self): + return len(self._base16Key) + + def __str__(self): + return str(self.getBase16Keys()) + + def getBase16Keys(self): + return self._base16Key + + def getBase64Keys(self): + return self._base64Key + +class ParseConfig(ConfigParser.ConfigParser): + + # This must be lowercase + OPTION_WILDCARD_TAG = "all" + + def generateKeyMap(self, target_build_variant): + + keyMap = dict() + + for tag in self.sections(): + + options = self.options(tag) + + for option in options: + + # Only generate the key map for debug or release, + # not both! + if option != target_build_variant and \ + option != ParseConfig.OPTION_WILDCARD_TAG: + logging.info("Skipping " + tag + " : " + option + + " because target build variant is set to " + + str(target_build_variant)) + continue + + if tag in keyMap: + sys.exit("Duplicate tag detected " + tag) + + path = self.get(tag, option) + + keyMap[tag] = GenerateKeys(path) + + # Multiple certificates may exist in + # the pem file. GenerateKeys supports + # this however, the mac_permissions.xml + # as well as PMS do not. + assert len(keyMap[tag]) == 1 + + return keyMap + +class ReplaceTags(handler.ContentHandler): + + DEFAULT_TAG = "default" + PACKAGE_TAG = "package" + POLICY_TAG = "policy" + SIGNER_TAG = "signer" + SIGNATURE_TAG = "signature" + + TAGS_WITH_CHILDREN = [ DEFAULT_TAG, PACKAGE_TAG, POLICY_TAG, SIGNER_TAG ] + + XML_ENCODING_TAG = '<?xml version="1.0" encoding="iso-8859-1"?>' + + def __init__(self, keyMap, out=sys.stdout): + + handler.ContentHandler.__init__(self) + self._keyMap = keyMap + self._out = out + + def startDocument(self): + self._out.write(ReplaceTags.XML_ENCODING_TAG) + self._out.write("<!-- AUTOGENERATED FILE DO NOT MODIFY -->") + + def startElement(self, tag, attrs): + + self._out.write('<' + tag) + + for (name, value) in attrs.items(): + + if name == ReplaceTags.SIGNATURE_TAG and value in self._keyMap: + for key in self._keyMap[value].getBase16Keys(): + logging.info("Replacing " + name + " " + value + " with " + key) + self._out.write(' %s="%s"' % (name, saxutils.escape(key))) + else: + self._out.write(' %s="%s"' % (name, saxutils.escape(value))) + + if tag in ReplaceTags.TAGS_WITH_CHILDREN: + self._out.write('>') + else: + self._out.write('/>') + + def endElement(self, tag): + if tag in ReplaceTags.TAGS_WITH_CHILDREN: + self._out.write('</%s>' % tag) + + def characters(self, content): + if not content.isspace(): + self._out.write(saxutils.escape(content)) + + def ignorableWhitespace(self, content): + pass + + def processingInstruction(self, target, data): + self._out.write('<?%s %s?>' % (target, data)) + +if __name__ == "__main__": + + # Intentional double space to line up equls signs and opening " for + # readability. + usage = "usage: %prog [options] CONFIG_FILE MAC_PERMISSIONS_FILE\n" + usage += "This tool allows one to configure an automatic inclusion " + usage += "of signing keys into the mac_permision.xml file from the " + usage += "pem files." + + version = "%prog " + str(__VERSION) + + parser = OptionParser(usage=usage, version=version) + + parser.add_option("-v", "--verbose", + action="store_true", dest="verbose", default=False, + help="Print internal operations to stdout") + + parser.add_option("-o", "--output", default="stdout", dest="output_file", + metavar="FILE", help="Specify an output file, default is stdout") + + parser.add_option("-c", "--cwd", default=os.getcwd(), dest="root", + metavar="DIR", help="Specify a root (CWD) directory to run this from, it" \ + "chdirs' AFTER loading the config file") + + parser.add_option("-t", "--target-build-variant", default="eng", dest="target_build_variant", + help="Specify the TARGET_BUILD_VARIANT, defaults to eng") + + + (options, args) = parser.parse_args() + + if len(args) != 2: + parser.error("Must specify a config file (keys.conf) AND mac_permissions.xml file!") + + logging.basicConfig(level=logging.INFO if options.verbose == True else logging.WARN) + + # Read the config file + config = ParseConfig() + config.read(args[0]) + + os.chdir(options.root) + + output_file = sys.stdout if options.output_file == "stdout" else open(options.output_file, "w") + logging.info("Setting output file to: " + options.output_file) + + # Generate the key list + key_map = config.generateKeyMap(options.target_build_variant.lower()) + logging.info("Generate key map:") + for k in key_map: + logging.info(k + " : " + str(key_map[k])) + # Generate the XML file with markup replaced with keys + parser = make_parser() + parser.setContentHandler(ReplaceTags(key_map, output_file)) + parser.parse(args[1]) |