diff options
-rw-r--r-- | scripts/imx/imx-image.c | 182 | ||||
-rw-r--r-- | scripts/imx/imx.c | 3 | ||||
-rw-r--r-- | scripts/imx/imx.h | 3 |
3 files changed, 167 insertions, 21 deletions
diff --git a/scripts/imx/imx-image.c b/scripts/imx/imx-image.c index b627b8c2c5..5eca4463dd 100644 --- a/scripts/imx/imx-image.c +++ b/scripts/imx/imx-image.c @@ -15,6 +15,7 @@ * GNU General Public License for more details. * */ +#define _GNU_SOURCE #include <stdio.h> #include <unistd.h> #include <getopt.h> @@ -27,19 +28,19 @@ #include <fcntl.h> #include <endian.h> #include <linux/kernel.h> +#include <sys/file.h> #include "imx.h" #include <include/filetype.h> #define MAX_DCD 1024 -#define HEADER_LEN 0x1000 /* length of the blank area + IVT + DCD */ #define CSF_LEN 0x2000 /* length of the CSF (needed for HAB) */ static uint32_t dcdtable[MAX_DCD]; static int curdcd; static int add_barebox_header; -static int prepare_sign; +static char *prgname; /* * ============================================================================ @@ -229,6 +230,11 @@ static int add_header_v1(struct config_data *data, void *buf) buf += dcdsize; + if (data->csf) { + hdr->app_code_csf = loadaddr + imagesize; + imagesize += CSF_LEN; + } + *(uint32_t *)buf = imagesize; return 0; @@ -281,7 +287,7 @@ static int add_header_v2(struct config_data *data, void *buf) hdr->boot_data.start = loadaddr; hdr->boot_data.size = imagesize; - if (prepare_sign) { + if (data->csf) { hdr->csf = loadaddr + imagesize; hdr->boot_data.size += CSF_LEN; } @@ -309,7 +315,6 @@ static void usage(const char *prgname) "-b add barebox header to image. If used, barebox recognizes\n" " the image as regular barebox image which can be used as\n" " second stage image\n" - "-p prepare image for signing\n" "-h this help\n", prgname); exit(1); } @@ -439,6 +444,132 @@ static int write_mem(struct config_data *data, uint32_t addr, uint32_t val, int } } +/* + * This uses the Freescale Code Signing Tool (CST) to sign the image. + * The cst is expected to be executable as 'cst' or if exists, the content + * of the environment variable 'CST' is used. + */ +static int hab_sign(struct config_data *data) +{ + int fd, outfd, ret, lockfd; + char *csffile, *command; + struct stat s; + char *cst; + void *buf; + + cst = getenv("CST"); + if (!cst) + cst = "cst"; + + ret = asprintf(&csffile, "%s.csfbin", data->outfile); + if (ret < 0) + exit(1); + + ret = stat(csffile, &s); + if (!ret) { + if (S_ISREG(s.st_mode)) { + ret = unlink(csffile); + if (ret) { + fprintf(stderr, "Cannot remove %s: %s\n", + csffile, strerror(errno)); + return -errno; + } + } else { + fprintf(stderr, "%s exists and is no regular file\n", + csffile); + return -EINVAL; + } + } + + ret = asprintf(&command, "%s -o %s", cst, csffile); + if (ret < 0) + return -ENOMEM; + + /* + * The cst uses "csfsig.bin" as temporary file. This of course breaks when it's + * called multiple times as often happens with parallel builds. Until cst learns + * how to properly create temporary files without races lock accesses to this + * file. + */ + lockfd = open(prgname, O_RDONLY); + if (lockfd < 0) { + fprintf(stderr, "Cannot open csfsig.bin: %s\n", strerror(errno)); + return -errno; + } + + ret = flock(lockfd, LOCK_EX); + if (ret) { + fprintf(stderr, "Cannot lock csfsig.bin: %s\n", strerror(errno)); + return -errno; + } + + FILE *f = popen(command, "w"); + if (!f) { + perror("popen"); + return -errno; + } + + fwrite(data->csf, 1, strlen(data->csf) + 1, f); + + pclose(f); + + flock(lockfd, LOCK_UN); + close(lockfd); + + /* + * the Freescale code signing tool doesn't fail if there + * are errors in the command sequence file, it just doesn't + * produce any output, so we have to check for existence of + * the output file rather than checking the return value of + * the cst call. + */ + fd = open(csffile, O_RDONLY); + if (fd < 0) { + fprintf(stderr, "Failed to open %s: %s\n", csffile, strerror(errno)); + fprintf(stderr, "%s failed\n", cst); + return -errno; + } + + ret = fstat(fd, &s); + if (ret < 0) { + fprintf(stderr, "stat failed: %s\n", strerror(errno)); + return -errno; + } + + buf = malloc(CSF_LEN); + if (!buf) + return -ENOMEM; + + memset(buf, 0x5a, CSF_LEN); + + if (s.st_size > CSF_LEN) { + fprintf(stderr, "CSF file size exceeds maximum CSF len of %d bytes\n", + CSF_LEN); + } + + ret = xread(fd, buf, s.st_size); + if (ret < 0) { + fprintf(stderr, "read failed: %s\n", strerror(errno)); + return -errno; + } + + outfd = open(data->outfile, O_WRONLY | O_APPEND); + + ret = xwrite(outfd, buf, CSF_LEN); + if (ret < 0) { + fprintf(stderr, "write failed: %s\n", strerror(errno)); + return -errno; + } + + ret = close(outfd); + if (ret) { + perror("close"); + exit(1); + } + + return 0; +} + int main(int argc, char *argv[]) { int opt, ret; @@ -451,13 +582,16 @@ int main(int argc, char *argv[]) int infd, outfd; int dcd_only = 0; int now = 0; + int sign_image = 0; struct config_data data = { .image_dcd_offset = 0xffffffff, .write_mem = write_mem, .check = check, }; - while ((opt = getopt(argc, argv, "c:hf:o:bdp")) != -1) { + prgname = argv[0]; + + while ((opt = getopt(argc, argv, "c:hf:o:bds")) != -1) { switch (opt) { case 'c': configfile = optarg; @@ -474,8 +608,8 @@ int main(int argc, char *argv[]) case 'd': dcd_only = 1; break; - case 'p': - prepare_sign = 1; + case 's': + sign_image = 1; break; case 'h': usage(argv[0]); @@ -509,10 +643,23 @@ int main(int argc, char *argv[]) data.image_size = s.st_size; } + /* + * Add HEADER_LEN to the image size for the blank aera + IVT + DCD. + * Align up to a 4k boundary, because: + * - at least i.MX5 NAND boot only reads full NAND pages and misses the + * last partial NAND page. + * - i.MX6 SPI NOR boot corrupts the last few bytes of an image loaded + * in ver funy ways when the image size is not 4 byte aligned + */ + data.load_size = roundup(data.image_size + HEADER_LEN, 0x1000); + ret = parse_config(&data, configfile); if (ret) exit(1); + if (!sign_image) + data.csf = NULL; + buf = calloc(1, HEADER_LEN); if (!buf) exit(1); @@ -538,19 +685,6 @@ int main(int argc, char *argv[]) exit (0); } - /* - * Add HEADER_LEN to the image size for the blank aera + IVT + DCD. - * Align up to a 4k boundary, because: - * - at least i.MX5 NAND boot only reads full NAND pages and misses the - * last partial NAND page. - * - i.MX6 SPI NOR boot corrupts the last few bytes of an image loaded - * in ver funy ways when the image size is not 4 byte aligned - */ - data.load_size = roundup(data.image_size + HEADER_LEN, 0x1000); - - if (data.cpu_type == 35) - data.load_size += HEADER_LEN; - switch (data.header_version) { case 1: add_header_v1(&data, buf); @@ -616,7 +750,7 @@ int main(int argc, char *argv[]) /* pad until next 4k boundary */ now = 4096 - (insize % 4096); - if (prepare_sign && now) { + if (data.csf && now) { memset(buf, 0x5a, now); ret = xwrite(outfd, buf, now); @@ -632,5 +766,11 @@ int main(int argc, char *argv[]) exit(1); } + if (data.csf) { + ret = hab_sign(&data); + if (ret) + exit(1); + } + exit(0); } diff --git a/scripts/imx/imx.c b/scripts/imx/imx.c index 6b397fc473..82ef97f80c 100644 --- a/scripts/imx/imx.c +++ b/scripts/imx/imx.c @@ -230,6 +230,9 @@ static int do_soc(struct config_data *data, int argc, char *argv[]) fprintf(stderr, "%s ", socs[i].name); fprintf(stderr, "\n"); + if (data->cpu_type == 35) + data->load_size += HEADER_LEN; + return -EINVAL; } diff --git a/scripts/imx/imx.h b/scripts/imx/imx.h index 0876370edb..85071b4ed3 100644 --- a/scripts/imx/imx.h +++ b/scripts/imx/imx.h @@ -1,3 +1,6 @@ + +#define HEADER_LEN 0x1000 /* length of the blank area + IVT + DCD */ + /* * ============================================================================ * i.MX flash header v1 handling. Found on i.MX35 and i.MX51 |