blob: ff6267ff2b3e263e4fbf4e93e24d93f5fae33394 [file] [log] [blame]
#!/usr/bin/env python
# Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.
# THIS FILE IS COPIED FROM AUTOTEST LIBRARY AND FOLLOWING PEP8 CODING STYLE RULE
# FOR BACKWARD COMPATIBLE, WE'RE NOT CHANGING ITS INDENTATION AND FUNCTION NAMES
"""
Chrome OS firmware verification block parser.
This module helps parsing firmware verification blocks so that we can
retrieve the version and other information from a blob.
See help(unpack_verification_block) for more information.
ref: src/platform/vboot_reference/firmware/lib/include/vboot_struct.h
"""
import struct
import sys
# Constant Definition
KEY_BLOCK_MAGIC = "CHROMEOS"
KEY_BLOCK_MAGIC_SIZE = 8
KEY_BLOCK_HEADER_VERSION_MAJOR = 2
KEY_BLOCK_HEADER_VERSION_MINOR = 1
FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR = 2
FIRMWARE_PREAMBLE_HEADER_VERSION_MINOR = 0
def unpack_VbKeyBlockHeader(blob, offset=0):
"""
Unpacks a VbKeyBlockHeader from a blob, starting from offset.
The blob is supposed to be a VBLOCK_A or VBLOCK_A in firmware image.
Blob structure:
typedef struct VbKeyBlockHeader {
uint8_t magic[KEY_BLOCK_MAGIC_SIZE];
uint32_t header_version_major;
uint32_t header_version_minor;
uint64_t key_block_size;
...
};
"""
fields = struct.unpack_from('<8sIIQ', blob, offset)
names = ('magic', 'header_version_major', 'header_version_minor',
'key_block_size')
header = dict(zip(names, fields))
# check values
if header['magic'] != KEY_BLOCK_MAGIC:
raise ValueError, 'unknown key block magic: %s' % header['magic']
major = header['header_version_major']
minor = header['header_version_minor']
if major != KEY_BLOCK_HEADER_VERSION_MAJOR or \
minor != KEY_BLOCK_HEADER_VERSION_MINOR:
raise ValueError, 'unknown key block version (%d.%d)' % (major, minor)
return header
def unpack_VbFirmwarePreambleHeader(blob, offset=0):
"""
Unpacks a VbFirmwarePreambleHeader from a blob, starting from offset.
The blob is supposed to be located immediately after a VbKeyBlockHeader.
(i.e., offset = VbKeyBlockHeader[key_block_size])
Blob structure:
typedef struct VbFirmwarePreambleHeader {
uint64_t preamble_size;
struct VbSignature preamble_signature {
uint64_t sig_offset;
uint64_t sig_size;
uint64_t data_size;
};
uint32_t header_version_major;
uint32_t header_version_minor;
uint64_t firmware_version;
...
};
"""
fields = struct.unpack_from('<QQQQIIQ', blob, offset)
names = ('preamble_size',
'sig_offset', 'sig_size', 'data_size',
'header_version_major', 'header_version_minor',
'firmware_version')
header = dict(zip(names, fields))
# check values
major = header['header_version_major']
minor = header['header_version_minor']
if major != FIRMWARE_PREAMBLE_HEADER_VERSION_MAJOR or \
minor != FIRMWARE_PREAMBLE_HEADER_VERSION_MINOR:
raise ValueError, 'unknown preamble version: (%d.%d)' % (major, minor)
return header
def unpack_verification_block(blob, offset=0):
"""
Unpacks a Chrome OS verification block.
Returns a dictionary of VbKeyBlockHeader and VbFirmwarePreambleHeader.
Use help(unpack_VbKeyBlockHeader) and help(unpack_VbFirmwarePreambleHeader)
for more detail information.
"""
result = {}
result['VbKeyBlockHeader'] = unpack_VbKeyBlockHeader(blob, offset)
result['VbFirmwarePreambleHeader'] = unpack_VbFirmwarePreambleHeader(
blob, result['VbKeyBlockHeader']['key_block_size'])
return result
# -----------------------------------------------------------------------------
def test_report_vblock_info(blob, offset=0):
""" Reports the information of a vblock blob. """
kb_header = unpack_VbKeyBlockHeader(blob, offset)
print "-- VbKeyBlockHeader --"
for name, value in kb_header.items():
print name, ':', value
preamble = unpack_VbFirmwarePreambleHeader(blob,
kb_header['key_block_size'])
print "-- VbFirmwarePreambleHeader --"
for name, value in preamble.items():
print name, ':', value
print "-- END --"
# main stub
if __name__ == "__main__":
# when running in command line, try to report blob in the parameters
for filename in sys.argv[1:]:
test_report_vblock_info(open(filename, "rb").read())