X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=tools%2Fkwbimage.c;h=02fd0c949fff6dbb94224bf783ef4d6f1e247d92;hb=7fec249bb76db8bc21b98c08822116597154704d;hp=93797c99da76604961493e3a7674aa618cd829fb;hpb=43ade93bdb0c8bd57382be810a05b3793749ce85;p=oweals%2Fu-boot.git diff --git a/tools/kwbimage.c b/tools/kwbimage.c index 93797c99da..02fd0c949f 100644 --- a/tools/kwbimage.c +++ b/tools/kwbimage.c @@ -1,3 +1,4 @@ +// SPDX-License-Identifier: GPL-2.0+ /* * Image manipulator for Marvell SoCs * supports Kirkwood, Dove, Armada 370, Armada XP, and Armada 38x @@ -5,8 +6,6 @@ * (C) Copyright 2013 Thomas Petazzoni * * - * SPDX-License-Identifier: GPL-2.0+ - * * Not implemented: support for the register headers in v1 images */ @@ -18,10 +17,31 @@ #include "kwbimage.h" #ifdef CONFIG_KWB_SECURE +#include #include #include #include #include + +#if OPENSSL_VERSION_NUMBER < 0x10100000L || \ + (defined(LIBRESSL_VERSION_NUMBER) && LIBRESSL_VERSION_NUMBER < 0x2070000fL) +static void RSA_get0_key(const RSA *r, + const BIGNUM **n, const BIGNUM **e, const BIGNUM **d) +{ + if (n != NULL) + *n = r->n; + if (e != NULL) + *e = r->e; + if (d != NULL) + *d = r->d; +} + +#elif !defined(LIBRESSL_VERSION_NUMBER) +void EVP_MD_CTX_cleanup(EVP_MD_CTX *ctx) +{ + EVP_MD_CTX_reset(ctx); +} +#endif #endif static struct image_cfg_element *image_cfg; @@ -270,6 +290,33 @@ static uint8_t image_checksum8(void *start, uint32_t len) return csum; } +size_t kwbimage_header_size(unsigned char *ptr) +{ + if (image_version((void *)ptr) == 0) + return sizeof(struct main_hdr_v0); + else + return KWBHEADER_V1_SIZE((struct main_hdr_v1 *)ptr); +} + +/* + * Verify checksum over a complete header that includes the checksum field. + * Return 1 when OK, otherwise 0. + */ +static int main_hdr_checksum_ok(void *hdr) +{ + /* Offsets of checksum in v0 and v1 headers are the same */ + struct main_hdr_v0 *main_hdr = (struct main_hdr_v0 *)hdr; + uint8_t checksum; + + checksum = image_checksum8(hdr, kwbimage_header_size(hdr)); + /* Calculated checksum includes the header checksum field. Compensate + * for that. + */ + checksum -= main_hdr->checksum; + + return checksum == main_hdr->checksum; +} + static uint32_t image_checksum32(void *start, uint32_t len) { uint32_t csum = 0; @@ -470,12 +517,16 @@ static int kwb_export_pubkey(RSA *key, struct pubkey_der_v1 *dst, FILE *hashf, char *keyname) { int size_exp, size_mod, size_seq; + const BIGNUM *key_e, *key_n; uint8_t *cur; char *errmsg = "Failed to encode %s\n"; - if (!key || !key->e || !key->n || !dst) { + RSA_get0_key(key, NULL, &key_e, NULL); + RSA_get0_key(key, &key_n, NULL, NULL); + + if (!key || !key_e || !key_n || !dst) { fprintf(stderr, "export pk failed: (%p, %p, %p, %p)", - key, key->e, key->n, dst); + key, key_e, key_n, dst); fprintf(stderr, errmsg, keyname); return -EINVAL; } @@ -490,8 +541,8 @@ static int kwb_export_pubkey(RSA *key, struct pubkey_der_v1 *dst, FILE *hashf, * do the encoding manually. */ - size_exp = BN_num_bytes(key->e); - size_mod = BN_num_bytes(key->n); + 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) { @@ -520,14 +571,14 @@ static int kwb_export_pubkey(RSA *key, struct pubkey_der_v1 *dst, FILE *hashf, *cur++ = 0x82; *cur++ = (size_mod >> 8) & 0xFF; *cur++ = size_mod & 0xFF; - BN_bn2bin(key->n, cur); + 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); + BN_bn2bin(key_e, cur); if (hashf) { struct hash_v1 pk_hash; @@ -650,7 +701,7 @@ int kwb_verify(RSA *key, void *data, int datasz, struct sig_v1 *sig, goto err_ctx; } - if (!EVP_VerifyFinal(ctx, sig->sig, sizeof(sig->sig), evp_key)) { + if (EVP_VerifyFinal(ctx, sig->sig, sizeof(sig->sig), evp_key) != 1) { ret = openssl_err("Could not verify signature"); goto err_ctx; } @@ -964,7 +1015,7 @@ static size_t image_headersz_v1(int *hasext) * The payload should be aligned on some reasonable * boundary */ - return ALIGN_SUP(headersz, 4096); + return ALIGN(headersz, 4096); } int add_binary_header_v1(uint8_t *cur) @@ -992,7 +1043,11 @@ int add_binary_header_v1(uint8_t *cur) return -1; } - fstat(fileno(bin), &s); + if (fstat(fileno(bin), &s)) { + fprintf(stderr, "Cannot stat binary file %s\n", + binarye->binary.file); + goto err_close; + } binhdrsz = sizeof(struct opt_hdr_v1) + (binarye->binary.nargs + 2) * sizeof(uint32_t) + @@ -1003,7 +1058,7 @@ int add_binary_header_v1(uint8_t *cur) * 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; + binhdrsz = ALIGN(binhdrsz, 4) + 4; hdr->headersz_lsb = cpu_to_le16(binhdrsz & 0xFFFF); hdr->headersz_msb = (binhdrsz & 0xFFFF0000) >> 16; @@ -1022,12 +1077,12 @@ int add_binary_header_v1(uint8_t *cur) fprintf(stderr, "Could not read binary image %s\n", binarye->binary.file); - return -1; + goto err_close; } fclose(bin); - cur += ALIGN_SUP(s.st_size, 4); + cur += ALIGN(s.st_size, 4); /* * For now, we don't support more than one binary @@ -1040,6 +1095,11 @@ int add_binary_header_v1(uint8_t *cur) cur += sizeof(uint32_t); return 0; + +err_close: + fclose(bin); + + return -1; } #if defined(CONFIG_KWB_SECURE) @@ -1213,6 +1273,13 @@ static void *image_create_v1(size_t *imagesz, struct image_tool_params *params, e = image_find_option(IMAGE_CFG_DEBUG); if (e) main_hdr->flags = e->debug ? 0x1 : 0; + e = image_find_option(IMAGE_CFG_BINARY); + if (e) { + char *s = strrchr(e->binary.file, '/'); + + if (strcmp(s, "/binary.0") == 0) + main_hdr->destaddr = cpu_to_le32(params->addr); + } #if defined(CONFIG_KWB_SECURE) if (image_get_csk_index() >= 0) { @@ -1443,47 +1510,6 @@ static int image_get_version(void) return e->version; } -static int image_version_file(const char *input) -{ - FILE *fcfg; - int version; - int ret; - - fcfg = fopen(input, "r"); - if (!fcfg) { - fprintf(stderr, "Could not open input file %s\n", input); - return -1; - } - - image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX * - sizeof(struct image_cfg_element)); - if (!image_cfg) { - fprintf(stderr, "Cannot allocate memory\n"); - fclose(fcfg); - return -1; - } - - memset(image_cfg, 0, - IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element)); - rewind(fcfg); - - ret = image_create_config_parse(fcfg); - fclose(fcfg); - if (ret) { - free(image_cfg); - return -1; - } - - version = image_get_version(); - /* Fallback to version 0 is no version is provided in the cfg file */ - if (version == -1) - version = 0; - - free(image_cfg); - - return version; -} - static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd, struct image_tool_params *params) { @@ -1522,7 +1548,7 @@ static void kwbimage_set_header(void *ptr, struct stat *sbuf, int ifd, } /* The MVEBU BootROM does not allow non word aligned payloads */ - sbuf->st_size = ALIGN_SUP(sbuf->st_size, 4); + sbuf->st_size = ALIGN(sbuf->st_size, 4); version = image_get_version(); switch (version) { @@ -1595,14 +1621,13 @@ static int kwbimage_check_image_types(uint8_t type) static int kwbimage_verify_header(unsigned char *ptr, int image_size, struct image_tool_params *params) { - struct main_hdr_v0 *main_hdr; uint8_t checksum; + size_t header_size = kwbimage_header_size(ptr); - main_hdr = (struct main_hdr_v0 *)ptr; - checksum = image_checksum8(ptr, - sizeof(struct main_hdr_v0) - - sizeof(uint8_t)); - if (checksum != main_hdr->checksum) + if (header_size > image_size) + return -FDT_ERR_BADSTRUCTURE; + + if (!main_hdr_checksum_ok(ptr)) return -FDT_ERR_BADSTRUCTURE; /* Only version 0 extended header has checksum */ @@ -1624,18 +1649,62 @@ static int kwbimage_verify_header(unsigned char *ptr, int image_size, static int kwbimage_generate(struct image_tool_params *params, struct image_type_params *tparams) { + FILE *fcfg; int alloc_len; + int version; void *hdr; - int version = 0; + int ret; + + fcfg = fopen(params->imagename, "r"); + if (!fcfg) { + fprintf(stderr, "Could not open input file %s\n", + params->imagename); + exit(EXIT_FAILURE); + } + + image_cfg = malloc(IMAGE_CFG_ELEMENT_MAX * + sizeof(struct image_cfg_element)); + if (!image_cfg) { + fprintf(stderr, "Cannot allocate memory\n"); + fclose(fcfg); + exit(EXIT_FAILURE); + } + + memset(image_cfg, 0, + IMAGE_CFG_ELEMENT_MAX * sizeof(struct image_cfg_element)); + rewind(fcfg); - version = image_version_file(params->imagename); - if (version == 0) { + ret = image_create_config_parse(fcfg); + fclose(fcfg); + if (ret) { + free(image_cfg); + exit(EXIT_FAILURE); + } + + version = image_get_version(); + switch (version) { + /* + * Fallback to version 0 if no version is provided in the + * cfg file + */ + case -1: + case 0: alloc_len = sizeof(struct main_hdr_v0) + sizeof(struct ext_hdr_v0); - } else { + break; + + case 1: alloc_len = image_headersz_v1(NULL); + break; + + default: + fprintf(stderr, "Unsupported version %d\n", version); + free(image_cfg); + exit(EXIT_FAILURE); } + free(image_cfg); + hdr = malloc(alloc_len); if (!hdr) { fprintf(stderr, "%s: malloc return failure: %s\n",