summaryrefslogtreecommitdiff
path: root/utils/sbtools/sbtoelf.c
diff options
context:
space:
mode:
Diffstat (limited to 'utils/sbtools/sbtoelf.c')
-rw-r--r--utils/sbtools/sbtoelf.c274
1 files changed, 145 insertions, 129 deletions
diff --git a/utils/sbtools/sbtoelf.c b/utils/sbtools/sbtoelf.c
index fb4567bed9..3c1c750582 100644
--- a/utils/sbtools/sbtoelf.c
+++ b/utils/sbtools/sbtoelf.c
@@ -28,21 +28,19 @@
28 28
29#define _ISOC99_SOURCE /* snprintf() */ 29#define _ISOC99_SOURCE /* snprintf() */
30#include <stdio.h> 30#include <stdio.h>
31#include <sys/types.h>
32#include <sys/stat.h>
33#include <fcntl.h>
34#include <errno.h> 31#include <errno.h>
35#include <unistd.h>
36#include <stdlib.h> 32#include <stdlib.h>
37#include <inttypes.h>
38#include <string.h> 33#include <string.h>
39#include <ctype.h> 34#include <ctype.h>
40#include <time.h> 35#include <time.h>
36#include <stdarg.h>
41#include <strings.h> 37#include <strings.h>
38#include <getopt.h>
42 39
43#include "crypto.h" 40#include "crypto.h"
44#include "elf.h" 41#include "elf.h"
45#include "sb.h" 42#include "sb.h"
43#include "misc.h"
46 44
47#if 1 /* ANSI colors */ 45#if 1 /* ANSI colors */
48 46
@@ -60,104 +58,24 @@ char BLUE[] = { 0x1b, 0x5b, 0x31, 0x3b, '3', '4', 0x6d, '\0' };
60# define color(a) 58# define color(a)
61#endif 59#endif
62 60
63#define bug(...) do { fprintf(stderr,"ERROR: "__VA_ARGS__); exit(1); } while(0)
64#define bugp(a) do { perror("ERROR: "a); exit(1); } while(0)
65
66/* all blocks are sized as a multiple of 0x1ff */ 61/* all blocks are sized as a multiple of 0x1ff */
67#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff) 62#define PAD_TO_BOUNDARY(x) (((x) + 0x1ff) & ~0x1ff)
68 63
69/* If you find a firmware that breaks the known format ^^ */ 64/* If you find a firmware that breaks the known format ^^ */
70#define assert(a) do { if(!(a)) { fprintf(stderr,"Assertion \"%s\" failed in %s() line %d!\n\nPlease send us your firmware!\n",#a,__func__,__LINE__); exit(1); } } while(0) 65#define assert(a) do { if(!(a)) { fprintf(stderr,"Assertion \"%s\" failed in %s() line %d!\n\nPlease send us your firmware!\n",#a,__func__,__LINE__); exit(1); } } while(0)
71 66
67#define crypto_cbc(...) \
68 do { int ret = crypto_cbc(__VA_ARGS__); \
69 if(ret != CRYPTO_ERROR_SUCCESS) \
70 bug("crypto_cbc error: %d\n", ret); \
71 }while(0)
72
72/* globals */ 73/* globals */
73 74
74uint8_t *g_buf; /* file content */ 75uint8_t *g_buf; /* file content */
75#define PREFIX_SIZE 128 76char *g_out_prefix;
76char out_prefix[PREFIX_SIZE]; 77bool g_debug;
77const char *key_file; 78bool g_raw_mode;
78
79char *s_getenv(const char *name)
80{
81 char *s = getenv(name);
82 return s ? s : "";
83}
84
85void *xmalloc(size_t s) /* malloc helper, used in elf.c */
86{
87 void * r = malloc(s);
88 if(!r) bugp("malloc");
89 return r;
90}
91
92static void print_hex(byte *data, int len, bool newline)
93{
94 for(int i = 0; i < len; i++)
95 printf("%02X ", data[i]);
96 if(newline)
97 printf("\n");
98}
99
100static int convxdigit(char digit, byte *val)
101{
102 if(digit >= '0' && digit <= '9')
103 {
104 *val = digit - '0';
105 return 0;
106 }
107 else if(digit >= 'A' && digit <= 'F')
108 {
109 *val = digit - 'A' + 10;
110 return 0;
111 }
112 else if(digit >= 'a' && digit <= 'f')
113 {
114 *val = digit - 'a' + 10;
115 return 0;
116 }
117 else
118 return 1;
119}
120
121typedef byte (*key_array_t)[16];
122
123static key_array_t read_keys(int num_keys)
124{
125 int size;
126 struct stat st;
127 int fd = open(key_file,O_RDONLY);
128 if(fd == -1)
129 bugp("opening key file failed");
130 if(fstat(fd,&st) == -1)
131 bugp("key file stat() failed");
132 size = st.st_size;
133 char *buf = xmalloc(size);
134 if(read(fd, buf, size) != (ssize_t)size)
135 bugp("reading key file");
136 close(fd);
137
138 key_array_t keys = xmalloc(sizeof(byte[16]) * num_keys);
139 int pos = 0;
140 for(int i = 0; i < num_keys; i++)
141 {
142 /* skip ws */
143 while(pos < size && isspace(buf[pos]))
144 pos++;
145 /* enough space ? */
146 if((pos + 32) > size)
147 bugp("invalid key file (not enough keys)");
148 for(int j = 0; j < 16; j++)
149 {
150 byte a, b;
151 if(convxdigit(buf[pos + 2 * j], &a) || convxdigit(buf[pos + 2 * j + 1], &b))
152 bugp(" invalid key, it should be a 128-bit key written in hexadecimal\n");
153 keys[i][j] = (a << 4) | b;
154 }
155 pos += 32;
156 }
157 free(buf);
158
159 return keys;
160}
161 79
162#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round)) 80#define ROUND_UP(val, round) ((((val) + (round) - 1) / (round)) * (round))
163 81
@@ -195,17 +113,21 @@ static void extract_elf_section(struct elf_params_t *elf, int count, const char
195 113
196static void extract_section(int data_sec, char name[5], byte *buf, int size, const char *indent) 114static void extract_section(int data_sec, char name[5], byte *buf, int size, const char *indent)
197{ 115{
198 char filename[PREFIX_SIZE + 32]; 116 char *filename = xmalloc(strlen(g_out_prefix) + strlen(name) + 5);
199 snprintf(filename, sizeof filename, "%s%s.bin", out_prefix, name); 117 if(g_out_prefix)
200 FILE *fd = fopen(filename, "wb"); 118 {
201 if (fd != NULL) { 119 sprintf(filename, "%s%s.bin", g_out_prefix, name);
202 fwrite(buf, size, 1, fd); 120 FILE *fd = fopen(filename, "wb");
203 fclose(fd); 121 if (fd != NULL)
122 {
123 fwrite(buf, size, 1, fd);
124 fclose(fd);
125 }
204 } 126 }
205 if(data_sec) 127 if(data_sec)
206 return; 128 return;
207 129
208 snprintf(filename, sizeof filename, "%s%s", out_prefix, name); 130 sprintf(filename, "%s%s", g_out_prefix, name);
209 131
210 /* elf construction */ 132 /* elf construction */
211 struct elf_params_t elf; 133 struct elf_params_t elf;
@@ -484,19 +406,23 @@ static void extract(unsigned long filesize)
484 printf("0x%08x\n", sb_header->first_boot_sec_id); 406 printf("0x%08x\n", sb_header->first_boot_sec_id);
485 407
486 /* encryption cbc-mac */ 408 /* encryption cbc-mac */
487 key_array_t keys = NULL; /* array of 16-bytes keys */
488 byte real_key[16]; 409 byte real_key[16];
489 bool valid_key = false; /* false until a matching key was found */ 410 bool valid_key = false; /* false until a matching key was found */
490 if(sb_header->nr_keys > 0) 411 if(sb_header->nr_keys > 0)
491 { 412 {
492 keys = read_keys(sb_header->nr_keys); 413 if(sb_header->nr_keys > g_nr_keys)
414 {
415 color(GREY);
416 bug("SB file has %d keys but only %d were specified on command line\n",
417 sb_header->nr_keys, g_nr_keys);
418 }
493 color(BLUE); 419 color(BLUE);
494 printf("Encryption data\n"); 420 printf("Encryption data\n");
495 for(int i = 0; i < sb_header->nr_keys; i++) 421 for(int i = 0; i < sb_header->nr_keys; i++)
496 { 422 {
497 color(RED); 423 color(RED);
498 printf(" Key %d: ", i); 424 printf(" Key %d: ", i);
499 print_hex(keys[i], 16, true); 425 print_key(&g_key_array[i], true);
500 color(GREEN); 426 color(GREEN);
501 printf(" CBC-MAC of headers: "); 427 printf(" CBC-MAC of headers: ");
502 428
@@ -512,8 +438,8 @@ static void extract(unsigned long filesize)
512 byte computed_cbc_mac[16]; 438 byte computed_cbc_mac[16];
513 byte zero[16]; 439 byte zero[16];
514 memset(zero, 0, 16); 440 memset(zero, 0, 16);
515 cbc_mac(g_buf, NULL, sb_header->header_size + sb_header->nr_sections, 441 crypto_cbc(g_buf, NULL, sb_header->header_size + sb_header->nr_sections,
516 keys[i], zero, &computed_cbc_mac, 1); 442 &g_key_array[i], zero, &computed_cbc_mac, 1);
517 color(RED); 443 color(RED);
518 bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0; 444 bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0;
519 if(ok) 445 if(ok)
@@ -533,7 +459,7 @@ static void extract(unsigned long filesize)
533 byte decrypted_key[16]; 459 byte decrypted_key[16];
534 byte iv[16]; 460 byte iv[16];
535 memcpy(iv, g_buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */ 461 memcpy(iv, g_buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
536 cbc_mac(dict_entry->key, decrypted_key, 1, keys[i], iv, NULL, 0); 462 crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[i], iv, NULL, 0);
537 printf(" Decrypted key : "); 463 printf(" Decrypted key : ");
538 color(YELLOW); 464 color(YELLOW);
539 print_hex(decrypted_key, 16, false); 465 print_hex(decrypted_key, 16, false);
@@ -769,37 +695,127 @@ static void extract(unsigned long filesize)
769 printf(" Failed\n"); 695 printf(" Failed\n");
770} 696}
771 697
772int main(int argc, const char **argv) 698void usage(void)
773{ 699{
774 int fd; 700 printf("Usage: sbtoelf [options] sb-file\n");
775 struct stat st; 701 printf("Options:\n");
776 if(argc != 3 && argc != 4) 702 printf(" -?/--help\tDisplay this message\n");
777 { 703 printf(" -o <file>\tSet output prefix\n");
778 printf("Usage: %s <firmware> <key file> [<out prefix>]\n",*argv); 704 printf(" -d/--debug\tEnable debug output\n");
779 printf("To use raw command mode, set environment variable SB_RAW_CMD to YES\n"); 705 printf(" -k <file>\tAdd key file\n");
780 return 1; 706 printf(" -z\t\tAdd zero key\n");
781 } 707 printf(" -r\t\tUse raw command mode\n");
708 printf(" --single-key <key>\tAdd single key\n");
709 printf(" --usb-otp <vid>:<pid>\tAdd USB OTP device\n");
710 exit(1);
711}
782 712
783 if(argc == 4) 713static struct crypto_key_t g_zero_key =
784 snprintf(out_prefix, PREFIX_SIZE, "%s", argv[3]); 714{
785 else 715 .method = CRYPTO_KEY,
786 strcpy(out_prefix, ""); 716 .u.key = {0}
717};
787 718
788 if( (fd = open(argv[1], O_RDONLY)) == -1 ) 719int main(int argc, char **argv)
789 bugp("opening firmware failed"); 720{
721 while(1)
722 {
723 static struct option long_options[] =
724 {
725 {"help", no_argument, 0, '?'},
726 {"debug", no_argument, 0, 'd'},
727 {"single-key", required_argument, 0, 's'},
728 {"usb-otp", required_argument, 0, 'u'},
729 {0, 0, 0, 0}
730 };
731
732 int c = getopt_long(argc, argv, "?do:k:zr", long_options, NULL);
733 if(c == -1)
734 break;
735 switch(c)
736 {
737 case -1:
738 break;
739 case 'd':
740 g_debug = true;
741 break;
742 case '?':
743 usage();
744 break;
745 case 'o':
746 g_out_prefix = optarg;
747 break;
748 case 'k':
749 {
750 int kac;
751 key_array_t ka = read_keys(optarg, &kac);
752 add_keys(ka, kac);
753 break;
754 }
755 case 'z':
756 {
757 add_keys(&g_zero_key, 1);
758 break;
759 }
760 case 's':
761 {
762 struct crypto_key_t key;
763 key.method = CRYPTO_KEY;
764 if(strlen(optarg) != 32)
765 bug("The key given in argument is invalid");
766 for(int i = 0; i < 16; i++)
767 {
768 byte a, b;
769 if(convxdigit(optarg[2 * i], &a) || convxdigit(optarg[2 * i + 1], &b))
770 bugp("The key given in argument is invalid\n");
771 key.u.key[i] = (a << 4) | b;
772 }
773 add_keys(&key, 1);
774 break;
775 }
776 case 'u':
777 {
778 int vid, pid;
779 char *p = strchr(optarg, ':');
780 if(p == NULL)
781 bug("Invalid VID/PID\n");
782
783 char *end;
784 vid = strtol(optarg, &end, 16);
785 if(end != p)
786 bug("Invalid VID/PID\n");
787 pid = strtol(p + 1, &end, 16);
788 if(end != (optarg + strlen(optarg)))
789 bug("Invalid VID/PID\n");
790 struct crypto_key_t key;
791 key.method = CRYPTO_USBOTP;
792 key.u.vid_pid = vid << 16 | pid;
793 add_keys(&key, 1);
794 break;
795 }
796 default:
797 abort();
798 }
799 }
790 800
791 key_file = argv[2]; 801 if(argc - optind != 1)
802 bug("Missing sb file or too many files after options\n");
792 803
793 if(fstat(fd, &st) == -1) 804 const char *sb_file = argv[optind];
794 bugp("firmware stat() failed"); 805 FILE *fd = fopen(sb_file, "rb");
806 if(fd == NULL)
807 bug("Cannot open input file\n");
808 fseek(fd, 0, SEEK_END);
809 size_t size = ftell(fd);
810 fseek(fd, 0, SEEK_SET);
795 811
796 g_buf = xmalloc(st.st_size); 812 g_buf = xmalloc(size);
797 if(read(fd, g_buf, st.st_size) != (ssize_t)st.st_size) /* load the whole file into memory */ 813 if(fread(g_buf, 1, size, fd) != size) /* load the whole file into memory */
798 bugp("reading firmware"); 814 bugp("reading firmware");
799 815
800 close(fd); 816 fclose(fd);
801 817
802 extract(st.st_size); 818 extract(size);
803 819
804 color(OFF); 820 color(OFF);
805 821