VbError_t nvstorage_write_disk(const uint8_t *buf) { VbDiskInfo *internal_disk; uint8_t *block_buf; if (get_internal_disk(&internal_disk)) return 1; if (get_nvcxt_block_of_disk(internal_disk, &block_buf)) return 1; memcpy(block_buf, buf, VBNV_BLOCK_SIZE); if (VbExDiskWrite(internal_disk->handle, CHROMEOS_VBNVCONTEXT_LBA, 1, block_buf)) { VBDEBUG("Failed to write internal disk!\n"); VbExFree(block_buf); return 1; } VbExFree(block_buf); #ifdef CONFIG_EXYNOS5 /* * XXX(chrome-os-partner:10415): On Exynos, reliable write operations * need write busy time; so add a delay here. In the long run, we * should avoid using eMMC as VbNvContext storage media. */ mdelay(1); #endif return VBERROR_SUCCESS; }
static int do_vbexport_test_malloc_size(uint32_t size) { char *mem = VbExMalloc(size); int i, line_size; #if CONFIG_ARM line_size = dcache_get_line_size(); #elif defined CACHE_LINE_SIZE line_size = CACHE_LINE_SIZE; #else line_size = __BIGGEST_ALIGNMENT__; #endif VbExDebug("Trying to malloc a memory block for %lu bytes...", size); if ((uintptr_t)mem % line_size != 0) { VbExDebug("\nMemory not algined with a cache line!\n"); VbExFree(mem); return 1; } for (i = 0; i < size; i++) { mem[i] = i % 0x100; } for (i = 0; i < size; i++) { if (mem[i] != i % 0x100) { VbExDebug("\nMemory verification failed!\n"); VbExFree(mem); return 1; } } VbExFree(mem); VbExDebug(" - SUCCESS\n"); return 0; }
/* This function is also used by tests */ void VbApiKernelFree(VbCommonParams *cparams) { /* VbSelectAndLoadKernel() always allocates this, tests don't */ if (cparams->gbb) { VbExFree(cparams->gbb); cparams->gbb = NULL; } if (cparams->bmp) { VbExFree(cparams->bmp); cparams->bmp = NULL; } }
/** * Show an image on the screen at the given location */ static int show_image(ImageInfo *image, int x, int y) { uint32_t inoutsize; void *rawimg; int err; inoutsize = image->original_size; if (COMPRESS_NONE == image->compression) { rawimg = NULL; } else { rawimg = VbExMalloc(inoutsize); if (VbExDecompress(image + 1, image->compressed_size, image->compression, rawimg, &inoutsize)) { return -1; } } err = VbExDisplayImage(x, y, rawimg ? rawimg : image + 1, inoutsize); if (rawimg) VbExFree(rawimg); return err ? -1 : 0; }
static void VerifyDigestTest(const VbPublicKey *public_key, const VbPrivateKey *private_key) { const uint8_t test_data[] = "This is some other test data to sign."; VbSignature *sig; RSAPublicKey *rsa; uint8_t *digest; sig = CalculateSignature(test_data, sizeof(test_data), private_key); rsa = PublicKeyToRSA(public_key); digest = DigestBuf(test_data, sizeof(test_data), (int)public_key->algorithm); TEST_NEQ(sig && rsa && digest, 0, "VerifyData() prerequisites"); if (!sig || !rsa || !digest) return; TEST_EQ(VerifyDigest(digest, sig, rsa), 0, "VerifyDigest() ok"); GetSignatureData(sig)[0] ^= 0x5A; TEST_EQ(VerifyDigest(digest, sig, rsa), 1, "VerifyDigest() wrong sig"); sig->sig_size = 1; TEST_EQ(VerifyDigest(digest, sig, rsa), 1, "VerifyDigest() sig size"); RSAPublicKeyFree(rsa); free(sig); VbExFree(digest); }
void VbExStreamClose(VbExStream_t stream) { struct disk_stream *s = (struct disk_stream *)stream; /* Allow freeing a null pointer */ if (!s) return; VbExFree(s); return; }
static void FillInSha1Sum(char *outbuf, VbPublicKey *key) { uint8_t *buf = ((uint8_t *)key) + key->key_offset; uint64_t buflen = key->key_size; uint8_t *digest = DigestBuf(buf, buflen, SHA1_DIGEST_ALGORITHM); int i; for (i = 0; i < SHA1_DIGEST_SIZE; i++) { Uint8ToString(outbuf, digest[i]); outbuf += 2; } *outbuf = '\0'; VbExFree(digest); }
VbError_t nvstorage_read_disk(uint8_t *buf) { VbDiskInfo *internal_disk; uint8_t *block_buf; if (get_internal_disk(&internal_disk)) return 1; if (get_nvcxt_block_of_disk(internal_disk, &block_buf)) return 1; memcpy(buf, block_buf, VBNV_BLOCK_SIZE); VbExFree(block_buf); return VBERROR_SUCCESS; }
/* * Allocates 1-block-sized memory to block_buf_ptr and fills it as the first * block of the disk. * Returns 0 for success, non-zero for failure. */ static int get_nvcxt_block_of_disk(const VbDiskInfo *disk, uint8_t **block_buf_ptr) { uint8_t *block_buf = NULL; block_buf = VbExMalloc(disk->bytes_per_lba); if (VbExDiskRead(disk->handle, CHROMEOS_VBNVCONTEXT_LBA, 1, block_buf)) { VBDEBUG("Failed to read internal disk!\n"); VbExFree(block_buf); return 1; } *block_buf_ptr = block_buf; return 0; }
/** * Write any changes for the GPT data back to the drive, then free the buffers. * * Returns 0 if successful, 1 if error. */ int WriteAndFreeGptData(VbExDiskHandle_t disk_handle, GptData *gptdata) { int legacy = 0; GptHeader *header = (GptHeader *)gptdata->primary_header; uint64_t entries_bytes = header->number_of_entries * header->size_of_entry; uint64_t entries_sectors = entries_bytes / gptdata->sector_bytes; int ret = 1; /* * TODO(namnguyen): Preserve padding between primary GPT header and * its entries. */ uint64_t entries_lba = GPT_PMBR_SECTORS + GPT_HEADER_SECTORS; if (gptdata->primary_header) { GptHeader *h = (GptHeader *)(gptdata->primary_header); entries_lba = h->entries_lba; /* * Avoid even looking at this data if we don't need to. We * may in fact not have read it from disk if the read failed, * and this avoids a valgrind complaint. */ if (gptdata->modified) { legacy = !Memcmp(h->signature, GPT_HEADER_SIGNATURE2, GPT_HEADER_SIGNATURE_SIZE); } if (gptdata->modified & GPT_MODIFIED_HEADER1) { if (legacy) { VBDEBUG(("Not updating GPT header 1: " "legacy mode is enabled.\n")); } else { VBDEBUG(("Updating GPT header 1\n")); if (0 != VbExDiskWrite(disk_handle, 1, 1, gptdata->primary_header)) goto fail; } } } if (gptdata->primary_entries) { if (gptdata->modified & GPT_MODIFIED_ENTRIES1) { if (legacy) { VBDEBUG(("Not updating GPT entries 1: " "legacy mode is enabled.\n")); } else { VBDEBUG(("Updating GPT entries 1\n")); if (0 != VbExDiskWrite(disk_handle, entries_lba, entries_sectors, gptdata->primary_entries)) goto fail; } } } entries_lba = (gptdata->gpt_drive_sectors - entries_sectors - GPT_HEADER_SECTORS); if (gptdata->secondary_header) { GptHeader *h = (GptHeader *)(gptdata->secondary_header); entries_lba = h->entries_lba; if (gptdata->modified & GPT_MODIFIED_HEADER2) { VBDEBUG(("Updating GPT entries 2\n")); if (0 != VbExDiskWrite(disk_handle, gptdata->gpt_drive_sectors - 1, 1, gptdata->secondary_header)) goto fail; } } if (gptdata->secondary_entries) { if (gptdata->modified & GPT_MODIFIED_ENTRIES2) { VBDEBUG(("Updating GPT header 2\n")); if (0 != VbExDiskWrite(disk_handle, entries_lba, entries_sectors, gptdata->secondary_entries)) goto fail; } } ret = 0; fail: /* Avoid leaking memory on disk write failure */ if (gptdata->primary_header) VbExFree(gptdata->primary_header); if (gptdata->primary_entries) VbExFree(gptdata->primary_entries); if (gptdata->secondary_entries) VbExFree(gptdata->secondary_entries); if (gptdata->secondary_header) VbExFree(gptdata->secondary_header); /* Success */ return ret; }
/** * Caller should call this prior to booting. */ void VbAudioClose(VbAudioContext *audio) { VbExBeep(0,0); if (audio->free_notes_when_done) VbExFree(audio->music_notes); }
VbError_t VbDisplayDebugInfo(VbCommonParams *cparams, VbNvContext *vncptr) { VbSharedDataHeader *shared = (VbSharedDataHeader *)cparams->shared_data_blob; GoogleBinaryBlockHeader *gbb = cparams->gbb; char buf[DEBUG_INFO_SIZE] = ""; char sha1sum[SHA1_DIGEST_SIZE * 2 + 1]; char hwid[256]; uint32_t used = 0; VbPublicKey *key; VbError_t ret; uint32_t i; /* Redisplay current screen to overwrite any previous debug output */ VbDisplayScreen(cparams, disp_current_screen, 1, vncptr); /* Add hardware ID */ VbRegionReadHWID(cparams, hwid, sizeof(hwid)); used += StrnAppend(buf + used, "HWID: ", DEBUG_INFO_SIZE - used); used += StrnAppend(buf + used, hwid, DEBUG_INFO_SIZE - used); /* Add recovery reason */ used += StrnAppend(buf + used, "\nrecovery_reason: 0x", DEBUG_INFO_SIZE - used); used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, shared->recovery_reason, 16, 2); used += StrnAppend(buf + used, " ", DEBUG_INFO_SIZE - used); used += StrnAppend(buf + used, RecoveryReasonString(shared->recovery_reason), DEBUG_INFO_SIZE - used); /* Add VbSharedData flags */ used += StrnAppend(buf + used, "\nVbSD.flags: 0x", DEBUG_INFO_SIZE - used); used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, shared->flags, 16, 8); /* Add raw contents of VbNvStorage */ used += StrnAppend(buf + used, "\nVbNv.raw:", DEBUG_INFO_SIZE - used); for (i = 0; i < VBNV_BLOCK_SIZE; i++) { used += StrnAppend(buf + used, " ", DEBUG_INFO_SIZE - used); used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, vncptr->raw[i], 16, 2); } /* Add dev_boot_usb flag */ VbNvGet(vncptr, VBNV_DEV_BOOT_USB, &i); used += StrnAppend(buf + used, "\ndev_boot_usb: ", DEBUG_INFO_SIZE - used); used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0); /* Add dev_boot_legacy flag */ VbNvGet(vncptr, VBNV_DEV_BOOT_LEGACY, &i); used += StrnAppend(buf + used, "\ndev_boot_legacy: ", DEBUG_INFO_SIZE - used); used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0); /* Add dev_boot_signed_only flag */ VbNvGet(vncptr, VBNV_DEV_BOOT_SIGNED_ONLY, &i); used += StrnAppend(buf + used, "\ndev_boot_signed_only: ", DEBUG_INFO_SIZE - used); used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, i, 10, 0); /* Add TPM versions */ used += StrnAppend(buf + used, "\nTPM: fwver=0x", DEBUG_INFO_SIZE - used); used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, shared->fw_version_tpm, 16, 8); used += StrnAppend(buf + used, " kernver=0x", DEBUG_INFO_SIZE - used); used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, shared->kernel_version_tpm, 16, 8); /* Add GBB flags */ used += StrnAppend(buf + used, "\ngbb.flags: 0x", DEBUG_INFO_SIZE - used); if (gbb->major_version == GBB_MAJOR_VER && gbb->minor_version >= 1) { used += Uint64ToString(buf + used, DEBUG_INFO_SIZE - used, gbb->flags, 16, 8); } else { used += StrnAppend(buf + used, "0 (default)", DEBUG_INFO_SIZE - used); } /* Add sha1sum for Root & Recovery keys */ ret = VbGbbReadRootKey(cparams, &key); if (!ret) { FillInSha1Sum(sha1sum, key); VbExFree(key); used += StrnAppend(buf + used, "\ngbb.rootkey: ", DEBUG_INFO_SIZE - used); used += StrnAppend(buf + used, sha1sum, DEBUG_INFO_SIZE - used); } ret = VbGbbReadRecoveryKey(cparams, &key); if (!ret) { FillInSha1Sum(sha1sum, key); VbExFree(key); used += StrnAppend(buf + used, "\ngbb.recovery_key: ", DEBUG_INFO_SIZE - used); used += StrnAppend(buf + used, sha1sum, DEBUG_INFO_SIZE - used); } /* If we're in dev-mode, show the kernel subkey that we expect, too. */ if (0 == shared->recovery_reason) { FillInSha1Sum(sha1sum, &shared->kernel_subkey); used += StrnAppend(buf + used, "\nkernel_subkey: ", DEBUG_INFO_SIZE - used); used += StrnAppend(buf + used, sha1sum, DEBUG_INFO_SIZE - used); } /* Make sure we finish with a newline */ used += StrnAppend(buf + used, "\n", DEBUG_INFO_SIZE - used); /* TODO: add more interesting data: * - Information on current disks */ buf[DEBUG_INFO_SIZE - 1] = '\0'; return VbExDisplayDebugInfo(buf); }
VbError_t VbDisplayScreenFromGBB(VbCommonParams *cparams, uint32_t screen, VbNvContext *vncptr) { char *fullimage = NULL; BmpBlockHeader hdr; uint32_t screen_index; uint32_t localization = 0; VbError_t retval = VBERROR_UNKNOWN; /* Assume error until proven ok */ uint32_t inoutsize; uint32_t i; VbFont_t *font; const char *text_to_show; int rtol = 0; VbError_t ret; ret = VbGbbReadBmpHeader(cparams, &hdr); if (ret) return ret; /* * Translate screen ID into index. Note that not all screens are in * the GBB. * * TODO: ensure screen IDs match indices? Having this translation here * is awful. */ switch (screen) { case VB_SCREEN_DEVELOPER_WARNING: screen_index = SCREEN_DEVELOPER_WARNING; break; case VB_SCREEN_RECOVERY_REMOVE: screen_index = SCREEN_RECOVERY_REMOVE; break; case VB_SCREEN_RECOVERY_NO_GOOD: screen_index = SCREEN_RECOVERY_NO_GOOD; break; case VB_SCREEN_RECOVERY_INSERT: screen_index = SCREEN_RECOVERY_INSERT; break; case VB_SCREEN_RECOVERY_TO_DEV: screen_index = SCREEN_RECOVERY_TO_DEV; break; case VB_SCREEN_DEVELOPER_TO_NORM: screen_index = SCREEN_DEVELOPER_TO_NORM; break; case VB_SCREEN_WAIT: screen_index = SCREEN_WAIT; break; case VB_SCREEN_TO_NORM_CONFIRMED: screen_index = SCREEN_TO_NORM_CONFIRMED; break; case VB_SCREEN_BLANK: case VB_SCREEN_DEVELOPER_EGG: default: /* Screens which aren't in the GBB */ VBDEBUG(("VbDisplayScreenFromGBB(): screen %d not in the GBB\n", (int)screen)); retval = VBERROR_INVALID_SCREEN_INDEX; goto VbDisplayScreenFromGBB_exit; } if (screen_index >= hdr.number_of_screenlayouts) { VBDEBUG(("VbDisplayScreenFromGBB(): " "screen %d index %d not in the GBB\n", (int)screen, (int)screen_index)); retval = VBERROR_INVALID_SCREEN_INDEX; goto VbDisplayScreenFromGBB_exit; } /* Clip localization to number of localizations present in the GBB */ VbNvGet(vncptr, VBNV_LOCALIZATION_INDEX, &localization); if (localization >= hdr.number_of_localizations) { localization = 0; VbNvSet(vncptr, VBNV_LOCALIZATION_INDEX, localization); } /* Display all bitmaps for the image */ for (i = 0; i < MAX_IMAGE_IN_LAYOUT; i++) { ScreenLayout layout; ImageInfo image_info; char hwid[256]; ret = VbGbbReadImage(cparams, localization, screen_index, i, &layout, &image_info, &fullimage, &inoutsize); if (ret == VBERROR_NO_IMAGE_PRESENT) { continue; } else if (ret) { retval = ret; goto VbDisplayScreenFromGBB_exit; } switch(image_info.format) { case FORMAT_BMP: if (i == 0) { /** * In current version GBB bitmaps, first image * is always the background. */ ret = VbExDisplaySetDimension( image_info.width, image_info.height); if (ret) { VBDEBUG(("VbExDisplaySetDimension" "(%d,%d): failed (%#x).\n", image_info.width, image_info.height, ret)); } } retval = VbExDisplayImage(layout.images[i].x, layout.images[i].y, fullimage, inoutsize); break; case FORMAT_FONT: /* * The uncompressed blob is our font structure. Cache * it as needed. */ font = VbInternalizeFontData( (FontArrayHeader *)fullimage); /* TODO: handle text in general here */ if (TAG_HWID == image_info.tag || TAG_HWID_RTOL == image_info.tag) { VbRegionReadHWID(cparams, hwid, sizeof(hwid)); text_to_show = hwid; rtol = (TAG_HWID_RTOL == image_info.tag); } else { text_to_show = ""; rtol = 0; } VbRenderTextAtPos(text_to_show, rtol, layout.images[i].x, layout.images[i].y, font); VbDoneWithFontForNow(font); break; default: VBDEBUG(("VbDisplayScreenFromGBB(): " "unsupported ImageFormat %d\n", image_info.format)); retval = VBERROR_INVALID_GBB; } VbExFree(fullimage); if (VBERROR_SUCCESS != retval) goto VbDisplayScreenFromGBB_exit; } /* Successful if all bitmaps displayed */ retval = VBERROR_SUCCESS; VbRegionCheckVersion(cparams); VbDisplayScreenFromGBB_exit: VBDEBUG(("leaving VbDisplayScreenFromGBB() with %d\n",retval)); return retval; }
static int do_vbexport_test_diskrw(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[]) { int ret = 0; VbDiskInfo *disk_info; VbExDiskHandle_t handle; uint32_t disk_count, test_lba_count, buf_byte_count, i; uint8_t *original_buf, *target_buf, *verify_buf; uint64_t t0, t1; switch (argc) { case 1: /* if no argument given, use the default lba count */ test_lba_count = DEFAULT_TEST_LBA_COUNT; break; case 2: /* use argument */ test_lba_count = simple_strtoul(argv[1], NULL, 10); if (!test_lba_count) { VbExDebug("The first argument is not a number!\n"); return cmd_usage(cmdtp); } break; default: return cmd_usage(cmdtp); } /* We perform read/write operations on the first internal disk. */ if (VbExDiskGetInfo(&disk_info, &disk_count, VB_DISK_FLAG_FIXED) || disk_count == 0) { VbExDebug("No internal disk found!\n"); return 1; } handle = disk_info[0].handle; buf_byte_count = disk_info[0].bytes_per_lba * test_lba_count; VbExDiskFreeInfo(disk_info, handle); /* Allocate the buffer and fill the target test pattern. */ original_buf = VbExMalloc(buf_byte_count); target_buf = VbExMalloc(buf_byte_count); verify_buf = VbExMalloc(buf_byte_count); /* Fill the target test pattern. */ for (i = 0; i < buf_byte_count; i++) target_buf[i] = i & 0xff; t0 = VbExGetTimer(); if (VbExDiskRead(handle, TEST_LBA_START, test_lba_count, original_buf)) { VbExDebug("Failed to read disk.\n"); goto out; } t1 = VbExGetTimer(); VbExDebug("test_diskrw: disk_read, lba_count: %u, time: %llu\n", test_lba_count, t1 - t0); t0 = VbExGetTimer(); ret = VbExDiskWrite(handle, TEST_LBA_START, test_lba_count, target_buf); t1 = VbExGetTimer(); VbExDebug("test_diskrw: disk_write, lba_count: %u, time: %llu\n", test_lba_count, t1 - t0); if (ret) { VbExDebug("Failed to write disk.\n"); ret = 1; } else { /* Read back and verify the data. */ VbExDiskRead(handle, TEST_LBA_START, test_lba_count, verify_buf); if (memcmp(target_buf, verify_buf, buf_byte_count) != 0) { VbExDebug("Verify failed. The target data wrote " "wrong.\n"); ret = 1; } } /* Write the original data back. */ if (VbExDiskWrite(handle, TEST_LBA_START, test_lba_count, original_buf)) { VbExDebug("Failed to write the original data back. The disk " "may now be corrupt.\n"); } out: VbExDiskFreeInfo(disk_info, NULL); VbExFree(original_buf); VbExFree(target_buf); VbExFree(verify_buf); if (ret == 0) VbExDebug("Read and write disk test SUCCESS.\n"); return ret; }
int KeyBlockVerify(const VbKeyBlockHeader *block, uint64_t size, const VbPublicKey *key, int hash_only) { const VbSignature *sig; /* Sanity checks before attempting signature of data */ if(size < sizeof(VbKeyBlockHeader)) { VBDEBUG(("Not enough space for key block header.\n")); return VBOOT_KEY_BLOCK_INVALID; } if (SafeMemcmp(block->magic, KEY_BLOCK_MAGIC, KEY_BLOCK_MAGIC_SIZE)) { VBDEBUG(("Not a valid verified boot key block.\n")); return VBOOT_KEY_BLOCK_INVALID; } if (block->header_version_major != KEY_BLOCK_HEADER_VERSION_MAJOR) { VBDEBUG(("Incompatible key block header version.\n")); return VBOOT_KEY_BLOCK_INVALID; } if (size < block->key_block_size) { VBDEBUG(("Not enough data for key block.\n")); return VBOOT_KEY_BLOCK_INVALID; } if (!hash_only && !key) { VBDEBUG(("Missing required public key.\n")); return VBOOT_PUBLIC_KEY_INVALID; } /* * Check signature or hash, depending on the hash_only parameter. Note * that we don't require a key even if the keyblock has a signature, * because the caller may not care if the keyblock itself is signed * (for example, booting a Google-signed kernel in developer mode). */ if (hash_only) { /* Check hash */ uint8_t *header_checksum = NULL; int rv; sig = &block->key_block_checksum; if (VerifySignatureInside(block, block->key_block_size, sig)) { VBDEBUG(("Key block hash off end of block\n")); return VBOOT_KEY_BLOCK_INVALID; } if (sig->sig_size != SHA512_DIGEST_SIZE) { VBDEBUG(("Wrong hash size for key block.\n")); return VBOOT_KEY_BLOCK_INVALID; } /* Make sure advertised signature data sizes are sane. */ if (block->key_block_size < sig->data_size) { VBDEBUG(("Signature calculated past end of block\n")); return VBOOT_KEY_BLOCK_INVALID; } VBDEBUG(("Checking key block hash only...\n")); header_checksum = DigestBuf((const uint8_t *)block, sig->data_size, SHA512_DIGEST_ALGORITHM); rv = SafeMemcmp(header_checksum, GetSignatureDataC(sig), SHA512_DIGEST_SIZE); VbExFree(header_checksum); if (rv) { VBDEBUG(("Invalid key block hash.\n")); return VBOOT_KEY_BLOCK_HASH; } } else { /* Check signature */ RSAPublicKey *rsa; int rv; sig = &block->key_block_signature; if (VerifySignatureInside(block, block->key_block_size, sig)) { VBDEBUG(("Key block signature off end of block\n")); return VBOOT_KEY_BLOCK_INVALID; } rsa = PublicKeyToRSA(key); if (!rsa) { VBDEBUG(("Invalid public key\n")); return VBOOT_PUBLIC_KEY_INVALID; } /* Make sure advertised signature data sizes are sane. */ if (block->key_block_size < sig->data_size) { VBDEBUG(("Signature calculated past end of block\n")); RSAPublicKeyFree(rsa); return VBOOT_KEY_BLOCK_INVALID; } VBDEBUG(("Checking key block signature...\n")); rv = VerifyData((const uint8_t *)block, size, sig, rsa); RSAPublicKeyFree(rsa); if (rv) { VBDEBUG(("Invalid key block signature.\n")); return VBOOT_KEY_BLOCK_SIGNATURE; } } /* Verify we signed enough data */ if (sig->data_size < sizeof(VbKeyBlockHeader)) { VBDEBUG(("Didn't sign enough data\n")); return VBOOT_KEY_BLOCK_INVALID; } /* Verify data key is inside the block and inside signed data */ if (VerifyPublicKeyInside(block, block->key_block_size, &block->data_key)) { VBDEBUG(("Data key off end of key block\n")); return VBOOT_KEY_BLOCK_INVALID; } if (VerifyPublicKeyInside(block, sig->data_size, &block->data_key)) { VBDEBUG(("Data key off end of signed data\n")); return VBOOT_KEY_BLOCK_INVALID; } /* Success */ return VBOOT_SUCCESS; }
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; }