| /* 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. |
| * |
| * Routines for verifying a firmware image's signature. |
| */ |
| |
| #include <stdio.h> |
| |
| #include "fmap.h" |
| #include "gbb_header.h" |
| #include "host_misc.h" |
| #include "load_firmware_fw.h" |
| #include "vboot_struct.h" |
| |
| |
| typedef struct _CallerInternal { |
| struct { |
| uint8_t* fw; |
| uint64_t size; |
| } firmware[2]; |
| } CallerInternal; |
| |
| static char* progname = NULL; |
| static char* image_path = NULL; |
| |
| |
| /* wrapper of FmapAreaIndex; print error when not found */ |
| int FmapAreaIndexOrError(const FmapHeader* fh, const FmapAreaHeader* ah, |
| const char* name); |
| /* return NULL on error */ |
| const char* status_string(int status); |
| |
| int GetFirmwareBody(LoadFirmwareParams* params, uint64_t firmware_index) { |
| CallerInternal* ci = (CallerInternal*) params->caller_internal; |
| |
| if (firmware_index != 0 && firmware_index != 1) |
| return 1; |
| |
| UpdateFirmwareBodyHash(params, |
| ci->firmware[firmware_index].fw, |
| ci->firmware[firmware_index].size); |
| |
| return 0; |
| } |
| |
| /* Get GBB |
| * |
| * Return pointer to GBB from firmware image, or NULL if not found. |
| * |
| * [base_of_rom] pointer to firmware image |
| * [fmap] pointer to Flash Map of firmware image |
| * [gbb_size] GBB size will be stored here if GBB is found |
| */ |
| void* GetFirmwareGBB(const void* base_of_rom, const void* fmap, |
| uint64_t* gbb_size) { |
| const FmapHeader* fh = (const FmapHeader*) fmap; |
| const FmapAreaHeader* ah = (const FmapAreaHeader*) |
| (fmap + sizeof(FmapHeader)); |
| int i = FmapAreaIndexOrError(fh, ah, "GBB Area"); |
| |
| if (i < 0) |
| return NULL; |
| |
| *gbb_size = ah[i].area_size; |
| return (void*)(base_of_rom + ah[i].area_offset); |
| } |
| |
| /* Get verification block |
| * |
| * Return zero if succeed, or non-zero if failed |
| * |
| * [base_of_rom] pointer to firmware image |
| * [fmap] pointer to Flash Map of firmware image |
| * [index] index of verification block |
| * [verification_block_ptr] pointer to storing the found verification block |
| * [verification_size_ptr] pointer to store the found verification block size |
| */ |
| int GetVerificationBlock(const void* base_of_rom, const void* fmap, int index, |
| void** verification_block_ptr, uint64_t* verification_size_ptr) { |
| const char* key_area_name[2] = { |
| "Firmware A Key", |
| "Firmware B Key" |
| }; |
| const FmapHeader* fh = (const FmapHeader*) fmap; |
| const FmapAreaHeader* ah = (const FmapAreaHeader*) |
| (fmap + sizeof(FmapHeader)); |
| int i = FmapAreaIndexOrError(fh, ah, key_area_name[index]); |
| const void* kb; |
| const VbKeyBlockHeader* kbh; |
| const VbFirmwarePreambleHeader* fph; |
| |
| if (i < 0) |
| return 1; |
| |
| kb = base_of_rom + ah[i].area_offset; |
| *verification_block_ptr = (void*) kb; |
| |
| kbh = (const VbKeyBlockHeader*) kb; |
| fph = (const VbFirmwarePreambleHeader*) (kb + kbh->key_block_size); |
| |
| *verification_size_ptr = kbh->key_block_size + fph->preamble_size; |
| |
| return 0; |
| } |
| |
| /* Return non-zero if not found */ |
| int GetFirmwareData(const void* base_of_rom, const void* fmap, int index, |
| void *verification_block, uint8_t** body_ptr, uint64_t *size_ptr) { |
| const char* data_area_name[2] = { |
| "Firmware A Data", |
| "Firmware B Data" |
| }; |
| const FmapHeader* fh = (const FmapHeader*) fmap; |
| const FmapAreaHeader* ah = (const FmapAreaHeader*) |
| (fmap + sizeof(FmapHeader)); |
| const VbKeyBlockHeader* kbh = (const VbKeyBlockHeader*) verification_block; |
| const VbFirmwarePreambleHeader* fph = (const VbFirmwarePreambleHeader*) |
| (verification_block + kbh->key_block_size); |
| int i = FmapAreaIndexOrError(fh, ah, data_area_name[index]); |
| |
| if (i < 0) |
| return 1; |
| |
| *body_ptr = (uint8_t*) (base_of_rom + ah[i].area_offset); |
| *size_ptr = (uint64_t) fph->body_signature.data_size; |
| return 0; |
| } |
| |
| /* Verify firmware image [base_of_rom] using [fmap] for looking up areas. |
| * Return zero on success, non-zero on error |
| * |
| * [base_of_rom] pointer to start of firmware image |
| * [fmap] pointer to start of Flash Map of firmware image |
| */ |
| int DriveLoadFirmware(const void* base_of_rom, const void* fmap) { |
| LoadFirmwareParams lfp; |
| CallerInternal ci; |
| |
| const char* status_str; |
| int index, status; |
| |
| void** vblock_ptr[2] = { |
| &lfp.verification_block_0, &lfp.verification_block_1 |
| }; |
| uint64_t* vsize_ptr[2] = { |
| &lfp.verification_size_0, &lfp.verification_size_1 |
| }; |
| |
| /* Initialize LoadFirmwareParams lfp */ |
| |
| lfp.caller_internal = &ci; |
| lfp.gbb_data = GetFirmwareGBB(base_of_rom, fmap, &lfp.gbb_size); |
| if (!lfp.gbb_data) { |
| printf("ERROR: cannot get firmware GBB\n"); |
| return 1; |
| } |
| |
| printf("firmware GBB at 0x%08" PRIx64 "\n", |
| (uint64_t) (lfp.gbb_data - base_of_rom)); |
| |
| /* Loop to initialize firmware key and data A / B */ |
| for (index = 0; index < 2; ++index) { |
| if (GetVerificationBlock(base_of_rom, fmap, index, |
| vblock_ptr[index], vsize_ptr[index])) { |
| printf("ERROR: cannot get key block %d\n", index); |
| return 1; |
| } |
| |
| printf("verification block %d at 0x%08" PRIx64 "\n", index, |
| (uint64_t) (*vblock_ptr[index] - base_of_rom)); |
| printf("verification block %d size is 0x%08" PRIx64 "\n", index, |
| *vsize_ptr[index]); |
| |
| if (GetFirmwareData(base_of_rom, fmap, index, *vblock_ptr[index], |
| &(ci.firmware[index].fw), &(ci.firmware[index].size))) { |
| printf("ERROR: cannot get firmware body %d\n", index); |
| return 1; |
| } |
| |
| printf("firmware %c at 0x%08" PRIx64 "\n", "AB"[index], |
| (uint64_t) ((void*) ci.firmware[index].fw - base_of_rom)); |
| printf("firmware %c size is 0x%08" PRIx64 "\n", "AB"[index], |
| ci.firmware[index].size); |
| } |
| |
| lfp.shared_data_blob = Malloc(VB_SHARED_DATA_MIN_SIZE); |
| lfp.shared_data_size = VB_SHARED_DATA_MIN_SIZE; |
| printf("shared data size 0x%08" PRIx64 "\n", lfp.shared_data_size); |
| |
| lfp.boot_flags = 0; |
| printf("boot flags is 0x%08" PRIx64 "\n", lfp.boot_flags); |
| |
| status = LoadFirmware(&lfp); |
| status_str = status_string(status); |
| if (status_str) |
| printf("LoadFirmware returns %s\n", status_str); |
| else |
| printf("LoadFirmware returns unknown status code: %d\n", status); |
| if (status == LOAD_FIRMWARE_SUCCESS) |
| printf("firmwiare index is %" PRIu64 "\n", lfp.firmware_index); |
| |
| Free(lfp.shared_data_blob); |
| |
| return 0; |
| } |
| |
| /* wrap FmapAreaIndex; print error when not found */ |
| int FmapAreaIndexOrError(const FmapHeader* fh, const FmapAreaHeader* ah, |
| const char* name) { |
| int i = FmapAreaIndex(fh, ah, name); |
| if (i < 0) |
| fprintf(stderr, "%s: can't find %s in firmware image\n", progname, name); |
| return i; |
| } |
| |
| /* Convert status returned by LoadFirmware to string. Return NULL on error. */ |
| const char* status_string(int status) { |
| switch (status) { |
| case LOAD_FIRMWARE_SUCCESS: |
| return "LOAD_FIRMWARE_SUCCESS"; |
| case LOAD_FIRMWARE_RECOVERY: |
| return "LOAD_FIRMWARE_RECOVERY"; |
| case LOAD_FIRMWARE_REBOOT: |
| return "LOAD_FIRMWARE_REBOOT"; |
| default: |
| return NULL; |
| } |
| } |
| |
| int main(int argc, char* argv[]) { |
| int retval = 0; |
| const void* base_of_rom; |
| const void* fmap; |
| uint64_t rom_size; |
| |
| progname = argv[0]; |
| |
| if (argc < 2) { |
| fprintf(stderr, "usage: %s <firmware_image>\n", progname); |
| exit(1); |
| } |
| |
| image_path = argv[1]; |
| |
| base_of_rom = ReadFile(image_path, &rom_size); |
| if (base_of_rom == NULL) { |
| fprintf(stderr, "%s: can not open %s\n", progname, image_path); |
| exit(1); |
| } |
| |
| printf("opened %s\n", image_path); |
| |
| fmap = FmapFind((char*) base_of_rom, rom_size); |
| |
| retval = DriveLoadFirmware(base_of_rom, fmap); |
| |
| Free((void*) base_of_rom); |
| |
| return retval; |
| } |