libubootenv: rework patchset with Digi-specific functionality

* Move Digi code out of the upstream files to minimize conflicts in
  version migrations.
* Remove all the TEE client copied code and use the libteeclient library.
* Some fixes in the Optee-based environment encryption
* Some simplifications in CAAM-based environment encryption.

https://onedigi.atlassian.net/browse/DUB-1079

Signed-off-by: Javier Viguera <javier.viguera@digi.com>
This commit is contained in:
Javier Viguera 2024-05-28 17:57:01 +02:00
parent a288a03ef5
commit 720c5f7218
7 changed files with 543 additions and 3106 deletions

View File

@ -52,10 +52,10 @@ index 3ed3244..e83b3a5 100644
} }
#endif #endif
diff --git a/src/uboot_env.c b/src/uboot_env.c diff --git a/src/uboot_env.c b/src/uboot_env.c
index 750b736..b7ad4c4 100644 index ae85c7e..358dfbb 100644
--- a/src/uboot_env.c --- a/src/uboot_env.c
+++ b/src/uboot_env.c +++ b/src/uboot_env.c
@@ -2234,3 +2234,99 @@ void libuboot_exit(struct uboot_ctx *ctx) @@ -2103,3 +2103,99 @@ void libuboot_exit(struct uboot_ctx *ctx)
free(ctx); free(ctx);
} }

View File

@ -27,10 +27,10 @@ Signed-off-by: Gabriel Valcazar <gabriel.valcazar@digi.com>
2 files changed, 90 insertions(+), 2 deletions(-) 2 files changed, 90 insertions(+), 2 deletions(-)
diff --git a/src/uboot_env.c b/src/uboot_env.c diff --git a/src/uboot_env.c b/src/uboot_env.c
index b7ad4c4..924a6cf 100644 index 358dfbb..c1f334e 100644
--- a/src/uboot_env.c --- a/src/uboot_env.c
+++ b/src/uboot_env.c +++ b/src/uboot_env.c
@@ -591,6 +591,73 @@ static int check_env_device(struct uboot_flash_env *dev) @@ -581,6 +581,73 @@ static int check_env_device(struct uboot_flash_env *dev)
return 0; return 0;
} }
@ -104,7 +104,7 @@ index b7ad4c4..924a6cf 100644
static bool check_compatible_devices(struct uboot_ctx *ctx) static bool check_compatible_devices(struct uboot_ctx *ctx)
{ {
if (!ctx->redundant) if (!ctx->redundant)
@@ -602,6 +669,12 @@ static bool check_compatible_devices(struct uboot_ctx *ctx) @@ -592,6 +659,12 @@ static bool check_compatible_devices(struct uboot_ctx *ctx)
return false; return false;
if (ctx->envdevs[0].envsize != ctx->envdevs[1].envsize) if (ctx->envdevs[0].envsize != ctx->envdevs[1].envsize)
return false; return false;
@ -117,7 +117,7 @@ index b7ad4c4..924a6cf 100644
return true; return true;
} }
@@ -648,7 +721,7 @@ static int fileread(struct uboot_flash_env *dev, void *data) @@ -638,7 +711,7 @@ static int fileread(struct uboot_flash_env *dev, void *data)
return ret; return ret;
} }
@ -126,7 +126,7 @@ index b7ad4c4..924a6cf 100644
{ {
size_t count; size_t count;
size_t blocksize; size_t blocksize;
@@ -667,6 +740,17 @@ static int mtdread(struct uboot_flash_env *dev, void *data) @@ -657,6 +730,17 @@ static int mtdread(struct uboot_flash_env *dev, void *data)
ret = read(dev->fd, data, dev->envsize); ret = read(dev->fd, data, dev->envsize);
break; break;
case MTD_NANDFLASH: case MTD_NANDFLASH:
@ -144,7 +144,7 @@ index b7ad4c4..924a6cf 100644
if (dev->offset) if (dev->offset)
if (lseek(dev->fd, dev->offset, SEEK_SET) < 0) { if (lseek(dev->fd, dev->offset, SEEK_SET) < 0) {
ret = -EIO; ret = -EIO;
@@ -742,7 +826,7 @@ static int devread(struct uboot_ctx *ctx, unsigned int copy, void *data) @@ -732,7 +816,7 @@ static int devread(struct uboot_ctx *ctx, unsigned int copy, void *data)
ret = fileread(dev, data); ret = fileread(dev, data);
break; break;
case DEVICE_MTD: case DEVICE_MTD:
@ -154,13 +154,13 @@ index b7ad4c4..924a6cf 100644
case DEVICE_UBI: case DEVICE_UBI:
ret = ubiread(dev, data); ret = ubiread(dev, data);
diff --git a/src/uboot_private.h b/src/uboot_private.h diff --git a/src/uboot_private.h b/src/uboot_private.h
index ee2d305..84bd1bc 100644 index 40e5446..c8fecc4 100644
--- a/src/uboot_private.h --- a/src/uboot_private.h
+++ b/src/uboot_private.h +++ b/src/uboot_private.h
@@ -116,10 +116,14 @@ struct uboot_ctx { @@ -114,10 +114,14 @@ LIST_HEAD(vars, var_entry);
struct uboot_ctx {
/** true if the environment is redundant */
bool redundant; bool redundant;
/** true if the environment is encrypted */
bool encrypted;
+ /** true if the environment is dynamic */ + /** true if the environment is dynamic */
+ bool dynamic_env; + bool dynamic_env;
/** set to valid after a successful load */ /** set to valid after a successful load */
@ -169,6 +169,6 @@ index ee2d305..84bd1bc 100644
size_t size; size_t size;
+ /** top limit of the dynamic environment */ + /** top limit of the dynamic environment */
+ loff_t top_limit; + loff_t top_limit;
/** usable environment size */
unsigned int usable_size;
/** devices where environment is stored */ /** devices where environment is stored */
struct uboot_flash_env envdevs[2];
/** Set which device contains the current(last valid) environment */

View File

@ -15,26 +15,63 @@ Signed-off-by: Diaz de Grenu, Jose <Jose.DiazdeGrenu@digi.com>
Signed-off-by: Gonzalo Ruiz <Gonzalo.Ruiz@digi.com> Signed-off-by: Gonzalo Ruiz <Gonzalo.Ruiz@digi.com>
Signed-off-by: Hector Palacios <hector.palacios@digi.com> Signed-off-by: Hector Palacios <hector.palacios@digi.com>
Signed-off-by: Gabriel Valcazar <gabriel.valcazar@digi.com> Signed-off-by: Gabriel Valcazar <gabriel.valcazar@digi.com>
# This is the commit message #2:
fall back to read HWID from nvmem device if not available on DT
Old U-Boot versions don't populate the HWID on the device tree. This may
be used as a key modifier for TrustFence encryption and, if not available
on the DT, newer firmware may be unable to unencrypt the U-Boot
environment.
This patch implements a fall-back function to query the HWID directly from
the nvmem device node if it cannot locate it at the DT.
This is only implemented for ccimx6 family, which may be in the case of
having an old U-Boot.
https://onedigi.atlassian.net/browse/DEL-8444
Signed-off-by: Hector Palacios <hector.palacios@digi.com>
# This is the commit message #3:
ubootenv: generalize env encryption code
Generalize the code to make room for Optee-based encryption.
* Move the code to the crypt.c/h files to minimize changes on the upstream
uboot_env.c file.
* Rename env_caam_get_keymod to env_get_keymod as this function is not
CAAM-specific.
* Create a public env_crypt function that will select the proper (CAAM,
Optee) implementation.
Signed-off-by: Javier Viguera <javier.viguera@digi.com>
--- ---
src/CMakeLists.txt | 2 + src/CMakeLists.txt | 4 +
src/caam_keyblob.h | 42 +++++++ src/caam_keyblob.h | 42 +++++++
src/md5.c | 275 ++++++++++++++++++++++++++++++++++++++++++++ src/crypt.c | 179 +++++++++++++++++++++++++++++
src/crypt.h | 10 ++
src/md5.c | 275 +++++++++++++++++++++++++++++++++++++++++++++
src/md5.h | 24 ++++ src/md5.h | 24 ++++
src/uboot_env.c | 131 +++++++++++++++++++++ src/uboot_env.c | 18 +++
src/uboot_private.h | 4 + 7 files changed, 552 insertions(+)
6 files changed, 478 insertions(+)
create mode 100644 src/caam_keyblob.h create mode 100644 src/caam_keyblob.h
create mode 100644 src/crypt.c
create mode 100644 src/crypt.h
create mode 100644 src/md5.c create mode 100644 src/md5.c
create mode 100644 src/md5.h create mode 100644 src/md5.h
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index ababe0f..fb1efa2 100644 index ababe0f..638f1c1 100644
--- a/src/CMakeLists.txt --- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt +++ b/src/CMakeLists.txt
@@ -4,6 +4,8 @@ @@ -4,6 +4,10 @@
cmake_minimum_required (VERSION 2.6) cmake_minimum_required (VERSION 2.6)
# Sources and private headers # Sources and private headers
SET(libubootenv_SOURCES SET(libubootenv_SOURCES
+ crypt.c
+ crypt.h
+ md5.c + md5.c
+ md5.h + md5.h
uboot_env.c uboot_env.c
@ -88,6 +125,207 @@ index 0000000..e313e87
+#endif +#endif
+ +
+#endif /* CAAM_KEYBLOB_H */ +#endif /* CAAM_KEYBLOB_H */
diff --git a/src/crypt.c b/src/crypt.c
new file mode 100644
index 0000000..213cffd
--- /dev/null
+++ b/src/crypt.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright 2024 Digi International Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <arpa/inet.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#include "caam_keyblob.h"
+#include "md5.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"
+#define MAX_HWID_WORDS 4
+
+/* Function that checks if machine is compatible (on the DT) */
+static bool machine_is_compatible(char *machine)
+{
+ int fd, nchars, len = 0;
+ int ret = false;
+ char str[256];
+ char *p = str;
+
+ fd = open("/proc/device-tree/compatible", O_RDONLY);
+ if (fd < 0)
+ return false;
+
+ nchars = read(fd, str, 255);
+ while (len < nchars) {
+ if (!strcmp(p, machine)) {
+ ret = true;
+ break;
+ }
+ len += strlen(p) + 1;
+ p += strlen(p) + 1;
+ }
+ close(fd);
+
+ return ret;
+}
+
+static int env_get_keymod(unsigned char output[16])
+{
+ int i;
+ int len;
+ int fd;
+ uint32_t ocotp_hwid[MAX_HWID_WORDS];
+ char dt_prop[32];
+ char buf[sizeof(uint32_t)];
+
+ 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) {
+ 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 if (machine_is_compatible("digi,ccimx6ul") ||
+ machine_is_compatible("digi,ccimx6")) {
+ /*
+ * If HWID not available on the DT (old U-Boot version),
+ * fall back to read it directly from the nvmem device.
+ */
+ int hwid_offset = 136; /* (Bank * 8 + Word) * 4 */
+
+ /* HWID for CC6 family only has two words */
+ if (i == 2)
+ break;
+
+ fd = open("/sys/bus/nvmem/devices/imx-ocotp0/nvmem",
+ O_RDONLY);
+ if (fd < 0)
+ return fd;
+ len = lseek(fd, hwid_offset + i * 4, SEEK_SET);
+
+ len = read(fd, buf, sizeof(unsigned int));
+ if (len < 0) {
+ close(fd);
+ return -1;
+ }
+ ocotp_hwid[i] = *(unsigned int *)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, unsigned int size, const int enc)
+{
+ struct caam_kb_data enc_data;
+ int fd;
+ int ret = 0;
+ const int len = size;
+ int ioctl_mode;
+ char *buffer;
+ unsigned char key_modifier[16];
+
+ ret = env_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, enc ? len : len - BLOB_OVERHEAD);
+
+out:
+ close(fd);
+free:
+ free(buffer);
+
+ return ret;
+}
+
+int env_crypt(char *data, unsigned int size, const int enc)
+{
+ return env_caam_crypt(data, size, enc);
+}
+
+int is_env_encrypted(void)
+{
+ const char *dt_prop = "/proc/device-tree/digi,uboot-env,encrypted";
+
+ return access(dt_prop, F_OK) != -1;
+}
diff --git a/src/crypt.h b/src/crypt.h
new file mode 100644
index 0000000..8d85c7f
--- /dev/null
+++ b/src/crypt.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2024 Digi International Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#pragma once
+
+int env_crypt(char *data, unsigned int size, const int enc);
+int is_env_encrypted(void);
diff --git a/src/md5.c b/src/md5.c diff --git a/src/md5.c b/src/md5.c
new file mode 100644 new file mode 100644
index 0000000..47ae8bf index 0000000..47ae8bf
@ -400,146 +638,26 @@ index 0000000..02a9a9d
+ +
+#endif /* _MD5_H */ +#endif /* _MD5_H */
diff --git a/src/uboot_env.c b/src/uboot_env.c diff --git a/src/uboot_env.c b/src/uboot_env.c
index ae85c7e..750b736 100644 index c1f334e..30ef835 100644
--- a/src/uboot_env.c --- a/src/uboot_env.c
+++ b/src/uboot_env.c +++ b/src/uboot_env.c
@@ -34,11 +34,21 @@ @@ -37,6 +37,7 @@
#include <sys/ioctl.h>
#include <zlib.h>
#include <yaml.h>
+#include <arpa/inet.h>
#include <mtd/mtd-user.h> #include <mtd/mtd-user.h>
#include <mtd/ubi-user.h> #include <mtd/ubi-user.h>
+#include "caam_keyblob.h" +#include "crypt.h"
+#include "md5.h"
#include "uboot_private.h" #include "uboot_private.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"
+
#define UBI_MAX_VOLUME 128 #define UBI_MAX_VOLUME 128
@@ -1187,6 +1188,15 @@ int libuboot_env_store(struct uboot_ctx *ctx)
#define DEVICE_MTD_NAME "/dev/mtd"
@@ -1028,6 +1038,105 @@ const struct uboot_version_info *libuboot_version_info(void)
return &libinfo;
}
+static int is_env_encrypted(void)
+{
+ const char *dt_prop = "/proc/device-tree/digi,uboot-env,encrypted";
+
+ return access(dt_prop, F_OK) != -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];
+ 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, unsigned int size, const int enc)
+{
+ struct caam_kb_data enc_data;
+ int fd;
+ int ret = 0;
+ const int len = size;
+ 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, enc ? len : len - BLOB_OVERHEAD);
+
+out:
+ close(fd);
+free:
+ free(buffer);
+
+ return ret;
+}
+
int libuboot_env_store(struct uboot_ctx *ctx)
{
struct var_entry *entry;
@@ -1103,6 +1212,15 @@ int libuboot_env_store(struct uboot_ctx *ctx)
((struct uboot_env_redund *)image)->flags = flags; ((struct uboot_env_redund *)image)->flags = flags;
} }
+ if (ctx->encrypted) { + if (is_env_encrypted()) {
+ ret = env_caam_crypt(data, ctx->usable_size, 1); + size_t usable_envsize = ctx->size - offsetdata;
+ ret = env_crypt(data, usable_envsize, 1);
+ if (ret) { + if (ret) {
+ fprintf(stderr, + fprintf(stderr, "Error: can't encrypt env for flash\n");
+ "Error: can't encrypt env for flash\n");
+ return ret; + return ret;
+ } + }
+ } + }
@ -547,56 +665,18 @@ index ae85c7e..750b736 100644
*(uint32_t *)image = crc32(0, (uint8_t *)data, ctx->size - offsetdata); *(uint32_t *)image = crc32(0, (uint8_t *)data, ctx->size - offsetdata);
copy = ctx->redundant ? (ctx->current ? 0 : 1) : 0; copy = ctx->redundant ? (ctx->current ? 0 : 1) : 0;
@@ -1167,6 +1285,13 @@ static int libuboot_load(struct uboot_ctx *ctx) @@ -1251,6 +1261,14 @@ static int libuboot_load(struct uboot_ctx *ctx)
} }
crc = *(uint32_t *)(buf[i] + offsetcrc); crc = *(uint32_t *)(buf[i] + offsetcrc);
dev->crc = crc32(0, (uint8_t *)data, usable_envsize); dev->crc = crc32(0, (uint8_t *)data, usable_envsize);
+ if (ctx->encrypted) { + if (is_env_encrypted()) {
+ ret = env_caam_crypt((char *)data, ctx->usable_size, 0); + ret = env_crypt(data, usable_envsize, 0);
+ if (ret) { + if (ret) {
+ fprintf(stderr, "Error: can't decrypt environment\n"); + fprintf(stderr,
+ "Error: can't decrypt environment\n");
+ return ret; + return ret;
+ } + }
+ } + }
crcenv[i] = dev->crc == crc; crcenv[i] = dev->crc == crc;
if (ctx->redundant) if (ctx->redundant)
dev->flags = *(uint8_t *)(buf[i] + offsetflags); dev->flags = *(uint8_t *)(buf[i] + offsetflags);
@@ -1773,6 +1898,11 @@ int libuboot_read_config_ext(struct uboot_ctx **ctxlist, const char *config)
break;
}
}
+
+ ctx->usable_size = ctx->size - sizeof(uint32_t);
+ if (ctx->redundant)
+ ctx->usable_size -= sizeof(char);
+
if (ndev == 0)
retval = -EINVAL;
@@ -2042,6 +2172,7 @@ int libuboot_initialize(struct uboot_ctx **out,
return -ENOMEM;
ctx->valid = false;
+ ctx->encrypted = is_env_encrypted();
ret = libuboot_configure(ctx, envdevs);
if (ret < 0) {
diff --git a/src/uboot_private.h b/src/uboot_private.h
index 40e5446..ee2d305 100644
--- a/src/uboot_private.h
+++ b/src/uboot_private.h
@@ -114,10 +114,14 @@ LIST_HEAD(vars, var_entry);
struct uboot_ctx {
/** true if the environment is redundant */
bool redundant;
+ /** true if the environment is encrypted */
+ bool encrypted;
/** set to valid after a successful load */
bool valid;
/** size of the environment */
size_t size;
+ /** usable environment size */
+ unsigned int usable_size;
/** devices where environment is stored */
struct uboot_flash_env envdevs[2];
/** Set which device contains the current(last valid) environment */

View File

@ -0,0 +1,259 @@
From: Mike Engel <Mike.Engel@digi.com>
Date: Fri, 26 May 2023 11:21:43 +0200
Subject: [PATCH] Implement support for environment encryption using Optee
Co-authored-by: Javier Viguera <javier.viguera@digi.com>
Signed-off-by: Mike Engel <Mike.Engel@digi.com>
Signed-off-by: Javier Viguera <javier.viguera@digi.com>
---
src/CMakeLists.txt | 3 +
src/crypt.c | 10 ++-
src/crypt_optee.c | 172 +++++++++++++++++++++++++++++++++++++++++++++
src/crypt_optee.h | 10 +++
4 files changed, 194 insertions(+), 1 deletion(-)
create mode 100644 src/crypt_optee.c
create mode 100644 src/crypt_optee.h
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 638f1c1..f218b35 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -6,6 +6,8 @@ cmake_minimum_required (VERSION 2.6)
SET(libubootenv_SOURCES
crypt.c
crypt.h
+ crypt_optee.c
+ crypt_optee.h
md5.c
md5.h
uboot_env.c
@@ -26,6 +28,7 @@ ADD_LIBRARY(ubootenv_static STATIC ${libubootenv_SOURCES} ${include_HEADERS})
SET_TARGET_PROPERTIES(ubootenv_static PROPERTIES OUTPUT_NAME ubootenv)
add_executable(fw_printenv fw_printenv.c)
target_link_libraries(ubootenv z yaml)
+target_link_libraries(ubootenv teec)
target_link_libraries(fw_printenv ubootenv)
add_custom_target(fw_setenv ALL ${CMAKE_COMMAND} -E create_symlink fw_printenv fw_setenv)
diff --git a/src/crypt.c b/src/crypt.c
index 213cffd..e3f9a5d 100644
--- a/src/crypt.c
+++ b/src/crypt.c
@@ -15,6 +15,7 @@
#include <unistd.h>
#include "caam_keyblob.h"
+#include "crypt_optee.h"
#include "md5.h"
/*
@@ -168,7 +169,14 @@ free:
int env_crypt(char *data, unsigned int size, const int enc)
{
- return env_caam_crypt(data, size, enc);
+ if (is_env_optee_encrypted()) {
+ unsigned char key_modifier[16];
+ if (env_get_keymod(key_modifier))
+ return -1;
+ return env_optee_crypt((char *)key_modifier, data, size, enc);
+ } else {
+ return env_caam_crypt(data, size, enc);
+ }
}
int is_env_encrypted(void)
diff --git a/src/crypt_optee.c b/src/crypt_optee.c
new file mode 100644
index 0000000..fc74141
--- /dev/null
+++ b/src/crypt_optee.c
@@ -0,0 +1,172 @@
+/*
+ * Copyright 2024 Digi International Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#include <arpa/inet.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <tee_client_api.h>
+#include <unistd.h>
+
+#define AES_BLOCK_LENGTH 16
+
+/* From TA's public header (aes_ta.h) */
+#define TA_AES_UUID \
+ { 0xc2fad363, 0x5d9f, 0x4fc4, \
+ { 0xa4, 0x17, 0x55, 0x58, 0x41, 0xe0, 0x57, 0x45 } }
+#define TA_AES_ALGO_ECB 0
+#define TA_AES_ALGO_CBC 1
+#define TA_AES_ALGO_CTR 2
+#define TA_AES_SIZE_128BIT (128 / 8)
+#define TA_AES_SIZE_256BIT (256 / 8)
+#define TA_AES_MODE_DECODE 0
+#define TA_AES_MODE_ENCODE 1
+#define TA_AES_CMD_PREPARE 0
+#define TA_AES_CMD_SET_KEY 1
+#define TA_AES_CMD_SET_IV 2
+#define TA_AES_CMD_CIPHER 3
+
+struct tee_ctx {
+ TEEC_Context ctx;
+ TEEC_Session sess;
+};
+
+static void prepare_tee_session(struct tee_ctx *ctx)
+{
+ TEEC_Result ret;
+ uint32_t origin;
+ TEEC_UUID uuid = TA_AES_UUID;
+
+ ret = TEEC_InitializeContext(NULL, &ctx->ctx);
+ if (ret != TEEC_SUCCESS)
+ printf("TEEC_InitializeContext failed with code 0x%x", ret);
+
+ /* Open a session with the TA */
+ ret = TEEC_OpenSession(&ctx->ctx, &ctx->sess, &uuid,
+ TEEC_LOGIN_PUBLIC, NULL, NULL, &origin);
+ if (ret != TEEC_SUCCESS)
+ printf("TEEC_Opensession failed with code 0x%x origin 0x%x",
+ ret, origin);
+
+}
+
+static void terminate_tee_session(struct tee_ctx *ctx)
+{
+ TEEC_CloseSession(&ctx->sess);
+ TEEC_FinalizeContext(&ctx->ctx);
+}
+
+static void prepare_aes(struct tee_ctx *ctx, int encode)
+{
+ TEEC_Operation op;
+ uint32_t origin;
+ TEEC_Result res;
+
+ memset(&op, 0, sizeof(op));
+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
+ TEEC_VALUE_INPUT,
+ TEEC_VALUE_INPUT, TEEC_NONE);
+
+ op.params[0].value.a = TA_AES_ALGO_CTR;
+ op.params[1].value.a = TA_AES_SIZE_256BIT;
+ op.params[2].value.a = encode ? TA_AES_MODE_ENCODE : TA_AES_MODE_DECODE;
+
+ res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_PREPARE, &op, &origin);
+ if (res != TEEC_SUCCESS)
+ printf("TEEC_InvokeCommand(PREPARE) failed 0x%x origin 0x%x",
+ res, origin);
+}
+
+static void set_key(struct tee_ctx *ctx, size_t key_sz)
+{
+ TEEC_Operation op;
+ uint32_t origin;
+ TEEC_Result res;
+
+ memset(&op, 0, sizeof(op));
+
+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_VALUE_INPUT,
+ TEEC_NONE, TEEC_NONE, TEEC_NONE);
+
+ op.params[0].value.a = key_sz;
+
+ res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_SET_KEY, &op, &origin);
+ if (res != TEEC_SUCCESS)
+ printf("TEEC_InvokeCommand(SET_KEY) failed 0x%x origin 0x%x",
+ res, origin);
+}
+
+static void set_iv(struct tee_ctx *ctx, char *iv, size_t iv_sz)
+{
+ TEEC_Operation op;
+ uint32_t origin;
+ TEEC_Result res;
+
+ memset(&op, 0, sizeof(op));
+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
+ TEEC_NONE, TEEC_NONE, TEEC_NONE);
+ op.params[0].tmpref.buffer = iv;
+ op.params[0].tmpref.size = iv_sz;
+
+ res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_SET_IV, &op, &origin);
+ if (res != TEEC_SUCCESS)
+ printf("TEEC_InvokeCommand(SET_IV) failed 0x%x origin 0x%x",
+ res, origin);
+}
+
+static void cipher_buffer(struct tee_ctx *ctx, char *in, char *out, size_t sz)
+{
+ TEEC_Operation op;
+ uint32_t origin;
+ TEEC_Result res;
+
+ memset(&op, 0, sizeof(op));
+ op.paramTypes = TEEC_PARAM_TYPES(TEEC_MEMREF_TEMP_INPUT,
+ TEEC_MEMREF_TEMP_OUTPUT,
+ TEEC_NONE, TEEC_NONE);
+ op.params[0].tmpref.buffer = in;
+ op.params[0].tmpref.size = sz;
+ op.params[1].tmpref.buffer = out;
+ op.params[1].tmpref.size = sz;
+
+ res = TEEC_InvokeCommand(&ctx->sess, TA_AES_CMD_CIPHER, &op, &origin);
+ if (res != TEEC_SUCCESS)
+ printf("TEEC_InvokeCommand(CIPHER) failed 0x%x origin 0x%x",
+ res, origin);
+}
+
+int env_optee_crypt(char *keymod, char *data, unsigned int size, const int enc)
+{
+ struct tee_ctx tee;
+ char *cryptdata;
+ int ret = 0;
+
+ prepare_tee_session(&tee);
+ prepare_aes(&tee, enc);
+ set_key(&tee, TA_AES_SIZE_256BIT);
+ set_iv(&tee, keymod, AES_BLOCK_LENGTH);
+ cryptdata = calloc(1, size);
+ if (cryptdata) {
+ cipher_buffer(&tee, data, cryptdata, size);
+ memcpy(data, cryptdata, size);
+ free(cryptdata);
+ } else {
+ printf("%s: can't allocate memory\n", __func__);
+ ret = -ENOMEM;
+ }
+ terminate_tee_session(&tee);
+
+ return ret;
+}
+
+int is_env_optee_encrypted(void)
+{
+ const char *dt_prop =
+ "/proc/device-tree/digi,uboot-env,encrypted-optee";
+
+ return access(dt_prop, F_OK) != -1;
+}
diff --git a/src/crypt_optee.h b/src/crypt_optee.h
new file mode 100644
index 0000000..e0c77a7
--- /dev/null
+++ b/src/crypt_optee.h
@@ -0,0 +1,10 @@
+/*
+ * Copyright 2024 Digi International Inc
+ *
+ * SPDX-License-Identifier: GPL-2.0+
+ */
+
+#pragma once
+
+int env_optee_crypt(char *keymod, char *data, unsigned int size, const int enc);
+int is_env_optee_encrypted(void);

View File

@ -1,105 +0,0 @@
From: Hector Palacios <hector.palacios@digi.com>
Date: Mon, 3 Apr 2023 18:21:07 +0200
Subject: [PATCH] fall back to read HWID from nvmem device if not available on
DT
Old U-Boot versions don't populate the HWID on the device tree. This may
be used as a key modifier for TrustFence encryption and, if not available
on the DT, newer firmware may be unable to unencrypt the U-Boot
environment.
This patch implements a fall-back function to query the HWID directly from
the nvmem device node if it cannot locate it at the DT.
This is only implemented for ccimx6 family, which may be in the case of
having an old U-Boot.
Signed-off-by: Hector Palacios <hector.palacios@digi.com>
https://onedigi.atlassian.net/browse/DEL-8444
---
src/uboot_env.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++--
1 file changed, 52 insertions(+), 2 deletions(-)
diff --git a/src/uboot_env.c b/src/uboot_env.c
index 924a6cf..d507cac 100644
--- a/src/uboot_env.c
+++ b/src/uboot_env.c
@@ -1129,6 +1129,32 @@ static int is_env_encrypted(void)
return access(dt_prop, F_OK) != -1;
}
+/* Function that checks if machine is compatible (on the DT) */
+static bool machine_is_compatible(char *machine)
+{
+ int fd, nchars, len = 0;
+ int ret = false;
+ char str[256];
+ char *p = str;
+
+ fd = open("/proc/device-tree/compatible", O_RDONLY);
+ if (fd < 0)
+ return false;
+
+ nchars = read(fd, str, 255);
+ while (len < nchars) {
+ if (!strcmp(p, machine)) {
+ ret = true;
+ break;
+ }
+ len += strlen(p) + 1;
+ p += strlen(p) + 1;
+ }
+
+ close(fd);
+ return ret;
+}
+
#define MAX_HWID_WORDS 4
static int env_caam_get_keymod(unsigned char output[16])
{
@@ -1137,12 +1163,11 @@ static int env_caam_get_keymod(unsigned char output[16])
int fd;
uint32_t ocotp_hwid[MAX_HWID_WORDS];
char dt_prop[32];
+ char buf[sizeof(uint32_t)];
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;
@@ -1153,6 +1178,31 @@ static int env_caam_get_keymod(unsigned char output[16])
}
ocotp_hwid[i] = ntohl(*(uint32_t *)buf);
close(fd);
+ } else if (machine_is_compatible("digi,ccimx6ul") ||
+ machine_is_compatible("digi,ccimx6")) {
+ /*
+ * If HWID not available on the DT (old U-Boot version),
+ * fall back to read it directly from the nvmem device.
+ */
+ int hwid_offset = 136; /* (Bank * 8 + Word) * 4 */
+
+ /* HWID for CC6 family only has two words */
+ if (i == 2)
+ break;
+
+ fd = open("/sys/bus/nvmem/devices/imx-ocotp0/nvmem",
+ O_RDONLY);
+ if (fd < 0)
+ return fd;
+ len = lseek(fd, hwid_offset + i * 4, SEEK_SET);
+
+ len = read(fd, buf, sizeof(unsigned int));
+ if (len < 0) {
+ close(fd);
+ return -1;
+ }
+ ocotp_hwid[i] = *(unsigned int *)buf;
+ close(fd);
} else {
break;
}

View File

@ -15,13 +15,18 @@ FW_CONFIG_FILE:ccmp1 = "${@bb.utils.contains('IMAGE_FEATURES', 'read-only-rootfs
'ubi/fw_env.config_default', \ 'ubi/fw_env.config_default', \
'ubi/fw_env.config', d)}" 'ubi/fw_env.config', d)}"
DEPENDS += "${@oe.utils.conditional('OPTEE_PATCHES', '', '', 'optee-client', d)}"
OPTEE_PATCHES = ""
OPTEE_PATCHES:ccimx93 = "file://0004-Implement-support-for-environment-encryption-using-O.patch"
OPTEE_PATCHES:ccmp1 = "file://0004-Implement-support-for-environment-encryption-using-O.patch"
SRC_URI += " \ SRC_URI += " \
file://${FW_CONFIG_FILE} \ file://${FW_CONFIG_FILE} \
file://0001-Implement-support-for-environment-encryption-by-CAAM.patch \ file://0001-Implement-U-Boot-environment-access-functions.patch \
file://0002-Implement-U-Boot-environment-access-functions.patch \ file://0002-tools-env-add-support-to-set-dynamic-location-of-env.patch \
file://0003-tools-env-add-support-to-set-dynamic-location-of-env.patch \ file://0003-Implement-support-for-environment-encryption-by-CAAM.patch \
file://0004-fall-back-to-read-HWID-from-nvmem-device-if-not-avai.patch \ ${@bb.utils.contains('MACHINE_FEATURES', 'optee', '${OPTEE_PATCHES}', '', d)} \
file://0005-Implement-support-for-environment-encryption-for-CCM.patch \
" "
do_install:append() { do_install:append() {