aboutsummaryrefslogtreecommitdiffstats
path: root/tools/insertkeys.py
diff options
context:
space:
mode:
authorWilliam Roberts <w.roberts@sta.samsung.com>2012-12-06 05:45:15 +0900
committerWilliam Roberts <w.roberts@sta.samsung.com>2012-12-08 09:26:37 +0900
commit22fc04103b70dd5a1cb1b5a8309ef20461e06289 (patch)
treeb60629ea7ee7eb90b6e56a3663add3aac6ef305b /tools/insertkeys.py
parent2c8a55dcf4e571c198118dd4459d62894f6378f3 (diff)
downloadandroid_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-xtools/insertkeys.py208
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])