Yilin Yang | 19da693 | 2019-12-10 13:39:28 +0800 | [diff] [blame] | 1 | #!/usr/bin/env python3 |
Hung-Te Lin | 1990b74 | 2017-08-09 17:34:57 +0800 | [diff] [blame] | 2 | # Copyright 2011 The Chromium OS Authors. All rights reserved. |
Hung-Te Lin | c83105f | 2011-03-16 18:38:04 +0800 | [diff] [blame] | 3 | # Use of this source code is governed by a BSD-style license that can be |
| 4 | # found in the LICENSE file. |
| 5 | |
| 6 | # THIS FILE IS COPIED FROM AUTOTEST LIBRARY AND FOLLOWING PEP8 CODING STYLE RULE |
| 7 | # FOR BACKWARD COMPATIBLE, WE'RE NOT CHANGING ITS INDENTATION AND FUNCTION NAMES |
| 8 | |
| 9 | """ |
| 10 | Chrome OS firmware verification block parser. |
| 11 | |
| 12 | This module helps parsing firmware verification blocks so that we can |
| 13 | retrieve the version and other information from a blob. |
| 14 | |
| 15 | See help(unpack_verification_block) for more information. |
| 16 | |
| 17 | ref: src/platform/vboot_reference/firmware/lib/include/vboot_struct.h |
| 18 | """ |
| 19 | |
| 20 | import struct |
| 21 | import sys |
| 22 | |
| 23 | # Constant Definition |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 24 | KEY_BLOCK_MAGIC = 'CHROMEOS' |
Hung-Te Lin | c83105f | 2011-03-16 18:38:04 +0800 | [diff] [blame] | 25 | KEY_BLOCK_MAGIC_SIZE = 8 |
| 26 | KEY_BLOCK_HEADER_VERSION_MAJOR = 2 |
| 27 | KEY_BLOCK_HEADER_VERSION_MINOR = 1 |
| 28 | FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR = 2 |
| 29 | FIRMWARE_PREAMBLE_HEADER_VERSION_MINOR = 0 |
| 30 | |
| 31 | |
| 32 | def unpack_VbKeyBlockHeader(blob, offset=0): |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 33 | """Unpacks a VbKeyBlockHeader from a blob, starting from offset. |
Hung-Te Lin | c83105f | 2011-03-16 18:38:04 +0800 | [diff] [blame] | 34 | |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 35 | The blob is supposed to be a VBLOCK_A or VBLOCK_A in firmware image. |
| 36 | Blob structure: |
| 37 | typedef struct VbKeyBlockHeader { |
| 38 | uint8_t magic[KEY_BLOCK_MAGIC_SIZE]; |
| 39 | uint32_t header_version_major; |
| 40 | uint32_t header_version_minor; |
| 41 | uint64_t key_block_size; |
| 42 | ... |
| 43 | }; |
| 44 | """ |
| 45 | fields = struct.unpack_from('<8sIIQ', blob, offset) |
| 46 | names = ('magic', 'header_version_major', 'header_version_minor', |
| 47 | 'key_block_size') |
| 48 | header = dict(zip(names, fields)) |
| 49 | # check values |
| 50 | if header['magic'] != KEY_BLOCK_MAGIC: |
Hung-Te Lin | eec4e33 | 2017-06-01 23:16:40 +0800 | [diff] [blame] | 51 | raise ValueError('unknown key block magic: %s' % header['magic']) |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 52 | major = header['header_version_major'] |
| 53 | minor = header['header_version_minor'] |
Hung-Te Lin | eec4e33 | 2017-06-01 23:16:40 +0800 | [diff] [blame] | 54 | if major != KEY_BLOCK_HEADER_VERSION_MAJOR: |
| 55 | raise ValueError('unknown key block version (%d.%d)' % (major, minor)) |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 56 | return header |
Hung-Te Lin | c83105f | 2011-03-16 18:38:04 +0800 | [diff] [blame] | 57 | |
| 58 | |
| 59 | def unpack_VbFirmwarePreambleHeader(blob, offset=0): |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 60 | """Unpacks a VbFirmwarePreambleHeader from a blob, starting from offset. |
Hung-Te Lin | c83105f | 2011-03-16 18:38:04 +0800 | [diff] [blame] | 61 | |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 62 | The blob is supposed to be located immediately after a VbKeyBlockHeader. |
| 63 | (i.e., offset = VbKeyBlockHeader[key_block_size]) |
| 64 | Blob structure: |
| 65 | typedef struct VbFirmwarePreambleHeader { |
| 66 | uint64_t preamble_size; |
| 67 | struct VbSignature preamble_signature { |
| 68 | uint64_t sig_offset; |
| 69 | uint64_t sig_size; |
| 70 | uint64_t data_size; |
| 71 | }; |
| 72 | uint32_t header_version_major; |
| 73 | uint32_t header_version_minor; |
| 74 | uint64_t firmware_version; |
| 75 | ... |
| 76 | }; |
| 77 | """ |
| 78 | fields = struct.unpack_from('<QQQQIIQ', blob, offset) |
| 79 | names = ('preamble_size', |
| 80 | 'sig_offset', 'sig_size', 'data_size', |
| 81 | 'header_version_major', 'header_version_minor', |
| 82 | 'firmware_version') |
| 83 | header = dict(zip(names, fields)) |
| 84 | # check values |
| 85 | major = header['header_version_major'] |
| 86 | minor = header['header_version_minor'] |
| 87 | if major != FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR: |
Hung-Te Lin | eec4e33 | 2017-06-01 23:16:40 +0800 | [diff] [blame] | 88 | raise ValueError('unknown preamble version: (%d.%d)' % (major, minor)) |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 89 | return header |
Hung-Te Lin | c83105f | 2011-03-16 18:38:04 +0800 | [diff] [blame] | 90 | |
| 91 | |
| 92 | def unpack_verification_block(blob, offset=0): |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 93 | """Unpacks a Chrome OS verification block. |
Hung-Te Lin | c83105f | 2011-03-16 18:38:04 +0800 | [diff] [blame] | 94 | |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 95 | Returns a dictionary of VbKeyBlockHeader and VbFirmwarePreambleHeader. |
Hung-Te Lin | c83105f | 2011-03-16 18:38:04 +0800 | [diff] [blame] | 96 | |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 97 | Use help(unpack_VbKeyBlockHeader) and help(unpack_VbFirmwarePreambleHeader) |
| 98 | for more detail information. |
| 99 | """ |
| 100 | result = {} |
| 101 | result['VbKeyBlockHeader'] = unpack_VbKeyBlockHeader(blob, offset) |
| 102 | result['VbFirmwarePreambleHeader'] = unpack_VbFirmwarePreambleHeader( |
| 103 | blob, result['VbKeyBlockHeader']['key_block_size']) |
| 104 | return result |
Hung-Te Lin | c83105f | 2011-03-16 18:38:04 +0800 | [diff] [blame] | 105 | |
| 106 | |
| 107 | # ----------------------------------------------------------------------------- |
| 108 | |
| 109 | |
| 110 | def test_report_vblock_info(blob, offset=0): |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 111 | """ Reports the information of a vblock blob. """ |
| 112 | kb_header = unpack_VbKeyBlockHeader(blob, offset) |
Yilin Yang | 71e3941 | 2019-09-24 09:26:46 +0800 | [diff] [blame] | 113 | print('-- VbKeyBlockHeader --') |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 114 | for name, value in kb_header.items(): |
Yilin Yang | 71e3941 | 2019-09-24 09:26:46 +0800 | [diff] [blame] | 115 | print(name, ':', value) |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 116 | preamble = unpack_VbFirmwarePreambleHeader(blob, |
| 117 | kb_header['key_block_size']) |
Yilin Yang | 71e3941 | 2019-09-24 09:26:46 +0800 | [diff] [blame] | 118 | print('-- VbFirmwarePreambleHeader --') |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 119 | for name, value in preamble.items(): |
Yilin Yang | 71e3941 | 2019-09-24 09:26:46 +0800 | [diff] [blame] | 120 | print(name, ':', value) |
| 121 | print('-- END --') |
Hung-Te Lin | c83105f | 2011-03-16 18:38:04 +0800 | [diff] [blame] | 122 | |
| 123 | |
| 124 | # main stub |
Hung-Te Lin | 56b1840 | 2015-01-16 14:52:30 +0800 | [diff] [blame] | 125 | if __name__ == '__main__': |
| 126 | # when running in command line, try to report blob in the parameters |
| 127 | for filename in sys.argv[1:]: |
| 128 | test_report_vblock_info(open(filename, 'rb').read()) |