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