From bd51ec1aef445d8f3962d9c0cb28112717cfcc7d Mon Sep 17 00:00:00 2001 From: Jaska Uimonen Date: Tue, 16 Nov 2021 09:50:21 +0200 Subject: [PATCH] rimage: add functionality to resign fw image Add function to resign already signed images. This can be done with switch "q" as follows: "rimage -q sof-tgl.ri -o sof-tgl-mod.ri -c tgl.toml -k key.pem" Signed-off-by: Jaska Uimonen --- src/include/rimage/rimage.h | 4 ++ src/manifest.c | 124 ++++++++++++++++++++++++++++++++++++ src/pkcs1_5.c | 35 ++++++++++ src/rimage.c | 11 +++- 4 files changed, 173 insertions(+), 1 deletion(-) diff --git a/src/include/rimage/rimage.h b/src/include/rimage/rimage.h index e6d38ebed..e5b918e3c 100644 --- a/src/include/rimage/rimage.h +++ b/src/include/rimage/rimage.h @@ -73,6 +73,7 @@ struct module { struct image { const char *out_file; + const char *in_file; FILE *out_fd; void *pos; @@ -201,6 +202,9 @@ int pkcs_v1_5_verify_man_v2_5(struct image *image, void *ptr1, unsigned int size1, void *ptr2, unsigned int size2); +int resign_image(struct image *image); +int get_key_size(struct image *image); + int elf_parse_module(struct image *image, int module_index, const char *name); void elf_free_module(struct image *image, int module_index); int elf_is_rom(struct image *image, Elf32_Shdr *section); diff --git a/src/manifest.c b/src/manifest.c index 1bf10d9b6..e682503b1 100644 --- a/src/manifest.c +++ b/src/manifest.c @@ -1427,3 +1427,127 @@ out: fclose(in_file); return 0; } + + +int resign_image(struct image *image) +{ + int key_size, key_file_size; + size_t size, read; + FILE *in_file; + void *buffer; + int ret, i; + + /* open image for reading */ + in_file = fopen(image->in_file, "rb"); + if (!in_file) { + fprintf(stderr, "error: unable to open %s for reading %d\n", + image->in_file, errno); + return -errno; + } + + /* get file size */ + ret = fseek(in_file, 0, SEEK_END); + if (ret < 0) { + fprintf(stderr, "error: unable to seek eof %s for reading %d\n", + image->verify_file, errno); + ret = -errno; + goto out; + } + + size = ftell(in_file); + if (size < 0) { + fprintf(stderr, "error: unable to get file size for %s %d\n", + image->verify_file, errno); + ret = -errno; + goto out; + } + + ret = fseek(in_file, 0, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "error: unable to seek %s for reading %d\n", + image->verify_file, errno); + ret = -errno; + goto out; + } + + /* allocate buffer for parsing */ + buffer = malloc(size); + if (!buffer) { + ret = -ENOMEM; + goto out; + } + + /* read file into buffer */ + read = fread(buffer, 1, size, in_file); + if (read != size) { + fprintf(stderr, "error: unable to read %ld bytes from %s err %d\n", + size, image->in_file, errno); + ret = errno; + goto out; + } + + fclose(in_file); + + for (i = 0; i < size; i += sizeof(uint32_t)) { + /* find CSE header marker "$CPD" */ + if (*(uint32_t *)(buffer + i) == CSE_HEADER_MAKER) { + image->fw_image = buffer + i; + break; + } + } + + if (i >= size) { + fprintf(stderr, "error: didn't found header marker %d\n", i); + ret = -EINVAL; + goto out; + } + + image->image_end = size; + + /* check that key size matches */ + if (image->adsp->man_v2_5) { + key_size = 384; + } else { + key_size = 256; + } + + key_file_size = get_key_size(image); + + if (key_file_size > key_size) { + fprintf(stderr, "error: key size %d is longer than original key %d\n", + key_file_size, key_size); + ret = -EINVAL; + goto out; + } + + /* resign */ + if (image->adsp->man_v1_5) + ret = ri_manifest_sign_v1_5(image); + else if (image->adsp->man_v1_8) + ret = ri_manifest_sign_v1_8(image); + else if (image->adsp->man_v2_5) + ret = ri_manifest_sign_v2_5(image); + else + ret = -EINVAL; + + if (ret < 0) { + fprintf(stderr, "error: unable to sign image\n"); + goto out; + } + + /* open outfile for writing */ + unlink(image->out_file); + image->out_fd = fopen(image->out_file, "wb"); + if (!image->out_fd) { + fprintf(stderr, "error: unable to open %s for writing %d\n", + image->out_file, errno); + ret = -EINVAL; + goto out; + } + + man_write_fw_mod(image); + +out: + free(buffer); + return ret; +} diff --git a/src/pkcs1_5.c b/src/pkcs1_5.c index 9b23a54db..c4be1856e 100644 --- a/src/pkcs1_5.c +++ b/src/pkcs1_5.c @@ -694,3 +694,38 @@ int ri_manifest_verify_v2_5(struct image *image) return pkcs_v1_5_verify_man_v2_5(image, man, data1, size1, data2, size2); } + +int get_key_size(struct image *image) +{ + RSA *priv_rsa = NULL; + EVP_PKEY *privkey; + FILE *fp; + int key_length; + char path[256]; + + /* require private key */ + if (!image->key_name) { + return -EINVAL; + } + + /* load in RSA private key from PEM file */ + memset(path, 0, sizeof(path)); + strncpy(path, image->key_name, sizeof(path) - 1); + + fp = fopen(path, "rb"); + if (!fp) { + fprintf(stderr, "error: can't open file %s %d\n", + path, -errno); + return -errno; + } + PEM_read_PrivateKey(fp, &privkey, NULL, NULL); + fclose(fp); + + priv_rsa = EVP_PKEY_get1_RSA(privkey); + key_length = RSA_size(priv_rsa); + + RSA_free(priv_rsa); + EVP_PKEY_free(privkey); + + return key_length; +} diff --git a/src/rimage.c b/src/rimage.c index 507911ca4..67710d9f3 100644 --- a/src/rimage.c +++ b/src/rimage.c @@ -30,6 +30,7 @@ static void usage(char *name) fprintf(stdout, "\t -b build version\n"); fprintf(stdout, "\t -e build extended manifest\n"); fprintf(stdout, "\t -y verify signed file\n"); + fprintf(stdout, "\t -q resign binary\n"); } int main(int argc, char *argv[]) @@ -43,7 +44,7 @@ int main(int argc, char *argv[]) memset(&image, 0, sizeof(image)); - while ((opt = getopt(argc, argv, "ho:va:s:k:ri:x:f:b:ec:y:")) != -1) { + while ((opt = getopt(argc, argv, "ho:va:s:k:ri:x:f:b:ec:y:q:")) != -1) { switch (opt) { case 'o': image.out_file = optarg; @@ -84,6 +85,9 @@ int main(int argc, char *argv[]) case 'h': usage(argv[0]); return 0; + case 'q': + image.in_file = optarg; + break; default: /* getopt's default error message is good enough */ return 1; @@ -152,6 +156,11 @@ int main(int argc, char *argv[]) goto out; } + if (image.in_file) { + fprintf(stdout, "going to re-sign\n"); + return resign_image(&image); + } + /* set IMR Type in found machine definition */ if (image.adsp->man_v1_8) image.adsp->man_v1_8->adsp_file_ext.imr_type = imr_type;