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 firmware image's signature.
6  */
7 
8 #include <stdio.h>
9 #include <stdlib.h>
10 #include <string.h>
11 
12 #include "2common.h"
13 #include "2misc.h"
14 #include "2secdata.h"
15 #include "2sysincludes.h"
16 
17 const char *gbb_fname;
18 const char *vblock_fname;
19 const char *body_fname;
20 
21 #if defined(ENABLE_HWCRYPTO_RSA_TESTS)
vb2api_hwcrypto_allowed(struct vb2_context * ctx)22 bool vb2api_hwcrypto_allowed(struct vb2_context *ctx)
23 {
24 	printf("hwcrypto is allowed.\n");
25 	return true;
26 }
27 #endif
28 
29 /**
30  * Local implementation which reads resources from individual files.  Could be
31  * more elegant and read from image.bin, if we understood the fmap.
32  */
vb2ex_read_resource(struct vb2_context * c,enum vb2_resource_index index,uint32_t offset,void * buf,uint32_t size)33 vb2_error_t vb2ex_read_resource(struct vb2_context *c,
34 				enum vb2_resource_index index, uint32_t offset,
35 				void *buf, uint32_t size)
36 {
37 	const char *fname;
38 	FILE *f;
39 	int got_size;
40 
41 	/* Get the filename for the resource */
42 	switch (index) {
43 	case VB2_RES_GBB:
44 		fname = gbb_fname;
45 		break;
46 	case VB2_RES_FW_VBLOCK:
47 		fname = vblock_fname;
48 		break;
49 	default:
50 		return VB2_ERROR_UNKNOWN;
51 	}
52 
53 	/* Open file and seek to the requested offset */
54 	f = fopen(fname, "rb");
55 	if (!f)
56 		return VB2_ERROR_UNKNOWN;
57 
58 	if (fseek(f, offset, SEEK_SET)) {
59 		fclose(f);
60 		return VB2_ERROR_UNKNOWN;
61 	}
62 
63 	/* Read data and close file */
64 	got_size = fread(buf, 1, size, f);
65 	fclose(f);
66 
67 	/* Return success if we read everything */
68 	return got_size == size ? VB2_SUCCESS : VB2_ERROR_UNKNOWN;
69 }
70 
vb2ex_tpm_clear_owner(struct vb2_context * c)71 vb2_error_t vb2ex_tpm_clear_owner(struct vb2_context *c)
72 {
73 	// TODO: implement
74 	return VB2_SUCCESS;
75 }
76 
77 /**
78  * Save non-volatile and/or secure data if needed.
79  */
save_if_needed(struct vb2_context * c)80 static void save_if_needed(struct vb2_context *c)
81 {
82 
83 	if (c->flags & VB2_CONTEXT_NVDATA_CHANGED) {
84 		// TODO: implement
85 		c->flags &= ~VB2_CONTEXT_NVDATA_CHANGED;
86 	}
87 
88 	if (c->flags & VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED) {
89 		// TODO: implement
90 		c->flags &= ~VB2_CONTEXT_SECDATA_FIRMWARE_CHANGED;
91 	}
92 }
93 
94 /**
95  * Verify firmware body
96  */
hash_body(struct vb2_context * c)97 static vb2_error_t hash_body(struct vb2_context *c)
98 {
99 	uint32_t remaining;
100 	uint8_t block[8192];
101 	uint32_t size;
102 	FILE *f;
103 	vb2_error_t rv;
104 
105 	/* Open the body data */
106 	f = fopen(body_fname, "rb");
107 	if (!f)
108 		return VB2_ERROR_TEST_INPUT_FILE;
109 
110 	/* Start the body hash */
111 	rv = vb2api_init_hash(c, VB2_HASH_TAG_FW_BODY);
112 	if (rv) {
113 		fclose(f);
114 		return rv;
115 	}
116 
117 	remaining = vb2api_get_firmware_size(c);
118 	printf("Expect %d bytes of body...\n", remaining);
119 
120 	/* Extend over the body */
121 	while (remaining) {
122 		size = sizeof(block);
123 		if (size > remaining)
124 			size = remaining;
125 
126 		/* Read next body block */
127 		size = fread(block, 1, size, f);
128 		if (size <= 0)
129 			break;
130 
131 		/* Hash it */
132 		rv = vb2api_extend_hash(c, block, size);
133 		if (rv) {
134 			fclose(f);
135 			return rv;
136 		}
137 
138 		remaining -= size;
139 	}
140 
141 	fclose(f);
142 
143 	/* Check the result */
144 	rv = vb2api_check_hash(c);
145 	if (rv)
146 		return rv;
147 
148 	return VB2_SUCCESS;
149 }
150 
print_help(const char * progname)151 static void print_help(const char *progname)
152 {
153 	printf("Usage: %s <gbb> <vblock> <body>\n", progname);
154 }
155 
main(int argc,char * argv[])156 int main(int argc, char *argv[])
157 {
158 	uint8_t workbuf[VB2_FIRMWARE_WORKBUF_RECOMMENDED_SIZE]
159 		__attribute__((aligned(VB2_WORKBUF_ALIGN)));
160 	struct vb2_context *ctx;
161 	struct vb2_shared_data *sd;
162 	vb2_error_t rv;
163 
164 	if (argc < 4) {
165 		print_help(argv[0]);
166 		return 1;
167 	}
168 
169 	/* Save filenames */
170 	gbb_fname = argv[1];
171 	vblock_fname = argv[2];
172 	body_fname = argv[3];
173 
174 	/* Intialize workbuf with sentinel value to see how much we'll use. */
175 	uint32_t *ptr = (uint32_t *)workbuf;
176 	while ((uint8_t *)ptr + sizeof(*ptr) <= workbuf + sizeof(workbuf))
177 		*ptr++ = 0xbeefdead;
178 
179 	/* Set up context */
180 	if (vb2api_init(workbuf, sizeof(workbuf), &ctx)) {
181 		printf("Failed to initialize workbuf.\n");
182 		return 1;
183 	}
184 	sd = vb2_get_sd(ctx);
185 
186 	/* Initialize secure context */
187 	vb2api_secdata_firmware_create(ctx);
188 	vb2api_secdata_kernel_create(ctx);
189 
190 	// TODO: optional args to set contents for nvdata, secdata?
191 
192 	/* Do early init */
193 	printf("Phase 1...\n");
194 	rv = vb2api_fw_phase1(ctx);
195 	if (rv) {
196 		printf("Phase 1 wants recovery mode.\n");
197 		save_if_needed(ctx);
198 		return rv;
199 	}
200 
201 	/* Determine which firmware slot to boot */
202 	printf("Phase 2...\n");
203 	rv = vb2api_fw_phase2(ctx);
204 	if (rv) {
205 		printf("Phase 2 wants reboot.\n");
206 		save_if_needed(ctx);
207 		return rv;
208 	}
209 
210 	/* Try that slot */
211 	printf("Phase 3...\n");
212 	rv = vb2api_fw_phase3(ctx);
213 	if (rv) {
214 		printf("Phase 3 wants reboot.\n");
215 		save_if_needed(ctx);
216 		return rv;
217 	}
218 
219 	/* Verify body */
220 	printf("Hash body...\n");
221 	rv = hash_body(ctx);
222 	save_if_needed(ctx);
223 	if (rv) {
224 		printf("Phase 4 wants reboot.\n");
225 		return rv;
226 	}
227 
228 	printf("Yaay!\n");
229 
230 	while ((uint8_t *)ptr > workbuf && *--ptr == 0xbeefdead)
231 		/* find last used workbuf offset */;
232 	printf("Workbuf used = %d bytes, high watermark = %zu bytes\n",
233 		sd->workbuf_used, (uint8_t *)ptr + sizeof(*ptr) - workbuf);
234 
235 	return 0;
236 }
237