blob: 5e636e99fd94d9e375ed412210bb2d8bfe77cfe8 [file] [log] [blame]
Amaury Poulyd2a58f32011-10-29 17:01:47 +00001/***************************************************************************
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>
Amaury Poulye36471d2011-11-01 11:23:43 +000024#include <ctype.h>
Amaury Poulyd2a58f32011-10-29 17:01:47 +000025#include "misc.h"
26#include "crypto.h"
27#include "sb.h"
28
29static void fill_gaps(struct sb_file_t *sb)
30{
31 for(int i = 0; i < sb->nr_sections; i++)
32 {
33 struct sb_section_t *sec = &sb->sections[i];
34 for(int j = 0; j < sec->nr_insts; j++)
35 {
36 struct sb_inst_t *inst = &sec->insts[j];
37 if(inst->inst != SB_INST_LOAD)
38 continue;
39 inst->padding_size = ROUND_UP(inst->size, BLOCK_SIZE) - inst->size;
40 /* emulate elftosb2 behaviour: generate 15 bytes (that's a safe maximum) */
41 inst->padding = xmalloc(15);
42 generate_random_data(inst->padding, 15);
43 }
44 }
45}
46
47static void compute_sb_offsets(struct sb_file_t *sb)
48{
49 sb->image_size = 0;
50 /* sb header */
51 sb->image_size += sizeof(struct sb_header_t) / BLOCK_SIZE;
52 /* sections headers */
53 sb->image_size += sb->nr_sections * sizeof(struct sb_section_header_t) / BLOCK_SIZE;
54 /* key dictionary */
55 sb->image_size += g_nr_keys * sizeof(struct sb_key_dictionary_entry_t) / BLOCK_SIZE;
56 /* sections */
57 for(int i = 0; i < sb->nr_sections; i++)
58 {
59 /* each section has a preliminary TAG command */
60 sb->image_size += sizeof(struct sb_instruction_tag_t) / BLOCK_SIZE;
61 /* we might need to pad the section so compute next alignment */
62 uint32_t alignment = BLOCK_SIZE;
63 if((i + 1) < sb->nr_sections)
64 alignment = sb->sections[i + 1].alignment;
65 alignment /= BLOCK_SIZE; /* alignment in block sizes */
66
67 struct sb_section_t *sec = &sb->sections[i];
Amaury Poulye36471d2011-11-01 11:23:43 +000068 sec->sec_size = 0;
Amaury Poulyd2a58f32011-10-29 17:01:47 +000069
70 if(g_debug)
71 {
72 printf("%s section 0x%08x", sec->is_data ? "Data" : "Boot",
73 sec->identifier);
74 if(sec->is_cleartext)
75 printf(" (cleartext)");
76 printf("\n");
77 }
78
79 sec->file_offset = sb->image_size;
80 for(int j = 0; j < sec->nr_insts; j++)
81 {
82 struct sb_inst_t *inst = &sec->insts[j];
83 if(inst->inst == SB_INST_CALL || inst->inst == SB_INST_JUMP)
84 {
85 if(g_debug)
86 printf(" %s | addr=0x%08x | arg=0x%08x\n",
87 inst->inst == SB_INST_CALL ? "CALL" : "JUMP", inst->addr, inst->argument);
88 sb->image_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE;
89 sec->sec_size += sizeof(struct sb_instruction_call_t) / BLOCK_SIZE;
90 }
91 else if(inst->inst == SB_INST_FILL)
92 {
93 if(g_debug)
94 printf(" FILL | addr=0x%08x | len=0x%08x | pattern=0x%08x\n",
95 inst->addr, inst->size, inst->pattern);
96 sb->image_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE;
97 sec->sec_size += sizeof(struct sb_instruction_fill_t) / BLOCK_SIZE;
98 }
99 else if(inst->inst == SB_INST_LOAD)
100 {
101 if(g_debug)
102 printf(" LOAD | addr=0x%08x | len=0x%08x\n", inst->addr, inst->size);
103 /* load header */
104 sb->image_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE;
105 sec->sec_size += sizeof(struct sb_instruction_load_t) / BLOCK_SIZE;
106 /* data + alignment */
107 sb->image_size += (inst->size + inst->padding_size) / BLOCK_SIZE;
108 sec->sec_size += (inst->size + inst->padding_size) / BLOCK_SIZE;
109 }
110 else if(inst->inst == SB_INST_MODE)
111 {
112 if(g_debug)
113 printf(" MODE | mod=0x%08x", inst->addr);
114 sb->image_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE;
115 sec->sec_size += sizeof(struct sb_instruction_mode_t) / BLOCK_SIZE;
116 }
117 else if(inst->inst == SB_INST_DATA)
118 {
119 if(g_debug)
120 printf(" DATA | size=0x%08x\n", inst->size);
121 sb->image_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE;
122 sec->sec_size += ROUND_UP(inst->size, BLOCK_SIZE) / BLOCK_SIZE;
123 }
124 else
125 bug("die on inst %d\n", inst->inst);
126 }
127 /* we need to make sure next section starts on the right alignment.
128 * Since each section starts with a boot tag, we thus need to ensure
129 * that this sections ends at adress X such that X+BLOCK_SIZE is
130 * a multiple of the alignment.
131 * For data sections, we just add random data, otherwise we add nops */
132 uint32_t missing_sz = alignment - ((sb->image_size + 1) % alignment);
133 if(missing_sz != alignment)
134 {
135 struct sb_inst_t *aug_insts;
136 int nr_aug_insts = 0;
137
138 if(sb->sections[i].is_data)
139 {
140 nr_aug_insts = 1;
Amaury Pouly58279372011-11-06 01:49:13 +0000141 aug_insts = xmalloc(sizeof(struct sb_inst_t));
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000142 memset(aug_insts, 0, sizeof(struct sb_inst_t));
143 aug_insts[0].inst = SB_INST_DATA;
144 aug_insts[0].size = missing_sz * BLOCK_SIZE;
145 aug_insts[0].data = xmalloc(missing_sz * BLOCK_SIZE);
146 generate_random_data(aug_insts[0].data, missing_sz * BLOCK_SIZE);
147 if(g_debug)
148 printf(" DATA | size=0x%08x\n", aug_insts[0].size);
149 }
150 else
151 {
152 nr_aug_insts = missing_sz;
Amaury Pouly58279372011-11-06 01:49:13 +0000153 aug_insts = xmalloc(sizeof(struct sb_inst_t) * nr_aug_insts);
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000154 memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts);
155 for(int j = 0; j < nr_aug_insts; j++)
156 {
157 aug_insts[j].inst = SB_INST_NOP;
158 if(g_debug)
159 printf(" NOOP\n");
160 }
161 }
162
163 sb->sections[i].insts = augment_array(sb->sections[i].insts, sizeof(struct sb_inst_t),
164 sb->sections[i].nr_insts, aug_insts, nr_aug_insts);
165 sb->sections[i].nr_insts += nr_aug_insts;
Amaury Pouly58279372011-11-06 01:49:13 +0000166 free(aug_insts);
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000167
168 /* augment image and section size */
169 sb->image_size += missing_sz;
170 sec->sec_size += missing_sz;
171 }
172 }
173 /* final signature */
174 sb->image_size += 2;
175}
176
177static uint64_t generate_timestamp()
178{
Amaury Pouly1b7455e2011-12-17 10:22:36 +0000179 struct tm tm_base;
180 memset(&tm_base, 0, sizeof(tm_base));
181 /* 2000/1/1 0:00:00 */
182 tm_base.tm_mday = 1;
183 tm_base.tm_year = 100;
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000184 time_t t = time(NULL) - mktime(&tm_base);
185 return (uint64_t)t * 1000000L;
186}
187
188static uint16_t swap16(uint16_t t)
189{
190 return (t << 8) | (t >> 8);
191}
192
193static void fix_version(struct sb_version_t *ver)
194{
195 ver->major = swap16(ver->major);
196 ver->minor = swap16(ver->minor);
197 ver->revision = swap16(ver->revision);
198}
199
200static void produce_sb_header(struct sb_file_t *sb, struct sb_header_t *sb_hdr)
201{
202 struct sha_1_params_t sha_1_params;
203
204 sb_hdr->signature[0] = 'S';
205 sb_hdr->signature[1] = 'T';
206 sb_hdr->signature[2] = 'M';
207 sb_hdr->signature[3] = 'P';
208 sb_hdr->major_ver = IMAGE_MAJOR_VERSION;
209 sb_hdr->minor_ver = IMAGE_MINOR_VERSION;
210 sb_hdr->flags = 0;
211 sb_hdr->image_size = sb->image_size;
212 sb_hdr->header_size = sizeof(struct sb_header_t) / BLOCK_SIZE;
Amaury Poulye36471d2011-11-01 11:23:43 +0000213 sb_hdr->first_boot_sec_id = sb->first_boot_sec_id;
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000214 sb_hdr->nr_keys = g_nr_keys;
215 sb_hdr->nr_sections = sb->nr_sections;
216 sb_hdr->sec_hdr_size = sizeof(struct sb_section_header_t) / BLOCK_SIZE;
217 sb_hdr->key_dict_off = sb_hdr->header_size +
218 sb_hdr->sec_hdr_size * sb_hdr->nr_sections;
219 sb_hdr->first_boot_tag_off = sb_hdr->key_dict_off +
220 sizeof(struct sb_key_dictionary_entry_t) * sb_hdr->nr_keys / BLOCK_SIZE;
221 generate_random_data(sb_hdr->rand_pad0, sizeof(sb_hdr->rand_pad0));
222 generate_random_data(sb_hdr->rand_pad1, sizeof(sb_hdr->rand_pad1));
Amaury Poulye36471d2011-11-01 11:23:43 +0000223 /* Version 1.0 has 6 bytes of random padding,
224 * Version 1.1 requires the last 4 bytes to be 'sgtl' */
225 if(sb->minor_version >= 1)
226 memcpy(&sb_hdr->rand_pad0[2], "sgtl", 4);
227
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000228 sb_hdr->timestamp = generate_timestamp();
229 sb_hdr->product_ver = sb->product_ver;
230 fix_version(&sb_hdr->product_ver);
231 sb_hdr->component_ver = sb->component_ver;
232 fix_version(&sb_hdr->component_ver);
Amaury Poulye36471d2011-11-01 11:23:43 +0000233 sb_hdr->drive_tag = sb->drive_tag;
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000234
235 sha_1_init(&sha_1_params);
236 sha_1_update(&sha_1_params, &sb_hdr->signature[0],
237 sizeof(struct sb_header_t) - sizeof(sb_hdr->sha1_header));
238 sha_1_finish(&sha_1_params);
239 sha_1_output(&sha_1_params, sb_hdr->sha1_header);
240}
241
242static void produce_sb_section_header(struct sb_section_t *sec,
243 struct sb_section_header_t *sec_hdr)
244{
245 sec_hdr->identifier = sec->identifier;
246 sec_hdr->offset = sec->file_offset;
247 sec_hdr->size = sec->sec_size;
248 sec_hdr->flags = (sec->is_data ? 0 : SECTION_BOOTABLE)
249 | (sec->is_cleartext ? SECTION_CLEARTEXT : 0);
250}
251
252static uint8_t instruction_checksum(struct sb_instruction_header_t *hdr)
253{
254 uint8_t sum = 90;
255 byte *ptr = (byte *)hdr;
256 for(int i = 1; i < 16; i++)
257 sum += ptr[i];
258 return sum;
259}
260
261static void produce_section_tag_cmd(struct sb_section_t *sec,
262 struct sb_instruction_tag_t *tag, bool is_last)
263{
264 tag->hdr.opcode = SB_INST_TAG;
265 tag->hdr.flags = is_last ? SB_INST_LAST_TAG : 0;
266 tag->identifier = sec->identifier;
267 tag->len = sec->sec_size;
268 tag->flags = (sec->is_data ? 0 : SECTION_BOOTABLE)
269 | (sec->is_cleartext ? SECTION_CLEARTEXT : 0);
270 tag->hdr.checksum = instruction_checksum(&tag->hdr);
271}
272
273void produce_sb_instruction(struct sb_inst_t *inst,
274 struct sb_instruction_common_t *cmd)
275{
276 memset(cmd, 0, sizeof(struct sb_instruction_common_t));
277 cmd->hdr.opcode = inst->inst;
278 switch(inst->inst)
279 {
280 case SB_INST_CALL:
281 case SB_INST_JUMP:
282 cmd->addr = inst->addr;
283 cmd->data = inst->argument;
284 break;
285 case SB_INST_FILL:
286 cmd->addr = inst->addr;
287 cmd->len = inst->size;
288 cmd->data = inst->pattern;
289 break;
290 case SB_INST_LOAD:
291 cmd->addr = inst->addr;
292 cmd->len = inst->size;
293 cmd->data = crc_continue(crc(inst->data, inst->size),
294 inst->padding, inst->padding_size);
295 break;
296 case SB_INST_MODE:
297 cmd->data = inst->addr;
298 break;
299 case SB_INST_NOP:
300 break;
301 default:
302 bug("die\n");
303 }
304 cmd->hdr.checksum = instruction_checksum(&cmd->hdr);
305}
306
Amaury Pouly58279372011-11-06 01:49:13 +0000307enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename)
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000308{
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000309 struct crypto_key_t real_key;
310 real_key.method = CRYPTO_KEY;
311 byte crypto_iv[16];
312 byte (*cbc_macs)[16] = xmalloc(16 * g_nr_keys);
313 /* init CBC-MACs */
314 for(int i = 0; i < g_nr_keys; i++)
315 memset(cbc_macs[i], 0, 16);
316
317 fill_gaps(sb);
318 compute_sb_offsets(sb);
319
320 generate_random_data(real_key.u.key, 16);
321
322 /* global SHA-1 */
323 struct sha_1_params_t file_sha1;
324 sha_1_init(&file_sha1);
325 /* produce and write header */
326 struct sb_header_t sb_hdr;
327 produce_sb_header(sb, &sb_hdr);
Amaury Pouly58279372011-11-06 01:49:13 +0000328 /* allocate image */
329 byte *buf = xmalloc(sb_hdr.image_size * BLOCK_SIZE);
330 byte *buf_p = buf;
331 #define write(p, sz) do { memcpy(buf_p, p, sz); buf_p += sz; } while(0)
332
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000333 sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr));
Amaury Pouly58279372011-11-06 01:49:13 +0000334 write(&sb_hdr, sizeof(sb_hdr));
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000335
336 memcpy(crypto_iv, &sb_hdr, 16);
337
338 /* update CBC-MACs */
339 for(int i = 0; i < g_nr_keys; i++)
340 crypto_cbc((byte *)&sb_hdr, NULL, sizeof(sb_hdr) / BLOCK_SIZE, &g_key_array[i],
341 cbc_macs[i], &cbc_macs[i], 1);
342
343 /* produce and write section headers */
344 for(int i = 0; i < sb_hdr.nr_sections; i++)
345 {
346 struct sb_section_header_t sb_sec_hdr;
347 produce_sb_section_header(&sb->sections[i], &sb_sec_hdr);
348 sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr));
Amaury Pouly58279372011-11-06 01:49:13 +0000349 write(&sb_sec_hdr, sizeof(sb_sec_hdr));
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000350 /* update CBC-MACs */
351 for(int j = 0; j < g_nr_keys; j++)
352 crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
353 &g_key_array[j], cbc_macs[j], &cbc_macs[j], 1);
354 }
355 /* produce key dictionary */
356 for(int i = 0; i < g_nr_keys; i++)
357 {
358 struct sb_key_dictionary_entry_t entry;
359 memcpy(entry.hdr_cbc_mac, cbc_macs[i], 16);
360 crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i],
361 crypto_iv, NULL, 1);
362
Amaury Pouly58279372011-11-06 01:49:13 +0000363 write(&entry, sizeof(entry));
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000364 sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry));
365 }
366
Amaury Pouly58279372011-11-06 01:49:13 +0000367 free(cbc_macs);
368
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000369 /* HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK */
370 /* Image crafting, don't use it unless you understand what you do */
Amaury Pouly58279372011-11-06 01:49:13 +0000371 if(sb->override_real_key)
372 memcpy(real_key.u.key, sb->real_key, 16);
373 if(sb->override_crypto_iv)
374 memcpy(crypto_iv, sb->crypto_iv, 16);
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000375 /* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */
376 if(g_debug)
377 {
378 printf("Real key: ");
379 for(int j = 0; j < 16; j++)
380 printf("%02x", real_key.u.key[j]);
381 printf("\n");
382 printf("IV : ");
383 for(int j = 0; j < 16; j++)
384 printf("%02x", crypto_iv[j]);
385 printf("\n");
386 }
387 /* produce sections data */
388 for(int i = 0; i< sb_hdr.nr_sections; i++)
389 {
390 /* produce tag command */
391 struct sb_instruction_tag_t tag_cmd;
392 produce_section_tag_cmd(&sb->sections[i], &tag_cmd, (i + 1) == sb_hdr.nr_sections);
393 if(g_nr_keys > 0)
394 crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
395 &real_key, crypto_iv, NULL, 1);
396 sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd));
Amaury Pouly58279372011-11-06 01:49:13 +0000397 write(&tag_cmd, sizeof(tag_cmd));
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000398 /* produce other commands */
399 byte cur_cbc_mac[16];
400 memcpy(cur_cbc_mac, crypto_iv, 16);
401 for(int j = 0; j < sb->sections[i].nr_insts; j++)
402 {
403 struct sb_inst_t *inst = &sb->sections[i].insts[j];
404 /* command */
405 if(inst->inst != SB_INST_DATA)
406 {
407 struct sb_instruction_common_t cmd;
408 produce_sb_instruction(inst, &cmd);
409 if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
410 crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
411 &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
412 sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
Amaury Pouly58279372011-11-06 01:49:13 +0000413 write(&cmd, sizeof(cmd));
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000414 }
415 /* data */
416 if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA)
417 {
418 uint32_t sz = inst->size + inst->padding_size;
419 byte *data = xmalloc(sz);
420 memcpy(data, inst->data, inst->size);
421 memcpy(data + inst->size, inst->padding, inst->padding_size);
422 if(g_nr_keys > 0 && !sb->sections[i].is_cleartext)
423 crypto_cbc(data, data, sz / BLOCK_SIZE,
424 &real_key, cur_cbc_mac, &cur_cbc_mac, 1);
425 sha_1_update(&file_sha1, data, sz);
Amaury Pouly58279372011-11-06 01:49:13 +0000426 write(data, sz);
Amaury Poulyd2a58f32011-10-29 17:01:47 +0000427 free(data);
428 }
429 }
430 }
431 /* write file SHA-1 */
432 byte final_sig[32];
433 sha_1_finish(&file_sha1);
434 sha_1_output(&file_sha1, final_sig);
435 generate_random_data(final_sig + 20, 12);
436 if(g_nr_keys > 0)
437 crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1);
Amaury Pouly58279372011-11-06 01:49:13 +0000438 write(final_sig, 32);
Amaury Poulye36471d2011-11-01 11:23:43 +0000439
Amaury Pouly58279372011-11-06 01:49:13 +0000440 if(buf_p - buf != sb_hdr.image_size * BLOCK_SIZE)
441 bug("SB image buffer was not entirely filled !");
442
443 FILE *fd = fopen(filename, "wb");
444 if(fd == NULL)
445 return SB_OPEN_ERROR;
446 if(fwrite(buf, sb_hdr.image_size * BLOCK_SIZE, 1, fd) != 1)
447 {
448 free(buf);
449 return SB_WRITE_ERROR;
450 }
451 fclose(fd);
452 free(buf);
453
454 return SB_SUCCESS;
Amaury Poulye36471d2011-11-01 11:23:43 +0000455}
456
457static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
Amaury Pouly58279372011-11-06 01:49:13 +0000458 int size, const char *indent, void *u, sb_color_printf cprintf, enum sb_error_t *err)
Amaury Poulye36471d2011-11-01 11:23:43 +0000459{
460 #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
Amaury Pouly58279372011-11-06 01:49:13 +0000461 #define fatal(e, ...) \
462 do { if(err) *err = e; \
463 cprintf(u, true, GREY, __VA_ARGS__); \
464 sb_free_section(*sec); \
465 free(sec); \
466 return NULL; } while(0)
Amaury Poulye36471d2011-11-01 11:23:43 +0000467
468 struct sb_section_t *sec = xmalloc(sizeof(struct sb_section_t));
469 memset(sec, 0, sizeof(struct sb_section_t));
470 sec->identifier = id;
471 sec->is_data = data_sec;
472 sec->sec_size = ROUND_UP(size, BLOCK_SIZE) / BLOCK_SIZE;
473
474 if(data_sec)
475 {
476 sec->nr_insts = 1;
477 sec->insts = xmalloc(sizeof(struct sb_inst_t));
478 memset(sec->insts, 0, sizeof(struct sb_inst_t));
479 sec->insts->inst = SB_INST_DATA;
480 sec->insts->size = size;
481 sec->insts->data = memdup(buf, size);
482 return sec;
483 }
484
485 /* Pretty print the content */
486 int pos = 0;
487 while(pos < size)
488 {
489 struct sb_inst_t inst;
490 memset(&inst, 0, sizeof(inst));
491
492 struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)&buf[pos];
493 inst.inst = hdr->opcode;
494
495 printf(OFF, "%s", indent);
496 uint8_t checksum = instruction_checksum(hdr);
497 if(checksum != hdr->checksum)
Amaury Pouly58279372011-11-06 01:49:13 +0000498 fatal(SB_CHECKSUM_ERROR, "Bad instruction checksum");
Amaury Poulye36471d2011-11-01 11:23:43 +0000499 if(hdr->flags != 0)
500 {
501 printf(GREY, "[");
502 printf(BLUE, "f=%x", hdr->flags);
503 printf(GREY, "] ");
504 }
505 if(hdr->opcode == SB_INST_LOAD)
506 {
507 struct sb_instruction_load_t *load = (struct sb_instruction_load_t *)&buf[pos];
508 inst.size = load->len;
509 inst.addr = load->addr;
510 inst.data = memdup(load + 1, load->len);
511
512 printf(RED, "LOAD");
513 printf(OFF, " | ");
514 printf(BLUE, "addr=0x%08x", load->addr);
515 printf(OFF, " | ");
516 printf(GREEN, "len=0x%08x", load->len);
517 printf(OFF, " | ");
518 printf(YELLOW, "crc=0x%08x", load->crc);
519 /* data is padded to 16-byte boundary with random data and crc'ed with it */
520 uint32_t computed_crc = crc(&buf[pos + sizeof(struct sb_instruction_load_t)],
521 ROUND_UP(load->len, 16));
522 if(load->crc == computed_crc)
523 printf(RED, " Ok\n");
524 else
Amaury Pouly58279372011-11-06 01:49:13 +0000525 {
Amaury Poulye36471d2011-11-01 11:23:43 +0000526 printf(RED, " Failed (crc=0x%08x)\n", computed_crc);
Amaury Pouly58279372011-11-06 01:49:13 +0000527 fatal(SB_CHECKSUM_ERROR, "Instruction data crc error\n");
528 }
Amaury Poulye36471d2011-11-01 11:23:43 +0000529
530 pos += load->len + sizeof(struct sb_instruction_load_t);
531 }
532 else if(hdr->opcode == SB_INST_FILL)
533 {
534 struct sb_instruction_fill_t *fill = (struct sb_instruction_fill_t *)&buf[pos];
535 inst.pattern = fill->pattern;
536 inst.size = fill->len;
537 inst.addr = fill->addr;
538
539 printf(RED, "FILL");
540 printf(OFF, " | ");
541 printf(BLUE, "addr=0x%08x", fill->addr);
542 printf(OFF, " | ");
543 printf(GREEN, "len=0x%08x", fill->len);
544 printf(OFF, " | ");
545 printf(YELLOW, "pattern=0x%08x\n", fill->pattern);
546
547 pos += sizeof(struct sb_instruction_fill_t);
548 }
549 else if(hdr->opcode == SB_INST_CALL ||
550 hdr->opcode == SB_INST_JUMP)
551 {
552 int is_call = (hdr->opcode == SB_INST_CALL);
553 struct sb_instruction_call_t *call = (struct sb_instruction_call_t *)&buf[pos];
554 inst.addr = call->addr;
555 inst.argument = call->arg;
556
557 if(is_call)
558 printf(RED, "CALL");
559 else
560 printf(RED, "JUMP");
561 printf(OFF, " | ");
562 printf(BLUE, "addr=0x%08x", call->addr);
563 printf(OFF, " | ");
564 printf(GREEN, "arg=0x%08x\n", call->arg);
565
566 pos += sizeof(struct sb_instruction_call_t);
567 }
568 else if(hdr->opcode == SB_INST_MODE)
569 {
570 struct sb_instruction_mode_t *mode = (struct sb_instruction_mode_t *)hdr;
571 inst.argument = mode->mode;
572
573 printf(RED, "MODE");
574 printf(OFF, " | ");
575 printf(BLUE, "mod=0x%08x\n", mode->mode);
576
577 pos += sizeof(struct sb_instruction_mode_t);
578 }
579 else if(hdr->opcode == SB_INST_NOP)
580 {
581 printf(RED, "NOOP\n");
582 pos += sizeof(struct sb_instruction_mode_t);
583 }
584 else
585 {
Amaury Pouly58279372011-11-06 01:49:13 +0000586 fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos);
Amaury Poulye36471d2011-11-01 11:23:43 +0000587 break;
588 }
589
590 sec->insts = augment_array(sec->insts, sizeof(struct sb_inst_t), sec->nr_insts++, &inst, 1);
591 pos = ROUND_UP(pos, BLOCK_SIZE);
592 }
593
594 return sec;
595 #undef printf
Amaury Pouly58279372011-11-06 01:49:13 +0000596 #undef fatal
Amaury Poulye36471d2011-11-01 11:23:43 +0000597}
598
Amaury Poulydd0fffe2011-11-01 11:26:16 +0000599void sb_fill_section_name(char name[5], uint32_t identifier)
Amaury Poulye36471d2011-11-01 11:23:43 +0000600{
601 name[0] = (identifier >> 24) & 0xff;
602 name[1] = (identifier >> 16) & 0xff;
603 name[2] = (identifier >> 8) & 0xff;
604 name[3] = identifier & 0xff;
605 for(int i = 0; i < 4; i++)
606 if(!isprint(name[i]))
607 name[i] = '_';
608 name[4] = 0;
609}
610
611static uint32_t guess_alignment(uint32_t off)
612{
613 /* find greatest power of two which divides the offset */
614 if(off == 0)
615 return 1;
616 uint32_t a = 1;
617 while(off % (2 * a) == 0)
618 a *= 2;
619 return a;
620}
621
622struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
Amaury Pouly58279372011-11-06 01:49:13 +0000623 sb_color_printf cprintf, enum sb_error_t *err)
Amaury Poulye36471d2011-11-01 11:23:43 +0000624{
Amaury Pouly58279372011-11-06 01:49:13 +0000625 uint8_t *buf = NULL;
626 struct sb_file_t *sb_file = NULL;
627
Amaury Poulye36471d2011-11-01 11:23:43 +0000628 #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
Amaury Pouly58279372011-11-06 01:49:13 +0000629 #define fatal(e, ...) \
630 do { if(err) *err = e; \
631 cprintf(u, true, GREY, __VA_ARGS__); \
632 free(buf); \
633 sb_free(sb_file); \
634 return NULL; } while(0)
Amaury Poulye36471d2011-11-01 11:23:43 +0000635 #define print_hex(c, p, len, nl) \
636 do { printf(c, ""); print_hex(p, len, nl); } while(0)
637
638 FILE *f = fopen(filename, "rb");
639 if(f == NULL)
Amaury Pouly58279372011-11-06 01:49:13 +0000640 fatal(SB_OPEN_ERROR, "Cannot open file for reading\n");
Amaury Poulye36471d2011-11-01 11:23:43 +0000641 fseek(f, 0, SEEK_END);
642 long filesize = ftell(f);
643 fseek(f, 0, SEEK_SET);
Amaury Pouly58279372011-11-06 01:49:13 +0000644 buf = xmalloc(filesize);
645 if(fread(buf, filesize, 1, f) != 1)
646 {
647 fclose(f);
648 fatal(SB_READ_ERROR, "Cannot read file\n");
649 }
Amaury Poulye36471d2011-11-01 11:23:43 +0000650 fclose(f);
651
652 struct sha_1_params_t sha_1_params;
Amaury Pouly58279372011-11-06 01:49:13 +0000653 sb_file = xmalloc(sizeof(struct sb_file_t));
Amaury Poulye36471d2011-11-01 11:23:43 +0000654 memset(sb_file, 0, sizeof(struct sb_file_t));
655 struct sb_header_t *sb_header = (struct sb_header_t *)buf;
656
657 sb_file->image_size = sb_header->image_size;
658 sb_file->minor_version = sb_header->minor_ver;
659 sb_file->flags = sb_header->flags;
660 sb_file->drive_tag = sb_header->drive_tag;
661 sb_file->first_boot_sec_id = sb_header->first_boot_sec_id;
662
663 if(memcmp(sb_header->signature, "STMP", 4) != 0)
Amaury Pouly58279372011-11-06 01:49:13 +0000664 fatal(SB_FORMAT_ERROR, "Bad signature\n");
Amaury Poulye36471d2011-11-01 11:23:43 +0000665 if(sb_header->image_size * BLOCK_SIZE > filesize)
Amaury Pouly58279372011-11-06 01:49:13 +0000666 fatal(SB_FORMAT_ERROR, "File too small");
Amaury Poulye36471d2011-11-01 11:23:43 +0000667 if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t))
Amaury Pouly58279372011-11-06 01:49:13 +0000668 fatal(SB_FORMAT_ERROR, "Bad header size");
Amaury Poulye36471d2011-11-01 11:23:43 +0000669 if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t))
Amaury Pouly58279372011-11-06 01:49:13 +0000670 fatal(SB_FORMAT_ERROR, "Bad section header size");
Amaury Poulye36471d2011-11-01 11:23:43 +0000671
672 if(filesize > sb_header->image_size * BLOCK_SIZE)
673 {
674 printf(GREY, "[Restrict file size from %lu to %d bytes]\n", filesize,
675 sb_header->image_size * BLOCK_SIZE);
676 filesize = sb_header->image_size * BLOCK_SIZE;
677 }
678
679 printf(BLUE, "Basic info:\n");
680 printf(GREEN, " SB version: ");
681 printf(YELLOW, "%d.%d\n", sb_header->major_ver, sb_header->minor_ver);
682 printf(GREEN, " Header SHA-1: ");
683 byte *hdr_sha1 = sb_header->sha1_header;
684 print_hex(YELLOW, hdr_sha1, 20, false);
685 /* Check SHA1 sum */
686 byte computed_sha1[20];
687 sha_1_init(&sha_1_params);
688 sha_1_update(&sha_1_params, &sb_header->signature[0],
689 sizeof(struct sb_header_t) - sizeof(sb_header->sha1_header));
690 sha_1_finish(&sha_1_params);
691 sha_1_output(&sha_1_params, computed_sha1);
692 if(memcmp(hdr_sha1, computed_sha1, 20) == 0)
693 printf(RED, " Ok\n");
694 else
695 printf(RED, " Failed\n");
696 printf(GREEN, " Flags: ");
697 printf(YELLOW, "%x\n", sb_header->flags);
698 printf(GREEN, " Total file size : ");
699 printf(YELLOW, "%ld\n", filesize);
700
701 /* Sizes and offsets */
702 printf(BLUE, "Sizes and offsets:\n");
703 printf(GREEN, " # of encryption keys = ");
704 printf(YELLOW, "%d\n", sb_header->nr_keys);
705 printf(GREEN, " # of sections = ");
706 printf(YELLOW, "%d\n", sb_header->nr_sections);
707
708 /* Versions */
709 printf(BLUE, "Versions\n");
710
711 printf(GREEN, " Random 1: ");
712 print_hex(YELLOW, sb_header->rand_pad0, sizeof(sb_header->rand_pad0), true);
713 printf(GREEN, " Random 2: ");
714 print_hex(YELLOW, sb_header->rand_pad1, sizeof(sb_header->rand_pad1), true);
715
716 uint64_t micros = sb_header->timestamp;
717 time_t seconds = (micros / (uint64_t)1000000L);
Amaury Pouly1b7455e2011-12-17 10:22:36 +0000718 struct tm tm_base;
719 memset(&tm_base, 0, sizeof(tm_base));
720 /* 2000/1/1 0:00:00 */
721 tm_base.tm_mday = 1;
722 tm_base.tm_year = 100;
Amaury Poulye36471d2011-11-01 11:23:43 +0000723 seconds += mktime(&tm_base);
724 struct tm *time = gmtime(&seconds);
725 printf(GREEN, " Creation date/time = ");
726 printf(YELLOW, "%s", asctime(time));
727
728 struct sb_version_t product_ver = sb_header->product_ver;
729 fix_version(&product_ver);
730 struct sb_version_t component_ver = sb_header->component_ver;
731 fix_version(&component_ver);
732
733 memcpy(&sb_file->product_ver, &product_ver, sizeof(product_ver));
734 memcpy(&sb_file->component_ver, &component_ver, sizeof(component_ver));
735
736 printf(GREEN, " Product version = ");
737 printf(YELLOW, "%X.%X.%X\n", product_ver.major, product_ver.minor, product_ver.revision);
738 printf(GREEN, " Component version = ");
739 printf(YELLOW, "%X.%X.%X\n", component_ver.major, component_ver.minor, component_ver.revision);
740
741 printf(GREEN, " Drive tag = ");
742 printf(YELLOW, "%x\n", sb_header->drive_tag);
743 printf(GREEN, " First boot tag offset = ");
744 printf(YELLOW, "%x\n", sb_header->first_boot_tag_off);
745 printf(GREEN, " First boot section ID = ");
746 printf(YELLOW, "0x%08x\n", sb_header->first_boot_sec_id);
747
748 /* encryption cbc-mac */
749 byte real_key[16];
750 bool valid_key = false; /* false until a matching key was found */
Amaury Pouly58279372011-11-06 01:49:13 +0000751
Amaury Poulye36471d2011-11-01 11:23:43 +0000752 if(sb_header->nr_keys > 0)
753 {
Amaury Pouly58279372011-11-06 01:49:13 +0000754 byte (*cbcmacs)[16] = xmalloc(16 * g_nr_keys);
755 printf(BLUE, "Encryption keys\n");
756 for(int i = 0; i < g_nr_keys; i++)
Amaury Poulye36471d2011-11-01 11:23:43 +0000757 {
758 printf(RED, " Key %d: ", i);
759 printf(YELLOW, "");
760 print_key(&g_key_array[i], true);
Amaury Pouly58279372011-11-06 01:49:13 +0000761 printf(GREEN, " CBC-MAC: ");
762 /* check it */
763 byte zero[16];
764 memset(zero, 0, 16);
765 int ret = crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections,
766 &g_key_array[i], zero, &cbcmacs[i], 1);
767 if(ret != CRYPTO_ERROR_SUCCESS)
768 {
769 free(cbcmacs);
770 fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d", ret);
771 }
772 print_hex(YELLOW, cbcmacs[i], 16, true);
773 }
Amaury Poulye36471d2011-11-01 11:23:43 +0000774
Amaury Pouly58279372011-11-06 01:49:13 +0000775 printf(BLUE, "DEK\n");
776 for(int i = 0; i < sb_header->nr_keys; i++)
777 {
778 printf(RED, " Entry %d\n", i);
Amaury Poulye36471d2011-11-01 11:23:43 +0000779 uint32_t ofs = sizeof(struct sb_header_t)
780 + sizeof(struct sb_section_header_t) * sb_header->nr_sections
781 + sizeof(struct sb_key_dictionary_entry_t) * i;
782 struct sb_key_dictionary_entry_t *dict_entry =
783 (struct sb_key_dictionary_entry_t *)&buf[ofs];
784 /* cbc mac */
Amaury Pouly58279372011-11-06 01:49:13 +0000785 printf(GREEN, " Encrypted key: ");
786 print_hex(YELLOW, dict_entry->key, 16, true);
787 printf(GREEN, " CBC-MAC : ");
Amaury Poulye36471d2011-11-01 11:23:43 +0000788 print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false);
789 /* check it */
Amaury Pouly58279372011-11-06 01:49:13 +0000790 int idx = 0;
791 while(idx < g_nr_keys && memcmp(dict_entry->hdr_cbc_mac, cbcmacs[idx], 16) != 0)
792 idx++;
793 if(idx != g_nr_keys)
Amaury Poulye36471d2011-11-01 11:23:43 +0000794 {
Amaury Pouly58279372011-11-06 01:49:13 +0000795 printf(RED, " Match\n");
796 /* decrypt */
797 byte decrypted_key[16];
798 byte iv[16];
799 memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
800 int ret = crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[idx], iv, NULL, 0);
801 if(ret != CRYPTO_ERROR_SUCCESS)
802 {
803 free(cbcmacs);
804 fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d\n", ret);
805 }
806 printf(GREEN, " Decrypted key: ");
807 print_hex(YELLOW, decrypted_key, 16, false);
808 if(valid_key)
809 {
810 if(memcmp(real_key, decrypted_key, 16) == 0)
811 printf(RED, " Cross-Check Ok");
812 else
813 printf(RED, " Cross-Check Failed");
814 }
815 else
816 {
817 memcpy(real_key, decrypted_key, 16);
818 valid_key = true;
819 }
820 printf(OFF, "\n");
Amaury Poulye36471d2011-11-01 11:23:43 +0000821 }
822 else
Amaury Pouly58279372011-11-06 01:49:13 +0000823 printf(RED, " Don't Match\n");
Amaury Poulye36471d2011-11-01 11:23:43 +0000824 }
Amaury Pouly58279372011-11-06 01:49:13 +0000825
826 free(cbcmacs);
827
828 if(!valid_key)
829 fatal(SB_NO_VALID_KEY, "No valid key found\n");
830
831 if(getenv("SB_REAL_KEY") != 0)
832 {
833 struct crypto_key_t k;
834 char *env = getenv("SB_REAL_KEY");
835 if(!parse_key(&env, &k) || *env)
836 bug("Invalid SB_REAL_KEY\n");
837 memcpy(real_key, k.u.key, 16);
838 }
839
840 printf(RED, " Summary:\n");
841 printf(GREEN, " Real key: ");
842 print_hex(YELLOW, real_key, 16, true);
843 printf(GREEN, " IV : ");
844 print_hex(YELLOW, buf, 16, true);
845
846 sb_file->override_real_key = true;
847 memcpy(sb_file->real_key, real_key, 16);
848 sb_file->override_crypto_iv = true;
849 memcpy(sb_file->crypto_iv, buf, 16);
Amaury Poulye36471d2011-11-01 11:23:43 +0000850 }
851
Amaury Poulye36471d2011-11-01 11:23:43 +0000852 /* sections */
853 if(!raw_mode)
854 {
855 sb_file->nr_sections = sb_header->nr_sections;
856 sb_file->sections = xmalloc(sb_file->nr_sections * sizeof(struct sb_section_t));
857 memset(sb_file->sections, 0, sb_file->nr_sections * sizeof(struct sb_section_t));
858 printf(BLUE, "Sections\n");
859 for(int i = 0; i < sb_header->nr_sections; i++)
860 {
861 uint32_t ofs = sb_header->header_size * BLOCK_SIZE + i * sizeof(struct sb_section_header_t);
862 struct sb_section_header_t *sec_hdr = (struct sb_section_header_t *)&buf[ofs];
863
864 char name[5];
Amaury Poulydd0fffe2011-11-01 11:26:16 +0000865 sb_fill_section_name(name, sec_hdr->identifier);
Amaury Poulye36471d2011-11-01 11:23:43 +0000866 int pos = sec_hdr->offset * BLOCK_SIZE;
867 int size = sec_hdr->size * BLOCK_SIZE;
868 int data_sec = !(sec_hdr->flags & SECTION_BOOTABLE);
869 int encrypted = !(sec_hdr->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
870
871 printf(GREEN, " Section ");
872 printf(YELLOW, "'%s'\n", name);
873 printf(GREEN, " pos = ");
874 printf(YELLOW, "%8x - %8x\n", pos, pos+size);
875 printf(GREEN, " len = ");
876 printf(YELLOW, "%8x\n", size);
877 printf(GREEN, " flags = ");
878 printf(YELLOW, "%8x", sec_hdr->flags);
879 if(data_sec)
880 printf(RED, " Data Section");
881 else
882 printf(RED, " Boot Section");
883 if(encrypted)
884 printf(RED, " (Encrypted)");
885 printf(OFF, "\n");
886
887 /* save it */
888 byte *sec = xmalloc(size);
889 if(encrypted)
890 cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0);
891 else
892 memcpy(sec, buf + pos, size);
893
894 struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier,
Amaury Pouly58279372011-11-06 01:49:13 +0000895 sec, size, " ", u, cprintf, err);
Amaury Poulye36471d2011-11-01 11:23:43 +0000896 if(s)
897 {
898 s->is_cleartext = !encrypted;
899 s->alignment = guess_alignment(pos);
900 memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t));
901 free(s);
902 }
Amaury Pouly58279372011-11-06 01:49:13 +0000903 else
904 fatal(*err, "Error reading section\n");
Amaury Poulye36471d2011-11-01 11:23:43 +0000905
906 free(sec);
907 }
908 }
909 else
910 {
911 /* advanced raw mode */
912 printf(BLUE, "Commands\n");
913 uint32_t offset = sb_header->first_boot_tag_off * BLOCK_SIZE;
914 byte iv[16];
915 const char *indent = " ";
916 while(true)
917 {
918 /* restart with IV */
919 memcpy(iv, buf, 16);
920 byte cmd[BLOCK_SIZE];
921 if(sb_header->nr_keys > 0)
922 cbc_mac(buf + offset, cmd, 1, real_key, iv, &iv, 0);
923 else
924 memcpy(cmd, buf + offset, BLOCK_SIZE);
925 struct sb_instruction_header_t *hdr = (struct sb_instruction_header_t *)cmd;
926 printf(OFF, "%s", indent);
927 uint8_t checksum = instruction_checksum(hdr);
928 if(checksum != hdr->checksum)
929 printf(GREY, "[Bad checksum']");
930
931 if(hdr->opcode == SB_INST_NOP)
932 {
933 printf(RED, "NOOP\n");
934 offset += BLOCK_SIZE;
935 }
936 else if(hdr->opcode == SB_INST_TAG)
937 {
938 struct sb_instruction_tag_t *tag = (struct sb_instruction_tag_t *)hdr;
939 printf(RED, "BTAG");
940 printf(OFF, " | ");
941 printf(BLUE, "sec=0x%08x", tag->identifier);
942 printf(OFF, " | ");
943 printf(GREEN, "cnt=0x%08x", tag->len);
944 printf(OFF, " | ");
945 printf(YELLOW, "flg=0x%08x", tag->flags);
946 if(tag->hdr.flags & SB_INST_LAST_TAG)
947 {
948 printf(OFF, " | ");
949 printf(RED, " Last section");
950 }
951 printf(OFF, "\n");
952 offset += sizeof(struct sb_instruction_tag_t);
953
954 char name[5];
Amaury Poulydd0fffe2011-11-01 11:26:16 +0000955 sb_fill_section_name(name, tag->identifier);
Amaury Poulye36471d2011-11-01 11:23:43 +0000956 int pos = offset;
957 int size = tag->len * BLOCK_SIZE;
958 int data_sec = !(tag->flags & SECTION_BOOTABLE);
959 int encrypted = !(tag->flags & SECTION_CLEARTEXT) && sb_header->nr_keys > 0;
960
961 printf(GREEN, "%sSection ", indent);
962 printf(YELLOW, "'%s'\n", name);
963 printf(GREEN, "%s pos = ", indent);
964 printf(YELLOW, "%8x - %8x\n", pos, pos+size);
965 printf(GREEN, "%s len = ", indent);
966 printf(YELLOW, "%8x\n", size);
967 printf(GREEN, "%s flags = ", indent);
968 printf(YELLOW, "%8x", tag->flags);
969 if(data_sec)
970 printf(RED, " Data Section");
971 else
972 printf(RED, " Boot Section");
973 if(encrypted)
974 printf(RED, " (Encrypted)");
975 printf(OFF, "\n");
976
977 /* save it */
978 byte *sec = xmalloc(size);
979 if(encrypted)
980 cbc_mac(buf + pos, sec, size / BLOCK_SIZE, real_key, buf, NULL, 0);
981 else
982 memcpy(sec, buf + pos, size);
983
984 struct sb_section_t *s = read_section(data_sec, tag->identifier,
Amaury Pouly58279372011-11-06 01:49:13 +0000985 sec, size, " ", u, cprintf, err);
Amaury Poulye36471d2011-11-01 11:23:43 +0000986 if(s)
987 {
988 s->is_cleartext = !encrypted;
989 s->alignment = guess_alignment(pos);
990 sb_file->sections = augment_array(sb_file->sections,
991 sizeof(struct sb_section_t), sb_file->nr_sections++,
992 s, 1);
993 free(s);
994 }
Amaury Pouly58279372011-11-06 01:49:13 +0000995 else
996 fatal(*err, "Error reading section\n");
Amaury Poulye36471d2011-11-01 11:23:43 +0000997 free(sec);
998
999 /* last one ? */
1000 if(tag->hdr.flags & SB_INST_LAST_TAG)
1001 break;
1002 offset += size;
1003 }
1004 else
1005 {
Amaury Pouly58279372011-11-06 01:49:13 +00001006 fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset);
Amaury Poulye36471d2011-11-01 11:23:43 +00001007 break;
1008 }
1009 }
1010 }
1011
1012 /* final signature */
1013 printf(BLUE, "Final signature:\n");
1014 byte decrypted_block[32];
1015 if(sb_header->nr_keys > 0)
1016 {
1017 printf(GREEN, " Encrypted SHA-1:\n");
1018 byte *encrypted_block = &buf[filesize - 32];
1019 printf(OFF, " ");
1020 print_hex(YELLOW, encrypted_block, 16, true);
1021 printf(OFF, " ");
1022 print_hex(YELLOW, encrypted_block + 16, 16, true);
1023 /* decrypt it */
1024 cbc_mac(encrypted_block, decrypted_block, 2, real_key, buf, NULL, 0);
1025 }
1026 else
1027 memcpy(decrypted_block, &buf[filesize - 32], 32);
1028 printf(GREEN, " File SHA-1:\n ");
1029 print_hex(YELLOW, decrypted_block, 20, false);
1030 /* check it */
1031 sha_1_init(&sha_1_params);
1032 sha_1_update(&sha_1_params, buf, filesize - 32);
1033 sha_1_finish(&sha_1_params);
1034 sha_1_output(&sha_1_params, computed_sha1);
1035 if(memcmp(decrypted_block, computed_sha1, 20) == 0)
1036 printf(RED, " Ok\n");
1037 else
Amaury Pouly58279372011-11-06 01:49:13 +00001038 {
Amaury Poulye36471d2011-11-01 11:23:43 +00001039 printf(RED, " Failed\n");
Amaury Pouly58279372011-11-06 01:49:13 +00001040 fatal(SB_CHECKSUM_ERROR, "File SHA-1 error\n");
1041 }
Amaury Poulye36471d2011-11-01 11:23:43 +00001042 free(buf);
1043
1044 return sb_file;
1045 #undef printf
1046 #undef fatal
1047 #undef print_hex
1048}
1049
Amaury Poulycd832bd2011-11-06 19:41:29 +00001050void sb_free_instruction(struct sb_inst_t inst)
1051{
1052 free(inst.padding);
1053 free(inst.data);
1054}
1055
Amaury Pouly58279372011-11-06 01:49:13 +00001056void sb_free_section(struct sb_section_t sec)
1057{
1058 for(int j = 0; j < sec.nr_insts; j++)
Amaury Poulycd832bd2011-11-06 19:41:29 +00001059 sb_free_instruction(sec.insts[j]);
Amaury Pouly58279372011-11-06 01:49:13 +00001060 free(sec.insts);
1061}
1062
1063void sb_free(struct sb_file_t *file)
1064{
1065 if(!file) return;
1066
1067 for(int i = 0; i < file->nr_sections; i++)
1068 sb_free_section(file->sections[i]);
1069
1070 free(file->sections);
1071 free(file);
1072}
1073
Amaury Poulye36471d2011-11-01 11:23:43 +00001074void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf)
1075{
1076 #define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
1077 #define print_hex(c, p, len, nl) \
1078 do { printf(c, ""); print_hex(p, len, nl); } while(0)
1079
1080 #define TREE RED
1081 #define HEADER GREEN
1082 #define TEXT YELLOW
1083 #define TEXT2 BLUE
1084 #define SEP OFF
1085
1086 printf(HEADER, "SB File\n");
1087 printf(TREE, "+-");
1088 printf(HEADER, "Version: ");
1089 printf(TEXT, "1.%d\n", file->minor_version);
1090 printf(TREE, "+-");
1091 printf(HEADER, "Flags: ");
1092 printf(TEXT, "%x\n", file->flags);
1093 printf(TREE, "+-");
1094 printf(HEADER, "Drive Tag: ");
1095 printf(TEXT, "%x\n", file->drive_tag);
1096 printf(TREE, "+-");
1097 printf(HEADER, "First Boot Section ID: ");
1098 char name[5];
Amaury Poulydd0fffe2011-11-01 11:26:16 +00001099 sb_fill_section_name(name, file->first_boot_sec_id);
Amaury Poulye36471d2011-11-01 11:23:43 +00001100 printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name);
1101
Amaury Pouly58279372011-11-06 01:49:13 +00001102 if(file->override_real_key)
Amaury Poulye36471d2011-11-01 11:23:43 +00001103 {
1104 printf(TREE, "+-");
1105 printf(HEADER, "Real key: ");
Amaury Pouly58279372011-11-06 01:49:13 +00001106 print_hex(TEXT, file->real_key, 16, true);
Amaury Poulye36471d2011-11-01 11:23:43 +00001107 }
Amaury Pouly58279372011-11-06 01:49:13 +00001108 if(file->override_crypto_iv)
Amaury Poulye36471d2011-11-01 11:23:43 +00001109 {
1110 printf(TREE, "+-");
1111 printf(HEADER, "IV : ");
Amaury Pouly58279372011-11-06 01:49:13 +00001112 print_hex(TEXT, file->crypto_iv, 16, true);
Amaury Poulye36471d2011-11-01 11:23:43 +00001113 }
1114 printf(TREE, "+-");
1115 printf(HEADER, "Product Version: ");
1116 printf(TEXT, "%X.%X.%X\n", file->product_ver.major, file->product_ver.minor,
1117 file->product_ver.revision);
1118 printf(TREE, "+-");
1119 printf(HEADER, "Component Version: ");
1120 printf(TEXT, "%X.%X.%X\n", file->component_ver.major, file->component_ver.minor,
1121 file->component_ver.revision);
1122
1123 for(int i = 0; i < file->nr_sections; i++)
1124 {
1125 struct sb_section_t *sec = &file->sections[i];
1126 printf(TREE, "+-");
1127 printf(HEADER, "Section\n");
1128 printf(TREE,"| +-");
1129 printf(HEADER, "Identifier: ");
Amaury Poulydd0fffe2011-11-01 11:26:16 +00001130 sb_fill_section_name(name, sec->identifier);
Amaury Poulye36471d2011-11-01 11:23:43 +00001131 printf(TEXT, "%08x (%s)\n", sec->identifier, name);
1132 printf(TREE, "| +-");
1133 printf(HEADER, "Type: ");
1134 printf(TEXT, "%s (%s)\n", sec->is_data ? "Data Section" : "Boot Section",
1135 sec->is_cleartext ? "Cleartext" : "Encrypted");
1136 printf(TREE, "| +-");
1137 printf(HEADER, "Alignment: ");
1138 printf(TEXT, "%d (bytes)\n", sec->alignment);
1139 printf(TREE, "| +-");
1140 printf(HEADER, "Instructions\n");
1141 for(int j = 0; j < sec->nr_insts; j++)
1142 {
1143 struct sb_inst_t *inst = &sec->insts[j];
1144 printf(TREE, "| | +-");
1145 switch(inst->inst)
1146 {
1147 case SB_INST_DATA:
1148 printf(HEADER, "DATA");
1149 printf(SEP, " | ");
1150 printf(TEXT, "size=0x%08x\n", inst->size);
1151 break;
1152 case SB_INST_CALL:
1153 case SB_INST_JUMP:
1154 printf(HEADER, "%s", inst->inst == SB_INST_CALL ? "CALL" : "JUMP");
1155 printf(SEP, " | ");
1156 printf(TEXT, "addr=0x%08x", inst->addr);
1157 printf(SEP, " | ");
1158 printf(TEXT2, "arg=0x%08x\n", inst->argument);
1159 break;
1160 case SB_INST_LOAD:
1161 printf(HEADER, "LOAD");
1162 printf(SEP, " | ");
1163 printf(TEXT, "addr=0x%08x", inst->addr);
1164 printf(SEP, " | ");
1165 printf(TEXT2, "len=0x%08x\n", inst->size);
1166 break;
1167 case SB_INST_FILL:
1168 printf(HEADER, "FILL");
1169 printf(SEP, " | ");
1170 printf(TEXT, "addr=0x%08x", inst->addr);
1171 printf(SEP, " | ");
1172 printf(TEXT2, "len=0x%08x", inst->size);
1173 printf(SEP, " | ");
1174 printf(TEXT2, "pattern=0x%08x\n", inst->pattern);
1175 break;
1176 case SB_INST_MODE:
1177 printf(HEADER, "MODE");
1178 printf(SEP, " | ");
1179 printf(TEXT, "mod=0x%08x\n", inst->addr);
1180 break;
1181 case SB_INST_NOP:
1182 printf(HEADER, "NOOP\n");
1183 break;
1184 default:
1185 printf(GREY, "[Unknown instruction %x]\n", inst->inst);
1186 }
1187 }
1188 }
1189
1190 #undef printf
1191 #undef print_hex
1192}