summaryrefslogtreecommitdiffstats
path: root/tools/encrypt_fw
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 17:43:51 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-21 17:43:51 +0000
commitbe58c81aff4cd4c0ccf43dbd7998da4a6a08c03b (patch)
tree779c248fb61c83f65d1f0dc867f2053d76b4e03a /tools/encrypt_fw
parentInitial commit. (diff)
downloadarm-trusted-firmware-be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b.tar.xz
arm-trusted-firmware-be58c81aff4cd4c0ccf43dbd7998da4a6a08c03b.zip
Adding upstream version 2.10.0+dfsg.upstream/2.10.0+dfsgupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'tools/encrypt_fw')
-rw-r--r--tools/encrypt_fw/Makefile89
-rw-r--r--tools/encrypt_fw/include/cmd_opt.h32
-rw-r--r--tools/encrypt_fw/include/debug.h59
-rw-r--r--tools/encrypt_fw/include/encrypt.h19
-rw-r--r--tools/encrypt_fw/src/cmd_opt.c59
-rw-r--r--tools/encrypt_fw/src/encrypt.c167
-rw-r--r--tools/encrypt_fw/src/main.c224
7 files changed, 649 insertions, 0 deletions
diff --git a/tools/encrypt_fw/Makefile b/tools/encrypt_fw/Makefile
new file mode 100644
index 0000000..924e5fe
--- /dev/null
+++ b/tools/encrypt_fw/Makefile
@@ -0,0 +1,89 @@
+#
+# Copyright (c) 2019-2022, Linaro Limited. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-3-Clause
+#
+
+V ?= 0
+BUILD_INFO ?= 1
+DEBUG := 0
+ENCTOOL ?= encrypt_fw${BIN_EXT}
+BINARY := $(notdir ${ENCTOOL})
+OPENSSL_DIR := /usr
+
+
+MAKE_HELPERS_DIRECTORY := ../../make_helpers/
+include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
+include ${MAKE_HELPERS_DIRECTORY}build_env.mk
+include ${MAKE_HELPERS_DIRECTORY}defaults.mk
+
+OBJECTS := src/encrypt.o \
+ src/cmd_opt.o \
+ src/main.o
+
+HOSTCCFLAGS := -Wall -std=c99
+
+# Select OpenSSL version flag according to the OpenSSL build selected
+# from setting the OPENSSL_DIR path.
+$(eval $(call SELECT_OPENSSL_API_VERSION))
+
+ifeq (${DEBUG},1)
+ HOSTCCFLAGS += -g -O0 -DDEBUG -DLOG_LEVEL=40
+else
+ifeq (${BUILD_INFO},1)
+ HOSTCCFLAGS += -O2 -DLOG_LEVEL=20
+else
+ HOSTCCFLAGS += -O2 -DLOG_LEVEL=10
+endif
+endif
+ifeq (${V},0)
+ Q := @
+else
+ Q :=
+endif
+
+HOSTCCFLAGS += ${DEFINES}
+# USING_OPENSSL3 flag will be added to the HOSTCCFLAGS variable with the proper
+# computed value.
+HOSTCCFLAGS += -DUSING_OPENSSL3=$(USING_OPENSSL3)
+
+
+# Make soft links and include from local directory otherwise wrong headers
+# could get pulled in from firmware tree.
+INC_DIR := -I ./include -I ../../include/tools_share -I ${OPENSSL_DIR}/include
+
+# Include library directories where OpenSSL library files are located.
+# For a normal installation (i.e.: when ${OPENSSL_DIR} = /usr or
+# /usr/local), binaries are located under the ${OPENSSL_DIR}/lib/
+# directory. However, for a local build of OpenSSL, the built binaries are
+# located under the main project directory (i.e.: ${OPENSSL_DIR}, not
+# ${OPENSSL_DIR}/lib/).
+LIB_DIR := -L ${OPENSSL_DIR}/lib -L ${OPENSSL_DIR}
+LIB := -lssl -lcrypto
+
+HOSTCC ?= gcc
+
+.PHONY: all clean realclean --openssl
+
+all: --openssl ${BINARY}
+
+${BINARY}: ${OBJECTS} Makefile
+ @echo " HOSTLD $@"
+ @echo 'const char build_msg[] = "Built : "__TIME__", "__DATE__;' | \
+ ${HOSTCC} -c ${HOSTCCFLAGS} -xc - -o src/build_msg.o
+ ${Q}${HOSTCC} src/build_msg.o ${OBJECTS} ${LIB_DIR} ${LIB} -o $@
+
+%.o: %.c
+ @echo " HOSTCC $<"
+ ${Q}${HOSTCC} -c ${HOSTCCFLAGS} ${INC_DIR} $< -o $@
+
+--openssl:
+ifeq ($(DEBUG),1)
+ @echo "Selected OpenSSL version: ${OPENSSL_CURRENT_VER}"
+endif
+
+clean:
+ $(call SHELL_DELETE_ALL, src/build_msg.o ${OBJECTS})
+
+realclean: clean
+ $(call SHELL_DELETE,${BINARY})
diff --git a/tools/encrypt_fw/include/cmd_opt.h b/tools/encrypt_fw/include/cmd_opt.h
new file mode 100644
index 0000000..bd7d31f
--- /dev/null
+++ b/tools/encrypt_fw/include/cmd_opt.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef CMD_OPT_H
+#define CMD_OPT_H
+
+#include <getopt.h>
+
+#define CMD_OPT_MAX_NUM 64
+
+/* Supported long command line option types */
+enum {
+ CMD_OPT_FW
+};
+
+/* Structure to define a command line option */
+typedef struct cmd_opt_s {
+ struct option long_opt;
+ const char *help_msg;
+} cmd_opt_t;
+
+/* Exported API*/
+void cmd_opt_add(const cmd_opt_t *cmd_opt);
+const struct option *cmd_opt_get_array(void);
+const char *cmd_opt_get_name(int idx);
+const char *cmd_opt_get_help_msg(int idx);
+
+#endif /* CMD_OPT_H */
diff --git a/tools/encrypt_fw/include/debug.h b/tools/encrypt_fw/include/debug.h
new file mode 100644
index 0000000..ee8f1f5
--- /dev/null
+++ b/tools/encrypt_fw/include/debug.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef DEBUG_H
+#define DEBUG_H
+
+#include <stdio.h>
+
+/* The log output macros print output to the console. These macros produce
+ * compiled log output only if the LOG_LEVEL defined in the makefile (or the
+ * make command line) is greater or equal than the level required for that
+ * type of log output.
+ * The format expected is the same as for printf(). For example:
+ * INFO("Info %s.\n", "message") -> INFO: Info message.
+ * WARN("Warning %s.\n", "message") -> WARNING: Warning message.
+ */
+
+#define LOG_LEVEL_NONE 0
+#define LOG_LEVEL_ERROR 10
+#define LOG_LEVEL_NOTICE 20
+#define LOG_LEVEL_WARNING 30
+#define LOG_LEVEL_INFO 40
+#define LOG_LEVEL_VERBOSE 50
+
+
+#if LOG_LEVEL >= LOG_LEVEL_NOTICE
+# define NOTICE(...) printf("NOTICE: " __VA_ARGS__)
+#else
+# define NOTICE(...)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_ERROR
+# define ERROR(...) printf("ERROR: " __VA_ARGS__)
+#else
+# define ERROR(...)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_WARNING
+# define WARN(...) printf("WARNING: " __VA_ARGS__)
+#else
+# define WARN(...)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_INFO
+# define INFO(...) printf("INFO: " __VA_ARGS__)
+#else
+# define INFO(...)
+#endif
+
+#if LOG_LEVEL >= LOG_LEVEL_VERBOSE
+# define VERBOSE(...) printf("VERBOSE: " __VA_ARGS__)
+#else
+# define VERBOSE(...)
+#endif
+
+#endif /* DEBUG_H */
diff --git a/tools/encrypt_fw/include/encrypt.h b/tools/encrypt_fw/include/encrypt.h
new file mode 100644
index 0000000..25d3011
--- /dev/null
+++ b/tools/encrypt_fw/include/encrypt.h
@@ -0,0 +1,19 @@
+/*
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#ifndef ENCRYPT_H
+#define ENCRYPT_H
+
+/* Supported key algorithms */
+enum {
+ KEY_ALG_GCM /* AES-GCM (default) */
+};
+
+int encrypt_file(unsigned short fw_enc_status, int enc_alg, char *key_string,
+ char *nonce_string, const char *ip_name, const char *op_name);
+
+#endif /* ENCRYPT_H */
diff --git a/tools/encrypt_fw/src/cmd_opt.c b/tools/encrypt_fw/src/cmd_opt.c
new file mode 100644
index 0000000..64180d1
--- /dev/null
+++ b/tools/encrypt_fw/src/cmd_opt.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <cmd_opt.h>
+#include <getopt.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include "debug.h"
+
+/* Command line options */
+static struct option long_opt[CMD_OPT_MAX_NUM+1];
+static const char *help_msg[CMD_OPT_MAX_NUM+1];
+static int num_reg_opt;
+
+void cmd_opt_add(const cmd_opt_t *cmd_opt)
+{
+ assert(cmd_opt != NULL);
+
+ if (num_reg_opt >= CMD_OPT_MAX_NUM) {
+ ERROR("Out of memory. Please increase CMD_OPT_MAX_NUM\n");
+ exit(1);
+ }
+
+ long_opt[num_reg_opt].name = cmd_opt->long_opt.name;
+ long_opt[num_reg_opt].has_arg = cmd_opt->long_opt.has_arg;
+ long_opt[num_reg_opt].flag = 0;
+ long_opt[num_reg_opt].val = cmd_opt->long_opt.val;
+
+ help_msg[num_reg_opt] = cmd_opt->help_msg;
+
+ num_reg_opt++;
+}
+
+const struct option *cmd_opt_get_array(void)
+{
+ return long_opt;
+}
+
+const char *cmd_opt_get_name(int idx)
+{
+ if (idx >= num_reg_opt) {
+ return NULL;
+ }
+
+ return long_opt[idx].name;
+}
+
+const char *cmd_opt_get_help_msg(int idx)
+{
+ if (idx >= num_reg_opt) {
+ return NULL;
+ }
+
+ return help_msg[idx];
+}
diff --git a/tools/encrypt_fw/src/encrypt.c b/tools/encrypt_fw/src/encrypt.c
new file mode 100644
index 0000000..18a514c
--- /dev/null
+++ b/tools/encrypt_fw/src/encrypt.c
@@ -0,0 +1,167 @@
+/*
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <firmware_encrypted.h>
+#include <openssl/evp.h>
+#include <stdio.h>
+#include <string.h>
+#include "debug.h"
+#include "encrypt.h"
+
+#define BUFFER_SIZE 256
+#define IV_SIZE 12
+#define IV_STRING_SIZE 24
+#define TAG_SIZE 16
+#define KEY_SIZE 32
+#define KEY_STRING_SIZE 64
+
+static int gcm_encrypt(unsigned short fw_enc_status, char *key_string,
+ char *nonce_string, const char *ip_name,
+ const char *op_name)
+{
+ FILE *ip_file;
+ FILE *op_file;
+ EVP_CIPHER_CTX *ctx;
+ unsigned char data[BUFFER_SIZE], enc_data[BUFFER_SIZE];
+ unsigned char key[KEY_SIZE], iv[IV_SIZE], tag[TAG_SIZE];
+ int bytes, enc_len = 0, i, j, ret = 0;
+ struct fw_enc_hdr header;
+
+ memset(&header, 0, sizeof(struct fw_enc_hdr));
+
+ if (strlen(key_string) != KEY_STRING_SIZE) {
+ ERROR("Unsupported key size: %lu\n", strlen(key_string));
+ return -1;
+ }
+
+ for (i = 0, j = 0; i < KEY_SIZE; i++, j += 2) {
+ if (sscanf(&key_string[j], "%02hhx", &key[i]) != 1) {
+ ERROR("Incorrect key format\n");
+ return -1;
+ }
+ }
+
+ if (strlen(nonce_string) != IV_STRING_SIZE) {
+ ERROR("Unsupported IV size: %lu\n", strlen(nonce_string));
+ return -1;
+ }
+
+ for (i = 0, j = 0; i < IV_SIZE; i++, j += 2) {
+ if (sscanf(&nonce_string[j], "%02hhx", &iv[i]) != 1) {
+ ERROR("Incorrect IV format\n");
+ return -1;
+ }
+ }
+
+ ip_file = fopen(ip_name, "rb");
+ if (ip_file == NULL) {
+ ERROR("Cannot read %s\n", ip_name);
+ return -1;
+ }
+
+ op_file = fopen(op_name, "wb");
+ if (op_file == NULL) {
+ ERROR("Cannot write %s\n", op_name);
+ fclose(ip_file);
+ return -1;
+ }
+
+ ret = fseek(op_file, sizeof(struct fw_enc_hdr), SEEK_SET);
+ if (ret) {
+ ERROR("fseek failed\n");
+ goto out_file;
+ }
+
+ ctx = EVP_CIPHER_CTX_new();
+ if (ctx == NULL) {
+ ERROR("EVP_CIPHER_CTX_new failed\n");
+ ret = -1;
+ goto out_file;
+ }
+
+ ret = EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL);
+ if (ret != 1) {
+ ERROR("EVP_EncryptInit_ex failed\n");
+ ret = -1;
+ goto out;
+ }
+
+ ret = EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv);
+ if (ret != 1) {
+ ERROR("EVP_EncryptInit_ex failed\n");
+ goto out;
+ }
+
+ while ((bytes = fread(data, 1, BUFFER_SIZE, ip_file)) != 0) {
+ ret = EVP_EncryptUpdate(ctx, enc_data, &enc_len, data, bytes);
+ if (ret != 1) {
+ ERROR("EVP_EncryptUpdate failed\n");
+ ret = -1;
+ goto out;
+ }
+
+ fwrite(enc_data, 1, enc_len, op_file);
+ }
+
+ ret = EVP_EncryptFinal_ex(ctx, enc_data, &enc_len);
+ if (ret != 1) {
+ ERROR("EVP_EncryptFinal_ex failed\n");
+ ret = -1;
+ goto out;
+ }
+
+ ret = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, TAG_SIZE, tag);
+ if (ret != 1) {
+ ERROR("EVP_CIPHER_CTX_ctrl failed\n");
+ ret = -1;
+ goto out;
+ }
+
+ header.magic = ENC_HEADER_MAGIC;
+ header.flags |= fw_enc_status & FW_ENC_STATUS_FLAG_MASK;
+ header.dec_algo = KEY_ALG_GCM;
+ header.iv_len = IV_SIZE;
+ header.tag_len = TAG_SIZE;
+ memcpy(header.iv, iv, IV_SIZE);
+ memcpy(header.tag, tag, TAG_SIZE);
+
+ ret = fseek(op_file, 0, SEEK_SET);
+ if (ret) {
+ ERROR("fseek failed\n");
+ goto out;
+ }
+
+ fwrite(&header, 1, sizeof(struct fw_enc_hdr), op_file);
+
+out:
+ EVP_CIPHER_CTX_free(ctx);
+
+out_file:
+ fclose(ip_file);
+ fclose(op_file);
+
+ /*
+ * EVP_* APIs returns 1 as success but enctool considers
+ * 0 as success.
+ */
+ if (ret == 1)
+ ret = 0;
+
+ return ret;
+}
+
+int encrypt_file(unsigned short fw_enc_status, int enc_alg, char *key_string,
+ char *nonce_string, const char *ip_name, const char *op_name)
+{
+ switch (enc_alg) {
+ case KEY_ALG_GCM:
+ return gcm_encrypt(fw_enc_status, key_string, nonce_string,
+ ip_name, op_name);
+ default:
+ return -1;
+ }
+}
diff --git a/tools/encrypt_fw/src/main.c b/tools/encrypt_fw/src/main.c
new file mode 100644
index 0000000..39b7af7
--- /dev/null
+++ b/tools/encrypt_fw/src/main.c
@@ -0,0 +1,224 @@
+/*
+ * Copyright (c) 2019, Linaro Limited. All rights reserved.
+ * Author: Sumit Garg <sumit.garg@linaro.org>
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+
+#include <assert.h>
+#include <ctype.h>
+#include <getopt.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+
+#include <openssl/conf.h>
+
+#include "cmd_opt.h"
+#include "debug.h"
+#include "encrypt.h"
+#include "firmware_encrypted.h"
+
+#define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0])))
+#define HELP_OPT_MAX_LEN 128
+
+/* Global options */
+
+/* Info messages created in the Makefile */
+extern const char build_msg[];
+
+static char *key_algs_str[] = {
+ [KEY_ALG_GCM] = "gcm",
+};
+
+static void print_help(const char *cmd, const struct option *long_opt)
+{
+ int rem, i = 0;
+ const struct option *opt;
+ char line[HELP_OPT_MAX_LEN];
+ char *p;
+
+ assert(cmd != NULL);
+ assert(long_opt != NULL);
+
+ printf("\n\n");
+ printf("The firmware encryption tool loads the binary image and\n"
+ "outputs encrypted binary image using an encryption key\n"
+ "provided as an input hex string.\n");
+ printf("\n");
+ printf("Usage:\n");
+ printf("\t%s [OPTIONS]\n\n", cmd);
+
+ printf("Available options:\n");
+ opt = long_opt;
+ while (opt->name) {
+ p = line;
+ rem = HELP_OPT_MAX_LEN;
+ if (isalpha(opt->val)) {
+ /* Short format */
+ sprintf(p, "-%c,", (char)opt->val);
+ p += 3;
+ rem -= 3;
+ }
+ snprintf(p, rem, "--%s %s", opt->name,
+ (opt->has_arg == required_argument) ? "<arg>" : "");
+ printf("\t%-32s %s\n", line, cmd_opt_get_help_msg(i));
+ opt++;
+ i++;
+ }
+ printf("\n");
+}
+
+static int get_key_alg(const char *key_alg_str)
+{
+ int i;
+
+ for (i = 0 ; i < NUM_ELEM(key_algs_str) ; i++) {
+ if (strcmp(key_alg_str, key_algs_str[i]) == 0) {
+ return i;
+ }
+ }
+
+ return -1;
+}
+
+static void parse_fw_enc_status_flag(const char *arg,
+ unsigned short *fw_enc_status)
+{
+ unsigned long flag;
+ char *endptr;
+
+ flag = strtoul(arg, &endptr, 16);
+ if (*endptr != '\0' || flag > FW_ENC_WITH_BSSK) {
+ ERROR("Invalid fw_enc_status flag '%s'\n", arg);
+ exit(1);
+ }
+
+ *fw_enc_status = flag & FW_ENC_STATUS_FLAG_MASK;
+}
+
+/* Common command line options */
+static const cmd_opt_t common_cmd_opt[] = {
+ {
+ { "help", no_argument, NULL, 'h' },
+ "Print this message and exit"
+ },
+ {
+ { "fw-enc-status", required_argument, NULL, 'f' },
+ "Firmware encryption status flag (with SSK=0 or BSSK=1)."
+ },
+ {
+ { "key-alg", required_argument, NULL, 'a' },
+ "Encryption key algorithm: 'gcm' (default)"
+ },
+ {
+ { "key", required_argument, NULL, 'k' },
+ "Encryption key (for supported algorithm)."
+ },
+ {
+ { "nonce", required_argument, NULL, 'n' },
+ "Nonce or Initialization Vector (for supported algorithm)."
+ },
+ {
+ { "in", required_argument, NULL, 'i' },
+ "Input filename to be encrypted."
+ },
+ {
+ { "out", required_argument, NULL, 'o' },
+ "Encrypted output filename."
+ },
+};
+
+int main(int argc, char *argv[])
+{
+ int i, key_alg, ret;
+ int c, opt_idx = 0;
+ const struct option *cmd_opt;
+ char *key = NULL;
+ char *nonce = NULL;
+ char *in_fn = NULL;
+ char *out_fn = NULL;
+ unsigned short fw_enc_status = 0;
+
+ NOTICE("Firmware Encryption Tool: %s\n", build_msg);
+
+ /* Set default options */
+ key_alg = KEY_ALG_GCM;
+
+ /* Add common command line options */
+ for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) {
+ cmd_opt_add(&common_cmd_opt[i]);
+ }
+
+ /* Get the command line options populated during the initialization */
+ cmd_opt = cmd_opt_get_array();
+
+ while (1) {
+ /* getopt_long stores the option index here. */
+ c = getopt_long(argc, argv, "a:f:hi:k:n:o:", cmd_opt, &opt_idx);
+
+ /* Detect the end of the options. */
+ if (c == -1) {
+ break;
+ }
+
+ switch (c) {
+ case 'a':
+ key_alg = get_key_alg(optarg);
+ if (key_alg < 0) {
+ ERROR("Invalid key algorithm '%s'\n", optarg);
+ exit(1);
+ }
+ break;
+ case 'f':
+ parse_fw_enc_status_flag(optarg, &fw_enc_status);
+ break;
+ case 'k':
+ key = optarg;
+ break;
+ case 'i':
+ in_fn = optarg;
+ break;
+ case 'o':
+ out_fn = optarg;
+ break;
+ case 'n':
+ nonce = optarg;
+ break;
+ case 'h':
+ print_help(argv[0], cmd_opt);
+ exit(0);
+ case '?':
+ default:
+ print_help(argv[0], cmd_opt);
+ exit(1);
+ }
+ }
+
+ if (!key) {
+ ERROR("Key must not be NULL\n");
+ exit(1);
+ }
+
+ if (!nonce) {
+ ERROR("Nonce must not be NULL\n");
+ exit(1);
+ }
+
+ if (!in_fn) {
+ ERROR("Input filename must not be NULL\n");
+ exit(1);
+ }
+
+ if (!out_fn) {
+ ERROR("Output filename must not be NULL\n");
+ exit(1);
+ }
+
+ ret = encrypt_file(fw_enc_status, key_alg, key, nonce, in_fn, out_fn);
+
+ CRYPTO_cleanup_all_ex_data();
+
+ return ret;
+}