From: "Diaz de Grenu, Jose" <Jose.DiazdeGrenu@digi.com>
Date: Tue, 23 Aug 2016 13:05:05 +0200
Subject: [PATCH 1/4] tools: env: implement support for environment encryption
 by CAAM

https://jira.digi.com/browse/DEL-2836

Signed-off-by: Diaz de Grenu, Jose <Jose.DiazdeGrenu@digi.com>
Signed-off-by: Gonzalo Ruiz <Gonzalo.Ruiz@digi.com>
---
 configs/sandbox_defconfig |   1 +
 tools/env/Makefile        |   2 +-
 tools/env/caam_keyblob.h  |  45 +++++++++++++++
 tools/env/fw_env.c        | 140 ++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 187 insertions(+), 1 deletion(-)
 create mode 100644 tools/env/caam_keyblob.h

diff --git a/configs/sandbox_defconfig b/configs/sandbox_defconfig
index 2fc84a1..f033d9c 100644
--- a/configs/sandbox_defconfig
+++ b/configs/sandbox_defconfig
@@ -200,3 +200,4 @@ CONFIG_UT_TIME=y
 CONFIG_UT_DM=y
 CONFIG_UT_ENV=y
 CONFIG_UT_OVERLAY=y
+CONFIG_MD5=y
diff --git a/tools/env/Makefile b/tools/env/Makefile
index 4633e0e..33e41f5 100644
--- a/tools/env/Makefile
+++ b/tools/env/Makefile
@@ -23,7 +23,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 0000000..1cdf394
--- /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 <linux/ioctl.h>
+#include <linux/types.h>
+
+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 a5d7595..b124b1e 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -24,6 +24,7 @@
 #include <sys/types.h>
 #include <sys/ioctl.h>
 #include <sys/stat.h>
+#include <u-boot/md5.h>
 #include <unistd.h>
 #include <dirent.h>

@@ -37,9 +38,19 @@

 #include <mtd/ubi-user.h>

+#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"
+
+#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
+
 struct env_opts default_opts = {
 #ifdef CONFIG_FILE
 	.config_file = CONFIG_FILE
@@ -117,6 +128,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 +454,103 @@ 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;
+}
+
+static int env_caam_get_keymod(unsigned char output[16])
+{
+	int i;
+	int len;
+	int fd;
+	char buff[32];
+	uint32_t ocotp_hwid[2];
+	const char *ocotp_hwid_file[2] = {
+		"/sys/fsl_otp/HW_OCOTP_MAC0",
+		"/sys/fsl_otp/HW_OCOTP_MAC1"
+	};
+
+	for (i = 0; i < ARRAY_SIZE(ocotp_hwid); i++) {
+		fd = open(ocotp_hwid_file[i], O_RDONLY);
+		if (fd < 0)
+			return fd;
+		len = read(fd, buff, sizeof(buff));
+		if (len < 0) {
+			close(fd);
+			return -1;
+		}
+		/* drop last character (new line) */
+		buff[len - 1] = '\0';
+		ocotp_hwid[i] = strtoul(buff, NULL, 0);
+		close(fd);
+	}
+
+	md5((unsigned char *)(&ocotp_hwid), sizeof(ocotp_hwid), 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 +614,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 +1516,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 +1556,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 +1622,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;
