diff options
Diffstat (limited to 'tools/cert_create')
26 files changed, 4141 insertions, 0 deletions
diff --git a/tools/cert_create/Makefile b/tools/cert_create/Makefile new file mode 100644 index 0000000..042e844 --- /dev/null +++ b/tools/cert_create/Makefile @@ -0,0 +1,111 @@ +# +# Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +PLAT := none +V ?= 0 +DEBUG := 0 +CRTTOOL ?= cert_create${BIN_EXT} +BINARY := $(notdir ${CRTTOOL}) +COT := tbbr + +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 + +ifneq (${PLAT},none) +TF_PLATFORM_ROOT := ../../plat/ +include ${MAKE_HELPERS_DIRECTORY}plat_helpers.mk +PLAT_CERT_CREATE_HELPER_MK := ${PLAT_DIR}/cert_create_tbbr.mk +endif + +# Common source files. +OBJECTS := src/cert.o \ + src/cmd_opt.o \ + src/ext.o \ + src/key.o \ + src/main.o \ + src/sha.o + +# Chain of trust. +ifeq (${COT},tbbr) + include src/tbbr/tbbr.mk +else ifeq (${COT},dualroot) + include src/dualroot/cot.mk +else ifeq (${COT},cca) + include src/cca/cot.mk +else + $(error Unknown chain of trust ${COT}) +endif + +ifneq (,$(wildcard ${PLAT_CERT_CREATE_HELPER_MK})) +include ${PLAT_CERT_CREATE_HELPER_MK} +endif + +# Select OpenSSL version flag according to the OpenSSL build selected +# from setting the OPENSSL_DIR path. +$(eval $(call SELECT_OPENSSL_API_VERSION)) + +HOSTCCFLAGS := -Wall -std=c99 + +ifeq (${DEBUG},1) + HOSTCCFLAGS += -g -O0 -DDEBUG -DLOG_LEVEL=40 +else + HOSTCCFLAGS += -O2 -DLOG_LEVEL=20 +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 ${PLAT_INCLUDE} -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: ${BINARY} + +${BINARY}: --openssl ${OBJECTS} Makefile + @echo " HOSTLD $@" + @echo 'const char build_msg[] = "Built : "__TIME__", "__DATE__; \ + const char platform_msg[] = "${PLAT_MSG}";' | \ + ${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/cert_create/include/cca/cca_cot.h b/tools/cert_create/include/cca/cca_cot.h new file mode 100644 index 0000000..56585fb --- /dev/null +++ b/tools/cert_create/include/cca/cca_cot.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2022, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef CCA_COT_H +#define CCA_COT_H + +/* Certificates. */ +enum { + /* Certificates owned by the silicon provider. */ + CCA_CONTENT_CERT, + CORE_SWD_KEY_CERT, + SPMC_CONTENT_CERT, + SIP_SECURE_PARTITION_CONTENT_CERT, + + /* Certificates owned by the platform owner. */ + PLAT_KEY_CERT, + PLAT_SECURE_PARTITION_CONTENT_CERT, + NON_TRUSTED_FW_CONTENT_CERT, +}; + +/* Certificate extensions. */ +enum { + /* Extensions used in certificates owned by the silicon provider. */ + TRUSTED_FW_NVCOUNTER_EXT, + TRUSTED_BOOT_FW_HASH_EXT, + TRUSTED_BOOT_FW_CONFIG_HASH_EXT, + HW_CONFIG_HASH_EXT, + FW_CONFIG_HASH_EXT, + SWD_ROT_PK_EXT, + CORE_SWD_PK_EXT, + SOC_AP_FW_HASH_EXT, + SOC_FW_CONFIG_HASH_EXT, + RMM_HASH_EXT, + TRUSTED_OS_FW_HASH_EXT, + TRUSTED_OS_FW_CONFIG_HASH_EXT, + SP_PKG1_HASH_EXT, + SP_PKG2_HASH_EXT, + SP_PKG3_HASH_EXT, + SP_PKG4_HASH_EXT, + + /* Extensions used in certificates owned by the platform owner. */ + PROT_PK_EXT, + PLAT_PK_EXT, + SP_PKG5_HASH_EXT, + SP_PKG6_HASH_EXT, + SP_PKG7_HASH_EXT, + SP_PKG8_HASH_EXT, + NON_TRUSTED_FW_NVCOUNTER_EXT, + NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT, + NON_TRUSTED_FW_CONFIG_HASH_EXT, +}; + +/* Keys. */ +enum { + /* Keys owned by the silicon provider. */ + ROT_KEY, + SWD_ROT_KEY, + CORE_SWD_KEY, + + /* Keys owned by the platform owner. */ + PROT_KEY, + PLAT_KEY, +}; + +#endif /* CCA_COT_H */ diff --git a/tools/cert_create/include/cert.h b/tools/cert_create/include/cert.h new file mode 100644 index 0000000..5d39a88 --- /dev/null +++ b/tools/cert_create/include/cert.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef CERT_H +#define CERT_H + +#include <openssl/ossl_typ.h> +#include <openssl/x509.h> +#include "ext.h" +#include "key.h" + +#define CERT_MAX_EXT 9 + +/* + * This structure contains information related to the generation of the + * certificates. All these fields must be known and specified at build time + * except for the file name, which is picked up from the command line at + * run time. + * + * One instance of this structure must be created for each of the certificates + * present in the chain of trust. + * + * If the issuer points to this same instance, the generated certificate will + * be self-signed. + */ +typedef struct cert_s cert_t; +struct cert_s { + int id; /* Unique identifier */ + + const char *opt; /* Command line option to pass filename */ + const char *fn; /* Filename to save the certificate */ + const char *cn; /* Subject CN (Company Name) */ + const char *help_msg; /* Help message */ + + /* These fields must be defined statically */ + int key; /* Key to be signed */ + int issuer; /* Issuer certificate */ + int ext[CERT_MAX_EXT]; /* Certificate extensions */ + int num_ext; /* Number of extensions in the certificate */ + + X509 *x; /* X509 certificate container */ +}; + +/* Exported API */ +int cert_init(void); +cert_t *cert_get_by_opt(const char *opt); +int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value); +int cert_new( + int md_alg, + cert_t *cert, + int days, + int ca, + STACK_OF(X509_EXTENSION) * sk); +void cert_cleanup(void); + +/* Macro to register the certificates used in the CoT */ +#define REGISTER_COT(_certs) \ + cert_t *def_certs = &_certs[0]; \ + const unsigned int num_def_certs = sizeof(_certs)/sizeof(_certs[0]) + +/* Macro to register the platform defined certificates used in the CoT */ +#define PLAT_REGISTER_COT(_pdef_certs) \ + cert_t *pdef_certs = &_pdef_certs[0]; \ + const unsigned int num_pdef_certs = sizeof(_pdef_certs)/sizeof(_pdef_certs[0]) + +/* Exported variables */ +extern cert_t *def_certs; +extern const unsigned int num_def_certs; +extern cert_t *pdef_certs; +extern const unsigned int num_pdef_certs; + +extern cert_t *certs; +extern unsigned int num_certs; +#endif /* CERT_H */ diff --git a/tools/cert_create/include/cmd_opt.h b/tools/cert_create/include/cmd_opt.h new file mode 100644 index 0000000..10df00e --- /dev/null +++ b/tools/cert_create/include/cmd_opt.h @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. 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_CERT, + CMD_OPT_KEY, + CMD_OPT_EXT +}; + +/* 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/cert_create/include/debug.h b/tools/cert_create/include/debug.h new file mode 100644 index 0000000..ee8f1f5 --- /dev/null +++ b/tools/cert_create/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/cert_create/include/dualroot/cot.h b/tools/cert_create/include/dualroot/cot.h new file mode 100644 index 0000000..3e50c89 --- /dev/null +++ b/tools/cert_create/include/dualroot/cot.h @@ -0,0 +1,81 @@ +/* + * Copyright (c) 2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef DUALROOT_COT_H +#define DUALROOT_COT_H + +/* Certificates. */ +enum { + /* Certificates owned by the silicon provider. */ + TRUSTED_BOOT_FW_CERT, + TRUSTED_KEY_CERT, + SCP_FW_KEY_CERT, + SCP_FW_CONTENT_CERT, + SOC_FW_KEY_CERT, + SOC_FW_CONTENT_CERT, + TRUSTED_OS_FW_KEY_CERT, + TRUSTED_OS_FW_CONTENT_CERT, + SIP_SECURE_PARTITION_CONTENT_CERT, + FWU_CERT, + + /* Certificates owned by the platform owner. */ + NON_TRUSTED_FW_CONTENT_CERT, + PLAT_SECURE_PARTITION_CONTENT_CERT, +}; + +/* Certificate extensions. */ +enum { + /* Extensions used in certificates owned by the silicon provider. */ + TRUSTED_FW_NVCOUNTER_EXT, + TRUSTED_BOOT_FW_HASH_EXT, + TRUSTED_BOOT_FW_CONFIG_HASH_EXT, + HW_CONFIG_HASH_EXT, + FW_CONFIG_HASH_EXT, + TRUSTED_WORLD_PK_EXT, + SCP_FW_CONTENT_CERT_PK_EXT, + SCP_FW_HASH_EXT, + SOC_FW_CONTENT_CERT_PK_EXT, + SOC_AP_FW_HASH_EXT, + SOC_FW_CONFIG_HASH_EXT, + TRUSTED_OS_FW_CONTENT_CERT_PK_EXT, + TRUSTED_OS_FW_HASH_EXT, + TRUSTED_OS_FW_EXTRA1_HASH_EXT, + TRUSTED_OS_FW_EXTRA2_HASH_EXT, + TRUSTED_OS_FW_CONFIG_HASH_EXT, + SP_PKG1_HASH_EXT, + SP_PKG2_HASH_EXT, + SP_PKG3_HASH_EXT, + SP_PKG4_HASH_EXT, + SP_PKG5_HASH_EXT, + SP_PKG6_HASH_EXT, + SP_PKG7_HASH_EXT, + SP_PKG8_HASH_EXT, + SCP_FWU_CFG_HASH_EXT, + AP_FWU_CFG_HASH_EXT, + FWU_HASH_EXT, + + /* Extensions used in certificates owned by the platform owner. */ + PROT_PK_EXT, + NON_TRUSTED_FW_NVCOUNTER_EXT, + NON_TRUSTED_FW_CONTENT_CERT_PK_EXT, + NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT, + NON_TRUSTED_FW_CONFIG_HASH_EXT, +}; + +/* Keys. */ +enum { + /* Keys owned by the silicon provider. */ + ROT_KEY, + TRUSTED_WORLD_KEY, + SCP_FW_CONTENT_CERT_KEY, + SOC_FW_CONTENT_CERT_KEY, + TRUSTED_OS_FW_CONTENT_CERT_KEY, + + /* Keys owned by the platform owner. */ + PROT_KEY, +}; + +#endif /* DUALROOT_COT_H */ diff --git a/tools/cert_create/include/ext.h b/tools/cert_create/include/ext.h new file mode 100644 index 0000000..0e7f3be --- /dev/null +++ b/tools/cert_create/include/ext.h @@ -0,0 +1,95 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef EXT_H +#define EXT_H + +#include <openssl/x509v3.h> +#include "key.h" + +/* Extension types supported */ +enum ext_type_e { + EXT_TYPE_NVCOUNTER, + EXT_TYPE_PKEY, + EXT_TYPE_HASH +}; + +/* NV-Counter types */ +enum nvctr_type_e { + NVCTR_TYPE_TFW, + NVCTR_TYPE_NTFW +}; + +/* + * This structure contains the relevant information to create the extensions + * to be included in the certificates. This extensions will be used to + * establish the chain of trust. + */ +typedef struct ext_s { + const char *oid; /* OID of the extension */ + const char *sn; /* Short name */ + const char *ln; /* Long description */ + const char *opt; /* Command line option to specify data */ + const char *help_msg; /* Help message */ + const char *arg; /* Argument passed from command line */ + int asn1_type; /* OpenSSL ASN1 type of the extension data. + * Supported types are: + * - V_ASN1_INTEGER + * - V_ASN1_OCTET_STRING + */ + int type; /* See ext_type_e */ + + /* Extension attributes (depends on extension type) */ + union { + int nvctr_type; /* See nvctr_type_e */ + int key; /* Index into array of registered public keys */ + } attr; + + int alias; /* In case OpenSSL provides an standard + * extension of the same type, add the new + * extension as an alias of this one + */ + + X509V3_EXT_METHOD method; /* This field may be used to define a custom + * function to print the contents of the + * extension */ + + int optional; /* This field may be used optionally to exclude an image */ +} ext_t; + +enum { + EXT_NON_CRIT = 0, + EXT_CRIT = !EXT_NON_CRIT, +}; + +/* Exported API */ +int ext_init(void); +ext_t *ext_get_by_opt(const char *opt); +X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md, + unsigned char *buf, size_t len); +X509_EXTENSION *ext_new_nvcounter(int nid, int crit, int value); +X509_EXTENSION *ext_new_key(int nid, int crit, EVP_PKEY *k); +void ext_cleanup(void); + +/* Macro to register the extensions used in the CoT */ +#define REGISTER_EXTENSIONS(_ext) \ + ext_t *def_extensions = &_ext[0]; \ + const unsigned int num_def_extensions = sizeof(_ext)/sizeof(_ext[0]) + +/* Macro to register the platform defined extensions used in the CoT */ +#define PLAT_REGISTER_EXTENSIONS(_pdef_ext) \ + ext_t *pdef_extensions = &_pdef_ext[0]; \ + const unsigned int num_pdef_extensions = sizeof(_pdef_ext)/sizeof(_pdef_ext[0]) + +/* Exported variables */ +extern ext_t *def_extensions; +extern const unsigned int num_def_extensions; +extern ext_t *pdef_extensions; +extern const unsigned int num_pdef_extensions; + +extern ext_t *extensions; +extern unsigned int num_extensions; +#endif /* EXT_H */ diff --git a/tools/cert_create/include/key.h b/tools/cert_create/include/key.h new file mode 100644 index 0000000..312575b --- /dev/null +++ b/tools/cert_create/include/key.h @@ -0,0 +1,99 @@ +/* + * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef KEY_H +#define KEY_H + +#include <openssl/ossl_typ.h> + +/* Error codes */ +enum { + KEY_ERR_NONE, + KEY_ERR_MALLOC, + KEY_ERR_FILENAME, + KEY_ERR_OPEN, + KEY_ERR_LOAD +}; + +/* Supported key algorithms */ +enum { + KEY_ALG_RSA, /* RSA PSS as defined by PKCS#1 v2.1 (default) */ +#ifndef OPENSSL_NO_EC + KEY_ALG_ECDSA_NIST, + KEY_ALG_ECDSA_BRAINPOOL_R, + KEY_ALG_ECDSA_BRAINPOOL_T, +#endif /* OPENSSL_NO_EC */ + KEY_ALG_MAX_NUM +}; + +/* Maximum number of valid key sizes per algorithm */ +#define KEY_SIZE_MAX_NUM 4 + +/* Supported hash algorithms */ +enum{ + HASH_ALG_SHA256, + HASH_ALG_SHA384, + HASH_ALG_SHA512, +}; + +/* Supported key sizes */ +/* NOTE: the first item in each array is the default key size */ +static const unsigned int KEY_SIZES[KEY_ALG_MAX_NUM][KEY_SIZE_MAX_NUM] = { + { 2048, 1024, 3072, 4096 }, /* KEY_ALG_RSA */ +#ifndef OPENSSL_NO_EC + {}, /* KEY_ALG_ECDSA_NIST */ + {}, /* KEY_ALG_ECDSA_BRAINPOOL_R */ + {} /* KEY_ALG_ECDSA_BRAINPOOL_T */ +#endif /* OPENSSL_NO_EC */ +}; + +/* + * This structure contains the relevant information to create the keys + * required to sign the certificates. + * + * One instance of this structure must be created for each key, usually in an + * array fashion. The filename is obtained at run time from the command line + * parameters + */ +typedef struct key_s { + int id; /* Key id */ + const char *opt; /* Command line option to specify a key */ + const char *help_msg; /* Help message */ + const char *desc; /* Key description (debug purposes) */ + char *fn; /* Filename to load/store the key */ + EVP_PKEY *key; /* Key container */ +} key_t; + +/* Exported API */ +int key_init(void); +key_t *key_get_by_opt(const char *opt); +#if !USING_OPENSSL3 +int key_new(key_t *key); +#endif +int key_create(key_t *key, int type, int key_bits); +int key_load(key_t *key, unsigned int *err_code); +int key_store(key_t *key); +void key_cleanup(void); + +/* Macro to register the keys used in the CoT */ +#define REGISTER_KEYS(_keys) \ + key_t *def_keys = &_keys[0]; \ + const unsigned int num_def_keys = sizeof(_keys)/sizeof(_keys[0]) + +/* Macro to register the platform defined keys used in the CoT */ +#define PLAT_REGISTER_KEYS(_pdef_keys) \ + key_t *pdef_keys = &_pdef_keys[0]; \ + const unsigned int num_pdef_keys = sizeof(_pdef_keys)/sizeof(_pdef_keys[0]) + +/* Exported variables */ +extern key_t *def_keys; +extern const unsigned int num_def_keys; +extern key_t *pdef_keys; +extern const unsigned int num_pdef_keys; + +extern key_t *keys; +extern unsigned int num_keys; +#endif /* KEY_H */ diff --git a/tools/cert_create/include/sha.h b/tools/cert_create/include/sha.h new file mode 100644 index 0000000..4c55f37 --- /dev/null +++ b/tools/cert_create/include/sha.h @@ -0,0 +1,12 @@ +/* + * Copyright (c) 2015-2017, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef SHA_H +#define SHA_H + +int sha_file(int md_alg, const char *filename, unsigned char *md); + +#endif /* SHA_H */ diff --git a/tools/cert_create/include/tbbr/tbb_cert.h b/tools/cert_create/include/tbbr/tbb_cert.h new file mode 100644 index 0000000..e5fa3a2 --- /dev/null +++ b/tools/cert_create/include/tbbr/tbb_cert.h @@ -0,0 +1,30 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef TBB_CERT_H +#define TBB_CERT_H + +#include "cert.h" + +/* + * Enumerate the certificates that are used to establish the chain of trust + */ +enum { + TRUSTED_BOOT_FW_CERT, + TRUSTED_KEY_CERT, + SCP_FW_KEY_CERT, + SCP_FW_CONTENT_CERT, + SOC_FW_KEY_CERT, + SOC_FW_CONTENT_CERT, + TRUSTED_OS_FW_KEY_CERT, + TRUSTED_OS_FW_CONTENT_CERT, + NON_TRUSTED_FW_KEY_CERT, + NON_TRUSTED_FW_CONTENT_CERT, + SIP_SECURE_PARTITION_CONTENT_CERT, + FWU_CERT +}; + +#endif /* TBB_CERT_H */ diff --git a/tools/cert_create/include/tbbr/tbb_ext.h b/tools/cert_create/include/tbbr/tbb_ext.h new file mode 100644 index 0000000..692b2d4 --- /dev/null +++ b/tools/cert_create/include/tbbr/tbb_ext.h @@ -0,0 +1,47 @@ +/* + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ +#ifndef TBB_EXT_H +#define TBB_EXT_H + +#include "ext.h" + +/* TBBR extensions */ +enum { + TRUSTED_FW_NVCOUNTER_EXT, + NON_TRUSTED_FW_NVCOUNTER_EXT, + TRUSTED_BOOT_FW_HASH_EXT, + TRUSTED_BOOT_FW_CONFIG_HASH_EXT, + HW_CONFIG_HASH_EXT, + FW_CONFIG_HASH_EXT, + TRUSTED_WORLD_PK_EXT, + NON_TRUSTED_WORLD_PK_EXT, + SCP_FW_CONTENT_CERT_PK_EXT, + SCP_FW_HASH_EXT, + SOC_FW_CONTENT_CERT_PK_EXT, + SOC_AP_FW_HASH_EXT, + SOC_FW_CONFIG_HASH_EXT, + TRUSTED_OS_FW_CONTENT_CERT_PK_EXT, + TRUSTED_OS_FW_HASH_EXT, + TRUSTED_OS_FW_EXTRA1_HASH_EXT, + TRUSTED_OS_FW_EXTRA2_HASH_EXT, + TRUSTED_OS_FW_CONFIG_HASH_EXT, + NON_TRUSTED_FW_CONTENT_CERT_PK_EXT, + NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT, + NON_TRUSTED_FW_CONFIG_HASH_EXT, + SP_PKG1_HASH_EXT, + SP_PKG2_HASH_EXT, + SP_PKG3_HASH_EXT, + SP_PKG4_HASH_EXT, + SP_PKG5_HASH_EXT, + SP_PKG6_HASH_EXT, + SP_PKG7_HASH_EXT, + SP_PKG8_HASH_EXT, + SCP_FWU_CFG_HASH_EXT, + AP_FWU_CFG_HASH_EXT, + FWU_HASH_EXT +}; + +#endif /* TBB_EXT_H */ diff --git a/tools/cert_create/include/tbbr/tbb_key.h b/tools/cert_create/include/tbbr/tbb_key.h new file mode 100644 index 0000000..47ad1de --- /dev/null +++ b/tools/cert_create/include/tbbr/tbb_key.h @@ -0,0 +1,25 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef TBB_KEY_H +#define TBB_KEY_H + +#include "key.h" + +/* + * Enumerate the keys that are used to establish the chain of trust + */ +enum { + ROT_KEY, + TRUSTED_WORLD_KEY, + NON_TRUSTED_WORLD_KEY, + SCP_FW_CONTENT_CERT_KEY, + SOC_FW_CONTENT_CERT_KEY, + TRUSTED_OS_FW_CONTENT_CERT_KEY, + NON_TRUSTED_FW_CONTENT_CERT_KEY +}; + +#endif /* TBB_KEY_H */ diff --git a/tools/cert_create/src/cca/cot.c b/tools/cert_create/src/cca/cot.c new file mode 100644 index 0000000..5a35ff6 --- /dev/null +++ b/tools/cert_create/src/cca/cot.c @@ -0,0 +1,439 @@ +/* + * Copyright (c) 2022, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "cca/cca_cot.h" + +#include <cca_oid.h> + +#include "cert.h" +#include "ext.h" +#include "key.h" + +/* + * Certificates used in the chain of trust. + * + * All certificates are self-signed so the issuer certificate field points to + * itself. + */ +static cert_t cot_certs[] = { + [CCA_CONTENT_CERT] = { + .id = CCA_CONTENT_CERT, + .opt = "cca-cert", + .help_msg = "CCA Content Certificate (output file)", + .cn = "CCA Content Certificate", + .key = ROT_KEY, + .issuer = CCA_CONTENT_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + SOC_AP_FW_HASH_EXT, + SOC_FW_CONFIG_HASH_EXT, + RMM_HASH_EXT, + TRUSTED_BOOT_FW_HASH_EXT, + TRUSTED_BOOT_FW_CONFIG_HASH_EXT, + HW_CONFIG_HASH_EXT, + FW_CONFIG_HASH_EXT, + }, + .num_ext = 8 + }, + + [CORE_SWD_KEY_CERT] = { + .id = CORE_SWD_KEY_CERT, + .opt = "core-swd-cert", + .help_msg = "Core Secure World Key Certificate (output file)", + .cn = "Core Secure World Key Certificate", + .key = SWD_ROT_KEY, + .issuer = CORE_SWD_KEY_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + SWD_ROT_PK_EXT, + CORE_SWD_PK_EXT, + }, + .num_ext = 3 + }, + + [SPMC_CONTENT_CERT] = { + .id = SPMC_CONTENT_CERT, + .opt = "tos-fw-cert", + .help_msg = "SPMC Content Certificate (output file)", + .cn = "SPMC Content Certificate", + .key = CORE_SWD_KEY, + .issuer = SPMC_CONTENT_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + TRUSTED_OS_FW_HASH_EXT, + TRUSTED_OS_FW_CONFIG_HASH_EXT, + }, + .num_ext = 3 + }, + + [SIP_SECURE_PARTITION_CONTENT_CERT] = { + .id = SIP_SECURE_PARTITION_CONTENT_CERT, + .opt = "sip-sp-cert", + .help_msg = "SiP owned Secure Partition Content Certificate (output file)", + .cn = "SiP owned Secure Partition Content Certificate", + .key = CORE_SWD_KEY, + .issuer = SIP_SECURE_PARTITION_CONTENT_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + SP_PKG1_HASH_EXT, + SP_PKG2_HASH_EXT, + SP_PKG3_HASH_EXT, + SP_PKG4_HASH_EXT, + }, + .num_ext = 5 + }, + + [PLAT_KEY_CERT] = { + .id = PLAT_KEY_CERT, + .opt = "plat-key-cert", + .help_msg = "Platform Key Certificate (output file)", + .cn = "Platform Key Certificate", + .key = PROT_KEY, + .issuer = PLAT_KEY_CERT, + .ext = { + NON_TRUSTED_FW_NVCOUNTER_EXT, + PROT_PK_EXT, + PLAT_PK_EXT, + }, + .num_ext = 3 + }, + + [PLAT_SECURE_PARTITION_CONTENT_CERT] = { + .id = PLAT_SECURE_PARTITION_CONTENT_CERT, + .opt = "plat-sp-cert", + .help_msg = "Platform owned Secure Partition Content Certificate (output file)", + .cn = "Platform owned Secure Partition Content Certificate", + .key = PLAT_KEY, + .issuer = PLAT_SECURE_PARTITION_CONTENT_CERT, + .ext = { + NON_TRUSTED_FW_NVCOUNTER_EXT, + SP_PKG5_HASH_EXT, + SP_PKG6_HASH_EXT, + SP_PKG7_HASH_EXT, + SP_PKG8_HASH_EXT, + }, + .num_ext = 5 + }, + + [NON_TRUSTED_FW_CONTENT_CERT] = { + .id = NON_TRUSTED_FW_CONTENT_CERT, + .opt = "nt-fw-cert", + .help_msg = "Non-Trusted Firmware Content Certificate (output file)", + .cn = "Non-Trusted Firmware Content Certificate", + .key = PLAT_KEY, + .issuer = NON_TRUSTED_FW_CONTENT_CERT, + .ext = { + NON_TRUSTED_FW_NVCOUNTER_EXT, + NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT, + NON_TRUSTED_FW_CONFIG_HASH_EXT, + }, + .num_ext = 3 + }, +}; + +REGISTER_COT(cot_certs); + + +/* Certificate extensions. */ +static ext_t cot_ext[] = { + [TRUSTED_FW_NVCOUNTER_EXT] = { + .oid = TRUSTED_FW_NVCOUNTER_OID, + .opt = "tfw-nvctr", + .help_msg = "Trusted Firmware Non-Volatile counter value", + .sn = "TrustedWorldNVCounter", + .ln = "Trusted World Non-Volatile counter", + .asn1_type = V_ASN1_INTEGER, + .type = EXT_TYPE_NVCOUNTER, + .attr.nvctr_type = NVCTR_TYPE_TFW + }, + + [TRUSTED_BOOT_FW_HASH_EXT] = { + .oid = TRUSTED_BOOT_FW_HASH_OID, + .opt = "tb-fw", + .help_msg = "Trusted Boot Firmware image file", + .sn = "TrustedBootFirmwareHash", + .ln = "Trusted Boot Firmware hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + + [TRUSTED_BOOT_FW_CONFIG_HASH_EXT] = { + .oid = TRUSTED_BOOT_FW_CONFIG_HASH_OID, + .opt = "tb-fw-config", + .help_msg = "Trusted Boot Firmware Config file", + .sn = "TrustedBootFirmwareConfigHash", + .ln = "Trusted Boot Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [HW_CONFIG_HASH_EXT] = { + .oid = HW_CONFIG_HASH_OID, + .opt = "hw-config", + .help_msg = "HW Config file", + .sn = "HWConfigHash", + .ln = "HW Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [FW_CONFIG_HASH_EXT] = { + .oid = FW_CONFIG_HASH_OID, + .opt = "fw-config", + .help_msg = "Firmware Config file", + .sn = "FirmwareConfigHash", + .ln = "Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [SWD_ROT_PK_EXT] = { + .oid = SWD_ROT_PK_OID, + .sn = "SWDRoTKey", + .ln = "Secure World Root of Trust Public Key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = SWD_ROT_KEY + }, + + [CORE_SWD_PK_EXT] = { + .oid = CORE_SWD_PK_OID, + .sn = "CORESWDKey", + .ln = "Core Secure World Public Key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = CORE_SWD_KEY + }, + + [SOC_AP_FW_HASH_EXT] = { + .oid = SOC_AP_FW_HASH_OID, + .opt = "soc-fw", + .help_msg = "SoC AP Firmware image file", + .sn = "SoCAPFirmwareHash", + .ln = "SoC AP Firmware hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + + [SOC_FW_CONFIG_HASH_EXT] = { + .oid = SOC_FW_CONFIG_HASH_OID, + .opt = "soc-fw-config", + .help_msg = "SoC Firmware Config file", + .sn = "SocFirmwareConfigHash", + .ln = "SoC Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [RMM_HASH_EXT] = { + .oid = RMM_HASH_OID, + .opt = "rmm-fw", + .help_msg = "RMM Firmware image file", + .sn = "RMMFirmwareHash", + .ln = "RMM Firmware hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + + [TRUSTED_OS_FW_HASH_EXT] = { + .oid = TRUSTED_OS_FW_HASH_OID, + .opt = "tos-fw", + .help_msg = "Trusted OS image file", + .sn = "TrustedOSHash", + .ln = "Trusted OS hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + + [TRUSTED_OS_FW_CONFIG_HASH_EXT] = { + .oid = TRUSTED_OS_FW_CONFIG_HASH_OID, + .opt = "tos-fw-config", + .help_msg = "Trusted OS Firmware Config file", + .sn = "TrustedOSFirmwareConfigHash", + .ln = "Trusted OS Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [SP_PKG1_HASH_EXT] = { + .oid = SP_PKG1_HASH_OID, + .opt = "sp-pkg1", + .help_msg = "Secure Partition Package1 file", + .sn = "SPPkg1Hash", + .ln = "SP Pkg1 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG2_HASH_EXT] = { + .oid = SP_PKG2_HASH_OID, + .opt = "sp-pkg2", + .help_msg = "Secure Partition Package2 file", + .sn = "SPPkg2Hash", + .ln = "SP Pkg2 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG3_HASH_EXT] = { + .oid = SP_PKG3_HASH_OID, + .opt = "sp-pkg3", + .help_msg = "Secure Partition Package3 file", + .sn = "SPPkg3Hash", + .ln = "SP Pkg3 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG4_HASH_EXT] = { + .oid = SP_PKG4_HASH_OID, + .opt = "sp-pkg4", + .help_msg = "Secure Partition Package4 file", + .sn = "SPPkg4Hash", + .ln = "SP Pkg4 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [PROT_PK_EXT] = { + .oid = PROT_PK_OID, + .sn = "PlatformRoTKey", + .ln = "Platform Root of Trust Public Key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = PROT_KEY + }, + + [PLAT_PK_EXT] = { + .oid = PLAT_PK_OID, + .sn = "PLATKey", + .ln = "Platform Public Key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = PLAT_KEY + }, + + [SP_PKG5_HASH_EXT] = { + .oid = SP_PKG5_HASH_OID, + .opt = "sp-pkg5", + .help_msg = "Secure Partition Package5 file", + .sn = "SPPkg5Hash", + .ln = "SP Pkg5 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG6_HASH_EXT] = { + .oid = SP_PKG6_HASH_OID, + .opt = "sp-pkg6", + .help_msg = "Secure Partition Package6 file", + .sn = "SPPkg6Hash", + .ln = "SP Pkg6 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG7_HASH_EXT] = { + .oid = SP_PKG7_HASH_OID, + .opt = "sp-pkg7", + .help_msg = "Secure Partition Package7 file", + .sn = "SPPkg7Hash", + .ln = "SP Pkg7 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG8_HASH_EXT] = { + .oid = SP_PKG8_HASH_OID, + .opt = "sp-pkg8", + .help_msg = "Secure Partition Package8 file", + .sn = "SPPkg8Hash", + .ln = "SP Pkg8 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [NON_TRUSTED_FW_NVCOUNTER_EXT] = { + .oid = NON_TRUSTED_FW_NVCOUNTER_OID, + .opt = "ntfw-nvctr", + .help_msg = "Non-Trusted Firmware Non-Volatile counter value", + .sn = "NormalWorldNVCounter", + .ln = "Non-Trusted Firmware Non-Volatile counter", + .asn1_type = V_ASN1_INTEGER, + .type = EXT_TYPE_NVCOUNTER, + .attr.nvctr_type = NVCTR_TYPE_NTFW + }, + + [NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT] = { + .oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID, + .opt = "nt-fw", + .help_msg = "Non-Trusted World Bootloader image file", + .sn = "NonTrustedWorldBootloaderHash", + .ln = "Non-Trusted World hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + + [NON_TRUSTED_FW_CONFIG_HASH_EXT] = { + .oid = NON_TRUSTED_FW_CONFIG_HASH_OID, + .opt = "nt-fw-config", + .help_msg = "Non Trusted OS Firmware Config file", + .sn = "NonTrustedOSFirmwareConfigHash", + .ln = "Non-Trusted OS Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, +}; + +REGISTER_EXTENSIONS(cot_ext); + +/* Keys used to establish the chain of trust. */ +static key_t cot_keys[] = { + [ROT_KEY] = { + .id = ROT_KEY, + .opt = "rot-key", + .help_msg = "Root Of Trust key (input/output file)", + .desc = "Root Of Trust key" + }, + + [SWD_ROT_KEY] = { + .id = SWD_ROT_KEY, + .opt = "swd-rot-key", + .help_msg = "Secure World Root of Trust key", + .desc = "Secure World Root of Trust key" + }, + + [CORE_SWD_KEY] = { + .id = CORE_SWD_KEY, + .opt = "core-swd-key", + .help_msg = "Core Secure World key", + .desc = "Core Secure World key" + }, + + [PROT_KEY] = { + .id = PROT_KEY, + .opt = "prot-key", + .help_msg = "Platform Root of Trust key", + .desc = "Platform Root of Trust key" + }, + + [PLAT_KEY] = { + .id = PLAT_KEY, + .opt = "plat-key", + .help_msg = "Platform key", + .desc = "Platform key" + }, +}; + +REGISTER_KEYS(cot_keys); diff --git a/tools/cert_create/src/cca/cot.mk b/tools/cert_create/src/cca/cot.mk new file mode 100644 index 0000000..d0c80bb --- /dev/null +++ b/tools/cert_create/src/cca/cot.mk @@ -0,0 +1,10 @@ +# +# Copyright (c) 2022, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +PLAT_MSG := Confidential Compute Architecture root of trust +PLAT_INCLUDE := ../../include/tools_share + +OBJECTS += src/cca/cot.o diff --git a/tools/cert_create/src/cert.c b/tools/cert_create/src/cert.c new file mode 100644 index 0000000..2513213 --- /dev/null +++ b/tools/cert_create/src/cert.c @@ -0,0 +1,294 @@ +/* + * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <openssl/conf.h> +#include <openssl/err.h> +#include <openssl/opensslv.h> +#include <openssl/pem.h> +#include <openssl/sha.h> +#include <openssl/x509v3.h> + +#include "cert.h" +#include "cmd_opt.h" +#include "debug.h" +#include "key.h" +#include "sha.h" + +#define SERIAL_RAND_BITS 64 +#define RSA_SALT_LEN 32 + +cert_t *certs; +unsigned int num_certs; + +int rand_serial(BIGNUM *b, ASN1_INTEGER *ai) +{ + BIGNUM *btmp; + int ret = 0; + if (b) + btmp = b; + else + btmp = BN_new(); + + if (!btmp) + return 0; + +#if USING_OPENSSL3 + if (!BN_rand(btmp, SERIAL_RAND_BITS, 0, 0)) +#else + if (!BN_pseudo_rand(btmp, SERIAL_RAND_BITS, 0, 0)) +#endif + goto error; + if (ai && !BN_to_ASN1_INTEGER(btmp, ai)) + goto error; + + ret = 1; + +error: + + if (!b) + BN_free(btmp); + + return ret; +} +const EVP_MD *get_digest(int alg) +{ + switch (alg) { + case HASH_ALG_SHA256: + return EVP_sha256(); + case HASH_ALG_SHA384: + return EVP_sha384(); + case HASH_ALG_SHA512: + return EVP_sha512(); + default: + return NULL; + } +} + +int cert_add_ext(X509 *issuer, X509 *subject, int nid, char *value) +{ + X509_EXTENSION *ex; + X509V3_CTX ctx; + + /* No configuration database */ + X509V3_set_ctx_nodb(&ctx); + + /* Set issuer and subject certificates in the context */ + X509V3_set_ctx(&ctx, issuer, subject, NULL, NULL, 0); + ex = X509V3_EXT_conf_nid(NULL, &ctx, nid, value); + if (!ex) { + ERR_print_errors_fp(stdout); + return 0; + } + + X509_add_ext(subject, ex, -1); + X509_EXTENSION_free(ex); + + return 1; +} + +int cert_new( + int md_alg, + cert_t *cert, + int days, + int ca, + STACK_OF(X509_EXTENSION) * sk) +{ + EVP_PKEY *pkey = keys[cert->key].key; + cert_t *issuer_cert = &certs[cert->issuer]; + EVP_PKEY *ikey = keys[issuer_cert->key].key; + X509 *issuer = issuer_cert->x; + X509 *x; + X509_EXTENSION *ex; + X509_NAME *name; + ASN1_INTEGER *sno; + int i, num, rc = 0; + EVP_MD_CTX *mdCtx; + EVP_PKEY_CTX *pKeyCtx = NULL; + + /* Create the certificate structure */ + x = X509_new(); + if (!x) { + return 0; + } + + /* If we do not have a key, use the issuer key (the certificate will + * become self signed). This happens in content certificates. */ + if (!pkey) { + pkey = ikey; + } + + /* If we do not have an issuer certificate, use our own (the certificate + * will become self signed) */ + if (!issuer) { + issuer = x; + } + + mdCtx = EVP_MD_CTX_create(); + if (mdCtx == NULL) { + ERR_print_errors_fp(stdout); + goto END; + } + + /* Sign the certificate with the issuer key */ + if (!EVP_DigestSignInit(mdCtx, &pKeyCtx, get_digest(md_alg), NULL, ikey)) { + ERR_print_errors_fp(stdout); + goto END; + } + + /* + * Set additional parameters if issuing public key algorithm is RSA. + * This is not required for ECDSA. + */ + if (EVP_PKEY_base_id(ikey) == EVP_PKEY_RSA) { + if (!EVP_PKEY_CTX_set_rsa_padding(pKeyCtx, RSA_PKCS1_PSS_PADDING)) { + ERR_print_errors_fp(stdout); + goto END; + } + + if (!EVP_PKEY_CTX_set_rsa_pss_saltlen(pKeyCtx, RSA_SALT_LEN)) { + ERR_print_errors_fp(stdout); + goto END; + } + + if (!EVP_PKEY_CTX_set_rsa_mgf1_md(pKeyCtx, get_digest(md_alg))) { + ERR_print_errors_fp(stdout); + goto END; + } + } + + /* x509.v3 */ + X509_set_version(x, 2); + + /* Random serial number */ + sno = ASN1_INTEGER_new(); + rand_serial(NULL, sno); + X509_set_serialNumber(x, sno); + ASN1_INTEGER_free(sno); + + X509_gmtime_adj(X509_get_notBefore(x), 0); + X509_gmtime_adj(X509_get_notAfter(x), (long)60*60*24*days); + X509_set_pubkey(x, pkey); + + /* Subject name */ + name = X509_get_subject_name(x); + X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, + (const unsigned char *)cert->cn, -1, -1, 0); + X509_set_subject_name(x, name); + + /* Issuer name */ + name = X509_get_issuer_name(x); + X509_NAME_add_entry_by_txt(name, "CN", MBSTRING_ASC, + (const unsigned char *)issuer_cert->cn, -1, -1, 0); + X509_set_issuer_name(x, name); + + /* Add various extensions: standard extensions */ + cert_add_ext(issuer, x, NID_subject_key_identifier, "hash"); + cert_add_ext(issuer, x, NID_authority_key_identifier, "keyid:always"); + if (ca) { + cert_add_ext(issuer, x, NID_basic_constraints, "CA:TRUE"); + cert_add_ext(issuer, x, NID_key_usage, "keyCertSign"); + } else { + cert_add_ext(issuer, x, NID_basic_constraints, "CA:FALSE"); + } + + /* Add custom extensions */ + if (sk != NULL) { + num = sk_X509_EXTENSION_num(sk); + for (i = 0; i < num; i++) { + ex = sk_X509_EXTENSION_value(sk, i); + X509_add_ext(x, ex, -1); + } + } + + if (!X509_sign_ctx(x, mdCtx)) { + ERR_print_errors_fp(stdout); + goto END; + } + + /* X509 certificate signed successfully */ + rc = 1; + cert->x = x; + +END: + EVP_MD_CTX_destroy(mdCtx); + return rc; +} + +int cert_init(void) +{ + cmd_opt_t cmd_opt; + cert_t *cert; + unsigned int i; + + certs = malloc((num_def_certs * sizeof(def_certs[0])) +#ifdef PDEF_CERTS + + (num_pdef_certs * sizeof(pdef_certs[0])) +#endif + ); + if (certs == NULL) { + ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__); + return 1; + } + + memcpy(&certs[0], &def_certs[0], + (num_def_certs * sizeof(def_certs[0]))); + +#ifdef PDEF_CERTS + memcpy(&certs[num_def_certs], &pdef_certs[0], + (num_pdef_certs * sizeof(pdef_certs[0]))); + + num_certs = num_def_certs + num_pdef_certs; +#else + num_certs = num_def_certs; +#endif + + for (i = 0; i < num_certs; i++) { + cert = &certs[i]; + cmd_opt.long_opt.name = cert->opt; + cmd_opt.long_opt.has_arg = required_argument; + cmd_opt.long_opt.flag = NULL; + cmd_opt.long_opt.val = CMD_OPT_CERT; + cmd_opt.help_msg = cert->help_msg; + cmd_opt_add(&cmd_opt); + } + + return 0; +} + +cert_t *cert_get_by_opt(const char *opt) +{ + cert_t *cert; + unsigned int i; + + for (i = 0; i < num_certs; i++) { + cert = &certs[i]; + if (0 == strcmp(cert->opt, opt)) { + return cert; + } + } + + return NULL; +} + +void cert_cleanup(void) +{ + unsigned int i; + + for (i = 0; i < num_certs; i++) { + if (certs[i].fn != NULL) { + void *ptr = (void *)certs[i].fn; + + certs[i].fn = NULL; + free(ptr); + } + } + free(certs); +} + diff --git a/tools/cert_create/src/cmd_opt.c b/tools/cert_create/src/cmd_opt.c new file mode 100644 index 0000000..64180d1 --- /dev/null +++ b/tools/cert_create/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/cert_create/src/dualroot/cot.c b/tools/cert_create/src/dualroot/cot.c new file mode 100644 index 0000000..4dd4cf0 --- /dev/null +++ b/tools/cert_create/src/dualroot/cot.c @@ -0,0 +1,583 @@ +/* + * Copyright (c) 2020, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <dualroot_oid.h> + +#include "cert.h" +#include "ext.h" +#include "key.h" + +#include "dualroot/cot.h" + +/* + * Certificates used in the chain of trust. + * + * All certificates are self-signed so the issuer certificate field points to + * itself. + */ +static cert_t cot_certs[] = { + [TRUSTED_BOOT_FW_CERT] = { + .id = TRUSTED_BOOT_FW_CERT, + .opt = "tb-fw-cert", + .help_msg = "Trusted Boot FW Certificate (output file)", + .cn = "Trusted Boot FW Certificate", + .key = ROT_KEY, + .issuer = TRUSTED_BOOT_FW_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + TRUSTED_BOOT_FW_HASH_EXT, + TRUSTED_BOOT_FW_CONFIG_HASH_EXT, + HW_CONFIG_HASH_EXT, + FW_CONFIG_HASH_EXT + }, + .num_ext = 5 + }, + + [TRUSTED_KEY_CERT] = { + .id = TRUSTED_KEY_CERT, + .opt = "trusted-key-cert", + .help_msg = "Trusted Key Certificate (output file)", + .cn = "Trusted Key Certificate", + .key = ROT_KEY, + .issuer = TRUSTED_KEY_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + TRUSTED_WORLD_PK_EXT, + }, + .num_ext = 2 + }, + + [SCP_FW_KEY_CERT] = { + .id = SCP_FW_KEY_CERT, + .opt = "scp-fw-key-cert", + .help_msg = "SCP Firmware Key Certificate (output file)", + .cn = "SCP Firmware Key Certificate", + .key = TRUSTED_WORLD_KEY, + .issuer = SCP_FW_KEY_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + SCP_FW_CONTENT_CERT_PK_EXT + }, + .num_ext = 2 + }, + + [SCP_FW_CONTENT_CERT] = { + .id = SCP_FW_CONTENT_CERT, + .opt = "scp-fw-cert", + .help_msg = "SCP Firmware Content Certificate (output file)", + .cn = "SCP Firmware Content Certificate", + .key = SCP_FW_CONTENT_CERT_KEY, + .issuer = SCP_FW_CONTENT_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + SCP_FW_HASH_EXT + }, + .num_ext = 2 + }, + + [SOC_FW_KEY_CERT] = { + .id = SOC_FW_KEY_CERT, + .opt = "soc-fw-key-cert", + .help_msg = "SoC Firmware Key Certificate (output file)", + .cn = "SoC Firmware Key Certificate", + .key = TRUSTED_WORLD_KEY, + .issuer = SOC_FW_KEY_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + SOC_FW_CONTENT_CERT_PK_EXT + }, + .num_ext = 2 + }, + + [SOC_FW_CONTENT_CERT] = { + .id = SOC_FW_CONTENT_CERT, + .opt = "soc-fw-cert", + .help_msg = "SoC Firmware Content Certificate (output file)", + .cn = "SoC Firmware Content Certificate", + .key = SOC_FW_CONTENT_CERT_KEY, + .issuer = SOC_FW_CONTENT_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + SOC_AP_FW_HASH_EXT, + SOC_FW_CONFIG_HASH_EXT, + }, + .num_ext = 3 + }, + + [TRUSTED_OS_FW_KEY_CERT] = { + .id = TRUSTED_OS_FW_KEY_CERT, + .opt = "tos-fw-key-cert", + .help_msg = "Trusted OS Firmware Key Certificate (output file)", + .cn = "Trusted OS Firmware Key Certificate", + .key = TRUSTED_WORLD_KEY, + .issuer = TRUSTED_OS_FW_KEY_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + TRUSTED_OS_FW_CONTENT_CERT_PK_EXT + }, + .num_ext = 2 + }, + + [TRUSTED_OS_FW_CONTENT_CERT] = { + .id = TRUSTED_OS_FW_CONTENT_CERT, + .opt = "tos-fw-cert", + .help_msg = "Trusted OS Firmware Content Certificate (output file)", + .cn = "Trusted OS Firmware Content Certificate", + .key = TRUSTED_OS_FW_CONTENT_CERT_KEY, + .issuer = TRUSTED_OS_FW_CONTENT_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + TRUSTED_OS_FW_HASH_EXT, + TRUSTED_OS_FW_EXTRA1_HASH_EXT, + TRUSTED_OS_FW_EXTRA2_HASH_EXT, + TRUSTED_OS_FW_CONFIG_HASH_EXT, + }, + .num_ext = 5 + }, + + [SIP_SECURE_PARTITION_CONTENT_CERT] = { + .id = SIP_SECURE_PARTITION_CONTENT_CERT, + .opt = "sip-sp-cert", + .help_msg = "SiP owned Secure Partition Content Certificate (output file)", + .fn = NULL, + .cn = "SiP owned Secure Partition Content Certificate", + .key = TRUSTED_WORLD_KEY, + .issuer = SIP_SECURE_PARTITION_CONTENT_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + SP_PKG1_HASH_EXT, + SP_PKG2_HASH_EXT, + SP_PKG3_HASH_EXT, + SP_PKG4_HASH_EXT, + }, + .num_ext = 5 + }, + + [PLAT_SECURE_PARTITION_CONTENT_CERT] = { + .id = PLAT_SECURE_PARTITION_CONTENT_CERT, + .opt = "plat-sp-cert", + .help_msg = "Platform owned Secure Partition Content Certificate (output file)", + .fn = NULL, + .cn = "Platform owned Secure Partition Content Certificate", + .key = PROT_KEY, + .issuer = PLAT_SECURE_PARTITION_CONTENT_CERT, + .ext = { + NON_TRUSTED_FW_NVCOUNTER_EXT, + SP_PKG5_HASH_EXT, + SP_PKG6_HASH_EXT, + SP_PKG7_HASH_EXT, + SP_PKG8_HASH_EXT, + PROT_PK_EXT, + }, + .num_ext = 6 + }, + + [FWU_CERT] = { + .id = FWU_CERT, + .opt = "fwu-cert", + .help_msg = "Firmware Update Certificate (output file)", + .cn = "Firmware Update Certificate", + .key = ROT_KEY, + .issuer = FWU_CERT, + .ext = { + SCP_FWU_CFG_HASH_EXT, + AP_FWU_CFG_HASH_EXT, + FWU_HASH_EXT + }, + .num_ext = 3 + }, + + [NON_TRUSTED_FW_CONTENT_CERT] = { + .id = NON_TRUSTED_FW_CONTENT_CERT, + .opt = "nt-fw-cert", + .help_msg = "Non-Trusted Firmware Content Certificate (output file)", + .cn = "Non-Trusted Firmware Content Certificate", + .key = PROT_KEY, + .issuer = NON_TRUSTED_FW_CONTENT_CERT, + .ext = { + NON_TRUSTED_FW_NVCOUNTER_EXT, + NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT, + NON_TRUSTED_FW_CONFIG_HASH_EXT, + PROT_PK_EXT, + }, + .num_ext = 4 + }, +}; + +REGISTER_COT(cot_certs); + + +/* Certificate extensions. */ +static ext_t cot_ext[] = { + [TRUSTED_FW_NVCOUNTER_EXT] = { + .oid = TRUSTED_FW_NVCOUNTER_OID, + .opt = "tfw-nvctr", + .help_msg = "Trusted Firmware Non-Volatile counter value", + .sn = "TrustedWorldNVCounter", + .ln = "Trusted World Non-Volatile counter", + .asn1_type = V_ASN1_INTEGER, + .type = EXT_TYPE_NVCOUNTER, + .attr.nvctr_type = NVCTR_TYPE_TFW + }, + + [TRUSTED_BOOT_FW_HASH_EXT] = { + .oid = TRUSTED_BOOT_FW_HASH_OID, + .opt = "tb-fw", + .help_msg = "Trusted Boot Firmware image file", + .sn = "TrustedBootFirmwareHash", + .ln = "Trusted Boot Firmware hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + + [TRUSTED_BOOT_FW_CONFIG_HASH_EXT] = { + .oid = TRUSTED_BOOT_FW_CONFIG_HASH_OID, + .opt = "tb-fw-config", + .help_msg = "Trusted Boot Firmware Config file", + .sn = "TrustedBootFirmwareConfigHash", + .ln = "Trusted Boot Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [HW_CONFIG_HASH_EXT] = { + .oid = HW_CONFIG_HASH_OID, + .opt = "hw-config", + .help_msg = "HW Config file", + .sn = "HWConfigHash", + .ln = "HW Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [FW_CONFIG_HASH_EXT] = { + .oid = FW_CONFIG_HASH_OID, + .opt = "fw-config", + .help_msg = "Firmware Config file", + .sn = "FirmwareConfigHash", + .ln = "Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [TRUSTED_WORLD_PK_EXT] = { + .oid = TRUSTED_WORLD_PK_OID, + .sn = "TrustedWorldPublicKey", + .ln = "Trusted World Public Key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = TRUSTED_WORLD_KEY + }, + + [SCP_FW_CONTENT_CERT_PK_EXT] = { + .oid = SCP_FW_CONTENT_CERT_PK_OID, + .sn = "SCPFirmwareContentCertPK", + .ln = "SCP Firmware content certificate public key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = SCP_FW_CONTENT_CERT_KEY + }, + + [SCP_FW_HASH_EXT] = { + .oid = SCP_FW_HASH_OID, + .opt = "scp-fw", + .help_msg = "SCP Firmware image file", + .sn = "SCPFirmwareHash", + .ln = "SCP Firmware hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + + [SOC_FW_CONTENT_CERT_PK_EXT] = { + .oid = SOC_FW_CONTENT_CERT_PK_OID, + .sn = "SoCFirmwareContentCertPK", + .ln = "SoC Firmware content certificate public key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = SOC_FW_CONTENT_CERT_KEY + }, + + [SOC_AP_FW_HASH_EXT] = { + .oid = SOC_AP_FW_HASH_OID, + .opt = "soc-fw", + .help_msg = "SoC AP Firmware image file", + .sn = "SoCAPFirmwareHash", + .ln = "SoC AP Firmware hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + + [SOC_FW_CONFIG_HASH_EXT] = { + .oid = SOC_FW_CONFIG_HASH_OID, + .opt = "soc-fw-config", + .help_msg = "SoC Firmware Config file", + .sn = "SocFirmwareConfigHash", + .ln = "SoC Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [TRUSTED_OS_FW_CONTENT_CERT_PK_EXT] = { + .oid = TRUSTED_OS_FW_CONTENT_CERT_PK_OID, + .sn = "TrustedOSFirmwareContentCertPK", + .ln = "Trusted OS Firmware content certificate public key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = TRUSTED_OS_FW_CONTENT_CERT_KEY + }, + + [TRUSTED_OS_FW_HASH_EXT] = { + .oid = TRUSTED_OS_FW_HASH_OID, + .opt = "tos-fw", + .help_msg = "Trusted OS image file", + .sn = "TrustedOSHash", + .ln = "Trusted OS hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + + [TRUSTED_OS_FW_EXTRA1_HASH_EXT] = { + .oid = TRUSTED_OS_FW_EXTRA1_HASH_OID, + .opt = "tos-fw-extra1", + .help_msg = "Trusted OS Extra1 image file", + .sn = "TrustedOSExtra1Hash", + .ln = "Trusted OS Extra1 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [TRUSTED_OS_FW_EXTRA2_HASH_EXT] = { + .oid = TRUSTED_OS_FW_EXTRA2_HASH_OID, + .opt = "tos-fw-extra2", + .help_msg = "Trusted OS Extra2 image file", + .sn = "TrustedOSExtra2Hash", + .ln = "Trusted OS Extra2 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [TRUSTED_OS_FW_CONFIG_HASH_EXT] = { + .oid = TRUSTED_OS_FW_CONFIG_HASH_OID, + .opt = "tos-fw-config", + .help_msg = "Trusted OS Firmware Config file", + .sn = "TrustedOSFirmwareConfigHash", + .ln = "Trusted OS Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [SP_PKG1_HASH_EXT] = { + .oid = SP_PKG1_HASH_OID, + .opt = "sp-pkg1", + .help_msg = "Secure Partition Package1 file", + .sn = "SPPkg1Hash", + .ln = "SP Pkg1 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG2_HASH_EXT] = { + .oid = SP_PKG2_HASH_OID, + .opt = "sp-pkg2", + .help_msg = "Secure Partition Package2 file", + .sn = "SPPkg2Hash", + .ln = "SP Pkg2 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG3_HASH_EXT] = { + .oid = SP_PKG3_HASH_OID, + .opt = "sp-pkg3", + .help_msg = "Secure Partition Package3 file", + .sn = "SPPkg3Hash", + .ln = "SP Pkg3 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG4_HASH_EXT] = { + .oid = SP_PKG4_HASH_OID, + .opt = "sp-pkg4", + .help_msg = "Secure Partition Package4 file", + .sn = "SPPkg4Hash", + .ln = "SP Pkg4 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG5_HASH_EXT] = { + .oid = SP_PKG5_HASH_OID, + .opt = "sp-pkg5", + .help_msg = "Secure Partition Package5 file", + .sn = "SPPkg5Hash", + .ln = "SP Pkg5 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG6_HASH_EXT] = { + .oid = SP_PKG6_HASH_OID, + .opt = "sp-pkg6", + .help_msg = "Secure Partition Package6 file", + .sn = "SPPkg6Hash", + .ln = "SP Pkg6 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG7_HASH_EXT] = { + .oid = SP_PKG7_HASH_OID, + .opt = "sp-pkg7", + .help_msg = "Secure Partition Package7 file", + .sn = "SPPkg7Hash", + .ln = "SP Pkg7 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG8_HASH_EXT] = { + .oid = SP_PKG8_HASH_OID, + .opt = "sp-pkg8", + .help_msg = "Secure Partition Package8 file", + .sn = "SPPkg8Hash", + .ln = "SP Pkg8 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [SCP_FWU_CFG_HASH_EXT] = { + .oid = SCP_FWU_CFG_HASH_OID, + .opt = "scp-fwu-cfg", + .help_msg = "SCP Firmware Update Config image file", + .sn = "SCPFWUpdateConfig", + .ln = "SCP Firmware Update Config hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [AP_FWU_CFG_HASH_EXT] = { + .oid = AP_FWU_CFG_HASH_OID, + .opt = "ap-fwu-cfg", + .help_msg = "AP Firmware Update Config image file", + .sn = "APFWUpdateConfig", + .ln = "AP Firmware Update Config hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [FWU_HASH_EXT] = { + .oid = FWU_HASH_OID, + .opt = "fwu", + .help_msg = "Firmware Updater image file", + .sn = "FWUpdaterHash", + .ln = "Firmware Updater hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + + [PROT_PK_EXT] = { + .oid = PROT_PK_OID, + .sn = "PlatformRoTKey", + .ln = "Platform Root of Trust Public Key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = PROT_KEY + }, + + [NON_TRUSTED_FW_NVCOUNTER_EXT] = { + .oid = NON_TRUSTED_FW_NVCOUNTER_OID, + .opt = "ntfw-nvctr", + .help_msg = "Non-Trusted Firmware Non-Volatile counter value", + .sn = "NormalWorldNVCounter", + .ln = "Non-Trusted Firmware Non-Volatile counter", + .asn1_type = V_ASN1_INTEGER, + .type = EXT_TYPE_NVCOUNTER, + .attr.nvctr_type = NVCTR_TYPE_NTFW + }, + + [NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT] = { + .oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID, + .opt = "nt-fw", + .help_msg = "Non-Trusted World Bootloader image file", + .sn = "NonTrustedWorldBootloaderHash", + .ln = "Non-Trusted World hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + + [NON_TRUSTED_FW_CONFIG_HASH_EXT] = { + .oid = NON_TRUSTED_FW_CONFIG_HASH_OID, + .opt = "nt-fw-config", + .help_msg = "Non Trusted OS Firmware Config file", + .sn = "NonTrustedOSFirmwareConfigHash", + .ln = "Non-Trusted OS Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, +}; + +REGISTER_EXTENSIONS(cot_ext); + + +/* Keys used to establish the chain of trust. */ +static key_t cot_keys[] = { + [ROT_KEY] = { + .id = ROT_KEY, + .opt = "rot-key", + .help_msg = "Root Of Trust key (input/output file)", + .desc = "Root Of Trust key" + }, + + [TRUSTED_WORLD_KEY] = { + .id = TRUSTED_WORLD_KEY, + .opt = "trusted-world-key", + .help_msg = "Trusted World key (input/output file)", + .desc = "Trusted World key" + }, + + [SCP_FW_CONTENT_CERT_KEY] = { + .id = SCP_FW_CONTENT_CERT_KEY, + .opt = "scp-fw-key", + .help_msg = "SCP Firmware Content Certificate key (input/output file)", + .desc = "SCP Firmware Content Certificate key" + }, + + [SOC_FW_CONTENT_CERT_KEY] = { + .id = SOC_FW_CONTENT_CERT_KEY, + .opt = "soc-fw-key", + .help_msg = "SoC Firmware Content Certificate key (input/output file)", + .desc = "SoC Firmware Content Certificate key" + }, + + [TRUSTED_OS_FW_CONTENT_CERT_KEY] = { + .id = TRUSTED_OS_FW_CONTENT_CERT_KEY, + .opt = "tos-fw-key", + .help_msg = "Trusted OS Firmware Content Certificate key (input/output file)", + .desc = "Trusted OS Firmware Content Certificate key" + }, + + [PROT_KEY] = { + .id = PROT_KEY, + .opt = "prot-key", + .help_msg = "Platform Root of Trust key", + .desc = "Platform Root of Trust key" + }, +}; + +REGISTER_KEYS(cot_keys); diff --git a/tools/cert_create/src/dualroot/cot.mk b/tools/cert_create/src/dualroot/cot.mk new file mode 100644 index 0000000..a572484 --- /dev/null +++ b/tools/cert_create/src/dualroot/cot.mk @@ -0,0 +1,10 @@ +# +# Copyright (c) 2020, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +PLAT_MSG := Dual root of trust +PLAT_INCLUDE := ../../include/tools_share + +OBJECTS += src/dualroot/cot.o diff --git a/tools/cert_create/src/ext.c b/tools/cert_create/src/ext.c new file mode 100644 index 0000000..acf57a4 --- /dev/null +++ b/tools/cert_create/src/ext.c @@ -0,0 +1,334 @@ +/* + * Copyright (c) 2015-2022, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stddef.h> +#include <stdio.h> +#include <string.h> +#include <openssl/asn1.h> +#include <openssl/asn1t.h> +#include <openssl/err.h> +#include <openssl/x509v3.h> + +#include "cmd_opt.h" +#include "debug.h" +#include "ext.h" + +ext_t *extensions; +unsigned int num_extensions; + +DECLARE_ASN1_ITEM(ASN1_INTEGER) +DECLARE_ASN1_ITEM(X509_ALGOR) +DECLARE_ASN1_ITEM(ASN1_OCTET_STRING) + +typedef struct { + X509_ALGOR *hashAlgorithm; + ASN1_OCTET_STRING *dataHash; +} HASH; + +ASN1_SEQUENCE(HASH) = { + ASN1_SIMPLE(HASH, hashAlgorithm, X509_ALGOR), + ASN1_SIMPLE(HASH, dataHash, ASN1_OCTET_STRING), +} ASN1_SEQUENCE_END(HASH) + +DECLARE_ASN1_FUNCTIONS(HASH) +IMPLEMENT_ASN1_FUNCTIONS(HASH) + +/* + * This function adds the CoT extensions to the internal extension list + * maintained by OpenSSL so they can be used later. + * + * It also initializes the methods to print the contents of the extension. If an + * alias is specified in the CoT extension, we reuse the methods of the alias. + * Otherwise, only methods for V_ASN1_INTEGER and V_ASN1_OCTET_STRING are + * provided. Any other type will be printed as a raw ascii string. + * + * Return: 0 = success, Otherwise: error + */ +int ext_init(void) +{ + cmd_opt_t cmd_opt; + ext_t *ext; + X509V3_EXT_METHOD *m; + int nid, ret; + unsigned int i; + + extensions = malloc((num_def_extensions * sizeof(def_extensions[0])) +#ifdef PDEF_EXTS + + (num_pdef_extensions * sizeof(pdef_extensions[0])) +#endif + ); + if (extensions == NULL) { + ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__); + return 1; + } + + memcpy(&extensions[0], &def_extensions[0], + (num_def_extensions * sizeof(def_extensions[0]))); +#ifdef PDEF_EXTS + memcpy(&extensions[num_def_extensions], &pdef_extensions[0], + (num_pdef_extensions * sizeof(pdef_extensions[0]))); + num_extensions = num_def_extensions + num_pdef_extensions; +#else + num_extensions = num_def_extensions; +#endif + + for (i = 0; i < num_extensions; i++) { + ext = &extensions[i]; + /* Register command line option */ + if (ext->opt) { + cmd_opt.long_opt.name = ext->opt; + cmd_opt.long_opt.has_arg = required_argument; + cmd_opt.long_opt.flag = NULL; + cmd_opt.long_opt.val = CMD_OPT_EXT; + cmd_opt.help_msg = ext->help_msg; + cmd_opt_add(&cmd_opt); + } + /* Register the extension OID in OpenSSL */ + if (ext->oid == NULL) { + continue; + } + nid = OBJ_create(ext->oid, ext->sn, ext->ln); + if (ext->alias) { + X509V3_EXT_add_alias(nid, ext->alias); + } else { + m = &ext->method; + memset(m, 0x0, sizeof(X509V3_EXT_METHOD)); + switch (ext->asn1_type) { + case V_ASN1_INTEGER: + m->it = ASN1_ITEM_ref(ASN1_INTEGER); + m->i2s = (X509V3_EXT_I2S)i2s_ASN1_INTEGER; + m->s2i = (X509V3_EXT_S2I)s2i_ASN1_INTEGER; + break; + case V_ASN1_OCTET_STRING: + m->it = ASN1_ITEM_ref(ASN1_OCTET_STRING); + m->i2s = (X509V3_EXT_I2S)i2s_ASN1_OCTET_STRING; + m->s2i = (X509V3_EXT_S2I)s2i_ASN1_OCTET_STRING; + break; + default: + continue; + } + m->ext_nid = nid; + ret = X509V3_EXT_add(m); + if (!ret) { + ERR_print_errors_fp(stdout); + return 1; + } + } + } + return 0; +} + +/* + * Create a new extension + * + * Extension ::= SEQUENCE { + * id OBJECT IDENTIFIER, + * critical BOOLEAN DEFAULT FALSE, + * value OCTET STRING } + * + * Parameters: + * pex: OpenSSL extension pointer (output parameter) + * nid: extension identifier + * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) + * data: extension data. This data will be encapsulated in an Octet String + * + * Return: Extension address, NULL if error + */ +static +X509_EXTENSION *ext_new(int nid, int crit, unsigned char *data, int len) +{ + X509_EXTENSION *ex; + ASN1_OCTET_STRING *ext_data; + + /* Octet string containing the extension data */ + ext_data = ASN1_OCTET_STRING_new(); + ASN1_OCTET_STRING_set(ext_data, data, len); + + /* Create the extension */ + ex = X509_EXTENSION_create_by_NID(NULL, nid, crit, ext_data); + + /* The extension makes a copy of the data, so we can free this object */ + ASN1_OCTET_STRING_free(ext_data); + + return ex; +} + +/* + * Creates a x509v3 extension containing a hash + * + * DigestInfo ::= SEQUENCE { + * digestAlgorithm AlgorithmIdentifier, + * digest OCTET STRING + * } + * + * AlgorithmIdentifier ::= SEQUENCE { + * algorithm OBJECT IDENTIFIER, + * parameters ANY DEFINED BY algorithm OPTIONAL + * } + * + * Parameters: + * nid: extension identifier + * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) + * md: hash algorithm + * buf: pointer to the buffer that contains the hash + * len: size of the hash in bytes + * + * Return: Extension address, NULL if error + */ +X509_EXTENSION *ext_new_hash(int nid, int crit, const EVP_MD *md, + unsigned char *buf, size_t len) +{ + X509_EXTENSION *ex; + HASH *hash; + ASN1_OBJECT *algorithm; + unsigned char *p = NULL; + int sz; + + /* HASH structure containing algorithm + hash */ + hash = HASH_new(); + if (hash == NULL) { + return NULL; + } + + /* OBJECT_IDENTIFIER with hash algorithm */ + algorithm = OBJ_nid2obj(EVP_MD_type(md)); + if (algorithm == NULL) { + HASH_free(hash); + return NULL; + } + + /* Create X509_ALGOR */ + hash->hashAlgorithm->algorithm = algorithm; + hash->hashAlgorithm->parameter = ASN1_TYPE_new(); + ASN1_TYPE_set(hash->hashAlgorithm->parameter, V_ASN1_NULL, NULL); + + /* OCTET_STRING with the actual hash */ + ASN1_OCTET_STRING_set(hash->dataHash, buf, len); + + /* DER encoded HASH */ + sz = i2d_HASH(hash, &p); + if ((sz <= 0) || (p == NULL)) { + HASH_free(hash); + return NULL; + } + + /* Create the extension */ + ex = ext_new(nid, crit, p, sz); + + /* Clean up */ + OPENSSL_free(p); + HASH_free(hash); + + return ex; +} + +/* + * Creates a x509v3 extension containing a nvcounter encapsulated in an ASN1 + * Integer + * + * Parameters: + * pex: OpenSSL extension pointer (output parameter) + * nid: extension identifier + * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) + * value: nvcounter value + * + * Return: Extension address, NULL if error + */ +X509_EXTENSION *ext_new_nvcounter(int nid, int crit, int value) +{ + X509_EXTENSION *ex; + ASN1_INTEGER *counter; + unsigned char *p = NULL; + int sz; + + /* Encode counter */ + counter = ASN1_INTEGER_new(); + ASN1_INTEGER_set(counter, value); + sz = i2d_ASN1_INTEGER(counter, &p); + + /* Create the extension */ + ex = ext_new(nid, crit, p, sz); + + /* Free objects */ + OPENSSL_free(p); + ASN1_INTEGER_free(counter); + + return ex; +} + +/* + * Creates a x509v3 extension containing a public key in DER format: + * + * SubjectPublicKeyInfo ::= SEQUENCE { + * algorithm AlgorithmIdentifier, + * subjectPublicKey BIT STRING } + * + * Parameters: + * pex: OpenSSL extension pointer (output parameter) + * nid: extension identifier + * crit: extension critical (EXT_NON_CRIT, EXT_CRIT) + * k: key + * + * Return: Extension address, NULL if error + */ +X509_EXTENSION *ext_new_key(int nid, int crit, EVP_PKEY *k) +{ + X509_EXTENSION *ex; + unsigned char *p; + int sz; + + /* Encode key */ + BIO *mem = BIO_new(BIO_s_mem()); + if (i2d_PUBKEY_bio(mem, k) <= 0) { + ERR_print_errors_fp(stderr); + return NULL; + } + p = (unsigned char *)OPENSSL_malloc(4096); + sz = BIO_read(mem, p, 4096); + + /* Create the extension */ + ex = ext_new(nid, crit, p, sz); + + /* Clean up */ + BIO_free(mem); + OPENSSL_free(p); + + return ex; +} + +ext_t *ext_get_by_opt(const char *opt) +{ + ext_t *ext; + unsigned int i; + + /* Sequential search. This is not a performance concern since the number + * of extensions is bounded and the code runs on a host machine */ + for (i = 0; i < num_extensions; i++) { + ext = &extensions[i]; + if (ext->opt && !strcmp(ext->opt, opt)) { + return ext; + } + } + + return NULL; +} + +void ext_cleanup(void) +{ + unsigned int i; + + for (i = 0; i < num_extensions; i++) { + if (extensions[i].arg != NULL) { + void *ptr = (void *)extensions[i].arg; + + extensions[i].arg = NULL; + free(ptr); + } + } + free(extensions); + X509V3_EXT_cleanup(); +} + diff --git a/tools/cert_create/src/key.c b/tools/cert_create/src/key.c new file mode 100644 index 0000000..487777b --- /dev/null +++ b/tools/cert_create/src/key.c @@ -0,0 +1,318 @@ +/* + * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <getopt.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> + +#include <openssl/conf.h> +#include <openssl/evp.h> +#include <openssl/pem.h> + +#include "cert.h" +#include "cmd_opt.h" +#include "debug.h" +#include "key.h" +#include "sha.h" + +#define MAX_FILENAME_LEN 1024 + +key_t *keys; +unsigned int num_keys; + +#if !USING_OPENSSL3 +/* + * Create a new key container + */ +int key_new(key_t *key) +{ + /* Create key pair container */ + key->key = EVP_PKEY_new(); + if (key->key == NULL) { + return 0; + } + + return 1; +} +#endif + +static int key_create_rsa(key_t *key, int key_bits) +{ +#if USING_OPENSSL3 + EVP_PKEY *rsa = EVP_RSA_gen(key_bits); + if (rsa == NULL) { + printf("Cannot generate RSA key\n"); + return 0; + } + key->key = rsa; + return 1; +#else + BIGNUM *e; + RSA *rsa = NULL; + + e = BN_new(); + if (e == NULL) { + printf("Cannot create RSA exponent\n"); + return 0; + } + + if (!BN_set_word(e, RSA_F4)) { + printf("Cannot assign RSA exponent\n"); + goto err2; + } + + rsa = RSA_new(); + if (rsa == NULL) { + printf("Cannot create RSA key\n"); + goto err2; + } + + if (!RSA_generate_key_ex(rsa, key_bits, e, NULL)) { + printf("Cannot generate RSA key\n"); + goto err; + } + + if (!EVP_PKEY_assign_RSA(key->key, rsa)) { + printf("Cannot assign RSA key\n"); + goto err; + } + + BN_free(e); + return 1; + +err: + RSA_free(rsa); +err2: + BN_free(e); + return 0; +#endif +} + +#ifndef OPENSSL_NO_EC +#if USING_OPENSSL3 +static int key_create_ecdsa(key_t *key, int key_bits, const char *curve) +{ + EVP_PKEY *ec = EVP_EC_gen(curve); + if (ec == NULL) { + printf("Cannot generate EC key\n"); + return 0; + } + + key->key = ec; + return 1; +} + +static int key_create_ecdsa_nist(key_t *key, int key_bits) +{ + return key_create_ecdsa(key, key_bits, "prime256v1"); +} + +static int key_create_ecdsa_brainpool_r(key_t *key, int key_bits) +{ + return key_create_ecdsa(key, key_bits, "brainpoolP256r1"); +} + +static int key_create_ecdsa_brainpool_t(key_t *key, int key_bits) +{ + return key_create_ecdsa(key, key_bits, "brainpoolP256t1"); +} +#else +static int key_create_ecdsa(key_t *key, int key_bits, const int curve_id) +{ + EC_KEY *ec; + + ec = EC_KEY_new_by_curve_name(curve_id); + if (ec == NULL) { + printf("Cannot create EC key\n"); + return 0; + } + if (!EC_KEY_generate_key(ec)) { + printf("Cannot generate EC key\n"); + goto err; + } + EC_KEY_set_flags(ec, EC_PKEY_NO_PARAMETERS); + EC_KEY_set_asn1_flag(ec, OPENSSL_EC_NAMED_CURVE); + if (!EVP_PKEY_assign_EC_KEY(key->key, ec)) { + printf("Cannot assign EC key\n"); + goto err; + } + + return 1; + +err: + EC_KEY_free(ec); + return 0; +} + +static int key_create_ecdsa_nist(key_t *key, int key_bits) +{ + return key_create_ecdsa(key, key_bits, NID_X9_62_prime256v1); +} + +static int key_create_ecdsa_brainpool_r(key_t *key, int key_bits) +{ + return key_create_ecdsa(key, key_bits, NID_brainpoolP256r1); +} + +static int key_create_ecdsa_brainpool_t(key_t *key, int key_bits) +{ + return key_create_ecdsa(key, key_bits, NID_brainpoolP256t1); +} +#endif /* USING_OPENSSL3 */ +#endif /* OPENSSL_NO_EC */ + +typedef int (*key_create_fn_t)(key_t *key, int key_bits); +static const key_create_fn_t key_create_fn[KEY_ALG_MAX_NUM] = { + [KEY_ALG_RSA] = key_create_rsa, +#ifndef OPENSSL_NO_EC + [KEY_ALG_ECDSA_NIST] = key_create_ecdsa_nist, + [KEY_ALG_ECDSA_BRAINPOOL_R] = key_create_ecdsa_brainpool_r, + [KEY_ALG_ECDSA_BRAINPOOL_T] = key_create_ecdsa_brainpool_t, +#endif /* OPENSSL_NO_EC */ +}; + +int key_create(key_t *key, int type, int key_bits) +{ + if (type >= KEY_ALG_MAX_NUM) { + printf("Invalid key type\n"); + return 0; + } + + if (key_create_fn[type]) { + return key_create_fn[type](key, key_bits); + } + + return 0; +} + +int key_load(key_t *key, unsigned int *err_code) +{ + FILE *fp; + EVP_PKEY *k; + + if (key->fn) { + /* Load key from file */ + fp = fopen(key->fn, "r"); + if (fp) { + k = PEM_read_PrivateKey(fp, &key->key, NULL, NULL); + fclose(fp); + if (k) { + *err_code = KEY_ERR_NONE; + return 1; + } else { + ERROR("Cannot load key from %s\n", key->fn); + *err_code = KEY_ERR_LOAD; + } + } else { + WARN("Cannot open file %s\n", key->fn); + *err_code = KEY_ERR_OPEN; + } + } else { + WARN("Key filename not specified\n"); + *err_code = KEY_ERR_FILENAME; + } + + return 0; +} + +int key_store(key_t *key) +{ + FILE *fp; + + if (key->fn) { + fp = fopen(key->fn, "w"); + if (fp) { + PEM_write_PrivateKey(fp, key->key, + NULL, NULL, 0, NULL, NULL); + fclose(fp); + return 1; + } else { + ERROR("Cannot create file %s\n", key->fn); + } + } else { + ERROR("Key filename not specified\n"); + } + + return 0; +} + +int key_init(void) +{ + cmd_opt_t cmd_opt; + key_t *key; + unsigned int i; + + keys = malloc((num_def_keys * sizeof(def_keys[0])) +#ifdef PDEF_KEYS + + (num_pdef_keys * sizeof(pdef_keys[0])) +#endif + ); + + if (keys == NULL) { + ERROR("%s:%d Failed to allocate memory.\n", __func__, __LINE__); + return 1; + } + + memcpy(&keys[0], &def_keys[0], (num_def_keys * sizeof(def_keys[0]))); +#ifdef PDEF_KEYS + memcpy(&keys[num_def_keys], &pdef_keys[0], + (num_pdef_keys * sizeof(pdef_keys[0]))); + + num_keys = num_def_keys + num_pdef_keys; +#else + num_keys = num_def_keys; +#endif + ; + + for (i = 0; i < num_keys; i++) { + key = &keys[i]; + if (key->opt != NULL) { + cmd_opt.long_opt.name = key->opt; + cmd_opt.long_opt.has_arg = required_argument; + cmd_opt.long_opt.flag = NULL; + cmd_opt.long_opt.val = CMD_OPT_KEY; + cmd_opt.help_msg = key->help_msg; + cmd_opt_add(&cmd_opt); + } + } + + return 0; +} + +key_t *key_get_by_opt(const char *opt) +{ + key_t *key; + unsigned int i; + + /* Sequential search. This is not a performance concern since the number + * of keys is bounded and the code runs on a host machine */ + for (i = 0; i < num_keys; i++) { + key = &keys[i]; + if (0 == strcmp(key->opt, opt)) { + return key; + } + } + + return NULL; +} + +void key_cleanup(void) +{ + unsigned int i; + + for (i = 0; i < num_keys; i++) { + EVP_PKEY_free(keys[i].key); + if (keys[i].fn != NULL) { + void *ptr = keys[i].fn; + + free(ptr); + keys[i].fn = NULL; + } + } + free(keys); +} + diff --git a/tools/cert_create/src/main.c b/tools/cert_create/src/main.c new file mode 100644 index 0000000..2ab6bcf --- /dev/null +++ b/tools/cert_create/src/main.c @@ -0,0 +1,617 @@ +/* + * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved. + * + * 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 <openssl/engine.h> +#include <openssl/err.h> +#include <openssl/pem.h> +#include <openssl/sha.h> +#include <openssl/x509v3.h> + +#include "cert.h" +#include "cmd_opt.h" +#include "debug.h" +#include "ext.h" +#include "key.h" +#include "sha.h" + +/* + * Helper macros to simplify the code. This macro assigns the return value of + * the 'fn' function to 'v' and exits if the value is NULL. + */ +#define CHECK_NULL(v, fn) \ + do { \ + v = fn; \ + if (v == NULL) { \ + ERROR("NULL object at %s:%d\n", __FILE__, __LINE__); \ + exit(1); \ + } \ + } while (0) + +/* + * This macro assigns the NID corresponding to 'oid' to 'v' and exits if the + * NID is undefined. + */ +#define CHECK_OID(v, oid) \ + do { \ + v = OBJ_txt2nid(oid); \ + if (v == NID_undef) { \ + ERROR("Cannot find extension %s\n", oid); \ + exit(1); \ + } \ + } while (0) + +#define MAX_FILENAME_LEN 1024 +#define VAL_DAYS 7300 +#define ID_TO_BIT_MASK(id) (1 << id) +#define NUM_ELEM(x) ((sizeof(x)) / (sizeof(x[0]))) +#define HELP_OPT_MAX_LEN 128 + +/* Global options */ +static int key_alg; +static int hash_alg; +static int key_size; +static int new_keys; +static int save_keys; +static int print_cert; + +/* Info messages created in the Makefile */ +extern const char build_msg[]; +extern const char platform_msg[]; + + +static char *strdup(const char *str) +{ + int n = strlen(str) + 1; + char *dup = malloc(n); + if (dup) { + strcpy(dup, str); + } + return dup; +} + +static const char *key_algs_str[] = { + [KEY_ALG_RSA] = "rsa", +#ifndef OPENSSL_NO_EC + [KEY_ALG_ECDSA_NIST] = "ecdsa", + [KEY_ALG_ECDSA_BRAINPOOL_R] = "ecdsa-brainpool-regular", + [KEY_ALG_ECDSA_BRAINPOOL_T] = "ecdsa-brainpool-twisted", +#endif /* OPENSSL_NO_EC */ +}; + +static const char *hash_algs_str[] = { + [HASH_ALG_SHA256] = "sha256", + [HASH_ALG_SHA384] = "sha384", + [HASH_ALG_SHA512] = "sha512", +}; + +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 certificate generation tool loads the binary images and\n" + "optionally the RSA or ECC keys, and outputs the key and content\n" + "certificates properly signed to implement the chain of trust.\n" + "If keys are provided, they must be in PEM format.\n" + "Certificates are generated in DER format.\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 (0 == strcmp(key_alg_str, key_algs_str[i])) { + return i; + } + } + + return -1; +} + +static int get_key_size(const char *key_size_str) +{ + char *end; + long key_size; + + key_size = strtol(key_size_str, &end, 10); + if (*end != '\0') + return -1; + + return key_size; +} + +static int get_hash_alg(const char *hash_alg_str) +{ + int i; + + for (i = 0 ; i < NUM_ELEM(hash_algs_str) ; i++) { + if (0 == strcmp(hash_alg_str, hash_algs_str[i])) { + return i; + } + } + + return -1; +} + +static void check_cmd_params(void) +{ + cert_t *cert; + ext_t *ext; + key_t *key; + int i, j; + bool valid_size; + + /* Only save new keys */ + if (save_keys && !new_keys) { + ERROR("Only new keys can be saved to disk\n"); + exit(1); + } + + /* Validate key-size */ + valid_size = false; + for (i = 0; i < KEY_SIZE_MAX_NUM; i++) { + if (key_size == KEY_SIZES[key_alg][i]) { + valid_size = true; + break; + } + } + if (!valid_size) { + ERROR("'%d' is not a valid key size for '%s'\n", + key_size, key_algs_str[key_alg]); + NOTICE("Valid sizes are: "); + for (i = 0; i < KEY_SIZE_MAX_NUM && + KEY_SIZES[key_alg][i] != 0; i++) { + printf("%d ", KEY_SIZES[key_alg][i]); + } + printf("\n"); + exit(1); + } + + /* Check that all required options have been specified in the + * command line */ + for (i = 0; i < num_certs; i++) { + cert = &certs[i]; + if (cert->fn == NULL) { + /* Certificate not requested. Skip to the next one */ + continue; + } + + /* Check that all parameters required to create this certificate + * have been specified in the command line */ + for (j = 0; j < cert->num_ext; j++) { + ext = &extensions[cert->ext[j]]; + switch (ext->type) { + case EXT_TYPE_NVCOUNTER: + /* Counter value must be specified */ + if ((!ext->optional) && (ext->arg == NULL)) { + ERROR("Value for '%s' not specified\n", + ext->ln); + exit(1); + } + break; + case EXT_TYPE_PKEY: + /* Key filename must be specified */ + key = &keys[ext->attr.key]; + if (!new_keys && key->fn == NULL) { + ERROR("Key '%s' required by '%s' not " + "specified\n", key->desc, + cert->cn); + exit(1); + } + break; + case EXT_TYPE_HASH: + /* + * Binary image must be specified + * unless it is explicitly made optional. + */ + if ((!ext->optional) && (ext->arg == NULL)) { + ERROR("Image for '%s' not specified\n", + ext->ln); + exit(1); + } + break; + default: + ERROR("Unknown extension type '%d' in '%s'\n", + ext->type, ext->ln); + exit(1); + break; + } + } + } +} + +/* Common command line options */ +static const cmd_opt_t common_cmd_opt[] = { + { + { "help", no_argument, NULL, 'h' }, + "Print this message and exit" + }, + { + { "key-alg", required_argument, NULL, 'a' }, + "Key algorithm: 'rsa' (default)- RSAPSS scheme as per PKCS#1 v2.1, " \ + "'ecdsa', 'ecdsa-brainpool-regular', 'ecdsa-brainpool-twisted'" + }, + { + { "key-size", required_argument, NULL, 'b' }, + "Key size (for supported algorithms)." + }, + { + { "hash-alg", required_argument, NULL, 's' }, + "Hash algorithm : 'sha256' (default), 'sha384', 'sha512'" + }, + { + { "save-keys", no_argument, NULL, 'k' }, + "Save key pairs into files. Filenames must be provided" + }, + { + { "new-keys", no_argument, NULL, 'n' }, + "Generate new key pairs if no key files are provided" + }, + { + { "print-cert", no_argument, NULL, 'p' }, + "Print the certificates in the standard output" + } +}; + +int main(int argc, char *argv[]) +{ + STACK_OF(X509_EXTENSION) * sk; + X509_EXTENSION *cert_ext = NULL; + ext_t *ext; + key_t *key; + cert_t *cert; + FILE *file; + int i, j, ext_nid, nvctr; + int c, opt_idx = 0; + const struct option *cmd_opt; + const char *cur_opt; + unsigned int err_code; + unsigned char md[SHA512_DIGEST_LENGTH]; + unsigned int md_len; + const EVP_MD *md_info; + + NOTICE("CoT Generation Tool: %s\n", build_msg); + NOTICE("Target platform: %s\n", platform_msg); + + /* Set default options */ + key_alg = KEY_ALG_RSA; + hash_alg = HASH_ALG_SHA256; + key_size = -1; + + /* Add common command line options */ + for (i = 0; i < NUM_ELEM(common_cmd_opt); i++) { + cmd_opt_add(&common_cmd_opt[i]); + } + + /* Initialize the certificates */ + if (cert_init() != 0) { + ERROR("Cannot initialize certificates\n"); + exit(1); + } + + /* Initialize the keys */ + if (key_init() != 0) { + ERROR("Cannot initialize keys\n"); + exit(1); + } + + /* Initialize the new types and register OIDs for the extensions */ + if (ext_init() != 0) { + ERROR("Cannot initialize extensions\n"); + exit(1); + } + + /* 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:b:hknps:", 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 'b': + key_size = get_key_size(optarg); + if (key_size <= 0) { + ERROR("Invalid key size '%s'\n", optarg); + exit(1); + } + break; + case 'h': + print_help(argv[0], cmd_opt); + exit(0); + case 'k': + save_keys = 1; + break; + case 'n': + new_keys = 1; + break; + case 'p': + print_cert = 1; + break; + case 's': + hash_alg = get_hash_alg(optarg); + if (hash_alg < 0) { + ERROR("Invalid hash algorithm '%s'\n", optarg); + exit(1); + } + break; + case CMD_OPT_EXT: + cur_opt = cmd_opt_get_name(opt_idx); + ext = ext_get_by_opt(cur_opt); + ext->arg = strdup(optarg); + break; + case CMD_OPT_KEY: + cur_opt = cmd_opt_get_name(opt_idx); + key = key_get_by_opt(cur_opt); + key->fn = strdup(optarg); + break; + case CMD_OPT_CERT: + cur_opt = cmd_opt_get_name(opt_idx); + cert = cert_get_by_opt(cur_opt); + cert->fn = strdup(optarg); + break; + case '?': + default: + print_help(argv[0], cmd_opt); + exit(1); + } + } + + /* Select a reasonable default key-size */ + if (key_size == -1) { + key_size = KEY_SIZES[key_alg][0]; + } + + /* Check command line arguments */ + check_cmd_params(); + + /* Indicate SHA as image hash algorithm in the certificate + * extension */ + if (hash_alg == HASH_ALG_SHA384) { + md_info = EVP_sha384(); + md_len = SHA384_DIGEST_LENGTH; + } else if (hash_alg == HASH_ALG_SHA512) { + md_info = EVP_sha512(); + md_len = SHA512_DIGEST_LENGTH; + } else { + md_info = EVP_sha256(); + md_len = SHA256_DIGEST_LENGTH; + } + + /* Load private keys from files (or generate new ones) */ + for (i = 0 ; i < num_keys ; i++) { +#if !USING_OPENSSL3 + if (!key_new(&keys[i])) { + ERROR("Failed to allocate key container\n"); + exit(1); + } +#endif + + /* First try to load the key from disk */ + if (key_load(&keys[i], &err_code)) { + /* Key loaded successfully */ + continue; + } + + /* Key not loaded. Check the error code */ + if (err_code == KEY_ERR_LOAD) { + /* File exists, but it does not contain a valid private + * key. Abort. */ + ERROR("Error loading '%s'\n", keys[i].fn); + exit(1); + } + + /* File does not exist, could not be opened or no filename was + * given */ + if (new_keys) { + /* Try to create a new key */ + NOTICE("Creating new key for '%s'\n", keys[i].desc); + if (!key_create(&keys[i], key_alg, key_size)) { + ERROR("Error creating key '%s'\n", keys[i].desc); + exit(1); + } + } else { + if (err_code == KEY_ERR_OPEN) { + ERROR("Error opening '%s'\n", keys[i].fn); + } else { + ERROR("Key '%s' not specified\n", keys[i].desc); + } + exit(1); + } + } + + /* Create the certificates */ + for (i = 0 ; i < num_certs ; i++) { + + cert = &certs[i]; + + if (cert->fn == NULL) { + /* Certificate not requested. Skip to the next one */ + continue; + } + + /* Create a new stack of extensions. This stack will be used + * to create the certificate */ + CHECK_NULL(sk, sk_X509_EXTENSION_new_null()); + + for (j = 0 ; j < cert->num_ext ; j++) { + + ext = &extensions[cert->ext[j]]; + + /* Get OpenSSL internal ID for this extension */ + CHECK_OID(ext_nid, ext->oid); + + /* + * Three types of extensions are currently supported: + * - EXT_TYPE_NVCOUNTER + * - EXT_TYPE_HASH + * - EXT_TYPE_PKEY + */ + switch (ext->type) { + case EXT_TYPE_NVCOUNTER: + if (ext->optional && ext->arg == NULL) { + /* Skip this NVCounter */ + continue; + } else { + /* Checked by `check_cmd_params` */ + assert(ext->arg != NULL); + nvctr = atoi(ext->arg); + CHECK_NULL(cert_ext, ext_new_nvcounter(ext_nid, + EXT_CRIT, nvctr)); + } + break; + case EXT_TYPE_HASH: + if (ext->arg == NULL) { + if (ext->optional) { + /* Include a hash filled with zeros */ + memset(md, 0x0, SHA512_DIGEST_LENGTH); + } else { + /* Do not include this hash in the certificate */ + continue; + } + } else { + /* Calculate the hash of the file */ + if (!sha_file(hash_alg, ext->arg, md)) { + ERROR("Cannot calculate hash of %s\n", + ext->arg); + exit(1); + } + } + CHECK_NULL(cert_ext, ext_new_hash(ext_nid, + EXT_CRIT, md_info, md, + md_len)); + break; + case EXT_TYPE_PKEY: + CHECK_NULL(cert_ext, ext_new_key(ext_nid, + EXT_CRIT, keys[ext->attr.key].key)); + break; + default: + ERROR("Unknown extension type '%d' in %s\n", + ext->type, cert->cn); + exit(1); + } + + /* Push the extension into the stack */ + sk_X509_EXTENSION_push(sk, cert_ext); + } + + /* Create certificate. Signed with corresponding key */ + if (!cert_new(hash_alg, cert, VAL_DAYS, 0, sk)) { + ERROR("Cannot create %s\n", cert->cn); + exit(1); + } + + for (cert_ext = sk_X509_EXTENSION_pop(sk); cert_ext != NULL; + cert_ext = sk_X509_EXTENSION_pop(sk)) { + X509_EXTENSION_free(cert_ext); + } + + sk_X509_EXTENSION_free(sk); + } + + + /* Print the certificates */ + if (print_cert) { + for (i = 0 ; i < num_certs ; i++) { + if (!certs[i].x) { + continue; + } + printf("\n\n=====================================\n\n"); + X509_print_fp(stdout, certs[i].x); + } + } + + /* Save created certificates to files */ + for (i = 0 ; i < num_certs ; i++) { + if (certs[i].x && certs[i].fn) { + file = fopen(certs[i].fn, "w"); + if (file != NULL) { + i2d_X509_fp(file, certs[i].x); + fclose(file); + } else { + ERROR("Cannot create file %s\n", certs[i].fn); + } + } + } + + /* Save keys */ + if (save_keys) { + for (i = 0 ; i < num_keys ; i++) { + if (!key_store(&keys[i])) { + ERROR("Cannot save %s\n", keys[i].desc); + } + } + } + + /* If we got here, then we must have filled the key array completely. + * We can then safely call free on all of the keys in the array + */ + key_cleanup(); + +#ifndef OPENSSL_NO_ENGINE + ENGINE_cleanup(); +#endif + CRYPTO_cleanup_all_ex_data(); + + + /* We allocated strings through strdup, so now we have to free them */ + + ext_cleanup(); + + cert_cleanup(); + + return 0; +} diff --git a/tools/cert_create/src/sha.c b/tools/cert_create/src/sha.c new file mode 100644 index 0000000..bb750d4 --- /dev/null +++ b/tools/cert_create/src/sha.c @@ -0,0 +1,118 @@ +/* + * Copyright (c) 2015-2022, Arm Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdio.h> +#include "debug.h" +#include "key.h" +#if USING_OPENSSL3 +#include <openssl/evp.h> +#include <openssl/obj_mac.h> +#else +#include <openssl/sha.h> +#endif + +#define BUFFER_SIZE 256 + +#if USING_OPENSSL3 +static int get_algorithm_nid(int hash_alg) +{ + int nids[] = {NID_sha256, NID_sha384, NID_sha512}; + if (hash_alg < 0 || hash_alg >= sizeof(nids) / sizeof(*nids)) { + return NID_undef; + } + return nids[hash_alg]; +} +#endif + +int sha_file(int md_alg, const char *filename, unsigned char *md) +{ + FILE *inFile; + int bytes; + unsigned char data[BUFFER_SIZE]; +#if USING_OPENSSL3 + EVP_MD_CTX *mdctx; + const EVP_MD *md_type; + int alg_nid; + unsigned int total_bytes; +#else + SHA256_CTX shaContext; + SHA512_CTX sha512Context; +#endif + + if ((filename == NULL) || (md == NULL)) { + ERROR("%s(): NULL argument\n", __func__); + return 0; + } + + inFile = fopen(filename, "rb"); + if (inFile == NULL) { + ERROR("Cannot read %s\n", filename); + return 0; + } + +#if USING_OPENSSL3 + + mdctx = EVP_MD_CTX_new(); + if (mdctx == NULL) { + fclose(inFile); + ERROR("%s(): Could not create EVP MD context\n", __func__); + return 0; + } + + alg_nid = get_algorithm_nid(md_alg); + if (alg_nid == NID_undef) { + ERROR("%s(): Invalid hash algorithm\n", __func__); + goto err; + } + + md_type = EVP_get_digestbynid(alg_nid); + if (EVP_DigestInit_ex(mdctx, md_type, NULL) == 0) { + ERROR("%s(): Could not initialize EVP MD digest\n", __func__); + goto err; + } + + while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) { + EVP_DigestUpdate(mdctx, data, bytes); + } + EVP_DigestFinal_ex(mdctx, md, &total_bytes); + + fclose(inFile); + EVP_MD_CTX_free(mdctx); + return 1; + +err: + fclose(inFile); + EVP_MD_CTX_free(mdctx); + return 0; + +#else + + if (md_alg == HASH_ALG_SHA384) { + SHA384_Init(&sha512Context); + while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) { + SHA384_Update(&sha512Context, data, bytes); + } + SHA384_Final(md, &sha512Context); + } else if (md_alg == HASH_ALG_SHA512) { + SHA512_Init(&sha512Context); + while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) { + SHA512_Update(&sha512Context, data, bytes); + } + SHA512_Final(md, &sha512Context); + } else { + SHA256_Init(&shaContext); + while ((bytes = fread(data, 1, BUFFER_SIZE, inFile)) != 0) { + SHA256_Update(&shaContext, data, bytes); + } + SHA256_Final(md, &shaContext); + } + + fclose(inFile); + return 1; + +#endif +} + diff --git a/tools/cert_create/src/tbbr/tbb_cert.c b/tools/cert_create/src/tbbr/tbb_cert.c new file mode 100644 index 0000000..f4fe63d --- /dev/null +++ b/tools/cert_create/src/tbbr/tbb_cert.c @@ -0,0 +1,206 @@ +/* + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "tbbr/tbb_cert.h" +#include "tbbr/tbb_ext.h" +#include "tbbr/tbb_key.h" + +/* + * Certificates used in the chain of trust + * + * The order of the certificates must follow the enumeration specified in + * tbb_cert.h. All certificates are self-signed, so the issuer certificate + * field points to itself. + */ +static cert_t tbb_certs[] = { + [TRUSTED_BOOT_FW_CERT] = { + .id = TRUSTED_BOOT_FW_CERT, + .opt = "tb-fw-cert", + .help_msg = "Trusted Boot FW Certificate (output file)", + .fn = NULL, + .cn = "Trusted Boot FW Certificate", + .key = ROT_KEY, + .issuer = TRUSTED_BOOT_FW_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + TRUSTED_BOOT_FW_HASH_EXT, + TRUSTED_BOOT_FW_CONFIG_HASH_EXT, + HW_CONFIG_HASH_EXT, + FW_CONFIG_HASH_EXT + }, + .num_ext = 5 + }, + [TRUSTED_KEY_CERT] = { + .id = TRUSTED_KEY_CERT, + .opt = "trusted-key-cert", + .help_msg = "Trusted Key Certificate (output file)", + .fn = NULL, + .cn = "Trusted Key Certificate", + .key = ROT_KEY, + .issuer = TRUSTED_KEY_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + TRUSTED_WORLD_PK_EXT, + NON_TRUSTED_WORLD_PK_EXT + }, + .num_ext = 3 + }, + [SCP_FW_KEY_CERT] = { + .id = SCP_FW_KEY_CERT, + .opt = "scp-fw-key-cert", + .help_msg = "SCP Firmware Key Certificate (output file)", + .fn = NULL, + .cn = "SCP Firmware Key Certificate", + .key = TRUSTED_WORLD_KEY, + .issuer = SCP_FW_KEY_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + SCP_FW_CONTENT_CERT_PK_EXT + }, + .num_ext = 2 + }, + [SCP_FW_CONTENT_CERT] = { + .id = SCP_FW_CONTENT_CERT, + .opt = "scp-fw-cert", + .help_msg = "SCP Firmware Content Certificate (output file)", + .fn = NULL, + .cn = "SCP Firmware Content Certificate", + .key = SCP_FW_CONTENT_CERT_KEY, + .issuer = SCP_FW_CONTENT_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + SCP_FW_HASH_EXT + }, + .num_ext = 2 + }, + [SOC_FW_KEY_CERT] = { + .id = SOC_FW_KEY_CERT, + .opt = "soc-fw-key-cert", + .help_msg = "SoC Firmware Key Certificate (output file)", + .fn = NULL, + .cn = "SoC Firmware Key Certificate", + .key = TRUSTED_WORLD_KEY, + .issuer = SOC_FW_KEY_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + SOC_FW_CONTENT_CERT_PK_EXT + }, + .num_ext = 2 + }, + [SOC_FW_CONTENT_CERT] = { + .id = SOC_FW_CONTENT_CERT, + .opt = "soc-fw-cert", + .help_msg = "SoC Firmware Content Certificate (output file)", + .fn = NULL, + .cn = "SoC Firmware Content Certificate", + .key = SOC_FW_CONTENT_CERT_KEY, + .issuer = SOC_FW_CONTENT_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + SOC_AP_FW_HASH_EXT, + SOC_FW_CONFIG_HASH_EXT, + }, + .num_ext = 3 + }, + [TRUSTED_OS_FW_KEY_CERT] = { + .id = TRUSTED_OS_FW_KEY_CERT, + .opt = "tos-fw-key-cert", + .help_msg = "Trusted OS Firmware Key Certificate (output file)", + .fn = NULL, + .cn = "Trusted OS Firmware Key Certificate", + .key = TRUSTED_WORLD_KEY, + .issuer = TRUSTED_OS_FW_KEY_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + TRUSTED_OS_FW_CONTENT_CERT_PK_EXT + }, + .num_ext = 2 + }, + [TRUSTED_OS_FW_CONTENT_CERT] = { + .id = TRUSTED_OS_FW_CONTENT_CERT, + .opt = "tos-fw-cert", + .help_msg = "Trusted OS Firmware Content Certificate (output file)", + .fn = NULL, + .cn = "Trusted OS Firmware Content Certificate", + .key = TRUSTED_OS_FW_CONTENT_CERT_KEY, + .issuer = TRUSTED_OS_FW_CONTENT_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + TRUSTED_OS_FW_HASH_EXT, + TRUSTED_OS_FW_EXTRA1_HASH_EXT, + TRUSTED_OS_FW_EXTRA2_HASH_EXT, + TRUSTED_OS_FW_CONFIG_HASH_EXT, + }, + .num_ext = 5 + }, + [NON_TRUSTED_FW_KEY_CERT] = { + .id = NON_TRUSTED_FW_KEY_CERT, + .opt = "nt-fw-key-cert", + .help_msg = "Non-Trusted Firmware Key Certificate (output file)", + .fn = NULL, + .cn = "Non-Trusted Firmware Key Certificate", + .key = NON_TRUSTED_WORLD_KEY, + .issuer = NON_TRUSTED_FW_KEY_CERT, + .ext = { + NON_TRUSTED_FW_NVCOUNTER_EXT, + NON_TRUSTED_FW_CONTENT_CERT_PK_EXT + }, + .num_ext = 2 + }, + [NON_TRUSTED_FW_CONTENT_CERT] = { + .id = NON_TRUSTED_FW_CONTENT_CERT, + .opt = "nt-fw-cert", + .help_msg = "Non-Trusted Firmware Content Certificate (output file)", + .fn = NULL, + .cn = "Non-Trusted Firmware Content Certificate", + .key = NON_TRUSTED_FW_CONTENT_CERT_KEY, + .issuer = NON_TRUSTED_FW_CONTENT_CERT, + .ext = { + NON_TRUSTED_FW_NVCOUNTER_EXT, + NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT, + NON_TRUSTED_FW_CONFIG_HASH_EXT, + }, + .num_ext = 3 + }, + [SIP_SECURE_PARTITION_CONTENT_CERT] = { + .id = SIP_SECURE_PARTITION_CONTENT_CERT, + .opt = "sip-sp-cert", + .help_msg = "SiP owned Secure Partition Content Certificate (output file)", + .fn = NULL, + .cn = "SiP owned Secure Partition Content Certificate", + .key = TRUSTED_WORLD_KEY, + .issuer = SIP_SECURE_PARTITION_CONTENT_CERT, + .ext = { + TRUSTED_FW_NVCOUNTER_EXT, + SP_PKG1_HASH_EXT, + SP_PKG2_HASH_EXT, + SP_PKG3_HASH_EXT, + SP_PKG4_HASH_EXT, + SP_PKG5_HASH_EXT, + SP_PKG6_HASH_EXT, + SP_PKG7_HASH_EXT, + SP_PKG8_HASH_EXT, + }, + .num_ext = 9 + }, + [FWU_CERT] = { + .id = FWU_CERT, + .opt = "fwu-cert", + .help_msg = "Firmware Update Certificate (output file)", + .fn = NULL, + .cn = "Firmware Update Certificate", + .key = ROT_KEY, + .issuer = FWU_CERT, + .ext = { + SCP_FWU_CFG_HASH_EXT, + AP_FWU_CFG_HASH_EXT, + FWU_HASH_EXT + }, + .num_ext = 3 + } +}; + +REGISTER_COT(tbb_certs); diff --git a/tools/cert_create/src/tbbr/tbb_ext.c b/tools/cert_create/src/tbbr/tbb_ext.c new file mode 100644 index 0000000..60bafb4 --- /dev/null +++ b/tools/cert_create/src/tbbr/tbb_ext.c @@ -0,0 +1,328 @@ +/* + * Copyright (c) 2015-2020, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include <stdio.h> +#include <string.h> +#include <openssl/err.h> +#include <openssl/x509v3.h> + +#if USE_TBBR_DEFS +#include <tbbr_oid.h> +#else +#include <platform_oid.h> +#endif + +#include "ext.h" +#include "tbbr/tbb_ext.h" +#include "tbbr/tbb_key.h" + +static ext_t tbb_ext[] = { + [TRUSTED_FW_NVCOUNTER_EXT] = { + .oid = TRUSTED_FW_NVCOUNTER_OID, + .opt = "tfw-nvctr", + .help_msg = "Trusted Firmware Non-Volatile counter value", + .sn = "TrustedWorldNVCounter", + .ln = "Trusted World Non-Volatile counter", + .asn1_type = V_ASN1_INTEGER, + .type = EXT_TYPE_NVCOUNTER, + .attr.nvctr_type = NVCTR_TYPE_TFW + }, + [NON_TRUSTED_FW_NVCOUNTER_EXT] = { + .oid = NON_TRUSTED_FW_NVCOUNTER_OID, + .opt = "ntfw-nvctr", + .help_msg = "Non-Trusted Firmware Non-Volatile counter value", + .sn = "NormalWorldNVCounter", + .ln = "Non-Trusted Firmware Non-Volatile counter", + .asn1_type = V_ASN1_INTEGER, + .type = EXT_TYPE_NVCOUNTER, + .attr.nvctr_type = NVCTR_TYPE_NTFW + }, + [TRUSTED_BOOT_FW_HASH_EXT] = { + .oid = TRUSTED_BOOT_FW_HASH_OID, + .opt = "tb-fw", + .help_msg = "Trusted Boot Firmware image file", + .sn = "TrustedBootFirmwareHash", + .ln = "Trusted Boot Firmware hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + [TRUSTED_BOOT_FW_CONFIG_HASH_EXT] = { + .oid = TRUSTED_BOOT_FW_CONFIG_HASH_OID, + .opt = "tb-fw-config", + .help_msg = "Trusted Boot Firmware Config file", + .sn = "TrustedBootFirmwareConfigHash", + .ln = "Trusted Boot Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [HW_CONFIG_HASH_EXT] = { + .oid = HW_CONFIG_HASH_OID, + .opt = "hw-config", + .help_msg = "HW Config file", + .sn = "HWConfigHash", + .ln = "HW Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [FW_CONFIG_HASH_EXT] = { + .oid = FW_CONFIG_HASH_OID, + .opt = "fw-config", + .help_msg = "Firmware Config file", + .sn = "FirmwareConfigHash", + .ln = "Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [TRUSTED_WORLD_PK_EXT] = { + .oid = TRUSTED_WORLD_PK_OID, + .sn = "TrustedWorldPublicKey", + .ln = "Trusted World Public Key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = TRUSTED_WORLD_KEY + }, + [NON_TRUSTED_WORLD_PK_EXT] = { + .oid = NON_TRUSTED_WORLD_PK_OID, + .sn = "NonTrustedWorldPublicKey", + .ln = "Non-Trusted World Public Key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = NON_TRUSTED_WORLD_KEY + }, + [SCP_FW_CONTENT_CERT_PK_EXT] = { + .oid = SCP_FW_CONTENT_CERT_PK_OID, + .sn = "SCPFirmwareContentCertPK", + .ln = "SCP Firmware content certificate public key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = SCP_FW_CONTENT_CERT_KEY + }, + [SCP_FW_HASH_EXT] = { + .oid = SCP_FW_HASH_OID, + .opt = "scp-fw", + .help_msg = "SCP Firmware image file", + .sn = "SCPFirmwareHash", + .ln = "SCP Firmware hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + [SOC_FW_CONTENT_CERT_PK_EXT] = { + .oid = SOC_FW_CONTENT_CERT_PK_OID, + .sn = "SoCFirmwareContentCertPK", + .ln = "SoC Firmware content certificate public key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = SOC_FW_CONTENT_CERT_KEY + }, + [SOC_AP_FW_HASH_EXT] = { + .oid = SOC_AP_FW_HASH_OID, + .opt = "soc-fw", + .help_msg = "SoC AP Firmware image file", + .sn = "SoCAPFirmwareHash", + .ln = "SoC AP Firmware hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + [SOC_FW_CONFIG_HASH_EXT] = { + .oid = SOC_FW_CONFIG_HASH_OID, + .opt = "soc-fw-config", + .help_msg = "SoC Firmware Config file", + .sn = "SocFirmwareConfigHash", + .ln = "SoC Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [TRUSTED_OS_FW_CONTENT_CERT_PK_EXT] = { + .oid = TRUSTED_OS_FW_CONTENT_CERT_PK_OID, + .sn = "TrustedOSFirmwareContentCertPK", + .ln = "Trusted OS Firmware content certificate public key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = TRUSTED_OS_FW_CONTENT_CERT_KEY + }, + [TRUSTED_OS_FW_HASH_EXT] = { + .oid = TRUSTED_OS_FW_HASH_OID, + .opt = "tos-fw", + .help_msg = "Trusted OS image file", + .sn = "TrustedOSHash", + .ln = "Trusted OS hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + [TRUSTED_OS_FW_EXTRA1_HASH_EXT] = { + .oid = TRUSTED_OS_FW_EXTRA1_HASH_OID, + .opt = "tos-fw-extra1", + .help_msg = "Trusted OS Extra1 image file", + .sn = "TrustedOSExtra1Hash", + .ln = "Trusted OS Extra1 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [TRUSTED_OS_FW_EXTRA2_HASH_EXT] = { + .oid = TRUSTED_OS_FW_EXTRA2_HASH_OID, + .opt = "tos-fw-extra2", + .help_msg = "Trusted OS Extra2 image file", + .sn = "TrustedOSExtra2Hash", + .ln = "Trusted OS Extra2 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [TRUSTED_OS_FW_CONFIG_HASH_EXT] = { + .oid = TRUSTED_OS_FW_CONFIG_HASH_OID, + .opt = "tos-fw-config", + .help_msg = "Trusted OS Firmware Config file", + .sn = "TrustedOSFirmwareConfigHash", + .ln = "Trusted OS Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [NON_TRUSTED_FW_CONTENT_CERT_PK_EXT] = { + .oid = NON_TRUSTED_FW_CONTENT_CERT_PK_OID, + .sn = "NonTrustedFirmwareContentCertPK", + .ln = "Non-Trusted Firmware content certificate public key", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_PKEY, + .attr.key = NON_TRUSTED_FW_CONTENT_CERT_KEY + }, + [NON_TRUSTED_WORLD_BOOTLOADER_HASH_EXT] = { + .oid = NON_TRUSTED_WORLD_BOOTLOADER_HASH_OID, + .opt = "nt-fw", + .help_msg = "Non-Trusted World Bootloader image file", + .sn = "NonTrustedWorldBootloaderHash", + .ln = "Non-Trusted World hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH + }, + [NON_TRUSTED_FW_CONFIG_HASH_EXT] = { + .oid = NON_TRUSTED_FW_CONFIG_HASH_OID, + .opt = "nt-fw-config", + .help_msg = "Non Trusted OS Firmware Config file", + .sn = "NonTrustedOSFirmwareConfigHash", + .ln = "Non-Trusted OS Firmware Config hash", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG1_HASH_EXT] = { + .oid = SP_PKG1_HASH_OID, + .opt = "sp-pkg1", + .help_msg = "Secure Partition Package1 file", + .sn = "SPPkg1Hash", + .ln = "SP Pkg1 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG2_HASH_EXT] = { + .oid = SP_PKG2_HASH_OID, + .opt = "sp-pkg2", + .help_msg = "Secure Partition Package2 file", + .sn = "SPPkg2Hash", + .ln = "SP Pkg2 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG3_HASH_EXT] = { + .oid = SP_PKG3_HASH_OID, + .opt = "sp-pkg3", + .help_msg = "Secure Partition Package3 file", + .sn = "SPPkg3Hash", + .ln = "SP Pkg3 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG4_HASH_EXT] = { + .oid = SP_PKG4_HASH_OID, + .opt = "sp-pkg4", + .help_msg = "Secure Partition Package4 file", + .sn = "SPPkg4Hash", + .ln = "SP Pkg4 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG5_HASH_EXT] = { + .oid = SP_PKG5_HASH_OID, + .opt = "sp-pkg5", + .help_msg = "Secure Partition Package5 file", + .sn = "SPPkg5Hash", + .ln = "SP Pkg5 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG6_HASH_EXT] = { + .oid = SP_PKG6_HASH_OID, + .opt = "sp-pkg6", + .help_msg = "Secure Partition Package6 file", + .sn = "SPPkg6Hash", + .ln = "SP Pkg6 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG7_HASH_EXT] = { + .oid = SP_PKG7_HASH_OID, + .opt = "sp-pkg7", + .help_msg = "Secure Partition Package7 file", + .sn = "SPPkg7Hash", + .ln = "SP Pkg7 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SP_PKG8_HASH_EXT] = { + .oid = SP_PKG8_HASH_OID, + .opt = "sp-pkg8", + .help_msg = "Secure Partition Package8 file", + .sn = "SPPkg8Hash", + .ln = "SP Pkg8 hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [SCP_FWU_CFG_HASH_EXT] = { + .oid = SCP_FWU_CFG_HASH_OID, + .opt = "scp-fwu-cfg", + .help_msg = "SCP Firmware Update Config image file", + .sn = "SCPFWUpdateConfig", + .ln = "SCP Firmware Update Config hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [AP_FWU_CFG_HASH_EXT] = { + .oid = AP_FWU_CFG_HASH_OID, + .opt = "ap-fwu-cfg", + .help_msg = "AP Firmware Update Config image file", + .sn = "APFWUpdateConfig", + .ln = "AP Firmware Update Config hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + }, + [FWU_HASH_EXT] = { + .oid = FWU_HASH_OID, + .opt = "fwu", + .help_msg = "Firmware Updater image file", + .sn = "FWUpdaterHash", + .ln = "Firmware Updater hash (SHA256)", + .asn1_type = V_ASN1_OCTET_STRING, + .type = EXT_TYPE_HASH, + .optional = 1 + } +}; + +REGISTER_EXTENSIONS(tbb_ext); diff --git a/tools/cert_create/src/tbbr/tbb_key.c b/tools/cert_create/src/tbbr/tbb_key.c new file mode 100644 index 0000000..a81f0e4 --- /dev/null +++ b/tools/cert_create/src/tbbr/tbb_key.c @@ -0,0 +1,59 @@ +/* + * Copyright (c) 2015, ARM Limited and Contributors. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include "tbbr/tbb_key.h" + +/* + * Keys used to establish the chain of trust + * + * The order of the keys must follow the enumeration specified in tbb_key.h + */ +static key_t tbb_keys[] = { + [ROT_KEY] = { + .id = ROT_KEY, + .opt = "rot-key", + .help_msg = "Root Of Trust key (input/output file)", + .desc = "Root Of Trust key" + }, + [TRUSTED_WORLD_KEY] = { + .id = TRUSTED_WORLD_KEY, + .opt = "trusted-world-key", + .help_msg = "Trusted World key (input/output file)", + .desc = "Trusted World key" + }, + [NON_TRUSTED_WORLD_KEY] = { + .id = NON_TRUSTED_WORLD_KEY, + .opt = "non-trusted-world-key", + .help_msg = "Non Trusted World key (input/output file)", + .desc = "Non Trusted World key" + }, + [SCP_FW_CONTENT_CERT_KEY] = { + .id = SCP_FW_CONTENT_CERT_KEY, + .opt = "scp-fw-key", + .help_msg = "SCP Firmware Content Certificate key (input/output file)", + .desc = "SCP Firmware Content Certificate key" + }, + [SOC_FW_CONTENT_CERT_KEY] = { + .id = SOC_FW_CONTENT_CERT_KEY, + .opt = "soc-fw-key", + .help_msg = "SoC Firmware Content Certificate key (input/output file)", + .desc = "SoC Firmware Content Certificate key" + }, + [TRUSTED_OS_FW_CONTENT_CERT_KEY] = { + .id = TRUSTED_OS_FW_CONTENT_CERT_KEY, + .opt = "tos-fw-key", + .help_msg = "Trusted OS Firmware Content Certificate key (input/output file)", + .desc = "Trusted OS Firmware Content Certificate key" + }, + [NON_TRUSTED_FW_CONTENT_CERT_KEY] = { + .id = NON_TRUSTED_FW_CONTENT_CERT_KEY, + .opt = "nt-fw-key", + .help_msg = "Non Trusted Firmware Content Certificate key (input/output file)", + .desc = "Non Trusted Firmware Content Certificate key" + } +}; + +REGISTER_KEYS(tbb_keys); diff --git a/tools/cert_create/src/tbbr/tbbr.mk b/tools/cert_create/src/tbbr/tbbr.mk new file mode 100644 index 0000000..ee82d31 --- /dev/null +++ b/tools/cert_create/src/tbbr/tbbr.mk @@ -0,0 +1,29 @@ +# +# Copyright (c) 2020, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +USE_TBBR_DEFS := 1 +$(eval $(call add_define,USE_TBBR_DEFS)) + +ifeq (${USE_TBBR_DEFS},1) +# In this case, cert_tool is platform-independent +PLAT_MSG := TBBR Generic +PLAT_INCLUDE := ../../include/tools_share +else +PLAT_MSG := ${PLAT} + +TF_PLATFORM_ROOT := ../../plat/ +include ${MAKE_HELPERS_DIRECTORY}plat_helpers.mk + +PLAT_INCLUDE := $(wildcard ${PLAT_DIR}include) + +ifeq ($(PLAT_INCLUDE),) + $(error "Error: Invalid platform '${PLAT}' has no include directory.") +endif +endif + +OBJECTS += src/tbbr/tbb_cert.o \ + src/tbbr/tbb_ext.o \ + src/tbbr/tbb_key.o |