1 /* Copyright 2011 The ChromiumOS Authors
2 * Use of this source code is governed by a BSD-style license that can be
3 * found in the LICENSE file.
4 *
5 * Routines for verifying a file's signature. Useful in testing the core
6 * RSA verification implementation.
7 */
8
9 #include <stdio.h>
10 #include <sys/types.h>
11 #include <unistd.h>
12
13 #include "2api.h"
14 #include "2common.h"
15 #include "2misc.h"
16 #include "2sysincludes.h"
17 #include "host_common.h"
18
19 #define LBA_BYTES 512
20 #define KERNEL_BUFFER_SIZE 0xA00000
21
22 static uint8_t workbuf[VB2_KERNEL_WORKBUF_RECOMMENDED_SIZE];
23 static struct vb2_context *ctx;
24 static struct vb2_shared_data *sd;
25
26 /* Global variables for stub functions */
27 static struct vb2_kernel_params lkp;
28 static struct vb2_disk_info disk_info;
29 static FILE *image_file = NULL;
30
31
32 /* Boot device stub implementations to read from the image file */
VbExDiskRead(vb2ex_disk_handle_t handle,uint64_t lba_start,uint64_t lba_count,void * buffer)33 vb2_error_t VbExDiskRead(vb2ex_disk_handle_t handle, uint64_t lba_start,
34 uint64_t lba_count, void *buffer)
35 {
36 printf("Read(%" PRIu64 ", %" PRIu64 ")\n", lba_start, lba_count);
37
38 if (lba_start >= disk_info.streaming_lba_count ||
39 lba_start + lba_count > disk_info.streaming_lba_count) {
40 fprintf(stderr,
41 "Read overrun: %" PRIu64 " + %" PRIu64
42 " > %" PRIu64 "\n", lba_start,
43 lba_count, disk_info.streaming_lba_count);
44 return 1;
45 }
46
47 if (0 != fseek(image_file, lba_start * disk_info.bytes_per_lba,
48 SEEK_SET) ||
49 1 != fread(buffer, lba_count * disk_info.bytes_per_lba, 1,
50 image_file)) {
51 fprintf(stderr, "Read error.");
52 return 1;
53 }
54 return VB2_SUCCESS;
55 }
56
57
VbExDiskWrite(vb2ex_disk_handle_t handle,uint64_t lba_start,uint64_t lba_count,const void * buffer)58 vb2_error_t VbExDiskWrite(vb2ex_disk_handle_t handle, uint64_t lba_start,
59 uint64_t lba_count, const void *buffer)
60 {
61 printf("Write(%" PRIu64 ", %" PRIu64 ")\n", lba_start, lba_count);
62
63 if (lba_start >= disk_info.streaming_lba_count ||
64 lba_start + lba_count > disk_info.streaming_lba_count) {
65 fprintf(stderr,
66 "Read overrun: %" PRIu64 " + %" PRIu64
67 " > %" PRIu64 "\n", lba_start, lba_count,
68 disk_info.streaming_lba_count);
69 return 1;
70 }
71
72 /* TODO: enable writes, once we're sure it won't trash
73 our example file */
74 return VB2_SUCCESS;
75
76 fseek(image_file, lba_start * disk_info.bytes_per_lba, SEEK_SET);
77 if (1 != fwrite(buffer, lba_count * disk_info.bytes_per_lba, 1,
78 image_file)) {
79 fprintf(stderr, "Read error.");
80 return 1;
81 }
82 return VB2_SUCCESS;
83 }
84
85
86 #define BOOT_FLAG_DEVELOPER (1 << 0)
87 #define BOOT_FLAG_RECOVERY (1 << 1)
88
89 /* Main routine */
main(int argc,char * argv[])90 int main(int argc, char* argv[])
91 {
92 const char* image_name;
93 uint64_t key_size = 0;
94 struct vb2_packed_key *key_blob = NULL;
95 struct vb2_gbb_header* gbb;
96 vb2_error_t rv;
97 int c, argsleft;
98 int errorcnt = 0;
99 char *e = 0;
100
101 memset(&lkp, 0, sizeof(lkp));
102 disk_info.bytes_per_lba = LBA_BYTES;
103 int boot_flags = BOOT_FLAG_RECOVERY;
104
105 /* Parse options */
106 opterr = 0;
107 while ((c = getopt(argc, argv, ":b:")) != -1) {
108 switch (c) {
109 case 'b':
110 boot_flags = strtoull(optarg, &e, 0);
111 if (!*optarg || (e && *e)) {
112 fprintf(stderr,
113 "Invalid argument to -%c: \"%s\"\n",
114 c, optarg);
115 errorcnt++;
116 }
117 break;
118 case '?':
119 fprintf(stderr, "Unrecognized switch: -%c\n", optopt);
120 errorcnt++;
121 break;
122 case ':':
123 fprintf(stderr, "Missing argument to -%c\n", optopt);
124 errorcnt++;
125 break;
126 default:
127 errorcnt++;
128 break;
129 }
130 }
131
132 /* Update argc */
133 argsleft = argc - optind;
134
135 if (errorcnt || !argsleft) {
136 fprintf(stderr,
137 "usage: %s [options] <drive_image> [<sign_key>]\n",
138 argv[0]);
139 fprintf(stderr, "\noptions:\n");
140 /* These cases are because uint64_t isn't necessarily the same
141 as ULL. */
142 fprintf(stderr, " -b NUM boot flag bits (default %d):\n",
143 BOOT_FLAG_RECOVERY);
144 fprintf(stderr, " %d = developer mode on\n",
145 BOOT_FLAG_DEVELOPER);
146 fprintf(stderr, " %d = recovery mode on\n",
147 BOOT_FLAG_RECOVERY);
148 return 1;
149 }
150
151 image_name = argv[optind];
152
153 /* Read header signing key blob */
154 if (argsleft > 1) {
155 key_blob = (struct vb2_packed_key *)
156 ReadFile(argv[optind+1], &key_size);
157 if (!key_blob) {
158 fprintf(stderr, "Unable to read key file %s\n",
159 argv[optind+1]);
160 return 1;
161 }
162 printf("Read %" PRIu64 " bytes of key from %s\n", key_size,
163 argv[optind+1]);
164 if (key_size > 16*1024*1024) {
165 fprintf(stderr, "Key blob size=%" PRIu64
166 " is ridiculous.\n", key_size);
167 free(key_blob);
168 return 1;
169 }
170 }
171
172 /* Initialize the GBB */
173 uint32_t gbb_size = sizeof(struct vb2_gbb_header) + key_size;
174 gbb = (struct vb2_gbb_header*)malloc(gbb_size);
175 memset(gbb, 0, gbb_size);
176 memcpy(gbb->signature, VB2_GBB_SIGNATURE, VB2_GBB_SIGNATURE_SIZE);
177 gbb->major_version = VB2_GBB_MAJOR_VER;
178 gbb->minor_version = VB2_GBB_MINOR_VER;
179 gbb->header_size = sizeof(struct vb2_gbb_header);
180 /* Fill in the given key, if any, for both root and recovery */
181 if (key_blob) {
182 gbb->rootkey_offset = gbb->header_size;
183 gbb->rootkey_size = key_size;
184 memcpy((uint8_t*)gbb + gbb->rootkey_offset, key_blob, key_size);
185
186 gbb->recovery_key_offset = gbb->rootkey_offset;
187 gbb->recovery_key_size = key_size;
188 }
189
190 printf("bootflags = %d\n", boot_flags);
191
192 /* Get image size */
193 printf("Reading from image: %s\n", image_name);
194 image_file = fopen(image_name, "rb");
195 if (!image_file) {
196 fprintf(stderr, "Unable to open image file %s\n", image_name);
197 return 1;
198 }
199 fseek(image_file, 0, SEEK_END);
200 disk_info.streaming_lba_count = (ftell(image_file) / LBA_BYTES);
201 disk_info.lba_count = disk_info.streaming_lba_count;
202 rewind(image_file);
203 printf("Streaming LBA count: %" PRIu64 "\n",
204 disk_info.streaming_lba_count);
205
206 /* Allocate a buffer for the kernel */
207 lkp.kernel_buffer = malloc(KERNEL_BUFFER_SIZE);
208 if (!lkp.kernel_buffer) {
209 fprintf(stderr, "Unable to allocate kernel buffer.\n");
210 return 1;
211 }
212 lkp.kernel_buffer_size = KERNEL_BUFFER_SIZE;
213
214 /* Set up vboot context. */
215 if (vb2api_init(&workbuf, sizeof(workbuf), &ctx)) {
216 fprintf(stderr, "Can't initialize workbuf\n");
217 return 1;
218 }
219 sd = vb2_get_sd(ctx);
220
221 /* Copy kernel subkey to workbuf, if any */
222 if (key_blob) {
223 struct vb2_workbuf wb;
224 struct vb2_packed_key *dst;
225 uint32_t kernkey_size =
226 key_blob->key_offset + key_blob->key_size;
227 vb2_workbuf_from_ctx(ctx, &wb);
228 dst = vb2_workbuf_alloc(&wb, kernkey_size);
229 memcpy(dst, key_blob, kernkey_size);
230 vb2_set_workbuf_used(ctx, vb2_offset_of(sd, wb.buf));
231 sd->kernel_key_offset = vb2_offset_of(sd, dst);
232 sd->kernel_key_size = kernkey_size;
233 }
234
235 /* Free the key blob, now that we're done with it */
236 free(key_blob);
237
238 /* No need to initialize ctx->nvdata[]; defaults are fine */
239 /* TODO(chromium:441893): support dev-mode flag and external gpt flag */
240 if (boot_flags & BOOT_FLAG_RECOVERY)
241 ctx->flags |= VB2_CONTEXT_RECOVERY_MODE;
242 if (boot_flags & BOOT_FLAG_DEVELOPER)
243 ctx->flags |= VB2_CONTEXT_DEVELOPER_MODE;
244
245 /* Call vb2api_load_kernel() */
246 rv = vb2api_load_kernel(ctx, &lkp, &disk_info);
247 printf("vb2api_load_kernel() returned %d\n", rv);
248
249 if (VB2_SUCCESS == rv) {
250 printf("Partition number: %u\n", lkp.partition_number);
251 printf("Bootloader offset: %" PRIu64 "\n",
252 lkp.bootloader_offset);
253 printf("Bootloader size: %u\n", lkp.bootloader_size);
254 printf("Partition guid: "
255 "%02x%02x%02x%02x-%02x%02x-%02x%02x"
256 "-%02x%02x-%02x%02x%02x%02x%02x%02x\n",
257 lkp.partition_guid[3],
258 lkp.partition_guid[2],
259 lkp.partition_guid[1],
260 lkp.partition_guid[0],
261 lkp.partition_guid[5],
262 lkp.partition_guid[4],
263 lkp.partition_guid[7],
264 lkp.partition_guid[6],
265 lkp.partition_guid[8],
266 lkp.partition_guid[9],
267 lkp.partition_guid[10],
268 lkp.partition_guid[11],
269 lkp.partition_guid[12],
270 lkp.partition_guid[13],
271 lkp.partition_guid[14],
272 lkp.partition_guid[15]);
273 }
274
275 fclose(image_file);
276 free(lkp.kernel_buffer);
277 return rv != VB2_SUCCESS;
278 }
279