Home | History | Annotate | Download | only in utility
      1 /* Copyright (c) 2011 The Chromium OS Authors. All rights reserved.
      2  * Use of this source code is governed by a BSD-style license that can be
      3  * found in the LICENSE file.
      4  */
      5 
      6 /* Routines for verifying a file's signature. Useful in testing the core
      7  * RSA verification implementation.
      8  */
      9 
     10 #include <inttypes.h>  /* For PRIu64 macro */
     11 #include <stdio.h>
     12 #include <stdlib.h>
     13 #include <string.h>
     14 #include <sys/types.h>
     15 #include <unistd.h>
     16 
     17 #include "gbb_header.h"
     18 #include "host_common.h"
     19 #include "load_firmware_fw.h"
     20 #include "load_kernel_fw.h"
     21 #include "rollback_index.h"
     22 #include "vboot_common.h"
     23 #include "vboot_kernel.h"
     24 
     25 #define LBA_BYTES 512
     26 #define KERNEL_BUFFER_SIZE 0xA00000
     27 
     28 /* Global variables for stub functions */
     29 static LoadKernelParams lkp;
     30 static VbCommonParams cparams;
     31 static VbNvContext vnc;
     32 static FILE *image_file = NULL;
     33 
     34 
     35 /* Boot device stub implementations to read from the image file */
     36 VbError_t VbExDiskRead(VbExDiskHandle_t handle, uint64_t lba_start,
     37                        uint64_t lba_count, void *buffer) {
     38   printf("Read(%" PRIu64 ", %" PRIu64 ")\n", lba_start, lba_count);
     39 
     40   if (lba_start >= lkp.streaming_lba_count ||
     41       lba_start + lba_count > lkp.streaming_lba_count) {
     42     fprintf(stderr, "Read overrun: %" PRIu64 " + %" PRIu64 " > %" PRIu64 "\n",
     43             lba_start, lba_count, lkp.streaming_lba_count);
     44     return 1;
     45   }
     46 
     47   fseek(image_file, lba_start * lkp.bytes_per_lba, SEEK_SET);
     48   if (1 != fread(buffer, lba_count * lkp.bytes_per_lba, 1, image_file)) {
     49     fprintf(stderr, "Read error.");
     50     return 1;
     51   }
     52   return VBERROR_SUCCESS;
     53 }
     54 
     55 
     56 VbError_t VbExDiskWrite(VbExDiskHandle_t handle, uint64_t lba_start,
     57                         uint64_t lba_count, const void *buffer) {
     58   printf("Write(%" PRIu64 ", %" PRIu64 ")\n", lba_start, lba_count);
     59 
     60   if (lba_start >= lkp.streaming_lba_count ||
     61       lba_start + lba_count > lkp.streaming_lba_count) {
     62     fprintf(stderr, "Read overrun: %" PRIu64 " + %" PRIu64 " > %" PRIu64 "\n",
     63             lba_start, lba_count, lkp.streaming_lba_count);
     64     return 1;
     65   }
     66 
     67   /* TODO: enable writes, once we're sure it won't trash our example file */
     68   return VBERROR_SUCCESS;
     69 
     70   fseek(image_file, lba_start * lkp.bytes_per_lba, SEEK_SET);
     71   if (1 != fwrite(buffer, lba_count * lkp.bytes_per_lba, 1, image_file)) {
     72     fprintf(stderr, "Read error.");
     73     return 1;
     74   }
     75   return VBERROR_SUCCESS;
     76 }
     77 
     78 
     79 /* Main routine */
     80 int main(int argc, char* argv[]) {
     81 
     82   const char* image_name;
     83   uint64_t key_size;
     84   uint8_t* key_blob = NULL;
     85   VbSharedDataHeader* shared;
     86   GoogleBinaryBlockHeader* gbb;
     87   VbError_t rv;
     88   int c, argsleft;
     89   int errorcnt = 0;
     90   char *e = 0;
     91 
     92   Memset(&lkp, 0, sizeof(LoadKernelParams));
     93   lkp.bytes_per_lba = LBA_BYTES;
     94   lkp.boot_flags = BOOT_FLAG_RECOVERY;
     95   Memset(&vnc, 0, sizeof(VbNvContext));
     96   VbNvSetup(&vnc);
     97   lkp.nv_context = &vnc;
     98   Memset(&cparams, 0, sizeof(VbCommonParams));
     99 
    100   /* Parse options */
    101   opterr = 0;
    102   while ((c=getopt(argc, argv, ":b:")) != -1)
    103   {
    104     switch (c)
    105     {
    106     case 'b':
    107       lkp.boot_flags = strtoull(optarg, &e, 0);
    108       if (!*optarg || (e && *e))
    109       {
    110         fprintf(stderr, "Invalid argument to -%c: \"%s\"\n", c, optarg);
    111         errorcnt++;
    112       }
    113       break;
    114     case '?':
    115       fprintf(stderr, "Unrecognized switch: -%c\n", optopt);
    116       errorcnt++;
    117       break;
    118     case ':':
    119       fprintf(stderr, "Missing argument to -%c\n", optopt);
    120       errorcnt++;
    121       break;
    122     default:
    123       errorcnt++;
    124       break;
    125     }
    126   }
    127 
    128   /* Update argc */
    129   argsleft = argc - optind;
    130 
    131   if (errorcnt || !argsleft)
    132   {
    133     fprintf(stderr, "usage: %s [options] <drive_image> [<sign_key>]\n",
    134             argv[0]);
    135     fprintf(stderr, "\noptions:\n");
    136     /* These cases are because uint64_t isn't necessarily the same as ULL. */
    137     fprintf(stderr, "  -b NUM     boot flag bits (default %" PRIu64 "):\n",
    138             (uint64_t)BOOT_FLAG_RECOVERY);
    139     fprintf(stderr, "               %" PRIu64 " = developer mode on\n",
    140             (uint64_t)BOOT_FLAG_DEVELOPER);
    141     fprintf(stderr, "               %" PRIu64 " = recovery mode on\n",
    142             (uint64_t)BOOT_FLAG_RECOVERY);
    143     return 1;
    144   }
    145 
    146   image_name = argv[optind];
    147 
    148   /* Read header signing key blob */
    149   if (argsleft > 1) {
    150     key_blob = ReadFile(argv[optind+1], &key_size);
    151     if (!key_blob) {
    152       fprintf(stderr, "Unable to read key file %s\n", argv[optind+1]);
    153       return 1;
    154     }
    155     printf("Read %" PRIu64 " bytes of key from %s\n", key_size, argv[optind+1]);
    156   }
    157 
    158   /* Initialize the GBB */
    159   lkp.gbb_size = sizeof(GoogleBinaryBlockHeader) + key_size;
    160   lkp.gbb_data = (void*)malloc(lkp.gbb_size);
    161   gbb = (GoogleBinaryBlockHeader*)lkp.gbb_data;
    162   cparams.gbb = gbb;
    163   Memset(gbb, 0, lkp.gbb_size);
    164   Memcpy(gbb->signature, GBB_SIGNATURE, GBB_SIGNATURE_SIZE);
    165   gbb->major_version = GBB_MAJOR_VER;
    166   gbb->minor_version = GBB_MINOR_VER;
    167   gbb->header_size = sizeof(GoogleBinaryBlockHeader);
    168   /* Fill in the given key, if any, for both root and recovery */
    169   if (key_blob) {
    170     gbb->rootkey_offset = gbb->header_size;
    171     gbb->rootkey_size = key_size;
    172     Memcpy((uint8_t*)gbb + gbb->rootkey_offset, key_blob, key_size);
    173 
    174     gbb->recovery_key_offset = gbb->rootkey_offset;
    175     gbb->recovery_key_size = key_size;
    176   }
    177 
    178   /* Initialize the shared data area */
    179   lkp.shared_data_blob = malloc(VB_SHARED_DATA_REC_SIZE);
    180   lkp.shared_data_size = VB_SHARED_DATA_REC_SIZE;
    181   shared = (VbSharedDataHeader*)lkp.shared_data_blob;
    182   if (0 != VbSharedDataInit(shared, lkp.shared_data_size)) {
    183     fprintf(stderr, "Unable to init shared data\n");
    184     return 1;
    185   }
    186   /* Copy in the key blob, if any */
    187   if (key_blob) {
    188     if (0 != VbSharedDataSetKernelKey(shared, (VbPublicKey*)key_blob)) {
    189       fprintf(stderr, "Unable to set key in shared data\n");
    190       return 1;
    191     }
    192   }
    193 
    194   /* Free the key blob, now that we're done with it */
    195   free(key_blob);
    196 
    197   printf("bootflags = %" PRIu64 "\n", lkp.boot_flags);
    198 
    199   /* Get image size */
    200   printf("Reading from image: %s\n", image_name);
    201   image_file = fopen(image_name, "rb");
    202   if (!image_file) {
    203     fprintf(stderr, "Unable to open image file %s\n", image_name);
    204     return 1;
    205   }
    206   fseek(image_file, 0, SEEK_END);
    207   lkp.streaming_lba_count = (ftell(image_file) / LBA_BYTES);
    208   lkp.gpt_lba_count = lkp.streaming_lba_count;
    209   rewind(image_file);
    210   printf("Streaming LBA count: %" PRIu64 "\n", lkp.streaming_lba_count);
    211 
    212   /* Allocate a buffer for the kernel */
    213   lkp.kernel_buffer = malloc(KERNEL_BUFFER_SIZE);
    214   if(!lkp.kernel_buffer) {
    215     fprintf(stderr, "Unable to allocate kernel buffer.\n");
    216     return 1;
    217   }
    218   lkp.kernel_buffer_size = KERNEL_BUFFER_SIZE;
    219 
    220   /* Call LoadKernel() */
    221   rv = LoadKernel(&lkp, &cparams);
    222   printf("LoadKernel() returned %d\n", rv);
    223 
    224   if (VBERROR_SUCCESS == rv) {
    225     printf("Partition number:   %" PRIu64 "\n", lkp.partition_number);
    226     printf("Bootloader address: %" PRIu64 "\n", lkp.bootloader_address);
    227     printf("Bootloader size:    %" PRIu64 "\n", lkp.bootloader_size);
    228     printf("Partition guid:     "
    229            "%02x%02x%02x%02x-%02x%02x-%02x%02x"
    230            "-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
    231            lkp.partition_guid[3],
    232            lkp.partition_guid[2],
    233            lkp.partition_guid[1],
    234            lkp.partition_guid[0],
    235            lkp.partition_guid[5],
    236            lkp.partition_guid[4],
    237            lkp.partition_guid[7],
    238            lkp.partition_guid[6],
    239            lkp.partition_guid[8],
    240            lkp.partition_guid[9],
    241            lkp.partition_guid[10],
    242            lkp.partition_guid[11],
    243            lkp.partition_guid[12],
    244            lkp.partition_guid[13],
    245            lkp.partition_guid[14],
    246            lkp.partition_guid[15]);
    247   }
    248 
    249   fclose(image_file);
    250   free(lkp.kernel_buffer);
    251   return rv != VBERROR_SUCCESS;
    252 }
    253