| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 1 | #! /usr/bin/env python |
| Tao Bao | 39d1756 | 2016-10-17 16:06:31 -0700 | [diff] [blame] | 2 | # |
| 3 | # Copyright (C) 2013 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. |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 16 | |
| Tao Bao | 39d1756 | 2016-10-17 16:06:31 -0700 | [diff] [blame] | 17 | import argparse |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 18 | import os |
| 19 | import sys |
| 20 | import struct |
| Tianjie Xu | 441ebc9 | 2016-10-25 18:11:24 -0700 | [diff] [blame] | 21 | import shlex |
| 22 | import subprocess |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 23 | import tempfile |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 24 | |
| 25 | VERSION = 0 |
| 26 | MAGIC_NUMBER = 0xb001b001 |
| Bowgo Tsai | 306bc2e | 2017-10-11 16:35:25 +0800 | [diff] [blame] | 27 | MAGIC_DISABLE = 0x46464f56 # "VOFF" |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 28 | BLOCK_SIZE = 4096 |
| 29 | METADATA_SIZE = BLOCK_SIZE * 8 |
| 30 | |
| 31 | def run(cmd): |
| Tianjie Xu | 441ebc9 | 2016-10-25 18:11:24 -0700 | [diff] [blame] | 32 | p = subprocess.Popen(cmd, stdout=subprocess.PIPE) |
| 33 | output, _ = p.communicate() |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 34 | print output |
| Tianjie Xu | 441ebc9 | 2016-10-25 18:11:24 -0700 | [diff] [blame] | 35 | if p.returncode: |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 36 | exit(-1) |
| 37 | |
| 38 | def get_verity_metadata_size(data_size): |
| 39 | return METADATA_SIZE |
| 40 | |
| Bowgo Tsai | 306bc2e | 2017-10-11 16:35:25 +0800 | [diff] [blame] | 41 | def build_metadata_block(verity_table, signature, verity_disable=False): |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 42 | table_len = len(verity_table) |
| Bowgo Tsai | 306bc2e | 2017-10-11 16:35:25 +0800 | [diff] [blame] | 43 | magic = MAGIC_DISABLE if verity_disable else MAGIC_NUMBER |
| 44 | block = struct.pack("II256sI", magic, VERSION, signature, table_len) |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 45 | block += verity_table |
| 46 | block = block.ljust(METADATA_SIZE, '\x00') |
| 47 | return block |
| 48 | |
| Tao Bao | 39d1756 | 2016-10-17 16:06:31 -0700 | [diff] [blame] | 49 | def sign_verity_table(table, signer_path, key_path, signer_args=None): |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 50 | with tempfile.NamedTemporaryFile(suffix='.table') as table_file: |
| 51 | with tempfile.NamedTemporaryFile(suffix='.sig') as signature_file: |
| 52 | table_file.write(table) |
| 53 | table_file.flush() |
| Tianjie Xu | 441ebc9 | 2016-10-25 18:11:24 -0700 | [diff] [blame] | 54 | if signer_args is None: |
| 55 | cmd = [signer_path, table_file.name, key_path, signature_file.name] |
| 56 | else: |
| 57 | args_list = shlex.split(signer_args) |
| 58 | cmd = [signer_path] + args_list + [table_file.name, key_path, signature_file.name] |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 59 | print cmd |
| 60 | run(cmd) |
| 61 | return signature_file.read() |
| 62 | |
| 63 | def build_verity_table(block_device, data_blocks, root_hash, salt): |
| 64 | table = "1 %s %s %s %s %s %s sha256 %s %s" |
| 65 | table %= ( block_device, |
| 66 | block_device, |
| 67 | BLOCK_SIZE, |
| 68 | BLOCK_SIZE, |
| 69 | data_blocks, |
| Sami Tolvanen | 8775778 | 2015-09-25 14:57:41 +0100 | [diff] [blame] | 70 | data_blocks, |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 71 | root_hash, |
| 72 | salt) |
| 73 | return table |
| 74 | |
| Tao Bao | 39d1756 | 2016-10-17 16:06:31 -0700 | [diff] [blame] | 75 | def build_verity_metadata(data_blocks, metadata_image, root_hash, salt, |
| Bowgo Tsai | 306bc2e | 2017-10-11 16:35:25 +0800 | [diff] [blame] | 76 | block_device, signer_path, signing_key, signer_args=None, |
| 77 | verity_disable=False): |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 78 | # build the verity table |
| 79 | verity_table = build_verity_table(block_device, data_blocks, root_hash, salt) |
| 80 | # build the verity table signature |
| Tao Bao | 39d1756 | 2016-10-17 16:06:31 -0700 | [diff] [blame] | 81 | signature = sign_verity_table(verity_table, signer_path, signing_key, signer_args) |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 82 | # build the metadata block |
| Bowgo Tsai | 306bc2e | 2017-10-11 16:35:25 +0800 | [diff] [blame] | 83 | metadata_block = build_metadata_block(verity_table, signature, verity_disable) |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 84 | # write it to the outfile |
| 85 | with open(metadata_image, "wb") as f: |
| 86 | f.write(metadata_block) |
| 87 | |
| 88 | if __name__ == "__main__": |
| Tao Bao | 39d1756 | 2016-10-17 16:06:31 -0700 | [diff] [blame] | 89 | parser = argparse.ArgumentParser() |
| 90 | subparsers = parser.add_subparsers() |
| 91 | |
| 92 | parser_size = subparsers.add_parser('size') |
| 93 | parser_size.add_argument('partition_size', type=int, action='store', help='partition size') |
| 94 | parser_size.set_defaults(dest='size') |
| 95 | |
| 96 | parser_build = subparsers.add_parser('build') |
| 97 | parser_build.add_argument('blocks', type=int, help='data image blocks') |
| 98 | parser_build.add_argument('metadata_image', action='store', help='metadata image') |
| 99 | parser_build.add_argument('root_hash', action='store', help='root hash') |
| 100 | parser_build.add_argument('salt', action='store', help='salt') |
| 101 | parser_build.add_argument('block_device', action='store', help='block device') |
| 102 | parser_build.add_argument('signer_path', action='store', help='verity signer path') |
| 103 | parser_build.add_argument('signing_key', action='store', help='verity signing key') |
| 104 | parser_build.add_argument('--signer_args', action='store', help='verity signer args') |
| Bowgo Tsai | 306bc2e | 2017-10-11 16:35:25 +0800 | [diff] [blame] | 105 | parser_build.add_argument('--verity_disable', action='store_true', |
| 106 | default=False, help='disable verity') |
| Tao Bao | 39d1756 | 2016-10-17 16:06:31 -0700 | [diff] [blame] | 107 | parser_build.set_defaults(dest='build') |
| 108 | |
| 109 | args = parser.parse_args() |
| 110 | |
| 111 | if args.dest == 'size': |
| 112 | print get_verity_metadata_size(args.partition_size) |
| Geremy Condra | 649fd55 | 2013-10-21 20:34:13 +0000 | [diff] [blame] | 113 | else: |
| Tao Bao | 39d1756 | 2016-10-17 16:06:31 -0700 | [diff] [blame] | 114 | build_verity_metadata(args.blocks / 4096, args.metadata_image, |
| 115 | args.root_hash, args.salt, args.block_device, |
| 116 | args.signer_path, args.signing_key, |
| Bowgo Tsai | 306bc2e | 2017-10-11 16:35:25 +0800 | [diff] [blame] | 117 | args.signer_args, args.verity_disable) |