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