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
15const char *gbb_fname;
16const char *vblock_fname;
17const 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 */
23int 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
63int 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 */
72static 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 */
89static 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
134static void print_help(const char *progname)
135{
136	printf("Usage: %s <gbb> <vblock> <body>\n", progname);
137}
138
139int 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