1#!/usr/bin/env python 2# 3# Copyright (C) 2025 The Android Open Source Project 4# 5# Licensed under the Apache License, Version 2.0 (the "License"); 6# you may not use this file except in compliance with the License. 7# You may obtain a copy of the License at 8# 9# http://www.apache.org/licenses/LICENSE-2.0 10# 11# Unless required by applicable law or agreed to in writing, software 12# distributed under the License is distributed on an "AS IS" BASIS, 13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14# See the License for the specific language governing permissions and 15# limitations under the License. 16"""brand_new_apex_verifier verifies blocklist files and public keys for brand-new APEX. 17 18Verifies the integrity of blocklist files and public keys associated with brand-new APEX modules. 19Specifically, it checks for duplicate entries in blocklist files and duplicate public key content. 20 21Example: 22 $ brand_new_apex_verifier --pubkey_paths path1 path2 --blocklist_paths --output_path output 23""" 24import argparse 25import os 26 27import apex_blocklist_pb2 28from google.protobuf import json_format 29 30 31def ParseArgs(): 32 parser = argparse.ArgumentParser() 33 parser.add_argument('--pubkey_paths', nargs='*', help='List of paths to the .avbpubkey files.') 34 parser.add_argument( 35 '--blocklist_paths', nargs='*', help='List of paths to the blocklist.json files.', 36 ) 37 parser.add_argument( 38 '--output_path', help='Output file path.', 39 ) 40 return parser.parse_args() 41 42 43def ParseBlocklistFile(file): 44 """Parses a blocklist JSON file into an ApexBlocklist protobuf object. 45 46 Args: 47 file: The path to the blocklist JSON file. 48 49 Returns: 50 An ApexBlocklist protobuf object. 51 52 Raises: 53 Exception: If parsing fails due to JSON format errors. 54 """ 55 try: 56 with open(file, 'rb') as f: 57 return json_format.Parse(f.read(), apex_blocklist_pb2.ApexBlocklist()) 58 except json_format.ParseError as err: 59 raise ValueError(err) from err 60 61 62def VerifyBlocklistFile(blocklist_paths): 63 """Verifies the provided blocklist files. 64 65 Checks for duplicate apex names within each blocklist file. 66 67 Args: 68 blocklist_paths: The paths to the blocklist files. 69 70 Raises: 71 Exception: If duplicate apex names are found in any blocklist file. 72 """ 73 for blocklist_path in blocklist_paths: 74 if not os.path.exists(blocklist_path): 75 continue 76 apex_blocklist = ParseBlocklistFile(blocklist_path) 77 blocked_apex = set() 78 for apex_item in apex_blocklist.blocked_apex: 79 if apex_item.name in blocked_apex: 80 raise ValueError(f'Duplicate apex name found in blocklist file: {blocklist_path}') 81 blocked_apex.add(apex_item.name) 82 83 84def VerifyPublicKey(pubkey_paths): 85 """Verifies the provided public key files. 86 87 Checks for duplicate public key file content. 88 89 Args: 90 pubkey_paths: Paths to the public key files. 91 92 Raises: 93 Exception: If duplicate public key content is found. 94 """ 95 pubkeys = {} 96 for file_path in pubkey_paths: 97 if not os.path.exists(file_path): 98 continue 99 try: 100 with open(file_path, 'rb') as f: 101 file_content = f.read() 102 if file_content in pubkeys: 103 raise ValueError( 104 f'Duplicate key material found: {pubkeys[file_content]} and ' 105 f'{file_path}.') 106 pubkeys[file_content] = file_path 107 except OSError as e: 108 raise ValueError(f'Error reading public key file {file_path}: {e}') from e 109 110 111def main(): 112 args = ParseArgs() 113 114 with open(args.output_path, 'w', encoding='utf-8') as f: 115 try: 116 VerifyBlocklistFile(args.blocklist_paths) 117 VerifyPublicKey(args.pubkey_paths) 118 f.write('Verification successful.') 119 except ValueError as e: 120 f.write(f'Verification failed: {e}') 121 122if __name__ == '__main__': 123 main() 124