| --- a/include/image.mk |
| +++ b/include/image.mk |
| @@ -443,7 +443,10 @@ endif |
| ROOTFS_ENCRYPT = $(if $(ROE_KEY_DIR),$(wildcard $(ROE_KEY_DIR)/$(ROE_KEY_NAME).key),) |
| |
| DEVICE_CHECK_FIT_KEY = $(if $(wildcard $(FIT_KEY_DIR)/$(FIT_KEY_NAME).key),install-images,install-disabled) |
| -DEVICE_CHECK_FIT_DIR = $(if $(FIT_KEY_DIR),$(DEVICE_CHECK_FIT_KEY),install-images) |
| +DEVICE_CHECK_FIT_DIR = $(if $(FIT_KEY_DIR),$(DEVICE_CHECK_FIT_KEY),install-disabled) |
| + |
| +DEVICE_CHECK_OFFLINE_FIT_KEY = $(if $(filter offline%,$(FIT_KEY_NAME)),install-images,$(DEVICE_CHECK_FIT_DIR)) |
| +DEVICE_CHECK_FIT_KEY_NAME = $(if $(FIT_KEY_NAME),$(DEVICE_CHECK_OFFLINE_FIT_KEY),install-images) |
| |
| DEVICE_EXTRA_PACKAGES = $(call qstrip,$(CONFIG_TARGET_DEVICE_PACKAGES_$(call target_conf,$(BOARD)$(if $(SUBTARGET),_$(SUBTARGET)))_DEVICE_$(1))) |
| |
| @@ -467,7 +470,7 @@ endef |
| define Device/Check |
| $(Device/Check/Common) |
| KDIR_KERNEL_IMAGE := $(KDIR)/$(1)$$(KERNEL_SUFFIX) |
| - _TARGET := $$(if $$(_PROFILE_SET),$$(DEVICE_CHECK_FIT_DIR),install-disabled) |
| + _TARGET := $$(if $$(_PROFILE_SET),$$(DEVICE_CHECK_FIT_KEY_NAME),install-disabled) |
| ifndef IB |
| _COMPILE_TARGET := $$(if $(CONFIG_IB)$$(_PROFILE_SET),compile,compile-disabled) |
| endif |
| --- a/scripts/mkits.sh |
| +++ b/scripts/mkits.sh |
| @@ -164,11 +164,17 @@ fi |
| |
| # Conditionally create signature information |
| if [ -n "${KEY_NAME_HINT}" ]; then |
| + if [[ "${KEY_NAME_HINT}" == "offline,"* ]]; then |
| + KEY_NAME_HINT=$(echo -n "${KEY_NAME_HINT}" | sed "s/^.*[,]//g") |
| + SIGN_OFFLINE=" |
| + sign-offline = <1>;" |
| + fi |
| SIGNATURE="\ |
| signature { |
| algo = \"sha1,rsa2048\"; |
| key-name-hint = \"${KEY_NAME_HINT}\"; |
| ${SIGN_IMAGES} |
| +${SIGN_OFFLINE} |
| };\ |
| " |
| fi |
| --- /dev/null |
| +++ b/tools/mkimage/patches/901-mtk-mkimage-add-offline-sign-support.patch |
| @@ -0,0 +1,382 @@ |
| +--- a/tools/image-host.c |
| ++++ b/tools/image-host.c |
| +@@ -168,6 +168,9 @@ static int fit_image_setup_sig(struct im |
| + { |
| + const char *node_name; |
| + const char *padding_name; |
| ++ const char *offline; |
| ++ const char offline_suffix[] = ",offline"; |
| ++ char *offline_algo_name = NULL; |
| + |
| + node_name = fit_get_name(fit, noffset, NULL); |
| + if (!algo_name) { |
| +@@ -188,7 +191,21 @@ static int fit_image_setup_sig(struct im |
| + info->node_offset = noffset; |
| + info->name = strdup(algo_name); |
| + info->checksum = image_get_checksum_algo(algo_name); |
| +- info->crypto = image_get_crypto_algo(algo_name); |
| ++ |
| ++ offline = fdt_getprop(fit, noffset, "sign-offline", NULL); |
| ++ if (offline) { |
| ++ offline_algo_name = calloc(strlen(algo_name) + strlen(offline_suffix) + 1, sizeof(char)); |
| ++ if (!offline_algo_name) |
| ++ return -ENOMEM; |
| ++ |
| ++ strcpy(offline_algo_name, algo_name); |
| ++ strcat(offline_algo_name, offline_suffix); |
| ++ |
| ++ info->crypto = image_get_crypto_algo(offline_algo_name); |
| ++ } else { |
| ++ info->crypto = image_get_crypto_algo(algo_name); |
| ++ } |
| ++ |
| + info->padding = image_get_padding_algo(padding_name); |
| + info->require_keys = require_keys; |
| + info->engine_id = engine_id; |
| +--- a/tools/image-sig-host.c |
| ++++ b/tools/image-sig-host.c |
| +@@ -11,6 +11,7 @@ |
| + #include <u-boot/ecdsa.h> |
| + #include <u-boot/rsa.h> |
| + #include <u-boot/hash-checksum.h> |
| ++#include "signoffline.h" |
| + |
| + struct checksum_algo checksum_algos[] = { |
| + { |
| +@@ -76,6 +77,27 @@ struct crypto_algo crypto_algos[] = { |
| + .add_verify_data = ecdsa_add_verify_data, |
| + .verify = ecdsa_verify, |
| + }, |
| ++ { |
| ++ .name = "rsa2048,offline", |
| ++ .key_len = RSA2048_BYTES, |
| ++ .sign = offline_sign, |
| ++ .add_verify_data = rsa_add_verify_data, |
| ++ .verify = offline_verify, |
| ++ }, |
| ++ { |
| ++ .name = "rsa3072,offline", |
| ++ .key_len = RSA3072_BYTES, |
| ++ .sign = offline_sign, |
| ++ .add_verify_data = rsa_add_verify_data, |
| ++ .verify = offline_verify, |
| ++ }, |
| ++ { |
| ++ .name = "rsa4096,offline", |
| ++ .key_len = RSA4096_BYTES, |
| ++ .sign = offline_sign, |
| ++ .add_verify_data = rsa_add_verify_data, |
| ++ .verify = offline_verify, |
| ++ }, |
| + }; |
| + |
| + struct padding_algo padding_algos[] = { |
| +--- a/tools/Makefile |
| ++++ b/tools/Makefile |
| +@@ -89,6 +89,8 @@ RSA_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $( |
| + rsa-sign.o rsa-verify.o \ |
| + rsa-mod-exp.o) |
| + |
| ++SIGNOFFLINE_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := signoffline.o |
| ++ |
| + ECDSA_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix lib/ecdsa/, ecdsa-libcrypto.o) |
| + |
| + AES_OBJS-$(CONFIG_TOOLS_LIBCRYPTO) := $(addprefix lib/aes/, \ |
| +@@ -149,7 +151,8 @@ dumpimage-mkimage-objs := aisimage.o \ |
| + mtk_image.o \ |
| + $(ECDSA_OBJS-y) \ |
| + $(RSA_OBJS-y) \ |
| +- $(AES_OBJS-y) |
| ++ $(AES_OBJS-y) \ |
| ++ $(SIGNOFFLINE_OBJS-y) |
| + |
| + dumpimage-objs := $(dumpimage-mkimage-objs) dumpimage.o |
| + mkimage-objs := $(dumpimage-mkimage-objs) mkimage.o |
| +--- /dev/null |
| ++++ b/tools/signoffline.h |
| +@@ -0,0 +1,18 @@ |
| ++// SPDX-License-Identifier: GPL-2.0+ |
| ++/* |
| ++ * Copyright (C) 2022 MediaTek Incorporation. All Rights Reserved. |
| ++ * |
| ++ */ |
| ++ |
| ++#ifndef SIGNOFFLINE_H_ |
| ++#define SIGNOFFLINE_H_ |
| ++ |
| ++int offline_sign(struct image_sign_info *info, |
| ++ const struct image_region region[], int region_count, |
| ++ uint8_t **sigp, uint *sig_len); |
| ++ |
| ++int offline_verify(struct image_sign_info *info, |
| ++ const struct image_region region[], int region_count, |
| ++ uint8_t *sig, uint sig_len); |
| ++ |
| ++#endif /* SIGNOFFLINE_H_ */ |
| +--- /dev/null |
| ++++ b/tools/signoffline.c |
| +@@ -0,0 +1,264 @@ |
| ++// SPDX-License-Identifier: GPL-2.0+ |
| ++/* |
| ++ * Copyright (C) 2022 MediaTek Incorporation. All Rights Reserved. |
| ++ * |
| ++ */ |
| ++#include <stdio.h> |
| ++#include <stdint.h> |
| ++#include <image.h> |
| ++#include <linux/libfdt.h> |
| ++#include <malloc.h> |
| ++#include <u-boot/sha512.h> |
| ++#include "mkimage.h" |
| ++ |
| ++#define OFFSIGN_MSG_FILE ".msg" |
| ++#define OFFSIGN_SIG_FILE ".sig" |
| ++#define OFFSIGN_MAX_TMPFILE_LEN 256 |
| ++#define OFFSIGN_MAX_CMDLINE_LEN 3 * OFFSIGN_MAX_TMPFILE_LEN + 128 + 1 |
| ++#define OPENSSL_PKEYUTL_CMD "openssl pkeyutl" |
| ++#define OPENSSL_PKEYUTL_OPER "-sign" |
| ++#define OPENSSL_PKEYUTL_PADDING "-pkeyopt rsa_padding_mode" |
| ++#define OPENSSL_PKEYUTL_SALT "-pkeyopt rsa_pss_saltlen:32" |
| ++ |
| ++static char img_prefix[OFFSIGN_MAX_TMPFILE_LEN]; |
| ++ |
| ++static int get_fit_identifier(const void *fit, char *img_prefix) |
| ++{ |
| ++ int ret = 0; |
| ++ int noffset = 0; |
| ++ int img_noffset = 0; |
| ++ int len = 0; |
| ++ const char *prop = NULL; |
| ++ char *p = NULL, *end_p = NULL; |
| ++ |
| ++ img_noffset = fdt_path_offset(fit, FIT_IMAGES_PATH); |
| ++ if (img_noffset < 0) { |
| ++ fprintf(stderr, "Can't find image parent node: %s\n", FIT_IMAGES_PATH); |
| ++ return img_noffset; |
| ++ } |
| ++ |
| ++ noffset = fdt_subnode_offset(fit, img_noffset, "fdt-1"); |
| ++ if (noffset < 0) { |
| ++ fprintf(stderr, "Can't find fdt-1 node in %s\n", FIT_IMAGES_PATH); |
| ++ return noffset; |
| ++ } |
| ++ |
| ++ prop = fdt_getprop(fit, noffset, FIT_DESC_PROP, &len); |
| ++ if (!prop) { |
| ++ fprintf(stderr, "Can't find %s property in node: fdt-1\n", FIT_DESC_PROP); |
| ++ return -EINVAL; |
| ++ } |
| ++ |
| ++ /* find FIT image name as tmpfile prefix */ |
| ++ p = strstr(prop, "OpenWrt "); |
| ++ if (!p) |
| ++ return -EINVAL; |
| ++ |
| ++ p = strchr(p, ' '); |
| ++ if (!p) |
| ++ return -EINVAL; |
| ++ p += 1; |
| ++ |
| ++ end_p = strchr(p, ' '); |
| ++ if (!end_p) |
| ++ return -EINVAL; |
| ++ |
| ++ if ((end_p - p) >= OFFSIGN_MAX_TMPFILE_LEN) |
| ++ return -EINVAL; |
| ++ |
| ++ strncpy(img_prefix, p, end_p - p); |
| ++ |
| ++ return ret; |
| ++} |
| ++ |
| ++static int prepare_offline_sign(struct image_sign_info *info, |
| ++ const struct image_region region[], |
| ++ int region_count) |
| ++{ |
| ++ int ret = 0; |
| ++ size_t len = 0; |
| ++ FILE *f = NULL; |
| ++ char msg_file[OFFSIGN_MAX_TMPFILE_LEN] = {0}; |
| ++ uint8_t checksum[SHA512_SUM_LEN] = {0}; |
| ++ |
| ++ ret = get_fit_identifier(info->fit, img_prefix); |
| ++ if (ret) |
| ++ return ret; |
| ++ |
| ++ len = snprintf(msg_file, sizeof(msg_file), |
| ++ "%s/%s%s", info->keydir, img_prefix, OFFSIGN_MSG_FILE); |
| ++ if (len < 0) |
| ++ return -EINVAL; |
| ++ |
| ++ /* calculate digest */ |
| ++ ret = info->checksum->calculate(info->checksum->name, region, |
| ++ region_count, checksum); |
| ++ if (ret) { |
| ++ fprintf(stderr, "Failed to calculate checksum of regions\n"); |
| ++ return ret; |
| ++ } |
| ++ |
| ++ /* write message to be signed to msg_file */ |
| ++ f = fopen(msg_file, "w"); |
| ++ if (!f) { |
| ++ fprintf(stderr, "Failed to open %s\n", msg_file); |
| ++ return -EINVAL; |
| ++ } |
| ++ |
| ++ len = fwrite(checksum, sizeof(uint8_t), |
| ++ info->checksum->checksum_len, f); |
| ++ if (len < 0) { |
| ++ fprintf(stderr, "Failed to write to %s\n", msg_file); |
| ++ ret = -EINVAL; |
| ++ } |
| ++ |
| ++ fclose(f); |
| ++ |
| ++ return ret; |
| ++} |
| ++ |
| ++static int sign_offline(struct image_sign_info *info, |
| ++ const struct image_region region[], |
| ++ int region_count, |
| ++ uint8_t **sigp, uint *sig_len) |
| ++{ |
| ++ int ret = 0; |
| ++ size_t len = 0; |
| ++ char cmd[OFFSIGN_MAX_CMDLINE_LEN] = {0}; |
| ++ char padding[8] = {0}; |
| ++ |
| ++ /* check padding */ |
| ++ if (info->padding && !strcmp(info->padding->name, "pss")) |
| ++ strncpy(padding, "pss", sizeof(padding)); |
| ++ else |
| ++ strncpy(padding, "pkcs1", sizeof(padding)); |
| ++ |
| ++ len = snprintf(cmd, sizeof(cmd), |
| ++ "%s %s -in %s/%s%s -inkey %s/%s.key -out %s/%s%s -pkeyopt digest:%s %s:%s", |
| ++ OPENSSL_PKEYUTL_CMD, |
| ++ OPENSSL_PKEYUTL_OPER, |
| ++ info->keydir, |
| ++ img_prefix, |
| ++ OFFSIGN_MSG_FILE, |
| ++ info->keydir, |
| ++ info->keyname, |
| ++ info->keydir, |
| ++ img_prefix, |
| ++ OFFSIGN_SIG_FILE, |
| ++ info->checksum->name, |
| ++ OPENSSL_PKEYUTL_PADDING, |
| ++ padding); |
| ++ if (len < 0) |
| ++ return -EINVAL; |
| ++ |
| ++ if (!strcmp(padding, "pss")) { |
| ++ len = snprintf(cmd + len, sizeof(cmd), "%s", OPENSSL_PKEYUTL_SALT); |
| ++ if (len < 0) |
| ++ return -EINVAL; |
| ++ } |
| ++ |
| ++ printf("%s\n", cmd); |
| ++ |
| ++ /* execute openssl command */ |
| ++ if (system(cmd) == -1) { |
| ++ fprintf(stderr,"%s: failed to sign FIT\n", OPENSSL_PKEYUTL_CMD); |
| ++ return -EINVAL; |
| ++ } |
| ++ |
| ++ return ret; |
| ++} |
| ++ |
| ++static int post_offline_sign(struct image_sign_info *info, |
| ++ uint8_t **sigp, uint *sig_len) |
| ++{ |
| ++ int ret = 0; |
| ++ FILE *f = NULL; |
| ++ size_t len = 0; |
| ++ void *sig = NULL; |
| ++ char sig_file[OFFSIGN_MAX_TMPFILE_LEN] = {0}; |
| ++ |
| ++ len = snprintf(sig_file, sizeof(sig_file), |
| ++ "%s/%s%s", info->keydir, img_prefix, OFFSIGN_SIG_FILE); |
| ++ if (len < 0) |
| ++ return -EINVAL; |
| ++ |
| ++ /* read signature from sig_file */ |
| ++ f = fopen(sig_file, "rb"); |
| ++ if (!f) { |
| ++ fprintf(stderr, "Failed to open %s\n", sig_file); |
| ++ return -EINVAL; |
| ++ } |
| ++ |
| ++ sig = calloc(info->crypto->key_len, sizeof(uint8_t)); |
| ++ if (!sig) { |
| ++ ret = -ENOMEM; |
| ++ goto post_offline_sign_err; |
| ++ } |
| ++ |
| ++ len = fread(sig, sizeof(uint8_t), info->crypto->key_len, f); |
| ++ if (len < 0) { |
| ++ fprintf(stderr, "Failed to read from %s\n", sig_file); |
| ++ ret = -EINVAL; |
| ++ goto post_offline_sign_err; |
| ++ } |
| ++ |
| ++ if (len != info->crypto->key_len) { |
| ++ fprintf(stderr, "Signature length is invalid\n"); |
| ++ ret = -EINVAL; |
| ++ goto post_offline_sign_err; |
| ++ } |
| ++ |
| ++ fclose(f); |
| ++ |
| ++ *sigp = sig; |
| ++ *sig_len= info->crypto->key_len; |
| ++ |
| ++ return 0; |
| ++ |
| ++post_offline_sign_err: |
| ++ fclose(f); |
| ++ if (sig) |
| ++ free(sig); |
| ++ |
| ++ return ret; |
| ++} |
| ++ |
| ++int offline_sign(struct image_sign_info *info, |
| ++ const struct image_region region[], int region_count, |
| ++ uint8_t **sigp, uint *sig_len) |
| ++{ |
| ++ int ret = 0; |
| ++ |
| ++ printf("%s:\n", __func__); |
| ++ |
| ++ ret = prepare_offline_sign(info, region, region_count); |
| ++ if (ret) { |
| ++ fprintf(stderr, "prepare_offline_sign() failed\n"); |
| ++ return -EINVAL; |
| ++ } |
| ++ |
| ++ ret = sign_offline(info, region, region_count, sigp, sig_len); |
| ++ if (ret) { |
| ++ fprintf(stderr, "sign_offline() failed\n"); |
| ++ return -EINVAL; |
| ++ } |
| ++ |
| ++ ret = post_offline_sign(info, sigp, sig_len); |
| ++ if (ret) { |
| ++ fprintf(stderr, "post_offline_sign() failed\n"); |
| ++ return -EINVAL; |
| ++ } |
| ++ |
| ++ return ret; |
| ++} |
| ++ |
| ++int offline_verify(struct image_sign_info *info, |
| ++ const struct image_region region[], int region_count, |
| ++ uint8_t *sig, uint sig_len) |
| ++{ |
| ++ int ret = 0; |
| ++ |
| ++ printf("%s:\n", __func__); |
| ++ |
| ++ return ret; |
| ++} |