summaryrefslogtreecommitdiff
path: root/utils/sbtools
diff options
context:
space:
mode:
Diffstat (limited to 'utils/sbtools')
-rw-r--r--utils/sbtools/dbparser.c10
-rw-r--r--utils/sbtools/elf.c2
-rw-r--r--utils/sbtools/elftosb.c10
-rw-r--r--utils/sbtools/misc.h2
-rw-r--r--utils/sbtools/sb.c680
-rw-r--r--utils/sbtools/sb.h18
-rw-r--r--utils/sbtools/sbtoelf.c673
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"
28typedef uint8_t byte;
29
30extern bool g_debug;
31extern void *xmalloc(size_t s);
32extern 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
37enum lexem_type_t 29enum 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,
223void elf_write_file(struct elf_params_t *params, elf_write_fn_t write, 223void 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
295void sb_produce_file(struct sb_file_t *sb, const char *filename) 302void 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
435static void *memdup(void *p, size_t len)
436{
437 void *cpy = xmalloc(len);
438 memcpy(cpy, p, len);
439 return cpy;
440}
441
442static 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
574static 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
586static 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
597struct 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
982void 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
204void sb_produce_file(struct sb_file_t *sb, const char *filename); 210void sb_write_file(struct sb_file_t *sb, const char *filename);
211
212typedef void (*sb_color_printf)(void *u, bool err, color_t c, const char *f, ...);
213struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
214 sb_color_printf printf);
215
216void 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
59uint8_t *g_buf; /* file content */
60char *g_out_prefix; 59char *g_out_prefix;
61bool g_debug;
62bool g_raw_mode;
63
64static 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
73static void elf_printf(void *user, bool error, const char *fmt, ...) 61static 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
107static void extract_section(int data_sec, char name[5], byte *buf, int size, const char *indent) 95static 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
258static 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
270static uint16_t swap16(uint16_t t)
271{
272 return (t << 8) | (t >> 8);
273}
274
275static 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
282static 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
700void 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
112static 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
715static struct crypto_key_t g_zero_key = 123static 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
721int main(int argc, char **argv) 129int 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}