1 /* Copyright 2017 IBM Corp.
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  * 	http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
12  * implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <config.h>
18 
19 #include <alloca.h>
20 #include <errno.h>
21 #include <fcntl.h>
22 #include <getopt.h>
23 #include <limits.h>
24 #include <openssl/bn.h>
25 #include <openssl/ec.h>
26 #include <openssl/ecdsa.h>
27 #include <openssl/obj_mac.h>
28 #include <openssl/opensslv.h>
29 #include <openssl/ossl_typ.h>
30 #include <openssl/sha.h>
31 #include <stdbool.h>
32 #include <stddef.h>
33 #include <stdint.h>
34 #include <stdio.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/mman.h>
38 #include <sys/stat.h>
39 #include <sysexits.h>
40 #include <unistd.h>
41 
42 #include "ccan/endian/endian.h"
43 #include "ccan/short_types/short_types.h"
44 #include "container-utils.h"
45 #include "container.h"
46 
47 #define PASSED 1
48 #define FAILED 0
49 #define UNATTEMPTED -1
50 
51 char *progname;
52 
53 bool print_stats;
54 bool verbose, debug;
55 int wrap = 100;
56 
57 ecc_key_t ECDSA_KEY_NULL;
58 
59 typedef struct keyprops {
60 	char index;
61 	const char *name;
62 	const ecc_key_t *key;
63 	const ecc_signature_t *sig;
64 } Keyprops;
65 
66 static void usage(int status);
67 
68 static bool getPayloadHash(int fdin, unsigned char *md);
69 static bool getVerificationHash(char *input, unsigned char *md, int len);
70 static bool verify_signature(const char *moniker, const unsigned char *dgst,
71 		int dgst_len, const ecc_signature_t sig_raw, const ecc_key_t key_raw);
72 
print_bytes(char * lead,uint8_t * buffer,size_t buflen)73 static void print_bytes(char *lead, uint8_t *buffer, size_t buflen)
74 {
75 	unsigned int i;
76 	unsigned int width;
77 	unsigned int leadbytes = strlen(lead);
78 	leadbytes = leadbytes > 30 ? 30 : leadbytes;
79 	width = (wrap - leadbytes) / 2;
80 	width = (width < 1) ? INT_MAX : width;
81 
82 	fprintf(stdout, "%s", lead);
83 	for (i = 1; i < buflen + 1; i++) {
84 		fprintf(stdout, "%02x", buffer[i - 1]);
85 		if (((i % width) == 0) && (i < buflen))
86 			fprintf(stdout, "\n%*c", leadbytes, ' ');
87 	}
88 	fprintf(stdout, "\n");
89 }
90 
stb_is_container(const void * buf,size_t size)91 bool stb_is_container(const void *buf, size_t size)
92 {
93 	ROM_container_raw *c;
94 
95 	c = (ROM_container_raw*) buf;
96 	if (!buf || size < SECURE_BOOT_HEADERS_SIZE)
97 		return false;
98 	if (be32_to_cpu(c->magic_number) != ROM_MAGIC_NUMBER)
99 		return false;
100 	return true;
101 }
102 
parse_stb_container(const void * data,size_t len,struct parsed_stb_container * c)103 int parse_stb_container(const void* data, size_t len,
104 		struct parsed_stb_container *c)
105 {
106 	const size_t prefix_data_min_size = 3 * (EC_COORDBYTES * 2);
107 	c->buf = data;
108 	c->bufsz = len;
109 	c->c = data;
110 	c->ph = data += sizeof(ROM_container_raw);
111 	c->pd = data += sizeof(ROM_prefix_header_raw)
112 			+ (c->ph->ecid_count * ECID_SIZE);
113 	c->sh = data += prefix_data_min_size
114 			+ c->ph->sw_key_count * (EC_COORDBYTES * 2);
115 	c->ssig = data += sizeof(ROM_sw_header_raw) + c->sh->ecid_count * ECID_SIZE;
116 
117 	return 0;
118 }
119 
display_version_raw(const ROM_version_raw v)120 static void display_version_raw(const ROM_version_raw v)
121 {
122 	printf("ver_alg:\n");
123 	printf("  version:  %04x\n", be16_to_cpu(v.version));
124 	printf("  hash_alg: %02x (%s)\n", v.hash_alg,
125 			(v.hash_alg == 1) ? "SHA512" : "UNKNOWN");
126 	printf("  sig_alg:  %02x (%s)\n", v.sig_alg,
127 			(v.sig_alg == 1) ? "SHA512/ECDSA-521" : "UNKNOWN");
128 }
129 
display_container_stats(const struct parsed_stb_container * c)130 static void display_container_stats(const struct parsed_stb_container *c)
131 {
132 	unsigned int size, offset;
133 
134 	printf("Container stats:\n");
135 	size = (uint8_t*) c->ph - (uint8_t *) c->c;
136 	offset = (uint8_t*) c->c - (uint8_t *) c->buf;
137 	printf("  HW header size        = %4u (%#06x) at offset %4u (%#06x)\n",
138 			size, size, offset, offset);
139 	size = (uint8_t*) c->pd - (uint8_t *) c->ph;
140 	offset = (uint8_t*) c->ph - (uint8_t *) c->buf;
141 	printf("  Prefix header size    = %4u (%#06x) at offset %4u (%#06x)\n",
142 			size, size, offset, offset);
143 	size = (uint8_t*) c->sh - (uint8_t *) c->pd;
144 	offset = (uint8_t*) c->pd - (uint8_t *) c->buf;
145 	printf("  Prefix data size      = %4u (%#06x) at offset %4u (%#06x)\n",
146 			size, size, offset, offset);
147 	size = (uint8_t*) c->ssig - (uint8_t *) c->sh;
148 	offset = (uint8_t*) c->sh - (uint8_t *) c->buf;
149 	printf("  SW header size        = %4u (%#06x) at offset %4u (%#06x)\n",
150 			size, size, offset, offset);
151 	size = sizeof(ecc_key_t) * c->ph->sw_key_count;
152 	offset = (uint8_t*) c->ssig - (uint8_t *) c->buf;
153 	printf("  SW signature size     = %4u (%#06x) at offset %4u (%#06x)\n",
154 			size, size, offset, offset);
155 
156 	printf("  TOTAL HEADER SIZE     = %4lu (%#0lx)\n", c->bufsz, c->bufsz);
157 	printf("  PAYLOAD SIZE          = %4lu (%#0lx)\n",
158 			be64_to_cpu(c->sh->payload_size), be64_to_cpu(c->sh->payload_size));
159 	printf("  TOTAL CONTAINER SIZE  = %4lu (%#0lx)\n",
160 			be64_to_cpu(c->c->container_size),
161 			be64_to_cpu(c->c->container_size));
162 	printf("\n");
163 }
164 
display_container(struct parsed_stb_container c)165 static void display_container(struct parsed_stb_container c)
166 {
167 	unsigned char md[SHA512_DIGEST_LENGTH];
168 	void *p;
169 
170 	printf("Container:\n");
171 	printf("magic:          0x%04x\n", be32_to_cpu(c.c->magic_number));
172 	printf("version:        0x%02x\n", be16_to_cpu(c.c->version));
173 	printf("container_size: 0x%08lx (%lu)\n", be64_to_cpu(c.c->container_size),
174 			be64_to_cpu(c.c->container_size));
175 	printf("target_hrmor:   0x%08lx\n", be64_to_cpu(c.c->target_hrmor));
176 	printf("stack_pointer:  0x%08lx\n", be64_to_cpu(c.c->stack_pointer));
177 	print_bytes((char *) "hw_pkey_a: ", (uint8_t *) c.c->hw_pkey_a,
178 			sizeof(c.c->hw_pkey_a));
179 	print_bytes((char *) "hw_pkey_b: ", (uint8_t *) c.c->hw_pkey_b,
180 			sizeof(c.c->hw_pkey_b));
181 	print_bytes((char *) "hw_pkey_c: ", (uint8_t *) c.c->hw_pkey_c,
182 			sizeof(c.c->hw_pkey_c));
183 
184 	p = SHA512(c.c->hw_pkey_a, sizeof(ecc_key_t) * 3, md);
185 	if (!p)
186 		die(EX_SOFTWARE, "%s", "Cannot get SHA512");
187 	printf("HW keys hash (calculated):\n");
188 	print_bytes((char *) "           ", (uint8_t *) md, sizeof(md));
189 	printf("\n");
190 
191 	printf("Prefix Header:\n");
192 	display_version_raw(c.ph->ver_alg);
193 	printf("code_start_offset: %08lx\n", be64_to_cpu(c.ph->code_start_offset));
194 	printf("reserved:          %08lx\n", be64_to_cpu(c.ph->reserved));
195 	printf("flags:             %08x\n", be32_to_cpu(c.ph->flags));
196 	printf("sw_key_count:      %02x\n", c.ph->sw_key_count);
197 	printf("payload_size:      %08lx\n", be64_to_cpu(c.ph->payload_size));
198 	print_bytes((char *) "payload_hash:      ", (uint8_t *) c.ph->payload_hash,
199 			sizeof(c.ph->payload_hash));
200 	printf("ecid_count:        %02x\n", c.ph->ecid_count);
201 
202 	for (int i = 0; i < c.ph->ecid_count; i++) {
203 		printf("ecid:              ");
204 		print_bytes((char *) "ecid:              ",
205 				(uint8_t *) c.ph->ecid[i].ecid, sizeof(c.ph->ecid[i].ecid));
206 		printf("\n");
207 	}
208 	printf("\n");
209 
210 	printf("Prefix Data:\n");
211 	print_bytes((char *) "hw_sig_a:  ", (uint8_t *) c.pd->hw_sig_a, sizeof(c.pd->hw_sig_a));
212 	print_bytes((char *) "hw_sig_b:  ", (uint8_t *) c.pd->hw_sig_b, sizeof(c.pd->hw_sig_b));
213 	print_bytes((char *) "hw_sig_c:  ", (uint8_t *) c.pd->hw_sig_c, sizeof(c.pd->hw_sig_c));
214 
215 	if (c.ph->sw_key_count >=1)
216 		print_bytes((char *) "sw_pkey_p: ", (uint8_t *) c.pd->sw_pkey_p, sizeof(c.pd->sw_pkey_p));
217 	if (c.ph->sw_key_count >=2)
218 		print_bytes((char *) "sw_pkey_q: ", (uint8_t *) c.pd->sw_pkey_q, sizeof(c.pd->sw_pkey_q));
219 	if (c.ph->sw_key_count >=3)
220 		print_bytes((char *) "sw_pkey_r: ", (uint8_t *) c.pd->sw_pkey_r, sizeof(c.pd->sw_pkey_r));
221 
222 	printf("\n");
223 
224 	printf("Software Header:\n");
225 	display_version_raw(c.sh->ver_alg);
226 	printf("code_start_offset: %08lx\n", be64_to_cpu(c.sh->code_start_offset));
227 	printf("reserved:          %08lx\n", be64_to_cpu(c.sh->reserved));
228 	printf("reserved (ASCII):  %.8s\n", (char *) &(c.sh->reserved));
229 	printf("flags:             %08x\n", be32_to_cpu(c.sh->flags));
230 	printf("reserved_0:        %02x\n", c.sh->reserved_0);
231 	printf("payload_size:      %08lx (%lu)\n", be64_to_cpu(c.sh->payload_size),
232 			be64_to_cpu(c.sh->payload_size));
233 	print_bytes((char *) "payload_hash:      ", (uint8_t *) c.sh->payload_hash,
234 			sizeof(c.sh->payload_hash));
235 	printf("ecid_count:        %02x\n", c.sh->ecid_count);
236 
237 	for (int i = 0; i < c.sh->ecid_count; i++) {
238 		printf("ecid:              ");
239 		print_bytes((char *) "ecid:              ",
240 				(uint8_t *) c.sh->ecid[i].ecid, sizeof(c.sh->ecid[i].ecid));
241 		printf("\n");
242 	}
243 	printf("\n");
244 
245 	printf("Software Signatures:\n");
246 	print_bytes((char *) "sw_sig_p:  ", (uint8_t *) c.ssig->sw_sig_p,
247 			sizeof(c.ssig->sw_sig_p));
248 	print_bytes((char *) "sw_sig_q:  ", (uint8_t *) c.ssig->sw_sig_q,
249 			sizeof(c.ssig->sw_sig_q));
250 	print_bytes((char *) "sw_sig_r:  ", (uint8_t *) c.ssig->sw_sig_r,
251 			sizeof(c.ssig->sw_sig_r));
252 	printf("\n");
253 
254 	if (print_stats)
255 	display_container_stats(&c);
256 }
257 
validate_container(struct parsed_stb_container c,int fdin)258 static bool validate_container(struct parsed_stb_container c, int fdin)
259 {
260 	static int n;
261 	static int status = true;
262 
263 	Keyprops *k;
264 
265 	Keyprops hwKeylist[] = {
266 		{ 'a', "HW_key_A", &(c.c->hw_pkey_a), &(c.pd->hw_sig_a) },
267 		{ 'b', "HW_key_B", &(c.c->hw_pkey_b), &(c.pd->hw_sig_b) },
268 		{ 'c', "HW_key_C", &(c.c->hw_pkey_c), &(c.pd->hw_sig_c) },
269 		{ 0, NULL, NULL, NULL },
270 	};
271 	Keyprops swKeylist[] = {
272 		{ 'p', "SW_key_P", &(c.pd->sw_pkey_p), &(c.ssig->sw_sig_p) },
273 		{ 'q', "SW_key_Q", &(c.pd->sw_pkey_q), &(c.ssig->sw_sig_q) },
274 		{ 'r', "SW_key_R", &(c.pd->sw_pkey_r), &(c.ssig->sw_sig_r) },
275 		{ 0, NULL, NULL, NULL },
276 	};
277 
278 	void *md = alloca(SHA512_DIGEST_LENGTH);
279 	void *p;
280 
281 	// Get Prefix header hash.
282 	p = SHA512((uint8_t *) c.ph, sizeof(ROM_prefix_header_raw), md);
283 	if (!p)
284 		die(EX_SOFTWARE, "%s", "Cannot get SHA512");
285 	if (verbose) print_bytes((char *) "PR header hash = ", (uint8_t *) md,
286 			SHA512_DIGEST_LENGTH);
287 
288 	// Verify HW key sigs.
289 	for (k = hwKeylist; k->index; k++) {
290 
291 		if (memcmp(k->key, &ECDSA_KEY_NULL, sizeof(ecc_key_t)))
292 			status = verify_signature(k->name, md, SHA512_DIGEST_LENGTH,
293 					*(k->sig), *(k->key)) && status;
294 		else
295 			if (verbose) printf("%s is NULL, skipping signature check.\n", k->name);
296 	}
297 	if (verbose) printf("\n");
298 
299 	// Get SW header hash.
300 	p = SHA512((uint8_t *) c.sh, sizeof(ROM_sw_header_raw), md);
301 	if (!p)
302 		die(EX_SOFTWARE, "%s", "Cannot get SHA512");
303 	if (verbose) print_bytes((char *) "SW header hash = ", (uint8_t *) md,
304 			SHA512_DIGEST_LENGTH);
305 
306 	// Verify SW key sigs.
307 	for (k = swKeylist, n = 1; k->index && n <= c.ph->sw_key_count; k++, n++) {
308 
309 		if (memcmp(k->key, &ECDSA_KEY_NULL, sizeof(ecc_key_t)))
310 			status = verify_signature(k->name, md, SHA512_DIGEST_LENGTH,
311 					*(k->sig), *(k->key)) && status;
312 		else
313 			if (verbose) printf("%s is NULL, skipping\n", k->name);
314 	}
315 	if (verbose) printf("\n");
316 
317 	// Verify Payload hash.
318 	status = getPayloadHash(fdin, md) && status;
319 	if (verbose) print_bytes((char *) "Payload hash = ", (uint8_t *) md,
320 			SHA512_DIGEST_LENGTH);
321 
322 	if (memcmp((uint8_t *) c.sh->payload_hash, md, SHA512_DIGEST_LENGTH)) {
323 		if (verbose)
324 			printf("Payload hash does not agree with value in SW header: MISMATCH\n");
325 		status = false;
326 	} else {
327 		if (verbose)
328 			printf("Payload hash agrees with value in SW header: VERIFIED ./\n");
329 		status = status && true;
330 	}
331 	if (verbose) printf("\n");
332 
333 	// Verify SW keys hash.
334 	p = SHA512(c.pd->sw_pkey_p, sizeof(ecc_key_t) * c.ph->sw_key_count, md);
335 	if (!p)
336 		die(EX_SOFTWARE, "%s", "Cannot get SHA512");
337 	if (verbose) print_bytes((char *) "SW keys hash = ", (uint8_t *) md,
338 			SHA512_DIGEST_LENGTH);
339 
340 	if (memcmp((uint8_t *) c.ph->payload_hash, md, SHA512_DIGEST_LENGTH)) {
341 		if (verbose)
342 			printf("SW keys hash does not agree with value in Prefix header: MISMATCH\n");
343 		status = false;
344 	} else {
345 		if (verbose)
346 			printf("SW keys hash agrees with value in Prefix header: VERIFIED ./\n");
347 		status = status && true;
348 	}
349 	if (verbose) printf("\n");
350 	return status;
351 }
352 
verify_container(struct parsed_stb_container c,char * verify)353 static bool verify_container(struct parsed_stb_container c, char * verify)
354 {
355 	static int status = false;
356 
357 	void *md = alloca(SHA512_DIGEST_LENGTH);
358 	void *p;
359 	void *md_verify;
360 
361 	p = SHA512(c.c->hw_pkey_a, sizeof(ecc_key_t) * 3, md);
362 	if (!p)
363 		die(EX_SOFTWARE, "%s", "Cannot get SHA512");
364 	if (verbose) print_bytes((char *) "HW keys hash = ", (uint8_t *) md,
365 			SHA512_DIGEST_LENGTH);
366 
367 	md_verify = alloca(SHA512_DIGEST_LENGTH);
368 	getVerificationHash(verify, md_verify, SHA512_DIGEST_LENGTH);
369 
370 	if (memcmp((uint8_t *) md_verify, md, SHA512_DIGEST_LENGTH )) {
371 		if (verbose)
372 			printf("HW keys hash does not agree with provided value: MISMATCH\n");
373 	} else {
374 		if (verbose)
375 			printf("HW keys hash agrees with provided value: VERIFIED ./\n");
376 		status = true;
377 	}
378 	if (verbose) printf("\n");
379 	return status;
380 }
381 
verify_signature(const char * moniker,const unsigned char * dgst,int dgst_len,const ecc_signature_t sig_raw,const ecc_key_t key_raw)382 static bool verify_signature(const char *moniker, const unsigned char *dgst,
383 		int dgst_len, const ecc_signature_t sig_raw, const ecc_key_t key_raw)
384 {
385 	int r;
386 	bool status = false;
387 	BIGNUM *r_bn, *s_bn;
388 	ECDSA_SIG* ecdsa_sig;
389 	EC_KEY *ec_key;
390 	const EC_GROUP *ec_group;
391 	unsigned char *buffer;
392 	BIGNUM *key_bn;
393 	EC_POINT *ec_point;
394 
395 	// Convert the raw sig to a structure that can be handled by openssl.
396 	debug_print((char *) "Raw sig = ", (uint8_t *) sig_raw,
397 			sizeof(ecc_signature_t));
398 
399 	r_bn = BN_new();
400 	s_bn = BN_new();
401 
402 	BN_bin2bn((const unsigned char*) &sig_raw[0], 66, r_bn);
403 	BN_bin2bn((const unsigned char*) &sig_raw[66], 66, s_bn);
404 
405 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
406 	ecdsa_sig = ECDSA_SIG_new();
407 	ECDSA_SIG_set0(ecdsa_sig, r_bn, s_bn);
408 #else
409 	ecdsa_sig = malloc(sizeof(ECDSA_SIG));
410 	ecdsa_sig->r = r_bn;
411 	ecdsa_sig->s = s_bn;
412 #endif
413 
414 	// Convert the raw key to a structure that can be handled by openssl.
415 	debug_print((char *) "Raw key = ", (uint8_t *) key_raw,
416 			sizeof(ecc_key_t));
417 
418 	ec_key = EC_KEY_new();
419 	if (!ec_key)
420 		die(EX_SOFTWARE, "%s", "Cannot EC_KEY_new");
421 
422 	ec_group = EC_GROUP_new_by_curve_name(NID_secp521r1);
423 	if (!ec_group)
424 		die(EX_SOFTWARE, "%s", "Cannot EC_GROUP_new_by_curve_name");
425 
426 	r = EC_KEY_set_group(ec_key, ec_group);
427 	if (r == 0)
428 		die(EX_SOFTWARE, "%s", "Cannot EC_KEY_set_group");
429 
430 	// Add prefix 0x04, for uncompressed key.
431 	buffer = alloca(sizeof(ecc_key_t) + 1);
432 	*buffer = 0x04;
433 	memcpy(buffer + 1, key_raw, sizeof(ecc_key_t));
434 
435 	key_bn = BN_new();
436 	BN_bin2bn((const unsigned char*) buffer, EC_COORDBYTES * 2 + 1, key_bn);
437 
438 	ec_point = EC_POINT_bn2point(ec_group, key_bn, NULL, NULL);
439 	if (!ec_point)
440 		die(EX_SOFTWARE, "%s", "Cannot EC_POINT_bn2point");
441 
442 	r = EC_KEY_set_public_key(ec_key, (const EC_POINT*) ec_point);
443 	if (r == 0)
444 		die(EX_SOFTWARE, "%s", "Cannot EC_KEY_set_public_key");
445 
446 	// Verify the signature.
447 	r = ECDSA_do_verify(dgst, dgst_len, ecdsa_sig, ec_key);
448 	if (r == 1) {
449 		if (verbose) printf("%s signature is good: VERIFIED ./\n", moniker);
450 		status = true;
451 	} else if (r == 0) {
452 		if (verbose) printf("%s signature FAILED to verify.\n", moniker);
453 		status = false;
454 	} else {
455 		die(EX_SOFTWARE, "%s", "Cannot ECDSA_do_verify");
456 	}
457 
458 	BN_free(r_bn);
459 	BN_free(s_bn);
460 	BN_free(key_bn);
461 
462 	EC_KEY_free(ec_key);
463 
464 #if OPENSSL_VERSION_NUMBER >= 0x10100000L
465 	ECDSA_SIG_free(ecdsa_sig);
466 #else
467 	free(ecdsa_sig);
468 #endif
469 	return status;
470 }
471 
getPayloadHash(int fdin,unsigned char * md)472 static bool getPayloadHash(int fdin, unsigned char *md)
473 {
474 	struct stat payload_st;
475 	void *payload;
476 	int r;
477 	void *p;
478 
479 	r = fstat(fdin, &payload_st);
480 	if (r != 0)
481 		die(EX_NOINPUT, "Cannot stat payload file at descriptor: %d (%s)", fdin,
482 				strerror(errno));
483 
484 	payload = mmap(NULL, payload_st.st_size - SECURE_BOOT_HEADERS_SIZE,
485 			PROT_READ, MAP_PRIVATE, fdin, SECURE_BOOT_HEADERS_SIZE);
486 	if (!payload)
487 		die(EX_OSERR, "Cannot mmap file at descriptor: %d (%s)", fdin,
488 				strerror(errno));
489 
490 	p = SHA512(payload, payload_st.st_size - SECURE_BOOT_HEADERS_SIZE, md);
491 	if (!p)
492 		die(EX_SOFTWARE, "%s", "Cannot get SHA512");
493 
494 	return true;
495 }
496 
getVerificationHash(char * input,unsigned char * md,int len)497 static bool getVerificationHash(char *input, unsigned char *md, int len)
498 {
499 	char buf[len * 2 + 1 + 2]; // allow trailing \n and leading "0x"
500 	char *p;
501 	struct stat s;
502 	int r;
503 
504 	if (isValidHex(input, len)) {
505 		p = input;
506 	} else {
507 		int fdin = open(input, O_RDONLY);
508 		if (fdin <= 0)
509 			die(EX_NOINPUT, "%s",
510 					"Verify requested but no valid hash or hash file provided");
511 
512 		r = fstat(fdin, &s);
513 		if (r != 0)
514 			die(EX_NOINPUT, "Cannot stat hash file: %s (%s)", input,
515 					strerror(errno));
516 		if ((size_t) s.st_size > (sizeof(buf)))
517 			die(EX_DATAERR,
518 					"Verify hash file \"%s\" invalid size: expected a %d byte hexadecimal value",
519 					input, len);
520 
521 		r = read(fdin, buf, s.st_size);
522 		if (r <= 0)
523 			die(EX_NOINPUT, "Cannot read hash file: %s (%s)", input,
524 					strerror(errno));
525 		p = (char *) buf;
526 
527 		for (unsigned int i = 0; i < sizeof(buf); i++) // strip newline char
528 			if (buf[i] == '\n')
529 				buf[i] = '\0';
530 
531 		close(fdin);
532 	}
533 
534 	// Convert hexascii to binary.
535 	if (isValidHex(p, len)) {
536 		if (!strncmp(p, "0x", 2)) // skip leading "0x"
537 			p += 2;
538 		for (int count = 0; count < len; count++) {
539 			sscanf(p, "%2hhx", &md[count]);
540 			p += 2;
541 		}
542 	} else
543 		die(EX_DATAERR,
544 				"Verify hash file \"%s\" invalid data: expected a %d byte hexadecimal value",
545 				input, len);
546 
547 	return true;
548 }
549 
usage(int status)550 __attribute__((__noreturn__)) static void usage (int status)
551 {
552 	if (status != 0) {
553 			fprintf(stderr, "Try '%s --help' for more information.\n", progname);
554 	}
555 	else {
556 		printf("Usage: %s [options]\n", progname);
557 		printf(
558 			"\n"
559 			"Options:\n"
560 			" -h, --help              display this message and exit\n"
561 			" -v, --verbose           show verbose output\n"
562 			" -d, --debug             show additional debug output\n"
563 			" -w, --wrap              column at which to wrap long output (wrap=0 => unlimited)\n"
564 			" -s, --stats             additionally print container stats\n"
565 			" -I, --imagefile         containerized image to display (input)\n"
566 			"     --validate          perform all checks to ensure is container valid for secure boot\n"
567 			"     --verify            value, or filename containing value, of the HW Keys hash to\n"
568 			"                         verify the container against. must be valid 64 byte hexascii.\n"
569 			"\n");
570 	};
571 	exit(status);
572 }
573 
574 static struct option const opts[] = {
575 	{ "help",             no_argument,       0,  'h' },
576 	{ "verbose",          no_argument,       0,  'v' },
577 	{ "debug",            no_argument,       0,  'd' },
578 	{ "wrap",             required_argument, 0,  'w' },
579 	{ "stats",            no_argument,       0,  's' },
580 	{ "imagefile",        required_argument, 0,  'I' },
581 	{ "validate",         no_argument,       0,  128 },
582 	{ "verify",           required_argument, 0,  129 },
583 	{ "no-print",         no_argument,       0,  130 },
584 	{ "print",            no_argument,       0,  131 },
585 	{ NULL, 0, NULL, 0 }
586 };
587 
588 static struct {
589 	char *imagefn;
590 	bool validate;
591 	char *verify;
592 	bool print_container;
593 } params;
594 
595 
main(int argc,char * argv[])596 int main(int argc, char* argv[])
597 {
598 	int indexptr;
599 	int r;
600 	struct stat st;
601 	void *container;
602 	struct parsed_stb_container c;
603 	int container_status = EX_OK;
604 	int validate_status = UNATTEMPTED;
605 	int verify_status = UNATTEMPTED;
606 	int fdin;
607 
608 	params.print_container = true;
609 
610 	progname = strrchr(argv[0], '/');
611 	if (progname != NULL)
612 		++progname;
613 	else
614 		progname = argv[0];
615 
616 	while (1) {
617 		int opt;
618 		opt = getopt_long(argc, argv, "hvdw:sI:", opts, &indexptr);
619 		if (opt == -1)
620 			break;
621 
622 		switch (opt) {
623 		case 'h':
624 		case '?':
625 			usage(EX_OK);
626 			break;
627 		case 'v':
628 			verbose = true;
629 			break;
630 		case 'd':
631 			debug = true;
632 			break;
633 		case 'w':
634 			wrap = atoi(optarg);
635 			wrap = (wrap < 2) ? INT_MAX : wrap;
636 			break;
637 		case 's':
638 			print_stats = true;
639 			break;
640 		case 'I':
641 			params.imagefn = optarg;
642 			break;
643 		case 128:
644 			params.validate = true;
645 			break;
646 		case 129:
647 			params.verify = optarg;
648 			break;
649 		case 130:
650 			params.print_container = false;
651 			break;
652 		case 131:
653 			params.print_container = true;
654 			break;
655 		default:
656 			usage(EX_USAGE);
657 		}
658 	}
659 
660 	fdin = open(params.imagefn, O_RDONLY);
661 	if (fdin <= 0)
662 		die(EX_NOINPUT, "Cannot open container file: %s (%s)", params.imagefn,
663 				strerror(errno));
664 
665 	r = fstat(fdin, &st);
666 	if (r != 0)
667 		die(EX_NOINPUT, "Cannot stat container file: %s (%s)", params.imagefn,
668 				strerror(errno));
669 
670 	container = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, fdin, 0);
671 	if (!container)
672 		die(EX_OSERR, "Cannot mmap file: %s (%s)", params.imagefn,
673 				strerror(errno));
674 
675 	if (!stb_is_container(container, SECURE_BOOT_HEADERS_SIZE))
676 		die(EX_DATAERR, "%s", "Not a container, missing magic number");
677 
678 	if (parse_stb_container(container, SECURE_BOOT_HEADERS_SIZE, &c) != 0)
679 		die(EX_DATAERR, "%s", "Failed to parse container");
680 
681 	if (params.print_container)
682 		display_container(c);
683 
684 	if (params.validate)
685 		validate_status = validate_container(c, fdin);
686 
687 	if (params.verify)
688 		verify_status = verify_container(c, params.verify);
689 
690 	if ((validate_status != UNATTEMPTED) || (verify_status != UNATTEMPTED)) {
691 
692 		printf("Container validity check %s. Container verification check %s.\n\n",
693 				(validate_status == UNATTEMPTED) ?
694 						"not attempted" :
695 						((validate_status == PASSED) ? "PASSED" : "FAILED"),
696 				(verify_status == UNATTEMPTED) ?
697 						"not attempted" :
698 						((verify_status == PASSED) ? "PASSED" : "FAILED"));
699 
700 		if ((validate_status == FAILED) || (verify_status == FAILED))
701 			container_status = 1;
702 	}
703 
704 	close(fdin);
705 	return container_status;
706 }
707