From: Hector Palacios Date: Fri, 17 Jul 2020 07:08:50 +0200 Subject: [PATCH] tools: env: implement support for environment encryption by CAAM Use the md5sum of HWID words (on the device tree) as key modifier. Signed-off-by: Diaz de Grenu, Jose Signed-off-by: Gonzalo Ruiz Signed-off-by: Hector Palacios https://jira.digi.com/browse/DEL-7185 https://jira.digi.com/browse/DEL-2836 --- tools/env/Makefile | 2 +- tools/env/caam_keyblob.h | 45 +++++++++++++ tools/env/fw_env.c | 141 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 187 insertions(+), 1 deletion(-) create mode 100644 tools/env/caam_keyblob.h diff --git a/tools/env/Makefile b/tools/env/Makefile index b627796e949e..fc7c44baa2b7 100644 --- a/tools/env/Makefile +++ b/tools/env/Makefile @@ -24,7 +24,7 @@ hostprogs-y := fw_printenv lib-y += fw_env.o \ crc32.o ctype.o linux_string.o \ - env_attr.o env_flags.o + env_attr.o env_flags.o ../../lib/md5.o fw_printenv-objs := fw_env_main.o $(lib-y) diff --git a/tools/env/caam_keyblob.h b/tools/env/caam_keyblob.h new file mode 100644 index 000000000000..1cdf3946c1ba --- /dev/null +++ b/tools/env/caam_keyblob.h @@ -0,0 +1,45 @@ +/* + * CAAM public-level include definitions for the key blob + * + * Copyright (C) 2015 Freescale Semiconductor, Inc. + */ + +#ifndef CAAM_KEYBLOB_H +#define CAAM_KEYBLOB_H + + +#include +#include + +struct caam_kb_data { + char *rawkey; + size_t rawkey_len; + char *keyblob; + size_t keyblob_len; + char *keymod; + size_t keymod_len; +}; + + +#define CAAM_KB_MAGIC 'I' + +/** + * DOC: CAAM_KB_ENCRYPT - generate a key blob from raw key + * + * Takes an caam_kb_data struct and returns it with the key blob + */ +#define CAAM_KB_ENCRYPT _IOWR(CAAM_KB_MAGIC, 0, \ + struct caam_kb_data) + +/** + * DOC: CAAM_KB_DECRYPT - get keys from a key blob + * + * Takes an caam_kb_data struct and returns it with the raw key. + */ +#define CAAM_KB_DECRYPT _IOWR(CAAM_KB_MAGIC, 1, struct caam_kb_data) + +#ifndef GENMEM_KEYMOD_LEN +#define GENMEM_KEYMOD_LEN 16 +#endif + +#endif /* CAAM_KEYBLOB_H */ diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c index a5d75958e1b6..228d11c070e6 100644 --- a/tools/env/fw_env.c +++ b/tools/env/fw_env.c @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -37,9 +38,17 @@ #include +#include "caam_keyblob.h" #include "fw_env_private.h" #include "fw_env.h" +/* + * The BLOB includes a random AES-256 key (32 bytes) and a + * Message Authentication Code (MAC) (16 bytes) + */ +#define BLOB_OVERHEAD 48 +#define CAAM_KEY_DEV "/dev/caam_kb" + struct env_opts default_opts = { #ifdef CONFIG_FILE .config_file = CONFIG_FILE @@ -117,6 +126,7 @@ static struct environment environment = { }; static int have_redund_env; +static int caam_encryption_flag; static unsigned char active_flag = 1; /* obsolete_flag must be 0 to efficiently set it on NOR flash without erasing */ @@ -442,6 +452,106 @@ char *fw_getdefenv(char *name) return NULL; } +static void check_caam_encryption(void) +{ + const char *dt_prop = "/proc/device-tree/digi,uboot-env,encrypted"; + + if (access(dt_prop, F_OK) != -1) + caam_encryption_flag = 1; +} + +#define MAX_HWID_WORDS 4 +static int env_caam_get_keymod(unsigned char output[16]) +{ + int i; + int len; + int fd; + uint32_t ocotp_hwid[MAX_HWID_WORDS]; + const char dt_prop[32]; + + for (i = 0; i < MAX_HWID_WORDS; i++) { + sprintf(dt_prop, "/proc/device-tree/digi,hwid_%d", i); + if (access(dt_prop, F_OK) != -1) { + char buf[sizeof(uint32_t)]; + + fd = open(dt_prop, O_RDONLY); + if (fd < 0) + return fd; + len = read(fd, buf, sizeof(uint32_t)); + if (len < 0) { + close(fd); + return -1; + } + ocotp_hwid[i] = ntohl(*(uint32_t *)buf); + close(fd); + } else { + break; + } + } + + /* Calculate md5sum on the raw HWID array */ + md5((unsigned char *)(&ocotp_hwid), sizeof(uint32_t) * i, output); + + return 0; +} + +static int env_caam_crypt(char *data, const int enc) +{ + struct caam_kb_data enc_data; + int fd; + int ret = 0; + const int len = usable_envsize; + int ioctl_mode; + char *buffer; + unsigned char key_modifier[16]; + + ret = env_caam_get_keymod(key_modifier); + if (ret) + return ret; + + enc_data.keymod = (char *)key_modifier; + enc_data.keymod_len = sizeof(key_modifier); + + enc_data.keyblob_len = len; + enc_data.rawkey_len = len - BLOB_OVERHEAD; + + buffer = malloc(len); + if (!buffer) { + printf("Could not allocate memory\n"); + return -1; + } + + if (enc) { + enc_data.rawkey = data; + ioctl_mode = CAAM_KB_ENCRYPT; + enc_data.keyblob = buffer; + } else { + enc_data.keyblob = data; + ioctl_mode = CAAM_KB_DECRYPT; + enc_data.rawkey = buffer; + } + + if ((fd = open(CAAM_KEY_DEV, O_RDWR)) < 0) { + ret = fd; + goto free; + } + + ret = ioctl(fd, ioctl_mode, &enc_data); + if (ret) { + printf("CAAM_KEY_DEV ioctl failed: %d\n", ret); + goto out; + } + + memcpy(data, buffer, len); + +out: + close(fd); +free: + free(buffer); + + return ret; +} + /* * Print the current definition of one, or more, or all * environment variables @@ -505,9 +615,20 @@ int fw_printenv(int argc, char *argv[], int value_only, struct env_opts *opts) int fw_env_flush(struct env_opts *opts) { + int ret; + if (!opts) opts = &default_opts; + if (caam_encryption_flag) { + ret = env_caam_crypt(environment.data, 1); + if (ret) { + fprintf(stderr, + "Error: can't encrypt env for flash\n"); + return ret; + } + } + /* * Update CRC */ @@ -1396,6 +1517,8 @@ int fw_env_open(struct env_opts *opts) struct env_image_single *single; struct env_image_redundant *redundant; + check_caam_encryption(); + if (!opts) opts = &default_opts; @@ -1434,6 +1557,15 @@ int fw_env_open(struct env_opts *opts) crc0 = crc32(0, (uint8_t *)environment.data, ENV_SIZE); + if (caam_encryption_flag) { + ret = env_caam_crypt(environment.data, 0); + if (ret) { + fprintf(stderr, + "Error: can't decrypt environment\n"); + return ret; + } + } + crc0_ok = (crc0 == *environment.crc); if (!have_redund_env) { if (!crc0_ok) { @@ -1491,6 +1623,15 @@ int fw_env_open(struct env_opts *opts) crc1 = crc32(0, (uint8_t *)redundant->data, ENV_SIZE); + if (caam_encryption_flag) { + ret = env_caam_crypt(redundant->data, 0); + if (ret) { + fprintf(stderr, + "Error: can't decrypt environment\n"); + return ret; + } + } + crc1_ok = (crc1 == redundant->crc); flag1 = redundant->flags;