All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/4] sunxi: TOC0 image type support
@ 2021-06-21  2:55 Samuel Holland
  2021-06-21  2:55 ` [PATCH 1/4] tools: Refactor mkimage linking with OpenSSL Samuel Holland
                   ` (4 more replies)
  0 siblings, 5 replies; 14+ messages in thread
From: Samuel Holland @ 2021-06-21  2:55 UTC (permalink / raw)
  To: Jagan Teki, Andre Przywara, Hans de Goede; +Cc: u-boot, Samuel Holland

This series adds support for the TOC0 image format used by the Allwinner
secure boot ROM (SBROM). This series has been tested on the following
SoCs/boards, with the eFuse burnt to enable secure mode:
  - A64: Pine A64 Plus
  - H5: Orange Pi Zero Plus
  - H6: Pine H64 Model B
  - H616: Orange Pi Zero 2

Samuel Holland (4):
  tools: Refactor mkimage linking with OpenSSL
  tools: mkimage: Add Allwinner TOC0 support
  sunxi: Support both SPL image types
  sunxi: Support building a SPL as a TOC0 image

 arch/arm/Kconfig                      |   1 +
 arch/arm/include/asm/arch-sunxi/spl.h |   2 -
 arch/arm/mach-imx/mxs/Kconfig         |   2 +
 arch/arm/mach-mvebu/Kconfig           |   1 +
 arch/arm/mach-sunxi/Kconfig           |   2 +
 arch/arm/mach-sunxi/board.c           |  20 +-
 board/sunxi/Kconfig                   |  24 +
 common/Kconfig.boot                   |   2 +
 common/image.c                        |   1 +
 include/image.h                       |   1 +
 include/sunxi_image.h                 | 205 ++++++++
 scripts/Makefile.spl                  |   3 +-
 scripts/config_whitelist.txt          |   1 -
 tools/Kconfig                         |   3 +
 tools/Makefile                        |  23 +-
 tools/mxsimage.c                      |   3 -
 tools/sunxi_toc0.c                    | 710 ++++++++++++++++++++++++++
 17 files changed, 976 insertions(+), 28 deletions(-)
 create mode 100644 board/sunxi/Kconfig
 create mode 100644 tools/sunxi_toc0.c

-- 
2.31.1


^ permalink raw reply	[flat|nested] 14+ messages in thread

* [PATCH 1/4] tools: Refactor mkimage linking with OpenSSL
  2021-06-21  2:55 [PATCH 0/4] sunxi: TOC0 image type support Samuel Holland
@ 2021-06-21  2:55 ` Samuel Holland
  2021-06-26 18:31   ` Simon Glass
  2021-06-21  2:55 ` [PATCH 2/4] tools: mkimage: Add Allwinner TOC0 support Samuel Holland
                   ` (3 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Samuel Holland @ 2021-06-21  2:55 UTC (permalink / raw)
  To: Jagan Teki, Andre Przywara, Hans de Goede
  Cc: u-boot, Samuel Holland, Stefano Babic, Fabio Estevam,
	NXP i.MX U-Boot Team, Stefan Roese, Simon Glass

Some mkimage features require linking with OpenSSL. Instead of linking
OpenSSL based on the individual platform symbols, create a single
Kconfig symbol which can be selected by platforms as necessary. Then,
all OpenSSL-dependent image types can be enabled at once.

Cc: Stefano Babic <sbabic@denx.de>
Cc: Fabio Estevam <festevam@gmail.com>
Cc: "NXP i.MX U-Boot Team" <uboot-imx@nxp.com>
Cc: Stefan Roese <sr@denx.de>
Cc: Simon Glass <sjg@chromium.org>
Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm/mach-imx/mxs/Kconfig |  2 ++
 arch/arm/mach-mvebu/Kconfig   |  1 +
 common/Kconfig.boot           |  2 ++
 scripts/config_whitelist.txt  |  1 -
 tools/Kconfig                 |  3 +++
 tools/Makefile                | 22 +++++++---------------
 tools/mxsimage.c              |  3 ---
 7 files changed, 15 insertions(+), 19 deletions(-)

diff --git a/arch/arm/mach-imx/mxs/Kconfig b/arch/arm/mach-imx/mxs/Kconfig
index 9f48ffda414..f067a9c38e0 100644
--- a/arch/arm/mach-imx/mxs/Kconfig
+++ b/arch/arm/mach-imx/mxs/Kconfig
@@ -3,6 +3,7 @@ if ARCH_MX23
 config MX23
 	bool
 	default y
+	select MKIMAGE_LINK_OPENSSL
 
 choice
 	prompt "MX23 board select"
@@ -34,6 +35,7 @@ if ARCH_MX28
 config MX28
 	bool
 	default y
+	select MKIMAGE_LINK_OPENSSL
 
 choice
 	prompt "MX28 board select"
diff --git a/arch/arm/mach-mvebu/Kconfig b/arch/arm/mach-mvebu/Kconfig
index cda65f74786..2a4f861015d 100644
--- a/arch/arm/mach-mvebu/Kconfig
+++ b/arch/arm/mach-mvebu/Kconfig
@@ -29,6 +29,7 @@ config ARMADA_38X
 	bool
 	select ARMADA_32BIT
 	select HAVE_MVEBU_EFUSE
+	select MKIMAGE_LINK_OPENSSL
 
 config ARMADA_38X_HS_IMPEDANCE_THRESH
 	hex  "Armada 38x USB 2.0 High-Speed Impedance Threshold (0x0 - 0x7)"
diff --git a/common/Kconfig.boot b/common/Kconfig.boot
index 89a3161f1fa..7d022d1ccfa 100644
--- a/common/Kconfig.boot
+++ b/common/Kconfig.boot
@@ -80,6 +80,7 @@ config FIT_SIGNATURE
 	select RSA_VERIFY
 	select IMAGE_SIGN_INFO
 	select FIT_FULL_CHECK
+	select MKIMAGE_LINK_OPENSSL
 	help
 	  This option enables signature verification of FIT uImages,
 	  using a hash signed and verified using RSA. If
@@ -115,6 +116,7 @@ config FIT_CIPHER
 	bool "Enable ciphering data in a FIT uImages"
 	depends on DM
 	select AES
+	select MKIMAGE_LINK_OPENSSL
 	help
 	  Enable the feature of data ciphering/unciphering in the tool mkimage
 	  and in the u-boot support of the FIT image.
diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt
index 3dbcc042a8a..e013e1f26aa 100644
--- a/scripts/config_whitelist.txt
+++ b/scripts/config_whitelist.txt
@@ -1066,7 +1066,6 @@ CONFIG_MXC_UART_BASE
 CONFIG_MXC_USB_FLAGS
 CONFIG_MXC_USB_PORT
 CONFIG_MXC_USB_PORTSC
-CONFIG_MXS
 CONFIG_MXS_AUART
 CONFIG_MXS_AUART_BASE
 CONFIG_MXS_OCOTP
diff --git a/tools/Kconfig b/tools/Kconfig
index b2f5012240c..df3dffa9e18 100644
--- a/tools/Kconfig
+++ b/tools/Kconfig
@@ -9,4 +9,7 @@ config MKIMAGE_DTC_PATH
 	  some cases the system dtc may not support all required features
 	  and the path to a different version should be given here.
 
+config MKIMAGE_LINK_OPENSSL
+	bool
+
 endmenu
diff --git a/tools/Makefile b/tools/Makefile
index d020c55d664..8843185703c 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -75,9 +75,10 @@ ECDSA_OBJS-$(CONFIG_FIT_SIGNATURE) := $(addprefix lib/ecdsa/, ecdsa-libcrypto.o)
 AES_OBJS-$(CONFIG_FIT_CIPHER) := $(addprefix lib/aes/, \
 					aes-encrypt.o aes-decrypt.o)
 
-# Cryptographic helpers that depend on openssl/libcrypto
-LIBCRYPTO_OBJS-$(CONFIG_FIT_SIGNATURE) := $(addprefix lib/, \
-					fdt-libcrypto.o)
+# Cryptographic helpers and image types that depend on openssl/libcrypto
+OPENSSL_OBJS-$(CONFIG_MKIMAGE_LINK_OPENSSL) := \
+			lib/fdt-libcrypto.o \
+			mxsimage.o \
 
 ROCKCHIP_OBS = lib/rc4.o rkcommon.o rkimage.o rksd.o rkspi.o
 
@@ -101,7 +102,6 @@ dumpimage-mkimage-objs := aisimage.o \
 			kwbimage.o \
 			lib/md5.o \
 			lpc32xximage.o \
-			mxsimage.o \
 			omapimage.o \
 			os_support.o \
 			pblimage.o \
@@ -121,7 +121,7 @@ dumpimage-mkimage-objs := aisimage.o \
 			zynqimage.o \
 			zynqmpimage.o \
 			zynqmpbif.o \
-			$(LIBCRYPTO_OBJS-y) \
+			$(OPENSSL_OBJS-y) \
 			$(LIBFDT_OBJS) \
 			gpimage.o \
 			gpimage-common.o \
@@ -136,12 +136,7 @@ fit_info-objs   := $(dumpimage-mkimage-objs) fit_info.o
 fit_check_sign-objs   := $(dumpimage-mkimage-objs) fit_check_sign.o
 file2include-objs := file2include.o
 
-ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_FIT_SIGNATURE),)
-# Add CONFIG_MXS into host CFLAGS, so we can check whether or not register
-# the mxsimage support within tools/mxsimage.c .
-HOSTCFLAGS_mxsimage.o += -DCONFIG_MXS
-endif
-
+ifneq ($(CONFIG_MKIMAGE_LINK_OPENSSL),)
 ifdef CONFIG_FIT_SIGNATURE
 # This affects include/image.h, but including the board config file
 # is tricky, so manually define this options here.
@@ -159,12 +154,9 @@ ifdef CONFIG_SYS_U_BOOT_OFFS
 HOSTCFLAGS_kwbimage.o += -DCONFIG_SYS_U_BOOT_OFFS=$(CONFIG_SYS_U_BOOT_OFFS)
 endif
 
-ifneq ($(CONFIG_ARMADA_38X),)
+# Enable image features which depend on OpenSSL.
 HOSTCFLAGS_kwbimage.o += -DCONFIG_KWB_SECURE
-endif
 
-# MXSImage needs LibSSL
-ifneq ($(CONFIG_MX23)$(CONFIG_MX28)$(CONFIG_ARMADA_38X)$(CONFIG_FIT_SIGNATURE)$(CONFIG_FIT_CIPHER),)
 HOSTCFLAGS_kwbimage.o += \
 	$(shell pkg-config --cflags libssl libcrypto 2> /dev/null || echo "")
 HOSTLDLIBS_mkimage += \
diff --git a/tools/mxsimage.c b/tools/mxsimage.c
index 002f4b525aa..2bfbb421eb6 100644
--- a/tools/mxsimage.c
+++ b/tools/mxsimage.c
@@ -5,8 +5,6 @@
  * Copyright (C) 2012-2013 Marek Vasut <marex@denx.de>
  */
 
-#ifdef CONFIG_MXS
-
 #include <errno.h>
 #include <fcntl.h>
 #include <stdio.h>
@@ -2363,4 +2361,3 @@ U_BOOT_IMAGE_TYPE(
 	NULL,
 	mxsimage_generate
 );
-#endif
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 2/4] tools: mkimage: Add Allwinner TOC0 support
  2021-06-21  2:55 [PATCH 0/4] sunxi: TOC0 image type support Samuel Holland
  2021-06-21  2:55 ` [PATCH 1/4] tools: Refactor mkimage linking with OpenSSL Samuel Holland
@ 2021-06-21  2:55 ` Samuel Holland
  2021-06-22  1:07   ` Andre Przywara
  2021-06-21  2:55 ` [PATCH 3/4] sunxi: Support both SPL image types Samuel Holland
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 14+ messages in thread
From: Samuel Holland @ 2021-06-21  2:55 UTC (permalink / raw)
  To: Jagan Teki, Andre Przywara, Hans de Goede; +Cc: u-boot, Samuel Holland

Most Allwinner sunxi SoCs have separate boot ROMs in non-secure and
secure mode. The non-secure boot ROM (NBROM) uses the existing
sunxi_egon image type. The secure boot ROM (SBROM) uses a completely
different image type, known as TOC0.

A TOC0 image is composed of a header and two or more items. These items
include signed firmware and a key chain linking to a root-of-trust
public key (ROTPK) hash burned to eFuses in the SoC. Signatures are made
using RSA-2048 + SHA256.

This TOC0 implementation has been verified to work with the A64, H5, H6,
and H616 SBROMs.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm/Kconfig      |   1 +
 common/image.c        |   1 +
 include/image.h       |   1 +
 include/sunxi_image.h | 191 ++++++++++++
 tools/Makefile        |   1 +
 tools/sunxi_toc0.c    | 710 ++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 905 insertions(+)
 create mode 100644 tools/sunxi_toc0.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 0448787b8bc..97bf21da2e2 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -998,6 +998,7 @@ config ARCH_SUNXI
 	select DM_SCSI if SCSI
 	select DM_SERIAL
 	select DM_USB if DISTRO_DEFAULTS
+	select MKIMAGE_LINK_OPENSSL
 	select OF_BOARD_SETUP
 	select OF_CONTROL
 	select OF_SEPARATE
diff --git a/common/image.c b/common/image.c
index 51854aae5dd..d354d5d8d37 100644
--- a/common/image.c
+++ b/common/image.c
@@ -191,6 +191,7 @@ static const table_entry_t uimage_type[] = {
 	{	IH_TYPE_MTKIMAGE,   "mtk_image",   "MediaTek BootROM loadable Image" },
 	{	IH_TYPE_COPRO, "copro", "Coprocessor Image"},
 	{	IH_TYPE_SUNXI_EGON, "sunxi_egon",  "Allwinner eGON Boot Image" },
+	{	IH_TYPE_SUNXI_TOC0, "sunxi_toc0",  "Allwinner TOC0 Boot Image" },
 	{	-1,		    "",		  "",			},
 };
 
diff --git a/include/image.h b/include/image.h
index 459685d4d43..c01cd2982e6 100644
--- a/include/image.h
+++ b/include/image.h
@@ -312,6 +312,7 @@ enum {
 	IH_TYPE_IMX8IMAGE,		/* Freescale IMX8Boot Image	*/
 	IH_TYPE_COPRO,			/* Coprocessor Image for remoteproc*/
 	IH_TYPE_SUNXI_EGON,		/* Allwinner eGON Boot Image */
+	IH_TYPE_SUNXI_TOC0,		/* Allwinner TOC0 Boot Image */
 
 	IH_TYPE_COUNT,			/* Number of image types */
 };
diff --git a/include/sunxi_image.h b/include/sunxi_image.h
index 5b2055c0af3..bdf80ec0e0a 100644
--- a/include/sunxi_image.h
+++ b/include/sunxi_image.h
@@ -9,9 +9,12 @@
  *
  * Shared between mkimage and the SPL.
  */
+
 #ifndef	SUNXI_IMAGE_H
 #define	SUNXI_IMAGE_H
 
+#include <linux/types.h>
+
 #define BOOT0_MAGIC		"eGON.BT0"
 #define BROM_STAMP_VALUE	0x5f0a6c39
 #define SPL_SIGNATURE		"SPL" /* marks "sunxi" SPL header */
@@ -79,4 +82,192 @@ struct boot_file_head {
 /* Compile time check to assure proper alignment of structure */
 typedef char boot_file_head_not_multiple_of_32[1 - 2*(sizeof(struct boot_file_head) % 32)];
 
+struct toc0_main_info {
+	uint8_t name[8];
+	__le32  magic;
+	__le32  checksum;
+	__le32  serial;
+	__le32  status;
+	__le32  num_items;
+	__le32  length;
+	uint8_t platform[4];
+	uint8_t reserved[8];
+	uint8_t end[4];
+};
+
+#define TOC0_MAIN_INFO_NAME		"TOC0.GLH"
+#define TOC0_MAIN_INFO_MAGIC		0x89119800
+#define TOC0_MAIN_INFO_END		"MIE;"
+
+struct toc0_item_info {
+	__le32  name;
+	__le32  offset;
+	__le32  length;
+	__le32  status;
+	__le32  type;
+	__le32  load_addr;
+	uint8_t reserved[4];
+	uint8_t end[4];
+};
+
+#define TOC0_ITEM_INFO_NAME_CERT	0x00010101
+#define TOC0_ITEM_INFO_NAME_FIRMWARE	0x00010202
+#define TOC0_ITEM_INFO_NAME_KEY		0x00010303
+#define TOC0_ITEM_INFO_END		"IIE;"
+
+struct toc0_small_tag {
+	uint8_t tag;
+	uint8_t length;
+};
+
+typedef struct toc0_small_tag toc0_small_int;
+typedef struct toc0_small_tag toc0_small_oct;
+typedef struct toc0_small_tag toc0_small_seq;
+typedef struct toc0_small_tag toc0_small_exp;
+
+#define TOC0_SMALL_INT(len) { 0x02, (len) }
+#define TOC0_SMALL_SEQ(len) { 0x30, (len) }
+#define TOC0_SMALL_EXP(tag, len) { 0xa0 | (tag), len }
+
+struct toc0_large_tag {
+	uint8_t tag;
+	uint8_t prefix;
+	uint8_t length_hi;
+	uint8_t length_lo;
+};
+
+typedef struct toc0_large_tag toc0_large_int;
+typedef struct toc0_large_tag toc0_large_bit;
+typedef struct toc0_large_tag toc0_large_seq;
+
+#define TOC0_LARGE_INT(len) { 0x02, 0x82, (len) >> 8, (len) & 0xff }
+#define TOC0_LARGE_BIT(len) { 0x03, 0x82, (len) >> 8, (len) & 0xff }
+#define TOC0_LARGE_SEQ(len) { 0x30, 0x82, (len) >> 8, (len) & 0xff }
+
+/*
+ * This looks somewhat like an X.509 certificate, but it is not valid BER.
+ *
+ * Some differences:
+ *  - Some X.509 certificate fields are missing or rearranged.
+ *  - Some sequences have the wrong tag.
+ *  - Zero-length sequences are accepted.
+ *  - Large strings and integers must be an even number of bytes long.
+ *  - Positive integers are not zero-extended to maintain their sign.
+ *
+ * See https://linux-sunxi.org/TOC0 for more information.
+ */
+struct toc0_cert_item {
+	toc0_large_seq tag_totalSequence;
+	struct toc0_totalSequence {
+		toc0_large_seq tag_mainSequence;
+		struct toc0_mainSequence {
+			toc0_small_exp tag_explicit0;
+			struct toc0_explicit0 {
+				toc0_small_int tag_version;
+				uint8_t version;
+			} explicit0;
+			toc0_small_int tag_serialNumber;
+			uint8_t serialNumber;
+			toc0_small_seq tag_signature;
+			toc0_small_seq tag_issuer;
+			toc0_small_seq tag_validity;
+			toc0_small_seq tag_subject;
+			toc0_large_seq tag_subjectPublicKeyInfo;
+			struct toc0_subjectPublicKeyInfo {
+				toc0_small_seq tag_algorithm;
+				toc0_large_seq tag_publicKey;
+				struct toc0_publicKey {
+					toc0_large_int tag_n;
+					uint8_t n[256];
+					toc0_small_int tag_e;
+					uint8_t e[3];
+				} publicKey;
+			} subjectPublicKeyInfo;
+			toc0_small_exp tag_explicit3;
+			struct toc0_explicit3 {
+				toc0_small_seq tag_extension;
+				struct toc0_extension {
+					toc0_small_int tag_digest;
+					uint8_t digest[32];
+				} extension;
+			} explicit3;
+		} mainSequence;
+		toc0_large_bit tag_sigSequence;
+		struct toc0_sigSequence {
+			toc0_small_seq tag_algorithm;
+			toc0_large_bit tag_signature;
+			uint8_t signature[256];
+		} sigSequence;
+	} totalSequence;
+};
+
+#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
+
+#define TOC0_CERT_ITEM {									\
+	TOC0_LARGE_SEQ(sizeof(struct toc0_totalSequence)),					\
+	{											\
+		TOC0_LARGE_SEQ(sizeof(struct toc0_mainSequence)),				\
+		{										\
+			TOC0_SMALL_EXP(0, sizeof(struct toc0_explicit0)),			\
+			{									\
+				TOC0_SMALL_INT(sizeof_field(struct toc0_explicit0, version)),	\
+				0,								\
+			},									\
+			TOC0_SMALL_INT(sizeof_field(struct toc0_mainSequence, serialNumber)),	\
+			0,									\
+			TOC0_SMALL_SEQ(0),							\
+			TOC0_SMALL_SEQ(0),							\
+			TOC0_SMALL_SEQ(0),							\
+			TOC0_SMALL_SEQ(0),							\
+			TOC0_LARGE_SEQ(sizeof(struct toc0_subjectPublicKeyInfo)),		\
+			{									\
+				TOC0_SMALL_SEQ(0),						\
+				TOC0_LARGE_SEQ(sizeof(struct toc0_publicKey)),			\
+				{								\
+					TOC0_LARGE_INT(sizeof_field(struct toc0_publicKey, n)),	\
+					{},							\
+					TOC0_SMALL_INT(sizeof_field(struct toc0_publicKey, e)),	\
+					{},							\
+				},								\
+			},									\
+			TOC0_SMALL_EXP(3, sizeof(struct toc0_explicit3)),			\
+			{									\
+				TOC0_SMALL_SEQ(sizeof(struct toc0_extension)),			\
+				{								\
+					TOC0_SMALL_INT(sizeof_field(struct toc0_extension, digest)), \
+					{},							\
+				},								\
+			},									\
+		},										\
+		TOC0_LARGE_BIT(sizeof(struct toc0_sigSequence)),				\
+		{										\
+			TOC0_SMALL_SEQ(0),							\
+			TOC0_LARGE_BIT(sizeof_field(struct toc0_sigSequence, signature)),	\
+			{},									\
+		},										\
+	},											\
+}
+
+struct toc0_key_item {
+	__le32  vendor_id;
+	__le32  key0_n_len;
+	__le32  key0_e_len;
+	__le32  key1_n_len;
+	__le32  key1_e_len;
+	__le32  sig_len;
+	uint8_t key0[512];
+	uint8_t key1[512];
+	uint8_t reserved[32];
+	uint8_t sig[256];
+};
+
+#define TOC0_DEFAULT_NUM_ITEMS		3
+#define TOC0_DEFAULT_HEADER_LEN						  \
+	ALIGN(								  \
+		sizeof(struct toc0_main_info)				+ \
+		sizeof(struct toc0_item_info) *	TOC0_DEFAULT_NUM_ITEMS	+ \
+		sizeof(struct toc0_cert_item)				+ \
+		sizeof(struct toc0_key_item),				  \
+	32)
+
 #endif
diff --git a/tools/Makefile b/tools/Makefile
index 8843185703c..cb8418466f0 100644
--- a/tools/Makefile
+++ b/tools/Makefile
@@ -79,6 +79,7 @@ AES_OBJS-$(CONFIG_FIT_CIPHER) := $(addprefix lib/aes/, \
 OPENSSL_OBJS-$(CONFIG_MKIMAGE_LINK_OPENSSL) := \
 			lib/fdt-libcrypto.o \
 			mxsimage.o \
+			sunxi_toc0.o \
 
 ROCKCHIP_OBS = lib/rc4.o rkcommon.o rkimage.o rksd.o rkspi.o
 
diff --git a/tools/sunxi_toc0.c b/tools/sunxi_toc0.c
new file mode 100644
index 00000000000..f0bf86b477c
--- /dev/null
+++ b/tools/sunxi_toc0.c
@@ -0,0 +1,710 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * (C) Copyright 2018 Arm Ltd.
+ * (C) Copyright 2020-2021 Samuel Holland <samuel@sholland.org>
+ */
+
+#include <assert.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <openssl/asn1t.h>
+#include <openssl/pem.h>
+#include <openssl/rsa.h>
+
+#include <image.h>
+#include <sunxi_image.h>
+
+#include "imagetool.h"
+#include "mkimage.h"
+
+/*
+ * NAND requires 8K padding. For other devices, BROM requires only
+ * 512B padding, but let's use the larger padding to cover everything.
+ */
+#define PAD_SIZE		8192
+
+#define pr_err(fmt, args...)	fprintf(stderr, "TOC0 ERR: " fmt, ##args)
+#define pr_warn(fmt, args...)	fprintf(stderr, "TOC0 WRN: " fmt, ##args)
+#define pr_info(fmt, args...)	fprintf(stderr, "TOC0 INF: " fmt, ##args)
+
+static char *fw_key_file   = "fw_key.pem";
+static char *key_item_file = "key_item.bin";
+static char *root_key_file = "root_key.pem";
+
+/*
+ * Create a key item in @buf, containing the public keys @root_key and @fw_key,
+ * and signed by the RSA key @root_key.
+ */
+static int toc0_create_key_item(uint8_t *buf, uint32_t *len,
+				RSA *root_key, RSA *fw_key)
+{
+	struct toc0_key_item *key_item = (void *)buf;
+	uint8_t digest[SHA256_DIGEST_LENGTH];
+	int ret = EXIT_FAILURE;
+	unsigned int sig_len;
+	int n_len, e_len;
+
+	/* Store key 0. */
+	n_len = BN_bn2bin(RSA_get0_n(root_key), key_item->key0);
+	e_len = BN_bn2bin(RSA_get0_e(root_key), key_item->key0 + n_len);
+	if (n_len + e_len > sizeof(key_item->key0)) {
+		pr_err("Root key is too large\n");
+		goto err;
+	}
+	key_item->key0_n_len = cpu_to_le32(n_len);
+	key_item->key0_e_len = cpu_to_le32(e_len);
+
+	/* Store key 1. */
+	n_len = BN_bn2bin(RSA_get0_n(fw_key), key_item->key1);
+	e_len = BN_bn2bin(RSA_get0_e(fw_key), key_item->key1 + n_len);
+	if (n_len + e_len > sizeof(key_item->key1)) {
+		pr_err("Firmware key is too large\n");
+		goto err;
+	}
+	key_item->key1_n_len = cpu_to_le32(n_len);
+	key_item->key1_e_len = cpu_to_le32(e_len);
+
+	/* Sign the key item. */
+	key_item->sig_len = cpu_to_le32(RSA_size(root_key));
+	SHA256(buf, key_item->sig - buf, digest);
+	if (!RSA_sign(NID_sha256, digest, sizeof(digest),
+		      key_item->sig, &sig_len, root_key)) {
+		pr_err("Failed to sign key item\n");
+		goto err;
+	}
+	if (sig_len != sizeof(key_item->sig)) {
+		pr_err("Signature length mismatch\n");
+		goto err;
+	}
+
+	*len = sizeof(*key_item);
+	ret = EXIT_SUCCESS;
+
+err:
+	return ret;
+}
+
+/*
+ * Verify the key item in @buf, containing two public keys @key0 and @key1,
+ * and signed by the RSA key @key0. If @root_key is provided, only signatures
+ * by that key will be accepted. @key1 is returned in @key.
+ */
+static int toc0_verify_key_item(const uint8_t *buf, uint32_t len,
+				RSA *root_key, RSA **fw_key)
+{
+	struct toc0_key_item *key_item = (void *)buf;
+	uint8_t digest[SHA256_DIGEST_LENGTH];
+	int ret = EXIT_FAILURE;
+	int n_len, e_len;
+	RSA *key0 = NULL;
+	RSA *key1 = NULL;
+	BIGNUM *n, *e;
+
+	if (len < sizeof(*key_item))
+		goto err;
+
+	/* Load key 0. */
+	n_len = le32_to_cpu(key_item->key0_n_len);
+	e_len = le32_to_cpu(key_item->key0_e_len);
+	if (n_len + e_len > sizeof(key_item->key0))
+		goto err;
+	n = BN_bin2bn(key_item->key0, n_len, NULL);
+	e = BN_bin2bn(key_item->key0 + n_len, e_len, NULL);
+	key0 = RSA_new();
+	if (!key0)
+		goto err;
+	if (!RSA_set0_key(key0, n, e, NULL))
+		goto err;
+
+	/* If a root key was provided, compare it to key 0. */
+	if (root_key && (BN_cmp(n, RSA_get0_n(root_key)) ||
+			 BN_cmp(e, RSA_get0_e(root_key)))) {
+		pr_err("Root key mismatch\n");
+		goto err;
+	}
+
+	/* Verify the key item signature. */
+	SHA256(buf, key_item->sig - buf, digest);
+	if (!RSA_verify(NID_sha256, digest, sizeof(digest),
+			key_item->sig, le32_to_cpu(key_item->sig_len), key0)) {
+		pr_err("Bad key item signature\n");
+		goto err;
+	}
+
+	if (fw_key) {
+		/* Load key 1. */
+		n_len = le32_to_cpu(key_item->key1_n_len);
+		e_len = le32_to_cpu(key_item->key1_e_len);
+		if (n_len + e_len > sizeof(key_item->key1))
+			goto err;
+		n = BN_bin2bn(key_item->key1, n_len, NULL);
+		e = BN_bin2bn(key_item->key1 + n_len, e_len, NULL);
+		key1 = RSA_new();
+		if (!key1)
+			goto err;
+		if (!RSA_set0_key(key1, n, e, NULL))
+			goto err;
+
+		if (*fw_key) {
+			/* If a FW key was provided, compare it to key 1. */
+			if (BN_cmp(n, RSA_get0_n(*fw_key)) ||
+			    BN_cmp(e, RSA_get0_e(*fw_key))) {
+				pr_err("Firmware key mismatch\n");
+				goto err;
+			}
+		} else {
+			/* Otherwise, send key1 back to the caller. */
+			*fw_key = key1;
+			key1 = NULL;
+		}
+	}
+
+	ret = EXIT_SUCCESS;
+
+err:
+	RSA_free(key0);
+	RSA_free(key1);
+
+	return ret;
+}
+
+/*
+ * Create a certificate in @buf, describing the firmware with SHA256 digest
+ * @digest, and signed by the RSA key @fw_key.
+ */
+static int toc0_create_cert_item(uint8_t *buf, uint32_t *len, RSA *fw_key,
+				 uint8_t digest[static SHA256_DIGEST_LENGTH])
+{
+	static const struct toc0_cert_item cert_item_template = TOC0_CERT_ITEM;
+	struct toc0_cert_item *cert_item = (void *)buf;
+	uint8_t cert_digest[SHA256_DIGEST_LENGTH];
+	struct toc0_totalSequence *totalSequence;
+	struct toc0_sigSequence *sigSequence;
+	struct toc0_extension *extension;
+	struct toc0_publicKey *publicKey;
+	int ret = EXIT_FAILURE;
+	unsigned int sig_len;
+
+	memcpy(cert_item, &cert_item_template, sizeof(*cert_item));
+	*len = sizeof(*cert_item);
+
+	/*
+	 * Fill in the public key.
+	 *
+	 * Only 2048-bit RSA keys are supported. Since this uses a fixed-size
+	 * structure, it may fail for non-standard exponents.
+	 */
+	totalSequence = &cert_item->totalSequence;
+	publicKey = &totalSequence->mainSequence.subjectPublicKeyInfo.publicKey;
+	if (BN_bn2binpad(RSA_get0_n(fw_key), publicKey->n, sizeof(publicKey->n)) < 0 ||
+	    BN_bn2binpad(RSA_get0_e(fw_key), publicKey->e, sizeof(publicKey->e)) < 0) {
+		pr_err("Incorrect key size\n");
+		goto err;
+	}
+
+	/* Fill in the firmware digest. */
+	extension = &totalSequence->mainSequence.explicit3.extension;
+	memcpy(&extension->digest, digest, SHA256_DIGEST_LENGTH);
+
+	/*
+	 * Sign the certificate.
+	 *
+	 * In older SBROM versions (and by default in newer versions),
+	 * the last 4 bytes of the certificate are not signed.
+	 *
+	 * (The buffer passed to SHA256 starts at tag_mainSequence, but
+	 *  the buffer size does not include the length of that tag.)
+	 */
+	SHA256((uint8_t *)totalSequence, sizeof(struct toc0_mainSequence),
+	       cert_digest);
+	sigSequence = &totalSequence->sigSequence;
+	if (!RSA_sign(NID_sha256, cert_digest, SHA256_DIGEST_LENGTH,
+		      sigSequence->signature, &sig_len, fw_key)) {
+		pr_err("Failed to sign certificate\n");
+		goto err;
+	}
+	if (sig_len != sizeof(sigSequence->signature)) {
+		pr_err("Signature length mismatch\n");
+		goto err;
+	}
+
+	ret = EXIT_SUCCESS;
+
+err:
+	return ret;
+}
+
+/*
+ * Verify the certificate in @buf, describing the firmware with SHA256 digest
+ * @digest, and signed by the RSA key contained within. If @fw_key is provided,
+ * only that key will be accepted.
+ *
+ * This function is only expected to work with images created by mkimage.
+ */
+static int toc0_verify_cert_item(const uint8_t *buf, uint32_t len, RSA *fw_key,
+				 uint8_t digest[static SHA256_DIGEST_LENGTH])
+{
+	const struct toc0_cert_item *cert_item = (const void *)buf;
+	uint8_t cert_digest[SHA256_DIGEST_LENGTH];
+	const struct toc0_totalSequence *totalSequence;
+	const struct toc0_sigSequence *sigSequence;
+	const struct toc0_extension *extension;
+	const struct toc0_publicKey *publicKey;
+	int ret = EXIT_FAILURE;
+	RSA *key = NULL;
+	BIGNUM *n, *e;
+
+	/* Extract the public key from the certificate. */
+	totalSequence = &cert_item->totalSequence;
+	publicKey = &totalSequence->mainSequence.subjectPublicKeyInfo.publicKey;
+	n = BN_bin2bn(publicKey->n, sizeof(publicKey->n), NULL);
+	e = BN_bin2bn(publicKey->e, sizeof(publicKey->e), NULL);
+	key = RSA_new();
+	if (!key)
+		goto err;
+	if (!RSA_set0_key(key, n, e, NULL))
+		goto err;
+
+	/* If a key was provided, compare it to the embedded key. */
+	if (fw_key && (BN_cmp(RSA_get0_n(key), RSA_get0_n(fw_key)) ||
+		       BN_cmp(RSA_get0_e(key), RSA_get0_e(fw_key)))) {
+		pr_err("Firmware key mismatch\n");
+		goto err;
+	}
+
+	/* If a digest was provided, compare it to the embedded digest. */
+	extension = &totalSequence->mainSequence.explicit3.extension;
+	if (digest && memcmp(&extension->digest, digest, SHA256_DIGEST_LENGTH)) {
+		pr_err("Firmware digest mismatch\n");
+		goto err;
+	}
+
+	/* Verify the certificate's signature. See the comment above. */
+	SHA256((uint8_t *)totalSequence, sizeof(struct toc0_mainSequence),
+	       cert_digest);
+	sigSequence = &totalSequence->sigSequence;
+	if (!RSA_verify(NID_sha256, cert_digest, SHA256_DIGEST_LENGTH,
+			sigSequence->signature,
+			sizeof(sigSequence->signature), key)) {
+		pr_err("Bad certificate signature\n");
+		goto err;
+	}
+
+	ret = EXIT_SUCCESS;
+
+err:
+	RSA_free(key);
+
+	return ret;
+}
+
+/*
+ * Always create a TOC0 containing 3 items. The extra item will be ignored on
+ * SoCs which do not support it.
+ */
+static int toc0_create(uint8_t *buf, uint32_t len, RSA *root_key, RSA *fw_key,
+		       uint8_t *key_item, uint32_t key_item_len,
+		       uint8_t *fw_item, uint32_t fw_item_len, uint32_t fw_addr)
+{
+	struct toc0_main_info *main = (void *)buf;
+	struct toc0_item_info *item = (void *)(main + 1);
+	uint8_t digest[SHA256_DIGEST_LENGTH];
+	uint32_t *buf32 = (void *)buf;
+	RSA *orig_fw_key = fw_key;
+	int ret = EXIT_FAILURE;
+	uint32_t checksum = 0;
+	uint32_t item_offset;
+	uint32_t item_length;
+	int i;
+
+	/* Hash the firmware for inclusion in the certificate. */
+	SHA256(fw_item, fw_item_len, digest);
+
+	/* Create the main TOC0 header, containing three items. */
+	memcpy(main->name, TOC0_MAIN_INFO_NAME, sizeof(main->name));
+	main->magic	= cpu_to_le32(TOC0_MAIN_INFO_MAGIC);
+	main->checksum	= cpu_to_le32(BROM_STAMP_VALUE);
+	main->num_items	= cpu_to_le32(TOC0_DEFAULT_NUM_ITEMS);
+	memcpy(main->end, TOC0_MAIN_INFO_END, sizeof(main->end));
+
+	/* The first item links the ROTPK to the signing key. */
+	item_offset = sizeof(*main) + TOC0_DEFAULT_NUM_ITEMS * sizeof(*item);
+	/* Using an existing key item avoids needing the root private key. */
+	if (key_item) {
+		item_length = sizeof(*key_item);
+		if (toc0_verify_key_item(key_item, item_length,
+					 root_key, &fw_key))
+			goto err;
+		memcpy(buf + item_offset, key_item, item_length);
+	} else if (toc0_create_key_item(buf + item_offset, &item_length,
+					root_key, fw_key)) {
+		goto err;
+	}
+
+	item->name	= cpu_to_le32(TOC0_ITEM_INFO_NAME_KEY);
+	item->offset	= cpu_to_le32(item_offset);
+	item->length	= cpu_to_le32(item_length);
+	memcpy(item->end, TOC0_ITEM_INFO_END, sizeof(item->end));
+
+	/* The second item contains a certificate signed by the firmware key. */
+	item_offset = item_offset + item_length;
+	if (toc0_create_cert_item(buf + item_offset, &item_length,
+				  fw_key, digest))
+		goto err;
+
+	item++;
+	item->name	= cpu_to_le32(TOC0_ITEM_INFO_NAME_CERT);
+	item->offset	= cpu_to_le32(item_offset);
+	item->length	= cpu_to_le32(item_length);
+	memcpy(item->end, TOC0_ITEM_INFO_END, sizeof(item->end));
+
+	/* The third item contains the actual boot code. */
+	item_offset = ALIGN(item_offset + item_length, 32);
+	item_length = fw_item_len;
+	if (buf + item_offset != fw_item)
+		memmove(buf + item_offset, fw_item, item_length);
+
+	item++;
+	item->name	= cpu_to_le32(TOC0_ITEM_INFO_NAME_FIRMWARE);
+	item->offset	= cpu_to_le32(item_offset);
+	item->length	= cpu_to_le32(item_length);
+	item->load_addr	= cpu_to_le32(fw_addr);
+	memcpy(item->end, TOC0_ITEM_INFO_END, sizeof(item->end));
+
+	/* Pad to the required block size with 0xff to be flash-friendly. */
+	item_offset = item_offset + item_length;
+	item_length = ALIGN(item_offset, PAD_SIZE) - item_offset;
+	memset(buf + item_offset, 0xff, item_length);
+
+	/* Fill in the total padded file length. */
+	item_offset = item_offset + item_length;
+	main->length = cpu_to_le32(item_offset);
+
+	/* Verify enough space was provided when creating the image. */
+	assert(len >= item_offset);
+
+	/* Calculate the checksum. Yes, it's that simple. */
+	for (i = 0; i < item_offset / 4; ++i)
+		checksum += le32_to_cpu(buf32[i]);
+	main->checksum = cpu_to_le32(checksum);
+
+	ret = EXIT_SUCCESS;
+
+err:
+	if (fw_key != orig_fw_key)
+		RSA_free(fw_key);
+
+	return ret;
+}
+
+static const struct toc0_item_info *
+toc0_find_item(const struct toc0_main_info *main,
+	       uint32_t name, uint32_t *offset, uint32_t *length)
+{
+	const struct toc0_item_info *item = (void *)(main + 1);
+	uint32_t item_offset, item_length;
+	uint32_t num_items, main_length;
+	int i;
+
+	num_items   = le32_to_cpu(main->num_items);
+	main_length = le32_to_cpu(main->length);
+
+	for (i = 0; i < num_items; ++i, ++item) {
+		if (le32_to_cpu(item->name) != name)
+			continue;
+
+		item_offset = le32_to_cpu(item->offset);
+		item_length = le32_to_cpu(item->length);
+
+		if (item_offset > main_length ||
+		    item_length > main_length - item_offset)
+			continue;
+
+		*offset = item_offset;
+		*length = item_length;
+
+		return item;
+	}
+
+	return NULL;
+}
+
+static int toc0_verify(const uint8_t *buf, uint32_t len, RSA *root_key)
+{
+	const struct toc0_main_info *main = (void *)buf;
+	const struct toc0_item_info *item;
+	uint8_t digest[SHA256_DIGEST_LENGTH];
+	uint32_t main_length = le32_to_cpu(main->length);
+	uint32_t checksum = BROM_STAMP_VALUE;
+	uint32_t *buf32 = (void *)buf;
+	uint32_t length, offset;
+	int ret = EXIT_FAILURE;
+	RSA *fw_key = NULL;
+	int i;
+
+	if (len < main_length)
+		goto err;
+
+	/* Verify the main header. */
+	if (memcmp(main->name, TOC0_MAIN_INFO_NAME, sizeof(main->name)))
+		goto err;
+	if (le32_to_cpu(main->magic) != TOC0_MAIN_INFO_MAGIC)
+		goto err;
+	/* Verify the checksum without modifying the buffer. */
+	for (i = 0; i < main_length / 4; ++i)
+		checksum += le32_to_cpu(buf32[i]);
+	if (checksum != 2 * le32_to_cpu(main->checksum))
+		goto err;
+	/* The length must be at least 512 byte aligned. */
+	if (main_length % 512)
+		goto err;
+	if (memcmp(main->end, TOC0_MAIN_INFO_END, sizeof(main->end)))
+		goto err;
+
+	/* Verify the key item if present. */
+	item = toc0_find_item(main, TOC0_ITEM_INFO_NAME_KEY, &offset, &length);
+	if (!item)
+		fw_key = root_key;
+	else if (toc0_verify_key_item(buf + offset, length, root_key, &fw_key))
+		goto err;
+
+	/* Hash the firmware to compare with the certificate. */
+	item = toc0_find_item(main, TOC0_ITEM_INFO_NAME_FIRMWARE, &offset, &length);
+	if (!item) {
+		pr_err("Image does not contain a firmware item\n");
+		goto err;
+	}
+	SHA256(buf + offset, length, digest);
+
+	/* Verify the certificate item. */
+	item = toc0_find_item(main, TOC0_ITEM_INFO_NAME_CERT, &offset, &length);
+	if (!item) {
+		pr_err("Image does not contain a certificate item\n");
+		goto err;
+	}
+	if (toc0_verify_cert_item(buf + offset, length, fw_key, digest))
+		goto err;
+
+	ret = EXIT_SUCCESS;
+
+err:
+	if (fw_key != root_key)
+		RSA_free(fw_key);
+
+	return ret;
+}
+
+static int toc0_check_params(struct image_tool_params *params)
+{
+	if (!params->dflag)
+		return -EINVAL;
+
+	if (params->keydir) {
+		asprintf(&fw_key_file, "%s/%s", params->keydir, fw_key_file);
+		asprintf(&key_item_file, "%s/%s", params->keydir, key_item_file);
+		asprintf(&root_key_file, "%s/%s", params->keydir, root_key_file);
+	}
+
+	return 0;
+}
+
+static int toc0_verify_header(unsigned char *buf, int image_size,
+			      struct image_tool_params *params)
+{
+	int ret = EXIT_FAILURE;
+	RSA *root_key = NULL;
+	FILE *fp;
+
+	/* A root public key is optional. */
+	fp = fopen(root_key_file, "rb");
+	if (fp) {
+		pr_info("Verifying image with existing root key\n");
+		root_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
+		if (!root_key)
+			root_key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);
+		fclose(fp);
+		if (!root_key) {
+			pr_err("Failed to read public key from '%s'\n",
+			       root_key_file);
+			goto err;
+		}
+	}
+
+	ret = toc0_verify(buf, image_size, root_key);
+
+err:
+	RSA_free(root_key);
+
+	return ret;
+}
+
+static const char *toc0_item_name(uint32_t name)
+{
+	if (name == TOC0_ITEM_INFO_NAME_CERT)
+		return "Certificate";
+	if (name == TOC0_ITEM_INFO_NAME_FIRMWARE)
+		return "Firmware";
+	if (name == TOC0_ITEM_INFO_NAME_KEY)
+		return "Key";
+	return "(unknown)";
+}
+
+static void toc0_print_header(const void *buf)
+{
+	const struct toc0_main_info *main = buf;
+	const struct toc0_item_info *item = (void *)(main + 1);
+	uint32_t head_length, main_length, num_items;
+	uint32_t item_offset, item_length, item_name;
+	int load_addr = -1;
+	int i;
+
+	num_items   = le32_to_cpu(main->num_items);
+	head_length = sizeof(*main) + num_items * sizeof(*item);
+	main_length = le32_to_cpu(main->length);
+
+	printf("Allwinner TOC0 Image\n"
+	       "Size: %d bytes\n"
+	       "Contents: %d items\n"
+	       " 00000000:%08x Headers\n",
+	       main_length, num_items, head_length);
+
+	for (i = 0; i < num_items; ++i, ++item) {
+		item_offset = le32_to_cpu(item->offset);
+		item_length = le32_to_cpu(item->length);
+		item_name   = le32_to_cpu(item->name);
+
+		if (item_name == TOC0_ITEM_INFO_NAME_FIRMWARE)
+			load_addr = le32_to_cpu(item->load_addr);
+
+		printf(" %08x:%08x %s\n",
+		       item_offset, item_length,
+		       toc0_item_name(item_name));
+	}
+
+	if (num_items && item_offset + item_length < main_length) {
+		item_offset = item_offset + item_length;
+		item_length = main_length - item_offset;
+
+		printf(" %08x:%08x Padding\n",
+		       item_offset, item_length);
+	}
+
+	if (load_addr != -1)
+		printf("Load address: 0x%08x\n", load_addr);
+}
+
+static void toc0_set_header(void *buf, struct stat *sbuf, int ifd,
+			    struct image_tool_params *params)
+{
+	uint32_t key_item_len = 0;
+	uint8_t *key_item = NULL;
+	int ret = EXIT_FAILURE;
+	RSA *root_key = NULL;
+	RSA *fw_key = NULL;
+	FILE *fp;
+
+	/* Either a key item or the root private key is required. */
+	fp = fopen(key_item_file, "rb");
+	if (fp) {
+		pr_info("Creating image using existing key item\n");
+		key_item_len = sizeof(struct toc0_key_item);
+		key_item = OPENSSL_malloc(key_item_len);
+		if (!key_item || fread(key_item, key_item_len, 1, fp) != 1) {
+			pr_err("Failed to read key item from '%s'\n",
+			       root_key_file);
+			goto err;
+		}
+		fclose(fp);
+		fp = NULL;
+	}
+
+	fp = fopen(root_key_file, "rb");
+	if (fp) {
+		root_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
+		if (!root_key)
+			root_key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);
+		fclose(fp);
+		fp = NULL;
+	}
+
+	/* When using an existing key item, the root key is optional. */
+	if (!key_item && (!root_key || !RSA_get0_d(root_key))) {
+		pr_err("Failed to read private key from '%s'\n",
+		       root_key_file);
+		goto err;
+	}
+
+	/* The certificate/firmware private key is always required. */
+	fp = fopen(fw_key_file, "rb");
+	if (fp) {
+		fw_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
+		fclose(fp);
+		fp = NULL;
+	}
+	if (!fw_key) {
+		/* If the root key is a private key, it can be used instead. */
+		if (root_key && RSA_get0_d(root_key)) {
+			pr_info("Using root key as firmware key\n");
+			fw_key = root_key;
+		} else {
+			pr_err("Failed to read private key from '%s'\n",
+			       fw_key_file);
+			goto err;
+		}
+	}
+
+	/* Warn about potential compatiblity issues. */
+	if (key_item || fw_key != root_key)
+		pr_warn("Only H6 supports separate root and firmware keys\n");
+
+	ret = toc0_create(buf, params->file_size, root_key, fw_key,
+			  key_item, key_item_len,
+			  buf + TOC0_DEFAULT_HEADER_LEN,
+			  params->orig_file_size, params->addr);
+
+err:
+	OPENSSL_free(key_item);
+	OPENSSL_free(root_key);
+	if (fw_key != root_key)
+		OPENSSL_free(fw_key);
+	if (fp)
+		fclose(fp);
+
+	if (ret != EXIT_SUCCESS)
+		exit(ret);
+}
+
+static int toc0_check_image_type(uint8_t type)
+{
+	return type == IH_TYPE_SUNXI_TOC0 ? 0 : 1;
+}
+
+static int toc0_vrec_header(struct image_tool_params *params,
+			    struct image_type_params *tparams)
+{
+	tparams->hdr = calloc(tparams->header_size, 1);
+
+	/* Save off the unpadded data size for SHA256 calculation. */
+	params->orig_file_size = params->file_size - TOC0_DEFAULT_HEADER_LEN;
+
+	/* Return padding to 8K blocks. */
+	return ALIGN(params->file_size, PAD_SIZE) - params->file_size;
+}
+
+U_BOOT_IMAGE_TYPE(
+	sunxi_toc0,
+	"Allwinner TOC0 Boot Image support",
+	TOC0_DEFAULT_HEADER_LEN,
+	NULL,
+	toc0_check_params,
+	toc0_verify_header,
+	toc0_print_header,
+	toc0_set_header,
+	NULL,
+	toc0_check_image_type,
+	NULL,
+	toc0_vrec_header
+);
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 3/4] sunxi: Support both SPL image types
  2021-06-21  2:55 [PATCH 0/4] sunxi: TOC0 image type support Samuel Holland
  2021-06-21  2:55 ` [PATCH 1/4] tools: Refactor mkimage linking with OpenSSL Samuel Holland
  2021-06-21  2:55 ` [PATCH 2/4] tools: mkimage: Add Allwinner TOC0 support Samuel Holland
@ 2021-06-21  2:55 ` Samuel Holland
  2021-06-21  2:55 ` [PATCH 4/4] sunxi: Support building a SPL as a TOC0 image Samuel Holland
  2021-06-21 15:43 ` [PATCH 0/4] sunxi: TOC0 image type support Andre Przywara
  4 siblings, 0 replies; 14+ messages in thread
From: Samuel Holland @ 2021-06-21  2:55 UTC (permalink / raw)
  To: Jagan Teki, Andre Przywara, Hans de Goede; +Cc: u-boot, Samuel Holland

SPL uses the image header to detect the boot device and to find the
offset of U-Boot proper. Since this information is stored differently in
eGON and TOC0 image headers, add code to find the correct value based on
the image type currently in use.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm/include/asm/arch-sunxi/spl.h |  2 --
 arch/arm/mach-sunxi/board.c           | 20 ++++++++++++++------
 include/sunxi_image.h                 | 14 ++++++++++++++
 3 files changed, 28 insertions(+), 8 deletions(-)

diff --git a/arch/arm/include/asm/arch-sunxi/spl.h b/arch/arm/include/asm/arch-sunxi/spl.h
index 58cdf806d9a..157b11e4897 100644
--- a/arch/arm/include/asm/arch-sunxi/spl.h
+++ b/arch/arm/include/asm/arch-sunxi/spl.h
@@ -19,8 +19,6 @@
 #define SUNXI_BOOTED_FROM_MMC0_HIGH	0x10
 #define SUNXI_BOOTED_FROM_MMC2_HIGH	0x12
 
-#define is_boot0_magic(addr)	(memcmp((void *)(addr), BOOT0_MAGIC, 8) == 0)
-
 uint32_t sunxi_get_boot_device(void);
 
 #endif
diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
index 9b84132eda6..8147f250f87 100644
--- a/arch/arm/mach-sunxi/board.c
+++ b/arch/arm/mach-sunxi/board.c
@@ -237,10 +237,13 @@ void s_init(void)
 
 static int sunxi_get_boot_source(void)
 {
-	if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */
-		return SUNXI_INVALID_BOOT_SOURCE;
+	if (is_egon_image((void *)SPL_ADDR))
+		return ((struct boot_file_head *)SPL_ADDR)->boot_media;
+	if (is_toc0_image((void *)SPL_ADDR))
+		return ((struct toc0_main_info *)SPL_ADDR)->platform[0];
 
-	return readb(SPL_ADDR + 0x28);
+	/* Not a valid BROM image, so we must have been booted via FEL. */
+	return SUNXI_INVALID_BOOT_SOURCE;
 }
 
 /* The sunxi internal brom will try to loader external bootloader
@@ -285,13 +288,18 @@ uint32_t sunxi_get_boot_device(void)
 	return -1;		/* Never reached */
 }
 
+#define is_toc0_magic(foo) true
+
 #ifdef CONFIG_SPL_BUILD
 static u32 sunxi_get_spl_size(void)
 {
-	if (!is_boot0_magic(SPL_ADDR + 4)) /* eGON.BT0 */
-		return 0;
+	if (is_egon_image((void *)SPL_ADDR))
+		return ((struct boot_file_head *)SPL_ADDR)->length;
+	if (is_toc0_image((void *)SPL_ADDR))
+		return ((struct toc0_main_info *)SPL_ADDR)->length;
 
-	return readl(SPL_ADDR + 0x10);
+	/* Unknown size, so fall back to the default offset. */
+	return 0;
 }
 
 /*
diff --git a/include/sunxi_image.h b/include/sunxi_image.h
index bdf80ec0e0a..b0424b6b7f1 100644
--- a/include/sunxi_image.h
+++ b/include/sunxi_image.h
@@ -270,4 +270,18 @@ struct toc0_key_item {
 		sizeof(struct toc0_key_item),				  \
 	32)
 
+static inline bool is_egon_image(void *addr)
+{
+	struct boot_file_head *head = addr;
+
+	return memcmp(head->magic, BOOT0_MAGIC, 8) == 0;
+}
+
+static inline bool is_toc0_image(void *addr)
+{
+	struct toc0_main_info *main = addr;
+
+	return memcmp(main->name, TOC0_MAIN_INFO_NAME, 8) == 0;
+}
+
 #endif
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* [PATCH 4/4] sunxi: Support building a SPL as a TOC0 image
  2021-06-21  2:55 [PATCH 0/4] sunxi: TOC0 image type support Samuel Holland
                   ` (2 preceding siblings ...)
  2021-06-21  2:55 ` [PATCH 3/4] sunxi: Support both SPL image types Samuel Holland
@ 2021-06-21  2:55 ` Samuel Holland
  2021-06-21 15:43 ` [PATCH 0/4] sunxi: TOC0 image type support Andre Przywara
  4 siblings, 0 replies; 14+ messages in thread
From: Samuel Holland @ 2021-06-21  2:55 UTC (permalink / raw)
  To: Jagan Teki, Andre Przywara, Hans de Goede; +Cc: u-boot, Samuel Holland

Now that mkimage can generate TOC0 images, and the SPL can interpret
them, hook up the build infrastructure so the user can choose which
image type to build.

Signed-off-by: Samuel Holland <samuel@sholland.org>
---
 arch/arm/mach-sunxi/Kconfig |  2 ++
 board/sunxi/Kconfig         | 24 ++++++++++++++++++++++++
 scripts/Makefile.spl        |  3 ++-
 3 files changed, 28 insertions(+), 1 deletion(-)
 create mode 100644 board/sunxi/Kconfig

diff --git a/arch/arm/mach-sunxi/Kconfig b/arch/arm/mach-sunxi/Kconfig
index bc8509b72a2..4c466325f3a 100644
--- a/arch/arm/mach-sunxi/Kconfig
+++ b/arch/arm/mach-sunxi/Kconfig
@@ -1088,6 +1088,8 @@ config BLUETOOTH_DT_DEVICE_FIXUP
 	  The used address is "bdaddr" if set, and "ethaddr" with the LSB
 	  flipped elsewise.
 
+source "board/sunxi/Kconfig"
+
 endif
 
 config CHIP_DIP_SCAN
diff --git a/board/sunxi/Kconfig b/board/sunxi/Kconfig
new file mode 100644
index 00000000000..c5c0929db52
--- /dev/null
+++ b/board/sunxi/Kconfig
@@ -0,0 +1,24 @@
+choice
+	prompt "SPL Image Type"
+	default SUNXI_SPL_IMAGE_EGON
+
+config SUNXI_SPL_IMAGE_EGON
+	bool "eGON (non-secure)"
+	help
+	  Select this option to embed the SPL binary in an eGON.BT0 image,
+	  which is compatible with the non-secure boot ROM (NBROM).
+
+	  This is usually the correct option to choose.
+
+config SUNXI_SPL_IMAGE_TOC0
+	bool "TOC0 (secure)"
+	help
+	  Select this option to embed the SPL binary in a TOC0 image,
+	  which is compatible with the secure boot ROM (SBROM).
+
+endchoice
+
+config SUNXI_SPL_IMAGE_TYPE
+	string
+	default "sunxi_egon" if SUNXI_SPL_IMAGE_EGON
+	default "sunxi_toc0" if SUNXI_SPL_IMAGE_TOC0
diff --git a/scripts/Makefile.spl b/scripts/Makefile.spl
index 5be1a9ba1b1..7cc78bb3186 100644
--- a/scripts/Makefile.spl
+++ b/scripts/Makefile.spl
@@ -414,7 +414,8 @@ endif
 $(obj)/$(SPL_BIN).sfp: $(obj)/$(SPL_BIN).bin FORCE
 	$(call if_changed,mkimage)
 
-MKIMAGEFLAGS_sunxi-spl.bin = -T sunxi_egon \
+MKIMAGEFLAGS_sunxi-spl.bin = -T $(CONFIG_SUNXI_SPL_IMAGE_TYPE) \
+	-a $(CONFIG_SPL_TEXT_BASE) \
 	-n $(CONFIG_DEFAULT_DEVICE_TREE)
 
 OBJCOPYFLAGS_u-boot-spl-dtb.hex := -I binary -O ihex --change-address=$(CONFIG_SPL_TEXT_BASE)
-- 
2.31.1


^ permalink raw reply related	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/4] sunxi: TOC0 image type support
  2021-06-21  2:55 [PATCH 0/4] sunxi: TOC0 image type support Samuel Holland
                   ` (3 preceding siblings ...)
  2021-06-21  2:55 ` [PATCH 4/4] sunxi: Support building a SPL as a TOC0 image Samuel Holland
@ 2021-06-21 15:43 ` Andre Przywara
  2021-06-21 20:35   ` Tom Rini
  4 siblings, 1 reply; 14+ messages in thread
From: Andre Przywara @ 2021-06-21 15:43 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Jagan Teki, Hans de Goede, u-boot, Tom Rini, Simon Glass,
	Jernej Škrabec

On Sun, 20 Jun 2021 21:55:51 -0500
Samuel Holland <samuel@sholland.org> wrote:

(CC:ing Tom and Simon for the compatibility problem below)

Hi,

> This series adds support for the TOC0 image format used by the Allwinner
> secure boot ROM (SBROM). This series has been tested on the following
> SoCs/boards, with the eFuse burnt to enable secure mode:
>   - A64: Pine A64 Plus
>   - H5: Orange Pi Zero Plus
>   - H6: Pine H64 Model B
>   - H616: Orange Pi Zero 2

many thanks for sending this. In general this looks good (will do a
more thorough review soon), just one thing that bothered me:

This requires OpenSLL 1.1.x. There is nothing really wrong about this,
but my (admittedly not the freshest) Slackware, but also long term
distros like RHEL/CentOS (<=7), still come with 1.0.x (headers) only.

I was wondering how important this is? I have the impression that
embedded developers sometimes use old^Wstable systems, so some people
might be bitten by it. I think in this case it will affect all user
trying to build mkimage, regardless of the target platform?

So I wanted to know what to do here?
- Can we provide some kind of compatibility support? OpenSSL seems
  to provide something:
https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes#Compatibility_Layer
  Haven't tested that fully yet, just downloading that tarball
  does not seem to cut it (or is missing files?). I guess one needs to
  copy&paste some code from the Wiki?
- Shall we detect missing v1.1.x support (via #if OPENSSL_VERSION_NUMBER
  < 0x10100000L) and disable just sunxi_toc0 support in this case?

Grateful for any opinions.

Cheers,
Andre


> 
> Samuel Holland (4):
>   tools: Refactor mkimage linking with OpenSSL
>   tools: mkimage: Add Allwinner TOC0 support
>   sunxi: Support both SPL image types
>   sunxi: Support building a SPL as a TOC0 image
> 
>  arch/arm/Kconfig                      |   1 +
>  arch/arm/include/asm/arch-sunxi/spl.h |   2 -
>  arch/arm/mach-imx/mxs/Kconfig         |   2 +
>  arch/arm/mach-mvebu/Kconfig           |   1 +
>  arch/arm/mach-sunxi/Kconfig           |   2 +
>  arch/arm/mach-sunxi/board.c           |  20 +-
>  board/sunxi/Kconfig                   |  24 +
>  common/Kconfig.boot                   |   2 +
>  common/image.c                        |   1 +
>  include/image.h                       |   1 +
>  include/sunxi_image.h                 | 205 ++++++++
>  scripts/Makefile.spl                  |   3 +-
>  scripts/config_whitelist.txt          |   1 -
>  tools/Kconfig                         |   3 +
>  tools/Makefile                        |  23 +-
>  tools/mxsimage.c                      |   3 -
>  tools/sunxi_toc0.c                    | 710 ++++++++++++++++++++++++++
>  17 files changed, 976 insertions(+), 28 deletions(-)
>  create mode 100644 board/sunxi/Kconfig
>  create mode 100644 tools/sunxi_toc0.c
> 


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/4] sunxi: TOC0 image type support
  2021-06-21 15:43 ` [PATCH 0/4] sunxi: TOC0 image type support Andre Przywara
@ 2021-06-21 20:35   ` Tom Rini
  2021-06-21 23:56     ` Andre Przywara
  0 siblings, 1 reply; 14+ messages in thread
From: Tom Rini @ 2021-06-21 20:35 UTC (permalink / raw)
  To: Andre Przywara
  Cc: Samuel Holland, Jagan Teki, Hans de Goede, u-boot, Simon Glass,
	Jernej Škrabec

[-- Attachment #1: Type: text/plain, Size: 2370 bytes --]

On Mon, Jun 21, 2021 at 04:43:00PM +0100, Andre Przywara wrote:
> On Sun, 20 Jun 2021 21:55:51 -0500
> Samuel Holland <samuel@sholland.org> wrote:
> 
> (CC:ing Tom and Simon for the compatibility problem below)
> 
> Hi,
> 
> > This series adds support for the TOC0 image format used by the Allwinner
> > secure boot ROM (SBROM). This series has been tested on the following
> > SoCs/boards, with the eFuse burnt to enable secure mode:
> >   - A64: Pine A64 Plus
> >   - H5: Orange Pi Zero Plus
> >   - H6: Pine H64 Model B
> >   - H616: Orange Pi Zero 2
> 
> many thanks for sending this. In general this looks good (will do a
> more thorough review soon), just one thing that bothered me:
> 
> This requires OpenSLL 1.1.x. There is nothing really wrong about this,
> but my (admittedly not the freshest) Slackware, but also long term
> distros like RHEL/CentOS (<=7), still come with 1.0.x (headers) only.
> 
> I was wondering how important this is? I have the impression that
> embedded developers sometimes use old^Wstable systems, so some people
> might be bitten by it. I think in this case it will affect all user
> trying to build mkimage, regardless of the target platform?
> 
> So I wanted to know what to do here?
> - Can we provide some kind of compatibility support? OpenSSL seems
>   to provide something:
> https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes#Compatibility_Layer
>   Haven't tested that fully yet, just downloading that tarball
>   does not seem to cut it (or is missing files?). I guess one needs to
>   copy&paste some code from the Wiki?
> - Shall we detect missing v1.1.x support (via #if OPENSSL_VERSION_NUMBER
>   < 0x10100000L) and disable just sunxi_toc0 support in this case?

There's two things.  First, the series should be on top of (sorry!)
https://patchwork.ozlabs.org/project/uboot/patch/20210524202317.1492578-1-mr.nuke.me@gmail.com/
which adds a similar Kconfig option to make building tools easier.

Second, while I think not supporting openssl 1.0.x is fine, I would like
to again ask for someone to spend the time looking at switching to one
of the GPL-compatible libraries as I'm pretty sure it's been raised a
few times that we can't link with openssl like we do.  This isn't a
blocker for the series, just an ask for help with a known problem.
Thanks!

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/4] sunxi: TOC0 image type support
  2021-06-21 20:35   ` Tom Rini
@ 2021-06-21 23:56     ` Andre Przywara
  2021-08-22  2:19       ` Samuel Holland
  0 siblings, 1 reply; 14+ messages in thread
From: Andre Przywara @ 2021-06-21 23:56 UTC (permalink / raw)
  To: Tom Rini
  Cc: Samuel Holland, Jagan Teki, Hans de Goede, u-boot, Simon Glass,
	Jernej Škrabec

On Mon, 21 Jun 2021 16:35:37 -0400
Tom Rini <trini@konsulko.com> wrote:

Hi Tom,

> On Mon, Jun 21, 2021 at 04:43:00PM +0100, Andre Przywara wrote:
> > On Sun, 20 Jun 2021 21:55:51 -0500
> > Samuel Holland <samuel@sholland.org> wrote:
> > 
> > (CC:ing Tom and Simon for the compatibility problem below)
> > 
> > Hi,
> >   
> > > This series adds support for the TOC0 image format used by the Allwinner
> > > secure boot ROM (SBROM). This series has been tested on the following
> > > SoCs/boards, with the eFuse burnt to enable secure mode:
> > >   - A64: Pine A64 Plus
> > >   - H5: Orange Pi Zero Plus
> > >   - H6: Pine H64 Model B
> > >   - H616: Orange Pi Zero 2  
> > 
> > many thanks for sending this. In general this looks good (will do a
> > more thorough review soon), just one thing that bothered me:
> > 
> > This requires OpenSLL 1.1.x. There is nothing really wrong about this,
> > but my (admittedly not the freshest) Slackware, but also long term
> > distros like RHEL/CentOS (<=7), still come with 1.0.x (headers) only.
> > 
> > I was wondering how important this is? I have the impression that
> > embedded developers sometimes use old^Wstable systems, so some people
> > might be bitten by it. I think in this case it will affect all user
> > trying to build mkimage, regardless of the target platform?
> > 
> > So I wanted to know what to do here?
> > - Can we provide some kind of compatibility support? OpenSSL seems
> >   to provide something:
> > https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes#Compatibility_Layer
> >   Haven't tested that fully yet, just downloading that tarball
> >   does not seem to cut it (or is missing files?). I guess one needs to
> >   copy&paste some code from the Wiki?
> > - Shall we detect missing v1.1.x support (via #if OPENSSL_VERSION_NUMBER
> >   < 0x10100000L) and disable just sunxi_toc0 support in this case?  
> 
> There's two things.  First, the series should be on top of (sorry!)
> https://patchwork.ozlabs.org/project/uboot/patch/20210524202317.1492578-1-mr.nuke.me@gmail.com/
> which adds a similar Kconfig option to make building tools easier.

So this is on top of Simon's large series? Poor Samuel! Is there a
branch somewhere?

> Second, while I think not supporting openssl 1.0.x is fine,

Well, this was not what I was hoping for ;-)
I followed the advice on the OpenSSL wiki and now have a rather small
compatibility header file, which lets me compile mkimage even against
OpenSSL v1.0.2u. It seems like kwbimage.c has similar provisions in
place, I guess this could be merged into the external header?
Happy to send a patch on top, if this seems useful.

> I would like
> to again ask for someone to spend the time looking at switching to one
> of the GPL-compatible libraries as I'm pretty sure it's been raised a
> few times that we can't link with openssl like we do.

Why is that? Because Apache is not compatible with GPLv2? The OpenSSL
webpage says that:
"Can I use OpenSSL with GPL software?
On many systems including the major Linux and BSD distributions, yes
(the GPL does not place restrictions on using libraries that are part
of the normal operating system distribution)."
And for mkimage we just build a regular userspace tool, which is linked
against the system installed OpenSSL library. From my understanding
this is what this quote above means with being permitted?

And what would be the alternatives? Take one of the smaller ones and
embed them into the code?
Otherwise we would probably need to pick something that is widely
available and shipped with distros, I guess? Like GnuTLS,
libgcrypt, nettle? Maybe LibreSSL?

Samuel, do you have an insight what would be a good fit?

Tom, do you have some pointer to previous discussions about this?

Cheers,
Andre


> This isn't a
> blocker for the series, just an ask for help with a known problem.
> Thanks!
> 

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 2/4] tools: mkimage: Add Allwinner TOC0 support
  2021-06-21  2:55 ` [PATCH 2/4] tools: mkimage: Add Allwinner TOC0 support Samuel Holland
@ 2021-06-22  1:07   ` Andre Przywara
  0 siblings, 0 replies; 14+ messages in thread
From: Andre Przywara @ 2021-06-22  1:07 UTC (permalink / raw)
  To: Samuel Holland; +Cc: Jagan Teki, Hans de Goede, u-boot

On Sun, 20 Jun 2021 21:55:53 -0500
Samuel Holland <samuel@sholland.org> wrote:

Hi Samuel,

many thanks for sending this, I like the idea of adding TOC0 support
to the venerable mkimage very much.

> Most Allwinner sunxi SoCs have separate boot ROMs in non-secure and
> secure mode. The non-secure boot ROM (NBROM) uses the existing
> sunxi_egon image type. The secure boot ROM (SBROM) uses a completely
> different image type, known as TOC0.
> 
> A TOC0 image is composed of a header and two or more items. These items
> include signed firmware and a key chain linking to a root-of-trust
> public key (ROTPK) hash burned to eFuses in the SoC. Signatures are made
> using RSA-2048 + SHA256.
> 
> This TOC0 implementation has been verified to work with the A64, H5, H6,
> and H616 SBROMs.

So as mentioned in the other mail, this requires OpenSSL v1.1.x.
I followed the suggestion on [1] and ended up with a compat header
file, which allows me to compile against v1.0.x installations. Any
objections against making this part of the series? Happy to provide
that patch.

[1]
https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes#Compatibility_Layer

Some warnings popped up with various (non-niche!) compilers:
 
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  arch/arm/Kconfig      |   1 +
>  common/image.c        |   1 +
>  include/image.h       |   1 +
>  include/sunxi_image.h | 191 ++++++++++++
>  tools/Makefile        |   1 +
>  tools/sunxi_toc0.c    | 710 ++++++++++++++++++++++++++++++++++++++++++
>  6 files changed, 905 insertions(+)
>  create mode 100644 tools/sunxi_toc0.c
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index 0448787b8bc..97bf21da2e2 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -998,6 +998,7 @@ config ARCH_SUNXI
>  	select DM_SCSI if SCSI
>  	select DM_SERIAL
>  	select DM_USB if DISTRO_DEFAULTS
> +	select MKIMAGE_LINK_OPENSSL
>  	select OF_BOARD_SETUP
>  	select OF_CONTROL
>  	select OF_SEPARATE
> diff --git a/common/image.c b/common/image.c
> index 51854aae5dd..d354d5d8d37 100644
> --- a/common/image.c
> +++ b/common/image.c
> @@ -191,6 +191,7 @@ static const table_entry_t uimage_type[] = {
>  	{	IH_TYPE_MTKIMAGE,   "mtk_image",   "MediaTek BootROM loadable Image" },
>  	{	IH_TYPE_COPRO, "copro", "Coprocessor Image"},
>  	{	IH_TYPE_SUNXI_EGON, "sunxi_egon",  "Allwinner eGON Boot Image" },
> +	{	IH_TYPE_SUNXI_TOC0, "sunxi_toc0",  "Allwinner TOC0 Boot Image" },
>  	{	-1,		    "",		  "",			},
>  };
>  
> diff --git a/include/image.h b/include/image.h
> index 459685d4d43..c01cd2982e6 100644
> --- a/include/image.h
> +++ b/include/image.h
> @@ -312,6 +312,7 @@ enum {
>  	IH_TYPE_IMX8IMAGE,		/* Freescale IMX8Boot Image	*/
>  	IH_TYPE_COPRO,			/* Coprocessor Image for remoteproc*/
>  	IH_TYPE_SUNXI_EGON,		/* Allwinner eGON Boot Image */
> +	IH_TYPE_SUNXI_TOC0,		/* Allwinner TOC0 Boot Image */
>  
>  	IH_TYPE_COUNT,			/* Number of image types */
>  };
> diff --git a/include/sunxi_image.h b/include/sunxi_image.h
> index 5b2055c0af3..bdf80ec0e0a 100644
> --- a/include/sunxi_image.h
> +++ b/include/sunxi_image.h
> @@ -9,9 +9,12 @@
>   *
>   * Shared between mkimage and the SPL.
>   */
> +
>  #ifndef	SUNXI_IMAGE_H
>  #define	SUNXI_IMAGE_H
>  
> +#include <linux/types.h>
> +
>  #define BOOT0_MAGIC		"eGON.BT0"
>  #define BROM_STAMP_VALUE	0x5f0a6c39
>  #define SPL_SIGNATURE		"SPL" /* marks "sunxi" SPL header */
> @@ -79,4 +82,192 @@ struct boot_file_head {
>  /* Compile time check to assure proper alignment of structure */
>  typedef char boot_file_head_not_multiple_of_32[1 - 2*(sizeof(struct boot_file_head) % 32)];
>  
> +struct toc0_main_info {
> +	uint8_t name[8];
> +	__le32  magic;
> +	__le32  checksum;
> +	__le32  serial;
> +	__le32  status;
> +	__le32  num_items;
> +	__le32  length;
> +	uint8_t platform[4];
> +	uint8_t reserved[8];
> +	uint8_t end[4];
> +};
> +
> +#define TOC0_MAIN_INFO_NAME		"TOC0.GLH"
> +#define TOC0_MAIN_INFO_MAGIC		0x89119800
> +#define TOC0_MAIN_INFO_END		"MIE;"
> +
> +struct toc0_item_info {
> +	__le32  name;
> +	__le32  offset;
> +	__le32  length;
> +	__le32  status;
> +	__le32  type;
> +	__le32  load_addr;
> +	uint8_t reserved[4];
> +	uint8_t end[4];
> +};
> +
> +#define TOC0_ITEM_INFO_NAME_CERT	0x00010101
> +#define TOC0_ITEM_INFO_NAME_FIRMWARE	0x00010202
> +#define TOC0_ITEM_INFO_NAME_KEY		0x00010303
> +#define TOC0_ITEM_INFO_END		"IIE;"
> +
> +struct toc0_small_tag {
> +	uint8_t tag;
> +	uint8_t length;
> +};
> +
> +typedef struct toc0_small_tag toc0_small_int;
> +typedef struct toc0_small_tag toc0_small_oct;
> +typedef struct toc0_small_tag toc0_small_seq;
> +typedef struct toc0_small_tag toc0_small_exp;
> +
> +#define TOC0_SMALL_INT(len) { 0x02, (len) }
> +#define TOC0_SMALL_SEQ(len) { 0x30, (len) }
> +#define TOC0_SMALL_EXP(tag, len) { 0xa0 | (tag), len }
> +
> +struct toc0_large_tag {
> +	uint8_t tag;
> +	uint8_t prefix;
> +	uint8_t length_hi;
> +	uint8_t length_lo;
> +};
> +
> +typedef struct toc0_large_tag toc0_large_int;
> +typedef struct toc0_large_tag toc0_large_bit;
> +typedef struct toc0_large_tag toc0_large_seq;
> +
> +#define TOC0_LARGE_INT(len) { 0x02, 0x82, (len) >> 8, (len) & 0xff }
> +#define TOC0_LARGE_BIT(len) { 0x03, 0x82, (len) >> 8, (len) & 0xff }
> +#define TOC0_LARGE_SEQ(len) { 0x30, 0x82, (len) >> 8, (len) & 0xff }
> +
> +/*
> + * This looks somewhat like an X.509 certificate, but it is not valid BER.
> + *
> + * Some differences:
> + *  - Some X.509 certificate fields are missing or rearranged.
> + *  - Some sequences have the wrong tag.
> + *  - Zero-length sequences are accepted.
> + *  - Large strings and integers must be an even number of bytes long.
> + *  - Positive integers are not zero-extended to maintain their sign.
> + *
> + * See https://linux-sunxi.org/TOC0 for more information.
> + */
> +struct toc0_cert_item {
> +	toc0_large_seq tag_totalSequence;
> +	struct toc0_totalSequence {
> +		toc0_large_seq tag_mainSequence;
> +		struct toc0_mainSequence {
> +			toc0_small_exp tag_explicit0;
> +			struct toc0_explicit0 {
> +				toc0_small_int tag_version;
> +				uint8_t version;
> +			} explicit0;
> +			toc0_small_int tag_serialNumber;
> +			uint8_t serialNumber;
> +			toc0_small_seq tag_signature;
> +			toc0_small_seq tag_issuer;
> +			toc0_small_seq tag_validity;
> +			toc0_small_seq tag_subject;
> +			toc0_large_seq tag_subjectPublicKeyInfo;
> +			struct toc0_subjectPublicKeyInfo {
> +				toc0_small_seq tag_algorithm;
> +				toc0_large_seq tag_publicKey;
> +				struct toc0_publicKey {
> +					toc0_large_int tag_n;
> +					uint8_t n[256];
> +					toc0_small_int tag_e;
> +					uint8_t e[3];
> +				} publicKey;
> +			} subjectPublicKeyInfo;
> +			toc0_small_exp tag_explicit3;
> +			struct toc0_explicit3 {
> +				toc0_small_seq tag_extension;
> +				struct toc0_extension {
> +					toc0_small_int tag_digest;
> +					uint8_t digest[32];
> +				} extension;
> +			} explicit3;
> +		} mainSequence;
> +		toc0_large_bit tag_sigSequence;
> +		struct toc0_sigSequence {
> +			toc0_small_seq tag_algorithm;
> +			toc0_large_bit tag_signature;
> +			uint8_t signature[256];
> +		} sigSequence;
> +	} totalSequence;
> +};
> +
> +#define sizeof_field(TYPE, MEMBER) sizeof((((TYPE *)0)->MEMBER))
> +
> +#define TOC0_CERT_ITEM {									\
> +	TOC0_LARGE_SEQ(sizeof(struct toc0_totalSequence)),					\
> +	{											\
> +		TOC0_LARGE_SEQ(sizeof(struct toc0_mainSequence)),				\
> +		{										\
> +			TOC0_SMALL_EXP(0, sizeof(struct toc0_explicit0)),			\
> +			{									\
> +				TOC0_SMALL_INT(sizeof_field(struct toc0_explicit0, version)),	\
> +				0,								\
> +			},									\
> +			TOC0_SMALL_INT(sizeof_field(struct toc0_mainSequence, serialNumber)),	\
> +			0,									\
> +			TOC0_SMALL_SEQ(0),							\
> +			TOC0_SMALL_SEQ(0),							\
> +			TOC0_SMALL_SEQ(0),							\
> +			TOC0_SMALL_SEQ(0),							\
> +			TOC0_LARGE_SEQ(sizeof(struct toc0_subjectPublicKeyInfo)),		\
> +			{									\
> +				TOC0_SMALL_SEQ(0),						\
> +				TOC0_LARGE_SEQ(sizeof(struct toc0_publicKey)),			\
> +				{								\
> +					TOC0_LARGE_INT(sizeof_field(struct toc0_publicKey, n)),	\
> +					{},							\
> +					TOC0_SMALL_INT(sizeof_field(struct toc0_publicKey, e)),	\
> +					{},							\
> +				},								\
> +			},									\
> +			TOC0_SMALL_EXP(3, sizeof(struct toc0_explicit3)),			\
> +			{									\
> +				TOC0_SMALL_SEQ(sizeof(struct toc0_extension)),			\
> +				{								\
> +					TOC0_SMALL_INT(sizeof_field(struct toc0_extension, digest)), \
> +					{},							\
> +				},								\
> +			},									\
> +		},										\
> +		TOC0_LARGE_BIT(sizeof(struct toc0_sigSequence)),				\
> +		{										\
> +			TOC0_SMALL_SEQ(0),							\
> +			TOC0_LARGE_BIT(sizeof_field(struct toc0_sigSequence, signature)),	\
> +			{},									\
> +		},										\
> +	},											\
> +}
> +
> +struct toc0_key_item {
> +	__le32  vendor_id;
> +	__le32  key0_n_len;
> +	__le32  key0_e_len;
> +	__le32  key1_n_len;
> +	__le32  key1_e_len;
> +	__le32  sig_len;
> +	uint8_t key0[512];
> +	uint8_t key1[512];
> +	uint8_t reserved[32];
> +	uint8_t sig[256];
> +};
> +
> +#define TOC0_DEFAULT_NUM_ITEMS		3
> +#define TOC0_DEFAULT_HEADER_LEN						  \
> +	ALIGN(								  \
> +		sizeof(struct toc0_main_info)				+ \
> +		sizeof(struct toc0_item_info) *	TOC0_DEFAULT_NUM_ITEMS	+ \
> +		sizeof(struct toc0_cert_item)				+ \
> +		sizeof(struct toc0_key_item),				  \
> +	32)
> +
>  #endif
> diff --git a/tools/Makefile b/tools/Makefile
> index 8843185703c..cb8418466f0 100644
> --- a/tools/Makefile
> +++ b/tools/Makefile
> @@ -79,6 +79,7 @@ AES_OBJS-$(CONFIG_FIT_CIPHER) := $(addprefix lib/aes/, \
>  OPENSSL_OBJS-$(CONFIG_MKIMAGE_LINK_OPENSSL) := \
>  			lib/fdt-libcrypto.o \
>  			mxsimage.o \
> +			sunxi_toc0.o \
>  
>  ROCKCHIP_OBS = lib/rc4.o rkcommon.o rkimage.o rksd.o rkspi.o
>  
> diff --git a/tools/sunxi_toc0.c b/tools/sunxi_toc0.c
> new file mode 100644
> index 00000000000..f0bf86b477c
> --- /dev/null
> +++ b/tools/sunxi_toc0.c
> @@ -0,0 +1,710 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * (C) Copyright 2018 Arm Ltd.
> + * (C) Copyright 2020-2021 Samuel Holland <samuel@sholland.org>
> + */
> +
> +#include <assert.h>
> +#include <stdint.h>
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <string.h>
> +
> +#include <openssl/asn1t.h>
> +#include <openssl/pem.h>
> +#include <openssl/rsa.h>
> +
> +#include <image.h>
> +#include <sunxi_image.h>
> +
> +#include "imagetool.h"
> +#include "mkimage.h"
> +
> +/*
> + * NAND requires 8K padding. For other devices, BROM requires only
> + * 512B padding, but let's use the larger padding to cover everything.
> + */
> +#define PAD_SIZE		8192
> +
> +#define pr_err(fmt, args...)	fprintf(stderr, "TOC0 ERR: " fmt, ##args)
> +#define pr_warn(fmt, args...)	fprintf(stderr, "TOC0 WRN: " fmt, ##args)
> +#define pr_info(fmt, args...)	fprintf(stderr, "TOC0 INF: " fmt, ##args)
> +
> +static char *fw_key_file   = "fw_key.pem";
> +static char *key_item_file = "key_item.bin";
> +static char *root_key_file = "root_key.pem";
> +
> +/*
> + * Create a key item in @buf, containing the public keys @root_key and @fw_key,
> + * and signed by the RSA key @root_key.
> + */
> +static int toc0_create_key_item(uint8_t *buf, uint32_t *len,
> +				RSA *root_key, RSA *fw_key)
> +{
> +	struct toc0_key_item *key_item = (void *)buf;
> +	uint8_t digest[SHA256_DIGEST_LENGTH];
> +	int ret = EXIT_FAILURE;
> +	unsigned int sig_len;
> +	int n_len, e_len;
> +
> +	/* Store key 0. */
> +	n_len = BN_bn2bin(RSA_get0_n(root_key), key_item->key0);
> +	e_len = BN_bn2bin(RSA_get0_e(root_key), key_item->key0 + n_len);
> +	if (n_len + e_len > sizeof(key_item->key0)) {
> +		pr_err("Root key is too large\n");
> +		goto err;
> +	}
> +	key_item->key0_n_len = cpu_to_le32(n_len);
> +	key_item->key0_e_len = cpu_to_le32(e_len);
> +
> +	/* Store key 1. */
> +	n_len = BN_bn2bin(RSA_get0_n(fw_key), key_item->key1);
> +	e_len = BN_bn2bin(RSA_get0_e(fw_key), key_item->key1 + n_len);
> +	if (n_len + e_len > sizeof(key_item->key1)) {
> +		pr_err("Firmware key is too large\n");
> +		goto err;
> +	}
> +	key_item->key1_n_len = cpu_to_le32(n_len);
> +	key_item->key1_e_len = cpu_to_le32(e_len);
> +
> +	/* Sign the key item. */
> +	key_item->sig_len = cpu_to_le32(RSA_size(root_key));
> +	SHA256(buf, key_item->sig - buf, digest);
> +	if (!RSA_sign(NID_sha256, digest, sizeof(digest),
> +		      key_item->sig, &sig_len, root_key)) {
> +		pr_err("Failed to sign key item\n");
> +		goto err;
> +	}
> +	if (sig_len != sizeof(key_item->sig)) {
> +		pr_err("Signature length mismatch\n");
> +		goto err;
> +	}
> +
> +	*len = sizeof(*key_item);
> +	ret = EXIT_SUCCESS;
> +
> +err:
> +	return ret;
> +}
> +
> +/*
> + * Verify the key item in @buf, containing two public keys @key0 and @key1,
> + * and signed by the RSA key @key0. If @root_key is provided, only signatures
> + * by that key will be accepted. @key1 is returned in @key.
> + */
> +static int toc0_verify_key_item(const uint8_t *buf, uint32_t len,
> +				RSA *root_key, RSA **fw_key)
> +{
> +	struct toc0_key_item *key_item = (void *)buf;
> +	uint8_t digest[SHA256_DIGEST_LENGTH];
> +	int ret = EXIT_FAILURE;
> +	int n_len, e_len;
> +	RSA *key0 = NULL;
> +	RSA *key1 = NULL;
> +	BIGNUM *n, *e;
> +
> +	if (len < sizeof(*key_item))
> +		goto err;
> +
> +	/* Load key 0. */
> +	n_len = le32_to_cpu(key_item->key0_n_len);
> +	e_len = le32_to_cpu(key_item->key0_e_len);
> +	if (n_len + e_len > sizeof(key_item->key0))
> +		goto err;
> +	n = BN_bin2bn(key_item->key0, n_len, NULL);
> +	e = BN_bin2bn(key_item->key0 + n_len, e_len, NULL);
> +	key0 = RSA_new();
> +	if (!key0)
> +		goto err;
> +	if (!RSA_set0_key(key0, n, e, NULL))
> +		goto err;
> +
> +	/* If a root key was provided, compare it to key 0. */
> +	if (root_key && (BN_cmp(n, RSA_get0_n(root_key)) ||
> +			 BN_cmp(e, RSA_get0_e(root_key)))) {
> +		pr_err("Root key mismatch\n");
> +		goto err;
> +	}
> +
> +	/* Verify the key item signature. */
> +	SHA256(buf, key_item->sig - buf, digest);
> +	if (!RSA_verify(NID_sha256, digest, sizeof(digest),
> +			key_item->sig, le32_to_cpu(key_item->sig_len), key0)) {
> +		pr_err("Bad key item signature\n");
> +		goto err;
> +	}
> +
> +	if (fw_key) {
> +		/* Load key 1. */
> +		n_len = le32_to_cpu(key_item->key1_n_len);
> +		e_len = le32_to_cpu(key_item->key1_e_len);
> +		if (n_len + e_len > sizeof(key_item->key1))
> +			goto err;
> +		n = BN_bin2bn(key_item->key1, n_len, NULL);
> +		e = BN_bin2bn(key_item->key1 + n_len, e_len, NULL);
> +		key1 = RSA_new();
> +		if (!key1)
> +			goto err;
> +		if (!RSA_set0_key(key1, n, e, NULL))
> +			goto err;
> +
> +		if (*fw_key) {
> +			/* If a FW key was provided, compare it to key 1. */
> +			if (BN_cmp(n, RSA_get0_n(*fw_key)) ||
> +			    BN_cmp(e, RSA_get0_e(*fw_key))) {
> +				pr_err("Firmware key mismatch\n");
> +				goto err;
> +			}
> +		} else {
> +			/* Otherwise, send key1 back to the caller. */
> +			*fw_key = key1;
> +			key1 = NULL;
> +		}
> +	}
> +
> +	ret = EXIT_SUCCESS;
> +
> +err:
> +	RSA_free(key0);
> +	RSA_free(key1);
> +
> +	return ret;
> +}
> +
> +/*
> + * Create a certificate in @buf, describing the firmware with SHA256 digest
> + * @digest, and signed by the RSA key @fw_key.
> + */
> +static int toc0_create_cert_item(uint8_t *buf, uint32_t *len, RSA *fw_key,
> +				 uint8_t digest[static SHA256_DIGEST_LENGTH])
> +{
> +	static const struct toc0_cert_item cert_item_template = TOC0_CERT_ITEM;
> +	struct toc0_cert_item *cert_item = (void *)buf;
> +	uint8_t cert_digest[SHA256_DIGEST_LENGTH];
> +	struct toc0_totalSequence *totalSequence;
> +	struct toc0_sigSequence *sigSequence;
> +	struct toc0_extension *extension;
> +	struct toc0_publicKey *publicKey;
> +	int ret = EXIT_FAILURE;
> +	unsigned int sig_len;
> +
> +	memcpy(cert_item, &cert_item_template, sizeof(*cert_item));
> +	*len = sizeof(*cert_item);
> +
> +	/*
> +	 * Fill in the public key.
> +	 *
> +	 * Only 2048-bit RSA keys are supported. Since this uses a fixed-size
> +	 * structure, it may fail for non-standard exponents.
> +	 */
> +	totalSequence = &cert_item->totalSequence;
> +	publicKey = &totalSequence->mainSequence.subjectPublicKeyInfo.publicKey;
> +	if (BN_bn2binpad(RSA_get0_n(fw_key), publicKey->n, sizeof(publicKey->n)) < 0 ||
> +	    BN_bn2binpad(RSA_get0_e(fw_key), publicKey->e, sizeof(publicKey->e)) < 0) {
> +		pr_err("Incorrect key size\n");
> +		goto err;
> +	}
> +
> +	/* Fill in the firmware digest. */
> +	extension = &totalSequence->mainSequence.explicit3.extension;
> +	memcpy(&extension->digest, digest, SHA256_DIGEST_LENGTH);
> +
> +	/*
> +	 * Sign the certificate.
> +	 *
> +	 * In older SBROM versions (and by default in newer versions),
> +	 * the last 4 bytes of the certificate are not signed.
> +	 *
> +	 * (The buffer passed to SHA256 starts at tag_mainSequence, but
> +	 *  the buffer size does not include the length of that tag.)
> +	 */
> +	SHA256((uint8_t *)totalSequence, sizeof(struct toc0_mainSequence),
> +	       cert_digest);
> +	sigSequence = &totalSequence->sigSequence;
> +	if (!RSA_sign(NID_sha256, cert_digest, SHA256_DIGEST_LENGTH,
> +		      sigSequence->signature, &sig_len, fw_key)) {
> +		pr_err("Failed to sign certificate\n");
> +		goto err;
> +	}
> +	if (sig_len != sizeof(sigSequence->signature)) {
> +		pr_err("Signature length mismatch\n");
> +		goto err;
> +	}
> +
> +	ret = EXIT_SUCCESS;
> +
> +err:
> +	return ret;
> +}
> +
> +/*
> + * Verify the certificate in @buf, describing the firmware with SHA256 digest
> + * @digest, and signed by the RSA key contained within. If @fw_key is provided,
> + * only that key will be accepted.
> + *
> + * This function is only expected to work with images created by mkimage.
> + */
> +static int toc0_verify_cert_item(const uint8_t *buf, uint32_t len, RSA *fw_key,
> +				 uint8_t digest[static SHA256_DIGEST_LENGTH])
> +{
> +	const struct toc0_cert_item *cert_item = (const void *)buf;
> +	uint8_t cert_digest[SHA256_DIGEST_LENGTH];
> +	const struct toc0_totalSequence *totalSequence;
> +	const struct toc0_sigSequence *sigSequence;
> +	const struct toc0_extension *extension;
> +	const struct toc0_publicKey *publicKey;
> +	int ret = EXIT_FAILURE;
> +	RSA *key = NULL;
> +	BIGNUM *n, *e;
> +
> +	/* Extract the public key from the certificate. */
> +	totalSequence = &cert_item->totalSequence;
> +	publicKey = &totalSequence->mainSequence.subjectPublicKeyInfo.publicKey;
> +	n = BN_bin2bn(publicKey->n, sizeof(publicKey->n), NULL);
> +	e = BN_bin2bn(publicKey->e, sizeof(publicKey->e), NULL);
> +	key = RSA_new();
> +	if (!key)
> +		goto err;
> +	if (!RSA_set0_key(key, n, e, NULL))
> +		goto err;
> +
> +	/* If a key was provided, compare it to the embedded key. */
> +	if (fw_key && (BN_cmp(RSA_get0_n(key), RSA_get0_n(fw_key)) ||
> +		       BN_cmp(RSA_get0_e(key), RSA_get0_e(fw_key)))) {
> +		pr_err("Firmware key mismatch\n");
> +		goto err;
> +	}
> +
> +	/* If a digest was provided, compare it to the embedded digest. */
> +	extension = &totalSequence->mainSequence.explicit3.extension;
> +	if (digest && memcmp(&extension->digest, digest, SHA256_DIGEST_LENGTH)) {
> +		pr_err("Firmware digest mismatch\n");
> +		goto err;
> +	}
> +
> +	/* Verify the certificate's signature. See the comment above. */
> +	SHA256((uint8_t *)totalSequence, sizeof(struct toc0_mainSequence),
> +	       cert_digest);
> +	sigSequence = &totalSequence->sigSequence;
> +	if (!RSA_verify(NID_sha256, cert_digest, SHA256_DIGEST_LENGTH,
> +			sigSequence->signature,
> +			sizeof(sigSequence->signature), key)) {
> +		pr_err("Bad certificate signature\n");
> +		goto err;
> +	}
> +
> +	ret = EXIT_SUCCESS;
> +
> +err:
> +	RSA_free(key);
> +
> +	return ret;
> +}
> +
> +/*
> + * Always create a TOC0 containing 3 items. The extra item will be ignored on
> + * SoCs which do not support it.
> + */
> +static int toc0_create(uint8_t *buf, uint32_t len, RSA *root_key, RSA *fw_key,
> +		       uint8_t *key_item, uint32_t key_item_len,
> +		       uint8_t *fw_item, uint32_t fw_item_len, uint32_t fw_addr)
> +{
> +	struct toc0_main_info *main = (void *)buf;

My compiler warns:
  HOSTCC  tools/sunxi_toc0.o
tools/sunxi_toc0.c: In function ‘toc0_create’:
tools/sunxi_toc0.c:314:25: warning: ‘main’ is usually a function [-Wmain]
  struct toc0_main_info *main = (void *)buf;

Can you rename this variable? "main" is indeed confusing and not very
descriptive.

> +	struct toc0_item_info *item = (void *)(main + 1);
> +	uint8_t digest[SHA256_DIGEST_LENGTH];
> +	uint32_t *buf32 = (void *)buf;
> +	RSA *orig_fw_key = fw_key;
> +	int ret = EXIT_FAILURE;
> +	uint32_t checksum = 0;
> +	uint32_t item_offset;
> +	uint32_t item_length;
> +	int i;
> +
> +	/* Hash the firmware for inclusion in the certificate. */
> +	SHA256(fw_item, fw_item_len, digest);
> +
> +	/* Create the main TOC0 header, containing three items. */
> +	memcpy(main->name, TOC0_MAIN_INFO_NAME, sizeof(main->name));
> +	main->magic	= cpu_to_le32(TOC0_MAIN_INFO_MAGIC);
> +	main->checksum	= cpu_to_le32(BROM_STAMP_VALUE);
> +	main->num_items	= cpu_to_le32(TOC0_DEFAULT_NUM_ITEMS);
> +	memcpy(main->end, TOC0_MAIN_INFO_END, sizeof(main->end));
> +
> +	/* The first item links the ROTPK to the signing key. */
> +	item_offset = sizeof(*main) + TOC0_DEFAULT_NUM_ITEMS * sizeof(*item);
> +	/* Using an existing key item avoids needing the root private key. */
> +	if (key_item) {
> +		item_length = sizeof(*key_item);
> +		if (toc0_verify_key_item(key_item, item_length,
> +					 root_key, &fw_key))
> +			goto err;
> +		memcpy(buf + item_offset, key_item, item_length);
> +	} else if (toc0_create_key_item(buf + item_offset, &item_length,
> +					root_key, fw_key)) {
> +		goto err;
> +	}
> +
> +	item->name	= cpu_to_le32(TOC0_ITEM_INFO_NAME_KEY);
> +	item->offset	= cpu_to_le32(item_offset);
> +	item->length	= cpu_to_le32(item_length);
> +	memcpy(item->end, TOC0_ITEM_INFO_END, sizeof(item->end));
> +
> +	/* The second item contains a certificate signed by the firmware key. */
> +	item_offset = item_offset + item_length;
> +	if (toc0_create_cert_item(buf + item_offset, &item_length,
> +				  fw_key, digest))
> +		goto err;
> +
> +	item++;
> +	item->name	= cpu_to_le32(TOC0_ITEM_INFO_NAME_CERT);
> +	item->offset	= cpu_to_le32(item_offset);
> +	item->length	= cpu_to_le32(item_length);
> +	memcpy(item->end, TOC0_ITEM_INFO_END, sizeof(item->end));
> +
> +	/* The third item contains the actual boot code. */
> +	item_offset = ALIGN(item_offset + item_length, 32);
> +	item_length = fw_item_len;
> +	if (buf + item_offset != fw_item)
> +		memmove(buf + item_offset, fw_item, item_length);
> +
> +	item++;
> +	item->name	= cpu_to_le32(TOC0_ITEM_INFO_NAME_FIRMWARE);
> +	item->offset	= cpu_to_le32(item_offset);
> +	item->length	= cpu_to_le32(item_length);
> +	item->load_addr	= cpu_to_le32(fw_addr);
> +	memcpy(item->end, TOC0_ITEM_INFO_END, sizeof(item->end));
> +
> +	/* Pad to the required block size with 0xff to be flash-friendly. */
> +	item_offset = item_offset + item_length;
> +	item_length = ALIGN(item_offset, PAD_SIZE) - item_offset;
> +	memset(buf + item_offset, 0xff, item_length);
> +
> +	/* Fill in the total padded file length. */
> +	item_offset = item_offset + item_length;
> +	main->length = cpu_to_le32(item_offset);
> +
> +	/* Verify enough space was provided when creating the image. */
> +	assert(len >= item_offset);
> +
> +	/* Calculate the checksum. Yes, it's that simple. */
> +	for (i = 0; i < item_offset / 4; ++i)
> +		checksum += le32_to_cpu(buf32[i]);
> +	main->checksum = cpu_to_le32(checksum);
> +
> +	ret = EXIT_SUCCESS;
> +
> +err:
> +	if (fw_key != orig_fw_key)
> +		RSA_free(fw_key);
> +
> +	return ret;
> +}
> +
> +static const struct toc0_item_info *
> +toc0_find_item(const struct toc0_main_info *main,
> +	       uint32_t name, uint32_t *offset, uint32_t *length)
> +{
> +	const struct toc0_item_info *item = (void *)(main + 1);
> +	uint32_t item_offset, item_length;
> +	uint32_t num_items, main_length;
> +	int i;
> +
> +	num_items   = le32_to_cpu(main->num_items);
> +	main_length = le32_to_cpu(main->length);
> +
> +	for (i = 0; i < num_items; ++i, ++item) {
> +		if (le32_to_cpu(item->name) != name)
> +			continue;
> +
> +		item_offset = le32_to_cpu(item->offset);
> +		item_length = le32_to_cpu(item->length);
> +
> +		if (item_offset > main_length ||
> +		    item_length > main_length - item_offset)
> +			continue;
> +
> +		*offset = item_offset;
> +		*length = item_length;
> +
> +		return item;
> +	}
> +
> +	return NULL;
> +}
> +
> +static int toc0_verify(const uint8_t *buf, uint32_t len, RSA *root_key)
> +{
> +	const struct toc0_main_info *main = (void *)buf;
> +	const struct toc0_item_info *item;
> +	uint8_t digest[SHA256_DIGEST_LENGTH];
> +	uint32_t main_length = le32_to_cpu(main->length);
> +	uint32_t checksum = BROM_STAMP_VALUE;
> +	uint32_t *buf32 = (void *)buf;
> +	uint32_t length, offset;
> +	int ret = EXIT_FAILURE;
> +	RSA *fw_key = NULL;
> +	int i;
> +
> +	if (len < main_length)
> +		goto err;
> +
> +	/* Verify the main header. */
> +	if (memcmp(main->name, TOC0_MAIN_INFO_NAME, sizeof(main->name)))
> +		goto err;
> +	if (le32_to_cpu(main->magic) != TOC0_MAIN_INFO_MAGIC)
> +		goto err;
> +	/* Verify the checksum without modifying the buffer. */
> +	for (i = 0; i < main_length / 4; ++i)
> +		checksum += le32_to_cpu(buf32[i]);
> +	if (checksum != 2 * le32_to_cpu(main->checksum))
> +		goto err;
> +	/* The length must be at least 512 byte aligned. */
> +	if (main_length % 512)
> +		goto err;
> +	if (memcmp(main->end, TOC0_MAIN_INFO_END, sizeof(main->end)))
> +		goto err;
> +
> +	/* Verify the key item if present. */
> +	item = toc0_find_item(main, TOC0_ITEM_INFO_NAME_KEY, &offset, &length);
> +	if (!item)
> +		fw_key = root_key;
> +	else if (toc0_verify_key_item(buf + offset, length, root_key, &fw_key))
> +		goto err;
> +
> +	/* Hash the firmware to compare with the certificate. */
> +	item = toc0_find_item(main, TOC0_ITEM_INFO_NAME_FIRMWARE, &offset, &length);
> +	if (!item) {
> +		pr_err("Image does not contain a firmware item\n");
> +		goto err;
> +	}
> +	SHA256(buf + offset, length, digest);
> +
> +	/* Verify the certificate item. */
> +	item = toc0_find_item(main, TOC0_ITEM_INFO_NAME_CERT, &offset, &length);
> +	if (!item) {
> +		pr_err("Image does not contain a certificate item\n");
> +		goto err;
> +	}
> +	if (toc0_verify_cert_item(buf + offset, length, fw_key, digest))
> +		goto err;
> +
> +	ret = EXIT_SUCCESS;
> +
> +err:
> +	if (fw_key != root_key)
> +		RSA_free(fw_key);
> +
> +	return ret;
> +}
> +
> +static int toc0_check_params(struct image_tool_params *params)
> +{
> +	if (!params->dflag)
> +		return -EINVAL;
> +
> +	if (params->keydir) {
> +		asprintf(&fw_key_file, "%s/%s", params->keydir, fw_key_file);

tools/sunxi_toc0.c: In function ‘toc0_check_params’:
tools/sunxi_toc0.c:508:3: warning: ignoring return value of ‘asprintf’, declared with attribute warn_unused_result [-Wunused-result]
  508 |   asprintf(&fw_key_file, "%s/%s", params->keydir, fw_key_file);

Can you provide some example which at least briefly mentions those
files here and their purpose?
I guess this would eventually become a chapter in the README.sunxi file
which I promised a while ago ...

Cheers,
Andre

> +		asprintf(&key_item_file, "%s/%s", params->keydir, key_item_file);
> +		asprintf(&root_key_file, "%s/%s", params->keydir, root_key_file);
> +	}
> +
> +	return 0;
> +}
> +
> +static int toc0_verify_header(unsigned char *buf, int image_size,
> +			      struct image_tool_params *params)
> +{
> +	int ret = EXIT_FAILURE;
> +	RSA *root_key = NULL;
> +	FILE *fp;
> +
> +	/* A root public key is optional. */
> +	fp = fopen(root_key_file, "rb");
> +	if (fp) {
> +		pr_info("Verifying image with existing root key\n");
> +		root_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
> +		if (!root_key)
> +			root_key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);
> +		fclose(fp);
> +		if (!root_key) {
> +			pr_err("Failed to read public key from '%s'\n",
> +			       root_key_file);
> +			goto err;
> +		}
> +	}
> +
> +	ret = toc0_verify(buf, image_size, root_key);
> +
> +err:
> +	RSA_free(root_key);
> +
> +	return ret;
> +}
> +
> +static const char *toc0_item_name(uint32_t name)
> +{
> +	if (name == TOC0_ITEM_INFO_NAME_CERT)
> +		return "Certificate";
> +	if (name == TOC0_ITEM_INFO_NAME_FIRMWARE)
> +		return "Firmware";
> +	if (name == TOC0_ITEM_INFO_NAME_KEY)
> +		return "Key";
> +	return "(unknown)";
> +}
> +
> +static void toc0_print_header(const void *buf)
> +{
> +	const struct toc0_main_info *main = buf;
> +	const struct toc0_item_info *item = (void *)(main + 1);
> +	uint32_t head_length, main_length, num_items;
> +	uint32_t item_offset, item_length, item_name;
> +	int load_addr = -1;
> +	int i;
> +
> +	num_items   = le32_to_cpu(main->num_items);
> +	head_length = sizeof(*main) + num_items * sizeof(*item);
> +	main_length = le32_to_cpu(main->length);
> +
> +	printf("Allwinner TOC0 Image\n"
> +	       "Size: %d bytes\n"
> +	       "Contents: %d items\n"
> +	       " 00000000:%08x Headers\n",
> +	       main_length, num_items, head_length);
> +
> +	for (i = 0; i < num_items; ++i, ++item) {
> +		item_offset = le32_to_cpu(item->offset);
> +		item_length = le32_to_cpu(item->length);
> +		item_name   = le32_to_cpu(item->name);
> +
> +		if (item_name == TOC0_ITEM_INFO_NAME_FIRMWARE)
> +			load_addr = le32_to_cpu(item->load_addr);
> +
> +		printf(" %08x:%08x %s\n",
> +		       item_offset, item_length,
> +		       toc0_item_name(item_name));
> +	}
> +
> +	if (num_items && item_offset + item_length < main_length) {
> +		item_offset = item_offset + item_length;
> +		item_length = main_length - item_offset;
> +
> +		printf(" %08x:%08x Padding\n",
> +		       item_offset, item_length);
> +	}
> +
> +	if (load_addr != -1)
> +		printf("Load address: 0x%08x\n", load_addr);
> +}
> +
> +static void toc0_set_header(void *buf, struct stat *sbuf, int ifd,
> +			    struct image_tool_params *params)
> +{
> +	uint32_t key_item_len = 0;
> +	uint8_t *key_item = NULL;
> +	int ret = EXIT_FAILURE;
> +	RSA *root_key = NULL;
> +	RSA *fw_key = NULL;
> +	FILE *fp;
> +
> +	/* Either a key item or the root private key is required. */
> +	fp = fopen(key_item_file, "rb");
> +	if (fp) {
> +		pr_info("Creating image using existing key item\n");
> +		key_item_len = sizeof(struct toc0_key_item);
> +		key_item = OPENSSL_malloc(key_item_len);
> +		if (!key_item || fread(key_item, key_item_len, 1, fp) != 1) {
> +			pr_err("Failed to read key item from '%s'\n",
> +			       root_key_file);
> +			goto err;
> +		}
> +		fclose(fp);
> +		fp = NULL;
> +	}
> +
> +	fp = fopen(root_key_file, "rb");
> +	if (fp) {
> +		root_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
> +		if (!root_key)
> +			root_key = PEM_read_RSAPublicKey(fp, NULL, NULL, NULL);
> +		fclose(fp);
> +		fp = NULL;
> +	}
> +
> +	/* When using an existing key item, the root key is optional. */
> +	if (!key_item && (!root_key || !RSA_get0_d(root_key))) {
> +		pr_err("Failed to read private key from '%s'\n",
> +		       root_key_file);
> +		goto err;
> +	}
> +
> +	/* The certificate/firmware private key is always required. */
> +	fp = fopen(fw_key_file, "rb");
> +	if (fp) {
> +		fw_key = PEM_read_RSAPrivateKey(fp, NULL, NULL, NULL);
> +		fclose(fp);
> +		fp = NULL;
> +	}
> +	if (!fw_key) {
> +		/* If the root key is a private key, it can be used instead. */
> +		if (root_key && RSA_get0_d(root_key)) {
> +			pr_info("Using root key as firmware key\n");
> +			fw_key = root_key;
> +		} else {
> +			pr_err("Failed to read private key from '%s'\n",
> +			       fw_key_file);
> +			goto err;
> +		}
> +	}
> +
> +	/* Warn about potential compatiblity issues. */
> +	if (key_item || fw_key != root_key)
> +		pr_warn("Only H6 supports separate root and firmware keys\n");
> +
> +	ret = toc0_create(buf, params->file_size, root_key, fw_key,
> +			  key_item, key_item_len,
> +			  buf + TOC0_DEFAULT_HEADER_LEN,
> +			  params->orig_file_size, params->addr);
> +
> +err:
> +	OPENSSL_free(key_item);
> +	OPENSSL_free(root_key);
> +	if (fw_key != root_key)
> +		OPENSSL_free(fw_key);
> +	if (fp)
> +		fclose(fp);
> +
> +	if (ret != EXIT_SUCCESS)
> +		exit(ret);
> +}
> +
> +static int toc0_check_image_type(uint8_t type)
> +{
> +	return type == IH_TYPE_SUNXI_TOC0 ? 0 : 1;
> +}
> +
> +static int toc0_vrec_header(struct image_tool_params *params,
> +			    struct image_type_params *tparams)
> +{
> +	tparams->hdr = calloc(tparams->header_size, 1);
> +
> +	/* Save off the unpadded data size for SHA256 calculation. */
> +	params->orig_file_size = params->file_size - TOC0_DEFAULT_HEADER_LEN;
> +
> +	/* Return padding to 8K blocks. */
> +	return ALIGN(params->file_size, PAD_SIZE) - params->file_size;
> +}
> +
> +U_BOOT_IMAGE_TYPE(
> +	sunxi_toc0,
> +	"Allwinner TOC0 Boot Image support",
> +	TOC0_DEFAULT_HEADER_LEN,
> +	NULL,
> +	toc0_check_params,
> +	toc0_verify_header,
> +	toc0_print_header,
> +	toc0_set_header,
> +	NULL,
> +	toc0_check_image_type,
> +	NULL,
> +	toc0_vrec_header
> +);


^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 1/4] tools: Refactor mkimage linking with OpenSSL
  2021-06-21  2:55 ` [PATCH 1/4] tools: Refactor mkimage linking with OpenSSL Samuel Holland
@ 2021-06-26 18:31   ` Simon Glass
  0 siblings, 0 replies; 14+ messages in thread
From: Simon Glass @ 2021-06-26 18:31 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Jagan Teki, Andre Przywara, Hans de Goede, U-Boot Mailing List,
	Stefano Babic, Fabio Estevam, NXP i.MX U-Boot Team, Stefan Roese

On Sun, 20 Jun 2021 at 20:55, Samuel Holland <samuel@sholland.org> wrote:
>
> Some mkimage features require linking with OpenSSL. Instead of linking
> OpenSSL based on the individual platform symbols, create a single
> Kconfig symbol which can be selected by platforms as necessary. Then,
> all OpenSSL-dependent image types can be enabled at once.
>
> Cc: Stefano Babic <sbabic@denx.de>
> Cc: Fabio Estevam <festevam@gmail.com>
> Cc: "NXP i.MX U-Boot Team" <uboot-imx@nxp.com>
> Cc: Stefan Roese <sr@denx.de>
> Cc: Simon Glass <sjg@chromium.org>
> Signed-off-by: Samuel Holland <samuel@sholland.org>
> ---
>  arch/arm/mach-imx/mxs/Kconfig |  2 ++
>  arch/arm/mach-mvebu/Kconfig   |  1 +
>  common/Kconfig.boot           |  2 ++
>  scripts/config_whitelist.txt  |  1 -
>  tools/Kconfig                 |  3 +++
>  tools/Makefile                | 22 +++++++---------------
>  tools/mxsimage.c              |  3 ---
>  7 files changed, 15 insertions(+), 19 deletions(-)

Reviewed-by: Simon Glass <sjg@chromium.org>

if you add help to the MKIMAGE_LINK_OPENSSL Kcofig

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/4] sunxi: TOC0 image type support
  2021-06-21 23:56     ` Andre Przywara
@ 2021-08-22  2:19       ` Samuel Holland
  2021-08-22 14:15         ` Tom Rini
  0 siblings, 1 reply; 14+ messages in thread
From: Samuel Holland @ 2021-08-22  2:19 UTC (permalink / raw)
  To: Andre Przywara, Tom Rini
  Cc: Jagan Teki, Hans de Goede, u-boot, Simon Glass, Jernej Škrabec


Hi Andre,

On 6/21/21 6:56 PM, Andre Przywara wrote:
> On Mon, 21 Jun 2021 16:35:37 -0400
> Tom Rini <trini@konsulko.com> wrote:
>> On Mon, Jun 21, 2021 at 04:43:00PM +0100, Andre Przywara wrote:
>>> On Sun, 20 Jun 2021 21:55:51 -0500
>>> Samuel Holland <samuel@sholland.org> wrote:
>>>
>>> (CC:ing Tom and Simon for the compatibility problem below)
>>>
>>> Hi,
>>>   
>>>> This series adds support for the TOC0 image format used by the Allwinner
>>>> secure boot ROM (SBROM). This series has been tested on the following
>>>> SoCs/boards, with the eFuse burnt to enable secure mode:
>>>>   - A64: Pine A64 Plus
>>>>   - H5: Orange Pi Zero Plus
>>>>   - H6: Pine H64 Model B
>>>>   - H616: Orange Pi Zero 2  
>>>
>>> many thanks for sending this. In general this looks good (will do a
>>> more thorough review soon), just one thing that bothered me:
>>>
>>> This requires OpenSLL 1.1.x. There is nothing really wrong about this,
>>> but my (admittedly not the freshest) Slackware, but also long term
>>> distros like RHEL/CentOS (<=7), still come with 1.0.x (headers) only.
>>>
>>> I was wondering how important this is? I have the impression that
>>> embedded developers sometimes use old^Wstable systems, so some people
>>> might be bitten by it. I think in this case it will affect all user
>>> trying to build mkimage, regardless of the target platform?
>>>
>>> So I wanted to know what to do here?
>>> - Can we provide some kind of compatibility support? OpenSSL seems
>>>   to provide something:
>>> https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes#Compatibility_Layer
>>>   Haven't tested that fully yet, just downloading that tarball
>>>   does not seem to cut it (or is missing files?). I guess one needs to
>>>   copy&paste some code from the Wiki?
>>> - Shall we detect missing v1.1.x support (via #if OPENSSL_VERSION_NUMBER
>>>   < 0x10100000L) and disable just sunxi_toc0 support in this case?  
>>
>> There's two things.  First, the series should be on top of (sorry!)
>> https://patchwork.ozlabs.org/project/uboot/patch/20210524202317.1492578-1-mr.nuke.me@gmail.com/
>> which adds a similar Kconfig option to make building tools easier.
> 
> So this is on top of Simon's large series? Poor Samuel! Is there a
> branch somewhere?

Now that all of these have landed, I'm rebasing this series.

>> Second, while I think not supporting openssl 1.0.x is fine,
> 
> Well, this was not what I was hoping for ;-)
> I followed the advice on the OpenSSL wiki and now have a rather small
> compatibility header file, which lets me compile mkimage even against
> OpenSSL v1.0.2u. It seems like kwbimage.c has similar provisions in
> place, I guess this could be merged into the external header?
> Happy to send a patch on top, if this seems useful.

Considering the note from the OpenSSL website:

> Note: The latest stable version is the 1.1.1 series. This is also
> our Long Term Support (LTS) version, supported until 11th September
> 2023. All older versions (including 1.1.0, 1.0.2, 1.0.0 and 0.9.8)
> are now out of support and should not be used. Users of these older
> versions are encouraged to upgrade to 1.1.1 as soon as possible.
and the fact that that I don't have access a system with an old OpenSSL,
I'm not too interested in spending much effort on it. I will, though,
happily test a patch if you do send one.

>> I would like
>> to again ask for someone to spend the time looking at switching to one
>> of the GPL-compatible libraries as I'm pretty sure it's been raised a
>> few times that we can't link with openssl like we do.
> 
> Why is that? Because Apache is not compatible with GPLv2? The OpenSSL
> webpage says that:
> "Can I use OpenSSL with GPL software?
> On many systems including the major Linux and BSD distributions, yes
> (the GPL does not place restrictions on using libraries that are part
> of the normal operating system distribution)."
> And for mkimage we just build a regular userspace tool, which is linked
> against the system installed OpenSSL library. From my understanding
> this is what this quote above means with being permitted?
> 
> And what would be the alternatives? Take one of the smaller ones and
> embed them into the code?
> Otherwise we would probably need to pick something that is widely
> available and shipped with distros, I guess? Like GnuTLS,
> libgcrypt, nettle? Maybe LibreSSL?
> 
> Samuel, do you have an insight what would be a good fit?

My original code was written against nettle. I switched to OpenSSL
because that was already integrated into U-Boot (oops!), and to use the
ASN.1 generation library (which the code no longer uses).

So nettle would work well here because all we need is SHA256 and plain
RSA. I don't know about the other image types.

Regards,
Samuel

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/4] sunxi: TOC0 image type support
  2021-08-22  2:19       ` Samuel Holland
@ 2021-08-22 14:15         ` Tom Rini
  2021-08-22 21:37           ` Vagrant Cascadian
  0 siblings, 1 reply; 14+ messages in thread
From: Tom Rini @ 2021-08-22 14:15 UTC (permalink / raw)
  To: Samuel Holland
  Cc: Andre Przywara, Jagan Teki, Hans de Goede, u-boot, Simon Glass,
	Jernej Škrabec, Vagrant Cascadian

[-- Attachment #1: Type: text/plain, Size: 5441 bytes --]

On Sat, Aug 21, 2021 at 09:19:56PM -0500, Samuel Holland wrote:
> 
> Hi Andre,
> 
> On 6/21/21 6:56 PM, Andre Przywara wrote:
> > On Mon, 21 Jun 2021 16:35:37 -0400
> > Tom Rini <trini@konsulko.com> wrote:
> >> On Mon, Jun 21, 2021 at 04:43:00PM +0100, Andre Przywara wrote:
> >>> On Sun, 20 Jun 2021 21:55:51 -0500
> >>> Samuel Holland <samuel@sholland.org> wrote:
> >>>
> >>> (CC:ing Tom and Simon for the compatibility problem below)
> >>>
> >>> Hi,
> >>>   
> >>>> This series adds support for the TOC0 image format used by the Allwinner
> >>>> secure boot ROM (SBROM). This series has been tested on the following
> >>>> SoCs/boards, with the eFuse burnt to enable secure mode:
> >>>>   - A64: Pine A64 Plus
> >>>>   - H5: Orange Pi Zero Plus
> >>>>   - H6: Pine H64 Model B
> >>>>   - H616: Orange Pi Zero 2  
> >>>
> >>> many thanks for sending this. In general this looks good (will do a
> >>> more thorough review soon), just one thing that bothered me:
> >>>
> >>> This requires OpenSLL 1.1.x. There is nothing really wrong about this,
> >>> but my (admittedly not the freshest) Slackware, but also long term
> >>> distros like RHEL/CentOS (<=7), still come with 1.0.x (headers) only.
> >>>
> >>> I was wondering how important this is? I have the impression that
> >>> embedded developers sometimes use old^Wstable systems, so some people
> >>> might be bitten by it. I think in this case it will affect all user
> >>> trying to build mkimage, regardless of the target platform?
> >>>
> >>> So I wanted to know what to do here?
> >>> - Can we provide some kind of compatibility support? OpenSSL seems
> >>>   to provide something:
> >>> https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes#Compatibility_Layer
> >>>   Haven't tested that fully yet, just downloading that tarball
> >>>   does not seem to cut it (or is missing files?). I guess one needs to
> >>>   copy&paste some code from the Wiki?
> >>> - Shall we detect missing v1.1.x support (via #if OPENSSL_VERSION_NUMBER
> >>>   < 0x10100000L) and disable just sunxi_toc0 support in this case?  
> >>
> >> There's two things.  First, the series should be on top of (sorry!)
> >> https://patchwork.ozlabs.org/project/uboot/patch/20210524202317.1492578-1-mr.nuke.me@gmail.com/
> >> which adds a similar Kconfig option to make building tools easier.
> > 
> > So this is on top of Simon's large series? Poor Samuel! Is there a
> > branch somewhere?
> 
> Now that all of these have landed, I'm rebasing this series.
> 
> >> Second, while I think not supporting openssl 1.0.x is fine,
> > 
> > Well, this was not what I was hoping for ;-)
> > I followed the advice on the OpenSSL wiki and now have a rather small
> > compatibility header file, which lets me compile mkimage even against
> > OpenSSL v1.0.2u. It seems like kwbimage.c has similar provisions in
> > place, I guess this could be merged into the external header?
> > Happy to send a patch on top, if this seems useful.
> 
> Considering the note from the OpenSSL website:
> 
> > Note: The latest stable version is the 1.1.1 series. This is also
> > our Long Term Support (LTS) version, supported until 11th September
> > 2023. All older versions (including 1.1.0, 1.0.2, 1.0.0 and 0.9.8)
> > are now out of support and should not be used. Users of these older
> > versions are encouraged to upgrade to 1.1.1 as soon as possible.
> and the fact that that I don't have access a system with an old OpenSSL,
> I'm not too interested in spending much effort on it. I will, though,
> happily test a patch if you do send one.

Since this series came up we now also have:
https://patchwork.ozlabs.org/project/uboot/patch/20210729183121.3798261-1-mr.nuke.me@gmail.com/

So I would rather not see more old openssl compatibility code added.

> >> I would like
> >> to again ask for someone to spend the time looking at switching to one
> >> of the GPL-compatible libraries as I'm pretty sure it's been raised a
> >> few times that we can't link with openssl like we do.
> > 
> > Why is that? Because Apache is not compatible with GPLv2? The OpenSSL
> > webpage says that:
> > "Can I use OpenSSL with GPL software?
> > On many systems including the major Linux and BSD distributions, yes
> > (the GPL does not place restrictions on using libraries that are part
> > of the normal operating system distribution)."
> > And for mkimage we just build a regular userspace tool, which is linked
> > against the system installed OpenSSL library. From my understanding
> > this is what this quote above means with being permitted?
> > 
> > And what would be the alternatives? Take one of the smaller ones and
> > embed them into the code?
> > Otherwise we would probably need to pick something that is widely
> > available and shipped with distros, I guess? Like GnuTLS,
> > libgcrypt, nettle? Maybe LibreSSL?
> > 
> > Samuel, do you have an insight what would be a good fit?
> 
> My original code was written against nettle. I switched to OpenSSL
> because that was already integrated into U-Boot (oops!), and to use the
> ASN.1 generation library (which the code no longer uses).
> 
> So nettle would work well here because all we need is SHA256 and plain
> RSA. I don't know about the other image types.

I'd like to see one of the parties that had noted the licensing problem
chime in and explain it again.

-- 
Tom

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 659 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/4] sunxi: TOC0 image type support
  2021-08-22 14:15         ` Tom Rini
@ 2021-08-22 21:37           ` Vagrant Cascadian
  2021-08-23  7:43             ` Peter Robinson
  0 siblings, 1 reply; 14+ messages in thread
From: Vagrant Cascadian @ 2021-08-22 21:37 UTC (permalink / raw)
  To: Tom Rini, Samuel Holland
  Cc: Andre Przywara, Jagan Teki, Hans de Goede, u-boot, Simon Glass,
	Jernej Škrabec

[-- Attachment #1: Type: text/plain, Size: 7809 bytes --]

On 2021-08-22, Tom Rini wrote:
> On Sat, Aug 21, 2021 at 09:19:56PM -0500, Samuel Holland wrote:
>> On 6/21/21 6:56 PM, Andre Przywara wrote:
>> > On Mon, 21 Jun 2021 16:35:37 -0400
>> > Tom Rini <trini@konsulko.com> wrote:
>> >> On Mon, Jun 21, 2021 at 04:43:00PM +0100, Andre Przywara wrote:
>> >>> On Sun, 20 Jun 2021 21:55:51 -0500
>> >>> Samuel Holland <samuel@sholland.org> wrote:
>> >>>
>> >>> (CC:ing Tom and Simon for the compatibility problem below)
>> >>>
>> >>> Hi,
>> >>>   
>> >>>> This series adds support for the TOC0 image format used by the Allwinner
>> >>>> secure boot ROM (SBROM). This series has been tested on the following
>> >>>> SoCs/boards, with the eFuse burnt to enable secure mode:
>> >>>>   - A64: Pine A64 Plus
>> >>>>   - H5: Orange Pi Zero Plus
>> >>>>   - H6: Pine H64 Model B
>> >>>>   - H616: Orange Pi Zero 2  
>> >>>
>> >>> many thanks for sending this. In general this looks good (will do a
>> >>> more thorough review soon), just one thing that bothered me:
>> >>>
>> >>> This requires OpenSLL 1.1.x. There is nothing really wrong about this,
>> >>> but my (admittedly not the freshest) Slackware, but also long term
>> >>> distros like RHEL/CentOS (<=7), still come with 1.0.x (headers) only.
>> >>>
>> >>> I was wondering how important this is? I have the impression that
>> >>> embedded developers sometimes use old^Wstable systems, so some people
>> >>> might be bitten by it. I think in this case it will affect all user
>> >>> trying to build mkimage, regardless of the target platform?
>> >>>
>> >>> So I wanted to know what to do here?
>> >>> - Can we provide some kind of compatibility support? OpenSSL seems
>> >>>   to provide something:
>> >>> https://wiki.openssl.org/index.php/OpenSSL_1.1.0_Changes#Compatibility_Layer
>> >>>   Haven't tested that fully yet, just downloading that tarball
>> >>>   does not seem to cut it (or is missing files?). I guess one needs to
>> >>>   copy&paste some code from the Wiki?
>> >>> - Shall we detect missing v1.1.x support (via #if OPENSSL_VERSION_NUMBER
>> >>>   < 0x10100000L) and disable just sunxi_toc0 support in this case?  
>> >>
>> >> There's two things.  First, the series should be on top of (sorry!)
>> >> https://patchwork.ozlabs.org/project/uboot/patch/20210524202317.1492578-1-mr.nuke.me@gmail.com/
>> >> which adds a similar Kconfig option to make building tools easier.
>> > 
>> > So this is on top of Simon's large series? Poor Samuel! Is there a
>> > branch somewhere?
>> 
>> Now that all of these have landed, I'm rebasing this series.
>> 
>> >> Second, while I think not supporting openssl 1.0.x is fine,
>> > 
>> > Well, this was not what I was hoping for ;-)
>> > I followed the advice on the OpenSSL wiki and now have a rather small
>> > compatibility header file, which lets me compile mkimage even against
>> > OpenSSL v1.0.2u. It seems like kwbimage.c has similar provisions in
>> > place, I guess this could be merged into the external header?
>> > Happy to send a patch on top, if this seems useful.
>> 
>> Considering the note from the OpenSSL website:
>> 
>> > Note: The latest stable version is the 1.1.1 series. This is also
>> > our Long Term Support (LTS) version, supported until 11th September
>> > 2023. All older versions (including 1.1.0, 1.0.2, 1.0.0 and 0.9.8)
>> > are now out of support and should not be used. Users of these older
>> > versions are encouraged to upgrade to 1.1.1 as soon as possible.
>> and the fact that that I don't have access a system with an old OpenSSL,
>> I'm not too interested in spending much effort on it. I will, though,
>> happily test a patch if you do send one.
>
> Since this series came up we now also have:
> https://patchwork.ozlabs.org/project/uboot/patch/20210729183121.3798261-1-mr.nuke.me@gmail.com/
>
> So I would rather not see more old openssl compatibility code added.
>
>> >> I would like
>> >> to again ask for someone to spend the time looking at switching to one
>> >> of the GPL-compatible libraries as I'm pretty sure it's been raised a
>> >> few times that we can't link with openssl like we do.
>> > 
>> > Why is that? Because Apache is not compatible with GPLv2? The OpenSSL
>> > webpage says that:
>> > "Can I use OpenSSL with GPL software?
>> > On many systems including the major Linux and BSD distributions, yes
>> > (the GPL does not place restrictions on using libraries that are part
>> > of the normal operating system distribution)."
>> > And for mkimage we just build a regular userspace tool, which is linked
>> > against the system installed OpenSSL library. From my understanding
>> > this is what this quote above means with being permitted?
>> > 
>> > And what would be the alternatives? Take one of the smaller ones and
>> > embed them into the code?
>> > Otherwise we would probably need to pick something that is widely
>> > available and shipped with distros, I guess? Like GnuTLS,
>> > libgcrypt, nettle? Maybe LibreSSL?
>> > 
>> > Samuel, do you have an insight what would be a good fit?
>> 
>> My original code was written against nettle. I switched to OpenSSL
>> because that was already integrated into U-Boot (oops!), and to use the
>> ASN.1 generation library (which the code no longer uses).
>> 
>> So nettle would work well here because all we need is SHA256 and plain
>> RSA. I don't know about the other image types.
>
> I'd like to see one of the parties that had noted the licensing problem
> chime in and explain it again.

The short of it is the openssl license has an advertising clause, and
the GPL requires no additional terms may be added when distributing
binaries. This is *fine* when distributing source code only, but once a
project such as Debian or some commercial entitry distributes binaries
of u-boot, the license incompatibility is triggered...

A more detailed explanation of the issue:

  https://people.gnome.org/~markmc/openssl-and-the-gpl.html


That said, Debian has recently and somewhat quietly decided to declare
openssl as a "system library" which in some opinions works around the
issue. I believe Fedora has used this workaround for quite a while
too. I personally think this is a very weak workaround and have only
reluctantly added openssl support in parts of Debian's u-boot packages,
and sometimes wonder if I shouldn't revert those changes...


If someone has the ability, time, resources, etc. to (optionally?)
switch u-boot to using a library that doesn't have any potential license
compatibility issues, that would be ideal, so ideal! But of course, it
requires *someone* to do the *work*. I don't believe *I* have the
requisite skills.


Another route would be to audit all the current codepaths using openssl
and get permission from all involved copyright holders to add a license
exception expressly permitting linking against openssl. In the past,
this was seen as something between impossible or implausible, due to the
sheer number of potential copyright holders which would need to give
permission to effectively relicense their GPL contributions with this
exception. Maybe the actual affected code paths would limit the number
of people involved enough to make it worth it... maybe not. Again, a
fair amount of work that *someone* would need to do just to even audit
the feasibility of this approach.


It is somewhat interesting to explore not adding *new* code to u-boot
that uses openssl by using a different library, and then the old code
might be able to be gradually migrated over to a different library? Last
I did a cursory look, nettle, gnutls and gcrypt seemed the most
promising candidates. I believe libressl has the same licensing issues
as openssl.


live well,
  vagrant

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 227 bytes --]

^ permalink raw reply	[flat|nested] 14+ messages in thread

* Re: [PATCH 0/4] sunxi: TOC0 image type support
  2021-08-22 21:37           ` Vagrant Cascadian
@ 2021-08-23  7:43             ` Peter Robinson
  0 siblings, 0 replies; 14+ messages in thread
From: Peter Robinson @ 2021-08-23  7:43 UTC (permalink / raw)
  To: Vagrant Cascadian
  Cc: Tom Rini, Samuel Holland, Andre Przywara, Jagan Teki,
	Hans de Goede, u-boot, Simon Glass, Jernej Škrabec

> > I'd like to see one of the parties that had noted the licensing problem
> > chime in and explain it again.
>
> The short of it is the openssl license has an advertising clause, and
> the GPL requires no additional terms may be added when distributing
> binaries. This is *fine* when distributing source code only, but once a
> project such as Debian or some commercial entitry distributes binaries
> of u-boot, the license incompatibility is triggered...

With OpenSSL 3, which is due shortly, the project will be moving to
the Apache 2 license.

> A more detailed explanation of the issue:
>
>   https://people.gnome.org/~markmc/openssl-and-the-gpl.html
>
>
> That said, Debian has recently and somewhat quietly decided to declare
> openssl as a "system library" which in some opinions works around the
> issue. I believe Fedora has used this workaround for quite a while
> too. I personally think this is a very weak workaround and have only
> reluctantly added openssl support in parts of Debian's u-boot packages,
> and sometimes wonder if I shouldn't revert those changes...

Fedora has always had OpenSSL as a system library but there's been
certain things that can't link against it because of incompatible
licenses.

>
> If someone has the ability, time, resources, etc. to (optionally?)
> switch u-boot to using a library that doesn't have any potential license
> compatibility issues, that would be ideal, so ideal! But of course, it
> requires *someone* to do the *work*. I don't believe *I* have the
> requisite skills.

It might be too soon to requiring something as new as openssl 3 but it
may also end up being the quickest way as openssl3 is parallel
installable with older versions.

> Another route would be to audit all the current codepaths using openssl
> and get permission from all involved copyright holders to add a license
> exception expressly permitting linking against openssl. In the past,
> this was seen as something between impossible or implausible, due to the
> sheer number of potential copyright holders which would need to give
> permission to effectively relicense their GPL contributions with this
> exception. Maybe the actual affected code paths would limit the number
> of people involved enough to make it worth it... maybe not. Again, a
> fair amount of work that *someone* would need to do just to even audit
> the feasibility of this approach.
>
>
> It is somewhat interesting to explore not adding *new* code to u-boot
> that uses openssl by using a different library, and then the old code
> might be able to be gradually migrated over to a different library? Last
> I did a cursory look, nettle, gnutls and gcrypt seemed the most
> promising candidates. I believe libressl has the same licensing issues
> as openssl.
>
>
> live well,
>   vagrant

^ permalink raw reply	[flat|nested] 14+ messages in thread

end of thread, other threads:[~2021-08-23  7:43 UTC | newest]

Thread overview: 14+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2021-06-21  2:55 [PATCH 0/4] sunxi: TOC0 image type support Samuel Holland
2021-06-21  2:55 ` [PATCH 1/4] tools: Refactor mkimage linking with OpenSSL Samuel Holland
2021-06-26 18:31   ` Simon Glass
2021-06-21  2:55 ` [PATCH 2/4] tools: mkimage: Add Allwinner TOC0 support Samuel Holland
2021-06-22  1:07   ` Andre Przywara
2021-06-21  2:55 ` [PATCH 3/4] sunxi: Support both SPL image types Samuel Holland
2021-06-21  2:55 ` [PATCH 4/4] sunxi: Support building a SPL as a TOC0 image Samuel Holland
2021-06-21 15:43 ` [PATCH 0/4] sunxi: TOC0 image type support Andre Przywara
2021-06-21 20:35   ` Tom Rini
2021-06-21 23:56     ` Andre Przywara
2021-08-22  2:19       ` Samuel Holland
2021-08-22 14:15         ` Tom Rini
2021-08-22 21:37           ` Vagrant Cascadian
2021-08-23  7:43             ` Peter Robinson

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.