Commit 091576e7 authored by Sandrine Bailleux's avatar Sandrine Bailleux Committed by TrustedFirmware Code Review
Browse files

Merge changes from topic "tbbr/fw_enc" into integration

* changes:
  docs: qemu: Add instructions to boot using FIP image
  docs: Update docs with firmware encryption feature
  qemu: Support optional encryption of BL31 and BL32 images
  qemu: Update flash address map to keep FIP in secure FLASH0
  Makefile: Add support to optionally encrypt BL31 and BL32
  tools: Add firmware authenticated encryption tool
  TBB: Add an IO abstraction layer to load encrypted firmwares
  drivers: crypto: Add authenticated decryption framework
parents a3d0fa31 4ebbea95
......@@ -109,6 +109,22 @@ define IMG_BIN
${BUILD_PLAT}/bl$(1).bin
endef
# IMG_ENC_BIN defines the default encrypted image file corresponding to a
# BL stage
# $(1) = BL stage (2, 30, 31, 32, 33)
define IMG_ENC_BIN
${BUILD_PLAT}/bl$(1)_enc.bin
endef
# ENCRYPT_FW invokes enctool to encrypt firmware binary
# $(1) = input firmware binary
# $(2) = output encrypted firmware binary
define ENCRYPT_FW
$(2): $(1) enctool
$$(ECHO) " ENC $$<"
$$(Q)$$(ENCTOOL) $$(ENC_ARGS) -i $$< -o $$@
endef
# TOOL_ADD_PAYLOAD appends the command line arguments required by fiptool to
# package a new payload and/or by cert_create to generate certificate.
# Optionally, it adds the dependency on this payload
......@@ -116,11 +132,17 @@ endef
# $(2) = command line option for the specified payload (i.e. --soc-fw)
# $(3) = tool target dependency (optional) (ex. build/fvp/release/bl31.bin)
# $(4) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip)
# $(5) = encrypted payload (optional) (ex. build/fvp/release/bl31_enc.bin)
define TOOL_ADD_PAYLOAD
ifneq ($(5),)
$(4)FIP_ARGS += $(2) $(5)
$(if $(3),$(4)CRT_DEPS += $(1))
else
$(4)FIP_ARGS += $(2) $(1)
$(if $(3),$(4)CRT_DEPS += $(3))
endif
$(if $(3),$(4)FIP_DEPS += $(3))
$(4)CRT_ARGS += $(2) $(1)
$(if $(3),$(4)CRT_DEPS += $(3))
endef
# TOOL_ADD_IMG_PAYLOAD works like TOOL_ADD_PAYLOAD, but applies image filters
......@@ -130,6 +152,7 @@ endef
# $(3) = command line option for the specified payload (ex. --soc-fw)
# $(4) = tool target dependency (optional) (ex. build/fvp/release/bl31.bin)
# $(5) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip)
# $(6) = encrypted payload (optional) (ex. build/fvp/release/bl31_enc.bin)
define TOOL_ADD_IMG_PAYLOAD
......@@ -143,10 +166,10 @@ $(call $(PRE_TOOL_FILTER)_RULE,$(PROCESSED_PATH),$(2))
$(PROCESSED_PATH): $(4)
$(call TOOL_ADD_PAYLOAD,$(PROCESSED_PATH),$(3),$(PROCESSED_PATH),$(5))
$(call TOOL_ADD_PAYLOAD,$(PROCESSED_PATH),$(3),$(PROCESSED_PATH),$(5),$(6))
else
$(call TOOL_ADD_PAYLOAD,$(2),$(3),$(4),$(5))
$(call TOOL_ADD_PAYLOAD,$(2),$(3),$(4),$(5),$(6))
endif
endef
......@@ -164,6 +187,7 @@ endef
# $(1) = image_type (scp_bl2, bl33, etc.)
# $(2) = command line option for fiptool (--scp-fw, --nt-fw, etc)
# $(3) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip)
# $(4) = Image encryption flag (optional) (0, 1)
# Example:
# $(eval $(call TOOL_ADD_IMG,bl33,--nt-fw))
define TOOL_ADD_IMG
......@@ -173,7 +197,14 @@ define TOOL_ADD_IMG
$(3)CRT_DEPS += check_$(1)
$(3)FIP_DEPS += check_$(1)
ifeq ($(4),1)
$(eval ENC_BIN := ${BUILD_PLAT}/$(1)_enc.bin)
$(call ENCRYPT_FW,$(value $(_V)),$(ENC_BIN))
$(call TOOL_ADD_IMG_PAYLOAD,$(1),$(value $(_V)),$(2),$(ENC_BIN),$(3), \
$(ENC_BIN))
else
$(call TOOL_ADD_IMG_PAYLOAD,$(1),$(value $(_V)),$(2),,$(3))
endif
.PHONY: check_$(1)
check_$(1):
......@@ -390,6 +421,7 @@ endef
# $(1) = BL stage (1, 2, 2u, 31, 32)
# $(2) = FIP command line option (if empty, image will not be included in the FIP)
# $(3) = FIP prefix (optional) (if FWU_, target is fwu_fip instead of fip)
# $(4) = BL encryption flag (optional) (0, 1)
define MAKE_BL
$(eval BUILD_DIR := ${BUILD_PLAT}/bl$(1))
$(eval BL_SOURCES := $(BL$(call uppercase,$(1))_SOURCES))
......@@ -400,6 +432,7 @@ define MAKE_BL
$(eval ELF := $(call IMG_ELF,$(1)))
$(eval DUMP := $(call IMG_DUMP,$(1)))
$(eval BIN := $(call IMG_BIN,$(1)))
$(eval ENC_BIN := $(call IMG_ENC_BIN,$(1)))
$(eval BL_LINKERFILE := $(BL$(call uppercase,$(1))_LINKERFILE))
$(eval BL_LIBS := $(BL$(call uppercase,$(1))_LIBS))
# We use sort only to get a list of unique object directory names.
......@@ -480,7 +513,13 @@ endif
all: bl$(1)
ifeq ($(4),1)
$(call ENCRYPT_FW,$(BIN),$(ENC_BIN))
$(if $(2),$(call TOOL_ADD_IMG_PAYLOAD,bl$(1),$(BIN),--$(2),$(ENC_BIN),$(3), \
$(ENC_BIN)))
else
$(if $(2),$(call TOOL_ADD_IMG_PAYLOAD,bl$(1),$(BIN),--$(2),$(BIN),$(3)))
endif
endef
......
......@@ -65,6 +65,9 @@ CTX_INCLUDE_PAUTH_REGS := 0
# Debug build
DEBUG := 0
# By default disable authenticated decryption support.
DECRYPTION_SUPPORT := none
# Build platform
DEFAULT_PLAT := fvp
......@@ -106,6 +109,18 @@ ENABLE_BTI := 0
# Use BRANCH_PROTECTION to enable PAUTH.
ENABLE_PAUTH := 0
# By default BL31 encryption disabled
ENCRYPT_BL31 := 0
# By default BL32 encryption disabled
ENCRYPT_BL32 := 0
# Default dummy firmware encryption key
ENC_KEY := 1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef
# Default dummy nonce for firmware encryption
ENC_NONCE := 1234567890abcdef12345678
# Build flag to treat usage of deprecated platform and framework APIs as error.
ERROR_DEPRECATED := 0
......@@ -121,6 +136,9 @@ FIP_NAME := fip.bin
# Default FWU_FIP file name
FWU_FIP_NAME := fwu_fip.bin
# By default firmware encryption with SSK
FW_ENC_STATUS := 0
# For Chain of Trust
GENERATE_COT := 0
......
......@@ -11,6 +11,7 @@
#include <common/debug.h>
#include <lib/xlat_tables/xlat_tables_compat.h>
#include <plat/common/platform.h>
#include <tools_share/firmware_encrypted.h>
/*
* The following platform functions are weakly defined. The Platforms
......@@ -22,6 +23,7 @@
#pragma weak bl2_plat_handle_pre_image_load
#pragma weak bl2_plat_handle_post_image_load
#pragma weak plat_try_next_boot_source
#pragma weak plat_get_enc_key_info
void bl2_el3_plat_prepare_exit(void)
{
......@@ -52,6 +54,31 @@ int plat_try_next_boot_source(void)
return 0;
}
/*
* Weak implementation to provide dummy decryption key only for test purposes,
* platforms must override this API for any real world firmware encryption
* use-case.
*/
int plat_get_enc_key_info(enum fw_enc_status_t fw_enc_status, uint8_t *key,
size_t *key_len, unsigned int *flags,
const uint8_t *img_id, size_t img_id_len)
{
#define DUMMY_FIP_ENC_KEY { 0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, \
0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, \
0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef, \
0x12, 0x34, 0x56, 0x78, 0x90, 0xab, 0xcd, 0xef }
const uint8_t dummy_key[] = DUMMY_FIP_ENC_KEY;
assert(*key_len >= sizeof(dummy_key));
*key_len = sizeof(dummy_key);
memcpy(key, dummy_key, *key_len);
*flags = 0;
return 0;
}
/*
* Set up the page tables for the generic and platform-specific memory regions.
* The size of the Trusted SRAM seen by the BL image must be specified as well
......
......@@ -12,6 +12,7 @@
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/io/io_driver.h>
#include <drivers/io/io_encrypted.h>
#include <drivers/io/io_fip.h>
#include <drivers/io/io_memmap.h>
#include <drivers/io/io_semihosting.h>
......@@ -47,6 +48,10 @@ static const io_dev_connector_t *memmap_dev_con;
static uintptr_t memmap_dev_handle;
static const io_dev_connector_t *sh_dev_con;
static uintptr_t sh_dev_handle;
#ifndef DECRYPTION_SUPPORT_none
static const io_dev_connector_t *enc_dev_con;
static uintptr_t enc_dev_handle;
#endif
static const io_block_spec_t fip_block_spec = {
.offset = PLAT_QEMU_FIP_BASE,
......@@ -172,10 +177,11 @@ static const io_file_spec_t sh_file_spec[] = {
#endif /* TRUSTED_BOARD_BOOT */
};
static int open_fip(const uintptr_t spec);
static int open_memmap(const uintptr_t spec);
#ifndef DECRYPTION_SUPPORT_none
static int open_enc_fip(const uintptr_t spec);
#endif
struct plat_io_policy {
uintptr_t *dev_handle;
......@@ -190,16 +196,46 @@ static const struct plat_io_policy policies[] = {
(uintptr_t)&fip_block_spec,
open_memmap
},
[ENC_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)NULL,
open_fip
},
[BL2_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl2_uuid_spec,
open_fip
},
#if ENCRYPT_BL31 && !defined(DECRYPTION_SUPPORT_none)
[BL31_IMAGE_ID] = {
&enc_dev_handle,
(uintptr_t)&bl31_uuid_spec,
open_enc_fip
},
#else
[BL31_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl31_uuid_spec,
open_fip
},
#endif
#if ENCRYPT_BL32 && !defined(DECRYPTION_SUPPORT_none)
[BL32_IMAGE_ID] = {
&enc_dev_handle,
(uintptr_t)&bl32_uuid_spec,
open_enc_fip
},
[BL32_EXTRA1_IMAGE_ID] = {
&enc_dev_handle,
(uintptr_t)&bl32_extra1_uuid_spec,
open_enc_fip
},
[BL32_EXTRA2_IMAGE_ID] = {
&enc_dev_handle,
(uintptr_t)&bl32_extra2_uuid_spec,
open_enc_fip
},
#else
[BL32_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl32_uuid_spec,
......@@ -215,6 +251,7 @@ static const struct plat_io_policy policies[] = {
(uintptr_t)&bl32_extra2_uuid_spec,
open_fip
},
#endif
[BL33_IMAGE_ID] = {
&fip_dev_handle,
(uintptr_t)&bl33_uuid_spec,
......@@ -271,7 +308,7 @@ static int open_fip(const uintptr_t spec)
/* See if a Firmware Image Package is available */
result = io_dev_init(fip_dev_handle, (uintptr_t)FIP_IMAGE_ID);
if (result == 0) {
if (result == 0 && spec != (uintptr_t)NULL) {
result = io_open(fip_dev_handle, spec, &local_image_handle);
if (result == 0) {
VERBOSE("Using FIP\n");
......@@ -281,6 +318,25 @@ static int open_fip(const uintptr_t spec)
return result;
}
#ifndef DECRYPTION_SUPPORT_none
static int open_enc_fip(const uintptr_t spec)
{
int result;
uintptr_t local_image_handle;
/* See if an encrypted FIP is available */
result = io_dev_init(enc_dev_handle, (uintptr_t)ENC_IMAGE_ID);
if (result == 0) {
result = io_open(enc_dev_handle, spec, &local_image_handle);
if (result == 0) {
VERBOSE("Using encrypted FIP\n");
io_close(local_image_handle);
}
}
return result;
}
#endif
static int open_memmap(const uintptr_t spec)
{
int result;
......@@ -333,6 +389,15 @@ void plat_qemu_io_setup(void)
&memmap_dev_handle);
assert(io_result == 0);
#ifndef DECRYPTION_SUPPORT_none
io_result = register_io_dev_enc(&enc_dev_con);
assert(io_result == 0);
io_result = io_dev_open(enc_dev_con, (uintptr_t)NULL,
&enc_dev_handle);
assert(io_result == 0);
#endif
/* Register the additional IO devices on this platform */
io_result = register_io_dev_sh(&sh_dev_con);
assert(io_result == 0);
......
......@@ -172,7 +172,7 @@
#define PLAT_VIRT_ADDR_SPACE_SIZE (1ULL << 32)
#define MAX_MMAP_REGIONS 11
#define MAX_XLAT_TABLES 6
#define MAX_IO_DEVICES 3
#define MAX_IO_DEVICES 4
#define MAX_IO_HANDLES 4
/*
......@@ -196,8 +196,8 @@
#define QEMU_FLASH1_BASE 0x04000000
#define QEMU_FLASH1_SIZE 0x04000000
#define PLAT_QEMU_FIP_BASE QEMU_FLASH1_BASE
#define PLAT_QEMU_FIP_MAX_SIZE QEMU_FLASH1_SIZE
#define PLAT_QEMU_FIP_BASE 0x00040000
#define PLAT_QEMU_FIP_MAX_SIZE 0x00400000
#define DEVICE0_BASE 0x08000000
#define DEVICE0_SIZE 0x01000000
......
......@@ -128,6 +128,11 @@ ifeq ($(add-lib-optee),yes)
BL2_SOURCES += lib/optee/optee_utils.c
endif
ifneq (${DECRYPTION_SUPPORT},none)
BL1_SOURCES += drivers/io/io_encrypted.c
BL2_SOURCES += drivers/io/io_encrypted.c
endif
QEMU_GICV2_SOURCES := drivers/arm/gic/v2/gicv2_helpers.c \
drivers/arm/gic/v2/gicv2_main.c \
drivers/arm/gic/common/gic_common.c \
......@@ -165,11 +170,19 @@ endif
# Add the build options to pack Trusted OS Extra1 and Trusted OS Extra2 images
# in the FIP if the platform requires.
ifneq ($(BL32_EXTRA1),)
ifneq (${DECRYPTION_SUPPORT},none)
$(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1,,$(ENCRYPT_BL32)))
else
$(eval $(call TOOL_ADD_IMG,bl32_extra1,--tos-fw-extra1))
endif
endif
ifneq ($(BL32_EXTRA2),)
ifneq (${DECRYPTION_SUPPORT},none)
$(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2,,$(ENCRYPT_BL32)))
else
$(eval $(call TOOL_ADD_IMG,bl32_extra2,--tos-fw-extra2))
endif
endif
SEPARATE_CODE_AND_RODATA := 1
ENABLE_STACK_PROTECTOR := 0
......
#
# 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})
/*
* 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 */
/*
* 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 */
/*
* 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 */
/*
* 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];
}
/*
* 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;
}
}
/*
* 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;
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment