13e70d4793a096cab829c3141491944485e482f9fRobert Craig#!/usr/bin/env python 23e70d4793a096cab829c3141491944485e482f9fRobert Craig# 33e70d4793a096cab829c3141491944485e482f9fRobert Craig# Copyright (C) 2013 The Android Open Source Project 43e70d4793a096cab829c3141491944485e482f9fRobert Craig# 53e70d4793a096cab829c3141491944485e482f9fRobert Craig# Licensed under the Apache License, Version 2.0 (the "License"); 63e70d4793a096cab829c3141491944485e482f9fRobert Craig# you may not use this file except in compliance with the License. 73e70d4793a096cab829c3141491944485e482f9fRobert Craig# You may obtain a copy of the License at 83e70d4793a096cab829c3141491944485e482f9fRobert Craig# 93e70d4793a096cab829c3141491944485e482f9fRobert Craig# http://www.apache.org/licenses/LICENSE-2.0 103e70d4793a096cab829c3141491944485e482f9fRobert Craig# 113e70d4793a096cab829c3141491944485e482f9fRobert Craig# Unless required by applicable law or agreed to in writing, software 123e70d4793a096cab829c3141491944485e482f9fRobert Craig# distributed under the License is distributed on an "AS IS" BASIS, 133e70d4793a096cab829c3141491944485e482f9fRobert Craig# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 143e70d4793a096cab829c3141491944485e482f9fRobert Craig# See the License for the specific language governing permissions and 153e70d4793a096cab829c3141491944485e482f9fRobert Craig# limitations under the License. 163e70d4793a096cab829c3141491944485e482f9fRobert Craig 173e70d4793a096cab829c3141491944485e482f9fRobert Craig""" 183e70d4793a096cab829c3141491944485e482f9fRobert CraigTool to help modify an existing mac_permissions.xml with additional app 193e70d4793a096cab829c3141491944485e482f9fRobert Craigcerts not already found in that policy. This becomes useful when a directory 203e70d4793a096cab829c3141491944485e482f9fRobert Craigcontaining apps is searched and the certs from those apps are added to the 213e70d4793a096cab829c3141491944485e482f9fRobert Craigpolicy not already explicitly listed. 223e70d4793a096cab829c3141491944485e482f9fRobert Craig""" 233e70d4793a096cab829c3141491944485e482f9fRobert Craig 243e70d4793a096cab829c3141491944485e482f9fRobert Craigimport sys 253e70d4793a096cab829c3141491944485e482f9fRobert Craigimport os 263e70d4793a096cab829c3141491944485e482f9fRobert Craigimport argparse 273e70d4793a096cab829c3141491944485e482f9fRobert Craigfrom base64 import b16encode, b64decode 283e70d4793a096cab829c3141491944485e482f9fRobert Craigimport fileinput 293e70d4793a096cab829c3141491944485e482f9fRobert Craigimport re 303e70d4793a096cab829c3141491944485e482f9fRobert Craigimport subprocess 313e70d4793a096cab829c3141491944485e482f9fRobert Craigimport zipfile 323e70d4793a096cab829c3141491944485e482f9fRobert Craig 333e70d4793a096cab829c3141491944485e482f9fRobert CraigPEM_CERT_RE = """-----BEGIN CERTIFICATE----- 343e70d4793a096cab829c3141491944485e482f9fRobert Craig(.+?) 353e70d4793a096cab829c3141491944485e482f9fRobert Craig-----END CERTIFICATE----- 363e70d4793a096cab829c3141491944485e482f9fRobert Craig""" 373e70d4793a096cab829c3141491944485e482f9fRobert Craigdef collect_certs_for_app(filename): 383e70d4793a096cab829c3141491944485e482f9fRobert Craig app_certs = set() 393e70d4793a096cab829c3141491944485e482f9fRobert Craig with zipfile.ZipFile(filename, 'r') as apkzip: 403e70d4793a096cab829c3141491944485e482f9fRobert Craig for info in apkzip.infolist(): 413e70d4793a096cab829c3141491944485e482f9fRobert Craig name = info.filename 423e70d4793a096cab829c3141491944485e482f9fRobert Craig if name.startswith('META-INF/') and name.endswith(('.DSA', '.RSA')): 433e70d4793a096cab829c3141491944485e482f9fRobert Craig cmd = ['openssl', 'pkcs7', '-inform', 'DER', 443e70d4793a096cab829c3141491944485e482f9fRobert Craig '-outform', 'PEM', '-print_certs'] 453e70d4793a096cab829c3141491944485e482f9fRobert Craig p = subprocess.Popen(cmd, stdin=subprocess.PIPE, stdout=subprocess.PIPE, 463e70d4793a096cab829c3141491944485e482f9fRobert Craig stderr=subprocess.PIPE) 473e70d4793a096cab829c3141491944485e482f9fRobert Craig pem_string, err = p.communicate(apkzip.read(name)) 483e70d4793a096cab829c3141491944485e482f9fRobert Craig if err and err.strip(): 493e70d4793a096cab829c3141491944485e482f9fRobert Craig raise RuntimeError('Problem running openssl on %s (%s)' % (filename, e)) 503e70d4793a096cab829c3141491944485e482f9fRobert Craig 513e70d4793a096cab829c3141491944485e482f9fRobert Craig # turn multiline base64 to single line base16 523e70d4793a096cab829c3141491944485e482f9fRobert Craig transform = lambda x: b16encode(b64decode(x.replace('\n', ''))).lower() 533e70d4793a096cab829c3141491944485e482f9fRobert Craig results = re.findall(PEM_CERT_RE, pem_string, re.DOTALL) 543e70d4793a096cab829c3141491944485e482f9fRobert Craig certs = [transform(i) for i in results] 553e70d4793a096cab829c3141491944485e482f9fRobert Craig 563e70d4793a096cab829c3141491944485e482f9fRobert Craig app_certs.update(certs) 573e70d4793a096cab829c3141491944485e482f9fRobert Craig 583e70d4793a096cab829c3141491944485e482f9fRobert Craig return app_certs 593e70d4793a096cab829c3141491944485e482f9fRobert Craig 603e70d4793a096cab829c3141491944485e482f9fRobert Craigdef add_leftover_certs(args): 613e70d4793a096cab829c3141491944485e482f9fRobert Craig all_app_certs = set() 623e70d4793a096cab829c3141491944485e482f9fRobert Craig for dirpath, _, files in os.walk(args.dir): 633e70d4793a096cab829c3141491944485e482f9fRobert Craig transform = lambda x: os.path.join(dirpath, x) 643e70d4793a096cab829c3141491944485e482f9fRobert Craig condition = lambda x: x.endswith('.apk') 653e70d4793a096cab829c3141491944485e482f9fRobert Craig apps = [transform(i) for i in files if condition(i)] 663e70d4793a096cab829c3141491944485e482f9fRobert Craig 673e70d4793a096cab829c3141491944485e482f9fRobert Craig # Collect certs for each app found 683e70d4793a096cab829c3141491944485e482f9fRobert Craig for app in apps: 693e70d4793a096cab829c3141491944485e482f9fRobert Craig app_certs = collect_certs_for_app(app) 703e70d4793a096cab829c3141491944485e482f9fRobert Craig all_app_certs.update(app_certs) 713e70d4793a096cab829c3141491944485e482f9fRobert Craig 723e70d4793a096cab829c3141491944485e482f9fRobert Craig if all_app_certs: 733e70d4793a096cab829c3141491944485e482f9fRobert Craig policy_certs = set() 743e70d4793a096cab829c3141491944485e482f9fRobert Craig with open(args.policy, 'r') as f: 753e70d4793a096cab829c3141491944485e482f9fRobert Craig cert_pattern = 'signature="([a-fA-F0-9]+)"' 763e70d4793a096cab829c3141491944485e482f9fRobert Craig policy_certs = re.findall(cert_pattern, f.read()) 773e70d4793a096cab829c3141491944485e482f9fRobert Craig 783e70d4793a096cab829c3141491944485e482f9fRobert Craig cert_diff = all_app_certs.difference(policy_certs) 793e70d4793a096cab829c3141491944485e482f9fRobert Craig 803e70d4793a096cab829c3141491944485e482f9fRobert Craig # Build xml stanzas 813e70d4793a096cab829c3141491944485e482f9fRobert Craig inner_tag = '<seinfo value="%s"/>' % args.seinfo 823e70d4793a096cab829c3141491944485e482f9fRobert Craig stanza = '<signer signature="%s">%s</signer>' 833e70d4793a096cab829c3141491944485e482f9fRobert Craig new_stanzas = [stanza % (cert, inner_tag) for cert in cert_diff] 843e70d4793a096cab829c3141491944485e482f9fRobert Craig mac_perms_string = ''.join(new_stanzas) 853e70d4793a096cab829c3141491944485e482f9fRobert Craig mac_perms_string += '</policy>' 863e70d4793a096cab829c3141491944485e482f9fRobert Craig 873e70d4793a096cab829c3141491944485e482f9fRobert Craig # Inline replace with new policy stanzas 883e70d4793a096cab829c3141491944485e482f9fRobert Craig for line in fileinput.input(args.policy, inplace=True): 893ea628fccc5c6276264c221adbfe057cf5df9b87Robert Craig sys.stdout.write(line.replace('</policy>', mac_perms_string)) 903e70d4793a096cab829c3141491944485e482f9fRobert Craig 913e70d4793a096cab829c3141491944485e482f9fRobert Craigdef main(argv): 923e70d4793a096cab829c3141491944485e482f9fRobert Craig parser = argparse.ArgumentParser(description=__doc__) 933e70d4793a096cab829c3141491944485e482f9fRobert Craig 943e70d4793a096cab829c3141491944485e482f9fRobert Craig parser.add_argument('-s', '--seinfo', dest='seinfo', required=True, 953e70d4793a096cab829c3141491944485e482f9fRobert Craig help='seinfo tag for each generated stanza') 963e70d4793a096cab829c3141491944485e482f9fRobert Craig parser.add_argument('-d', '--dir', dest='dir', required=True, 973e70d4793a096cab829c3141491944485e482f9fRobert Craig help='Directory to search for apks') 983e70d4793a096cab829c3141491944485e482f9fRobert Craig parser.add_argument('-f', '--file', dest='policy', required=True, 993e70d4793a096cab829c3141491944485e482f9fRobert Craig help='mac_permissions.xml policy file') 1003e70d4793a096cab829c3141491944485e482f9fRobert Craig 1013e70d4793a096cab829c3141491944485e482f9fRobert Craig parser.set_defaults(func=add_leftover_certs) 1023e70d4793a096cab829c3141491944485e482f9fRobert Craig args = parser.parse_args() 1033e70d4793a096cab829c3141491944485e482f9fRobert Craig args.func(args) 1043e70d4793a096cab829c3141491944485e482f9fRobert Craig 1053e70d4793a096cab829c3141491944485e482f9fRobert Craigif __name__ == '__main__': 1063e70d4793a096cab829c3141491944485e482f9fRobert Craig main(sys.argv) 107