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 */
29static LoadKernelParams lkp;
30static VbCommonParams cparams;
31static VbNvContext vnc;
32static FILE *image_file = NULL;
33
34
35/* Boot device stub implementations to read from the image file */
36VbError_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
56VbError_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 */
80int 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