mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-05-03 09:29:57 +00:00
tools: Add firmware authenticated encryption tool
Add firmware authenticated encryption tool which utilizes OpenSSL library to encrypt firmwares using a key provided via cmdline. Currently this tool supports AES-GCM as an authenticated encryption algorithm. Signed-off-by: Sumit Garg <sumit.garg@linaro.org> Change-Id: I60e296af1b98f1912a19d5f91066be7ea85836e4
This commit is contained in:
parent
2be57b8658
commit
90aa901fc1
8 changed files with 642 additions and 1 deletions
18
Makefile
18
Makefile
|
@ -716,6 +716,10 @@ include lib/stack_protector/stack_protector.mk
|
||||||
CRTTOOLPATH ?= tools/cert_create
|
CRTTOOLPATH ?= tools/cert_create
|
||||||
CRTTOOL ?= ${CRTTOOLPATH}/cert_create${BIN_EXT}
|
CRTTOOL ?= ${CRTTOOLPATH}/cert_create${BIN_EXT}
|
||||||
|
|
||||||
|
# Variables for use with Firmware Encryption Tool
|
||||||
|
ENCTOOLPATH ?= tools/encrypt_fw
|
||||||
|
ENCTOOL ?= ${ENCTOOLPATH}/encrypt_fw${BIN_EXT}
|
||||||
|
|
||||||
# Variables for use with Firmware Image Package
|
# Variables for use with Firmware Image Package
|
||||||
FIPTOOLPATH ?= tools/fiptool
|
FIPTOOLPATH ?= tools/fiptool
|
||||||
FIPTOOL ?= ${FIPTOOLPATH}/fiptool${BIN_EXT}
|
FIPTOOL ?= ${FIPTOOLPATH}/fiptool${BIN_EXT}
|
||||||
|
@ -935,7 +939,7 @@ endif
|
||||||
# Build targets
|
# Build targets
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
.PHONY: all msg_start clean realclean distclean cscope locate-checkpatch checkcodebase checkpatch fiptool sptool fip sp fwu_fip certtool dtbs memmap doc
|
.PHONY: all msg_start clean realclean distclean cscope locate-checkpatch checkcodebase checkpatch fiptool sptool fip sp fwu_fip certtool dtbs memmap doc enctool
|
||||||
.SUFFIXES:
|
.SUFFIXES:
|
||||||
|
|
||||||
all: msg_start
|
all: msg_start
|
||||||
|
@ -1038,6 +1042,7 @@ clean:
|
||||||
$(call SHELL_REMOVE_DIR,${BUILD_PLAT})
|
$(call SHELL_REMOVE_DIR,${BUILD_PLAT})
|
||||||
${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
|
${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
|
||||||
${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean
|
${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean
|
||||||
|
${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${ENCTOOLPATH} clean
|
||||||
${Q}${MAKE} --no-print-directory -C ${ROMLIBPATH} clean
|
${Q}${MAKE} --no-print-directory -C ${ROMLIBPATH} clean
|
||||||
|
|
||||||
realclean distclean:
|
realclean distclean:
|
||||||
|
@ -1047,6 +1052,7 @@ realclean distclean:
|
||||||
${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
|
${Q}${MAKE} --no-print-directory -C ${FIPTOOLPATH} clean
|
||||||
${Q}${MAKE} --no-print-directory -C ${SPTOOLPATH} clean
|
${Q}${MAKE} --no-print-directory -C ${SPTOOLPATH} clean
|
||||||
${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean
|
${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${CRTTOOLPATH} clean
|
||||||
|
${Q}${MAKE} PLAT=${PLAT} --no-print-directory -C ${ENCTOOLPATH} realclean
|
||||||
${Q}${MAKE} --no-print-directory -C ${ROMLIBPATH} clean
|
${Q}${MAKE} --no-print-directory -C ${ROMLIBPATH} clean
|
||||||
|
|
||||||
checkcodebase: locate-checkpatch
|
checkcodebase: locate-checkpatch
|
||||||
|
@ -1148,6 +1154,15 @@ doc:
|
||||||
@echo " BUILD DOCUMENTATION"
|
@echo " BUILD DOCUMENTATION"
|
||||||
${Q}${MAKE} --no-print-directory -C ${DOCS_PATH} html
|
${Q}${MAKE} --no-print-directory -C ${DOCS_PATH} html
|
||||||
|
|
||||||
|
enctool: ${ENCTOOL}
|
||||||
|
|
||||||
|
.PHONY: ${ENCTOOL}
|
||||||
|
${ENCTOOL}:
|
||||||
|
${Q}${MAKE} PLAT=${PLAT} BUILD_INFO=0 --no-print-directory -C ${ENCTOOLPATH}
|
||||||
|
@${ECHO_BLANK_LINE}
|
||||||
|
@echo "Built $@ successfully"
|
||||||
|
@${ECHO_BLANK_LINE}
|
||||||
|
|
||||||
cscope:
|
cscope:
|
||||||
@echo " CSCOPE"
|
@echo " CSCOPE"
|
||||||
${Q}find ${CURDIR} -name "*.[chsS]" > cscope.files
|
${Q}find ${CURDIR} -name "*.[chsS]" > cscope.files
|
||||||
|
@ -1184,6 +1199,7 @@ help:
|
||||||
@echo " cscope Generate cscope index"
|
@echo " cscope Generate cscope index"
|
||||||
@echo " distclean Remove all build artifacts for all platforms"
|
@echo " distclean Remove all build artifacts for all platforms"
|
||||||
@echo " certtool Build the Certificate generation tool"
|
@echo " certtool Build the Certificate generation tool"
|
||||||
|
@echo " enctool Build the Firmware encryption tool"
|
||||||
@echo " fiptool Build the Firmware Image Package (FIP) creation tool"
|
@echo " fiptool Build the Firmware Image Package (FIP) creation tool"
|
||||||
@echo " sp Build the Secure Partition Packages"
|
@echo " sp Build the Secure Partition Packages"
|
||||||
@echo " sptool Build the Secure Partition Package creation tool"
|
@echo " sptool Build the Secure Partition Package creation tool"
|
||||||
|
|
65
tools/encrypt_fw/Makefile
Normal file
65
tools/encrypt_fw/Makefile
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
#
|
||||||
|
# Copyright (c) 2019, Linaro Limited. All rights reserved.
|
||||||
|
#
|
||||||
|
# SPDX-License-Identifier: BSD-3-Clause
|
||||||
|
#
|
||||||
|
|
||||||
|
PROJECT := encrypt_fw
|
||||||
|
V ?= 0
|
||||||
|
BUILD_INFO ?= 1
|
||||||
|
DEBUG := 0
|
||||||
|
BINARY := ${PROJECT}${BIN_EXT}
|
||||||
|
OPENSSL_DIR := /usr
|
||||||
|
|
||||||
|
OBJECTS := src/encrypt.o \
|
||||||
|
src/cmd_opt.o \
|
||||||
|
src/main.o
|
||||||
|
|
||||||
|
HOSTCCFLAGS := -Wall -std=c99
|
||||||
|
|
||||||
|
MAKE_HELPERS_DIRECTORY := ../../make_helpers/
|
||||||
|
include ${MAKE_HELPERS_DIRECTORY}build_macros.mk
|
||||||
|
include ${MAKE_HELPERS_DIRECTORY}build_env.mk
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
# 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
|
||||||
|
LIB_DIR := -L ${OPENSSL_DIR}/lib
|
||||||
|
LIB := -lssl -lcrypto
|
||||||
|
|
||||||
|
HOSTCC ?= gcc
|
||||||
|
|
||||||
|
.PHONY: all clean realclean
|
||||||
|
|
||||||
|
all: clean ${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 $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
$(call SHELL_DELETE_ALL, src/build_msg.o ${OBJECTS})
|
||||||
|
|
||||||
|
realclean: clean
|
||||||
|
$(call SHELL_DELETE,${BINARY})
|
32
tools/encrypt_fw/include/cmd_opt.h
Normal file
32
tools/encrypt_fw/include/cmd_opt.h
Normal file
|
@ -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 */
|
59
tools/encrypt_fw/include/debug.h
Normal file
59
tools/encrypt_fw/include/debug.h
Normal file
|
@ -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 */
|
19
tools/encrypt_fw/include/encrypt.h
Normal file
19
tools/encrypt_fw/include/encrypt.h
Normal file
|
@ -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 */
|
59
tools/encrypt_fw/src/cmd_opt.c
Normal file
59
tools/encrypt_fw/src/cmd_opt.c
Normal file
|
@ -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];
|
||||||
|
}
|
167
tools/encrypt_fw/src/encrypt.c
Normal file
167
tools/encrypt_fw/src/encrypt.c
Normal file
|
@ -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;
|
||||||
|
}
|
||||||
|
}
|
224
tools/encrypt_fw/src/main.c
Normal file
224
tools/encrypt_fw/src/main.c
Normal file
|
@ -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;
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue