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