sbtools: rename to imxtools, move imx_hid_recovery to imxtools/sbloader, fix tools to correctly handle/free memory, properly return error codes
git-svn-id: svn://svn.rockbox.org/rockbox/trunk@30907 a1c6a512-1295-4272-9138-f99709370657
This commit is contained in:
parent
33d6bd61b5
commit
5827937270
20 changed files with 392 additions and 198 deletions
|
@ -1,15 +0,0 @@
|
||||||
CC=gcc
|
|
||||||
LD=gcc
|
|
||||||
|
|
||||||
all: imx_hid_recovery
|
|
||||||
|
|
||||||
imx_hid_recovery.o: imx_hid_recovery.c
|
|
||||||
$(CC) -c -Wall -O2 -std=c99 `pkg-config --cflags libusb-1.0` -o $@ $<
|
|
||||||
|
|
||||||
imx_hid_recovery: imx_hid_recovery.o
|
|
||||||
$(LD) -o $@ $< `pkg-config --libs libusb-1.0`
|
|
||||||
|
|
||||||
clean:
|
|
||||||
rm -rf imx_hid_recovery.o
|
|
||||||
|
|
||||||
|
|
|
@ -3,8 +3,9 @@ CC=gcc
|
||||||
LD=gcc
|
LD=gcc
|
||||||
CFLAGS=-g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES)
|
CFLAGS=-g -std=c99 -W -Wall `pkg-config --cflags libusb-1.0` $(DEFINES)
|
||||||
LDFLAGS=`pkg-config --libs libusb-1.0`
|
LDFLAGS=`pkg-config --libs libusb-1.0`
|
||||||
|
BINS=elftosb sbtoelf sbloader
|
||||||
|
|
||||||
all: elftosb sbtoelf
|
all: $(BINS)
|
||||||
|
|
||||||
%.o: %.c
|
%.o: %.c
|
||||||
$(CC) $(CFLAGS) -c -o $@ $<
|
$(CC) $(CFLAGS) -c -o $@ $<
|
||||||
|
@ -15,8 +16,11 @@ sbtoelf: sbtoelf.o crc.o crypto.o aes128.o sha1.o elf.o misc.o sb.o
|
||||||
elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o sb.o
|
elftosb: elftosb.o crc.o crypto.o aes128.o sha1.o elf.o dbparser.o misc.o sb.o
|
||||||
$(LD) -o $@ $^ $(LDFLAGS)
|
$(LD) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
sbloader: sbloader.o
|
||||||
|
$(LD) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -fr *.o
|
rm -fr *.o
|
||||||
|
|
||||||
veryclean:
|
veryclean:
|
||||||
rm -rf sbtoelf elftosb
|
rm -rf $(BINS)
|
|
@ -63,6 +63,7 @@ void crypto_setup(enum crypto_method_t method, void *param);
|
||||||
#define CRYPTO_ERROR_DEVREJECT -5 /* device rejected cypto operation */
|
#define CRYPTO_ERROR_DEVREJECT -5 /* device rejected cypto operation */
|
||||||
#define CRYPTO_ERROR_DEVSILENT -6 /* device did not notify completion */
|
#define CRYPTO_ERROR_DEVSILENT -6 /* device did not notify completion */
|
||||||
#define CRYPTO_ERROR_DEVERR -7 /* device did something wrong (like return too small buffer) */
|
#define CRYPTO_ERROR_DEVERR -7 /* device did something wrong (like return too small buffer) */
|
||||||
|
#define CRYPTO_NUM_ERRORS 8
|
||||||
/* return 0 on success, <0 on error */
|
/* return 0 on success, <0 on error */
|
||||||
int crypto_apply(
|
int crypto_apply(
|
||||||
byte *in_data, /* Input data */
|
byte *in_data, /* Input data */
|
|
@ -19,6 +19,7 @@
|
||||||
*
|
*
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
|
#define _POSIX_C_SOURCE 200809L /* for strdup */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
|
@ -48,6 +49,7 @@ enum lexem_type_t
|
||||||
struct lexem_t
|
struct lexem_t
|
||||||
{
|
{
|
||||||
enum lexem_type_t type;
|
enum lexem_type_t type;
|
||||||
|
/* if str is not NULL, it must be a malloc'd pointer */
|
||||||
char *str;
|
char *str;
|
||||||
uint32_t num;
|
uint32_t num;
|
||||||
int line;
|
int line;
|
||||||
|
@ -390,8 +392,15 @@ struct lex_ctx_t
|
||||||
struct lexem_t lexem;
|
struct lexem_t lexem;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void next(struct lex_ctx_t *ctx)
|
/* When lexems hold strings (like identifier), it might be useful to steal
|
||||||
|
* the pointer and don't clean the lexem but in other case, one don't want
|
||||||
|
* to keep the pointer to the string and just want to release the memory.
|
||||||
|
* Thus clean_lexem should be true except when one keeps a pointer */
|
||||||
|
static inline void next(struct lex_ctx_t *ctx, bool clean_lexem)
|
||||||
{
|
{
|
||||||
|
if(clean_lexem)
|
||||||
|
free(ctx->lexem.str);
|
||||||
|
memset(&ctx->lexem, 0, sizeof(struct lexem_t));
|
||||||
next_lexem(&ctx->ctx, &ctx->lexem);
|
next_lexem(&ctx->ctx, &ctx->lexem);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -411,7 +420,7 @@ static uint32_t parse_term_expr(struct lex_ctx_t *ctx, struct cmd_option_t *cons
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
parse_error(ctx->lexem, "Number or constant identifier expected\n");
|
parse_error(ctx->lexem, "Number or constant identifier expected\n");
|
||||||
next(ctx);
|
next(ctx, true);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -420,7 +429,7 @@ static uint32_t parse_shift_expr(struct lex_ctx_t *ctx, struct cmd_option_t *con
|
||||||
uint32_t v = parse_term_expr(ctx, const_list);
|
uint32_t v = parse_term_expr(ctx, const_list);
|
||||||
while(ctx->lexem.type == LEX_LSHIFT)
|
while(ctx->lexem.type == LEX_LSHIFT)
|
||||||
{
|
{
|
||||||
next(ctx);
|
next(ctx, true);
|
||||||
v <<= parse_term_expr(ctx, const_list);
|
v <<= parse_term_expr(ctx, const_list);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
|
@ -431,7 +440,7 @@ static uint32_t parse_or_expr(struct lex_ctx_t *ctx, struct cmd_option_t *const_
|
||||||
uint32_t v = parse_shift_expr(ctx, const_list);
|
uint32_t v = parse_shift_expr(ctx, const_list);
|
||||||
while(ctx->lexem.type == LEX_OR)
|
while(ctx->lexem.type == LEX_OR)
|
||||||
{
|
{
|
||||||
next(ctx);
|
next(ctx, true);
|
||||||
v |= parse_shift_expr(ctx, const_list);
|
v |= parse_shift_expr(ctx, const_list);
|
||||||
}
|
}
|
||||||
return v;
|
return v;
|
||||||
|
@ -470,7 +479,7 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
{
|
{
|
||||||
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
|
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
|
||||||
memset(opt, 0, sizeof(struct cmd_option_t));
|
memset(opt, 0, sizeof(struct cmd_option_t));
|
||||||
opt->name = init_const_name[i];
|
opt->name = strdup(init_const_name[i]);
|
||||||
opt->is_string = false;
|
opt->is_string = false;
|
||||||
opt->val = init_const_value[i];
|
opt->val = init_const_value[i];
|
||||||
opt->next = cmd_file->constant_list;
|
opt->next = cmd_file->constant_list;
|
||||||
|
@ -483,14 +492,14 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
lctx.ctx.begin = buf;
|
lctx.ctx.begin = buf;
|
||||||
lctx.ctx.ptr = buf;
|
lctx.ctx.ptr = buf;
|
||||||
lctx.ctx.end = buf + size;
|
lctx.ctx.end = buf + size;
|
||||||
#define next() next(&lctx)
|
#define next(clean_lexem) next(&lctx, clean_lexem)
|
||||||
#define lexem lctx.lexem
|
#define lexem lctx.lexem
|
||||||
/* init lexer */
|
/* init lexer */
|
||||||
next();
|
next(false); /* don't clean init lexem because it doesn't exist */
|
||||||
/* constants ? */
|
/* constants ? */
|
||||||
if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants"))
|
if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "constants"))
|
||||||
{
|
{
|
||||||
next();
|
next(true);
|
||||||
if(lexem.type != LEX_LBRACE)
|
if(lexem.type != LEX_LBRACE)
|
||||||
parse_error(lexem, "'{' expected after 'constants'\n");
|
parse_error(lexem, "'{' expected after 'constants'\n");
|
||||||
|
|
||||||
|
@ -498,16 +507,16 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
{
|
{
|
||||||
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
|
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
|
||||||
memset(opt, 0, sizeof(struct cmd_option_t));
|
memset(opt, 0, sizeof(struct cmd_option_t));
|
||||||
next();
|
next(true);
|
||||||
if(lexem.type == LEX_RBRACE)
|
if(lexem.type == LEX_RBRACE)
|
||||||
break;
|
break;
|
||||||
if(lexem.type != LEX_IDENTIFIER)
|
if(lexem.type != LEX_IDENTIFIER)
|
||||||
parse_error(lexem, "Identifier expected in constants\n");
|
parse_error(lexem, "Identifier expected in constants\n");
|
||||||
opt->name = lexem.str;
|
opt->name = lexem.str;
|
||||||
next();
|
next(false); /* lexem string is kept as option name */
|
||||||
if(lexem.type != LEX_EQUAL)
|
if(lexem.type != LEX_EQUAL)
|
||||||
parse_error(lexem, "'=' expected after identifier\n");
|
parse_error(lexem, "'=' expected after identifier\n");
|
||||||
next();
|
next(true);
|
||||||
opt->is_string = false;
|
opt->is_string = false;
|
||||||
opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
|
opt->val = parse_intexpr(&lctx, cmd_file->constant_list);
|
||||||
opt->next = cmd_file->constant_list;
|
opt->next = cmd_file->constant_list;
|
||||||
|
@ -515,34 +524,34 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
if(lexem.type != LEX_SEMICOLON)
|
if(lexem.type != LEX_SEMICOLON)
|
||||||
parse_error(lexem, "';' expected after string\n");
|
parse_error(lexem, "';' expected after string\n");
|
||||||
}
|
}
|
||||||
next();
|
next(true);
|
||||||
}
|
}
|
||||||
/* options ? */
|
/* options ? */
|
||||||
if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options"))
|
if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "options"))
|
||||||
{
|
{
|
||||||
next();
|
next(true);
|
||||||
if(lexem.type != LEX_LBRACE)
|
if(lexem.type != LEX_LBRACE)
|
||||||
parse_error(lexem, "'{' expected after 'options'\n");
|
parse_error(lexem, "'{' expected after 'options'\n");
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
|
next(true);
|
||||||
memset(opt, 0, sizeof(struct cmd_option_t));
|
|
||||||
next();
|
|
||||||
if(lexem.type == LEX_RBRACE)
|
if(lexem.type == LEX_RBRACE)
|
||||||
break;
|
break;
|
||||||
|
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
|
||||||
|
memset(opt, 0, sizeof(struct cmd_option_t));
|
||||||
if(lexem.type != LEX_IDENTIFIER)
|
if(lexem.type != LEX_IDENTIFIER)
|
||||||
parse_error(lexem, "Identifier expected in options\n");
|
parse_error(lexem, "Identifier expected in options\n");
|
||||||
opt->name = lexem.str;
|
opt->name = lexem.str;
|
||||||
next();
|
next(false); /* lexem string is kept as option name */
|
||||||
if(lexem.type != LEX_EQUAL)
|
if(lexem.type != LEX_EQUAL)
|
||||||
parse_error(lexem, "'=' expected after identifier\n");
|
parse_error(lexem, "'=' expected after identifier\n");
|
||||||
next();
|
next(true);
|
||||||
if(lexem.type == LEX_STRING)
|
if(lexem.type == LEX_STRING)
|
||||||
{
|
{
|
||||||
opt->is_string = true;
|
opt->is_string = true;
|
||||||
opt->str = lexem.str;
|
opt->str = lexem.str;
|
||||||
next();
|
next(false); /* lexem string is kept as option name */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -554,18 +563,18 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
if(lexem.type != LEX_SEMICOLON)
|
if(lexem.type != LEX_SEMICOLON)
|
||||||
parse_error(lexem, "';' expected after string\n");
|
parse_error(lexem, "';' expected after string\n");
|
||||||
}
|
}
|
||||||
next();
|
next(true);
|
||||||
}
|
}
|
||||||
/* sources */
|
/* sources */
|
||||||
if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources"))
|
if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "sources"))
|
||||||
parse_error(lexem, "'sources' expected\n");
|
parse_error(lexem, "'sources' expected\n");
|
||||||
next();
|
next(true);
|
||||||
if(lexem.type != LEX_LBRACE)
|
if(lexem.type != LEX_LBRACE)
|
||||||
parse_error(lexem, "'{' expected after 'sources'\n");
|
parse_error(lexem, "'{' expected after 'sources'\n");
|
||||||
|
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
next();
|
next(true);
|
||||||
if(lexem.type == LEX_RBRACE)
|
if(lexem.type == LEX_RBRACE)
|
||||||
break;
|
break;
|
||||||
struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t));
|
struct cmd_source_t *src = xmalloc(sizeof(struct cmd_source_t));
|
||||||
|
@ -573,28 +582,28 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
if(lexem.type != LEX_IDENTIFIER)
|
if(lexem.type != LEX_IDENTIFIER)
|
||||||
parse_error(lexem, "identifier expected in sources\n");
|
parse_error(lexem, "identifier expected in sources\n");
|
||||||
src->identifier = lexem.str;
|
src->identifier = lexem.str;
|
||||||
next();
|
next(false); /* lexem string is kept as source name */
|
||||||
if(lexem.type != LEX_EQUAL)
|
if(lexem.type != LEX_EQUAL)
|
||||||
parse_error(lexem, "'=' expected after identifier\n");
|
parse_error(lexem, "'=' expected after identifier\n");
|
||||||
next();
|
next(true);
|
||||||
if(lexem.type == LEX_STRING)
|
if(lexem.type == LEX_STRING)
|
||||||
{
|
{
|
||||||
src->is_extern = false;
|
src->is_extern = false;
|
||||||
src->filename = lexem.str;
|
src->filename = lexem.str;
|
||||||
next();
|
next(false); /* lexem string is kept as file name */
|
||||||
}
|
}
|
||||||
else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern"))
|
else if(lexem.type == LEX_IDENTIFIER && !strcmp(lexem.str, "extern"))
|
||||||
{
|
{
|
||||||
src->is_extern = true;
|
src->is_extern = true;
|
||||||
src->filename = "<extern>";
|
src->filename = strdup("<extern>"); /* duplicate because it will be free'd */
|
||||||
next();
|
next(true);
|
||||||
if(lexem.type != LEX_LPAREN)
|
if(lexem.type != LEX_LPAREN)
|
||||||
parse_error(lexem, "'(' expected after 'extern'\n");
|
parse_error(lexem, "'(' expected after 'extern'\n");
|
||||||
next();
|
next(true);
|
||||||
src->extern_nr = parse_intexpr(&lctx, cmd_file->constant_list);
|
src->extern_nr = parse_intexpr(&lctx, cmd_file->constant_list);
|
||||||
if(lexem.type != LEX_RPAREN)
|
if(lexem.type != LEX_RPAREN)
|
||||||
parse_error(lexem, "')' expected\n");
|
parse_error(lexem, "')' expected\n");
|
||||||
next();
|
next(true);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
parse_error(lexem, "String or 'extern' expected after '='\n");
|
parse_error(lexem, "String or 'extern' expected after '='\n");
|
||||||
|
@ -612,18 +621,18 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
struct cmd_section_t *end_sec = NULL;
|
struct cmd_section_t *end_sec = NULL;
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
|
next(true);
|
||||||
|
if(lexem.type == LEX_EOF)
|
||||||
|
break;
|
||||||
struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t));
|
struct cmd_section_t *sec = xmalloc(sizeof(struct cmd_section_t));
|
||||||
struct cmd_inst_t *end_list = NULL;
|
struct cmd_inst_t *end_list = NULL;
|
||||||
memset(sec, 0, sizeof(struct cmd_section_t));
|
memset(sec, 0, sizeof(struct cmd_section_t));
|
||||||
next();
|
|
||||||
if(lexem.type == LEX_EOF)
|
|
||||||
break;
|
|
||||||
if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0)
|
if(lexem.type != LEX_IDENTIFIER || strcmp(lexem.str, "section") != 0)
|
||||||
parse_error(lexem, "'section' expected\n");
|
parse_error(lexem, "'section' expected\n");
|
||||||
next();
|
next(true);
|
||||||
if(lexem.type != LEX_LPAREN)
|
if(lexem.type != LEX_LPAREN)
|
||||||
parse_error(lexem, "'(' expected after 'section'\n");
|
parse_error(lexem, "'(' expected after 'section'\n");
|
||||||
next();
|
next(true);
|
||||||
/* can be any number */
|
/* can be any number */
|
||||||
sec->identifier = parse_intexpr(&lctx, cmd_file->constant_list);
|
sec->identifier = parse_intexpr(&lctx, cmd_file->constant_list);
|
||||||
/* options ? */
|
/* options ? */
|
||||||
|
@ -631,21 +640,21 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
{
|
{
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
next();
|
next(true);
|
||||||
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
|
struct cmd_option_t *opt = xmalloc(sizeof(struct cmd_option_t));
|
||||||
memset(opt, 0, sizeof(struct cmd_option_t));
|
memset(opt, 0, sizeof(struct cmd_option_t));
|
||||||
if(lexem.type != LEX_IDENTIFIER)
|
if(lexem.type != LEX_IDENTIFIER)
|
||||||
parse_error(lexem, "Identifier expected for section option\n");
|
parse_error(lexem, "Identifier expected for section option\n");
|
||||||
opt->name = lexem.str;
|
opt->name = lexem.str;
|
||||||
next();
|
next(false); /* lexem string is kept as option name */
|
||||||
if(lexem.type != LEX_EQUAL)
|
if(lexem.type != LEX_EQUAL)
|
||||||
parse_error(lexem, "'=' expected after option identifier\n");
|
parse_error(lexem, "'=' expected after option identifier\n");
|
||||||
next();
|
next(true);
|
||||||
if(lexem.type == LEX_STRING)
|
if(lexem.type == LEX_STRING)
|
||||||
{
|
{
|
||||||
opt->is_string = true;
|
opt->is_string = true;
|
||||||
opt->str = lexem.str;
|
opt->str = lexem.str;
|
||||||
next();
|
next(false); /* lexem string is kept as option string */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -658,18 +667,18 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
}
|
}
|
||||||
if(lexem.type != LEX_RPAREN)
|
if(lexem.type != LEX_RPAREN)
|
||||||
parse_error(lexem, "')' expected after section identifier\n");
|
parse_error(lexem, "')' expected after section identifier\n");
|
||||||
next();
|
next(true);
|
||||||
if(lexem.type == LEX_LBRACE)
|
if(lexem.type == LEX_LBRACE)
|
||||||
{
|
{
|
||||||
sec->is_data = false;
|
sec->is_data = false;
|
||||||
/* commands */
|
/* commands */
|
||||||
while(true)
|
while(true)
|
||||||
{
|
{
|
||||||
struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t));
|
next(true);
|
||||||
memset(inst, 0, sizeof(struct cmd_inst_t));
|
|
||||||
next();
|
|
||||||
if(lexem.type == LEX_RBRACE)
|
if(lexem.type == LEX_RBRACE)
|
||||||
break;
|
break;
|
||||||
|
struct cmd_inst_t *inst = xmalloc(sizeof(struct cmd_inst_t));
|
||||||
|
memset(inst, 0, sizeof(struct cmd_inst_t));
|
||||||
if(lexem.type != LEX_IDENTIFIER)
|
if(lexem.type != LEX_IDENTIFIER)
|
||||||
parse_error(lexem, "Instruction expected in section\n");
|
parse_error(lexem, "Instruction expected in section\n");
|
||||||
if(strcmp(lexem.str, "load") == 0)
|
if(strcmp(lexem.str, "load") == 0)
|
||||||
|
@ -682,7 +691,7 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
inst->type = CMD_MODE;
|
inst->type = CMD_MODE;
|
||||||
else
|
else
|
||||||
parse_error(lexem, "Instruction expected in section\n");
|
parse_error(lexem, "Instruction expected in section\n");
|
||||||
next();
|
next(true);
|
||||||
|
|
||||||
if(inst->type == CMD_LOAD)
|
if(inst->type == CMD_LOAD)
|
||||||
{
|
{
|
||||||
|
@ -691,12 +700,12 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
inst->identifier = lexem.str;
|
inst->identifier = lexem.str;
|
||||||
if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
|
if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
|
||||||
parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
|
parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
|
||||||
next();
|
next(false); /* lexem string kept as identifier */
|
||||||
if(lexem.type == LEX_RANGLE)
|
if(lexem.type == LEX_RANGLE)
|
||||||
{
|
{
|
||||||
// load at
|
// load at
|
||||||
inst->type = CMD_LOAD_AT;
|
inst->type = CMD_LOAD_AT;
|
||||||
next();
|
next(true);
|
||||||
inst->addr = parse_intexpr(&lctx, cmd_file->constant_list);
|
inst->addr = parse_intexpr(&lctx, cmd_file->constant_list);
|
||||||
}
|
}
|
||||||
if(lexem.type != LEX_SEMICOLON)
|
if(lexem.type != LEX_SEMICOLON)
|
||||||
|
@ -709,7 +718,7 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
inst->identifier = lexem.str;
|
inst->identifier = lexem.str;
|
||||||
if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
|
if(db_find_source_by_id(cmd_file, inst->identifier) == NULL)
|
||||||
parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
|
parse_error(lexem, "Undefined reference to source '%s'\n", inst->identifier);
|
||||||
next();
|
next(false); /* lexem string kept as identifier */
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -719,11 +728,11 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
|
|
||||||
if(lexem.type == LEX_LPAREN)
|
if(lexem.type == LEX_LPAREN)
|
||||||
{
|
{
|
||||||
next();
|
next(true);
|
||||||
inst->argument = parse_intexpr(&lctx, cmd_file->constant_list);
|
inst->argument = parse_intexpr(&lctx, cmd_file->constant_list);
|
||||||
if(lexem.type != LEX_RPAREN)
|
if(lexem.type != LEX_RPAREN)
|
||||||
parse_error(lexem, "Expected closing brace\n");
|
parse_error(lexem, "Expected closing brace\n");
|
||||||
next();
|
next(true);
|
||||||
}
|
}
|
||||||
if(lexem.type != LEX_SEMICOLON)
|
if(lexem.type != LEX_SEMICOLON)
|
||||||
parse_error(lexem, "';' expected after command\n");
|
parse_error(lexem, "';' expected after command\n");
|
||||||
|
@ -751,11 +760,11 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
else if(lexem.type == LEX_LE)
|
else if(lexem.type == LEX_LE)
|
||||||
{
|
{
|
||||||
sec->is_data = true;
|
sec->is_data = true;
|
||||||
next();
|
next(true);
|
||||||
if(lexem.type != LEX_IDENTIFIER)
|
if(lexem.type != LEX_IDENTIFIER)
|
||||||
parse_error(lexem, "Identifier expected after '<='\n");
|
parse_error(lexem, "Identifier expected after '<='\n");
|
||||||
sec->source_id = lexem.str;
|
sec->source_id = lexem.str;
|
||||||
next();
|
next(false); /* lexem string is kept as source id */
|
||||||
if(lexem.type != LEX_SEMICOLON)
|
if(lexem.type != LEX_SEMICOLON)
|
||||||
parse_error(lexem, "';' expected after identifier\n");
|
parse_error(lexem, "';' expected after identifier\n");
|
||||||
}
|
}
|
||||||
|
@ -776,6 +785,7 @@ struct cmd_file_t *db_parse_file(const char *file)
|
||||||
#undef lexem
|
#undef lexem
|
||||||
#undef next
|
#undef next
|
||||||
|
|
||||||
|
free(buf);
|
||||||
return cmd_file;
|
return cmd_file;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -783,3 +793,57 @@ void db_generate_default_sb_version(struct sb_version_t *ver)
|
||||||
{
|
{
|
||||||
ver->major = ver->minor = ver->revision = 0x999;
|
ver->major = ver->minor = ver->revision = 0x999;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void db_free_option_list(struct cmd_option_t *opt_list)
|
||||||
|
{
|
||||||
|
while(opt_list)
|
||||||
|
{
|
||||||
|
struct cmd_option_t *next = opt_list->next;
|
||||||
|
fflush(stdout);
|
||||||
|
free(opt_list->name);
|
||||||
|
free(opt_list->str);
|
||||||
|
free(opt_list);
|
||||||
|
opt_list = next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void db_free(struct cmd_file_t *file)
|
||||||
|
{
|
||||||
|
db_free_option_list(file->opt_list);
|
||||||
|
db_free_option_list(file->constant_list);
|
||||||
|
struct cmd_source_t *src = file->source_list;
|
||||||
|
while(src)
|
||||||
|
{
|
||||||
|
struct cmd_source_t *next = src->next;
|
||||||
|
free(src->identifier);
|
||||||
|
fflush(stdout);
|
||||||
|
free(src->filename);
|
||||||
|
if(src->loaded)
|
||||||
|
{
|
||||||
|
if(src->type == CMD_SRC_BIN)
|
||||||
|
free(src->bin.data);
|
||||||
|
if(src->type == CMD_SRC_ELF)
|
||||||
|
elf_release(&src->elf);
|
||||||
|
}
|
||||||
|
free(src);
|
||||||
|
src = next;
|
||||||
|
}
|
||||||
|
struct cmd_section_t *sec = file->section_list;
|
||||||
|
while(sec)
|
||||||
|
{
|
||||||
|
struct cmd_section_t *next = sec->next;
|
||||||
|
db_free_option_list(sec->opt_list);
|
||||||
|
free(sec->source_id);
|
||||||
|
struct cmd_inst_t *inst = sec->inst_list;
|
||||||
|
while(inst)
|
||||||
|
{
|
||||||
|
struct cmd_inst_t *next = inst->next;
|
||||||
|
free(inst->identifier);
|
||||||
|
free(inst);
|
||||||
|
inst = next;
|
||||||
|
}
|
||||||
|
free(sec);
|
||||||
|
sec = next;
|
||||||
|
}
|
||||||
|
free(file);
|
||||||
|
}
|
|
@ -102,7 +102,7 @@ struct cmd_section_t
|
||||||
struct cmd_file_t
|
struct cmd_file_t
|
||||||
{
|
{
|
||||||
struct cmd_option_t *opt_list;
|
struct cmd_option_t *opt_list;
|
||||||
struct cmd_option_t *constant_list; /* constant all always integers */
|
struct cmd_option_t *constant_list; /* constant are always integers */
|
||||||
struct cmd_source_t *source_list;
|
struct cmd_source_t *source_list;
|
||||||
struct cmd_section_t *section_list;
|
struct cmd_section_t *section_list;
|
||||||
};
|
};
|
||||||
|
@ -112,5 +112,7 @@ struct cmd_option_t *db_find_option_by_id(struct cmd_option_t *opt, const char *
|
||||||
bool db_parse_sb_version(struct sb_version_t *ver, char *str);
|
bool db_parse_sb_version(struct sb_version_t *ver, char *str);
|
||||||
void db_generate_default_sb_version(struct sb_version_t *ver);
|
void db_generate_default_sb_version(struct sb_version_t *ver);
|
||||||
struct cmd_file_t *db_parse_file(const char *file);
|
struct cmd_file_t *db_parse_file(const char *file);
|
||||||
|
void db_free_option_list(struct cmd_option_t *opt_list);
|
||||||
|
void db_free(struct cmd_file_t *file);
|
||||||
|
|
||||||
#endif /* __DBPARSER__ */
|
#endif /* __DBPARSER__ */
|
|
@ -153,10 +153,7 @@ typedef struct
|
||||||
|
|
||||||
void elf_init(struct elf_params_t *params)
|
void elf_init(struct elf_params_t *params)
|
||||||
{
|
{
|
||||||
params->has_start_addr = false;
|
memset(params, 0, sizeof(struct elf_params_t));
|
||||||
params->start_addr = 0;
|
|
||||||
params->first_section = NULL;
|
|
||||||
params->last_section = NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
extern void *xmalloc(size_t s);
|
extern void *xmalloc(size_t s);
|
||||||
|
@ -463,6 +460,7 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read,
|
||||||
if(!read(user, shdr.sh_offset, data, shdr.sh_size))
|
if(!read(user, shdr.sh_offset, data, shdr.sh_size))
|
||||||
error_printf("error read self section data\n");
|
error_printf("error read self section data\n");
|
||||||
elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data);
|
elf_add_load_section(params, shdr.sh_addr, shdr.sh_size, data);
|
||||||
|
free(data);
|
||||||
|
|
||||||
if(strtab)
|
if(strtab)
|
||||||
printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]);
|
printf(user, false, "create load segment for %s\n", &strtab[shdr.sh_name]);
|
||||||
|
@ -480,6 +478,7 @@ bool elf_read_file(struct elf_params_t *params, elf_read_fn_t read,
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
free(strtab);
|
||||||
/* run through segments */
|
/* run through segments */
|
||||||
for(int i = 1; i < ehdr.e_phnum; i++)
|
for(int i = 1; i < ehdr.e_phnum; i++)
|
||||||
{
|
{
|
||||||
|
@ -557,16 +556,20 @@ int elf_get_nr_sections(struct elf_params_t *params)
|
||||||
|
|
||||||
void elf_release(struct elf_params_t *params)
|
void elf_release(struct elf_params_t *params)
|
||||||
{
|
{
|
||||||
struct elf_section_t *sec, *next_sec;
|
struct elf_section_t *sec = params->first_section;
|
||||||
sec = params->first_section;
|
|
||||||
while(sec)
|
while(sec)
|
||||||
{
|
{
|
||||||
next_sec = sec->next;
|
struct elf_section_t *next_sec = sec->next;
|
||||||
if(sec->type == EST_LOAD)
|
if(sec->type == EST_LOAD)
|
||||||
free(sec->section);
|
free(sec->section);
|
||||||
free(sec);
|
free(sec);
|
||||||
sec = next_sec;
|
sec = next_sec;
|
||||||
}
|
}
|
||||||
params->first_section = NULL;
|
struct elf_segment_t *seg = params->first_segment;
|
||||||
params->last_section = NULL;
|
while(seg)
|
||||||
|
{
|
||||||
|
struct elf_segment_t *next_seg = seg->next;
|
||||||
|
free(seg);
|
||||||
|
seg = next_seg;
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -20,6 +20,7 @@
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#define _ISOC99_SOURCE
|
#define _ISOC99_SOURCE
|
||||||
|
#define _POSIX_C_SOURCE 200809L /* for strdup */
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <errno.h>
|
#include <errno.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -77,7 +78,9 @@ static void resolve_extern(struct cmd_source_t *src)
|
||||||
src->is_extern = false;
|
src->is_extern = false;
|
||||||
if(src->extern_nr < 0 || src->extern_nr >= g_extern_count)
|
if(src->extern_nr < 0 || src->extern_nr >= g_extern_count)
|
||||||
bug("There aren't enough file on command file to resolve extern(%d)\n", src->extern_nr);
|
bug("There aren't enough file on command file to resolve extern(%d)\n", src->extern_nr);
|
||||||
src->filename = g_extern[src->extern_nr];
|
/* first free the old src->filename content */
|
||||||
|
free(src->filename);
|
||||||
|
src->filename = strdup(g_extern[src->extern_nr]);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id)
|
static void load_elf_by_id(struct cmd_file_t *cmd_file, const char *id)
|
||||||
|
@ -206,7 +209,7 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
|
||||||
|
|
||||||
sec->insts[0].inst = SB_INST_DATA;
|
sec->insts[0].inst = SB_INST_DATA;
|
||||||
sec->insts[0].size = bin->size;
|
sec->insts[0].size = bin->size;
|
||||||
sec->insts[0].data = bin->data;
|
sec->insts[0].data = memdup(bin->data, bin->size);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -266,7 +269,7 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
|
||||||
sec->insts[idx].inst = SB_INST_LOAD;
|
sec->insts[idx].inst = SB_INST_LOAD;
|
||||||
sec->insts[idx].addr = esec->addr;
|
sec->insts[idx].addr = esec->addr;
|
||||||
sec->insts[idx].size = esec->size;
|
sec->insts[idx].size = esec->size;
|
||||||
sec->insts[idx++].data = esec->section;
|
sec->insts[idx++].data = memdup(esec->section, esec->size);
|
||||||
}
|
}
|
||||||
else if(esec->type == EST_FILL)
|
else if(esec->type == EST_FILL)
|
||||||
{
|
{
|
||||||
|
@ -296,7 +299,7 @@ static struct sb_file_t *apply_cmd_file(struct cmd_file_t *cmd_file)
|
||||||
struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin;
|
struct bin_param_t *bin = &db_find_source_by_id(cmd_file, cinst->identifier)->bin;
|
||||||
sec->insts[idx].inst = SB_INST_LOAD;
|
sec->insts[idx].inst = SB_INST_LOAD;
|
||||||
sec->insts[idx].addr = cinst->addr;
|
sec->insts[idx].addr = cinst->addr;
|
||||||
sec->insts[idx].data = bin->data;
|
sec->insts[idx].data = memdup(bin->data, bin->size);
|
||||||
sec->insts[idx++].size = bin->size;
|
sec->insts[idx++].size = bin->size;
|
||||||
}
|
}
|
||||||
else if(cinst->type == CMD_MODE)
|
else if(cinst->type == CMD_MODE)
|
||||||
|
@ -431,11 +434,18 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
struct cmd_file_t *cmd_file = db_parse_file(cmd_filename);
|
struct cmd_file_t *cmd_file = db_parse_file(cmd_filename);
|
||||||
struct sb_file_t *sb_file = apply_cmd_file(cmd_file);
|
struct sb_file_t *sb_file = apply_cmd_file(cmd_file);
|
||||||
|
db_free(cmd_file);
|
||||||
|
|
||||||
if(real_key.method == CRYPTO_KEY)
|
if(real_key.method == CRYPTO_KEY)
|
||||||
sb_file->real_key = &real_key.u.key;
|
{
|
||||||
|
sb_file->override_real_key = true;
|
||||||
|
memcpy(sb_file->real_key, real_key.u.key, 16);
|
||||||
|
}
|
||||||
if(crypto_iv.method == CRYPTO_KEY)
|
if(crypto_iv.method == CRYPTO_KEY)
|
||||||
sb_file->crypto_iv = &crypto_iv.u.key;
|
{
|
||||||
|
sb_file->override_crypto_iv = true;
|
||||||
|
memcpy(sb_file->crypto_iv, crypto_iv.u.key, 16);
|
||||||
|
}
|
||||||
|
|
||||||
/* fill with default parameters since there is no command file support for them */
|
/* fill with default parameters since there is no command file support for them */
|
||||||
sb_file->drive_tag = 0;
|
sb_file->drive_tag = 0;
|
||||||
|
@ -444,6 +454,8 @@ int main(int argc, char **argv)
|
||||||
sb_file->minor_version = 1;
|
sb_file->minor_version = 1;
|
||||||
|
|
||||||
sb_write_file(sb_file, output_filename);
|
sb_write_file(sb_file, output_filename);
|
||||||
|
sb_free(sb_file);
|
||||||
|
clear_keys();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -29,6 +29,14 @@ bool g_debug = false;
|
||||||
/**
|
/**
|
||||||
* Misc
|
* Misc
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
void *memdup(void *p, size_t len)
|
||||||
|
{
|
||||||
|
void *cpy = xmalloc(len);
|
||||||
|
memcpy(cpy, p, len);
|
||||||
|
return cpy;
|
||||||
|
}
|
||||||
|
|
||||||
void generate_random_data(void *buf, size_t sz)
|
void generate_random_data(void *buf, size_t sz)
|
||||||
{
|
{
|
||||||
FILE *rand_fd = fopen("/dev/urandom", "rb");
|
FILE *rand_fd = fopen("/dev/urandom", "rb");
|
||||||
|
@ -144,6 +152,12 @@ void add_keys(key_array_t ka, int kac)
|
||||||
g_nr_keys += kac;
|
g_nr_keys += kac;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void clear_keys()
|
||||||
|
{
|
||||||
|
free(g_key_array);
|
||||||
|
g_nr_keys = 0;
|
||||||
|
}
|
||||||
|
|
||||||
void add_keys_from_file(const char *key_file)
|
void add_keys_from_file(const char *key_file)
|
||||||
{
|
{
|
||||||
int size;
|
int size;
|
|
@ -38,6 +38,7 @@ typedef struct crypto_key_t *key_array_t;
|
||||||
int g_nr_keys;
|
int g_nr_keys;
|
||||||
key_array_t g_key_array;
|
key_array_t g_key_array;
|
||||||
|
|
||||||
|
void *memdup(void *p, size_t len);
|
||||||
void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt);
|
void *augment_array(void *arr, size_t elem_sz, size_t cnt, void *aug, size_t aug_cnt);
|
||||||
void generate_random_data(void *buf, size_t sz);
|
void generate_random_data(void *buf, size_t sz);
|
||||||
void *xmalloc(size_t s);
|
void *xmalloc(size_t s);
|
||||||
|
@ -47,6 +48,7 @@ void add_keys(key_array_t ka, int kac);
|
||||||
bool parse_key(char **str, struct crypto_key_t *key);
|
bool parse_key(char **str, struct crypto_key_t *key);
|
||||||
void add_keys_from_file(const char *key_file);
|
void add_keys_from_file(const char *key_file);
|
||||||
void print_key(struct crypto_key_t *key, bool newline);
|
void print_key(struct crypto_key_t *key, bool newline);
|
||||||
|
void clear_keys();
|
||||||
|
|
||||||
typedef char color_t[];
|
typedef char color_t[];
|
||||||
|
|
|
@ -138,7 +138,7 @@ static void compute_sb_offsets(struct sb_file_t *sb)
|
||||||
if(sb->sections[i].is_data)
|
if(sb->sections[i].is_data)
|
||||||
{
|
{
|
||||||
nr_aug_insts = 1;
|
nr_aug_insts = 1;
|
||||||
aug_insts = malloc(sizeof(struct sb_inst_t));
|
aug_insts = xmalloc(sizeof(struct sb_inst_t));
|
||||||
memset(aug_insts, 0, sizeof(struct sb_inst_t));
|
memset(aug_insts, 0, sizeof(struct sb_inst_t));
|
||||||
aug_insts[0].inst = SB_INST_DATA;
|
aug_insts[0].inst = SB_INST_DATA;
|
||||||
aug_insts[0].size = missing_sz * BLOCK_SIZE;
|
aug_insts[0].size = missing_sz * BLOCK_SIZE;
|
||||||
|
@ -150,7 +150,7 @@ static void compute_sb_offsets(struct sb_file_t *sb)
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
nr_aug_insts = missing_sz;
|
nr_aug_insts = missing_sz;
|
||||||
aug_insts = malloc(sizeof(struct sb_inst_t) * nr_aug_insts);
|
aug_insts = xmalloc(sizeof(struct sb_inst_t) * nr_aug_insts);
|
||||||
memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts);
|
memset(aug_insts, 0, sizeof(struct sb_inst_t) * nr_aug_insts);
|
||||||
for(int j = 0; j < nr_aug_insts; j++)
|
for(int j = 0; j < nr_aug_insts; j++)
|
||||||
{
|
{
|
||||||
|
@ -163,6 +163,7 @@ static void compute_sb_offsets(struct sb_file_t *sb)
|
||||||
sb->sections[i].insts = augment_array(sb->sections[i].insts, sizeof(struct sb_inst_t),
|
sb->sections[i].insts = augment_array(sb->sections[i].insts, sizeof(struct sb_inst_t),
|
||||||
sb->sections[i].nr_insts, aug_insts, nr_aug_insts);
|
sb->sections[i].nr_insts, aug_insts, nr_aug_insts);
|
||||||
sb->sections[i].nr_insts += nr_aug_insts;
|
sb->sections[i].nr_insts += nr_aug_insts;
|
||||||
|
free(aug_insts);
|
||||||
|
|
||||||
/* augment image and section size */
|
/* augment image and section size */
|
||||||
sb->image_size += missing_sz;
|
sb->image_size += missing_sz;
|
||||||
|
@ -299,12 +300,8 @@ void produce_sb_instruction(struct sb_inst_t *inst,
|
||||||
cmd->hdr.checksum = instruction_checksum(&cmd->hdr);
|
cmd->hdr.checksum = instruction_checksum(&cmd->hdr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void sb_write_file(struct sb_file_t *sb, const char *filename)
|
enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename)
|
||||||
{
|
{
|
||||||
FILE *fd = fopen(filename, "wb");
|
|
||||||
if(fd == NULL)
|
|
||||||
bugp("cannot open output file");
|
|
||||||
|
|
||||||
struct crypto_key_t real_key;
|
struct crypto_key_t real_key;
|
||||||
real_key.method = CRYPTO_KEY;
|
real_key.method = CRYPTO_KEY;
|
||||||
byte crypto_iv[16];
|
byte crypto_iv[16];
|
||||||
|
@ -324,8 +321,13 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
|
||||||
/* produce and write header */
|
/* produce and write header */
|
||||||
struct sb_header_t sb_hdr;
|
struct sb_header_t sb_hdr;
|
||||||
produce_sb_header(sb, &sb_hdr);
|
produce_sb_header(sb, &sb_hdr);
|
||||||
|
/* allocate image */
|
||||||
|
byte *buf = xmalloc(sb_hdr.image_size * BLOCK_SIZE);
|
||||||
|
byte *buf_p = buf;
|
||||||
|
#define write(p, sz) do { memcpy(buf_p, p, sz); buf_p += sz; } while(0)
|
||||||
|
|
||||||
sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr));
|
sha_1_update(&file_sha1, (byte *)&sb_hdr, sizeof(sb_hdr));
|
||||||
fwrite(&sb_hdr, 1, sizeof(sb_hdr), fd);
|
write(&sb_hdr, sizeof(sb_hdr));
|
||||||
|
|
||||||
memcpy(crypto_iv, &sb_hdr, 16);
|
memcpy(crypto_iv, &sb_hdr, 16);
|
||||||
|
|
||||||
|
@ -340,7 +342,7 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
|
||||||
struct sb_section_header_t sb_sec_hdr;
|
struct sb_section_header_t sb_sec_hdr;
|
||||||
produce_sb_section_header(&sb->sections[i], &sb_sec_hdr);
|
produce_sb_section_header(&sb->sections[i], &sb_sec_hdr);
|
||||||
sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr));
|
sha_1_update(&file_sha1, (byte *)&sb_sec_hdr, sizeof(sb_sec_hdr));
|
||||||
fwrite(&sb_sec_hdr, 1, sizeof(sb_sec_hdr), fd);
|
write(&sb_sec_hdr, sizeof(sb_sec_hdr));
|
||||||
/* update CBC-MACs */
|
/* update CBC-MACs */
|
||||||
for(int j = 0; j < g_nr_keys; j++)
|
for(int j = 0; j < g_nr_keys; j++)
|
||||||
crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
|
crypto_cbc((byte *)&sb_sec_hdr, NULL, sizeof(sb_sec_hdr) / BLOCK_SIZE,
|
||||||
|
@ -354,16 +356,18 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
|
||||||
crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i],
|
crypto_cbc(real_key.u.key, entry.key, 1, &g_key_array[i],
|
||||||
crypto_iv, NULL, 1);
|
crypto_iv, NULL, 1);
|
||||||
|
|
||||||
fwrite(&entry, 1, sizeof(entry), fd);
|
write(&entry, sizeof(entry));
|
||||||
sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry));
|
sha_1_update(&file_sha1, (byte *)&entry, sizeof(entry));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(cbc_macs);
|
||||||
|
|
||||||
/* HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK */
|
/* HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK HACK */
|
||||||
/* Image crafting, don't use it unless you understand what you do */
|
/* Image crafting, don't use it unless you understand what you do */
|
||||||
if(sb->real_key != NULL)
|
if(sb->override_real_key)
|
||||||
memcpy(real_key.u.key, *sb->real_key, 16);
|
memcpy(real_key.u.key, sb->real_key, 16);
|
||||||
if(sb->crypto_iv != NULL)
|
if(sb->override_crypto_iv)
|
||||||
memcpy(crypto_iv, *sb->crypto_iv, 16);
|
memcpy(crypto_iv, sb->crypto_iv, 16);
|
||||||
/* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */
|
/* KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH KCAH */
|
||||||
if(g_debug)
|
if(g_debug)
|
||||||
{
|
{
|
||||||
|
@ -386,7 +390,7 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
|
||||||
crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
|
crypto_cbc((byte *)&tag_cmd, (byte *)&tag_cmd, sizeof(tag_cmd) / BLOCK_SIZE,
|
||||||
&real_key, crypto_iv, NULL, 1);
|
&real_key, crypto_iv, NULL, 1);
|
||||||
sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd));
|
sha_1_update(&file_sha1, (byte *)&tag_cmd, sizeof(tag_cmd));
|
||||||
fwrite(&tag_cmd, 1, sizeof(tag_cmd), fd);
|
write(&tag_cmd, sizeof(tag_cmd));
|
||||||
/* produce other commands */
|
/* produce other commands */
|
||||||
byte cur_cbc_mac[16];
|
byte cur_cbc_mac[16];
|
||||||
memcpy(cur_cbc_mac, crypto_iv, 16);
|
memcpy(cur_cbc_mac, crypto_iv, 16);
|
||||||
|
@ -402,7 +406,7 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
|
||||||
crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
|
crypto_cbc((byte *)&cmd, (byte *)&cmd, sizeof(cmd) / BLOCK_SIZE,
|
||||||
&real_key, cur_cbc_mac, &cur_cbc_mac, 1);
|
&real_key, cur_cbc_mac, &cur_cbc_mac, 1);
|
||||||
sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
|
sha_1_update(&file_sha1, (byte *)&cmd, sizeof(cmd));
|
||||||
fwrite(&cmd, 1, sizeof(cmd), fd);
|
write(&cmd, sizeof(cmd));
|
||||||
}
|
}
|
||||||
/* data */
|
/* data */
|
||||||
if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA)
|
if(inst->inst == SB_INST_LOAD || inst->inst == SB_INST_DATA)
|
||||||
|
@ -415,7 +419,7 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
|
||||||
crypto_cbc(data, data, sz / BLOCK_SIZE,
|
crypto_cbc(data, data, sz / BLOCK_SIZE,
|
||||||
&real_key, cur_cbc_mac, &cur_cbc_mac, 1);
|
&real_key, cur_cbc_mac, &cur_cbc_mac, 1);
|
||||||
sha_1_update(&file_sha1, data, sz);
|
sha_1_update(&file_sha1, data, sz);
|
||||||
fwrite(data, 1, sz, fd);
|
write(data, sz);
|
||||||
free(data);
|
free(data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -427,22 +431,35 @@ void sb_write_file(struct sb_file_t *sb, const char *filename)
|
||||||
generate_random_data(final_sig + 20, 12);
|
generate_random_data(final_sig + 20, 12);
|
||||||
if(g_nr_keys > 0)
|
if(g_nr_keys > 0)
|
||||||
crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1);
|
crypto_cbc(final_sig, final_sig, 2, &real_key, crypto_iv, NULL, 1);
|
||||||
fwrite(final_sig, 1, 32, fd);
|
write(final_sig, 32);
|
||||||
|
|
||||||
fclose(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void *memdup(void *p, size_t len)
|
if(buf_p - buf != sb_hdr.image_size * BLOCK_SIZE)
|
||||||
{
|
bug("SB image buffer was not entirely filled !");
|
||||||
void *cpy = xmalloc(len);
|
|
||||||
memcpy(cpy, p, len);
|
FILE *fd = fopen(filename, "wb");
|
||||||
return cpy;
|
if(fd == NULL)
|
||||||
|
return SB_OPEN_ERROR;
|
||||||
|
if(fwrite(buf, sb_hdr.image_size * BLOCK_SIZE, 1, fd) != 1)
|
||||||
|
{
|
||||||
|
free(buf);
|
||||||
|
return SB_WRITE_ERROR;
|
||||||
|
}
|
||||||
|
fclose(fd);
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
return SB_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
|
static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
|
||||||
int size, const char *indent, void *u, sb_color_printf cprintf)
|
int size, const char *indent, void *u, sb_color_printf cprintf, enum sb_error_t *err)
|
||||||
{
|
{
|
||||||
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
|
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
|
||||||
|
#define fatal(e, ...) \
|
||||||
|
do { if(err) *err = e; \
|
||||||
|
cprintf(u, true, GREY, __VA_ARGS__); \
|
||||||
|
sb_free_section(*sec); \
|
||||||
|
free(sec); \
|
||||||
|
return NULL; } while(0)
|
||||||
|
|
||||||
struct sb_section_t *sec = xmalloc(sizeof(struct sb_section_t));
|
struct sb_section_t *sec = xmalloc(sizeof(struct sb_section_t));
|
||||||
memset(sec, 0, sizeof(struct sb_section_t));
|
memset(sec, 0, sizeof(struct sb_section_t));
|
||||||
|
@ -474,7 +491,7 @@ static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
|
||||||
printf(OFF, "%s", indent);
|
printf(OFF, "%s", indent);
|
||||||
uint8_t checksum = instruction_checksum(hdr);
|
uint8_t checksum = instruction_checksum(hdr);
|
||||||
if(checksum != hdr->checksum)
|
if(checksum != hdr->checksum)
|
||||||
printf(GREY, "[Bad checksum]");
|
fatal(SB_CHECKSUM_ERROR, "Bad instruction checksum");
|
||||||
if(hdr->flags != 0)
|
if(hdr->flags != 0)
|
||||||
{
|
{
|
||||||
printf(GREY, "[");
|
printf(GREY, "[");
|
||||||
|
@ -501,7 +518,10 @@ static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
|
||||||
if(load->crc == computed_crc)
|
if(load->crc == computed_crc)
|
||||||
printf(RED, " Ok\n");
|
printf(RED, " Ok\n");
|
||||||
else
|
else
|
||||||
|
{
|
||||||
printf(RED, " Failed (crc=0x%08x)\n", computed_crc);
|
printf(RED, " Failed (crc=0x%08x)\n", computed_crc);
|
||||||
|
fatal(SB_CHECKSUM_ERROR, "Instruction data crc error\n");
|
||||||
|
}
|
||||||
|
|
||||||
pos += load->len + sizeof(struct sb_instruction_load_t);
|
pos += load->len + sizeof(struct sb_instruction_load_t);
|
||||||
}
|
}
|
||||||
|
@ -559,7 +579,7 @@ static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf(RED, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos);
|
fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (unsigned long)pos);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -569,6 +589,7 @@ static struct sb_section_t *read_section(bool data_sec, uint32_t id, byte *buf,
|
||||||
|
|
||||||
return sec;
|
return sec;
|
||||||
#undef printf
|
#undef printf
|
||||||
|
#undef fatal
|
||||||
}
|
}
|
||||||
|
|
||||||
void sb_fill_section_name(char name[5], uint32_t identifier)
|
void sb_fill_section_name(char name[5], uint32_t identifier)
|
||||||
|
@ -595,25 +616,37 @@ static uint32_t guess_alignment(uint32_t off)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
||||||
sb_color_printf cprintf)
|
sb_color_printf cprintf, enum sb_error_t *err)
|
||||||
{
|
{
|
||||||
|
uint8_t *buf = NULL;
|
||||||
|
struct sb_file_t *sb_file = NULL;
|
||||||
|
|
||||||
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
|
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
|
||||||
#define fatal(...) do { cprintf(u, true, GREY, __VA_ARGS__); return NULL; } while(0)
|
#define fatal(e, ...) \
|
||||||
|
do { if(err) *err = e; \
|
||||||
|
cprintf(u, true, GREY, __VA_ARGS__); \
|
||||||
|
free(buf); \
|
||||||
|
sb_free(sb_file); \
|
||||||
|
return NULL; } while(0)
|
||||||
#define print_hex(c, p, len, nl) \
|
#define print_hex(c, p, len, nl) \
|
||||||
do { printf(c, ""); print_hex(p, len, nl); } while(0)
|
do { printf(c, ""); print_hex(p, len, nl); } while(0)
|
||||||
|
|
||||||
FILE *f = fopen(filename, "rb");
|
FILE *f = fopen(filename, "rb");
|
||||||
if(f == NULL)
|
if(f == NULL)
|
||||||
fatal("Cannot open file for reading\n");
|
fatal(SB_OPEN_ERROR, "Cannot open file for reading\n");
|
||||||
fseek(f, 0, SEEK_END);
|
fseek(f, 0, SEEK_END);
|
||||||
long filesize = ftell(f);
|
long filesize = ftell(f);
|
||||||
fseek(f, 0, SEEK_SET);
|
fseek(f, 0, SEEK_SET);
|
||||||
uint8_t *buf = xmalloc(filesize);
|
buf = xmalloc(filesize);
|
||||||
fread(buf, 1, filesize, f);
|
if(fread(buf, filesize, 1, f) != 1)
|
||||||
|
{
|
||||||
|
fclose(f);
|
||||||
|
fatal(SB_READ_ERROR, "Cannot read file\n");
|
||||||
|
}
|
||||||
fclose(f);
|
fclose(f);
|
||||||
|
|
||||||
struct sha_1_params_t sha_1_params;
|
struct sha_1_params_t sha_1_params;
|
||||||
struct sb_file_t *sb_file = xmalloc(sizeof(struct sb_file_t));
|
sb_file = xmalloc(sizeof(struct sb_file_t));
|
||||||
memset(sb_file, 0, sizeof(struct sb_file_t));
|
memset(sb_file, 0, sizeof(struct sb_file_t));
|
||||||
struct sb_header_t *sb_header = (struct sb_header_t *)buf;
|
struct sb_header_t *sb_header = (struct sb_header_t *)buf;
|
||||||
|
|
||||||
|
@ -624,13 +657,13 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
||||||
sb_file->first_boot_sec_id = sb_header->first_boot_sec_id;
|
sb_file->first_boot_sec_id = sb_header->first_boot_sec_id;
|
||||||
|
|
||||||
if(memcmp(sb_header->signature, "STMP", 4) != 0)
|
if(memcmp(sb_header->signature, "STMP", 4) != 0)
|
||||||
fatal("Bad signature\n");
|
fatal(SB_FORMAT_ERROR, "Bad signature\n");
|
||||||
if(sb_header->image_size * BLOCK_SIZE > filesize)
|
if(sb_header->image_size * BLOCK_SIZE > filesize)
|
||||||
fatal("File too small mismatch");
|
fatal(SB_FORMAT_ERROR, "File too small");
|
||||||
if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t))
|
if(sb_header->header_size * BLOCK_SIZE != sizeof(struct sb_header_t))
|
||||||
fatal("Bad header size");
|
fatal(SB_FORMAT_ERROR, "Bad header size");
|
||||||
if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t))
|
if(sb_header->sec_hdr_size * BLOCK_SIZE != sizeof(struct sb_section_header_t))
|
||||||
fatal("Bad section header size");
|
fatal(SB_FORMAT_ERROR, "Bad section header size");
|
||||||
|
|
||||||
if(filesize > sb_header->image_size * BLOCK_SIZE)
|
if(filesize > sb_header->image_size * BLOCK_SIZE)
|
||||||
{
|
{
|
||||||
|
@ -707,87 +740,107 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
||||||
/* encryption cbc-mac */
|
/* encryption cbc-mac */
|
||||||
byte real_key[16];
|
byte real_key[16];
|
||||||
bool valid_key = false; /* false until a matching key was found */
|
bool valid_key = false; /* false until a matching key was found */
|
||||||
|
|
||||||
if(sb_header->nr_keys > 0)
|
if(sb_header->nr_keys > 0)
|
||||||
{
|
{
|
||||||
if(sb_header->nr_keys > g_nr_keys)
|
byte (*cbcmacs)[16] = xmalloc(16 * g_nr_keys);
|
||||||
{
|
printf(BLUE, "Encryption keys\n");
|
||||||
fatal("SB file has %d keys but only %d were specified\n",
|
for(int i = 0; i < g_nr_keys; i++)
|
||||||
sb_header->nr_keys, g_nr_keys);
|
|
||||||
}
|
|
||||||
printf(BLUE, "Encryption data\n");
|
|
||||||
for(int i = 0; i < sb_header->nr_keys; i++)
|
|
||||||
{
|
{
|
||||||
printf(RED, " Key %d: ", i);
|
printf(RED, " Key %d: ", i);
|
||||||
printf(YELLOW, "");
|
printf(YELLOW, "");
|
||||||
print_key(&g_key_array[i], true);
|
print_key(&g_key_array[i], true);
|
||||||
printf(GREEN, " CBC-MAC of headers: ");
|
printf(GREEN, " CBC-MAC: ");
|
||||||
|
/* check it */
|
||||||
|
byte zero[16];
|
||||||
|
memset(zero, 0, 16);
|
||||||
|
int ret = crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections,
|
||||||
|
&g_key_array[i], zero, &cbcmacs[i], 1);
|
||||||
|
if(ret != CRYPTO_ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
free(cbcmacs);
|
||||||
|
fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d", ret);
|
||||||
|
}
|
||||||
|
print_hex(YELLOW, cbcmacs[i], 16, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(BLUE, "DEK\n");
|
||||||
|
for(int i = 0; i < sb_header->nr_keys; i++)
|
||||||
|
{
|
||||||
|
printf(RED, " Entry %d\n", i);
|
||||||
uint32_t ofs = sizeof(struct sb_header_t)
|
uint32_t ofs = sizeof(struct sb_header_t)
|
||||||
+ sizeof(struct sb_section_header_t) * sb_header->nr_sections
|
+ sizeof(struct sb_section_header_t) * sb_header->nr_sections
|
||||||
+ sizeof(struct sb_key_dictionary_entry_t) * i;
|
+ sizeof(struct sb_key_dictionary_entry_t) * i;
|
||||||
struct sb_key_dictionary_entry_t *dict_entry =
|
struct sb_key_dictionary_entry_t *dict_entry =
|
||||||
(struct sb_key_dictionary_entry_t *)&buf[ofs];
|
(struct sb_key_dictionary_entry_t *)&buf[ofs];
|
||||||
/* cbc mac */
|
/* cbc mac */
|
||||||
|
printf(GREEN, " Encrypted key: ");
|
||||||
|
print_hex(YELLOW, dict_entry->key, 16, true);
|
||||||
|
printf(GREEN, " CBC-MAC : ");
|
||||||
print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false);
|
print_hex(YELLOW, dict_entry->hdr_cbc_mac, 16, false);
|
||||||
/* check it */
|
/* check it */
|
||||||
byte computed_cbc_mac[16];
|
int idx = 0;
|
||||||
byte zero[16];
|
while(idx < g_nr_keys && memcmp(dict_entry->hdr_cbc_mac, cbcmacs[idx], 16) != 0)
|
||||||
memset(zero, 0, 16);
|
idx++;
|
||||||
crypto_cbc(buf, NULL, sb_header->header_size + sb_header->nr_sections,
|
if(idx != g_nr_keys)
|
||||||
&g_key_array[i], zero, &computed_cbc_mac, 1);
|
|
||||||
|
|
||||||
bool ok = memcmp(dict_entry->hdr_cbc_mac, computed_cbc_mac, 16) == 0;
|
|
||||||
if(ok)
|
|
||||||
{
|
{
|
||||||
valid_key = true;
|
printf(RED, " Match\n");
|
||||||
printf(RED, " Ok\n");
|
/* decrypt */
|
||||||
|
byte decrypted_key[16];
|
||||||
|
byte iv[16];
|
||||||
|
memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
|
||||||
|
int ret = crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[idx], iv, NULL, 0);
|
||||||
|
if(ret != CRYPTO_ERROR_SUCCESS)
|
||||||
|
{
|
||||||
|
free(cbcmacs);
|
||||||
|
fatal(SB_FIRST_CRYPTO_ERROR + ret, "Crypto error: %d\n", ret);
|
||||||
|
}
|
||||||
|
printf(GREEN, " Decrypted key: ");
|
||||||
|
print_hex(YELLOW, decrypted_key, 16, false);
|
||||||
|
if(valid_key)
|
||||||
|
{
|
||||||
|
if(memcmp(real_key, decrypted_key, 16) == 0)
|
||||||
|
printf(RED, " Cross-Check Ok");
|
||||||
|
else
|
||||||
|
printf(RED, " Cross-Check Failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
memcpy(real_key, decrypted_key, 16);
|
||||||
|
valid_key = true;
|
||||||
|
}
|
||||||
|
printf(OFF, "\n");
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
printf(RED, " Failed\n");
|
printf(RED, " Don't Match\n");
|
||||||
|
|
||||||
printf(GREEN, " Encrypted key : ");
|
|
||||||
print_hex(YELLOW, dict_entry->key, 16, true);
|
|
||||||
/* decrypt */
|
|
||||||
byte decrypted_key[16];
|
|
||||||
byte iv[16];
|
|
||||||
memcpy(iv, buf, 16); /* uses the first 16-bytes of SHA-1 sig as IV */
|
|
||||||
crypto_cbc(dict_entry->key, decrypted_key, 1, &g_key_array[i], iv, NULL, 0);
|
|
||||||
printf(GREEN, " Decrypted key : ");
|
|
||||||
print_hex(YELLOW, decrypted_key, 16, false);
|
|
||||||
/* cross-check or copy */
|
|
||||||
if(valid_key && ok)
|
|
||||||
memcpy(real_key, decrypted_key, 16);
|
|
||||||
else if(valid_key)
|
|
||||||
{
|
|
||||||
if(memcmp(real_key, decrypted_key, 16) == 0)
|
|
||||||
printf(RED, " Cross-Check Ok");
|
|
||||||
else
|
|
||||||
printf(RED, " Cross-Check Failed");
|
|
||||||
}
|
|
||||||
printf(OFF, "\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(cbcmacs);
|
||||||
|
|
||||||
|
if(!valid_key)
|
||||||
|
fatal(SB_NO_VALID_KEY, "No valid key found\n");
|
||||||
|
|
||||||
|
if(getenv("SB_REAL_KEY") != 0)
|
||||||
|
{
|
||||||
|
struct crypto_key_t k;
|
||||||
|
char *env = getenv("SB_REAL_KEY");
|
||||||
|
if(!parse_key(&env, &k) || *env)
|
||||||
|
bug("Invalid SB_REAL_KEY\n");
|
||||||
|
memcpy(real_key, k.u.key, 16);
|
||||||
|
}
|
||||||
|
|
||||||
|
printf(RED, " Summary:\n");
|
||||||
|
printf(GREEN, " Real key: ");
|
||||||
|
print_hex(YELLOW, real_key, 16, true);
|
||||||
|
printf(GREEN, " IV : ");
|
||||||
|
print_hex(YELLOW, buf, 16, true);
|
||||||
|
|
||||||
|
sb_file->override_real_key = true;
|
||||||
|
memcpy(sb_file->real_key, real_key, 16);
|
||||||
|
sb_file->override_crypto_iv = true;
|
||||||
|
memcpy(sb_file->crypto_iv, buf, 16);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(getenv("SB_REAL_KEY") != 0)
|
|
||||||
{
|
|
||||||
struct crypto_key_t k;
|
|
||||||
char *env = getenv("SB_REAL_KEY");
|
|
||||||
if(!parse_key(&env, &k) || *env)
|
|
||||||
bug("Invalid SB_REAL_KEY\n");
|
|
||||||
memcpy(real_key, k.u.key, 16);
|
|
||||||
}
|
|
||||||
|
|
||||||
printf(RED, " Summary:\n");
|
|
||||||
printf(GREEN, " Real key: ");
|
|
||||||
print_hex(YELLOW, real_key, 16, true);
|
|
||||||
printf(GREEN, " IV : ");
|
|
||||||
print_hex(YELLOW, buf, 16, true);
|
|
||||||
|
|
||||||
sb_file->real_key = xmalloc(16);
|
|
||||||
memcpy(*sb_file->real_key, real_key, 16);
|
|
||||||
sb_file->crypto_iv = xmalloc(16);
|
|
||||||
memcpy(*sb_file->crypto_iv, buf, 16);
|
|
||||||
|
|
||||||
/* sections */
|
/* sections */
|
||||||
if(!raw_mode)
|
if(!raw_mode)
|
||||||
{
|
{
|
||||||
|
@ -831,7 +884,7 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
||||||
memcpy(sec, buf + pos, size);
|
memcpy(sec, buf + pos, size);
|
||||||
|
|
||||||
struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier,
|
struct sb_section_t *s = read_section(data_sec, sec_hdr->identifier,
|
||||||
sec, size, " ", u, cprintf);
|
sec, size, " ", u, cprintf, err);
|
||||||
if(s)
|
if(s)
|
||||||
{
|
{
|
||||||
s->is_cleartext = !encrypted;
|
s->is_cleartext = !encrypted;
|
||||||
|
@ -839,6 +892,8 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
||||||
memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t));
|
memcpy(&sb_file->sections[i], s, sizeof(struct sb_section_t));
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
fatal(*err, "Error reading section\n");
|
||||||
|
|
||||||
free(sec);
|
free(sec);
|
||||||
}
|
}
|
||||||
|
@ -919,7 +974,7 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
||||||
memcpy(sec, buf + pos, size);
|
memcpy(sec, buf + pos, size);
|
||||||
|
|
||||||
struct sb_section_t *s = read_section(data_sec, tag->identifier,
|
struct sb_section_t *s = read_section(data_sec, tag->identifier,
|
||||||
sec, size, " ", u, cprintf);
|
sec, size, " ", u, cprintf, err);
|
||||||
if(s)
|
if(s)
|
||||||
{
|
{
|
||||||
s->is_cleartext = !encrypted;
|
s->is_cleartext = !encrypted;
|
||||||
|
@ -929,6 +984,8 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
||||||
s, 1);
|
s, 1);
|
||||||
free(s);
|
free(s);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
fatal(*err, "Error reading section\n");
|
||||||
free(sec);
|
free(sec);
|
||||||
|
|
||||||
/* last one ? */
|
/* last one ? */
|
||||||
|
@ -938,7 +995,7 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
printf(RED, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset);
|
fatal(SB_FORMAT_ERROR, "Unknown instruction %d at address 0x%08lx\n", hdr->opcode, (long)offset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -970,7 +1027,10 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
||||||
if(memcmp(decrypted_block, computed_sha1, 20) == 0)
|
if(memcmp(decrypted_block, computed_sha1, 20) == 0)
|
||||||
printf(RED, " Ok\n");
|
printf(RED, " Ok\n");
|
||||||
else
|
else
|
||||||
|
{
|
||||||
printf(RED, " Failed\n");
|
printf(RED, " Failed\n");
|
||||||
|
fatal(SB_CHECKSUM_ERROR, "File SHA-1 error\n");
|
||||||
|
}
|
||||||
free(buf);
|
free(buf);
|
||||||
|
|
||||||
return sb_file;
|
return sb_file;
|
||||||
|
@ -979,6 +1039,27 @@ struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
||||||
#undef print_hex
|
#undef print_hex
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void sb_free_section(struct sb_section_t sec)
|
||||||
|
{
|
||||||
|
for(int j = 0; j < sec.nr_insts; j++)
|
||||||
|
{
|
||||||
|
free(sec.insts[j].padding);
|
||||||
|
free(sec.insts[j].data);
|
||||||
|
}
|
||||||
|
free(sec.insts);
|
||||||
|
}
|
||||||
|
|
||||||
|
void sb_free(struct sb_file_t *file)
|
||||||
|
{
|
||||||
|
if(!file) return;
|
||||||
|
|
||||||
|
for(int i = 0; i < file->nr_sections; i++)
|
||||||
|
sb_free_section(file->sections[i]);
|
||||||
|
|
||||||
|
free(file->sections);
|
||||||
|
free(file);
|
||||||
|
}
|
||||||
|
|
||||||
void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf)
|
void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf)
|
||||||
{
|
{
|
||||||
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
|
#define printf(c, ...) cprintf(u, false, c, __VA_ARGS__)
|
||||||
|
@ -1007,17 +1088,17 @@ void sb_dump(struct sb_file_t *file, void *u, sb_color_printf cprintf)
|
||||||
sb_fill_section_name(name, file->first_boot_sec_id);
|
sb_fill_section_name(name, file->first_boot_sec_id);
|
||||||
printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name);
|
printf(TEXT, "%08x (%s)\n", file->first_boot_sec_id, name);
|
||||||
|
|
||||||
if(file->real_key)
|
if(file->override_real_key)
|
||||||
{
|
{
|
||||||
printf(TREE, "+-");
|
printf(TREE, "+-");
|
||||||
printf(HEADER, "Real key: ");
|
printf(HEADER, "Real key: ");
|
||||||
print_hex(TEXT, *file->real_key, 16, true);
|
print_hex(TEXT, file->real_key, 16, true);
|
||||||
}
|
}
|
||||||
if(file->crypto_iv)
|
if(file->override_crypto_iv)
|
||||||
{
|
{
|
||||||
printf(TREE, "+-");
|
printf(TREE, "+-");
|
||||||
printf(HEADER, "IV : ");
|
printf(HEADER, "IV : ");
|
||||||
print_hex(TEXT, *file->crypto_iv, 16, true);
|
print_hex(TEXT, file->crypto_iv, 16, true);
|
||||||
}
|
}
|
||||||
printf(TREE, "+-");
|
printf(TREE, "+-");
|
||||||
printf(HEADER, "Product Version: ");
|
printf(HEADER, "Product Version: ");
|
|
@ -191,9 +191,11 @@ struct sb_section_t
|
||||||
struct sb_file_t
|
struct sb_file_t
|
||||||
{
|
{
|
||||||
/* override real, otherwise it is randomly generated */
|
/* override real, otherwise it is randomly generated */
|
||||||
uint8_t (*real_key)[16];
|
bool override_real_key;
|
||||||
|
uint8_t real_key[16];
|
||||||
/* override crypto IV, use with caution ! Use NULL to generate it */
|
/* override crypto IV, use with caution ! Use NULL to generate it */
|
||||||
uint8_t (*crypto_iv)[16];
|
bool override_crypto_iv;
|
||||||
|
uint8_t crypto_iv[16];
|
||||||
|
|
||||||
int nr_sections;
|
int nr_sections;
|
||||||
uint16_t drive_tag;
|
uint16_t drive_tag;
|
||||||
|
@ -207,13 +209,29 @@ struct sb_file_t
|
||||||
uint32_t image_size; /* in blocks */
|
uint32_t image_size; /* in blocks */
|
||||||
};
|
};
|
||||||
|
|
||||||
void sb_write_file(struct sb_file_t *sb, const char *filename);
|
enum sb_error_t
|
||||||
|
{
|
||||||
|
SB_SUCCESS = 0,
|
||||||
|
SB_ERROR = -1,
|
||||||
|
SB_OPEN_ERROR = -2,
|
||||||
|
SB_READ_ERROR = -3,
|
||||||
|
SB_WRITE_ERROR = -4,
|
||||||
|
SB_FORMAT_ERROR = -5,
|
||||||
|
SB_CHECKSUM_ERROR = -6,
|
||||||
|
SB_NO_VALID_KEY = -7,
|
||||||
|
SB_FIRST_CRYPTO_ERROR = -8,
|
||||||
|
SB_LAST_CRYPTO_ERROR = SB_FIRST_CRYPTO_ERROR - CRYPTO_NUM_ERRORS,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum sb_error_t sb_write_file(struct sb_file_t *sb, const char *filename);
|
||||||
|
|
||||||
typedef void (*sb_color_printf)(void *u, bool err, color_t c, const char *f, ...);
|
typedef void (*sb_color_printf)(void *u, bool err, color_t c, const char *f, ...);
|
||||||
struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
struct sb_file_t *sb_read_file(const char *filename, bool raw_mode, void *u,
|
||||||
sb_color_printf printf);
|
sb_color_printf printf, enum sb_error_t *err);
|
||||||
|
|
||||||
void sb_fill_section_name(char name[5], uint32_t identifier);
|
void sb_fill_section_name(char name[5], uint32_t identifier);
|
||||||
void sb_dump(struct sb_file_t *file, void *u, sb_color_printf printf);
|
void sb_dump(struct sb_file_t *file, void *u, sb_color_printf printf);
|
||||||
|
void sb_free_section(struct sb_section_t file);
|
||||||
|
void sb_free(struct sb_file_t *file);
|
||||||
|
|
||||||
#endif /* __SB_H__ */
|
#endif /* __SB_H__ */
|
|
@ -268,7 +268,15 @@ int main(int argc, char **argv)
|
||||||
|
|
||||||
const char *sb_filename = argv[optind];
|
const char *sb_filename = argv[optind];
|
||||||
|
|
||||||
struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf);
|
enum sb_error_t err;
|
||||||
|
struct sb_file_t *file = sb_read_file(sb_filename, raw_mode, NULL, sb_printf, &err);
|
||||||
|
if(file == NULL)
|
||||||
|
{
|
||||||
|
color(OFF);
|
||||||
|
printf("SB read failed: %d\n", err);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
color(OFF);
|
color(OFF);
|
||||||
if(g_out_prefix)
|
if(g_out_prefix)
|
||||||
extract_sb_file(file);
|
extract_sb_file(file);
|
||||||
|
@ -283,12 +291,12 @@ int main(int argc, char **argv)
|
||||||
/* sb_read_file will fill real key and IV but we don't want to override
|
/* sb_read_file will fill real key and IV but we don't want to override
|
||||||
* them when looping back otherwise the output will be inconsistent and
|
* them when looping back otherwise the output will be inconsistent and
|
||||||
* garbage */
|
* garbage */
|
||||||
free(file->real_key);
|
file->override_real_key = false;
|
||||||
file->real_key = NULL;
|
file->override_crypto_iv = false;
|
||||||
free(file->crypto_iv);
|
|
||||||
file->crypto_iv = NULL;
|
|
||||||
sb_write_file(file, loopback);
|
sb_write_file(file, loopback);
|
||||||
}
|
}
|
||||||
|
sb_free(file);
|
||||||
|
clear_keys();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
Loading…
Reference in a new issue