summaryrefslogtreecommitdiff
path: root/utils/sbtools
diff options
context:
space:
mode:
authorAmaury Pouly <pamaury@rockbox.org>2011-10-29 17:01:47 +0000
committerAmaury Pouly <pamaury@rockbox.org>2011-10-29 17:01:47 +0000
commitd2a58f3aadf33e11bcbc4743cac65d4464447db8 (patch)
treec800fee3b6598b86aa3ff3aaf971d4ad5d6e9d06 /utils/sbtools
parent93c6c79e8d2ee39056afe7f8145b051d4a0e8d38 (diff)
downloadrockbox-d2a58f3aadf33e11bcbc4743cac65d4464447db8.tar.gz
rockbox-d2a58f3aadf33e11bcbc4743cac65d4464447db8.zip
sbtools: move sb file production to its own file with a clean api, factor key reading even more
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30851 a1c6a512-1295-4272-9138-f99709370657
Diffstat (limited to 'utils/sbtools')
-rw-r--r--utils/sbtools/Makefile4
-rw-r--r--utils/sbtools/elftosb.c485
-rw-r--r--utils/sbtools/misc.c127
-rw-r--r--utils/sbtools/misc.h7
-rw-r--r--utils/sbtools/sb.c426
-rw-r--r--utils/sbtools/sb.h53
-rw-r--r--utils/sbtools/sbtoelf.c8
7 files changed, 574 insertions, 536 deletions
diff --git a/utils/sbtools/Makefile b/utils/sbtools/Makefile
index 15d3adb8a1..e4db3bf335 100644
--- a/utils/sbtools/Makefile
+++ b/utils/sbtools/Makefile
@@ -9,10 +9,10 @@ all: elftosb sbtoelf
9%.o: %.c 9%.o: %.c
10 $(CC) $(CFLAGS) -c -o $@ $< 10 $(CC) $(CFLAGS) -c -o $@ $<
11 11
12sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o elf.o misc.o 12sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o elf.o misc.o sb.o
13 $(LD) $(LDFLAGS) -o $@ $^ 13 $(LD) $(LDFLAGS) -o $@ $^
14 14
15elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o 15elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o sb.o
16 $(LD) $(LDFLAGS) -o $@ $^ 16 $(LD) $(LDFLAGS) -o $@ $^
17 17
18clean: 18clean:
diff --git a/utils/sbtools/elftosb.c b/utils/sbtools/elftosb.c
index 5e65ba3261..3e217a8979 100644
--- a/utils/sbtools/elftosb.c
+++ b/utils/sbtools/elftosb.c
@@ -35,6 +35,7 @@
35#include "sb.h" 35#include "sb.h"
36#include "dbparser.h" 36#include "dbparser.h"
37#include "misc.h" 37#include "misc.h"
38#include "sb.h"
38 39
39char **g_extern; 40char **g_extern;
40int g_extern_count; 41int g_extern_count;
@@ -51,47 +52,6 @@ int g_extern_count;
51 * command file to sb conversion 52 * command file to sb conversion
52 */ 53 */
53 54
54#define SB_INST_DATA 0xff
55
56struct sb_inst_t
57{
58 uint8_t inst; /* SB_INST_* */
59 uint32_t size;
60 // <union>
61 void *data;
62 uint32_t pattern;
63 uint32_t addr;
64 // </union>
65 uint32_t argument; // for call and jump
66 /* for production use */
67 uint32_t padding_size;
68 uint8_t *padding;
69};
70
71struct sb_section_t
72{
73 uint32_t identifier;
74 bool is_data;
75 bool is_cleartext;
76 uint32_t alignment;
77 // data sections are handled as a single SB_INST_DATA virtual instruction
78 int nr_insts;
79 struct sb_inst_t *insts;
80 /* for production use */
81 uint32_t file_offset; /* in blocks */
82 uint32_t sec_size; /* in blocks */
83};
84
85struct sb_file_t
86{
87 int nr_sections;
88 struct sb_section_t *sections;
89 struct sb_version_t product_ver;
90 struct sb_version_t component_ver;
91 /* for production use */
92 uint32_t image_size; /* in blocks */
93};
94
95static bool elf_read(void *user, uint32_t addr, void *buf, size_t count) 55static bool elf_read(void *user, uint32_t addr, void *buf, size_t count)
96{ 56{
97 if(fseek((FILE *)user, addr, SEEK_SET) == -1) 57 if(fseek((FILE *)user, addr, SEEK_SET) == -1)
@@ -355,443 +315,6 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
355 return sb; 315 return sb;
356} 316}
357 317
358/**
359 * SB file production
360 */
361
362/* helper function to augment an array, free old array */
363void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt)
364{
365 void *p = xmalloc(elem_sz * (cnt + aug_cnt));
366 memcpy(p, arr, elem_sz * cnt);
367 memcpy(p + elem_sz * cnt, aug, elem_sz * aug_cnt);
368 free(arr);
369 return p;
370}
371
372static void fill_gaps(struct sb_file_t *sb)
373{
374 for(int i = 0; i < sb->nr_sections; i++)
375 {
376 struct sb_section_t *sec = &sb->sections[i];
377 for(int j = 0; j < sec->nr_insts; j++)
378 {
379 struct sb_inst_t *inst = &sec->insts[j];
380 if(inst->inst != SB_INST_LOAD)
381 continue;
382 inst->padding_size = ROUND_UP(inst->size, BLOCK_SIZE) - inst->size;
383 /* emulate elftosb2 behaviour: generate 15 bytes (that's a safe maximum) */
384 inst->padding = xmalloc(15);
385 generate_random_data(inst->padding, 15);
386 }
387 }
388}
389
390static void compute_sb_offsets(struct sb_file_t *sb)
391{
392 sb->image_size = 0;
393 /* sb header */
394 sb->image_size += sizeof(struct sb_header_t) / BLOCK_SIZE;
395 /* sections headers */
396 sb->image_size += sb->nr_sections * sizeof(struct sb_section_header_t) / BLOCK_SIZE;
397 /* key dictionary */
398 sb->image_size += g_nr_keys * sizeof(struct sb_key_dictionary_entry_t) / BLOCK_SIZE;
399 /* sections */
400 for(int i = 0; i < sb->nr_sections; i++)
401 {
402 /* each section has a preliminary TAG command */
403 sb->image_size += sizeof(struct sb_instruction_tag_t) / BLOCK_SIZE;
404 /* we might need to pad the section so compute next alignment */
405 uint32_t alignment = BLOCK_SIZE;
406 if((i + 1) < sb->nr_sections)
407 alignment = sb->sections[i + 1].alignment;
408 alignment /= BLOCK_SIZE; /* alignment in block sizes */
409
410 struct sb_section_t *sec = &sb->sections[i];
411
412 if(g_debug)
413 {
414 printf("%s section 0x%08x", sec->is_data ? "Data" : "Boot",
415 sec->identifier);
416 if(sec->is_cleartext)
417 printf(" (cleartext)");
418 printf("\n");
419 }
420
421 sec->file_offset = sb->image_size;
422 for(int j = 0; j < sec->nr_insts; j++)
423 {
424 struct sb_inst_t *inst = &sec->insts[j];
425 if(inst->inst == SB_INST_CALL || inst->inst == SB_INST_JUMP)
426 {
427 if(g_debug)
428 printf(" %s | addr=0x%08x | arg=0x%08x\n",
429 inst->inst == SB_INST_CALL ? "CALL" : "JUMP", inst->addr, inst->argument);
430 sb->image_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE;
431 sec->sec_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE;
432 }
433 else if(inst->inst == SB_INST_FILL)
434 {
435 if(g_debug)
436 printf(" FILL | addr=0x%08x | len=0x%08x | pattern=0x%08x\n",
437 inst->addr, inst->size, inst->pattern);
438 sb->image_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE;
439 sec->sec_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE;
440 }
441 else if(inst->inst == SB_INST_LOAD)
442 {
443 if(g_debug)
444 printf(" LOAD | addr=0x%08x | len=0x%08x\n", inst->addr, inst->size);
445 /* load header */
446 sb->image_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE;
447 sec->sec_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE;
448 /* data + alignment */
449 sb->image_size += (inst->size + inst->padding_size) / BLOCK_SIZE;
450 sec->sec_size += (inst->size + inst->padding_size) / BLOCK_SIZE;
451 }
452 else if(inst->inst == SB_INST_MODE)
453 {
454 if(g_debug)
455 printf(" MODE | mod=0x%08x", inst->addr);
456 sb->image_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE;
457 sec->sec_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE;
458 }
459 else if(inst->inst == SB_INST_DATA)
460 {
461 if(g_debug)
462 printf(" DATA | size=0x%08x\n", inst->size);
463 sb->image_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE;
464 sec->sec_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE;
465 }
466 else
467 bug("die on inst %d\n", inst->inst);
468 }
469 /* we need to make sure next section starts on the right alignment.
470 * Since each section starts with a boot tag, we thus need to ensure
471 * that this sections ends at adress X such that X+BLOCK_SIZE is
472 * a multiple of the alignment.
473 * For data sections, we just add random data, otherwise we add nops */
474 uint32_t missing_sz = alignment - ((sb->image_size + 1) % alignment);
475 if(missing_sz != alignment)
476 {
477 struct sb_inst_t *aug_insts;
478 int nr_aug_insts = 0;
479
480 if(sb->sections[i].is_data)
481 {
482 nr_aug_insts = 1;
483 aug_insts = malloc(sizeof(struct sb_inst_t));
484 memset(aug_insts, 0, sizeof(struct sb_inst_t));
485 aug_insts[0].inst = SB_INST_DATA;
486 aug_insts[0].size = missing_sz * BLOCK_SIZE;
487 aug_insts[0].data = xmalloc(missing_sz * BLOCK_SIZE);
488 generate_random_data(aug_insts[0].data, missing_sz * BLOCK_SIZE);
489 if(g_debug)
490 printf(" DATA | size=0x%08x\n", aug_insts[0].size);
491 }
492 else
493 {
494 nr_aug_insts = missing_sz;
495 aug_insts = malloc(sizeof(struct sb_inst_t) * nr_aug_insts);
496 memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts);
497 for(int j = 0; j < nr_aug_insts; j++)
498 {
499 aug_insts[j].inst = SB_INST_NOP;
500 if(g_debug)
501 printf(" NOOP\n");
502 }
503 }
504
505 sb->sections[i].insts = augment_array(sb->sections[i].insts, sizeof(struct sb_inst_t),
506 sb->sections[i].nr_insts, aug_insts, nr_aug_insts);
507 sb->sections[i].nr_insts += nr_aug_insts;
508
509 /* augment image and section size */
510 sb->image_size += missing_sz;
511 sec->sec_size += missing_sz;
512 }
513 }
514 /* final signature */
515 sb->image_size += 2;
516}
517
518static uint64_t generate_timestamp()
519{
520 struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */
521 time_t t = time(NULL) - mktime(&tm_base);
522 return (uint64_t)t * 1000000L;
523}
524
525static uint16_t swap16(uint16_t t)
526{
527 return (t << 8) | (t >> 8);
528}
529
530static void fix_version(struct sb_version_t *ver)
531{
532 ver->major = swap16(ver->major);
533 ver->minor = swap16(ver->minor);
534 ver->revision = swap16(ver->revision);
535}
536
537static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr)
538{
539 struct sha_1_params_t sha_1_params;
540
541 sb_hdr->signature[0] = 'S';
542 sb_hdr->signature[1] = 'T';
543 sb_hdr->signature[2] = 'M';
544 sb_hdr->signature[3] = 'P';
545 sb_hdr->major_ver = IMAGE_MAJOR_VERSION;
546 sb_hdr->minor_ver = IMAGE_MINOR_VERSION;
547 sb_hdr->flags = 0;
548 sb_hdr->image_size = sb->image_size;
549 sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE;
550 sb_hdr->first_boot_sec_id = sb->sections[0].identifier;
551 sb_hdr->nr_keys = g_nr_keys;
552 sb_hdr->nr_sections = sb->nr_sections;
553 sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE;
554 sb_hdr->key_dict_off = sb_hdr->header_size +
555 sb_hdr->sec_hdr_size * sb_hdr->nr_sections;
556 sb_hdr->first_boot_tag_off = sb_hdr->key_dict_off +
557 sizeof(struct sb_key_dictionary_entry_t) * sb_hdr->nr_keys / BLOCK_SIZE;
558 generate_random_data(sb_hdr->rand_pad0, sizeof(sb_hdr->rand_pad0));
559 generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1));
560 sb_hdr->timestamp = generate_timestamp();
561 sb_hdr->product_ver = sb->product_ver;
562 fix_version(&sb_hdr->product_ver);
563 sb_hdr->component_ver = sb->component_ver;
564 fix_version(&sb_hdr->component_ver);
565 sb_hdr->drive_tag = 0;
566
567 sha_1_init(&sha_1_params);
568 sha_1_update(&sha_1_params, &sb_hdr->signature[0],
569 sizeof(struct sb_header_t) - sizeof(sb_hdr->sha1_header));
570 sha_1_finish(&sha_1_params);
571 sha_1_output(&sha_1_params, sb_hdr->sha1_header);
572}
573
574static void produce_sb_section_header(struct sb_section_t *sec,
575 struct sb_section_header_t *sec_hdr)
576{
577 sec_hdr->identifier = sec->identifier;
578 sec_hdr->offset = sec->file_offset;
579 sec_hdr->size = sec->sec_size;
580 sec_hdr->flags = (sec->is_data ? 0 : SECTION_BOOTABLE)
581 | (sec->is_cleartext ? SECTION_CLEARTEXT : 0);
582}
583
584static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr)
585{
586 uint8_t sum = 90;
587 byte *ptr = (byte *)hdr;
588 for(int i = 1; i < 16; i++)
589 sum += ptr[i];
590 return sum;
591}
592
593static void produce_section_tag_cmd(struct sb_section_t *sec,
594 struct sb_instruction_tag_t *tag, bool is_last)
595{
596 tag->hdr.opcode = SB_INST_TAG;
597 tag->hdr.flags = is_last ? SB_INST_LAST_TAG : 0;
598 tag->identifier = sec->identifier;
599 tag->len = sec->sec_size;
600 tag->flags = (sec->is_data ? 0 : SECTION_BOOTABLE)
601 | (sec->is_cleartext ? SECTION_CLEARTEXT : 0);
602 tag->hdr.checksum = instruction_checksum(&tag->hdr);
603}
604
605void produce_sb_instruction(struct sb_inst_t *inst,
606 struct sb_instruction_common_t *cmd)
607{
608 memset(cmd, 0, sizeof(struct sb_instruction_common_t));
609 cmd->hdr.opcode = inst->inst;
610 switch(inst->inst)
611 {
612 case SB_INST_CALL:
613 case SB_INST_JUMP:
614 cmd->addr = inst->addr;
615 cmd->data = inst->argument;
616 break;
617 case SB_INST_FILL:
618 cmd->addr = inst->addr;
619 cmd->len = inst->size;
620 cmd->data = inst->pattern;
621 break;
622 case SB_INST_LOAD:
623 cmd->addr = inst->addr;
624 cmd->len = inst->size;
625 cmd->data = crc_continue(crc(inst->data, inst->size),
626 inst->padding, inst->padding_size);
627 break;
628 case SB_INST_MODE:
629 cmd->data = inst->addr;
630 break;
631 case SB_INST_NOP:
632 break;
633 default:
634 bug("die\n");
635 }
636 cmd->hdr.checksum = instruction_checksum(&cmd->hdr);
637}
638
639static void produce_sb_file(struct sb_file_t *sb, const char *filename)
640{
641 FILE *fd = fopen(filename, "wb");
642 if(fd == NULL)
643 bugp("cannot open output file");
644
645 struct crypto_key_t real_key;
646 real_key.method = CRYPTO_KEY;
647 byte crypto_iv[16];
648 byte (*cbc_macs)[16] = xmalloc(16 * g_nr_keys);
649 /* init CBC-MACs */
650 for(int i = 0; i < g_nr_keys; i++)
651 memset(cbc_macs[i], 0, 16);
652
653 fill_gaps(sb);
654 compute_sb_offsets(sb);
655
656 generate_random_data(real_key.u.key, 16);
657
658 /* global SHA-1 */
659 struct sha_1_params_t file_sha1;
660 sha_1_init(&file_sha1);
661 /* produce and write header */
662 struct sb_header_t sb_hdr;
663 produce_sb_header(sb, &sb_hdr);
664 sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr));
665 fwrite(&sb_hdr, 1, sizeof(sb_hdr), fd);
666
667 memcpy(crypto_iv, &sb_hdr, 16);
668
669 /* update CBC-MACs */
670 for(int i = 0; i < g_nr_keys; i++)
671 crypto_cbc((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE, &g_key_array[i],
672 cbc_macs[i], &cbc_macs[i], 1);
673
674 /* produce and write section headers */
675 for(int i = 0; i < sb_hdr.nr_sections; i++)
676 {
677 struct sb_section_header_t sb_sec_hdr;
678 produce_sb_section_header(&sb->sections[i], &sb_sec_hdr);
679 sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr));
680 fwrite(&sb_sec_hdr, 1, sizeof(sb_sec_hdr), fd);
681 /* update CBC-MACs */
682 for(int j = 0; j < g_nr_keys; j++)
683 crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
684 &g_key_array[j], cbc_macs[j], &cbc_macs[j], 1);
685 }
686 /* produce key dictionary */
687 for(int i = 0; i < g_nr_keys; i++)
688 {
689 struct sb_key_dictionary_entry_t entry;
690 memcpy(entry.hdr_cbc_mac, cbc_macs[i], 16);
691 crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i],
692 crypto_iv, NULL, 1);
693
694 fwrite(&entry, 1, sizeof(entry), fd);
695 sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry));
696 }
697
698 /* HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK */
699 /* Image crafting, don't use it unless you understand what you do */
700 if(strlen(s_getenv("SB_OVERRIDE_REAL_KEY")) != 0)
701 {
702 const char *key = s_getenv("SB_OVERRIDE_REAL_KEY");
703 if(strlen(key) != 32)
704 bugp("Cannot override real key: invalid key length\n");
705 for(int i = 0; i < 16; i++)
706 {
707 byte a, b;
708 if(convxdigit(key[2 * i], &a) || convxdigit(key[2 * i + 1], &b))
709 bugp("Cannot override real key: key should be a 128-bit key written in hexadecimal\n");
710 real_key.u.key[i] = (a << 4) | b;
711 }
712 }
713 if(strlen(s_getenv("SB_OVERRIDE_IV")) != 0)
714 {
715 const char *iv = s_getenv("SB_OVERRIDE_IV");
716 if(strlen(iv) != 32)
717 bugp("Cannot override iv: invalid key length\n");
718 for(int i = 0; i < 16; i++)
719 {
720 byte a, b;
721 if(convxdigit(iv[2 * i], &a) || convxdigit(iv[2 * i + 1], &b))
722 bugp("Cannot override iv: key should be a 128-bit key written in hexadecimal\n");
723 crypto_iv[i] = (a << 4) | b;
724 }
725
726 }
727 /* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */
728 if(g_debug)
729 {
730 printf("Real key: ");
731 for(int j = 0; j < 16; j++)
732 printf("%02x", real_key.u.key[j]);
733 printf("\n");
734 printf("IV : ");
735 for(int j = 0; j < 16; j++)
736 printf("%02x", crypto_iv[j]);
737 printf("\n");
738 }
739 /* produce sections data */
740 for(int i = 0; i< sb_hdr.nr_sections; i++)
741 {
742 /* produce tag command */
743 struct sb_instruction_tag_t tag_cmd;
744 produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections);
745 if(g_nr_keys > 0)
746 crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
747 &real_key, crypto_iv, NULL, 1);
748 sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd));
749 fwrite(&tag_cmd, 1, sizeof(tag_cmd), fd);
750 /* produce other commands */
751 byte cur_cbc_mac[16];
752 memcpy(cur_cbc_mac, crypto_iv, 16);
753 for(int j = 0; j < sb->sections[i].nr_insts; j++)
754 {
755 struct sb_inst_t *inst = &sb->sections[i].insts[j];
756 /* command */
757 if(inst->inst != SB_INST_DATA)
758 {
759 struct sb_instruction_common_t cmd;
760 produce_sb_instruction(inst, &cmd);
761 if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
762 crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
763 &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
764 sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
765 fwrite(&cmd, 1, sizeof(cmd), fd);
766 }
767 /* data */
768 if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA)
769 {
770 uint32_t sz = inst->size + inst->padding_size;
771 byte *data = xmalloc(sz);
772 memcpy(data, inst->data, inst->size);
773 memcpy(data + inst->size, inst->padding, inst->padding_size);
774 if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
775 crypto_cbc(data, data, sz / BLOCK_SIZE,
776 &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
777 sha_1_update(&file_sha1, data, sz);
778 fwrite(data, 1, sz, fd);
779 free(data);
780 }
781 }
782 }
783 /* write file SHA-1 */
784 byte final_sig[32];
785 sha_1_finish(&file_sha1);
786 sha_1_output(&file_sha1, final_sig);
787 generate_random_data(final_sig + 20, 12);
788 if(g_nr_keys > 0)
789 crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1);
790 fwrite(final_sig, 1, 32, fd);
791
792 fclose(fd);
793}
794
795void usage(void) 318void usage(void)
796{ 319{
797 printf("Usage: elftosb [options | file]...\n"); 320 printf("Usage: elftosb [options | file]...\n");
@@ -848,9 +371,7 @@ int main(int argc, char **argv)
848 break; 371 break;
849 case 'k': 372 case 'k':
850 { 373 {
851 int kac; 374 add_keys_from_file(optarg);
852 key_array_t ka = read_keys(optarg, &kac);
853 add_keys(ka, kac);
854 break; 375 break;
855 } 376 }
856 case 'z': 377 case 'z':
@@ -922,7 +443,7 @@ int main(int argc, char **argv)
922 443
923 struct cmd_file_t *cmd_file = db_parse_file(cmd_filename); 444 struct cmd_file_t *cmd_file = db_parse_file(cmd_filename);
924 struct sb_file_t *sb_file = apply_cmd_file(cmd_file); 445 struct sb_file_t *sb_file = apply_cmd_file(cmd_file);
925 produce_sb_file(sb_file, output_filename); 446 sb_produce_file(sb_file, output_filename);
926 447
927 return 0; 448 return 0;
928} 449}
diff --git a/utils/sbtools/misc.c b/utils/sbtools/misc.c
index 09a8919aef..39934951ae 100644
--- a/utils/sbtools/misc.c
+++ b/utils/sbtools/misc.c
@@ -29,13 +29,6 @@ bool g_debug = false;
29/** 29/**
30 * Misc 30 * Misc
31 */ 31 */
32
33char *s_getenv(const char *name)
34{
35 char *s = getenv(name);
36 return s ? s : "";
37}
38
39void generate_random_data(void *buf, size_t sz) 32void generate_random_data(void *buf, size_t sz)
40{ 33{
41 FILE *rand_fd = fopen("/dev/urandom", "rb"); 34 FILE *rand_fd = fopen("/dev/urandom", "rb");
@@ -74,12 +67,73 @@ int convxdigit(char digit, byte *val)
74 return 1; 67 return 1;
75} 68}
76 69
70/* helper function to augment an array, free old array */
71void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt)
72{
73 void *p = xmalloc(elem_sz * (cnt + aug_cnt));
74 memcpy(p, arr, elem_sz * cnt);
75 memcpy(p + elem_sz * cnt, aug, elem_sz * aug_cnt);
76 free(arr);
77 return p;
78}
79
77/** 80/**
78 * Key file parsing 81 * Key file parsing
79 */ 82 */
80int g_nr_keys; 83int g_nr_keys;
81key_array_t g_key_array; 84key_array_t g_key_array;
82 85
86bool parse_key(char **pstr, struct crypto_key_t *key)
87{
88 char *str = *pstr;
89 /* ignore spaces */
90 while(isspace(*str))
91 str++;
92 /* CRYPTO_KEY: 32 hex characters
93 * CRYPTO_USBOTP: usbotp(vid:pid) where vid and pid are hex numbers */
94 if(isxdigit(str[0]))
95 {
96 if(strlen(str) < 32)
97 return false;
98 for(int j = 0; j < 16; j++)
99 {
100 byte a, b;
101 if(convxdigit(str[2 * j], &a) || convxdigit(str[2 * j + 1], &b))
102 return false;
103 key->u.key[j] = (a << 4) | b;
104 }
105 /* skip key */
106 *pstr = str + 32;
107 key->method = CRYPTO_KEY;
108 return true;
109 }
110 else
111 {
112 const char *prefix = "usbotp(";
113 if(strlen(str) < strlen(prefix))
114 return false;
115 if(strncmp(str, prefix, strlen(prefix)) != 0)
116 return false;
117 str += strlen(prefix);
118 /* vid */
119 long vid = strtol(str, &str, 16);
120 if(vid < 0 || vid > 0xffff)
121 return false;
122 if(*str++ != ':')
123 return false;
124 /* pid */
125 long pid = strtol(str, &str, 16);
126 if(pid < 0 || pid > 0xffff)
127 return false;
128 if(*str++ != ')')
129 return false;
130 *pstr = str;
131 key->method = CRYPTO_USBOTP;
132 key->u.vid_pid = vid << 16 | pid;
133 return true;
134 }
135}
136
83void add_keys(key_array_t ka, int kac) 137void add_keys(key_array_t ka, int kac)
84{ 138{
85 key_array_t new_ka = xmalloc((g_nr_keys + kac) * sizeof(struct crypto_key_t)); 139 key_array_t new_ka = xmalloc((g_nr_keys + kac) * sizeof(struct crypto_key_t));
@@ -90,61 +144,46 @@ void add_keys(key_array_t ka, int kac)
90 g_nr_keys += kac; 144 g_nr_keys += kac;
91} 145}
92 146
93key_array_t read_keys(const char *key_file, int *num_keys) 147void add_keys_from_file(const char *key_file)
94{ 148{
95 int size; 149 int size;
96 FILE *fd = fopen(key_file, "r"); 150 FILE *fd = fopen(key_file, "r");
97 if(fd == NULL) 151 if(fd == NULL)
98 bugp("opening key file failed"); 152 bug("opening key file failed");
99 fseek(fd, 0, SEEK_END); 153 fseek(fd, 0, SEEK_END);
100 size = ftell(fd); 154 size = ftell(fd);
101 fseek(fd, 0, SEEK_SET); 155 fseek(fd, 0, SEEK_SET);
102 char *buf = xmalloc(size); 156 char *buf = xmalloc(size + 1);
103 if(fread(buf, size, 1, fd) != (size_t)size) 157 if(fread(buf, 1, size, fd) != (size_t)size)
104 bugp("reading key file"); 158 bug("reading key file");
159 buf[size] = 0;
105 fclose(fd); 160 fclose(fd);
106 161
107 if(g_debug) 162 if(g_debug)
108 printf("Parsing key file '%s'...\n", key_file); 163 printf("Parsing key file '%s'...\n", key_file);
109 *num_keys = size ? 1 : 0; 164 char *p = buf;
110 char *ptr = buf; 165 while(1)
111 /* allow trailing newline at the end (but no space after it) */
112 while(ptr != buf + size && (ptr + 1) != buf + size)
113 {
114 if(*ptr++ == '\n')
115 (*num_keys)++;
116 }
117
118 key_array_t keys = xmalloc(sizeof(struct crypto_key_t) * *num_keys);
119 int pos = 0;
120 for(int i = 0; i < *num_keys; i++)
121 { 166 {
122 /* skip ws */ 167 struct crypto_key_t k;
123 while(pos < size && isspace(buf[pos])) 168 /* parse key */
124 pos++; 169 if(!parse_key(&p, &k))
125 /* enough space ? */ 170 bug("invalid key file");
126 if((pos + 32) > size)
127 bugp("invalid key file");
128 keys[i].method = CRYPTO_KEY;
129 for(int j = 0; j < 16; j++)
130 {
131 byte a, b;
132 if(convxdigit(buf[pos + 2 * j], &a) || convxdigit(buf[pos + 2 * j + 1], &b))
133 bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n");
134 keys[i].u.key[j] = (a << 4) | b;
135 }
136 if(g_debug) 171 if(g_debug)
137 { 172 {
138 printf("Add key: "); 173 printf("Add key: ");
139 for(int j = 0; j < 16; j++) 174 print_key(&k, true);
140 printf("%02x", keys[i].u.key[j]);
141 printf("\n");
142 } 175 }
143 pos += 32; 176 add_keys(&k, 1);
177 /* request at least one space character before next key, or end of file */
178 if(*p != 0 && !isspace(*p))
179 bug("invalid key file");
180 /* skip whitespace */
181 while(isspace(*p))
182 p++;
183 if(*p == 0)
184 break;
144 } 185 }
145 free(buf); 186 free(buf);
146
147 return keys;
148} 187}
149 188
150void print_hex(byte *data, int len, bool newline) 189void print_hex(byte *data, int len, bool newline)
diff --git a/utils/sbtools/misc.h b/utils/sbtools/misc.h
index 545285eafc..cc0a3fb5ea 100644
--- a/utils/sbtools/misc.h
+++ b/utils/sbtools/misc.h
@@ -30,19 +30,22 @@
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(a) do { perror("ERROR: "a); exit(1); } while(0)
32 32
33#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
34
33extern bool g_debug; 35extern bool g_debug;
34 36
35typedef struct crypto_key_t *key_array_t; 37typedef struct crypto_key_t *key_array_t;
36int g_nr_keys; 38int g_nr_keys;
37key_array_t g_key_array; 39key_array_t g_key_array;
38 40
39char *s_getenv(const char *name); 41void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt);
40void generate_random_data(void *buf, size_t sz); 42void generate_random_data(void *buf, size_t sz);
41void *xmalloc(size_t s); 43void *xmalloc(size_t s);
42int convxdigit(char digit, byte *val); 44int convxdigit(char digit, byte *val);
43void print_hex(byte *data, int len, bool newline); 45void print_hex(byte *data, int len, bool newline);
44void add_keys(key_array_t ka, int kac); 46void add_keys(key_array_t ka, int kac);
45key_array_t read_keys(const char *key_file, int *num_keys); 47bool parse_key(char **str, struct crypto_key_t *key);
48void add_keys_from_file(const char *key_file);
46void print_key(struct crypto_key_t *key, bool newline); 49void print_key(struct crypto_key_t *key, bool newline);
47 50
48#endif /* __MISC_H__ */ 51#endif /* __MISC_H__ */
diff --git a/utils/sbtools/sb.c b/utils/sbtools/sb.c
new file mode 100644
index 0000000000..3921710a2d
--- /dev/null
+++ b/utils/sbtools/sb.c
@@ -0,0 +1,426 @@
1/***************************************************************************
2 * __________ __ ___.
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
7 * \/ \/ \/ \/ \/
8 * $Id$
9 *
10 * Copyright (C) 2011 Amaury Pouly
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
16 *
17 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
18 * KIND, either express or implied.
19 *
20 ****************************************************************************/
21#include <stdio.h>
22#include <time.h>
23#include <stdlib.h>
24#include "misc.h"
25#include "crypto.h"
26#include "sb.h"
27
28static void fill_gaps(struct sb_file_t *sb)
29{
30 for(int i = 0; i < sb->nr_sections; i++)
31 {
32 struct sb_section_t *sec = &sb->sections[i];
33 for(int j = 0; j < sec->nr_insts; j++)
34 {
35 struct sb_inst_t *inst = &sec->insts[j];
36 if(inst->inst != SB_INST_LOAD)
37 continue;
38 inst->padding_size = ROUND_UP(inst->size, BLOCK_SIZE) - inst->size;
39 /* emulate elftosb2 behaviour: generate 15 bytes (that's a safe maximum) */
40 inst->padding = xmalloc(15);
41 generate_random_data(inst->padding, 15);
42 }
43 }
44}
45
46static void compute_sb_offsets(struct sb_file_t *sb)
47{
48 sb->image_size = 0;
49 /* sb header */
50 sb->image_size += sizeof(struct sb_header_t) / BLOCK_SIZE;
51 /* sections headers */
52 sb->image_size += sb->nr_sections * sizeof(struct sb_section_header_t) / BLOCK_SIZE;
53 /* key dictionary */
54 sb->image_size += g_nr_keys * sizeof(struct sb_key_dictionary_entry_t) / BLOCK_SIZE;
55 /* sections */
56 for(int i = 0; i < sb->nr_sections; i++)
57 {
58 /* each section has a preliminary TAG command */
59 sb->image_size += sizeof(struct sb_instruction_tag_t) / BLOCK_SIZE;
60 /* we might need to pad the section so compute next alignment */
61 uint32_t alignment = BLOCK_SIZE;
62 if((i + 1) < sb->nr_sections)
63 alignment = sb->sections[i + 1].alignment;
64 alignment /= BLOCK_SIZE; /* alignment in block sizes */
65
66 struct sb_section_t *sec = &sb->sections[i];
67
68 if(g_debug)
69 {
70 printf("%s section 0x%08x", sec->is_data ? "Data" : "Boot",
71 sec->identifier);
72 if(sec->is_cleartext)
73 printf(" (cleartext)");
74 printf("\n");
75 }
76
77 sec->file_offset = sb->image_size;
78 for(int j = 0; j < sec->nr_insts; j++)
79 {
80 struct sb_inst_t *inst = &sec->insts[j];
81 if(inst->inst == SB_INST_CALL || inst->inst == SB_INST_JUMP)
82 {
83 if(g_debug)
84 printf(" %s | addr=0x%08x | arg=0x%08x\n",
85 inst->inst == SB_INST_CALL ? "CALL" : "JUMP", inst->addr, inst->argument);
86 sb->image_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE;
87 sec->sec_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE;
88 }
89 else if(inst->inst == SB_INST_FILL)
90 {
91 if(g_debug)
92 printf(" FILL | addr=0x%08x | len=0x%08x | pattern=0x%08x\n",
93 inst->addr, inst->size, inst->pattern);
94 sb->image_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE;
95 sec->sec_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE;
96 }
97 else if(inst->inst == SB_INST_LOAD)
98 {
99 if(g_debug)
100 printf(" LOAD | addr=0x%08x | len=0x%08x\n", inst->addr, inst->size);
101 /* load header */
102 sb->image_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE;
103 sec->sec_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE;
104 /* data + alignment */
105 sb->image_size += (inst->size + inst->padding_size) / BLOCK_SIZE;
106 sec->sec_size += (inst->size + inst->padding_size) / BLOCK_SIZE;
107 }
108 else if(inst->inst == SB_INST_MODE)
109 {
110 if(g_debug)
111 printf(" MODE | mod=0x%08x", inst->addr);
112 sb->image_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE;
113 sec->sec_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE;
114 }
115 else if(inst->inst == SB_INST_DATA)
116 {
117 if(g_debug)
118 printf(" DATA | size=0x%08x\n", inst->size);
119 sb->image_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE;
120 sec->sec_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE;
121 }
122 else
123 bug("die on inst %d\n", inst->inst);
124 }
125 /* we need to make sure next section starts on the right alignment.
126 * Since each section starts with a boot tag, we thus need to ensure
127 * that this sections ends at adress X such that X+BLOCK_SIZE is
128 * a multiple of the alignment.
129 * For data sections, we just add random data, otherwise we add nops */
130 uint32_t missing_sz = alignment - ((sb->image_size + 1) % alignment);
131 if(missing_sz != alignment)
132 {
133 struct sb_inst_t *aug_insts;
134 int nr_aug_insts = 0;
135
136 if(sb->sections[i].is_data)
137 {
138 nr_aug_insts = 1;
139 aug_insts = malloc(sizeof(struct sb_inst_t));
140 memset(aug_insts, 0, sizeof(struct sb_inst_t));
141 aug_insts[0].inst = SB_INST_DATA;
142 aug_insts[0].size = missing_sz * BLOCK_SIZE;
143 aug_insts[0].data = xmalloc(missing_sz * BLOCK_SIZE);
144 generate_random_data(aug_insts[0].data, missing_sz * BLOCK_SIZE);
145 if(g_debug)
146 printf(" DATA | size=0x%08x\n", aug_insts[0].size);
147 }
148 else
149 {
150 nr_aug_insts = missing_sz;
151 aug_insts = malloc(sizeof(struct sb_inst_t) * nr_aug_insts);
152 memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts);
153 for(int j = 0; j < nr_aug_insts; j++)
154 {
155 aug_insts[j].inst = SB_INST_NOP;
156 if(g_debug)
157 printf(" NOOP\n");
158 }
159 }
160
161 sb->sections[i].insts = augment_array(sb->sections[i].insts, sizeof(struct sb_inst_t),
162 sb->sections[i].nr_insts, aug_insts, nr_aug_insts);
163 sb->sections[i].nr_insts += nr_aug_insts;
164
165 /* augment image and section size */
166 sb->image_size += missing_sz;
167 sec->sec_size += missing_sz;
168 }
169 }
170 /* final signature */
171 sb->image_size += 2;
172}
173
174static uint64_t generate_timestamp()
175{
176 struct tm tm_base = {0, 0, 0, 1, 0, 100, 0, 0, 1, 0, NULL}; /* 2000/1/1 0:00:00 */
177 time_t t = time(NULL) - mktime(&tm_base);
178 return (uint64_t)t * 1000000L;
179}
180
181static uint16_t swap16(uint16_t t)
182{
183 return (t << 8) | (t >> 8);
184}
185
186static void fix_version(struct sb_version_t *ver)
187{
188 ver->major = swap16(ver->major);
189 ver->minor = swap16(ver->minor);
190 ver->revision = swap16(ver->revision);
191}
192
193static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr)
194{
195 struct sha_1_params_t sha_1_params;
196
197 sb_hdr->signature[0] = 'S';
198 sb_hdr->signature[1] = 'T';
199 sb_hdr->signature[2] = 'M';
200 sb_hdr->signature[3] = 'P';
201 sb_hdr->major_ver = IMAGE_MAJOR_VERSION;
202 sb_hdr->minor_ver = IMAGE_MINOR_VERSION;
203 sb_hdr->flags = 0;
204 sb_hdr->image_size = sb->image_size;
205 sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE;
206 sb_hdr->first_boot_sec_id = sb->sections[0].identifier;
207 sb_hdr->nr_keys = g_nr_keys;
208 sb_hdr->nr_sections = sb->nr_sections;
209 sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE;
210 sb_hdr->key_dict_off = sb_hdr->header_size +
211 sb_hdr->sec_hdr_size * sb_hdr->nr_sections;
212 sb_hdr->first_boot_tag_off = sb_hdr->key_dict_off +
213 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));
215 generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1));
216 sb_hdr->timestamp = generate_timestamp();
217 sb_hdr->product_ver = sb->product_ver;
218 fix_version(&sb_hdr->product_ver);
219 sb_hdr->component_ver = sb->component_ver;
220 fix_version(&sb_hdr->component_ver);
221 sb_hdr->drive_tag = 0;
222
223 sha_1_init(&sha_1_params);
224 sha_1_update(&sha_1_params, &sb_hdr->signature[0],
225 sizeof(struct sb_header_t) - sizeof(sb_hdr->sha1_header));
226 sha_1_finish(&sha_1_params);
227 sha_1_output(&sha_1_params, sb_hdr->sha1_header);
228}
229
230static void produce_sb_section_header(struct sb_section_t *sec,
231 struct sb_section_header_t *sec_hdr)
232{
233 sec_hdr->identifier = sec->identifier;
234 sec_hdr->offset = sec->file_offset;
235 sec_hdr->size = sec->sec_size;
236 sec_hdr->flags = (sec->is_data ? 0 : SECTION_BOOTABLE)
237 | (sec->is_cleartext ? SECTION_CLEARTEXT : 0);
238}
239
240static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr)
241{
242 uint8_t sum = 90;
243 byte *ptr = (byte *)hdr;
244 for(int i = 1; i < 16; i++)
245 sum += ptr[i];
246 return sum;
247}
248
249static void produce_section_tag_cmd(struct sb_section_t *sec,
250 struct sb_instruction_tag_t *tag, bool is_last)
251{
252 tag->hdr.opcode = SB_INST_TAG;
253 tag->hdr.flags = is_last ? SB_INST_LAST_TAG : 0;
254 tag->identifier = sec->identifier;
255 tag->len = sec->sec_size;
256 tag->flags = (sec->is_data ? 0 : SECTION_BOOTABLE)
257 | (sec->is_cleartext ? SECTION_CLEARTEXT : 0);
258 tag->hdr.checksum = instruction_checksum(&tag->hdr);
259}
260
261void produce_sb_instruction(struct sb_inst_t *inst,
262 struct sb_instruction_common_t *cmd)
263{
264 memset(cmd, 0, sizeof(struct sb_instruction_common_t));
265 cmd->hdr.opcode = inst->inst;
266 switch(inst->inst)
267 {
268 case SB_INST_CALL:
269 case SB_INST_JUMP:
270 cmd->addr = inst->addr;
271 cmd->data = inst->argument;
272 break;
273 case SB_INST_FILL:
274 cmd->addr = inst->addr;
275 cmd->len = inst->size;
276 cmd->data = inst->pattern;
277 break;
278 case SB_INST_LOAD:
279 cmd->addr = inst->addr;
280 cmd->len = inst->size;
281 cmd->data = crc_continue(crc(inst->data, inst->size),
282 inst->padding, inst->padding_size);
283 break;
284 case SB_INST_MODE:
285 cmd->data = inst->addr;
286 break;
287 case SB_INST_NOP:
288 break;
289 default:
290 bug("die\n");
291 }
292 cmd->hdr.checksum = instruction_checksum(&cmd->hdr);
293}
294
295void sb_produce_file(struct sb_file_t *sb, const char *filename)
296{
297 FILE *fd = fopen(filename, "wb");
298 if(fd == NULL)
299 bugp("cannot open output file");
300
301 struct crypto_key_t real_key;
302 real_key.method = CRYPTO_KEY;
303 byte crypto_iv[16];
304 byte (*cbc_macs)[16] = xmalloc(16 * g_nr_keys);
305 /* init CBC-MACs */
306 for(int i = 0; i < g_nr_keys; i++)
307 memset(cbc_macs[i], 0, 16);
308
309 fill_gaps(sb);
310 compute_sb_offsets(sb);
311
312 generate_random_data(real_key.u.key, 16);
313
314 /* global SHA-1 */
315 struct sha_1_params_t file_sha1;
316 sha_1_init(&file_sha1);
317 /* produce and write header */
318 struct sb_header_t sb_hdr;
319 produce_sb_header(sb, &sb_hdr);
320 sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr));
321 fwrite(&sb_hdr, 1, sizeof(sb_hdr), fd);
322
323 memcpy(crypto_iv, &sb_hdr, 16);
324
325 /* update CBC-MACs */
326 for(int i = 0; i < g_nr_keys; i++)
327 crypto_cbc((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE, &g_key_array[i],
328 cbc_macs[i], &cbc_macs[i], 1);
329
330 /* produce and write section headers */
331 for(int i = 0; i < sb_hdr.nr_sections; i++)
332 {
333 struct sb_section_header_t sb_sec_hdr;
334 produce_sb_section_header(&sb->sections[i], &sb_sec_hdr);
335 sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr));
336 fwrite(&sb_sec_hdr, 1, sizeof(sb_sec_hdr), fd);
337 /* update CBC-MACs */
338 for(int j = 0; j < g_nr_keys; j++)
339 crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
340 &g_key_array[j], cbc_macs[j], &cbc_macs[j], 1);
341 }
342 /* produce key dictionary */
343 for(int i = 0; i < g_nr_keys; i++)
344 {
345 struct sb_key_dictionary_entry_t entry;
346 memcpy(entry.hdr_cbc_mac, cbc_macs[i], 16);
347 crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i],
348 crypto_iv, NULL, 1);
349
350 fwrite(&entry, 1, sizeof(entry), fd);
351 sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry));
352 }
353
354 /* HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK */
355 /* Image crafting, don't use it unless you understand what you do */
356 if(sb->real_key != NULL)
357 memcpy(real_key.u.key, *sb->real_key, 16);
358 if(sb->crypto_iv != NULL)
359 memcpy(crypto_iv, *sb->crypto_iv, 16);
360 /* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */
361 if(g_debug)
362 {
363 printf("Real key: ");
364 for(int j = 0; j < 16; j++)
365 printf("%02x", real_key.u.key[j]);
366 printf("\n");
367 printf("IV : ");
368 for(int j = 0; j < 16; j++)
369 printf("%02x", crypto_iv[j]);
370 printf("\n");
371 }
372 /* produce sections data */
373 for(int i = 0; i< sb_hdr.nr_sections; i++)
374 {
375 /* produce tag command */
376 struct sb_instruction_tag_t tag_cmd;
377 produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections);
378 if(g_nr_keys > 0)
379 crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
380 &real_key, crypto_iv, NULL, 1);
381 sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd));
382 fwrite(&tag_cmd, 1, sizeof(tag_cmd), fd);
383 /* produce other commands */
384 byte cur_cbc_mac[16];
385 memcpy(cur_cbc_mac, crypto_iv, 16);
386 for(int j = 0; j < sb->sections[i].nr_insts; j++)
387 {
388 struct sb_inst_t *inst = &sb->sections[i].insts[j];
389 /* command */
390 if(inst->inst != SB_INST_DATA)
391 {
392 struct sb_instruction_common_t cmd;
393 produce_sb_instruction(inst, &cmd);
394 if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
395 crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
396 &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
397 sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
398 fwrite(&cmd, 1, sizeof(cmd), fd);
399 }
400 /* data */
401 if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA)
402 {
403 uint32_t sz = inst->size + inst->padding_size;
404 byte *data = xmalloc(sz);
405 memcpy(data, inst->data, inst->size);
406 memcpy(data + inst->size, inst->padding, inst->padding_size);
407 if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
408 crypto_cbc(data, data, sz / BLOCK_SIZE,
409 &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
410 sha_1_update(&file_sha1, data, sz);
411 fwrite(data, 1, sz, fd);
412 free(data);
413 }
414 }
415 }
416 /* write file SHA-1 */
417 byte final_sig[32];
418 sha_1_finish(&file_sha1);
419 sha_1_output(&file_sha1, final_sig);
420 generate_random_data(final_sig + 20, 12);
421 if(g_nr_keys > 0)
422 crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1);
423 fwrite(final_sig, 1, 32, fd);
424
425 fclose(fd);
426}
diff --git a/utils/sbtools/sb.h b/utils/sbtools/sb.h
index 0a8fad10af..27f5668d2e 100644
--- a/utils/sbtools/sb.h
+++ b/utils/sbtools/sb.h
@@ -22,6 +22,7 @@
22#define __SB_H__ 22#define __SB_H__
23 23
24#include <stdint.h> 24#include <stdint.h>
25#include <stdbool.h>
25 26
26#define BLOCK_SIZE 16 27#define BLOCK_SIZE 16
27 28
@@ -150,4 +151,56 @@ struct sb_instruction_tag_t
150 uint32_t flags; /* section flags */ 151 uint32_t flags; /* section flags */
151} __attribute__((packed)); 152} __attribute__((packed));
152 153
154/*******
155 * API *
156 *******/
157
158#define SB_INST_DATA 0xff
159
160struct sb_inst_t
161{
162 uint8_t inst; /* SB_INST_* */
163 uint32_t size;
164 // <union>
165 void *data;
166 uint32_t pattern;
167 uint32_t addr;
168 // </union>
169 uint32_t argument; // for call and jump
170 /* for production use */
171 uint32_t padding_size;
172 uint8_t *padding;
173};
174
175struct sb_section_t
176{
177 uint32_t identifier;
178 bool is_data;
179 bool is_cleartext;
180 uint32_t alignment;
181 // data sections are handled as one or more SB_INST_DATA virtual instruction
182 int nr_insts;
183 struct sb_inst_t *insts;
184 /* for production use */
185 uint32_t file_offset; /* in blocks */
186 uint32_t sec_size; /* in blocks */
187};
188
189struct sb_file_t
190{
191 /* override real, otherwise it is randomly generated */
192 uint8_t (*real_key)[16];
193 /* override crypto IV, use with caution ! Use NULL to generate it */
194 uint8_t (*crypto_iv)[16];
195
196 int nr_sections;
197 struct sb_section_t *sections;
198 struct sb_version_t product_ver;
199 struct sb_version_t component_ver;
200 /* for production use */
201 uint32_t image_size; /* in blocks */
202};
203
204void sb_produce_file(struct sb_file_t *sb, const char *filename);
205
153#endif /* __SB_H__ */ 206#endif /* __SB_H__ */
diff --git a/utils/sbtools/sbtoelf.c b/utils/sbtools/sbtoelf.c
index 3c1c750582..3824ee094e 100644
--- a/utils/sbtools/sbtoelf.c
+++ b/utils/sbtools/sbtoelf.c
@@ -77,8 +77,6 @@ char *g_out_prefix;
77bool g_debug; 77bool g_debug;
78bool g_raw_mode; 78bool g_raw_mode;
79 79
80#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
81
82static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr) 80static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr)
83{ 81{
84 uint8_t sum = 90; 82 uint8_t sum = 90;
@@ -495,7 +493,7 @@ static void extract(unsigned long filesize)
495 print_hex(g_buf, 16, true); 493 print_hex(g_buf, 16, true);
496 494
497 /* sections */ 495 /* sections */
498 if(strcasecmp(s_getenv("SB_RAW_CMD"), "YES") != 0) 496 if(!g_raw_mode)
499 { 497 {
500 color(BLUE); 498 color(BLUE);
501 printf("Sections\n"); 499 printf("Sections\n");
@@ -747,9 +745,7 @@ int main(int argc, char **argv)
747 break; 745 break;
748 case 'k': 746 case 'k':
749 { 747 {
750 int kac; 748 add_keys_from_file(optarg);
751 key_array_t ka = read_keys(optarg, &kac);
752 add_keys(ka, kac);
753 break; 749 break;
754 } 750 }
755 case 'z': 751 case 'z':