diff options
Diffstat (limited to 'utils/sbtools')
-rw-r--r-- | utils/sbtools/dbparser.c | 10 | ||||
-rw-r--r-- | utils/sbtools/elf.c | 2 | ||||
-rw-r--r-- | utils/sbtools/elftosb.c | 10 | ||||
-rw-r--r-- | utils/sbtools/misc.h | 2 | ||||
-rw-r--r-- | utils/sbtools/sb.c | 680 | ||||
-rw-r--r-- | utils/sbtools/sb.h | 18 | ||||
-rw-r--r-- | utils/sbtools/sbtoelf.c | 673 |
7 files changed, 750 insertions, 645 deletions
diff --git a/utils/sbtools/dbparser.c b/utils/sbtools/dbparser.c index 2dcc21eeba..3cd0652d49 100644 --- a/utils/sbtools/dbparser.c +++ b/utils/sbtools/dbparser.c | |||
@@ -24,15 +24,7 @@ | |||
24 | #include <stdint.h> | 24 | #include <stdint.h> |
25 | #include <string.h> | 25 | #include <string.h> |
26 | #include "dbparser.h" | 26 | #include "dbparser.h" |
27 | 27 | #include "misc.h" | |
28 | typedef uint8_t byte; | ||
29 | |||
30 | extern bool g_debug; | ||
31 | extern void *xmalloc(size_t s); | ||
32 | extern int convxdigit(char digit, byte *val); | ||
33 | |||
34 | #define bug(...) do { fprintf(stderr, __VA_ARGS__); exit(1); } while(0) | ||
35 | #define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0) | ||
36 | 28 | ||
37 | enum lexem_type_t | 29 | enum lexem_type_t |
38 | { | 30 | { |
diff --git a/utils/sbtools/elf.c b/utils/sbtools/elf.c index 718cb58b05..91b5d74848 100644 --- a/utils/sbtools/elf.c +++ b/utils/sbtools/elf.c | |||
@@ -223,6 +223,8 @@ void elf_add_fill_section(struct elf_params_t *params, | |||
223 | void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, | 223 | void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, |
224 | elf_printf_fn_t printf, void *user) | 224 | elf_printf_fn_t printf, void *user) |
225 | { | 225 | { |
226 | (void) printf; | ||
227 | |||
226 | Elf32_Ehdr ehdr; | 228 | Elf32_Ehdr ehdr; |
227 | uint32_t phnum = 0; | 229 | uint32_t phnum = 0; |
228 | struct elf_section_t *sec = params->first_section; | 230 | struct elf_section_t *sec = params->first_section; |
diff --git a/utils/sbtools/elftosb.c b/utils/sbtools/elftosb.c index c1a86ea23b..b8d68b82e7 100644 --- a/utils/sbtools/elftosb.c +++ b/utils/sbtools/elftosb.c | |||
@@ -436,8 +436,14 @@ int main(int argc, char **argv) | |||
436 | sb_file->real_key = &real_key.u.key; | 436 | sb_file->real_key = &real_key.u.key; |
437 | if(crypto_iv.method == CRYPTO_KEY) | 437 | if(crypto_iv.method == CRYPTO_KEY) |
438 | sb_file->crypto_iv = &crypto_iv.u.key; | 438 | sb_file->crypto_iv = &crypto_iv.u.key; |
439 | 439 | ||
440 | sb_produce_file(sb_file, output_filename); | 440 | /* fill with default parameters since there is no command file support for them */ |
441 | sb_file->drive_tag = 0; | ||
442 | sb_file->first_boot_sec_id = sb_file->sections[0].identifier; | ||
443 | sb_file->flags = 0; | ||
444 | sb_file->minor_version = 1; | ||
445 | |||
446 | sb_write_file(sb_file, output_filename); | ||
441 | 447 | ||
442 | return 0; | 448 | return 0; |
443 | } | 449 | } |
diff --git a/utils/sbtools/misc.h b/utils/sbtools/misc.h index a685816047..9f14497680 100644 --- a/utils/sbtools/misc.h +++ b/utils/sbtools/misc.h | |||
@@ -28,7 +28,7 @@ | |||
28 | #define STR(a) _STR(a) | 28 | #define STR(a) _STR(a) |
29 | 29 | ||
30 | #define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0) | 30 | #define bug(...) do { fprintf(stderr,"["__FILE__":"STR(__LINE__)"]ERROR: "__VA_ARGS__); exit(1); } while(0) |
31 | #define bugp(a) do { perror("ERROR: "a); exit(1); } while(0) | 31 | #define bugp(...) do { fprintf(stderr, __VA_ARGS__); perror(" "); exit(1); } while(0) |
32 | 32 | ||
33 | #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) | 33 | #define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) |
34 | 34 | ||
diff --git a/utils/sbtools/sb.c b/utils/sbtools/sb.c index 3921710a2d..99f953600d 100644 --- a/utils/sbtools/sb.c +++ b/utils/sbtools/sb.c | |||
@@ -21,6 +21,7 @@ | |||
21 | #include <stdio.h> | 21 | #include <stdio.h> |
22 | #include <time.h> | 22 | #include <time.h> |
23 | #include <stdlib.h> | 23 | #include <stdlib.h> |
24 | #include <ctype.h> | ||
24 | #include "misc.h" | 25 | #include "misc.h" |
25 | #include "crypto.h" | 26 | #include "crypto.h" |
26 | #include "sb.h" | 27 | #include "sb.h" |
@@ -64,6 +65,7 @@ static void compute_sb_offsets(struct sb_file_t *sb) | |||
64 | alignment /= BLOCK_SIZE; /* alignment in block sizes */ | 65 | alignment /= BLOCK_SIZE; /* alignment in block sizes */ |
65 | 66 | ||
66 | struct sb_section_t *sec = &sb->sections[i]; | 67 | struct sb_section_t *sec = &sb->sections[i]; |
68 | sec->sec_size = 0; | ||
67 | 69 | ||
68 | if(g_debug) | 70 | if(g_debug) |
69 | { | 71 | { |
@@ -203,7 +205,7 @@ static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr) | |||
203 | sb_hdr->flags = 0; | 205 | sb_hdr->flags = 0; |
204 | sb_hdr->image_size = sb->image_size; | 206 | sb_hdr->image_size = sb->image_size; |
205 | sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE; | 207 | sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE; |
206 | sb_hdr->first_boot_sec_id = sb->sections[0].identifier; | 208 | sb_hdr->first_boot_sec_id = sb->first_boot_sec_id; |
207 | sb_hdr->nr_keys = g_nr_keys; | 209 | sb_hdr->nr_keys = g_nr_keys; |
208 | sb_hdr->nr_sections = sb->nr_sections; | 210 | sb_hdr->nr_sections = sb->nr_sections; |
209 | sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE; | 211 | sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE; |
@@ -213,12 +215,17 @@ static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr) | |||
213 | sizeof(struct sb_key_dictionary_entry_t) * sb_hdr->nr_keys / BLOCK_SIZE; | 215 | sizeof(struct sb_key_dictionary_entry_t) * sb_hdr->nr_keys / BLOCK_SIZE; |
214 | generate_random_data(sb_hdr->rand_pad0, sizeof(sb_hdr->rand_pad0)); | 216 | generate_random_data(sb_hdr->rand_pad0, sizeof(sb_hdr->rand_pad0)); |
215 | generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1)); | 217 | generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1)); |
218 | /* Version 1.0 has 6 bytes of random padding, | ||
219 | * Version 1.1 requires the last 4 bytes to be 'sgtl' */ | ||
220 | if(sb->minor_version >= 1) | ||
221 | memcpy(&sb_hdr->rand_pad0[2], "sgtl", 4); | ||
222 | |||
216 | sb_hdr->timestamp = generate_timestamp(); | 223 | sb_hdr->timestamp = generate_timestamp(); |
217 | sb_hdr->product_ver = sb->product_ver; | 224 | sb_hdr->product_ver = sb->product_ver; |
218 | fix_version(&sb_hdr->product_ver); | 225 | fix_version(&sb_hdr->product_ver); |
219 | sb_hdr->component_ver = sb->component_ver; | 226 | sb_hdr->component_ver = sb->component_ver; |
220 | fix_version(&sb_hdr->component_ver); | 227 | fix_version(&sb_hdr->component_ver); |
221 | sb_hdr->drive_tag = 0; | 228 | sb_hdr->drive_tag = sb->drive_tag; |
222 | 229 | ||
223 | sha_1_init(&sha_1_params); | 230 | sha_1_init(&sha_1_params); |
224 | sha_1_update(&sha_1_params, &sb_hdr->signature[0], | 231 | sha_1_update(&sha_1_params, &sb_hdr->signature[0], |
@@ -292,7 +299,7 @@ void produce_sb_instruction(struct sb_inst_t *inst, | |||
292 | cmd->hdr.checksum = instruction_checksum(&cmd->hdr); | 299 | cmd->hdr.checksum = instruction_checksum(&cmd->hdr); |
293 | } | 300 | } |
294 | 301 | ||
295 | void sb_produce_file(struct sb_file_t *sb, const char *filename) | 302 | void sb_write_file(struct sb_file_t *sb, const char *filename) |
296 | { | 303 | { |
297 | FILE *fd = fopen(filename, "wb"); | 304 | FILE *fd = fopen(filename, "wb"); |
298 | if(fd == NULL) | 305 | if(fd == NULL) |
@@ -424,3 +431,670 @@ void sb_produce_file(struct sb_file_t *sb, const char *filename) | |||
424 | 431 | ||
425 | fclose(fd); | 432 | fclose(fd); |
426 | } | 433 | } |
434 | |||
435 | static void *memdup(void *p, size_t len) | ||
436 | { | ||
437 | void *cpy = xmalloc(len); | ||
438 | memcpy(cpy, p, len); | ||
439 | return cpy; | ||
440 | } | ||
441 | |||
442 | static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf, | ||
443 | int size, const char *indent, void *u, sb_color_printf cprintf) | ||
444 | { | ||
445 | #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) | ||
446 | |||
447 | struct sb_section_t *sec = xmalloc(sizeof(struct sb_section_t)); | ||
448 | memset(sec, 0, sizeof(struct sb_section_t)); | ||
449 | sec->identifier = id; | ||
450 | sec->is_data = data_sec; | ||
451 | sec->sec_size = ROUND_UP(size, BLOCK_SIZE) / BLOCK_SIZE; | ||
452 | |||
453 | if(data_sec) | ||
454 | { | ||
455 | sec->nr_insts = 1; | ||
456 | sec->insts = xmalloc(sizeof(struct sb_inst_t)); | ||
457 | memset(sec->insts, 0, sizeof(struct sb_inst_t)); | ||
458 | sec->insts->inst = SB_INST_DATA; | ||
459 | sec->insts->size = size; | ||
460 | sec->insts->data = memdup(buf, size); | ||
461 | return sec; | ||
462 | } | ||
463 | |||
464 | /* Pretty print the content */ | ||
465 | int pos = 0; | ||
466 | while(pos < size) | ||
467 | { | ||
468 | struct sb_inst_t inst; | ||
469 | memset(&inst, 0, sizeof(inst)); | ||
470 | |||
471 | struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)&buf[pos]; | ||
472 | inst.inst = hdr->opcode; | ||
473 | |||
474 | printf(OFF, "%s", indent); | ||
475 | uint8_t checksum = instruction_checksum(hdr); | ||
476 | if(checksum != hdr->checksum) | ||
477 | printf(GREY, "[Bad checksum]"); | ||
478 | if(hdr->flags != 0) | ||
479 | { | ||
480 | printf(GREY, "["); | ||
481 | printf(BLUE, "f=%x", hdr->flags); | ||
482 | printf(GREY, "] "); | ||
483 | } | ||
484 | if(hdr->opcode == SB_INST_LOAD) | ||
485 | { | ||
486 | struct sb_instruction_load_t *load = (struct sb_instruction_load_t *)&buf[pos]; | ||
487 | inst.size = load->len; | ||
488 | inst.addr = load->addr; | ||
489 | inst.data = memdup(load + 1, load->len); | ||
490 | |||
491 | printf(RED, "LOAD"); | ||
492 | printf(OFF, " | "); | ||
493 | printf(BLUE, "addr=0x%08x", load->addr); | ||
494 | printf(OFF, " | "); | ||
495 | printf(GREEN, "len=0x%08x", load->len); | ||
496 | printf(OFF, " | "); | ||
497 | printf(YELLOW, "crc=0x%08x", load->crc); | ||
498 | /* data is padded to 16-byte boundary with random data and crc'ed with it */ | ||
499 | uint32_t computed_crc = crc(&buf[pos + sizeof(struct sb_instruction_load_t)], | ||
500 | ROUND_UP(load->len, 16)); | ||
501 | if(load->crc == computed_crc) | ||
502 | printf(RED, " Ok\n"); | ||
503 | else | ||
504 | printf(RED, " Failed (crc=0x%08x)\n", computed_crc); | ||
505 | |||
506 | pos += load->len + sizeof(struct sb_instruction_load_t); | ||
507 | } | ||
508 | else if(hdr->opcode == SB_INST_FILL) | ||
509 | { | ||
510 | struct sb_instruction_fill_t *fill = (struct sb_instruction_fill_t *)&buf[pos]; | ||
511 | inst.pattern = fill->pattern; | ||
512 | inst.size = fill->len; | ||
513 | inst.addr = fill->addr; | ||
514 | |||
515 | printf(RED, "FILL"); | ||
516 | printf(OFF, " | "); | ||
517 | printf(BLUE, "addr=0x%08x", fill->addr); | ||
518 | printf(OFF, " | "); | ||
519 | printf(GREEN, "len=0x%08x", fill->len); | ||
520 | printf(OFF, " | "); | ||
521 | printf(YELLOW, "pattern=0x%08x\n", fill->pattern); | ||
522 | |||
523 | pos += sizeof(struct sb_instruction_fill_t); | ||
524 | } | ||
525 | else if(hdr->opcode == SB_INST_CALL || | ||
526 | hdr->opcode == SB_INST_JUMP) | ||
527 | { | ||
528 | int is_call = (hdr->opcode == SB_INST_CALL); | ||
529 | struct sb_instruction_call_t *call = (struct sb_instruction_call_t *)&buf[pos]; | ||
530 | inst.addr = call->addr; | ||
531 | inst.argument = call->arg; | ||
532 | |||
533 | if(is_call) | ||
534 | printf(RED, "CALL"); | ||
535 | else | ||
536 | printf(RED, "JUMP"); | ||
537 | printf(OFF, " | "); | ||
538 | printf(BLUE, "addr=0x%08x", call->addr); | ||
539 | printf(OFF, " | "); | ||
540 | printf(GREEN, "arg=0x%08x\n", call->arg); | ||
541 | |||
542 | pos += sizeof(struct sb_instruction_call_t); | ||
543 | } | ||
544 | else if(hdr->opcode == SB_INST_MODE) | ||
545 | { | ||
546 | struct sb_instruction_mode_t *mode = (struct sb_instruction_mode_t *)hdr; | ||
547 | inst.argument = mode->mode; | ||
548 | |||
549 | printf(RED, "MODE"); | ||
550 | printf(OFF, " | "); | ||
551 | printf(BLUE, "mod=0x%08x\n", mode->mode); | ||
552 | |||
553 | pos += sizeof(struct sb_instruction_mode_t); | ||
554 | } | ||
555 | else if(hdr->opcode == SB_INST_NOP) | ||
556 | { | ||
557 | printf(RED, "NOOP\n"); | ||
558 | pos += sizeof(struct sb_instruction_mode_t); | ||
559 | } | ||
560 | else | ||
561 | { | ||
562 | printf(RED, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos); | ||
563 | break; | ||
564 | } | ||
565 | |||
566 | sec->insts = augment_array(sec->insts, sizeof(struct sb_inst_t), sec->nr_insts++, &inst, 1); | ||
567 | pos = ROUND_UP(pos, BLOCK_SIZE); | ||
568 | } | ||
569 | |||
570 | return sec; | ||
571 | #undef printf | ||
572 | } | ||
573 | |||
574 | static void fill_section_name(char name[5], uint32_t identifier) | ||
575 | { | ||
576 | name[0] = (identifier >> 24) & 0xff; | ||
577 | name[1] = (identifier >> 16) & 0xff; | ||
578 | name[2] = (identifier >> 8) & 0xff; | ||
579 | name[3] = identifier & 0xff; | ||
580 | for(int i = 0; i < 4; i++) | ||
581 | if(!isprint(name[i])) | ||
582 | name[i] = '_'; | ||
583 | name[4] = 0; | ||
584 | } | ||
585 | |||
586 | static uint32_t guess_alignment(uint32_t off) | ||
587 | { | ||
588 | /* find greatest power of two which divides the offset */ | ||
589 | if(off == 0) | ||
590 | return 1; | ||
591 | uint32_t a = 1; | ||
592 | while(off % (2 * a) == 0) | ||
593 | a *= 2; | ||
594 | return a; | ||
595 | } | ||
596 | |||
597 | struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u, | ||
598 | sb_color_printf cprintf) | ||
599 | { | ||
600 | #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) | ||
601 | #define fatal(...) do { cprintf(u, true, GREY, __VA_ARGS__); return NULL; } while(0) | ||
602 | #define print_hex(c, p, len, nl) \ | ||
603 | do { printf(c, ""); print_hex(p, len, nl); } while(0) | ||
604 | |||
605 | FILE *f = fopen(filename, "rb"); | ||
606 | if(f == NULL) | ||
607 | fatal("Cannot open file for reading\n"); | ||
608 | fseek(f, 0, SEEK_END); | ||
609 | long filesize = ftell(f); | ||
610 | fseek(f, 0, SEEK_SET); | ||
611 | uint8_t *buf = xmalloc(filesize); | ||
612 | fread(buf, 1, filesize, f); | ||
613 | fclose(f); | ||
614 | |||
615 | struct sha_1_params_t sha_1_params; | ||
616 | struct sb_file_t *sb_file = xmalloc(sizeof(struct sb_file_t)); | ||
617 | memset(sb_file, 0, sizeof(struct sb_file_t)); | ||
618 | struct sb_header_t *sb_header = (struct sb_header_t *)buf; | ||
619 | |||
620 | sb_file->image_size = sb_header->image_size; | ||
621 | sb_file->minor_version = sb_header->minor_ver; | ||
622 | sb_file->flags = sb_header->flags; | ||
623 | sb_file->drive_tag = sb_header->drive_tag; | ||
624 | sb_file->first_boot_sec_id = sb_header->first_boot_sec_id; | ||
625 | |||
626 | if(memcmp(sb_header->signature, "STMP", 4) != 0) | ||
627 | fatal("Bad signature\n"); | ||
628 | if(sb_header->image_size * BLOCK_SIZE > filesize) | ||
629 | fatal("File too small mismatch"); | ||
630 | if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t)) | ||
631 | fatal("Bad header size"); | ||
632 | if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t)) | ||
633 | fatal("Bad section header size"); | ||
634 | |||
635 | if(filesize > sb_header->image_size * BLOCK_SIZE) | ||
636 | { | ||
637 | printf(GREY, "[Restrict file size from %lu to %d bytes]\n", filesize, | ||
638 | sb_header->image_size * BLOCK_SIZE); | ||
639 | filesize = sb_header->image_size * BLOCK_SIZE; | ||
640 | } | ||
641 | |||
642 | printf(BLUE, "Basic info:\n"); | ||
643 | printf(GREEN, " SB version: "); | ||
644 | printf(YELLOW, "%d.%d\n", sb_header->major_ver, sb_header->minor_ver); | ||
645 | printf(GREEN, " Header SHA-1: "); | ||
646 | byte *hdr_sha1 = sb_header->sha1_header; | ||
647 | print_hex(YELLOW, hdr_sha1, 20, false); | ||
648 | /* Check SHA1 sum */ | ||
649 | byte computed_sha1[20]; | ||
650 | sha_1_init(&sha_1_params); | ||
651 | sha_1_update(&sha_1_params, &sb_header->signature[0], | ||
652 | sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header)); | ||
653 | sha_1_finish(&sha_1_params); | ||
654 | sha_1_output(&sha_1_params, computed_sha1); | ||
655 | if(memcmp(hdr_sha1, computed_sha1, 20) == 0) | ||
656 | printf(RED, " Ok\n"); | ||
657 | else | ||
658 | printf(RED, " Failed\n"); | ||
659 | printf(GREEN, " Flags: "); | ||
660 | printf(YELLOW, "%x\n", sb_header->flags); | ||
661 | printf(GREEN, " Total file size : "); | ||
662 | printf(YELLOW, "%ld\n", filesize); | ||
663 | |||
664 | /* Sizes and offsets */ | ||
665 | printf(BLUE, "Sizes and offsets:\n"); | ||
666 | printf(GREEN, " # of encryption keys = "); | ||
667 | printf(YELLOW, "%d\n", sb_header->nr_keys); | ||
668 | printf(GREEN, " # of sections = "); | ||
669 | printf(YELLOW, "%d\n", sb_header->nr_sections); | ||
670 | |||
671 | /* Versions */ | ||
672 | printf(BLUE, "Versions\n"); | ||
673 | |||
674 | printf(GREEN, " Random 1: "); | ||
675 | print_hex(YELLOW, sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true); | ||
676 | printf(GREEN, " Random 2: "); | ||
677 | print_hex(YELLOW, sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true); | ||
678 | |||
679 | uint64_t micros = sb_header->timestamp; | ||
680 | time_t seconds = (micros / (uint64_t)1000000L); | ||
681 | struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */ | ||
682 | seconds += mktime(&tm_base); | ||
683 | struct tm *time = gmtime(&seconds); | ||
684 | printf(GREEN, " Creation date/time = "); | ||
685 | printf(YELLOW, "%s", asctime(time)); | ||
686 | |||
687 | struct sb_version_t product_ver = sb_header->product_ver; | ||
688 | fix_version(&product_ver); | ||
689 | struct sb_version_t component_ver = sb_header->component_ver; | ||
690 | fix_version(&component_ver); | ||
691 | |||
692 | memcpy(&sb_file->product_ver, &product_ver, sizeof(product_ver)); | ||
693 | memcpy(&sb_file->component_ver, &component_ver, sizeof(component_ver)); | ||
694 | |||
695 | printf(GREEN, " Product version = "); | ||
696 | printf(YELLOW, "%X.%X.%X\n", product_ver.major, product_ver.minor, product_ver.revision); | ||
697 | printf(GREEN, " Component version = "); | ||
698 | printf(YELLOW, "%X.%X.%X\n", component_ver.major, component_ver.minor, component_ver.revision); | ||
699 | |||
700 | printf(GREEN, " Drive tag = "); | ||
701 | printf(YELLOW, "%x\n", sb_header->drive_tag); | ||
702 | printf(GREEN, " First boot tag offset = "); | ||
703 | printf(YELLOW, "%x\n", sb_header->first_boot_tag_off); | ||
704 | printf(GREEN, " First boot section ID = "); | ||
705 | printf(YELLOW, "0x%08x\n", sb_header->first_boot_sec_id); | ||
706 | |||
707 | /* encryption cbc-mac */ | ||
708 | byte real_key[16]; | ||
709 | bool valid_key = false; /* false until a matching key was found */ | ||
710 | if(sb_header->nr_keys > 0) | ||
711 | { | ||
712 | if(sb_header->nr_keys > g_nr_keys) | ||
713 | { | ||
714 | fatal("SB file has %d keys but only %d were specified\n", | ||
715 | sb_header->nr_keys, g_nr_keys); | ||
716 | } | ||
717 | printf(BLUE, "Encryption data\n"); | ||
718 | for(int i = 0; i < sb_header->nr_keys; i++) | ||
719 | { | ||
720 | printf(RED, " Key %d: ", i); | ||
721 | printf(YELLOW, ""); | ||
722 | print_key(&g_key_array[i], true); | ||
723 | printf(GREEN, " CBC-MAC of headers: "); | ||
724 | |||
725 | uint32_t ofs = sizeof(struct sb_header_t) | ||
726 | + sizeof(struct sb_section_header_t) * sb_header->nr_sections | ||
727 | + sizeof(struct sb_key_dictionary_entry_t) * i; | ||
728 | struct sb_key_dictionary_entry_t *dict_entry = | ||
729 | (struct sb_key_dictionary_entry_t *)&buf[ofs]; | ||
730 | /* cbc mac */ | ||
731 | print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false); | ||
732 | /* check it */ | ||
733 | byte computed_cbc_mac[16]; | ||
734 | byte zero[16]; | ||
735 | memset(zero, 0, 16); | ||
736 | crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections, | ||
737 | &g_key_array[i], zero, &computed_cbc_mac, 1); | ||
738 | |||
739 | bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0; | ||
740 | if(ok) | ||
741 | { | ||
742 | valid_key = true; | ||
743 | printf(RED, " Ok\n"); | ||
744 | } | ||
745 | else | ||
746 | printf(RED, " Failed\n"); | ||
747 | |||
748 | printf(GREEN, " Encrypted key : "); | ||
749 | print_hex(YELLOW, dict_entry->key, 16, true); | ||
750 | /* decrypt */ | ||
751 | byte decrypted_key[16]; | ||
752 | byte iv[16]; | ||
753 | memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */ | ||
754 | crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[i], iv, NULL, 0); | ||
755 | printf(GREEN, " Decrypted key : "); | ||
756 | print_hex(YELLOW, decrypted_key, 16, false); | ||
757 | /* cross-check or copy */ | ||
758 | if(valid_key && ok) | ||
759 | memcpy(real_key, decrypted_key, 16); | ||
760 | else if(valid_key) | ||
761 | { | ||
762 | if(memcmp(real_key, decrypted_key, 16) == 0) | ||
763 | printf(RED, " Cross-Check Ok"); | ||
764 | else | ||
765 | printf(RED, " Cross-Check Failed"); | ||
766 | } | ||
767 | printf(OFF, "\n"); | ||
768 | } | ||
769 | } | ||
770 | |||
771 | if(getenv("SB_REAL_KEY") != 0) | ||
772 | { | ||
773 | struct crypto_key_t k; | ||
774 | char *env = getenv("SB_REAL_KEY"); | ||
775 | if(!parse_key(&env, &k) || *env) | ||
776 | bug("Invalid SB_REAL_KEY"); | ||
777 | memcpy(real_key, k.u.key, 16); | ||
778 | } | ||
779 | |||
780 | printf(RED, " Summary:\n"); | ||
781 | printf(GREEN, " Real key: "); | ||
782 | print_hex(YELLOW, real_key, 16, true); | ||
783 | printf(GREEN, " IV : "); | ||
784 | print_hex(YELLOW, buf, 16, true); | ||
785 | |||
786 | sb_file->real_key = xmalloc(16); | ||
787 | memcpy(*sb_file->real_key, real_key, 16); | ||
788 | sb_file->crypto_iv = xmalloc(16); | ||
789 | memcpy(*sb_file->crypto_iv, buf, 16); | ||
790 | |||
791 | /* sections */ | ||
792 | if(!raw_mode) | ||
793 | { | ||
794 | sb_file->nr_sections = sb_header->nr_sections; | ||
795 | sb_file->sections = xmalloc(sb_file->nr_sections * sizeof(struct sb_section_t)); | ||
796 | memset(sb_file->sections, 0, sb_file->nr_sections * sizeof(struct sb_section_t)); | ||
797 | printf(BLUE, "Sections\n"); | ||
798 | for(int i = 0; i < sb_header->nr_sections; i++) | ||
799 | { | ||
800 | uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t); | ||
801 | struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&buf[ofs]; | ||
802 | |||
803 | char name[5]; | ||
804 | fill_section_name(name, sec_hdr->identifier); | ||
805 | int pos = sec_hdr->offset * BLOCK_SIZE; | ||
806 | int size = sec_hdr->size * BLOCK_SIZE; | ||
807 | int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE); | ||
808 | int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0; | ||
809 | |||
810 | printf(GREEN, " Section "); | ||
811 | printf(YELLOW, "'%s'\n", name); | ||
812 | printf(GREEN, " pos = "); | ||
813 | printf(YELLOW, "%8x - %8x\n", pos, pos+size); | ||
814 | printf(GREEN, " len = "); | ||
815 | printf(YELLOW, "%8x\n", size); | ||
816 | printf(GREEN, " flags = "); | ||
817 | printf(YELLOW, "%8x", sec_hdr->flags); | ||
818 | if(data_sec) | ||
819 | printf(RED, " Data Section"); | ||
820 | else | ||
821 | printf(RED, " Boot Section"); | ||
822 | if(encrypted) | ||
823 | printf(RED, " (Encrypted)"); | ||
824 | printf(OFF, "\n"); | ||
825 | |||
826 | /* save it */ | ||
827 | byte *sec = xmalloc(size); | ||
828 | if(encrypted) | ||
829 | cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0); | ||
830 | else | ||
831 | memcpy(sec, buf + pos, size); | ||
832 | |||
833 | struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier, | ||
834 | sec, size, " ", u, cprintf); | ||
835 | if(s) | ||
836 | { | ||
837 | s->is_cleartext = !encrypted; | ||
838 | s->alignment = guess_alignment(pos); | ||
839 | memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t)); | ||
840 | free(s); | ||
841 | } | ||
842 | |||
843 | free(sec); | ||
844 | } | ||
845 | } | ||
846 | else | ||
847 | { | ||
848 | /* advanced raw mode */ | ||
849 | printf(BLUE, "Commands\n"); | ||
850 | uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE; | ||
851 | byte iv[16]; | ||
852 | const char *indent = " "; | ||
853 | while(true) | ||
854 | { | ||
855 | /* restart with IV */ | ||
856 | memcpy(iv, buf, 16); | ||
857 | byte cmd[BLOCK_SIZE]; | ||
858 | if(sb_header->nr_keys > 0) | ||
859 | cbc_mac(buf + offset, cmd, 1, real_key, iv, &iv, 0); | ||
860 | else | ||
861 | memcpy(cmd, buf + offset, BLOCK_SIZE); | ||
862 | struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd; | ||
863 | printf(OFF, "%s", indent); | ||
864 | uint8_t checksum = instruction_checksum(hdr); | ||
865 | if(checksum != hdr->checksum) | ||
866 | printf(GREY, "[Bad checksum']"); | ||
867 | |||
868 | if(hdr->opcode == SB_INST_NOP) | ||
869 | { | ||
870 | printf(RED, "NOOP\n"); | ||
871 | offset += BLOCK_SIZE; | ||
872 | } | ||
873 | else if(hdr->opcode == SB_INST_TAG) | ||
874 | { | ||
875 | struct sb_instruction_tag_t *tag = (struct sb_instruction_tag_t *)hdr; | ||
876 | printf(RED, "BTAG"); | ||
877 | printf(OFF, " | "); | ||
878 | printf(BLUE, "sec=0x%08x", tag->identifier); | ||
879 | printf(OFF, " | "); | ||
880 | printf(GREEN, "cnt=0x%08x", tag->len); | ||
881 | printf(OFF, " | "); | ||
882 | printf(YELLOW, "flg=0x%08x", tag->flags); | ||
883 | if(tag->hdr.flags & SB_INST_LAST_TAG) | ||
884 | { | ||
885 | printf(OFF, " | "); | ||
886 | printf(RED, " Last section"); | ||
887 | } | ||
888 | printf(OFF, "\n"); | ||
889 | offset += sizeof(struct sb_instruction_tag_t); | ||
890 | |||
891 | char name[5]; | ||
892 | fill_section_name(name, tag->identifier); | ||
893 | int pos = offset; | ||
894 | int size = tag->len * BLOCK_SIZE; | ||
895 | int data_sec = !(tag->flags & SECTION_BOOTABLE); | ||
896 | int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0; | ||
897 | |||
898 | printf(GREEN, "%sSection ", indent); | ||
899 | printf(YELLOW, "'%s'\n", name); | ||
900 | printf(GREEN, "%s pos = ", indent); | ||
901 | printf(YELLOW, "%8x - %8x\n", pos, pos+size); | ||
902 | printf(GREEN, "%s len = ", indent); | ||
903 | printf(YELLOW, "%8x\n", size); | ||
904 | printf(GREEN, "%s flags = ", indent); | ||
905 | printf(YELLOW, "%8x", tag->flags); | ||
906 | if(data_sec) | ||
907 | printf(RED, " Data Section"); | ||
908 | else | ||
909 | printf(RED, " Boot Section"); | ||
910 | if(encrypted) | ||
911 | printf(RED, " (Encrypted)"); | ||
912 | printf(OFF, "\n"); | ||
913 | |||
914 | /* save it */ | ||
915 | byte *sec = xmalloc(size); | ||
916 | if(encrypted) | ||
917 | cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0); | ||
918 | else | ||
919 | memcpy(sec, buf + pos, size); | ||
920 | |||
921 | struct sb_section_t *s = read_section(data_sec, tag->identifier, | ||
922 | sec, size, " ", u, cprintf); | ||
923 | if(s) | ||
924 | { | ||
925 | s->is_cleartext = !encrypted; | ||
926 | s->alignment = guess_alignment(pos); | ||
927 | sb_file->sections = augment_array(sb_file->sections, | ||
928 | sizeof(struct sb_section_t), sb_file->nr_sections++, | ||
929 | s, 1); | ||
930 | free(s); | ||
931 | } | ||
932 | free(sec); | ||
933 | |||
934 | /* last one ? */ | ||
935 | if(tag->hdr.flags & SB_INST_LAST_TAG) | ||
936 | break; | ||
937 | offset += size; | ||
938 | } | ||
939 | else | ||
940 | { | ||
941 | printf(RED, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset); | ||
942 | break; | ||
943 | } | ||
944 | } | ||
945 | } | ||
946 | |||
947 | /* final signature */ | ||
948 | printf(BLUE, "Final signature:\n"); | ||
949 | byte decrypted_block[32]; | ||
950 | if(sb_header->nr_keys > 0) | ||
951 | { | ||
952 | printf(GREEN, " Encrypted SHA-1:\n"); | ||
953 | byte *encrypted_block = &buf[filesize - 32]; | ||
954 | printf(OFF, " "); | ||
955 | print_hex(YELLOW, encrypted_block, 16, true); | ||
956 | printf(OFF, " "); | ||
957 | print_hex(YELLOW, encrypted_block + 16, 16, true); | ||
958 | /* decrypt it */ | ||
959 | cbc_mac(encrypted_block, decrypted_block, 2, real_key, buf, NULL, 0); | ||
960 | } | ||
961 | else | ||
962 | memcpy(decrypted_block, &buf[filesize - 32], 32); | ||
963 | printf(GREEN, " File SHA-1:\n "); | ||
964 | print_hex(YELLOW, decrypted_block, 20, false); | ||
965 | /* check it */ | ||
966 | sha_1_init(&sha_1_params); | ||
967 | sha_1_update(&sha_1_params, buf, filesize - 32); | ||
968 | sha_1_finish(&sha_1_params); | ||
969 | sha_1_output(&sha_1_params, computed_sha1); | ||
970 | if(memcmp(decrypted_block, computed_sha1, 20) == 0) | ||
971 | printf(RED, " Ok\n"); | ||
972 | else | ||
973 | printf(RED, " Failed\n"); | ||
974 | free(buf); | ||
975 | |||
976 | return sb_file; | ||
977 | #undef printf | ||
978 | #undef fatal | ||
979 | #undef print_hex | ||
980 | } | ||
981 | |||
982 | void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf) | ||
983 | { | ||
984 | #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__) | ||
985 | #define print_hex(c, p, len, nl) \ | ||
986 | do { printf(c, ""); print_hex(p, len, nl); } while(0) | ||
987 | |||
988 | #define TREE RED | ||
989 | #define HEADER GREEN | ||
990 | #define TEXT YELLOW | ||
991 | #define TEXT2 BLUE | ||
992 | #define SEP OFF | ||
993 | |||
994 | printf(HEADER, "SB File\n"); | ||
995 | printf(TREE, "+-"); | ||
996 | printf(HEADER, "Version: "); | ||
997 | printf(TEXT, "1.%d\n", file->minor_version); | ||
998 | printf(TREE, "+-"); | ||
999 | printf(HEADER, "Flags: "); | ||
1000 | printf(TEXT, "%x\n", file->flags); | ||
1001 | printf(TREE, "+-"); | ||
1002 | printf(HEADER, "Drive Tag: "); | ||
1003 | printf(TEXT, "%x\n", file->drive_tag); | ||
1004 | printf(TREE, "+-"); | ||
1005 | printf(HEADER, "First Boot Section ID: "); | ||
1006 | char name[5]; | ||
1007 | fill_section_name(name, file->first_boot_sec_id); | ||
1008 | printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name); | ||
1009 | |||
1010 | if(file->real_key) | ||
1011 | { | ||
1012 | printf(TREE, "+-"); | ||
1013 | printf(HEADER, "Real key: "); | ||
1014 | print_hex(TEXT, *file->real_key, 16, true); | ||
1015 | } | ||
1016 | if(file->crypto_iv) | ||
1017 | { | ||
1018 | printf(TREE, "+-"); | ||
1019 | printf(HEADER, "IV : "); | ||
1020 | print_hex(TEXT, *file->crypto_iv, 16, true); | ||
1021 | } | ||
1022 | printf(TREE, "+-"); | ||
1023 | printf(HEADER, "Product Version: "); | ||
1024 | printf(TEXT, "%X.%X.%X\n", file->product_ver.major, file->product_ver.minor, | ||
1025 | file->product_ver.revision); | ||
1026 | printf(TREE, "+-"); | ||
1027 | printf(HEADER, "Component Version: "); | ||
1028 | printf(TEXT, "%X.%X.%X\n", file->component_ver.major, file->component_ver.minor, | ||
1029 | file->component_ver.revision); | ||
1030 | |||
1031 | for(int i = 0; i < file->nr_sections; i++) | ||
1032 | { | ||
1033 | struct sb_section_t *sec = &file->sections[i]; | ||
1034 | printf(TREE, "+-"); | ||
1035 | printf(HEADER, "Section\n"); | ||
1036 | printf(TREE,"| +-"); | ||
1037 | printf(HEADER, "Identifier: "); | ||
1038 | fill_section_name(name, sec->identifier); | ||
1039 | printf(TEXT, "%08x (%s)\n", sec->identifier, name); | ||
1040 | printf(TREE, "| +-"); | ||
1041 | printf(HEADER, "Type: "); | ||
1042 | printf(TEXT, "%s (%s)\n", sec->is_data ? "Data Section" : "Boot Section", | ||
1043 | sec->is_cleartext ? "Cleartext" : "Encrypted"); | ||
1044 | printf(TREE, "| +-"); | ||
1045 | printf(HEADER, "Alignment: "); | ||
1046 | printf(TEXT, "%d (bytes)\n", sec->alignment); | ||
1047 | printf(TREE, "| +-"); | ||
1048 | printf(HEADER, "Instructions\n"); | ||
1049 | for(int j = 0; j < sec->nr_insts; j++) | ||
1050 | { | ||
1051 | struct sb_inst_t *inst = &sec->insts[j]; | ||
1052 | printf(TREE, "| | +-"); | ||
1053 | switch(inst->inst) | ||
1054 | { | ||
1055 | case SB_INST_DATA: | ||
1056 | printf(HEADER, "DATA"); | ||
1057 | printf(SEP, " | "); | ||
1058 | printf(TEXT, "size=0x%08x\n", inst->size); | ||
1059 | break; | ||
1060 | case SB_INST_CALL: | ||
1061 | case SB_INST_JUMP: | ||
1062 | printf(HEADER, "%s", inst->inst == SB_INST_CALL ? "CALL" : "JUMP"); | ||
1063 | printf(SEP, " | "); | ||
1064 | printf(TEXT, "addr=0x%08x", inst->addr); | ||
1065 | printf(SEP, " | "); | ||
1066 | printf(TEXT2, "arg=0x%08x\n", inst->argument); | ||
1067 | break; | ||
1068 | case SB_INST_LOAD: | ||
1069 | printf(HEADER, "LOAD"); | ||
1070 | printf(SEP, " | "); | ||
1071 | printf(TEXT, "addr=0x%08x", inst->addr); | ||
1072 | printf(SEP, " | "); | ||
1073 | printf(TEXT2, "len=0x%08x\n", inst->size); | ||
1074 | break; | ||
1075 | case SB_INST_FILL: | ||
1076 | printf(HEADER, "FILL"); | ||
1077 | printf(SEP, " | "); | ||
1078 | printf(TEXT, "addr=0x%08x", inst->addr); | ||
1079 | printf(SEP, " | "); | ||
1080 | printf(TEXT2, "len=0x%08x", inst->size); | ||
1081 | printf(SEP, " | "); | ||
1082 | printf(TEXT2, "pattern=0x%08x\n", inst->pattern); | ||
1083 | break; | ||
1084 | case SB_INST_MODE: | ||
1085 | printf(HEADER, "MODE"); | ||
1086 | printf(SEP, " | "); | ||
1087 | printf(TEXT, "mod=0x%08x\n", inst->addr); | ||
1088 | break; | ||
1089 | case SB_INST_NOP: | ||
1090 | printf(HEADER, "NOOP\n"); | ||
1091 | break; | ||
1092 | default: | ||
1093 | printf(GREY, "[Unknown instruction %x]\n", inst->inst); | ||
1094 | } | ||
1095 | } | ||
1096 | } | ||
1097 | |||
1098 | #undef printf | ||
1099 | #undef print_hex | ||
1100 | } | ||
diff --git a/utils/sbtools/sb.h b/utils/sbtools/sb.h index 27f5668d2e..548b3ef55a 100644 --- a/utils/sbtools/sb.h +++ b/utils/sbtools/sb.h | |||
@@ -24,6 +24,8 @@ | |||
24 | #include <stdint.h> | 24 | #include <stdint.h> |
25 | #include <stdbool.h> | 25 | #include <stdbool.h> |
26 | 26 | ||
27 | #include "misc.h" | ||
28 | |||
27 | #define BLOCK_SIZE 16 | 29 | #define BLOCK_SIZE 16 |
28 | 30 | ||
29 | /* All fields are in big-endian BCD */ | 31 | /* All fields are in big-endian BCD */ |
@@ -161,12 +163,12 @@ struct sb_inst_t | |||
161 | { | 163 | { |
162 | uint8_t inst; /* SB_INST_* */ | 164 | uint8_t inst; /* SB_INST_* */ |
163 | uint32_t size; | 165 | uint32_t size; |
166 | uint32_t addr; | ||
164 | // <union> | 167 | // <union> |
165 | void *data; | 168 | void *data; |
166 | uint32_t pattern; | 169 | uint32_t pattern; |
167 | uint32_t addr; | ||
168 | // </union> | 170 | // </union> |
169 | uint32_t argument; // for call and jump | 171 | uint32_t argument; // for call, jump and mode |
170 | /* for production use */ | 172 | /* for production use */ |
171 | uint32_t padding_size; | 173 | uint32_t padding_size; |
172 | uint8_t *padding; | 174 | uint8_t *padding; |
@@ -194,6 +196,10 @@ struct sb_file_t | |||
194 | uint8_t (*crypto_iv)[16]; | 196 | uint8_t (*crypto_iv)[16]; |
195 | 197 | ||
196 | int nr_sections; | 198 | int nr_sections; |
199 | uint16_t drive_tag; | ||
200 | uint32_t first_boot_sec_id; | ||
201 | uint16_t flags; | ||
202 | uint8_t minor_version; | ||
197 | struct sb_section_t *sections; | 203 | struct sb_section_t *sections; |
198 | struct sb_version_t product_ver; | 204 | struct sb_version_t product_ver; |
199 | struct sb_version_t component_ver; | 205 | struct sb_version_t component_ver; |
@@ -201,6 +207,12 @@ struct sb_file_t | |||
201 | uint32_t image_size; /* in blocks */ | 207 | uint32_t image_size; /* in blocks */ |
202 | }; | 208 | }; |
203 | 209 | ||
204 | void sb_produce_file(struct sb_file_t *sb, const char *filename); | 210 | void sb_write_file(struct sb_file_t *sb, const char *filename); |
211 | |||
212 | typedef void (*sb_color_printf)(void *u, bool err, color_t c, const char *f, ...); | ||
213 | struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u, | ||
214 | sb_color_printf printf); | ||
215 | |||
216 | void sb_dump(struct sb_file_t *file, void *u, sb_color_printf printf); | ||
205 | 217 | ||
206 | #endif /* __SB_H__ */ | 218 | #endif /* __SB_H__ */ |
diff --git a/utils/sbtools/sbtoelf.c b/utils/sbtools/sbtoelf.c index 24417dc88e..0199ffb4f5 100644 --- a/utils/sbtools/sbtoelf.c +++ b/utils/sbtools/sbtoelf.c | |||
@@ -56,19 +56,7 @@ | |||
56 | 56 | ||
57 | /* globals */ | 57 | /* globals */ |
58 | 58 | ||
59 | uint8_t *g_buf; /* file content */ | ||
60 | char *g_out_prefix; | 59 | char *g_out_prefix; |
61 | bool g_debug; | ||
62 | bool g_raw_mode; | ||
63 | |||
64 | static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr) | ||
65 | { | ||
66 | uint8_t sum = 90; | ||
67 | byte *ptr = (byte *)hdr; | ||
68 | for(int i = 1; i < 16; i++) | ||
69 | sum += ptr[i]; | ||
70 | return sum; | ||
71 | } | ||
72 | 60 | ||
73 | static void elf_printf(void *user, bool error, const char *fmt, ...) | 61 | static void elf_printf(void *user, bool error, const char *fmt, ...) |
74 | { | 62 | { |
@@ -104,614 +92,34 @@ static void extract_elf_section(struct elf_params_t *elf, int count, const char | |||
104 | fclose(fd); | 92 | fclose(fd); |
105 | } | 93 | } |
106 | 94 | ||
107 | static void extract_section(int data_sec, char name[5], byte *buf, int size, const char *indent) | 95 | static void usage(void) |
108 | { | ||
109 | char *filename = xmalloc(strlen(g_out_prefix) + strlen(name) + 5); | ||
110 | if(g_out_prefix) | ||
111 | { | ||
112 | sprintf(filename, "%s%s.bin", g_out_prefix, name); | ||
113 | FILE *fd = fopen(filename, "wb"); | ||
114 | if (fd != NULL) | ||
115 | { | ||
116 | fwrite(buf, size, 1, fd); | ||
117 | fclose(fd); | ||
118 | } | ||
119 | } | ||
120 | if(data_sec) | ||
121 | return; | ||
122 | |||
123 | sprintf(filename, "%s%s", g_out_prefix, name); | ||
124 | |||
125 | /* elf construction */ | ||
126 | struct elf_params_t elf; | ||
127 | elf_init(&elf); | ||
128 | int elf_count = 0; | ||
129 | /* Pretty print the content */ | ||
130 | int pos = 0; | ||
131 | while(pos < size) | ||
132 | { | ||
133 | struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)&buf[pos]; | ||
134 | printf("%s", indent); | ||
135 | uint8_t checksum = instruction_checksum(hdr); | ||
136 | if(checksum != hdr->checksum) | ||
137 | { | ||
138 | color(GREY); | ||
139 | printf("[Bad checksum]"); | ||
140 | } | ||
141 | if(hdr->flags != 0) | ||
142 | { | ||
143 | color(GREY); | ||
144 | printf("["); | ||
145 | color(BLUE); | ||
146 | printf("f=%x", hdr->flags); | ||
147 | color(GREY); | ||
148 | printf("] "); | ||
149 | } | ||
150 | if(hdr->opcode == SB_INST_LOAD) | ||
151 | { | ||
152 | struct sb_instruction_load_t *load = (struct sb_instruction_load_t *)&buf[pos]; | ||
153 | color(RED); | ||
154 | printf("LOAD"); | ||
155 | color(OFF);printf(" | "); | ||
156 | color(BLUE); | ||
157 | printf("addr=0x%08x", load->addr); | ||
158 | color(OFF);printf(" | "); | ||
159 | color(GREEN); | ||
160 | printf("len=0x%08x", load->len); | ||
161 | color(OFF);printf(" | "); | ||
162 | color(YELLOW); | ||
163 | printf("crc=0x%08x", load->crc); | ||
164 | /* data is padded to 16-byte boundary with random data and crc'ed with it */ | ||
165 | uint32_t computed_crc = crc(&buf[pos + sizeof(struct sb_instruction_load_t)], | ||
166 | ROUND_UP(load->len, 16)); | ||
167 | color(RED); | ||
168 | if(load->crc == computed_crc) | ||
169 | printf(" Ok\n"); | ||
170 | else | ||
171 | printf(" Failed (crc=0x%08x)\n", computed_crc); | ||
172 | |||
173 | /* elf construction */ | ||
174 | elf_add_load_section(&elf, load->addr, load->len, | ||
175 | &buf[pos + sizeof(struct sb_instruction_load_t)]); | ||
176 | |||
177 | pos += load->len + sizeof(struct sb_instruction_load_t); | ||
178 | } | ||
179 | else if(hdr->opcode == SB_INST_FILL) | ||
180 | { | ||
181 | struct sb_instruction_fill_t *fill = (struct sb_instruction_fill_t *)&buf[pos]; | ||
182 | color(RED); | ||
183 | printf("FILL"); | ||
184 | color(OFF);printf(" | "); | ||
185 | color(BLUE); | ||
186 | printf("addr=0x%08x", fill->addr); | ||
187 | color(OFF);printf(" | "); | ||
188 | color(GREEN); | ||
189 | printf("len=0x%08x", fill->len); | ||
190 | color(OFF);printf(" | "); | ||
191 | color(YELLOW); | ||
192 | printf("pattern=0x%08x\n", fill->pattern); | ||
193 | color(OFF); | ||
194 | |||
195 | /* elf construction */ | ||
196 | elf_add_fill_section(&elf, fill->addr, fill->len, fill->pattern); | ||
197 | |||
198 | pos += sizeof(struct sb_instruction_fill_t); | ||
199 | } | ||
200 | else if(hdr->opcode == SB_INST_CALL || | ||
201 | hdr->opcode == SB_INST_JUMP) | ||
202 | { | ||
203 | int is_call = (hdr->opcode == SB_INST_CALL); | ||
204 | struct sb_instruction_call_t *call = (struct sb_instruction_call_t *)&buf[pos]; | ||
205 | color(RED); | ||
206 | if(is_call) | ||
207 | printf("CALL"); | ||
208 | else | ||
209 | printf("JUMP"); | ||
210 | color(OFF);printf(" | "); | ||
211 | color(BLUE); | ||
212 | printf("addr=0x%08x", call->addr); | ||
213 | color(OFF);printf(" | "); | ||
214 | color(GREEN); | ||
215 | printf("arg=0x%08x\n", call->arg); | ||
216 | color(OFF); | ||
217 | |||
218 | /* elf construction */ | ||
219 | elf_set_start_addr(&elf, call->addr); | ||
220 | extract_elf_section(&elf, elf_count++, filename, indent); | ||
221 | elf_release(&elf); | ||
222 | elf_init(&elf); | ||
223 | |||
224 | pos += sizeof(struct sb_instruction_call_t); | ||
225 | } | ||
226 | else if(hdr->opcode == SB_INST_MODE) | ||
227 | { | ||
228 | struct sb_instruction_mode_t *mode = (struct sb_instruction_mode_t *)hdr; | ||
229 | color(RED); | ||
230 | printf("MODE"); | ||
231 | color(OFF);printf(" | "); | ||
232 | color(BLUE); | ||
233 | printf("mod=0x%08x\n", mode->mode); | ||
234 | color(OFF); | ||
235 | pos += sizeof(struct sb_instruction_mode_t); | ||
236 | } | ||
237 | else if(hdr->opcode == SB_INST_NOP) | ||
238 | { | ||
239 | color(RED); | ||
240 | printf("NOOP\n"); | ||
241 | pos += sizeof(struct sb_instruction_mode_t); | ||
242 | } | ||
243 | else | ||
244 | { | ||
245 | color(RED); | ||
246 | printf("Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos); | ||
247 | break; | ||
248 | } | ||
249 | |||
250 | pos = ROUND_UP(pos, BLOCK_SIZE); | ||
251 | } | ||
252 | |||
253 | if(!elf_is_empty(&elf)) | ||
254 | extract_elf_section(&elf, elf_count++, filename, indent); | ||
255 | elf_release(&elf); | ||
256 | } | ||
257 | |||
258 | static void fill_section_name(char name[5], uint32_t identifier) | ||
259 | { | ||
260 | name[0] = (identifier >> 24) & 0xff; | ||
261 | name[1] = (identifier >> 16) & 0xff; | ||
262 | name[2] = (identifier >> 8) & 0xff; | ||
263 | name[3] = identifier & 0xff; | ||
264 | for(int i = 0; i < 4; i++) | ||
265 | if(!isprint(name[i])) | ||
266 | name[i] = '_'; | ||
267 | name[4] = 0; | ||
268 | } | ||
269 | |||
270 | static uint16_t swap16(uint16_t t) | ||
271 | { | ||
272 | return (t << 8) | (t >> 8); | ||
273 | } | ||
274 | |||
275 | static void fix_version(struct sb_version_t *ver) | ||
276 | { | ||
277 | ver->major = swap16(ver->major); | ||
278 | ver->minor = swap16(ver->minor); | ||
279 | ver->revision = swap16(ver->revision); | ||
280 | } | ||
281 | |||
282 | static void extract(unsigned long filesize) | ||
283 | { | ||
284 | struct sha_1_params_t sha_1_params; | ||
285 | /* Basic header info */ | ||
286 | struct sb_header_t *sb_header = (struct sb_header_t *)g_buf; | ||
287 | |||
288 | if(memcmp(sb_header->signature, "STMP", 4) != 0) | ||
289 | bugp("Bad signature"); | ||
290 | /* | ||
291 | if(sb_header->image_size * BLOCK_SIZE > filesize) | ||
292 | bugp("File size mismatch"); | ||
293 | */ | ||
294 | if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t)) | ||
295 | bugp("Bad header size"); | ||
296 | if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t)) | ||
297 | bugp("Bad section header size"); | ||
298 | |||
299 | if(filesize > sb_header->image_size * BLOCK_SIZE) | ||
300 | { | ||
301 | color(GREY); | ||
302 | printf("[Restrict file size from %lu to %d bytes]\n", filesize, | ||
303 | sb_header->image_size * BLOCK_SIZE); | ||
304 | filesize = sb_header->image_size * BLOCK_SIZE; | ||
305 | } | ||
306 | |||
307 | color(BLUE); | ||
308 | printf("Basic info:\n"); | ||
309 | color(GREEN); | ||
310 | printf(" SB version: "); | ||
311 | color(YELLOW); | ||
312 | printf("%d.%d\n", sb_header->major_ver, sb_header->minor_ver); | ||
313 | color(GREEN); | ||
314 | printf(" Header SHA-1: "); | ||
315 | byte *hdr_sha1 = sb_header->sha1_header; | ||
316 | color(YELLOW); | ||
317 | print_hex(hdr_sha1, 20, false); | ||
318 | /* Check SHA1 sum */ | ||
319 | byte computed_sha1[20]; | ||
320 | sha_1_init(&sha_1_params); | ||
321 | sha_1_update(&sha_1_params, &sb_header->signature[0], | ||
322 | sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header)); | ||
323 | sha_1_finish(&sha_1_params); | ||
324 | sha_1_output(&sha_1_params, computed_sha1); | ||
325 | color(RED); | ||
326 | if(memcmp(hdr_sha1, computed_sha1, 20) == 0) | ||
327 | printf(" Ok\n"); | ||
328 | else | ||
329 | printf(" Failed\n"); | ||
330 | color(GREEN); | ||
331 | printf(" Flags: "); | ||
332 | color(YELLOW); | ||
333 | printf("%x\n", sb_header->flags); | ||
334 | color(GREEN); | ||
335 | printf(" Total file size : "); | ||
336 | color(YELLOW); | ||
337 | printf("%ld\n", filesize); | ||
338 | |||
339 | /* Sizes and offsets */ | ||
340 | color(BLUE); | ||
341 | printf("Sizes and offsets:\n"); | ||
342 | color(GREEN); | ||
343 | printf(" # of encryption keys = "); | ||
344 | color(YELLOW); | ||
345 | printf("%d\n", sb_header->nr_keys); | ||
346 | color(GREEN); | ||
347 | printf(" # of sections = "); | ||
348 | color(YELLOW); | ||
349 | printf("%d\n", sb_header->nr_sections); | ||
350 | |||
351 | /* Versions */ | ||
352 | color(BLUE); | ||
353 | printf("Versions\n"); | ||
354 | color(GREEN); | ||
355 | |||
356 | printf(" Random 1: "); | ||
357 | color(YELLOW); | ||
358 | print_hex(sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true); | ||
359 | color(GREEN); | ||
360 | printf(" Random 2: "); | ||
361 | color(YELLOW); | ||
362 | print_hex(sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true); | ||
363 | |||
364 | uint64_t micros = sb_header->timestamp; | ||
365 | time_t seconds = (micros / (uint64_t)1000000L); | ||
366 | struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */ | ||
367 | seconds += mktime(&tm_base); | ||
368 | struct tm *time = gmtime(&seconds); | ||
369 | color(GREEN); | ||
370 | printf(" Creation date/time = "); | ||
371 | color(YELLOW); | ||
372 | printf("%s", asctime(time)); | ||
373 | |||
374 | struct sb_version_t product_ver = sb_header->product_ver; | ||
375 | fix_version(&product_ver); | ||
376 | struct sb_version_t component_ver = sb_header->component_ver; | ||
377 | fix_version(&component_ver); | ||
378 | |||
379 | color(GREEN); | ||
380 | printf(" Product version = "); | ||
381 | color(YELLOW); | ||
382 | printf("%X.%X.%X\n", product_ver.major, product_ver.minor, product_ver.revision); | ||
383 | color(GREEN); | ||
384 | printf(" Component version = "); | ||
385 | color(YELLOW); | ||
386 | printf("%X.%X.%X\n", component_ver.major, component_ver.minor, component_ver.revision); | ||
387 | |||
388 | color(GREEN); | ||
389 | printf(" Drive tag = "); | ||
390 | color(YELLOW); | ||
391 | printf("%x\n", sb_header->drive_tag); | ||
392 | color(GREEN); | ||
393 | printf(" First boot tag offset = "); | ||
394 | color(YELLOW); | ||
395 | printf("%x\n", sb_header->first_boot_tag_off); | ||
396 | color(GREEN); | ||
397 | printf(" First boot section ID = "); | ||
398 | color(YELLOW); | ||
399 | printf("0x%08x\n", sb_header->first_boot_sec_id); | ||
400 | |||
401 | /* encryption cbc-mac */ | ||
402 | byte real_key[16]; | ||
403 | bool valid_key = false; /* false until a matching key was found */ | ||
404 | if(sb_header->nr_keys > 0) | ||
405 | { | ||
406 | if(sb_header->nr_keys > g_nr_keys) | ||
407 | { | ||
408 | color(GREY); | ||
409 | bug("SB file has %d keys but only %d were specified on command line\n", | ||
410 | sb_header->nr_keys, g_nr_keys); | ||
411 | } | ||
412 | color(BLUE); | ||
413 | printf("Encryption data\n"); | ||
414 | for(int i = 0; i < sb_header->nr_keys; i++) | ||
415 | { | ||
416 | color(RED); | ||
417 | printf(" Key %d: ", i); | ||
418 | print_key(&g_key_array[i], true); | ||
419 | color(GREEN); | ||
420 | printf(" CBC-MAC of headers: "); | ||
421 | |||
422 | uint32_t ofs = sizeof(struct sb_header_t) | ||
423 | + sizeof(struct sb_section_header_t) * sb_header->nr_sections | ||
424 | + sizeof(struct sb_key_dictionary_entry_t) * i; | ||
425 | struct sb_key_dictionary_entry_t *dict_entry = | ||
426 | (struct sb_key_dictionary_entry_t *)&g_buf[ofs]; | ||
427 | /* cbc mac */ | ||
428 | color(YELLOW); | ||
429 | print_hex(dict_entry->hdr_cbc_mac, 16, false); | ||
430 | /* check it */ | ||
431 | byte computed_cbc_mac[16]; | ||
432 | byte zero[16]; | ||
433 | memset(zero, 0, 16); | ||
434 | crypto_cbc(g_buf, NULL, sb_header->header_size + sb_header->nr_sections, | ||
435 | &g_key_array[i], zero, &computed_cbc_mac, 1); | ||
436 | color(RED); | ||
437 | bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0; | ||
438 | if(ok) | ||
439 | { | ||
440 | valid_key = true; | ||
441 | printf(" Ok\n"); | ||
442 | } | ||
443 | else | ||
444 | printf(" Failed\n"); | ||
445 | color(GREEN); | ||
446 | |||
447 | printf(" Encrypted key : "); | ||
448 | color(YELLOW); | ||
449 | print_hex(dict_entry->key, 16, true); | ||
450 | color(GREEN); | ||
451 | /* decrypt */ | ||
452 | byte decrypted_key[16]; | ||
453 | byte iv[16]; | ||
454 | memcpy(iv, g_buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */ | ||
455 | crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[i], iv, NULL, 0); | ||
456 | printf(" Decrypted key : "); | ||
457 | color(YELLOW); | ||
458 | print_hex(decrypted_key, 16, false); | ||
459 | /* cross-check or copy */ | ||
460 | if(valid_key && ok) | ||
461 | memcpy(real_key, decrypted_key, 16); | ||
462 | else if(valid_key) | ||
463 | { | ||
464 | if(memcmp(real_key, decrypted_key, 16) == 0) | ||
465 | { | ||
466 | color(RED); | ||
467 | printf(" Cross-Check Ok"); | ||
468 | } | ||
469 | else | ||
470 | { | ||
471 | color(RED); | ||
472 | printf(" Cross-Check Failed"); | ||
473 | } | ||
474 | } | ||
475 | printf("\n"); | ||
476 | } | ||
477 | } | ||
478 | |||
479 | if(getenv("SB_REAL_KEY") != 0) | ||
480 | { | ||
481 | struct crypto_key_t k; | ||
482 | char *env = getenv("SB_REAL_KEY"); | ||
483 | if(!parse_key(&env, &k) || *env) | ||
484 | bug("Invalid SB_REAL_KEY"); | ||
485 | memcpy(real_key, k.u.key, 16); | ||
486 | } | ||
487 | |||
488 | color(RED); | ||
489 | printf(" Summary:\n"); | ||
490 | color(GREEN); | ||
491 | printf(" Real key: "); | ||
492 | color(YELLOW); | ||
493 | print_hex(real_key, 16, true); | ||
494 | color(GREEN); | ||
495 | printf(" IV : "); | ||
496 | color(YELLOW); | ||
497 | print_hex(g_buf, 16, true); | ||
498 | |||
499 | /* sections */ | ||
500 | if(!g_raw_mode) | ||
501 | { | ||
502 | color(BLUE); | ||
503 | printf("Sections\n"); | ||
504 | for(int i = 0; i < sb_header->nr_sections; i++) | ||
505 | { | ||
506 | uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t); | ||
507 | struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&g_buf[ofs]; | ||
508 | |||
509 | char name[5]; | ||
510 | fill_section_name(name, sec_hdr->identifier); | ||
511 | int pos = sec_hdr->offset * BLOCK_SIZE; | ||
512 | int size = sec_hdr->size * BLOCK_SIZE; | ||
513 | int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE); | ||
514 | int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0; | ||
515 | |||
516 | color(GREEN); | ||
517 | printf(" Section "); | ||
518 | color(YELLOW); | ||
519 | printf("'%s'\n", name); | ||
520 | color(GREEN); | ||
521 | printf(" pos = "); | ||
522 | color(YELLOW); | ||
523 | printf("%8x - %8x\n", pos, pos+size); | ||
524 | color(GREEN); | ||
525 | printf(" len = "); | ||
526 | color(YELLOW); | ||
527 | printf("%8x\n", size); | ||
528 | color(GREEN); | ||
529 | printf(" flags = "); | ||
530 | color(YELLOW); | ||
531 | printf("%8x", sec_hdr->flags); | ||
532 | color(RED); | ||
533 | if(data_sec) | ||
534 | printf(" Data Section"); | ||
535 | else | ||
536 | printf(" Boot Section"); | ||
537 | if(encrypted) | ||
538 | printf(" (Encrypted)"); | ||
539 | printf("\n"); | ||
540 | |||
541 | /* save it */ | ||
542 | byte *sec = xmalloc(size); | ||
543 | if(encrypted) | ||
544 | cbc_mac(g_buf + pos, sec, size / BLOCK_SIZE, real_key, g_buf, NULL, 0); | ||
545 | else | ||
546 | memcpy(sec, g_buf + pos, size); | ||
547 | |||
548 | extract_section(data_sec, name, sec, size, " "); | ||
549 | free(sec); | ||
550 | } | ||
551 | } | ||
552 | else | ||
553 | { | ||
554 | /* advanced raw mode */ | ||
555 | color(BLUE); | ||
556 | printf("Commands\n"); | ||
557 | uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE; | ||
558 | byte iv[16]; | ||
559 | const char *indent = " "; | ||
560 | while(true) | ||
561 | { | ||
562 | /* restart with IV */ | ||
563 | memcpy(iv, g_buf, 16); | ||
564 | byte cmd[BLOCK_SIZE]; | ||
565 | if(sb_header->nr_keys > 0) | ||
566 | cbc_mac(g_buf + offset, cmd, 1, real_key, iv, &iv, 0); | ||
567 | else | ||
568 | memcpy(cmd, g_buf + offset, BLOCK_SIZE); | ||
569 | struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd; | ||
570 | printf("%s", indent); | ||
571 | uint8_t checksum = instruction_checksum(hdr); | ||
572 | if(checksum != hdr->checksum) | ||
573 | { | ||
574 | color(GREY); | ||
575 | printf("[Bad checksum']"); | ||
576 | } | ||
577 | |||
578 | if(hdr->opcode == SB_INST_NOP) | ||
579 | { | ||
580 | color(RED); | ||
581 | printf("NOOP\n"); | ||
582 | offset += BLOCK_SIZE; | ||
583 | } | ||
584 | else if(hdr->opcode == SB_INST_TAG) | ||
585 | { | ||
586 | struct sb_instruction_tag_t *tag = (struct sb_instruction_tag_t *)hdr; | ||
587 | color(RED); | ||
588 | printf("BTAG"); | ||
589 | color(OFF);printf(" | "); | ||
590 | color(BLUE); | ||
591 | printf("sec=0x%08x", tag->identifier); | ||
592 | color(OFF);printf(" | "); | ||
593 | color(GREEN); | ||
594 | printf("cnt=0x%08x", tag->len); | ||
595 | color(OFF);printf(" | "); | ||
596 | color(YELLOW); | ||
597 | printf("flg=0x%08x", tag->flags); | ||
598 | color(OFF); | ||
599 | if(tag->hdr.flags & SB_INST_LAST_TAG) | ||
600 | { | ||
601 | printf(" | "); | ||
602 | color(RED); | ||
603 | printf(" Last section"); | ||
604 | color(OFF); | ||
605 | } | ||
606 | printf("\n"); | ||
607 | offset += sizeof(struct sb_instruction_tag_t); | ||
608 | |||
609 | char name[5]; | ||
610 | fill_section_name(name, tag->identifier); | ||
611 | int pos = offset; | ||
612 | int size = tag->len * BLOCK_SIZE; | ||
613 | int data_sec = !(tag->flags & SECTION_BOOTABLE); | ||
614 | int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0; | ||
615 | |||
616 | color(GREEN); | ||
617 | printf("%sSection ", indent); | ||
618 | color(YELLOW); | ||
619 | printf("'%s'\n", name); | ||
620 | color(GREEN); | ||
621 | printf("%s pos = ", indent); | ||
622 | color(YELLOW); | ||
623 | printf("%8x - %8x\n", pos, pos+size); | ||
624 | color(GREEN); | ||
625 | printf("%s len = ", indent); | ||
626 | color(YELLOW); | ||
627 | printf("%8x\n", size); | ||
628 | color(GREEN); | ||
629 | printf("%s flags = ", indent); | ||
630 | color(YELLOW); | ||
631 | printf("%8x", tag->flags); | ||
632 | color(RED); | ||
633 | if(data_sec) | ||
634 | printf(" Data Section"); | ||
635 | else | ||
636 | printf(" Boot Section"); | ||
637 | if(encrypted) | ||
638 | printf(" (Encrypted)"); | ||
639 | printf("\n"); | ||
640 | |||
641 | /* save it */ | ||
642 | byte *sec = xmalloc(size); | ||
643 | if(encrypted) | ||
644 | cbc_mac(g_buf + pos, sec, size / BLOCK_SIZE, real_key, g_buf, NULL, 0); | ||
645 | else | ||
646 | memcpy(sec, g_buf + pos, size); | ||
647 | |||
648 | extract_section(data_sec, name, sec, size, " "); | ||
649 | free(sec); | ||
650 | |||
651 | /* last one ? */ | ||
652 | if(tag->hdr.flags & SB_INST_LAST_TAG) | ||
653 | break; | ||
654 | offset += size; | ||
655 | } | ||
656 | else | ||
657 | { | ||
658 | color(RED); | ||
659 | printf("Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset); | ||
660 | break; | ||
661 | } | ||
662 | } | ||
663 | } | ||
664 | |||
665 | /* final signature */ | ||
666 | color(BLUE); | ||
667 | printf("Final signature:\n"); | ||
668 | byte decrypted_block[32]; | ||
669 | if(sb_header->nr_keys > 0) | ||
670 | { | ||
671 | color(GREEN); | ||
672 | printf(" Encrypted SHA-1:\n"); | ||
673 | color(YELLOW); | ||
674 | byte *encrypted_block = &g_buf[filesize - 32]; | ||
675 | printf(" "); | ||
676 | print_hex(encrypted_block, 16, true); | ||
677 | printf(" "); | ||
678 | print_hex(encrypted_block + 16, 16, true); | ||
679 | /* decrypt it */ | ||
680 | cbc_mac(encrypted_block, decrypted_block, 2, real_key, g_buf, NULL, 0); | ||
681 | } | ||
682 | else | ||
683 | memcpy(decrypted_block, &g_buf[filesize - 32], 32); | ||
684 | color(GREEN); | ||
685 | printf(" File SHA-1:\n "); | ||
686 | color(YELLOW); | ||
687 | print_hex(decrypted_block, 20, false); | ||
688 | /* check it */ | ||
689 | sha_1_init(&sha_1_params); | ||
690 | sha_1_update(&sha_1_params, g_buf, filesize - 32); | ||
691 | sha_1_finish(&sha_1_params); | ||
692 | sha_1_output(&sha_1_params, computed_sha1); | ||
693 | color(RED); | ||
694 | if(memcmp(decrypted_block, computed_sha1, 20) == 0) | ||
695 | printf(" Ok\n"); | ||
696 | else | ||
697 | printf(" Failed\n"); | ||
698 | } | ||
699 | |||
700 | void usage(void) | ||
701 | { | 96 | { |
702 | printf("Usage: sbtoelf [options] sb-file\n"); | 97 | printf("Usage: sbtoelf [options] sb-file\n"); |
703 | printf("Options:\n"); | 98 | printf("Options:\n"); |
704 | printf(" -?/--help\tDisplay this message\n"); | 99 | printf(" -?/--help\tDisplay this message\n"); |
705 | printf(" -o <file>\tSet output prefix\n"); | 100 | printf(" -o <file>\tSet output prefix\n"); |
706 | printf(" -d/--debug\tEnable debug output\n"); | 101 | printf(" -d/--debug\tEnable debug output*\n"); |
707 | printf(" -k <file>\tAdd key file\n"); | 102 | printf(" -k <file>\tAdd key file\n"); |
708 | printf(" -z\t\tAdd zero key\n"); | 103 | printf(" -z\t\tAdd zero key\n"); |
709 | printf(" -r\t\tUse raw command mode\n"); | 104 | printf(" -r\t\tUse raw command mode\n"); |
710 | printf(" -a/--add-key <key>\tAdd single key (hex or usbotp)\n"); | 105 | printf(" -a/--add-key <key>\tAdd single key (hex or usbotp)\n"); |
711 | printf(" -n/--no-color\tDisable output colors\n"); | 106 | printf(" -n/--no-color\tDisable output colors\n"); |
107 | printf(" -l/--loopback <file>\tProduce sb file out of extracted description*\n"); | ||
108 | printf("Options marked with a * are for debug purpose only\n"); | ||
712 | exit(1); | 109 | exit(1); |
713 | } | 110 | } |
714 | 111 | ||
112 | static void sb_printf(void *user, bool error, color_t c, const char *fmt, ...) | ||
113 | { | ||
114 | (void) user; | ||
115 | (void) error; | ||
116 | va_list args; | ||
117 | va_start(args, fmt); | ||
118 | color(c); | ||
119 | vprintf(fmt, args); | ||
120 | va_end(args); | ||
121 | } | ||
122 | |||
715 | static struct crypto_key_t g_zero_key = | 123 | static struct crypto_key_t g_zero_key = |
716 | { | 124 | { |
717 | .method = CRYPTO_KEY, | 125 | .method = CRYPTO_KEY, |
@@ -720,6 +128,9 @@ static struct crypto_key_t g_zero_key = | |||
720 | 128 | ||
721 | int main(int argc, char **argv) | 129 | int main(int argc, char **argv) |
722 | { | 130 | { |
131 | bool raw_mode = false; | ||
132 | const char *loopback = NULL; | ||
133 | |||
723 | while(1) | 134 | while(1) |
724 | { | 135 | { |
725 | static struct option long_options[] = | 136 | static struct option long_options[] = |
@@ -728,16 +139,22 @@ int main(int argc, char **argv) | |||
728 | {"debug", no_argument, 0, 'd'}, | 139 | {"debug", no_argument, 0, 'd'}, |
729 | {"add-key", required_argument, 0, 'a'}, | 140 | {"add-key", required_argument, 0, 'a'}, |
730 | {"no-color", no_argument, 0, 'n'}, | 141 | {"no-color", no_argument, 0, 'n'}, |
142 | {"loopback", required_argument, 0, 'l'}, | ||
731 | {0, 0, 0, 0} | 143 | {0, 0, 0, 0} |
732 | }; | 144 | }; |
733 | 145 | ||
734 | int c = getopt_long(argc, argv, "?do:k:zra:n", long_options, NULL); | 146 | int c = getopt_long(argc, argv, "?do:k:zra:nl:", long_options, NULL); |
735 | if(c == -1) | 147 | if(c == -1) |
736 | break; | 148 | break; |
737 | switch(c) | 149 | switch(c) |
738 | { | 150 | { |
739 | case -1: | 151 | case -1: |
740 | break; | 152 | break; |
153 | case 'l': | ||
154 | if(loopback) | ||
155 | bug("Only one loopback file can be specified !\n"); | ||
156 | loopback = optarg; | ||
157 | break; | ||
741 | case 'n': | 158 | case 'n': |
742 | enable_color(false); | 159 | enable_color(false); |
743 | break; | 160 | break; |
@@ -761,7 +178,7 @@ int main(int argc, char **argv) | |||
761 | break; | 178 | break; |
762 | } | 179 | } |
763 | case 'r': | 180 | case 'r': |
764 | g_raw_mode = true; | 181 | raw_mode = true; |
765 | break; | 182 | break; |
766 | case 'a': | 183 | case 'a': |
767 | { | 184 | { |
@@ -788,24 +205,26 @@ int main(int argc, char **argv) | |||
788 | return 1; | 205 | return 1; |
789 | } | 206 | } |
790 | 207 | ||
791 | const char *sb_file = argv[optind]; | 208 | const char *sb_filename = argv[optind]; |
792 | FILE *fd = fopen(sb_file, "rb"); | ||
793 | if(fd == NULL) | ||
794 | bug("Cannot open input file\n"); | ||
795 | fseek(fd, 0, SEEK_END); | ||
796 | size_t size = ftell(fd); | ||
797 | fseek(fd, 0, SEEK_SET); | ||
798 | |||
799 | g_buf = xmalloc(size); | ||
800 | if(fread(g_buf, 1, size, fd) != size) /* load the whole file into memory */ | ||
801 | bugp("reading firmware"); | ||
802 | |||
803 | fclose(fd); | ||
804 | |||
805 | extract(size); | ||
806 | 209 | ||
807 | color(OFF); | 210 | struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf); |
808 | 211 | if(g_debug) | |
809 | free(g_buf); | 212 | { |
213 | color(GREY); | ||
214 | printf("[Debug output]\n"); | ||
215 | sb_dump(file, NULL, sb_printf); | ||
216 | } | ||
217 | if(loopback) | ||
218 | { | ||
219 | /* sb_read_file will fill real key and IV but we don't want to override | ||
220 | * them when looping back otherwise the output will be inconsistent and | ||
221 | * garbage */ | ||
222 | free(file->real_key); | ||
223 | file->real_key = NULL; | ||
224 | free(file->crypto_iv); | ||
225 | file->crypto_iv = NULL; | ||
226 | sb_write_file(file, loopback); | ||
227 | } | ||
228 | |||
810 | return 0; | 229 | return 0; |
811 | } | 230 | } |