<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">--- 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-&gt;node_offset = noffset;
 	info-&gt;name = strdup(algo_name);
 	info-&gt;checksum = image_get_checksum_algo(algo_name);
-	info-&gt;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-&gt;crypto = image_get_crypto_algo(offline_algo_name);
+	} else {
+		info-&gt;crypto = image_get_crypto_algo(algo_name);
+	}
+
 	info-&gt;padding = image_get_padding_algo(padding_name);
 	info-&gt;require_keys = require_keys;
 	info-&gt;engine_id = engine_id;
--- a/tools/image-sig-host.c
+++ b/tools/image-sig-host.c
@@ -11,6 +11,7 @@
 #include &lt;u-boot/ecdsa.h&gt;
 #include &lt;u-boot/rsa.h&gt;
 #include &lt;u-boot/hash-checksum.h&gt;
+#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 &lt;stdio.h&gt;
+#include &lt;stdint.h&gt;
+#include &lt;image.h&gt;
+#include &lt;linux/libfdt.h&gt;
+#include &lt;malloc.h&gt;
+#include &lt;u-boot/sha512.h&gt;
+#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 &lt; 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 &lt; 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, &amp;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) &gt;= 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-&gt;fit, img_prefix);
+	if (ret)
+		return ret;
+
+	len = snprintf(msg_file, sizeof(msg_file),
+		       "%s/%s%s", info-&gt;keydir, img_prefix, OFFSIGN_MSG_FILE);
+	if (len &lt; 0)
+		return -EINVAL;
+
+	/* calculate digest */
+	ret = info-&gt;checksum-&gt;calculate(info-&gt;checksum-&gt;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-&gt;checksum-&gt;checksum_len, f);
+	if (len &lt; 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-&gt;padding &amp;&amp; !strcmp(info-&gt;padding-&gt;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-&gt;keydir,
+								img_prefix,
+								OFFSIGN_MSG_FILE,
+								info-&gt;keydir,
+								info-&gt;keyname,
+								info-&gt;keydir,
+								img_prefix,
+								OFFSIGN_SIG_FILE,
+								info-&gt;checksum-&gt;name,
+								OPENSSL_PKEYUTL_PADDING,
+								padding);
+	if (len &lt; 0)
+		return -EINVAL;
+
+	if (!strcmp(padding, "pss")) {
+		len = snprintf(cmd + len, sizeof(cmd), "%s", OPENSSL_PKEYUTL_SALT);
+		if (len &lt; 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-&gt;keydir, img_prefix, OFFSIGN_SIG_FILE);
+	if (len &lt; 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-&gt;crypto-&gt;key_len, sizeof(uint8_t));
+	if (!sig) {
+		ret = -ENOMEM;
+		goto post_offline_sign_err;
+	}
+
+	len = fread(sig, sizeof(uint8_t), info-&gt;crypto-&gt;key_len, f);
+	if (len &lt; 0) {
+		fprintf(stderr, "Failed to read from %s\n", sig_file);
+		ret = -EINVAL;
+		goto post_offline_sign_err;
+	}
+
+	if (len != info-&gt;crypto-&gt;key_len) {
+		fprintf(stderr, "Signature length is invalid\n");
+		ret = -EINVAL;
+		goto post_offline_sign_err;
+	}
+
+	fclose(f);
+
+	*sigp = sig;
+	*sig_len= info-&gt;crypto-&gt;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;
+}
</pre></body></html>