/* * This handles VBLOCK_A and VBLOCK_B while processing a BIOS image. We don't * do any signing here. We just check to see if the existing FMAP area contains * a firmware preamble so we can preserve its contents. We do the signing once * we've looked over all the components. */ static int fmap_sign_fw_preamble(const char *name, uint8_t *buf, uint32_t len, void *data) { VbKeyBlockHeader *key_block = (VbKeyBlockHeader *)buf; struct bios_state_s *state = (struct bios_state_s *)data; /* * If we have a valid keyblock and fw_preamble, then we can use them to * determine the size of the firmware body. Otherwise, we'll have to * just sign the whole region. */ if (VBOOT_SUCCESS != KeyBlockVerify(key_block, len, NULL, 1)) { fprintf(stderr, "Warning: %s keyblock is invalid. " "Signing the entire FW FMAP region...\n", name); goto whatever; } RSAPublicKey *rsa = PublicKeyToRSA(&key_block->data_key); if (!rsa) { fprintf(stderr, "Warning: %s public key is invalid. " "Signing the entire FW FMAP region...\n", name); goto whatever; } uint32_t more = key_block->key_block_size; VbFirmwarePreambleHeader *preamble = (VbFirmwarePreambleHeader *)(buf + more); uint32_t fw_size = preamble->body_signature.data_size; struct bios_area_s *fw_body_area = 0; switch (state->c) { case BIOS_FMAP_VBLOCK_A: fw_body_area = &state->area[BIOS_FMAP_FW_MAIN_A]; /* Preserve the flags if they're not specified */ if (!sign_option.flags_specified) sign_option.flags = preamble->flags; break; case BIOS_FMAP_VBLOCK_B: fw_body_area = &state->area[BIOS_FMAP_FW_MAIN_B]; break; default: DIE; } if (fw_size > fw_body_area->len) { fprintf(stderr, "%s says the firmware is larger than we have\n", name); return 1; } /* Update the firmware size */ fw_body_area->len = fw_size; whatever: state->area[state->c].is_valid = 1; return 0; }
/* Read a key block from a .keyblock file. Caller owns the returned * pointer, and must free it with free(). * * Returns NULL if error. */ VbKeyBlockHeader* KeyBlockRead(const char* filename) { VbKeyBlockHeader* block; uint64_t file_size; block = (VbKeyBlockHeader*)ReadFile(filename, &file_size); if (!block) { VBDEBUG(("Error reading key block file: %s\n", filename)); return NULL; } /* Verify the hash of the key block, since we can do that without * the public signing key. */ if (0 != KeyBlockVerify(block, file_size, NULL, 1)) { VBDEBUG(("Invalid key block file: %s\n", filename)); free(block); return NULL; } return block; }
static int Verify(const char* infile, const char* signpubkey, const char* fv_file, const char* kernelkey_file) { VbKeyBlockHeader* key_block; VbFirmwarePreambleHeader* preamble; VbPublicKey* data_key; VbPublicKey* sign_key; VbPublicKey* kernel_subkey; RSAPublicKey* rsa; uint8_t* blob; uint64_t blob_size; uint8_t* fv_data; uint64_t fv_size; uint64_t now = 0; uint32_t flags; if (!infile || !signpubkey || !fv_file) { VbExError("Must specify filename, signpubkey, and fv\n"); return 1; } /* Read public signing key */ sign_key = PublicKeyRead(signpubkey); if (!sign_key) { VbExError("Error reading signpubkey.\n"); return 1; } /* Read blob */ blob = ReadFile(infile, &blob_size); if (!blob) { VbExError("Error reading input file\n"); return 1; } /* Read firmware volume */ fv_data = ReadFile(fv_file, &fv_size); if (!fv_data) { VbExError("Error reading firmware volume\n"); return 1; } /* Verify key block */ key_block = (VbKeyBlockHeader*)blob; if (0 != KeyBlockVerify(key_block, blob_size, sign_key, 0)) { VbExError("Error verifying key block.\n"); return 1; } free(sign_key); now += key_block->key_block_size; printf("Key block:\n"); data_key = &key_block->data_key; printf(" Size: %" PRIu64 "\n", key_block->key_block_size); printf(" Flags: %" PRIu64 " (ignored)\n", key_block->key_block_flags); printf(" Data key algorithm: %" PRIu64 " %s\n", data_key->algorithm, (data_key->algorithm < kNumAlgorithms ? algo_strings[data_key->algorithm] : "(invalid)")); printf(" Data key version: %" PRIu64 "\n", data_key->key_version); printf(" Data key sha1sum: "); PrintPubKeySha1Sum(data_key); printf("\n"); rsa = PublicKeyToRSA(&key_block->data_key); if (!rsa) { VbExError("Error parsing data key.\n"); return 1; } /* Verify preamble */ preamble = (VbFirmwarePreambleHeader*)(blob + now); if (0 != VerifyFirmwarePreamble(preamble, blob_size - now, rsa)) { VbExError("Error verifying preamble.\n"); return 1; } now += preamble->preamble_size; flags = VbGetFirmwarePreambleFlags(preamble); printf("Preamble:\n"); printf(" Size: %" PRIu64 "\n", preamble->preamble_size); printf(" Header version: %" PRIu32 ".%" PRIu32"\n", preamble->header_version_major, preamble->header_version_minor); printf(" Firmware version: %" PRIu64 "\n", preamble->firmware_version); kernel_subkey = &preamble->kernel_subkey; printf(" Kernel key algorithm: %" PRIu64 " %s\n", kernel_subkey->algorithm, (kernel_subkey->algorithm < kNumAlgorithms ? algo_strings[kernel_subkey->algorithm] : "(invalid)")); printf(" Kernel key version: %" PRIu64 "\n", kernel_subkey->key_version); printf(" Kernel key sha1sum: "); PrintPubKeySha1Sum(kernel_subkey); printf("\n"); printf(" Firmware body size: %" PRIu64 "\n", preamble->body_signature.data_size); printf(" Preamble flags: %" PRIu32 "\n", flags); /* TODO: verify body size same as signature size */ /* Verify body */ if (flags & VB_FIRMWARE_PREAMBLE_USE_RO_NORMAL) { printf("Preamble requests USE_RO_NORMAL; skipping body verification.\n"); } else { if (0 != VerifyData(fv_data, fv_size, &preamble->body_signature, rsa)) { VbExError("Error verifying firmware body.\n"); return 1; } printf("Body verification succeeded.\n"); } if (kernelkey_file) { if (0 != PublicKeyWrite(kernelkey_file, kernel_subkey)) { fprintf(stderr, "vbutil_firmware: unable to write kernel subkey\n"); return 1; } } return 0; }
VbError_t VbVerifyMemoryBootImage(VbCommonParams *cparams, VbSelectAndLoadKernelParams *kparams, void *boot_image, size_t image_size) { VbError_t retval; VbPublicKey* kernel_subkey = NULL; uint8_t *kbuf; VbKeyBlockHeader *key_block; VbSharedDataHeader *shared = (VbSharedDataHeader *)cparams->shared_data_blob; RSAPublicKey *data_key = NULL; VbKernelPreambleHeader *preamble; uint64_t body_offset; int hash_only = 0; int dev_switch; if ((boot_image == NULL) || (image_size == 0)) return VBERROR_INVALID_PARAMETER; /* Clear output params in case we fail. */ kparams->disk_handle = NULL; kparams->partition_number = 0; kparams->bootloader_address = 0; kparams->bootloader_size = 0; kparams->flags = 0; Memset(kparams->partition_guid, 0, sizeof(kparams->partition_guid)); kbuf = boot_image; /* Read GBB Header */ cparams->bmp = NULL; cparams->gbb = VbExMalloc(sizeof(*cparams->gbb)); retval = VbGbbReadHeader_static(cparams, cparams->gbb); if (VBERROR_SUCCESS != retval) { VBDEBUG(("Gbb read header failed.\n")); return retval; } /* * We don't care verifying the image if: * 1. dev-mode switch is on and * 2. GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP is set. * * Check only the integrity of the image. */ dev_switch = shared->flags & VBSD_BOOT_DEV_SWITCH_ON; if (dev_switch && (cparams->gbb->flags & GBB_FLAG_FORCE_DEV_BOOT_FASTBOOT_FULL_CAP)) { VBDEBUG(("Only performing integrity-check.\n")); hash_only = 1; } else { /* Get recovery key. */ retval = VbGbbReadRecoveryKey(cparams, &kernel_subkey); if (VBERROR_SUCCESS != retval) { VBDEBUG(("Gbb Read Recovery key failed.\n")); return retval; } } /* If we fail at any step, retval returned would be invalid kernel. */ retval = VBERROR_INVALID_KERNEL_FOUND; /* Verify the key block. */ key_block = (VbKeyBlockHeader *)kbuf; if (0 != KeyBlockVerify(key_block, image_size, kernel_subkey, hash_only)) { VBDEBUG(("Verifying key block signature/hash failed.\n")); goto fail; } /* Check the key block flags against the current boot mode. */ if (!(key_block->key_block_flags & (dev_switch ? KEY_BLOCK_FLAG_DEVELOPER_1 : KEY_BLOCK_FLAG_DEVELOPER_0))) { VBDEBUG(("Key block developer flag mismatch.\n")); if (hash_only == 0) goto fail; } if (!(key_block->key_block_flags & KEY_BLOCK_FLAG_RECOVERY_1)) { VBDEBUG(("Key block recovery flag mismatch.\n")); if (hash_only == 0) goto fail; } /* Get key for preamble/data verification from the key block. */ data_key = PublicKeyToRSA(&key_block->data_key); if (!data_key) { VBDEBUG(("Data key bad.\n")); goto fail; } /* Verify the preamble, which follows the key block */ preamble = (VbKernelPreambleHeader *)(kbuf + key_block->key_block_size); if ((0 != VerifyKernelPreamble(preamble, image_size - key_block->key_block_size, data_key))) { VBDEBUG(("Preamble verification failed.\n")); goto fail; } VBDEBUG(("Kernel preamble is good.\n")); /* Verify kernel data */ body_offset = key_block->key_block_size + preamble->preamble_size; if (0 != VerifyData((const uint8_t *)(kbuf + body_offset), image_size - body_offset, &preamble->body_signature, data_key)) { VBDEBUG(("Kernel data verification failed.\n")); goto fail; } VBDEBUG(("Kernel is good.\n")); /* Fill in output parameters. */ kparams->kernel_buffer = kbuf + body_offset; kparams->kernel_buffer_size = image_size - body_offset; kparams->bootloader_address = preamble->bootloader_address; kparams->bootloader_size = preamble->bootloader_size; if (VbKernelHasFlags(preamble) == VBOOT_SUCCESS) kparams->flags = preamble->flags; retval = VBERROR_SUCCESS; fail: VbApiKernelFree(cparams); if (NULL != data_key) RSAPublicKeyFree(data_key); if (NULL != kernel_subkey) VbExFree(kernel_subkey); return retval; }