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 */
VbExDiskRead(VbExDiskHandle_t handle,uint64_t lba_start,uint64_t lba_count,void * buffer)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 
VbExDiskWrite(VbExDiskHandle_t handle,uint64_t lba_start,uint64_t lba_count,const void * buffer)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 */
main(int argc,char * argv[])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