blob: 191eb53d04ad63298bf121d7c2d77e2f4c2289d5 [file] [log] [blame]
--- 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;
++}