From 94084eea3bd33a8a10b55a9717bd6ba762826323 Mon Sep 17 00:00:00 2001 From: Mario Six Date: Wed, 11 Jan 2017 16:00:53 +0100 Subject: tools: kwbimage: Fix dest addr To enable secure boot, we need to jump back into the BootROM to continue the SoC's boot process instead of letting the SPL load and run the main U-Boot image. But, since the u-boot-spl.img (including the 64 byte header) is loaded by the SoC as the main image, we need to compensate for the header length to get a correct entry point. Thus, we subtract the header size from the destination address, so that the execution address points at the actual entry point of the image. The current boards ignore both parameters anyway, so this change shouldn't concern them. Signed-off-by: Mario Six Reviewed-by: Stefan Roese Signed-off-by: Stefan Roese --- tools/kwbimage.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'tools') diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 69844d9..e04d319 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -410,7 +410,8 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, cpu_to_le32(payloadsz - headersz + sizeof(uint32_t)); main_hdr->headersz_lsb = cpu_to_le16(headersz & 0xFFFF); main_hdr->headersz_msb = (headersz & 0xFFFF0000) >> 16; - main_hdr->destaddr = cpu_to_le32(params->addr); + main_hdr->destaddr = cpu_to_le32(params->addr) + - sizeof(image_header_t); main_hdr->execaddr = cpu_to_le32(params->ep); main_hdr->srcaddr = cpu_to_le32(headersz); main_hdr->ext = hasext; -- cgit v1.1 From 94490a4a707003f91cc384f367131ad91b82fd0e Mon Sep 17 00:00:00 2001 From: Mario Six Date: Wed, 11 Jan 2017 16:00:54 +0100 Subject: tools: kwbimage: Fix style violations Fix some style violations: - nine instances of missing blank lines after declarations - one overly long line - one split string (which also rewords an error message more concisely) - two superfluous else Signed-off-by: Mario Six Reviewed-by: Stefan Roese Signed-off-by: Stefan Roese --- tools/kwbimage.c | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) (limited to 'tools') diff --git a/tools/kwbimage.c b/tools/kwbimage.c index e04d319..0e7c96a 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -103,6 +103,7 @@ struct image_cfg_element { static const char *image_boot_mode_name(unsigned int id) { int i; + for (i = 0; boot_modes[i].name; i++) if (boot_modes[i].id == id) return boot_modes[i].name; @@ -112,6 +113,7 @@ static const char *image_boot_mode_name(unsigned int id) int image_boot_mode_id(const char *boot_mode_name) { int i; + for (i = 0; boot_modes[i].name; i++) if (!strcmp(boot_modes[i].name, boot_mode_name)) return boot_modes[i].id; @@ -122,6 +124,7 @@ int image_boot_mode_id(const char *boot_mode_name) int image_nand_ecc_mode_id(const char *nand_ecc_mode_name) { int i; + for (i = 0; nand_ecc_modes[i].name; i++) if (!strcmp(nand_ecc_modes[i].name, nand_ecc_mode_name)) return nand_ecc_modes[i].id; @@ -359,14 +362,14 @@ static size_t image_headersz_v1(struct image_tool_params *params, #if defined(CONFIG_SYS_U_BOOT_OFFS) if (headersz > CONFIG_SYS_U_BOOT_OFFS) { - fprintf(stderr, "Error: Image header (incl. SPL image) too big!\n"); + fprintf(stderr, + "Error: Image header (incl. SPL image) too big!\n"); fprintf(stderr, "header=0x%x CONFIG_SYS_U_BOOT_OFFS=0x%x!\n", (int)headersz, CONFIG_SYS_U_BOOT_OFFS); fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n"); return 0; - } else { - headersz = CONFIG_SYS_U_BOOT_OFFS; } + headersz = CONFIG_SYS_U_BOOT_OFFS; #endif /* @@ -514,11 +517,13 @@ static int image_create_config_parse_oneline(char *line, keyword = strtok_r(line, deliminiters, &saveptr); if (!strcmp(keyword, "VERSION")) { char *value = strtok_r(NULL, deliminiters, &saveptr); + el->type = IMAGE_CFG_VERSION; el->version = atoi(value); } else if (!strcmp(keyword, "BOOT_FROM")) { char *value = strtok_r(NULL, deliminiters, &saveptr); int ret = image_boot_mode_id(value); + if (ret < 0) { fprintf(stderr, "Invalid boot media '%s'\n", value); @@ -528,16 +533,19 @@ static int image_create_config_parse_oneline(char *line, el->bootfrom = ret; } else if (!strcmp(keyword, "NAND_BLKSZ")) { char *value = strtok_r(NULL, deliminiters, &saveptr); + el->type = IMAGE_CFG_NAND_BLKSZ; el->nandblksz = strtoul(value, NULL, 16); } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) { char *value = strtok_r(NULL, deliminiters, &saveptr); + el->type = IMAGE_CFG_NAND_BADBLK_LOCATION; el->nandbadblklocation = strtoul(value, NULL, 16); } else if (!strcmp(keyword, "NAND_ECC_MODE")) { char *value = strtok_r(NULL, deliminiters, &saveptr); int ret = image_nand_ecc_mode_id(value); + if (ret < 0) { fprintf(stderr, "Invalid NAND ECC mode '%s'\n", value); @@ -547,6 +555,7 @@ static int image_create_config_parse_oneline(char *line, el->nandeccmode = ret; } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) { char *value = strtok_r(NULL, deliminiters, &saveptr); + el->type = IMAGE_CFG_NAND_PAGESZ; el->nandpagesz = strtoul(value, NULL, 16); } else if (!strcmp(keyword, "BINARY")) { @@ -800,8 +809,8 @@ static int kwbimage_check_image_types(uint8_t type) { if (type == IH_TYPE_KWBIMAGE) return EXIT_SUCCESS; - else - return EXIT_FAILURE; + + return EXIT_FAILURE; } static int kwbimage_verify_header(unsigned char *ptr, int image_size, @@ -874,9 +883,9 @@ static int kwbimage_generate(struct image_tool_params *params, static int kwbimage_check_params(struct image_tool_params *params) { if (!strlen(params->imagename)) { - fprintf(stderr, "Error:%s - Configuration file not specified, " - "it is needed for kwbimage generation\n", - params->cmdname); + char *msg = "Configuration file for kwbimage creation omitted"; + + fprintf(stderr, "Error:%s - %s\n", params->cmdname, msg); return CFG_INVALID; } -- cgit v1.1 From 885fba155c70871cfbe83f13ed98cd804a049058 Mon Sep 17 00:00:00 2001 From: Mario Six Date: Wed, 11 Jan 2017 16:00:55 +0100 Subject: tools: kwbimage: Fix arithmetic with void pointers Arithmetic with void pointers, e.g. a - b where both a and b are void pointers, is undefined in the C standard. Since we are operating with byte data here, we switch the void pointers to uint8_t pointers, and add the necessary casts. Signed-off-by: Mario Six Reviewed-by: Stefan Roese Signed-off-by: Stefan Roese --- tools/kwbimage.c | 22 ++++++++++++---------- 1 file changed, 12 insertions(+), 10 deletions(-) (limited to 'tools') diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 0e7c96a..edc5d34 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -231,7 +231,7 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params, size_t headersz; struct main_hdr_v0 *main_hdr; struct ext_hdr_v0 *ext_hdr; - void *image; + uint8_t *image; int has_ext = 0; /* @@ -258,7 +258,7 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params, memset(image, 0, headersz); - main_hdr = image; + main_hdr = (struct main_hdr_v0 *)image; /* Fill in the main header */ main_hdr->blocksize = @@ -284,7 +284,8 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params, if (has_ext) { int cfgi, datai; - ext_hdr = image + sizeof(struct main_hdr_v0); + ext_hdr = (struct ext_hdr_v0 *) + (image + sizeof(struct main_hdr_v0)); ext_hdr->offset = cpu_to_le32(0x40); for (cfgi = 0, datai = 0; cfgi < cfgn; cfgi++) { @@ -385,7 +386,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, struct image_cfg_element *e, *binarye; struct main_hdr_v1 *main_hdr; size_t headersz; - void *image, *cur; + uint8_t *image, *cur; int hasext = 0; int ret; @@ -405,8 +406,8 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, memset(image, 0, headersz); - cur = main_hdr = image; - cur += sizeof(struct main_hdr_v1); + main_hdr = (struct main_hdr_v1 *)image; + cur = image + sizeof(struct main_hdr_v1); /* Fill the main header */ main_hdr->blocksize = @@ -437,7 +438,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, binarye = image_find_option(IMAGE_CFG_BINARY); if (binarye) { - struct opt_hdr_v1 *hdr = cur; + struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)cur; uint32_t *args; size_t binhdrsz; struct stat s; @@ -470,7 +471,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, cur += sizeof(struct opt_hdr_v1); - args = cur; + args = (uint32_t *)cur; *args = cpu_to_le32(binarye->binary.nargs); args++; for (argi = 0; argi < binarye->binary.nargs; argi++) @@ -820,7 +821,7 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size, struct ext_hdr_v0 *ext_hdr; uint8_t checksum; - main_hdr = (void *)ptr; + main_hdr = (struct main_hdr_v0 *)ptr; checksum = image_checksum8(ptr, sizeof(struct main_hdr_v0) - sizeof(uint8_t)); @@ -829,7 +830,8 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size, /* Only version 0 extended header has checksum */ if (image_version((void *)ptr) == 0) { - ext_hdr = (void *)ptr + sizeof(struct main_hdr_v0); + ext_hdr = (struct ext_hdr_v0 *) + (ptr + sizeof(struct main_hdr_v0)); checksum = image_checksum8(ext_hdr, sizeof(struct ext_hdr_v0) - sizeof(uint8_t)); -- cgit v1.1 From e89016c44bc48539d95ef8b4552e77a38b1e5fdc Mon Sep 17 00:00:00 2001 From: Mario Six Date: Wed, 11 Jan 2017 16:00:56 +0100 Subject: tools: kwbimage: Reduce scope of variables This patch reduces the scope of some variables. Signed-off-by: Mario Six Reviewed-by: Stefan Roese Signed-off-by: Stefan Roese --- tools/kwbimage.c | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/kwbimage.c b/tools/kwbimage.c index edc5d34..4fd9389 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -230,7 +230,6 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params, struct image_cfg_element *e; size_t headersz; struct main_hdr_v0 *main_hdr; - struct ext_hdr_v0 *ext_hdr; uint8_t *image; int has_ext = 0; @@ -282,6 +281,7 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params, /* Generate the ext header */ if (has_ext) { + struct ext_hdr_v0 *ext_hdr; int cfgi, datai; ext_hdr = (struct ext_hdr_v0 *) @@ -313,7 +313,6 @@ static size_t image_headersz_v1(struct image_tool_params *params, { struct image_cfg_element *binarye; size_t headersz; - int ret; /* * Calculate the size of the header and the size of the @@ -333,6 +332,7 @@ static size_t image_headersz_v1(struct image_tool_params *params, binarye = image_find_option(IMAGE_CFG_BINARY); if (binarye) { + int ret; struct stat s; ret = stat(binarye->binary.file, &s); @@ -388,7 +388,6 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, size_t headersz; uint8_t *image, *cur; int hasext = 0; - int ret; /* * Calculate the size of the header and the size of the @@ -444,6 +443,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, struct stat s; int argi; FILE *bin; + int ret; hdr->headertype = OPT_HDR_V1_BINARY_TYPE; @@ -818,7 +818,6 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size, struct image_tool_params *params) { struct main_hdr_v0 *main_hdr; - struct ext_hdr_v0 *ext_hdr; uint8_t checksum; main_hdr = (struct main_hdr_v0 *)ptr; @@ -830,6 +829,8 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size, /* Only version 0 extended header has checksum */ if (image_version((void *)ptr) == 0) { + struct ext_hdr_v0 *ext_hdr; + ext_hdr = (struct ext_hdr_v0 *) (ptr + sizeof(struct main_hdr_v0)); checksum = image_checksum8(ext_hdr, -- cgit v1.1 From e93cf53f14b5c246fda6739ed4f3f1c4817c2f0c Mon Sep 17 00:00:00 2001 From: Mario Six Date: Wed, 11 Jan 2017 16:00:57 +0100 Subject: tools: kwbimage: Remove unused parameter The parameter 'params' of the image_headersz_v1 function is never used by the function. Hence, remove it. Signed-off-by: Mario Six Reviewed-by: Stefan Roese Signed-off-by: Stefan Roese --- tools/kwbimage.c | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'tools') diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 4fd9389..87587f8 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -308,8 +308,7 @@ static void *image_create_v0(size_t *imagesz, struct image_tool_params *params, return image; } -static size_t image_headersz_v1(struct image_tool_params *params, - int *hasext) +static size_t image_headersz_v1(int *hasext) { struct image_cfg_element *binarye; size_t headersz; @@ -393,7 +392,7 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, * Calculate the size of the header and the size of the * payload */ - headersz = image_headersz_v1(params, &hasext); + headersz = image_headersz_v1(&hasext); if (headersz == 0) return NULL; @@ -855,7 +854,7 @@ static int kwbimage_generate(struct image_tool_params *params, alloc_len = sizeof(struct main_hdr_v0) + sizeof(struct ext_hdr_v0); } else { - alloc_len = image_headersz_v1(params, NULL); + alloc_len = image_headersz_v1(NULL); } hdr = malloc(alloc_len); -- cgit v1.1 From 79066ef8c9d3c56b46e41c290ae0f598a6d1c59f Mon Sep 17 00:00:00 2001 From: Mario Six Date: Wed, 11 Jan 2017 16:00:58 +0100 Subject: tools: kwbimage: Factor out add_binary_header_v1 In preparation of adding the creation of secure headers, we factor the add_binary_header_v1 function out of the image_create_v1 function. Signed-off-by: Mario Six Reviewed-by: Stefan Roese Signed-off-by: Stefan Roese --- tools/kwbimage.c | 146 ++++++++++++++++++++++++++++++------------------------- 1 file changed, 79 insertions(+), 67 deletions(-) (limited to 'tools') diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 87587f8..6cd4c34 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -369,6 +369,7 @@ static size_t image_headersz_v1(int *hasext) fprintf(stderr, "Increase CONFIG_SYS_U_BOOT_OFFS!\n"); return 0; } + headersz = CONFIG_SYS_U_BOOT_OFFS; #endif @@ -379,10 +380,85 @@ static size_t image_headersz_v1(int *hasext) return ALIGN_SUP(headersz, 4096); } +int add_binary_header_v1(uint8_t *cur) +{ + struct image_cfg_element *binarye; + struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)cur; + uint32_t *args; + size_t binhdrsz; + struct stat s; + int argi; + FILE *bin; + int ret; + + binarye = image_find_option(IMAGE_CFG_BINARY); + + if (!binarye) + return 0; + + hdr->headertype = OPT_HDR_V1_BINARY_TYPE; + + bin = fopen(binarye->binary.file, "r"); + if (!bin) { + fprintf(stderr, "Cannot open binary file %s\n", + binarye->binary.file); + return -1; + } + + fstat(fileno(bin), &s); + + binhdrsz = sizeof(struct opt_hdr_v1) + + (binarye->binary.nargs + 2) * sizeof(uint32_t) + + s.st_size; + + /* + * The size includes the binary image size, rounded + * up to a 4-byte boundary. Plus 4 bytes for the + * next-header byte and 3-byte alignment at the end. + */ + binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4; + hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF); + hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16; + + cur += sizeof(struct opt_hdr_v1); + + args = (uint32_t *)cur; + *args = cpu_to_le32(binarye->binary.nargs); + args++; + for (argi = 0; argi < binarye->binary.nargs; argi++) + args[argi] = cpu_to_le32(binarye->binary.args[argi]); + + cur += (binarye->binary.nargs + 1) * sizeof(uint32_t); + + ret = fread(cur, s.st_size, 1, bin); + if (ret != 1) { + fprintf(stderr, + "Could not read binary image %s\n", + binarye->binary.file); + return -1; + } + + fclose(bin); + + cur += ALIGN_SUP(s.st_size, 4); + + /* + * For now, we don't support more than one binary + * header, and no other header types are + * supported. So, the binary header is necessarily the + * last one + */ + *((uint32_t *)cur) = 0x00000000; + + cur += sizeof(uint32_t); + + return 0; +} + static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, int payloadsz) { - struct image_cfg_element *e, *binarye; + struct image_cfg_element *e; struct main_hdr_v1 *main_hdr; size_t headersz; uint8_t *image, *cur; @@ -434,72 +510,8 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, if (e) main_hdr->flags = e->debug ? 0x1 : 0; - binarye = image_find_option(IMAGE_CFG_BINARY); - if (binarye) { - struct opt_hdr_v1 *hdr = (struct opt_hdr_v1 *)cur; - uint32_t *args; - size_t binhdrsz; - struct stat s; - int argi; - FILE *bin; - int ret; - - hdr->headertype = OPT_HDR_V1_BINARY_TYPE; - - bin = fopen(binarye->binary.file, "r"); - if (!bin) { - fprintf(stderr, "Cannot open binary file %s\n", - binarye->binary.file); - return NULL; - } - - fstat(fileno(bin), &s); - - binhdrsz = sizeof(struct opt_hdr_v1) + - (binarye->binary.nargs + 2) * sizeof(uint32_t) + - s.st_size; - - /* - * The size includes the binary image size, rounded - * up to a 4-byte boundary. Plus 4 bytes for the - * next-header byte and 3-byte alignment at the end. - */ - binhdrsz = ALIGN_SUP(binhdrsz, 4) + 4; - hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF); - hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16; - - cur += sizeof(struct opt_hdr_v1); - - args = (uint32_t *)cur; - *args = cpu_to_le32(binarye->binary.nargs); - args++; - for (argi = 0; argi < binarye->binary.nargs; argi++) - args[argi] = cpu_to_le32(binarye->binary.args[argi]); - - cur += (binarye->binary.nargs + 1) * sizeof(uint32_t); - - ret = fread(cur, s.st_size, 1, bin); - if (ret != 1) { - fprintf(stderr, - "Could not read binary image %s\n", - binarye->binary.file); - return NULL; - } - - fclose(bin); - - cur += ALIGN_SUP(s.st_size, 4); - - /* - * For now, we don't support more than one binary - * header, and no other header types are - * supported. So, the binary header is necessarily the - * last one - */ - *((uint32_t *)cur) = 0x00000000; - - cur += sizeof(uint32_t); - } + if (add_binary_header_v1(cur)) + return NULL; /* Calculate and set the header checksum */ main_hdr->checksum = image_checksum8(main_hdr, headersz); -- cgit v1.1 From 4991b4f7f1e55fed161462cefca7fe483fd3e477 Mon Sep 17 00:00:00 2001 From: Mario Six Date: Wed, 11 Jan 2017 16:00:59 +0100 Subject: tools: kwbimage: Refactor line parsing and fix error The function image_create_config_parse_oneline is pretty complex, and since more parameters will be added to support secure booting, we refactor the function to make it more readable. Also, when a line contained just a keyword without any parameters, strtok_r returned NULL, which was then indiscriminately fed into atoi, causing a segfault. To correct this, we add a NULL check before feeding the extracted token to atoi, and print an error message in case the token is NULL. Signed-off-by: Mario Six Reviewed-by: Stefan Roese Signed-off-by: Stefan Roese --- tools/kwbimage.c | 177 +++++++++++++++++++++++++++++++++---------------------- 1 file changed, 106 insertions(+), 71 deletions(-) (limited to 'tools') diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 6cd4c34..9aa9c74 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -55,22 +55,43 @@ struct nand_ecc_mode nand_ecc_modes[] = { #define BINARY_MAX_ARGS 8 /* In-memory representation of a line of the configuration file */ + +enum image_cfg_type { + IMAGE_CFG_VERSION = 0x1, + IMAGE_CFG_BOOT_FROM, + IMAGE_CFG_DEST_ADDR, + IMAGE_CFG_EXEC_ADDR, + IMAGE_CFG_NAND_BLKSZ, + IMAGE_CFG_NAND_BADBLK_LOCATION, + IMAGE_CFG_NAND_ECC_MODE, + IMAGE_CFG_NAND_PAGESZ, + IMAGE_CFG_BINARY, + IMAGE_CFG_PAYLOAD, + IMAGE_CFG_DATA, + IMAGE_CFG_BAUDRATE, + IMAGE_CFG_DEBUG, + + IMAGE_CFG_COUNT +} type; + +static const char * const id_strs[] = { + [IMAGE_CFG_VERSION] = "VERSION", + [IMAGE_CFG_BOOT_FROM] = "BOOT_FROM", + [IMAGE_CFG_DEST_ADDR] = "DEST_ADDR", + [IMAGE_CFG_EXEC_ADDR] = "EXEC_ADDR", + [IMAGE_CFG_NAND_BLKSZ] = "NAND_BLKSZ", + [IMAGE_CFG_NAND_BADBLK_LOCATION] = "NAND_BADBLK_LOCATION", + [IMAGE_CFG_NAND_ECC_MODE] = "NAND_ECC_MODE", + [IMAGE_CFG_NAND_PAGESZ] = "NAND_PAGE_SIZE", + [IMAGE_CFG_BINARY] = "BINARY", + [IMAGE_CFG_PAYLOAD] = "PAYLOAD", + [IMAGE_CFG_DATA] = "DATA", + [IMAGE_CFG_BAUDRATE] = "BAUDRATE", + [IMAGE_CFG_DEBUG] = "DEBUG", +}; + struct image_cfg_element { - enum { - IMAGE_CFG_VERSION = 0x1, - IMAGE_CFG_BOOT_FROM, - IMAGE_CFG_DEST_ADDR, - IMAGE_CFG_EXEC_ADDR, - IMAGE_CFG_NAND_BLKSZ, - IMAGE_CFG_NAND_BADBLK_LOCATION, - IMAGE_CFG_NAND_ECC_MODE, - IMAGE_CFG_NAND_PAGESZ, - IMAGE_CFG_BINARY, - IMAGE_CFG_PAYLOAD, - IMAGE_CFG_DATA, - IMAGE_CFG_BAUDRATE, - IMAGE_CFG_DEBUG, - } type; + enum image_cfg_type type; union { unsigned int version; unsigned int bootfrom; @@ -520,78 +541,94 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, return image; } +int recognize_keyword(char *keyword) +{ + int kw_id; + + for (kw_id = 1; kw_id < IMAGE_CFG_COUNT; ++kw_id) + if (!strcmp(keyword, id_strs[kw_id])) + return kw_id; + + return 0; +} + static int image_create_config_parse_oneline(char *line, struct image_cfg_element *el) { - char *keyword, *saveptr; - char deliminiters[] = " \t"; + char *keyword, *saveptr, *value1, *value2; + char delimiters[] = " \t"; + int keyword_id, ret, argi; + char *unknown_msg = "Ignoring unknown line '%s'\n"; - keyword = strtok_r(line, deliminiters, &saveptr); - if (!strcmp(keyword, "VERSION")) { - char *value = strtok_r(NULL, deliminiters, &saveptr); + keyword = strtok_r(line, delimiters, &saveptr); + keyword_id = recognize_keyword(keyword); - el->type = IMAGE_CFG_VERSION; - el->version = atoi(value); - } else if (!strcmp(keyword, "BOOT_FROM")) { - char *value = strtok_r(NULL, deliminiters, &saveptr); - int ret = image_boot_mode_id(value); + if (!keyword_id) { + fprintf(stderr, unknown_msg, line); + return 0; + } + + el->type = keyword_id; + + value1 = strtok_r(NULL, delimiters, &saveptr); + + if (!value1) { + fprintf(stderr, "Parameter missing in line '%s'\n", line); + return -1; + } + + switch (keyword_id) { + case IMAGE_CFG_VERSION: + el->version = atoi(value1); + break; + case IMAGE_CFG_BOOT_FROM: + ret = image_boot_mode_id(value1); if (ret < 0) { - fprintf(stderr, - "Invalid boot media '%s'\n", value); + fprintf(stderr, "Invalid boot media '%s'\n", value1); return -1; } - el->type = IMAGE_CFG_BOOT_FROM; el->bootfrom = ret; - } else if (!strcmp(keyword, "NAND_BLKSZ")) { - char *value = strtok_r(NULL, deliminiters, &saveptr); - - el->type = IMAGE_CFG_NAND_BLKSZ; - el->nandblksz = strtoul(value, NULL, 16); - } else if (!strcmp(keyword, "NAND_BADBLK_LOCATION")) { - char *value = strtok_r(NULL, deliminiters, &saveptr); - - el->type = IMAGE_CFG_NAND_BADBLK_LOCATION; - el->nandbadblklocation = - strtoul(value, NULL, 16); - } else if (!strcmp(keyword, "NAND_ECC_MODE")) { - char *value = strtok_r(NULL, deliminiters, &saveptr); - int ret = image_nand_ecc_mode_id(value); + break; + case IMAGE_CFG_NAND_BLKSZ: + el->nandblksz = strtoul(value1, NULL, 16); + break; + case IMAGE_CFG_NAND_BADBLK_LOCATION: + el->nandbadblklocation = strtoul(value1, NULL, 16); + break; + case IMAGE_CFG_NAND_ECC_MODE: + ret = image_nand_ecc_mode_id(value1); if (ret < 0) { - fprintf(stderr, - "Invalid NAND ECC mode '%s'\n", value); + fprintf(stderr, "Invalid NAND ECC mode '%s'\n", value1); return -1; } - el->type = IMAGE_CFG_NAND_ECC_MODE; el->nandeccmode = ret; - } else if (!strcmp(keyword, "NAND_PAGE_SIZE")) { - char *value = strtok_r(NULL, deliminiters, &saveptr); - - el->type = IMAGE_CFG_NAND_PAGESZ; - el->nandpagesz = strtoul(value, NULL, 16); - } else if (!strcmp(keyword, "BINARY")) { - char *value = strtok_r(NULL, deliminiters, &saveptr); - int argi = 0; + break; + case IMAGE_CFG_NAND_PAGESZ: + el->nandpagesz = strtoul(value1, NULL, 16); + break; + case IMAGE_CFG_BINARY: + argi = 0; - el->type = IMAGE_CFG_BINARY; - el->binary.file = strdup(value); + el->binary.file = strdup(value1); while (1) { - value = strtok_r(NULL, deliminiters, &saveptr); + char *value = strtok_r(NULL, delimiters, &saveptr); + if (!value) break; el->binary.args[argi] = strtoul(value, NULL, 16); argi++; if (argi >= BINARY_MAX_ARGS) { fprintf(stderr, - "Too many argument for binary\n"); + "Too many arguments for BINARY\n"); return -1; } } el->binary.nargs = argi; - } else if (!strcmp(keyword, "DATA")) { - char *value1 = strtok_r(NULL, deliminiters, &saveptr); - char *value2 = strtok_r(NULL, deliminiters, &saveptr); + break; + case IMAGE_CFG_DATA: + value2 = strtok_r(NULL, delimiters, &saveptr); if (!value1 || !value2) { fprintf(stderr, @@ -599,19 +636,17 @@ static int image_create_config_parse_oneline(char *line, return -1; } - el->type = IMAGE_CFG_DATA; el->regdata.raddr = strtoul(value1, NULL, 16); el->regdata.rdata = strtoul(value2, NULL, 16); - } else if (!strcmp(keyword, "BAUDRATE")) { - char *value = strtok_r(NULL, deliminiters, &saveptr); - el->type = IMAGE_CFG_BAUDRATE; - el->baudrate = strtoul(value, NULL, 10); - } else if (!strcmp(keyword, "DEBUG")) { - char *value = strtok_r(NULL, deliminiters, &saveptr); - el->type = IMAGE_CFG_DEBUG; - el->debug = strtoul(value, NULL, 10); - } else { - fprintf(stderr, "Ignoring unknown line '%s'\n", line); + break; + case IMAGE_CFG_BAUDRATE: + el->baudrate = strtoul(value1, NULL, 10); + break; + case IMAGE_CFG_DEBUG: + el->debug = strtoul(value1, NULL, 10); + break; + default: + fprintf(stderr, unknown_msg, line); } return 0; -- cgit v1.1 From a1b6b0a9c1f91756b93e6d804837dc178d79d39e Mon Sep 17 00:00:00 2001 From: Mario Six Date: Wed, 11 Jan 2017 16:01:00 +0100 Subject: arm: mvebu: Implement secure boot The patch implements secure booting for the mvebu architecture. This includes: - The addition of secure headers and all needed signatures and keys in mkimage - Commands capable of writing the board's efuses to both write the needed cryptographic data and enable the secure booting mechanism - The creation of convenience text files containing the necessary commands to write the efuses The KAK and CSK keys are expected to reside in the files kwb_kak.key and kwb_csk.key (OpenSSL 2048 bit private keys) in the top-level directory. Signed-off-by: Reinhard Pfau Signed-off-by: Mario Six Reviewed-by: Stefan Roese Reviewed-by: Simon Glass Signed-off-by: Stefan Roese --- tools/Makefile | 6 +- tools/kwbimage.c | 744 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- tools/kwbimage.h | 37 +++ 3 files changed, 780 insertions(+), 7 deletions(-) (limited to 'tools') diff --git a/tools/Makefile b/tools/Makefile index cefcedf..f5ac631 100644 --- a/tools/Makefile +++ b/tools/Makefile @@ -142,8 +142,12 @@ ifdef CONFIG_SYS_U_BOOT_OFFS HOSTCFLAGS_kwbimage.o += -DCONFIG_SYS_U_BOOT_OFFS=$(CONFIG_SYS_U_BOOT_OFFS) endif +ifneq ($(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X),) +HOSTCFLAGS_kwbimage.o += -DCONFIG_KWB_SECURE +endif + # MXSImage needs LibSSL -ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_FIT_SIGNATURE),) +ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_ARMADA_38X)$(CONFIG_ARMADA_39X)$(CONFIG_FIT_SIGNATURE),) HOSTLOADLIBES_mkimage += \ $(shell pkg-config --libs libssl libcrypto 2> /dev/null || echo "-lssl -lcrypto") diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 9aa9c74..93797c9 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -1,30 +1,47 @@ /* * Image manipulator for Marvell SoCs - * supports Kirkwood, Dove, Armada 370, and Armada XP + * supports Kirkwood, Dove, Armada 370, Armada XP, and Armada 38x * * (C) Copyright 2013 Thomas Petazzoni * * * SPDX-License-Identifier: GPL-2.0+ * - * Not implemented: support for the register headers and secure - * headers in v1 images + * Not implemented: support for the register headers in v1 images */ #include "imagetool.h" #include #include +#include #include #include "kwbimage.h" +#ifdef CONFIG_KWB_SECURE +#include +#include +#include +#include +#endif + static struct image_cfg_element *image_cfg; static int cfgn; +#ifdef CONFIG_KWB_SECURE +static int verbose_mode; +#endif struct boot_mode { unsigned int id; const char *name; }; +/* + * SHA2-256 hash + */ +struct hash_v1 { + uint8_t hash[32]; +}; + struct boot_mode boot_modes[] = { { 0x4D, "i2c" }, { 0x5A, "spi" }, @@ -70,6 +87,16 @@ enum image_cfg_type { IMAGE_CFG_DATA, IMAGE_CFG_BAUDRATE, IMAGE_CFG_DEBUG, + IMAGE_CFG_KAK, + IMAGE_CFG_CSK, + IMAGE_CFG_CSK_INDEX, + IMAGE_CFG_JTAG_DELAY, + IMAGE_CFG_BOX_ID, + IMAGE_CFG_FLASH_ID, + IMAGE_CFG_SEC_COMMON_IMG, + IMAGE_CFG_SEC_SPECIALIZED_IMG, + IMAGE_CFG_SEC_BOOT_DEV, + IMAGE_CFG_SEC_FUSE_DUMP, IMAGE_CFG_COUNT } type; @@ -88,6 +115,16 @@ static const char * const id_strs[] = { [IMAGE_CFG_DATA] = "DATA", [IMAGE_CFG_BAUDRATE] = "BAUDRATE", [IMAGE_CFG_DEBUG] = "DEBUG", + [IMAGE_CFG_KAK] = "KAK", + [IMAGE_CFG_CSK] = "CSK", + [IMAGE_CFG_CSK_INDEX] = "CSK_INDEX", + [IMAGE_CFG_JTAG_DELAY] = "JTAG_DELAY", + [IMAGE_CFG_BOX_ID] = "BOX_ID", + [IMAGE_CFG_FLASH_ID] = "FLASH_ID", + [IMAGE_CFG_SEC_COMMON_IMG] = "SEC_COMMON_IMG", + [IMAGE_CFG_SEC_SPECIALIZED_IMG] = "SEC_SPECIALIZED_IMG", + [IMAGE_CFG_SEC_BOOT_DEV] = "SEC_BOOT_DEV", + [IMAGE_CFG_SEC_FUSE_DUMP] = "SEC_FUSE_DUMP" }; struct image_cfg_element { @@ -110,6 +147,14 @@ struct image_cfg_element { struct ext_hdr_v0_reg regdata; unsigned int baudrate; unsigned int debug; + const char *key_name; + int csk_idx; + uint8_t jtag_delay; + uint32_t boxid; + uint32_t flashid; + bool sec_specialized_img; + unsigned int sec_boot_dev; + const char *name; }; }; @@ -178,6 +223,32 @@ image_count_options(unsigned int optiontype) return count; } +#if defined(CONFIG_KWB_SECURE) + +static int image_get_csk_index(void) +{ + struct image_cfg_element *e; + + e = image_find_option(IMAGE_CFG_CSK_INDEX); + if (!e) + return -1; + + return e->csk_idx; +} + +static bool image_get_spezialized_img(void) +{ + struct image_cfg_element *e; + + e = image_find_option(IMAGE_CFG_SEC_SPECIALIZED_IMG); + if (!e) + return false; + + return e->sec_specialized_img; +} + +#endif + /* * Compute a 8-bit checksum of a memory area. This algorithm follows * the requirements of the Marvell SoC BootROM specifications. @@ -245,6 +316,493 @@ static uint8_t baudrate_to_option(unsigned int baudrate) } } +#if defined(CONFIG_KWB_SECURE) +static void kwb_msg(const char *fmt, ...) +{ + if (verbose_mode) { + va_list ap; + + va_start(ap, fmt); + vfprintf(stdout, fmt, ap); + va_end(ap); + } +} + +static int openssl_err(const char *msg) +{ + unsigned long ssl_err = ERR_get_error(); + + fprintf(stderr, "%s", msg); + fprintf(stderr, ": %s\n", + ERR_error_string(ssl_err, 0)); + + return -1; +} + +static int kwb_load_rsa_key(const char *keydir, const char *name, RSA **p_rsa) +{ + char path[PATH_MAX]; + RSA *rsa; + FILE *f; + + if (!keydir) + keydir = "."; + + snprintf(path, sizeof(path), "%s/%s.key", keydir, name); + f = fopen(path, "r"); + if (!f) { + fprintf(stderr, "Couldn't open RSA private key: '%s': %s\n", + path, strerror(errno)); + return -ENOENT; + } + + rsa = PEM_read_RSAPrivateKey(f, 0, NULL, ""); + if (!rsa) { + openssl_err("Failure reading private key"); + fclose(f); + return -EPROTO; + } + fclose(f); + *p_rsa = rsa; + + return 0; +} + +static int kwb_load_cfg_key(struct image_tool_params *params, + unsigned int cfg_option, const char *key_name, + RSA **p_key) +{ + struct image_cfg_element *e_key; + RSA *key; + int res; + + *p_key = NULL; + + e_key = image_find_option(cfg_option); + if (!e_key) { + fprintf(stderr, "%s not configured\n", key_name); + return -ENOENT; + } + + res = kwb_load_rsa_key(params->keydir, e_key->key_name, &key); + if (res < 0) { + fprintf(stderr, "Failed to load %s\n", key_name); + return -ENOENT; + } + + *p_key = key; + + return 0; +} + +static int kwb_load_kak(struct image_tool_params *params, RSA **p_kak) +{ + return kwb_load_cfg_key(params, IMAGE_CFG_KAK, "KAK", p_kak); +} + +static int kwb_load_csk(struct image_tool_params *params, RSA **p_csk) +{ + return kwb_load_cfg_key(params, IMAGE_CFG_CSK, "CSK", p_csk); +} + +static int kwb_compute_pubkey_hash(struct pubkey_der_v1 *pk, + struct hash_v1 *hash) +{ + EVP_MD_CTX *ctx; + unsigned int key_size; + unsigned int hash_size; + int ret = 0; + + if (!pk || !hash || pk->key[0] != 0x30 || pk->key[1] != 0x82) + return -EINVAL; + + key_size = (pk->key[2] << 8) + pk->key[3] + 4; + + ctx = EVP_MD_CTX_create(); + if (!ctx) + return openssl_err("EVP context creation failed"); + + EVP_MD_CTX_init(ctx); + if (!EVP_DigestInit(ctx, EVP_sha256())) { + ret = openssl_err("Digest setup failed"); + goto hash_err_ctx; + } + + if (!EVP_DigestUpdate(ctx, pk->key, key_size)) { + ret = openssl_err("Hashing data failed"); + goto hash_err_ctx; + } + + if (!EVP_DigestFinal(ctx, hash->hash, &hash_size)) { + ret = openssl_err("Could not obtain hash"); + goto hash_err_ctx; + } + + EVP_MD_CTX_cleanup(ctx); + +hash_err_ctx: + EVP_MD_CTX_destroy(ctx); + return ret; +} + +static int kwb_import_pubkey(RSA **key, struct pubkey_der_v1 *src, char *keyname) +{ + RSA *rsa; + const unsigned char *ptr; + + if (!key || !src) + goto fail; + + ptr = src->key; + rsa = d2i_RSAPublicKey(key, &ptr, sizeof(src->key)); + if (!rsa) { + openssl_err("error decoding public key"); + goto fail; + } + + return 0; +fail: + fprintf(stderr, "Failed to decode %s pubkey\n", keyname); + return -EINVAL; +} + +static int kwb_export_pubkey(RSA *key, struct pubkey_der_v1 *dst, FILE *hashf, + char *keyname) +{ + int size_exp, size_mod, size_seq; + uint8_t *cur; + char *errmsg = "Failed to encode %s\n"; + + if (!key || !key->e || !key->n || !dst) { + fprintf(stderr, "export pk failed: (%p, %p, %p, %p)", + key, key->e, key->n, dst); + fprintf(stderr, errmsg, keyname); + return -EINVAL; + } + + /* + * According to the specs, the key should be PKCS#1 DER encoded. + * But unfortunately the really required encoding seems to be different; + * it violates DER...! (But it still conformes to BER.) + * (Length always in long form w/ 2 byte length code; no leading zero + * when MSB of first byte is set...) + * So we cannot use the encoding func provided by OpenSSL and have to + * do the encoding manually. + */ + + size_exp = BN_num_bytes(key->e); + size_mod = BN_num_bytes(key->n); + size_seq = 4 + size_mod + 4 + size_exp; + + if (size_mod > 256) { + fprintf(stderr, "export pk failed: wrong mod size: %d\n", + size_mod); + fprintf(stderr, errmsg, keyname); + return -EINVAL; + } + + if (4 + size_seq > sizeof(dst->key)) { + fprintf(stderr, "export pk failed: seq too large (%d, %lu)\n", + 4 + size_seq, sizeof(dst->key)); + fprintf(stderr, errmsg, keyname); + return -ENOBUFS; + } + + cur = dst->key; + + /* PKCS#1 (RFC3447) RSAPublicKey structure */ + *cur++ = 0x30; /* SEQUENCE */ + *cur++ = 0x82; + *cur++ = (size_seq >> 8) & 0xFF; + *cur++ = size_seq & 0xFF; + /* Modulus */ + *cur++ = 0x02; /* INTEGER */ + *cur++ = 0x82; + *cur++ = (size_mod >> 8) & 0xFF; + *cur++ = size_mod & 0xFF; + BN_bn2bin(key->n, cur); + cur += size_mod; + /* Exponent */ + *cur++ = 0x02; /* INTEGER */ + *cur++ = 0x82; + *cur++ = (size_exp >> 8) & 0xFF; + *cur++ = size_exp & 0xFF; + BN_bn2bin(key->e, cur); + + if (hashf) { + struct hash_v1 pk_hash; + int i; + int ret = 0; + + ret = kwb_compute_pubkey_hash(dst, &pk_hash); + if (ret < 0) { + fprintf(stderr, errmsg, keyname); + return ret; + } + + fprintf(hashf, "SHA256 = "); + for (i = 0 ; i < sizeof(pk_hash.hash); ++i) + fprintf(hashf, "%02X", pk_hash.hash[i]); + fprintf(hashf, "\n"); + } + + return 0; +} + +int kwb_sign(RSA *key, void *data, int datasz, struct sig_v1 *sig, char *signame) +{ + EVP_PKEY *evp_key; + EVP_MD_CTX *ctx; + unsigned int sig_size; + int size; + int ret = 0; + + evp_key = EVP_PKEY_new(); + if (!evp_key) + return openssl_err("EVP_PKEY object creation failed"); + + if (!EVP_PKEY_set1_RSA(evp_key, key)) { + ret = openssl_err("EVP key setup failed"); + goto err_key; + } + + size = EVP_PKEY_size(evp_key); + if (size > sizeof(sig->sig)) { + fprintf(stderr, "Buffer to small for signature (%d bytes)\n", + size); + ret = -ENOBUFS; + goto err_key; + } + + ctx = EVP_MD_CTX_create(); + if (!ctx) { + ret = openssl_err("EVP context creation failed"); + goto err_key; + } + EVP_MD_CTX_init(ctx); + if (!EVP_SignInit(ctx, EVP_sha256())) { + ret = openssl_err("Signer setup failed"); + goto err_ctx; + } + + if (!EVP_SignUpdate(ctx, data, datasz)) { + ret = openssl_err("Signing data failed"); + goto err_ctx; + } + + if (!EVP_SignFinal(ctx, sig->sig, &sig_size, evp_key)) { + ret = openssl_err("Could not obtain signature"); + goto err_ctx; + } + + EVP_MD_CTX_cleanup(ctx); + EVP_MD_CTX_destroy(ctx); + EVP_PKEY_free(evp_key); + + return 0; + +err_ctx: + EVP_MD_CTX_destroy(ctx); +err_key: + EVP_PKEY_free(evp_key); + fprintf(stderr, "Failed to create %s signature\n", signame); + return ret; +} + +int kwb_verify(RSA *key, void *data, int datasz, struct sig_v1 *sig, + char *signame) +{ + EVP_PKEY *evp_key; + EVP_MD_CTX *ctx; + int size; + int ret = 0; + + evp_key = EVP_PKEY_new(); + if (!evp_key) + return openssl_err("EVP_PKEY object creation failed"); + + if (!EVP_PKEY_set1_RSA(evp_key, key)) { + ret = openssl_err("EVP key setup failed"); + goto err_key; + } + + size = EVP_PKEY_size(evp_key); + if (size > sizeof(sig->sig)) { + fprintf(stderr, "Invalid signature size (%d bytes)\n", + size); + ret = -EINVAL; + goto err_key; + } + + ctx = EVP_MD_CTX_create(); + if (!ctx) { + ret = openssl_err("EVP context creation failed"); + goto err_key; + } + EVP_MD_CTX_init(ctx); + if (!EVP_VerifyInit(ctx, EVP_sha256())) { + ret = openssl_err("Verifier setup failed"); + goto err_ctx; + } + + if (!EVP_VerifyUpdate(ctx, data, datasz)) { + ret = openssl_err("Hashing data failed"); + goto err_ctx; + } + + if (!EVP_VerifyFinal(ctx, sig->sig, sizeof(sig->sig), evp_key)) { + ret = openssl_err("Could not verify signature"); + goto err_ctx; + } + + EVP_MD_CTX_cleanup(ctx); + EVP_MD_CTX_destroy(ctx); + EVP_PKEY_free(evp_key); + + return 0; + +err_ctx: + EVP_MD_CTX_destroy(ctx); +err_key: + EVP_PKEY_free(evp_key); + fprintf(stderr, "Failed to verify %s signature\n", signame); + return ret; +} + +int kwb_sign_and_verify(RSA *key, void *data, int datasz, struct sig_v1 *sig, + char *signame) +{ + if (kwb_sign(key, data, datasz, sig, signame) < 0) + return -1; + + if (kwb_verify(key, data, datasz, sig, signame) < 0) + return -1; + + return 0; +} + + +int kwb_dump_fuse_cmds_38x(FILE *out, struct secure_hdr_v1 *sec_hdr) +{ + struct hash_v1 kak_pub_hash; + struct image_cfg_element *e; + unsigned int fuse_line; + int i, idx; + uint8_t *ptr; + uint32_t val; + int ret = 0; + + if (!out || !sec_hdr) + return -EINVAL; + + ret = kwb_compute_pubkey_hash(&sec_hdr->kak, &kak_pub_hash); + if (ret < 0) + goto done; + + fprintf(out, "# burn KAK pub key hash\n"); + ptr = kak_pub_hash.hash; + for (fuse_line = 26; fuse_line <= 30; ++fuse_line) { + fprintf(out, "fuse prog -y %u 0 ", fuse_line); + + for (i = 4; i-- > 0;) + fprintf(out, "%02hx", (ushort)ptr[i]); + ptr += 4; + fprintf(out, " 00"); + + if (fuse_line < 30) { + for (i = 3; i-- > 0;) + fprintf(out, "%02hx", (ushort)ptr[i]); + ptr += 3; + } else { + fprintf(out, "000000"); + } + + fprintf(out, " 1\n"); + } + + fprintf(out, "# burn CSK selection\n"); + + idx = image_get_csk_index(); + if (idx < 0 || idx > 15) { + ret = -EINVAL; + goto done; + } + if (idx > 0) { + for (fuse_line = 31; fuse_line < 31 + idx; ++fuse_line) + fprintf(out, "fuse prog -y %u 0 00000001 00000000 1\n", + fuse_line); + } else { + fprintf(out, "# CSK index is 0; no mods needed\n"); + } + + e = image_find_option(IMAGE_CFG_BOX_ID); + if (e) { + fprintf(out, "# set box ID\n"); + fprintf(out, "fuse prog -y 48 0 %08x 00000000 1\n", e->boxid); + } + + e = image_find_option(IMAGE_CFG_FLASH_ID); + if (e) { + fprintf(out, "# set flash ID\n"); + fprintf(out, "fuse prog -y 47 0 %08x 00000000 1\n", e->flashid); + } + + fprintf(out, "# enable secure mode "); + fprintf(out, "(must be the last fuse line written)\n"); + + val = 1; + e = image_find_option(IMAGE_CFG_SEC_BOOT_DEV); + if (!e) { + fprintf(stderr, "ERROR: secured mode boot device not given\n"); + ret = -EINVAL; + goto done; + } + + if (e->sec_boot_dev > 0xff) { + fprintf(stderr, "ERROR: secured mode boot device invalid\n"); + ret = -EINVAL; + goto done; + } + + val |= (e->sec_boot_dev << 8); + + fprintf(out, "fuse prog -y 24 0 %08x 0103e0a9 1\n", val); + + fprintf(out, "# lock (unused) fuse lines (0-23)s\n"); + for (fuse_line = 0; fuse_line < 24; ++fuse_line) + fprintf(out, "fuse prog -y %u 2 1\n", fuse_line); + + fprintf(out, "# OK, that's all :-)\n"); + +done: + return ret; +} + +static int kwb_dump_fuse_cmds(struct secure_hdr_v1 *sec_hdr) +{ + int ret = 0; + struct image_cfg_element *e; + + e = image_find_option(IMAGE_CFG_SEC_FUSE_DUMP); + if (!e) + return 0; + + if (!strcmp(e->name, "a38x")) { + FILE *out = fopen("kwb_fuses_a38x.txt", "w+"); + + kwb_dump_fuse_cmds_38x(out, sec_hdr); + fclose(out); + goto done; + } + + ret = -ENOSYS; + +done: + return ret; +} + +#endif + static void *image_create_v0(size_t *imagesz, struct image_tool_params *params, int payloadsz) { @@ -381,6 +939,14 @@ static size_t image_headersz_v1(int *hasext) *hasext = 1; } +#if defined(CONFIG_KWB_SECURE) + if (image_get_csk_index() >= 0) { + headersz += sizeof(struct secure_hdr_v1); + if (hasext) + *hasext = 1; + } +#endif + #if defined(CONFIG_SYS_U_BOOT_OFFS) if (headersz > CONFIG_SYS_U_BOOT_OFFS) { fprintf(stderr, @@ -476,14 +1042,129 @@ int add_binary_header_v1(uint8_t *cur) return 0; } +#if defined(CONFIG_KWB_SECURE) + +int export_pub_kak_hash(RSA *kak, struct secure_hdr_v1 *secure_hdr) +{ + FILE *hashf; + int res; + + hashf = fopen("pub_kak_hash.txt", "w"); + + res = kwb_export_pubkey(kak, &secure_hdr->kak, hashf, "KAK"); + + fclose(hashf); + + return res < 0 ? 1 : 0; +} + +int kwb_sign_csk_with_kak(struct image_tool_params *params, + struct secure_hdr_v1 *secure_hdr, RSA *csk) +{ + RSA *kak = NULL; + RSA *kak_pub = NULL; + int csk_idx = image_get_csk_index(); + struct sig_v1 tmp_sig; + + if (csk_idx >= 16) { + fprintf(stderr, "Invalid CSK index %d\n", csk_idx); + return 1; + } + + if (kwb_load_kak(params, &kak) < 0) + return 1; + + if (export_pub_kak_hash(kak, secure_hdr)) + return 1; + + if (kwb_import_pubkey(&kak_pub, &secure_hdr->kak, "KAK") < 0) + return 1; + + if (kwb_export_pubkey(csk, &secure_hdr->csk[csk_idx], NULL, "CSK") < 0) + return 1; + + if (kwb_sign_and_verify(kak, &secure_hdr->csk, + sizeof(secure_hdr->csk) + + sizeof(secure_hdr->csksig), + &tmp_sig, "CSK") < 0) + return 1; + + if (kwb_verify(kak_pub, &secure_hdr->csk, + sizeof(secure_hdr->csk) + + sizeof(secure_hdr->csksig), + &tmp_sig, "CSK (2)") < 0) + return 1; + + secure_hdr->csksig = tmp_sig; + + return 0; +} + +int add_secure_header_v1(struct image_tool_params *params, uint8_t *ptr, + int payloadsz, size_t headersz, uint8_t *image, + struct secure_hdr_v1 *secure_hdr) +{ + struct image_cfg_element *e_jtagdelay; + struct image_cfg_element *e_boxid; + struct image_cfg_element *e_flashid; + RSA *csk = NULL; + unsigned char *image_ptr; + size_t image_size; + struct sig_v1 tmp_sig; + bool specialized_img = image_get_spezialized_img(); + + kwb_msg("Create secure header content\n"); + + e_jtagdelay = image_find_option(IMAGE_CFG_JTAG_DELAY); + e_boxid = image_find_option(IMAGE_CFG_BOX_ID); + e_flashid = image_find_option(IMAGE_CFG_FLASH_ID); + + if (kwb_load_csk(params, &csk) < 0) + return 1; + + secure_hdr->headertype = OPT_HDR_V1_SECURE_TYPE; + secure_hdr->headersz_msb = 0; + secure_hdr->headersz_lsb = cpu_to_le16(sizeof(struct secure_hdr_v1)); + if (e_jtagdelay) + secure_hdr->jtag_delay = e_jtagdelay->jtag_delay; + if (e_boxid && specialized_img) + secure_hdr->boxid = cpu_to_le32(e_boxid->boxid); + if (e_flashid && specialized_img) + secure_hdr->flashid = cpu_to_le32(e_flashid->flashid); + + if (kwb_sign_csk_with_kak(params, secure_hdr, csk)) + return 1; + + image_ptr = ptr + headersz; + image_size = payloadsz - headersz; + + if (kwb_sign_and_verify(csk, image_ptr, image_size, + &secure_hdr->imgsig, "image") < 0) + return 1; + + if (kwb_sign_and_verify(csk, image, headersz, &tmp_sig, "header") < 0) + return 1; + + secure_hdr->hdrsig = tmp_sig; + + kwb_dump_fuse_cmds(secure_hdr); + + return 0; +} +#endif + static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, - int payloadsz) + uint8_t *ptr, int payloadsz) { struct image_cfg_element *e; struct main_hdr_v1 *main_hdr; +#if defined(CONFIG_KWB_SECURE) + struct secure_hdr_v1 *secure_hdr = NULL; +#endif size_t headersz; uint8_t *image, *cur; int hasext = 0; + uint8_t *next_ext = NULL; /* * Calculate the size of the header and the size of the @@ -502,7 +1183,9 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, memset(image, 0, headersz); main_hdr = (struct main_hdr_v1 *)image; - cur = image + sizeof(struct main_hdr_v1); + cur = image; + cur += sizeof(struct main_hdr_v1); + next_ext = &main_hdr->ext; /* Fill the main header */ main_hdr->blocksize = @@ -531,9 +1214,28 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, if (e) main_hdr->flags = e->debug ? 0x1 : 0; +#if defined(CONFIG_KWB_SECURE) + if (image_get_csk_index() >= 0) { + /* + * only reserve the space here; we fill the header later since + * we need the header to be complete to compute the signatures + */ + secure_hdr = (struct secure_hdr_v1 *)cur; + cur += sizeof(struct secure_hdr_v1); + next_ext = &secure_hdr->next; + } +#endif + *next_ext = 1; + if (add_binary_header_v1(cur)) return NULL; +#if defined(CONFIG_KWB_SECURE) + if (secure_hdr && add_secure_header_v1(params, ptr, payloadsz, + headersz, image, secure_hdr)) + return NULL; +#endif + /* Calculate and set the header checksum */ main_hdr->checksum = image_checksum8(main_hdr, headersz); @@ -645,6 +1347,36 @@ static int image_create_config_parse_oneline(char *line, case IMAGE_CFG_DEBUG: el->debug = strtoul(value1, NULL, 10); break; + case IMAGE_CFG_KAK: + el->key_name = strdup(value1); + break; + case IMAGE_CFG_CSK: + el->key_name = strdup(value1); + break; + case IMAGE_CFG_CSK_INDEX: + el->csk_idx = strtol(value1, NULL, 0); + break; + case IMAGE_CFG_JTAG_DELAY: + el->jtag_delay = strtoul(value1, NULL, 0); + break; + case IMAGE_CFG_BOX_ID: + el->boxid = strtoul(value1, NULL, 0); + break; + case IMAGE_CFG_FLASH_ID: + el->flashid = strtoul(value1, NULL, 0); + break; + case IMAGE_CFG_SEC_SPECIALIZED_IMG: + el->sec_specialized_img = true; + break; + case IMAGE_CFG_SEC_COMMON_IMG: + el->sec_specialized_img = false; + break; + case IMAGE_CFG_SEC_BOOT_DEV: + el->sec_boot_dev = strtoul(value1, NULL, 0); + break; + case IMAGE_CFG_SEC_FUSE_DUMP: + el->name = strdup(value1); + break; default: fprintf(stderr, unknown_msg, line); } @@ -804,7 +1536,7 @@ static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd, break; case 1: - image = image_create_v1(&headersz, params, sbuf->st_size); + image = image_create_v1(&headersz, params, ptr, sbuf->st_size); break; default: diff --git a/tools/kwbimage.h b/tools/kwbimage.h index 01c2f1f..20f4d0d 100644 --- a/tools/kwbimage.h +++ b/tools/kwbimage.h @@ -114,6 +114,43 @@ struct opt_hdr_v1 { }; /* + * Public Key data in DER format + */ +struct pubkey_der_v1 { + uint8_t key[524]; +}; + +/* + * Signature (RSA 2048) + */ +struct sig_v1 { + uint8_t sig[256]; +}; + +/* + * Structure of secure header (Armada 38x) + */ +struct secure_hdr_v1 { + uint8_t headertype; /* 0x0 */ + uint8_t headersz_msb; /* 0x1 */ + uint16_t headersz_lsb; /* 0x2 - 0x3 */ + uint32_t reserved1; /* 0x4 - 0x7 */ + struct pubkey_der_v1 kak; /* 0x8 - 0x213 */ + uint8_t jtag_delay; /* 0x214 */ + uint8_t reserved2; /* 0x215 */ + uint16_t reserved3; /* 0x216 - 0x217 */ + uint32_t boxid; /* 0x218 - 0x21B */ + uint32_t flashid; /* 0x21C - 0x21F */ + struct sig_v1 hdrsig; /* 0x220 - 0x31F */ + struct sig_v1 imgsig; /* 0x320 - 0x41F */ + struct pubkey_der_v1 csk[16]; /* 0x420 - 0x24DF */ + struct sig_v1 csksig; /* 0x24E0 - 0x25DF */ + uint8_t next; /* 0x25E0 */ + uint8_t reserved4; /* 0x25E1 */ + uint16_t reserved5; /* 0x25E2 - 0x25E3 */ +}; + +/* * Various values for the opt_hdr_v1->headertype field, describing the * different types of optional headers. The "secure" header contains * informations related to secure boot (encryption keys, etc.). The -- cgit v1.1