xref: /rk3399_ARM-atf/tools/marvell/doimage/doimage.c (revision 5985a1e4264ac50f0b3408315c43ac65f3f5c631)
16414dc6dSKonstantin Porotchkin /*
26414dc6dSKonstantin Porotchkin  * Copyright (C) 2018 Marvell International Ltd.
36414dc6dSKonstantin Porotchkin  *
46414dc6dSKonstantin Porotchkin  * SPDX-License-Identifier:     BSD-3-Clause
56414dc6dSKonstantin Porotchkin  * https://spdx.org/licenses
66414dc6dSKonstantin Porotchkin  */
76414dc6dSKonstantin Porotchkin 
86414dc6dSKonstantin Porotchkin #include <stdlib.h>
96414dc6dSKonstantin Porotchkin #include <stdio.h>
106414dc6dSKonstantin Porotchkin #include <stdint.h>
116414dc6dSKonstantin Porotchkin #include <stddef.h>
126414dc6dSKonstantin Porotchkin #include <string.h>
136414dc6dSKonstantin Porotchkin #include <unistd.h>
146414dc6dSKonstantin Porotchkin #include <sys/stat.h>
156414dc6dSKonstantin Porotchkin #include <sys/time.h>
166414dc6dSKonstantin Porotchkin 
176414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT
186414dc6dSKonstantin Porotchkin #include <libconfig.h>	/* for parsing config file */
196414dc6dSKonstantin Porotchkin 
206414dc6dSKonstantin Porotchkin #if !defined(MBEDTLS_CONFIG_FILE)
216414dc6dSKonstantin Porotchkin #include "mbedtls/config.h"
226414dc6dSKonstantin Porotchkin #else
236414dc6dSKonstantin Porotchkin #include MBEDTLS_CONFIG_FILE
246414dc6dSKonstantin Porotchkin #endif
256414dc6dSKonstantin Porotchkin 
266414dc6dSKonstantin Porotchkin /* mbedTLS stuff */
276414dc6dSKonstantin Porotchkin #if defined(MBEDTLS_BIGNUM_C) && defined(MBEDTLS_ENTROPY_C) && \
286414dc6dSKonstantin Porotchkin 	defined(MBEDTLS_SHA256_C) && \
296414dc6dSKonstantin Porotchkin 	defined(MBEDTLS_PK_PARSE_C) && defined(MBEDTLS_FS_IO) && \
306414dc6dSKonstantin Porotchkin 	defined(MBEDTLS_CTR_DRBG_C)
316414dc6dSKonstantin Porotchkin #include <mbedtls/error.h>
326414dc6dSKonstantin Porotchkin #include <mbedtls/entropy.h>
336414dc6dSKonstantin Porotchkin #include <mbedtls/ctr_drbg.h>
346414dc6dSKonstantin Porotchkin #include <mbedtls/md.h>
356414dc6dSKonstantin Porotchkin #include <mbedtls/pk.h>
366414dc6dSKonstantin Porotchkin #include <mbedtls/sha256.h>
376414dc6dSKonstantin Porotchkin #include <mbedtls/x509.h>
386414dc6dSKonstantin Porotchkin #else
396414dc6dSKonstantin Porotchkin #error "Bad mbedTLS configuration!"
406414dc6dSKonstantin Porotchkin #endif
416414dc6dSKonstantin Porotchkin #endif /* CONFIG_MVEBU_SECURE_BOOT */
426414dc6dSKonstantin Porotchkin 
436414dc6dSKonstantin Porotchkin #define MAX_FILENAME		256
446414dc6dSKonstantin Porotchkin #define CSK_ARR_SZ		16
456414dc6dSKonstantin Porotchkin #define CSK_ARR_EMPTY_FILE	"*"
466414dc6dSKonstantin Porotchkin #define AES_KEY_BIT_LEN		256
476414dc6dSKonstantin Porotchkin #define AES_KEY_BYTE_LEN	(AES_KEY_BIT_LEN >> 3)
486414dc6dSKonstantin Porotchkin #define AES_BLOCK_SZ		16
496414dc6dSKonstantin Porotchkin #define RSA_SIGN_BYTE_LEN	256
506414dc6dSKonstantin Porotchkin #define MAX_RSA_DER_BYTE_LEN	524
516414dc6dSKonstantin Porotchkin /* Number of address pairs in control array */
526414dc6dSKonstantin Porotchkin #define CP_CTRL_EL_ARRAY_SZ	32
536414dc6dSKonstantin Porotchkin 
54a79df348SKonstantin Porotchkin #define VERSION_STRING		"Marvell(C) doimage utility version 3.3"
556414dc6dSKonstantin Porotchkin 
566414dc6dSKonstantin Porotchkin /* A8K definitions */
576414dc6dSKonstantin Porotchkin 
586414dc6dSKonstantin Porotchkin /* Extension header types */
596414dc6dSKonstantin Porotchkin #define EXT_TYPE_SECURITY	0x1
606414dc6dSKonstantin Porotchkin #define EXT_TYPE_BINARY		0x2
616414dc6dSKonstantin Porotchkin 
626414dc6dSKonstantin Porotchkin #define MAIN_HDR_MAGIC		0xB105B002
636414dc6dSKonstantin Porotchkin 
646414dc6dSKonstantin Porotchkin /* PROLOG alignment considerations:
656414dc6dSKonstantin Porotchkin  *  128B: To allow supporting XMODEM protocol.
666414dc6dSKonstantin Porotchkin  *  8KB: To align the boot image to the largest NAND page size, and simplify
676414dc6dSKonstantin Porotchkin  *  the read operations from NAND.
686414dc6dSKonstantin Porotchkin  *  We choose the largest page size, in order to use a single image for all
696414dc6dSKonstantin Porotchkin  *  NAND page sizes.
706414dc6dSKonstantin Porotchkin  */
716414dc6dSKonstantin Porotchkin #define PROLOG_ALIGNMENT	(8 << 10)
726414dc6dSKonstantin Porotchkin 
736414dc6dSKonstantin Porotchkin /* UART argument bitfield */
746414dc6dSKonstantin Porotchkin #define UART_MODE_UNMODIFIED	0x0
756414dc6dSKonstantin Porotchkin #define UART_MODE_DISABLE	0x1
766414dc6dSKonstantin Porotchkin #define UART_MODE_UPDATE	0x2
776414dc6dSKonstantin Porotchkin 
786414dc6dSKonstantin Porotchkin typedef struct _main_header {
796414dc6dSKonstantin Porotchkin 	uint32_t	magic;			/*  0-3  */
806414dc6dSKonstantin Porotchkin 	uint32_t	prolog_size;		/*  4-7  */
816414dc6dSKonstantin Porotchkin 	uint32_t	prolog_checksum;	/*  8-11 */
826414dc6dSKonstantin Porotchkin 	uint32_t	boot_image_size;	/* 12-15 */
836414dc6dSKonstantin Porotchkin 	uint32_t	boot_image_checksum;	/* 16-19 */
846414dc6dSKonstantin Porotchkin 	uint32_t	rsrvd0;			/* 20-23 */
856414dc6dSKonstantin Porotchkin 	uint32_t	load_addr;		/* 24-27 */
866414dc6dSKonstantin Porotchkin 	uint32_t	exec_addr;		/* 28-31 */
876414dc6dSKonstantin Porotchkin 	uint8_t		uart_cfg;		/*  32   */
886414dc6dSKonstantin Porotchkin 	uint8_t		baudrate;		/*  33   */
896414dc6dSKonstantin Porotchkin 	uint8_t		ext_count;		/*  34   */
906414dc6dSKonstantin Porotchkin 	uint8_t		aux_flags;		/*  35   */
916414dc6dSKonstantin Porotchkin 	uint32_t	io_arg_0;		/* 36-39 */
926414dc6dSKonstantin Porotchkin 	uint32_t	io_arg_1;		/* 40-43 */
936414dc6dSKonstantin Porotchkin 	uint32_t	io_arg_2;		/* 43-47 */
946414dc6dSKonstantin Porotchkin 	uint32_t	io_arg_3;		/* 48-51 */
956414dc6dSKonstantin Porotchkin 	uint32_t	rsrvd1;			/* 52-55 */
966414dc6dSKonstantin Porotchkin 	uint32_t	rsrvd2;			/* 56-59 */
976414dc6dSKonstantin Porotchkin 	uint32_t	rsrvd3;			/* 60-63 */
986414dc6dSKonstantin Porotchkin } header_t;
996414dc6dSKonstantin Porotchkin 
1006414dc6dSKonstantin Porotchkin typedef struct _ext_header {
1016414dc6dSKonstantin Porotchkin 	uint8_t		type;
1026414dc6dSKonstantin Porotchkin 	uint8_t		offset;
1036414dc6dSKonstantin Porotchkin 	uint16_t	reserved;
1046414dc6dSKonstantin Porotchkin 	uint32_t	size;
1056414dc6dSKonstantin Porotchkin } ext_header_t;
1066414dc6dSKonstantin Porotchkin 
1076414dc6dSKonstantin Porotchkin typedef struct _sec_entry {
1086414dc6dSKonstantin Porotchkin 	uint8_t		kak_key[MAX_RSA_DER_BYTE_LEN];
1096414dc6dSKonstantin Porotchkin 	uint32_t	jtag_delay;
1106414dc6dSKonstantin Porotchkin 	uint32_t	box_id;
1116414dc6dSKonstantin Porotchkin 	uint32_t	flash_id;
1126414dc6dSKonstantin Porotchkin 	uint32_t	jtag_en;
1136414dc6dSKonstantin Porotchkin 	uint32_t	encrypt_en;
1146414dc6dSKonstantin Porotchkin 	uint32_t	efuse_dis;
1156414dc6dSKonstantin Porotchkin 	uint8_t		header_sign[RSA_SIGN_BYTE_LEN];
1166414dc6dSKonstantin Porotchkin 	uint8_t		image_sign[RSA_SIGN_BYTE_LEN];
1176414dc6dSKonstantin Porotchkin 	uint8_t		csk_keys[CSK_ARR_SZ][MAX_RSA_DER_BYTE_LEN];
1186414dc6dSKonstantin Porotchkin 	uint8_t		csk_sign[RSA_SIGN_BYTE_LEN];
1196414dc6dSKonstantin Porotchkin 	uint32_t	cp_ctrl_arr[CP_CTRL_EL_ARRAY_SZ];
1206414dc6dSKonstantin Porotchkin 	uint32_t	cp_efuse_arr[CP_CTRL_EL_ARRAY_SZ];
1216414dc6dSKonstantin Porotchkin } sec_entry_t;
1226414dc6dSKonstantin Porotchkin 
1236414dc6dSKonstantin Porotchkin /* A8K definitions end */
1246414dc6dSKonstantin Porotchkin 
1256414dc6dSKonstantin Porotchkin /* UART argument bitfield */
1266414dc6dSKonstantin Porotchkin #define UART_MODE_UNMODIFIED	0x0
1276414dc6dSKonstantin Porotchkin #define UART_MODE_DISABLE	0x1
1286414dc6dSKonstantin Porotchkin #define UART_MODE_UPDATE	0x2
1296414dc6dSKonstantin Porotchkin 
1306414dc6dSKonstantin Porotchkin #define uart_set_mode(arg, mode)	(arg |= (mode & 0x3))
1316414dc6dSKonstantin Porotchkin 
1326414dc6dSKonstantin Porotchkin typedef struct _sec_options {
1336414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT
1346414dc6dSKonstantin Porotchkin 	char aes_key_file[MAX_FILENAME+1];
1356414dc6dSKonstantin Porotchkin 	char kak_key_file[MAX_FILENAME+1];
1366414dc6dSKonstantin Porotchkin 	char csk_key_file[CSK_ARR_SZ][MAX_FILENAME+1];
1376414dc6dSKonstantin Porotchkin 	uint32_t	box_id;
1386414dc6dSKonstantin Porotchkin 	uint32_t	flash_id;
1396414dc6dSKonstantin Porotchkin 	uint32_t	jtag_delay;
1406414dc6dSKonstantin Porotchkin 	uint8_t		csk_index;
1416414dc6dSKonstantin Porotchkin 	uint8_t		jtag_enable;
1426414dc6dSKonstantin Porotchkin 	uint8_t		efuse_disable;
1436414dc6dSKonstantin Porotchkin 	uint32_t	cp_ctrl_arr[CP_CTRL_EL_ARRAY_SZ];
1446414dc6dSKonstantin Porotchkin 	uint32_t	cp_efuse_arr[CP_CTRL_EL_ARRAY_SZ];
1456414dc6dSKonstantin Porotchkin 	mbedtls_pk_context	kak_pk;
1466414dc6dSKonstantin Porotchkin 	mbedtls_pk_context	csk_pk[CSK_ARR_SZ];
1476414dc6dSKonstantin Porotchkin 	uint8_t		aes_key[AES_KEY_BYTE_LEN];
1486414dc6dSKonstantin Porotchkin 	uint8_t		*encrypted_image;
1496414dc6dSKonstantin Porotchkin 	uint32_t	enc_image_sz;
1506414dc6dSKonstantin Porotchkin #endif
1516414dc6dSKonstantin Porotchkin } sec_options;
1526414dc6dSKonstantin Porotchkin 
1536414dc6dSKonstantin Porotchkin typedef struct _options {
1546414dc6dSKonstantin Porotchkin 	char bin_ext_file[MAX_FILENAME+1];
1556414dc6dSKonstantin Porotchkin 	char sec_cfg_file[MAX_FILENAME+1];
1566414dc6dSKonstantin Porotchkin 	sec_options *sec_opts;
1576414dc6dSKonstantin Porotchkin 	uint32_t  load_addr;
1586414dc6dSKonstantin Porotchkin 	uint32_t  exec_addr;
1596414dc6dSKonstantin Porotchkin 	uint32_t  baudrate;
1606414dc6dSKonstantin Porotchkin 	uint8_t	  disable_print;
1616414dc6dSKonstantin Porotchkin 	int8_t    key_index; /* For header signatures verification only */
1626414dc6dSKonstantin Porotchkin 	uint32_t  nfc_io_args;
1636414dc6dSKonstantin Porotchkin } options_t;
1646414dc6dSKonstantin Porotchkin 
1656414dc6dSKonstantin Porotchkin void usage_err(char *msg)
1666414dc6dSKonstantin Porotchkin {
1676414dc6dSKonstantin Porotchkin 	fprintf(stderr, "Error: %s\n", msg);
1686414dc6dSKonstantin Porotchkin 	fprintf(stderr, "run 'doimage -h' to get usage information\n");
1696414dc6dSKonstantin Porotchkin 	exit(-1);
1706414dc6dSKonstantin Porotchkin }
1716414dc6dSKonstantin Porotchkin 
1726414dc6dSKonstantin Porotchkin void usage(void)
1736414dc6dSKonstantin Porotchkin {
1746414dc6dSKonstantin Porotchkin 	printf("\n\n%s\n\n", VERSION_STRING);
1756414dc6dSKonstantin Porotchkin 	printf("Usage: doimage [options] <input_file> [output_file]\n");
1766414dc6dSKonstantin Porotchkin 	printf("create bootrom image from u-boot and boot extensions\n\n");
1776414dc6dSKonstantin Porotchkin 
1786414dc6dSKonstantin Porotchkin 	printf("Arguments\n");
1796414dc6dSKonstantin Porotchkin 	printf("  input_file   name of boot image file.\n");
1806414dc6dSKonstantin Porotchkin 	printf("               if -p is used, name of the bootrom image file");
1816414dc6dSKonstantin Porotchkin 	printf("               to parse.\n");
1826414dc6dSKonstantin Porotchkin 	printf("  output_file  name of output bootrom image file\n");
1836414dc6dSKonstantin Porotchkin 
1846414dc6dSKonstantin Porotchkin 	printf("\nOptions\n");
1856414dc6dSKonstantin Porotchkin 	printf("  -s        target SOC name. supports a8020,a7020\n");
1866414dc6dSKonstantin Porotchkin 	printf("            different SOCs may have different boot image\n");
1876414dc6dSKonstantin Porotchkin 	printf("            format so it's mandatory to know the target SOC\n");
1886414dc6dSKonstantin Porotchkin 	printf("  -i        boot I/F name. supports nand, spi, nor\n");
1896414dc6dSKonstantin Porotchkin 	printf("            This affects certain parameters coded in the\n");
1906414dc6dSKonstantin Porotchkin 	printf("            image header\n");
1916414dc6dSKonstantin Porotchkin 	printf("  -l        boot image load address. default is 0x0\n");
1926414dc6dSKonstantin Porotchkin 	printf("  -e        boot image entry address. default is 0x0\n");
1936414dc6dSKonstantin Porotchkin 	printf("  -b        binary extension image file.\n");
1946414dc6dSKonstantin Porotchkin 	printf("            This image is executed before the boot image.\n");
1956414dc6dSKonstantin Porotchkin 	printf("            This is typically used to initialize the memory ");
1966414dc6dSKonstantin Porotchkin 	printf("            controller.\n");
1976414dc6dSKonstantin Porotchkin 	printf("            Currently supports only a single file.\n");
1986414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT
1996414dc6dSKonstantin Porotchkin 	printf("  -c        Make trusted boot image using parameters\n");
2006414dc6dSKonstantin Porotchkin 	printf("            from the configuration file.\n");
2016414dc6dSKonstantin Porotchkin #endif
2026414dc6dSKonstantin Porotchkin 	printf("  -p        Parse and display a pre-built boot image\n");
2036414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT
2046414dc6dSKonstantin Porotchkin 	printf("  -k        Key index for RSA signatures verification\n");
2056414dc6dSKonstantin Porotchkin 	printf("            when parsing the boot image\n");
2066414dc6dSKonstantin Porotchkin #endif
2076414dc6dSKonstantin Porotchkin 	printf("  -m        Disable prints of bootrom and binary extension\n");
2086414dc6dSKonstantin Porotchkin 	printf("  -u        UART baudrate used for bootrom prints.\n");
2096414dc6dSKonstantin Porotchkin 	printf("            Must be multiple of 1200\n");
2106414dc6dSKonstantin Porotchkin 	printf("  -h        Show this help message\n");
2116414dc6dSKonstantin Porotchkin 	printf(" IO-ROM NFC-NAND boot parameters:\n");
2126414dc6dSKonstantin Porotchkin 	printf("  -n        NAND device block size in KB [Default is 64KB].\n");
2136414dc6dSKonstantin Porotchkin 	printf("  -t        NAND cell technology (SLC [Default] or MLC)\n");
2146414dc6dSKonstantin Porotchkin 
2156414dc6dSKonstantin Porotchkin 	exit(-1);
2166414dc6dSKonstantin Porotchkin }
2176414dc6dSKonstantin Porotchkin 
2186414dc6dSKonstantin Porotchkin /* globals */
2196414dc6dSKonstantin Porotchkin static options_t opts = {
2206414dc6dSKonstantin Porotchkin 	.bin_ext_file = "NA",
2216414dc6dSKonstantin Porotchkin 	.sec_cfg_file = "NA",
2226414dc6dSKonstantin Porotchkin 	.sec_opts = 0,
2236414dc6dSKonstantin Porotchkin 	.load_addr = 0x0,
2246414dc6dSKonstantin Porotchkin 	.exec_addr = 0x0,
2256414dc6dSKonstantin Porotchkin 	.disable_print = 0,
2266414dc6dSKonstantin Porotchkin 	.baudrate = 0,
2276414dc6dSKonstantin Porotchkin 	.key_index = -1,
2286414dc6dSKonstantin Porotchkin };
2296414dc6dSKonstantin Porotchkin 
2306414dc6dSKonstantin Porotchkin int get_file_size(char *filename)
2316414dc6dSKonstantin Porotchkin {
2326414dc6dSKonstantin Porotchkin 	struct stat st;
2336414dc6dSKonstantin Porotchkin 
2346414dc6dSKonstantin Porotchkin 	if (stat(filename, &st) == 0)
2356414dc6dSKonstantin Porotchkin 		return st.st_size;
2366414dc6dSKonstantin Porotchkin 
2376414dc6dSKonstantin Porotchkin 	return -1;
2386414dc6dSKonstantin Porotchkin }
2396414dc6dSKonstantin Porotchkin 
2406414dc6dSKonstantin Porotchkin uint32_t checksum32(uint32_t *start, int len)
2416414dc6dSKonstantin Porotchkin {
2426414dc6dSKonstantin Porotchkin 	uint32_t sum = 0;
2436414dc6dSKonstantin Porotchkin 	uint32_t *startp = start;
2446414dc6dSKonstantin Porotchkin 
2456414dc6dSKonstantin Porotchkin 	do {
2466414dc6dSKonstantin Porotchkin 		sum += *startp;
2476414dc6dSKonstantin Porotchkin 		startp++;
2486414dc6dSKonstantin Porotchkin 		len -= 4;
2496414dc6dSKonstantin Porotchkin 	} while (len > 0);
2506414dc6dSKonstantin Porotchkin 
2516414dc6dSKonstantin Porotchkin 	return sum;
2526414dc6dSKonstantin Porotchkin }
2536414dc6dSKonstantin Porotchkin 
2546414dc6dSKonstantin Porotchkin /*******************************************************************************
2556414dc6dSKonstantin Porotchkin  *    create_rsa_signature (memory buffer content)
2566414dc6dSKonstantin Porotchkin  *          Create RSASSA-PSS/SHA-256 signature for memory buffer
2576414dc6dSKonstantin Porotchkin  *          using RSA Private Key
2586414dc6dSKonstantin Porotchkin  *    INPUT:
2596414dc6dSKonstantin Porotchkin  *          pk_ctx     Private Key context
2606414dc6dSKonstantin Porotchkin  *          input      memory buffer
2616414dc6dSKonstantin Porotchkin  *          ilen       buffer length
2626414dc6dSKonstantin Porotchkin  *          pers       personalization string for seeding the RNG.
2636414dc6dSKonstantin Porotchkin  *                     For instance a private key file name.
2646414dc6dSKonstantin Porotchkin  *    OUTPUT:
2656414dc6dSKonstantin Porotchkin  *          signature  RSA-2048 signature
2666414dc6dSKonstantin Porotchkin  *    RETURN:
2676414dc6dSKonstantin Porotchkin  *          0 on success
2686414dc6dSKonstantin Porotchkin  */
2696414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT
2706414dc6dSKonstantin Porotchkin int create_rsa_signature(mbedtls_pk_context	*pk_ctx,
2716414dc6dSKonstantin Porotchkin 			 const unsigned char	*input,
2726414dc6dSKonstantin Porotchkin 			 size_t			ilen,
2736414dc6dSKonstantin Porotchkin 			 const char		*pers,
2746414dc6dSKonstantin Porotchkin 			 uint8_t		*signature)
2756414dc6dSKonstantin Porotchkin {
2766414dc6dSKonstantin Porotchkin 	mbedtls_entropy_context		entropy;
2776414dc6dSKonstantin Porotchkin 	mbedtls_ctr_drbg_context	ctr_drbg;
2786414dc6dSKonstantin Porotchkin 	unsigned char			hash[32];
2796414dc6dSKonstantin Porotchkin 	unsigned char			buf[MBEDTLS_MPI_MAX_SIZE];
2806414dc6dSKonstantin Porotchkin 	int				rval;
2816414dc6dSKonstantin Porotchkin 
2826414dc6dSKonstantin Porotchkin 	/* Not sure this is required,
2836414dc6dSKonstantin Porotchkin 	 * but it's safer to start with empty buffers
2846414dc6dSKonstantin Porotchkin 	 */
2856414dc6dSKonstantin Porotchkin 	memset(hash, 0, sizeof(hash));
2866414dc6dSKonstantin Porotchkin 	memset(buf, 0, sizeof(buf));
2876414dc6dSKonstantin Porotchkin 
2886414dc6dSKonstantin Porotchkin 	mbedtls_ctr_drbg_init(&ctr_drbg);
2896414dc6dSKonstantin Porotchkin 	mbedtls_entropy_init(&entropy);
2906414dc6dSKonstantin Porotchkin 
2916414dc6dSKonstantin Porotchkin 	/* Seed the random number generator */
2926414dc6dSKonstantin Porotchkin 	rval = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
2936414dc6dSKonstantin Porotchkin 				(const unsigned char *)pers, strlen(pers));
2946414dc6dSKonstantin Porotchkin 	if (rval != 0) {
2956414dc6dSKonstantin Porotchkin 		fprintf(stderr, " Failed in ctr_drbg_init call (%d)!\n", rval);
2966414dc6dSKonstantin Porotchkin 		goto sign_exit;
2976414dc6dSKonstantin Porotchkin 	}
2986414dc6dSKonstantin Porotchkin 
2996414dc6dSKonstantin Porotchkin 	/* The PK context should be already initialized.
3006414dc6dSKonstantin Porotchkin 	 * Set the padding type for this PK context
3016414dc6dSKonstantin Porotchkin 	 */
3026414dc6dSKonstantin Porotchkin 	mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pk_ctx),
3036414dc6dSKonstantin Porotchkin 				MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256);
3046414dc6dSKonstantin Porotchkin 
3056414dc6dSKonstantin Porotchkin 	/* First compute the SHA256 hash for the input blob */
306a79df348SKonstantin Porotchkin 	mbedtls_sha256_ret(input, ilen, hash, 0);
3076414dc6dSKonstantin Porotchkin 
3086414dc6dSKonstantin Porotchkin 	/* Then calculate the hash signature */
3096414dc6dSKonstantin Porotchkin 	rval = mbedtls_rsa_rsassa_pss_sign(mbedtls_pk_rsa(*pk_ctx),
3106414dc6dSKonstantin Porotchkin 					   mbedtls_ctr_drbg_random,
3116414dc6dSKonstantin Porotchkin 					   &ctr_drbg,
3126414dc6dSKonstantin Porotchkin 					   MBEDTLS_RSA_PRIVATE,
3136414dc6dSKonstantin Porotchkin 					   MBEDTLS_MD_SHA256, 0, hash, buf);
3146414dc6dSKonstantin Porotchkin 	if (rval != 0) {
3156414dc6dSKonstantin Porotchkin 		fprintf(stderr,
3166414dc6dSKonstantin Porotchkin 			"Failed to create RSA signature for %s. Error %d\n",
3176414dc6dSKonstantin Porotchkin 			pers, rval);
3186414dc6dSKonstantin Porotchkin 		goto sign_exit;
3196414dc6dSKonstantin Porotchkin 	}
3206414dc6dSKonstantin Porotchkin 	memcpy(signature, buf, 256);
3216414dc6dSKonstantin Porotchkin 
3226414dc6dSKonstantin Porotchkin sign_exit:
3236414dc6dSKonstantin Porotchkin 	mbedtls_ctr_drbg_free(&ctr_drbg);
3246414dc6dSKonstantin Porotchkin 	mbedtls_entropy_free(&entropy);
3256414dc6dSKonstantin Porotchkin 
3266414dc6dSKonstantin Porotchkin 	return rval;
3276414dc6dSKonstantin Porotchkin } /* end of create_rsa_signature */
3286414dc6dSKonstantin Porotchkin 
3296414dc6dSKonstantin Porotchkin /*******************************************************************************
3306414dc6dSKonstantin Porotchkin  *    verify_rsa_signature (memory buffer content)
3316414dc6dSKonstantin Porotchkin  *          Verify RSASSA-PSS/SHA-256 signature for memory buffer
3326414dc6dSKonstantin Porotchkin  *          using RSA Public Key
3336414dc6dSKonstantin Porotchkin  *    INPUT:
3346414dc6dSKonstantin Porotchkin  *          pub_key    Public Key buffer
3356414dc6dSKonstantin Porotchkin  *          ilen       Public Key buffer length
3366414dc6dSKonstantin Porotchkin  *          input      memory buffer
3376414dc6dSKonstantin Porotchkin  *          ilen       buffer length
3386414dc6dSKonstantin Porotchkin  *          pers       personalization string for seeding the RNG.
3396414dc6dSKonstantin Porotchkin  *          signature  RSA-2048 signature
3406414dc6dSKonstantin Porotchkin  *    OUTPUT:
3416414dc6dSKonstantin Porotchkin  *          none
3426414dc6dSKonstantin Porotchkin  *    RETURN:
3436414dc6dSKonstantin Porotchkin  *          0 on success
3446414dc6dSKonstantin Porotchkin  */
3456414dc6dSKonstantin Porotchkin int verify_rsa_signature(const unsigned char	*pub_key,
3466414dc6dSKonstantin Porotchkin 			 size_t			klen,
3476414dc6dSKonstantin Porotchkin 			 const unsigned char	*input,
3486414dc6dSKonstantin Porotchkin 			 size_t			ilen,
3496414dc6dSKonstantin Porotchkin 			 const char		*pers,
3506414dc6dSKonstantin Porotchkin 			 uint8_t		*signature)
3516414dc6dSKonstantin Porotchkin {
3526414dc6dSKonstantin Porotchkin 	mbedtls_entropy_context		entropy;
3536414dc6dSKonstantin Porotchkin 	mbedtls_ctr_drbg_context	ctr_drbg;
3546414dc6dSKonstantin Porotchkin 	mbedtls_pk_context		pk_ctx;
3556414dc6dSKonstantin Porotchkin 	unsigned char			hash[32];
3566414dc6dSKonstantin Porotchkin 	int				rval;
357a79df348SKonstantin Porotchkin 	unsigned char			*pkey = (unsigned char *)pub_key;
3586414dc6dSKonstantin Porotchkin 
3596414dc6dSKonstantin Porotchkin 	/* Not sure this is required,
3606414dc6dSKonstantin Porotchkin 	 * but it's safer to start with empty buffer
3616414dc6dSKonstantin Porotchkin 	 */
3626414dc6dSKonstantin Porotchkin 	memset(hash, 0, sizeof(hash));
3636414dc6dSKonstantin Porotchkin 
3646414dc6dSKonstantin Porotchkin 	mbedtls_pk_init(&pk_ctx);
3656414dc6dSKonstantin Porotchkin 	mbedtls_ctr_drbg_init(&ctr_drbg);
3666414dc6dSKonstantin Porotchkin 	mbedtls_entropy_init(&entropy);
3676414dc6dSKonstantin Porotchkin 
3686414dc6dSKonstantin Porotchkin 	/* Seed the random number generator */
3696414dc6dSKonstantin Porotchkin 	rval = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
3706414dc6dSKonstantin Porotchkin 				(const unsigned char *)pers, strlen(pers));
3716414dc6dSKonstantin Porotchkin 	if (rval != 0) {
3726414dc6dSKonstantin Porotchkin 		fprintf(stderr, " Failed in ctr_drbg_init call (%d)!\n", rval);
3736414dc6dSKonstantin Porotchkin 		goto verify_exit;
3746414dc6dSKonstantin Porotchkin 	}
3756414dc6dSKonstantin Porotchkin 
3766414dc6dSKonstantin Porotchkin 	/* Check ability to read the public key */
377a79df348SKonstantin Porotchkin 	rval = mbedtls_pk_parse_subpubkey(&pkey, pub_key + klen, &pk_ctx);
3786414dc6dSKonstantin Porotchkin 	if (rval != 0) {
3796414dc6dSKonstantin Porotchkin 		fprintf(stderr, " Failed in pk_parse_public_key (%#x)!\n",
3806414dc6dSKonstantin Porotchkin 			rval);
3816414dc6dSKonstantin Porotchkin 		goto verify_exit;
3826414dc6dSKonstantin Porotchkin 	}
3836414dc6dSKonstantin Porotchkin 
3846414dc6dSKonstantin Porotchkin 	/* Set the padding type for the new PK context */
3856414dc6dSKonstantin Porotchkin 	mbedtls_rsa_set_padding(mbedtls_pk_rsa(pk_ctx),
3866414dc6dSKonstantin Porotchkin 				MBEDTLS_RSA_PKCS_V21,
3876414dc6dSKonstantin Porotchkin 				MBEDTLS_MD_SHA256);
3886414dc6dSKonstantin Porotchkin 
3896414dc6dSKonstantin Porotchkin 	/* Compute the SHA256 hash for the input buffer */
390a79df348SKonstantin Porotchkin 	mbedtls_sha256_ret(input, ilen, hash, 0);
3916414dc6dSKonstantin Porotchkin 
3926414dc6dSKonstantin Porotchkin 	rval = mbedtls_rsa_rsassa_pss_verify(mbedtls_pk_rsa(pk_ctx),
3936414dc6dSKonstantin Porotchkin 					     mbedtls_ctr_drbg_random,
3946414dc6dSKonstantin Porotchkin 					     &ctr_drbg,
3956414dc6dSKonstantin Porotchkin 					     MBEDTLS_RSA_PUBLIC,
3966414dc6dSKonstantin Porotchkin 					     MBEDTLS_MD_SHA256, 0,
3976414dc6dSKonstantin Porotchkin 					     hash, signature);
3986414dc6dSKonstantin Porotchkin 	if (rval != 0)
3996414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Failed to verify signature (%d)!\n", rval);
4006414dc6dSKonstantin Porotchkin 
4016414dc6dSKonstantin Porotchkin verify_exit:
4026414dc6dSKonstantin Porotchkin 
4036414dc6dSKonstantin Porotchkin 	mbedtls_pk_free(&pk_ctx);
4046414dc6dSKonstantin Porotchkin 	mbedtls_ctr_drbg_free(&ctr_drbg);
4056414dc6dSKonstantin Porotchkin 	mbedtls_entropy_free(&entropy);
4066414dc6dSKonstantin Porotchkin 	return rval;
4076414dc6dSKonstantin Porotchkin } /* end of verify_rsa_signature */
4086414dc6dSKonstantin Porotchkin 
4096414dc6dSKonstantin Porotchkin /*******************************************************************************
4106414dc6dSKonstantin Porotchkin  *    image_encrypt
4116414dc6dSKonstantin Porotchkin  *           Encrypt image buffer using AES-256-CBC scheme.
4126414dc6dSKonstantin Porotchkin  *           The resulting image is saved into opts.sec_opts->encrypted_image
4136414dc6dSKonstantin Porotchkin  *           and the adjusted image size into opts.sec_opts->enc_image_sz
4146414dc6dSKonstantin Porotchkin  *           First AES_BLOCK_SZ bytes of the output image contain IV
4156414dc6dSKonstantin Porotchkin  *    INPUT:
4166414dc6dSKonstantin Porotchkin  *          buf        Source buffer to encrypt
4176414dc6dSKonstantin Porotchkin  *          blen       Source buffer length
4186414dc6dSKonstantin Porotchkin  *    OUTPUT:
4196414dc6dSKonstantin Porotchkin  *          none
4206414dc6dSKonstantin Porotchkin  *    RETURN:
4216414dc6dSKonstantin Porotchkin  *          0 on success
4226414dc6dSKonstantin Porotchkin  */
4236414dc6dSKonstantin Porotchkin int image_encrypt(uint8_t *buf, uint32_t blen)
4246414dc6dSKonstantin Porotchkin {
4256414dc6dSKonstantin Porotchkin 	struct timeval		tv;
4266414dc6dSKonstantin Porotchkin 	char			*ptmp = (char *)&tv;
4276414dc6dSKonstantin Porotchkin 	unsigned char		digest[32];
4286414dc6dSKonstantin Porotchkin 	unsigned char		IV[AES_BLOCK_SZ];
4296414dc6dSKonstantin Porotchkin 	int			i, k;
4306414dc6dSKonstantin Porotchkin 	mbedtls_aes_context	aes_ctx;
4316414dc6dSKonstantin Porotchkin 	int			rval = -1;
4326414dc6dSKonstantin Porotchkin 	uint8_t			*test_img = 0;
4336414dc6dSKonstantin Porotchkin 
4346414dc6dSKonstantin Porotchkin 	if (AES_BLOCK_SZ > 32) {
4356414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Unsupported AES block size %d\n",
4366414dc6dSKonstantin Porotchkin 			AES_BLOCK_SZ);
4376414dc6dSKonstantin Porotchkin 		return rval;
4386414dc6dSKonstantin Porotchkin 	}
4396414dc6dSKonstantin Porotchkin 
4406414dc6dSKonstantin Porotchkin 	mbedtls_aes_init(&aes_ctx);
4416414dc6dSKonstantin Porotchkin 	memset(IV, 0, AES_BLOCK_SZ);
4426414dc6dSKonstantin Porotchkin 	memset(digest, 0, 32);
4436414dc6dSKonstantin Porotchkin 
4446414dc6dSKonstantin Porotchkin 	/* Generate initialization vector and init the AES engine
4456414dc6dSKonstantin Porotchkin 	 * Use file name XOR current time and finally SHA-256
4466414dc6dSKonstantin Porotchkin 	 * [0...AES_BLOCK_SZ-1]
4476414dc6dSKonstantin Porotchkin 	 */
4486414dc6dSKonstantin Porotchkin 	k = strlen(opts.sec_opts->aes_key_file);
4496414dc6dSKonstantin Porotchkin 	if (k > AES_BLOCK_SZ)
4506414dc6dSKonstantin Porotchkin 		k = AES_BLOCK_SZ;
4516414dc6dSKonstantin Porotchkin 	memcpy(IV, opts.sec_opts->aes_key_file, k);
4526414dc6dSKonstantin Porotchkin 	gettimeofday(&tv, 0);
4536414dc6dSKonstantin Porotchkin 
4546414dc6dSKonstantin Porotchkin 	for (i = 0, k = 0; i < AES_BLOCK_SZ; i++,
4556414dc6dSKonstantin Porotchkin 	     k = (k+1) % sizeof(struct timeval))
4566414dc6dSKonstantin Porotchkin 		IV[i] ^= ptmp[k];
4576414dc6dSKonstantin Porotchkin 
4586414dc6dSKonstantin Porotchkin 	/* compute SHA-256 digest of the results
4596414dc6dSKonstantin Porotchkin 	 * and use it as the init vector (IV)
4606414dc6dSKonstantin Porotchkin 	 */
461a79df348SKonstantin Porotchkin 	mbedtls_sha256_ret(IV, AES_BLOCK_SZ, digest, 0);
4626414dc6dSKonstantin Porotchkin 	memcpy(IV, digest, AES_BLOCK_SZ);
4636414dc6dSKonstantin Porotchkin 	mbedtls_aes_setkey_enc(&aes_ctx, opts.sec_opts->aes_key,
4646414dc6dSKonstantin Porotchkin 			       AES_KEY_BIT_LEN);
4656414dc6dSKonstantin Porotchkin 
4666414dc6dSKonstantin Porotchkin 	/* The output image has to include extra space for IV
4676414dc6dSKonstantin Porotchkin 	 * and to be aligned to the AES block size.
4686414dc6dSKonstantin Porotchkin 	 * The input image buffer has to be already aligned to AES_BLOCK_SZ
4696414dc6dSKonstantin Porotchkin 	 * and padded with zeroes
4706414dc6dSKonstantin Porotchkin 	 */
4716414dc6dSKonstantin Porotchkin 	opts.sec_opts->enc_image_sz = (blen + 2 * AES_BLOCK_SZ - 1) &
4726414dc6dSKonstantin Porotchkin 				      ~(AES_BLOCK_SZ - 1);
4736414dc6dSKonstantin Porotchkin 	opts.sec_opts->encrypted_image = calloc(opts.sec_opts->enc_image_sz, 1);
4746414dc6dSKonstantin Porotchkin 	if (opts.sec_opts->encrypted_image == 0) {
4756414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Failed to allocate encrypted image!\n");
4766414dc6dSKonstantin Porotchkin 		goto encrypt_exit;
4776414dc6dSKonstantin Porotchkin 	}
4786414dc6dSKonstantin Porotchkin 
4796414dc6dSKonstantin Porotchkin 	/* Put IV into the output buffer next to the encrypted image
4806414dc6dSKonstantin Porotchkin 	 * Since the IV is modified by the encryption function,
4816414dc6dSKonstantin Porotchkin 	 * this should be done now
4826414dc6dSKonstantin Porotchkin 	 */
4836414dc6dSKonstantin Porotchkin 	memcpy(opts.sec_opts->encrypted_image +
4846414dc6dSKonstantin Porotchkin 		   opts.sec_opts->enc_image_sz - AES_BLOCK_SZ,
4856414dc6dSKonstantin Porotchkin 		   IV, AES_BLOCK_SZ);
4866414dc6dSKonstantin Porotchkin 	rval = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT,
4876414dc6dSKonstantin Porotchkin 			     opts.sec_opts->enc_image_sz - AES_BLOCK_SZ,
4886414dc6dSKonstantin Porotchkin 			     IV, buf, opts.sec_opts->encrypted_image);
4896414dc6dSKonstantin Porotchkin 	if (rval != 0) {
4906414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Failed to encrypt the image! Error %d\n",
4916414dc6dSKonstantin Porotchkin 			rval);
4926414dc6dSKonstantin Porotchkin 		goto encrypt_exit;
4936414dc6dSKonstantin Porotchkin 	}
4946414dc6dSKonstantin Porotchkin 
4956414dc6dSKonstantin Porotchkin 	mbedtls_aes_free(&aes_ctx);
4966414dc6dSKonstantin Porotchkin 
4976414dc6dSKonstantin Porotchkin 	/* Try to decrypt the image and compare it with the original data */
4986414dc6dSKonstantin Porotchkin 	mbedtls_aes_init(&aes_ctx);
4996414dc6dSKonstantin Porotchkin 	mbedtls_aes_setkey_dec(&aes_ctx, opts.sec_opts->aes_key,
5006414dc6dSKonstantin Porotchkin 			       AES_KEY_BIT_LEN);
5016414dc6dSKonstantin Porotchkin 
5026414dc6dSKonstantin Porotchkin 	test_img = calloc(opts.sec_opts->enc_image_sz - AES_BLOCK_SZ, 1);
5036414dc6dSKonstantin Porotchkin 	if (test_img == 0) {
5046414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Failed to allocate test image!d\n");
5056414dc6dSKonstantin Porotchkin 		rval = -1;
5066414dc6dSKonstantin Porotchkin 		goto encrypt_exit;
5076414dc6dSKonstantin Porotchkin 	}
5086414dc6dSKonstantin Porotchkin 
5096414dc6dSKonstantin Porotchkin 	memcpy(IV, opts.sec_opts->encrypted_image +
5106414dc6dSKonstantin Porotchkin 		   opts.sec_opts->enc_image_sz - AES_BLOCK_SZ,
5116414dc6dSKonstantin Porotchkin 		   AES_BLOCK_SZ);
5126414dc6dSKonstantin Porotchkin 	rval = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT,
5136414dc6dSKonstantin Porotchkin 			     opts.sec_opts->enc_image_sz - AES_BLOCK_SZ,
5146414dc6dSKonstantin Porotchkin 			     IV, opts.sec_opts->encrypted_image, test_img);
5156414dc6dSKonstantin Porotchkin 	if (rval != 0) {
5166414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Failed to decrypt the image! Error %d\n",
5176414dc6dSKonstantin Porotchkin 			rval);
5186414dc6dSKonstantin Porotchkin 		goto encrypt_exit;
5196414dc6dSKonstantin Porotchkin 	}
5206414dc6dSKonstantin Porotchkin 
5216414dc6dSKonstantin Porotchkin 	for (i = 0; i < blen; i++) {
5226414dc6dSKonstantin Porotchkin 		if (buf[i] != test_img[i]) {
5236414dc6dSKonstantin Porotchkin 			fprintf(stderr, "Failed to compare the image after");
5246414dc6dSKonstantin Porotchkin 			fprintf(stderr, " decryption! Byte count is %d\n", i);
5256414dc6dSKonstantin Porotchkin 			rval = -1;
5266414dc6dSKonstantin Porotchkin 			goto encrypt_exit;
5276414dc6dSKonstantin Porotchkin 		}
5286414dc6dSKonstantin Porotchkin 	}
5296414dc6dSKonstantin Porotchkin 
5306414dc6dSKonstantin Porotchkin encrypt_exit:
5316414dc6dSKonstantin Porotchkin 
5326414dc6dSKonstantin Porotchkin 	mbedtls_aes_free(&aes_ctx);
5336414dc6dSKonstantin Porotchkin 	if (test_img)
5346414dc6dSKonstantin Porotchkin 		free(test_img);
5356414dc6dSKonstantin Porotchkin 
5366414dc6dSKonstantin Porotchkin 	return rval;
5376414dc6dSKonstantin Porotchkin } /* end of image_encrypt */
5386414dc6dSKonstantin Porotchkin 
5396414dc6dSKonstantin Porotchkin /*******************************************************************************
5406414dc6dSKonstantin Porotchkin  *    verify_secure_header_signatures
5416414dc6dSKonstantin Porotchkin  *          Verify CSK array, header and image signatures and print results
5426414dc6dSKonstantin Porotchkin  *    INPUT:
5436414dc6dSKonstantin Porotchkin  *          main_hdr       Main header
5446414dc6dSKonstantin Porotchkin  *          sec_ext        Secure extension
5456414dc6dSKonstantin Porotchkin  *    OUTPUT:
5466414dc6dSKonstantin Porotchkin  *          none
5476414dc6dSKonstantin Porotchkin  *    RETURN:
5486414dc6dSKonstantin Porotchkin  *          0 on success
5496414dc6dSKonstantin Porotchkin  */
5506414dc6dSKonstantin Porotchkin int verify_secure_header_signatures(header_t *main_hdr, sec_entry_t *sec_ext)
5516414dc6dSKonstantin Porotchkin {
5526414dc6dSKonstantin Porotchkin 	uint8_t	*image = (uint8_t *)main_hdr + main_hdr->prolog_size;
5536414dc6dSKonstantin Porotchkin 	uint8_t	signature[RSA_SIGN_BYTE_LEN];
5546414dc6dSKonstantin Porotchkin 	int		rval = -1;
5556414dc6dSKonstantin Porotchkin 
5566414dc6dSKonstantin Porotchkin 	/* Save headers signature and reset it in the secure header */
5576414dc6dSKonstantin Porotchkin 	memcpy(signature, sec_ext->header_sign, RSA_SIGN_BYTE_LEN);
5586414dc6dSKonstantin Porotchkin 	memset(sec_ext->header_sign, 0, RSA_SIGN_BYTE_LEN);
5596414dc6dSKonstantin Porotchkin 
5606414dc6dSKonstantin Porotchkin 	fprintf(stdout, "\nCheck RSA Signatures\n");
5616414dc6dSKonstantin Porotchkin 	fprintf(stdout, "#########################\n");
5626414dc6dSKonstantin Porotchkin 	fprintf(stdout, "CSK Block Signature: ");
5636414dc6dSKonstantin Porotchkin 	if (verify_rsa_signature(sec_ext->kak_key,
5646414dc6dSKonstantin Porotchkin 				 MAX_RSA_DER_BYTE_LEN,
5656414dc6dSKonstantin Porotchkin 				 &sec_ext->csk_keys[0][0],
5666414dc6dSKonstantin Porotchkin 				 sizeof(sec_ext->csk_keys),
5676414dc6dSKonstantin Porotchkin 				 "CSK Block Signature: ",
5686414dc6dSKonstantin Porotchkin 				 sec_ext->csk_sign) != 0) {
5696414dc6dSKonstantin Porotchkin 		fprintf(stdout, "ERROR\n");
5706414dc6dSKonstantin Porotchkin 		goto ver_error;
5716414dc6dSKonstantin Porotchkin 	}
5726414dc6dSKonstantin Porotchkin 	fprintf(stdout, "OK\n");
5736414dc6dSKonstantin Porotchkin 
5746414dc6dSKonstantin Porotchkin 	if (opts.key_index != -1) {
5756414dc6dSKonstantin Porotchkin 		fprintf(stdout, "Image Signature:     ");
5766414dc6dSKonstantin Porotchkin 		if (verify_rsa_signature(sec_ext->csk_keys[opts.key_index],
5776414dc6dSKonstantin Porotchkin 					 MAX_RSA_DER_BYTE_LEN,
5786414dc6dSKonstantin Porotchkin 					 image, main_hdr->boot_image_size,
5796414dc6dSKonstantin Porotchkin 					 "Image Signature: ",
5806414dc6dSKonstantin Porotchkin 					 sec_ext->image_sign) != 0) {
5816414dc6dSKonstantin Porotchkin 			fprintf(stdout, "ERROR\n");
5826414dc6dSKonstantin Porotchkin 			goto ver_error;
5836414dc6dSKonstantin Porotchkin 		}
5846414dc6dSKonstantin Porotchkin 		fprintf(stdout, "OK\n");
5856414dc6dSKonstantin Porotchkin 
5866414dc6dSKonstantin Porotchkin 		fprintf(stdout, "Header Signature:    ");
5876414dc6dSKonstantin Porotchkin 		if (verify_rsa_signature(sec_ext->csk_keys[opts.key_index],
5886414dc6dSKonstantin Porotchkin 					 MAX_RSA_DER_BYTE_LEN,
5896414dc6dSKonstantin Porotchkin 					 (uint8_t *)main_hdr,
5906414dc6dSKonstantin Porotchkin 					 main_hdr->prolog_size,
5916414dc6dSKonstantin Porotchkin 					 "Header Signature: ",
5926414dc6dSKonstantin Porotchkin 					 signature) != 0) {
5936414dc6dSKonstantin Porotchkin 			fprintf(stdout, "ERROR\n");
5946414dc6dSKonstantin Porotchkin 			goto ver_error;
5956414dc6dSKonstantin Porotchkin 		}
5966414dc6dSKonstantin Porotchkin 		fprintf(stdout, "OK\n");
5976414dc6dSKonstantin Porotchkin 	} else {
5986414dc6dSKonstantin Porotchkin 		fprintf(stdout, "SKIP Image and Header Signatures");
5996414dc6dSKonstantin Porotchkin 		fprintf(stdout, " check (undefined key index)\n");
6006414dc6dSKonstantin Porotchkin 	}
6016414dc6dSKonstantin Porotchkin 
6026414dc6dSKonstantin Porotchkin 	rval = 0;
6036414dc6dSKonstantin Porotchkin 
6046414dc6dSKonstantin Porotchkin ver_error:
6056414dc6dSKonstantin Porotchkin 	memcpy(sec_ext->header_sign, signature, RSA_SIGN_BYTE_LEN);
6066414dc6dSKonstantin Porotchkin 	return rval;
6076414dc6dSKonstantin Porotchkin }
6086414dc6dSKonstantin Porotchkin 
6096414dc6dSKonstantin Porotchkin /*******************************************************************************
6106414dc6dSKonstantin Porotchkin  *    verify_and_copy_file_name_entry
6116414dc6dSKonstantin Porotchkin  *    INPUT:
6126414dc6dSKonstantin Porotchkin  *          element_name
6136414dc6dSKonstantin Porotchkin  *          element
6146414dc6dSKonstantin Porotchkin  *    OUTPUT:
6156414dc6dSKonstantin Porotchkin  *          copy_to
6166414dc6dSKonstantin Porotchkin  *    RETURN:
6176414dc6dSKonstantin Porotchkin  *          0 on success
6186414dc6dSKonstantin Porotchkin  */
6196414dc6dSKonstantin Porotchkin int verify_and_copy_file_name_entry(const char *element_name,
6206414dc6dSKonstantin Porotchkin 				    const char *element, char *copy_to)
6216414dc6dSKonstantin Porotchkin {
6226414dc6dSKonstantin Porotchkin 	int element_length = strlen(element);
6236414dc6dSKonstantin Porotchkin 
6246414dc6dSKonstantin Porotchkin 	if (element_length >= MAX_FILENAME) {
6256414dc6dSKonstantin Porotchkin 		fprintf(stderr, "The file name %s for %s is too long (%d). ",
6266414dc6dSKonstantin Porotchkin 			element, element_name, element_length);
6276414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Maximum allowed %d characters!\n",
6286414dc6dSKonstantin Porotchkin 			MAX_FILENAME);
6296414dc6dSKonstantin Porotchkin 		return -1;
6306414dc6dSKonstantin Porotchkin 	} else if (element_length == 0) {
6316414dc6dSKonstantin Porotchkin 		fprintf(stderr, "The file name for %s is empty!\n",
6326414dc6dSKonstantin Porotchkin 			element_name);
6336414dc6dSKonstantin Porotchkin 		return -1;
6346414dc6dSKonstantin Porotchkin 	}
6356414dc6dSKonstantin Porotchkin 	memcpy(copy_to, element, element_length);
6366414dc6dSKonstantin Porotchkin 
6376414dc6dSKonstantin Porotchkin 	return 0;
6386414dc6dSKonstantin Porotchkin }
6396414dc6dSKonstantin Porotchkin 
6406414dc6dSKonstantin Porotchkin /*******************************************************************************
6416414dc6dSKonstantin Porotchkin  *    parse_sec_config_file
6426414dc6dSKonstantin Porotchkin  *          Read the secure boot configuration from a file
6436414dc6dSKonstantin Porotchkin  *          into internal structures
6446414dc6dSKonstantin Porotchkin  *    INPUT:
6456414dc6dSKonstantin Porotchkin  *          filename      File name
6466414dc6dSKonstantin Porotchkin  *    OUTPUT:
6476414dc6dSKonstantin Porotchkin  *          none
6486414dc6dSKonstantin Porotchkin  *    RETURN:
6496414dc6dSKonstantin Porotchkin  *          0 on success
6506414dc6dSKonstantin Porotchkin  */
6516414dc6dSKonstantin Porotchkin int parse_sec_config_file(char *filename)
6526414dc6dSKonstantin Porotchkin {
6536414dc6dSKonstantin Porotchkin 	config_t		sec_cfg;
6546414dc6dSKonstantin Porotchkin 	int			array_sz, element, rval = -1;
6556414dc6dSKonstantin Porotchkin 	const char		*cfg_string;
6566414dc6dSKonstantin Porotchkin 	int32_t			cfg_int32;
6576414dc6dSKonstantin Porotchkin 	const config_setting_t	*csk_array, *control_array;
6586414dc6dSKonstantin Porotchkin 	sec_options		*sec_opt = 0;
6596414dc6dSKonstantin Porotchkin 
6606414dc6dSKonstantin Porotchkin 	config_init(&sec_cfg);
6616414dc6dSKonstantin Porotchkin 
6626414dc6dSKonstantin Porotchkin 	if (config_read_file(&sec_cfg, filename) != CONFIG_TRUE) {
6636414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Failed to read data from config file ");
6646414dc6dSKonstantin Porotchkin 		fprintf(stderr, "%s\n\t%s at line %d\n",
6656414dc6dSKonstantin Porotchkin 			filename, config_error_text(&sec_cfg),
6666414dc6dSKonstantin Porotchkin 			config_error_line(&sec_cfg));
6676414dc6dSKonstantin Porotchkin 		goto exit_parse;
6686414dc6dSKonstantin Porotchkin 	}
6696414dc6dSKonstantin Porotchkin 
6706414dc6dSKonstantin Porotchkin 	sec_opt = (sec_options *)calloc(sizeof(sec_options), 1);
6716414dc6dSKonstantin Porotchkin 	if (sec_opt == 0) {
6726414dc6dSKonstantin Porotchkin 		fprintf(stderr,
6736414dc6dSKonstantin Porotchkin 			"Cannot allocate memory for secure boot options!\n");
6746414dc6dSKonstantin Porotchkin 		goto exit_parse;
6756414dc6dSKonstantin Porotchkin 	}
6766414dc6dSKonstantin Porotchkin 
6776414dc6dSKonstantin Porotchkin 	/* KAK file name */
6786414dc6dSKonstantin Porotchkin 	if (config_lookup_string(&sec_cfg, "kak_key_file",
6796414dc6dSKonstantin Porotchkin 				 &cfg_string) != CONFIG_TRUE) {
6806414dc6dSKonstantin Porotchkin 		fprintf(stderr, "The \"kak_key_file\" undefined!\n");
6816414dc6dSKonstantin Porotchkin 		goto exit_parse;
6826414dc6dSKonstantin Porotchkin 	}
6836414dc6dSKonstantin Porotchkin 	if (verify_and_copy_file_name_entry("kak_key_file",
6846414dc6dSKonstantin Porotchkin 					    cfg_string, sec_opt->kak_key_file))
6856414dc6dSKonstantin Porotchkin 		goto exit_parse;
6866414dc6dSKonstantin Porotchkin 
6876414dc6dSKonstantin Porotchkin 
6886414dc6dSKonstantin Porotchkin 	/* AES file name - can be empty/undefined */
6896414dc6dSKonstantin Porotchkin 	if (config_lookup_string(&sec_cfg, "aes_key_file",
6906414dc6dSKonstantin Porotchkin 				 &cfg_string) == CONFIG_TRUE) {
6916414dc6dSKonstantin Porotchkin 		if (verify_and_copy_file_name_entry("aes_key_file",
6926414dc6dSKonstantin Porotchkin 						    cfg_string,
6936414dc6dSKonstantin Porotchkin 						    sec_opt->aes_key_file))
6946414dc6dSKonstantin Porotchkin 			goto exit_parse;
6956414dc6dSKonstantin Porotchkin 	}
6966414dc6dSKonstantin Porotchkin 
6976414dc6dSKonstantin Porotchkin 	/* CSK file names array */
6986414dc6dSKonstantin Porotchkin 	csk_array = config_lookup(&sec_cfg, "csk_key_file");
6996414dc6dSKonstantin Porotchkin 	if (csk_array == NULL) {
7006414dc6dSKonstantin Porotchkin 		fprintf(stderr, "The \"csk_key_file\" undefined!\n");
7016414dc6dSKonstantin Porotchkin 		goto exit_parse;
7026414dc6dSKonstantin Porotchkin 	}
7036414dc6dSKonstantin Porotchkin 	array_sz = config_setting_length(csk_array);
7046414dc6dSKonstantin Porotchkin 	if (array_sz > CSK_ARR_SZ) {
7056414dc6dSKonstantin Porotchkin 		fprintf(stderr, "The \"csk_key_file\" array is too big! ");
7066414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Only first %d elements will be used\n",
7076414dc6dSKonstantin Porotchkin 			CSK_ARR_SZ);
7086414dc6dSKonstantin Porotchkin 		array_sz = CSK_ARR_SZ;
7096414dc6dSKonstantin Porotchkin 	} else if (array_sz == 0) {
7106414dc6dSKonstantin Porotchkin 		fprintf(stderr, "The \"csk_key_file\" array is empty!\n");
7116414dc6dSKonstantin Porotchkin 		goto exit_parse;
7126414dc6dSKonstantin Porotchkin 	}
7136414dc6dSKonstantin Porotchkin 
7146414dc6dSKonstantin Porotchkin 	for (element = 0; element < array_sz; element++) {
7156414dc6dSKonstantin Porotchkin 		cfg_string = config_setting_get_string_elem(csk_array, element);
7166414dc6dSKonstantin Porotchkin 		if (verify_and_copy_file_name_entry(
7176414dc6dSKonstantin Porotchkin 				"csk_key_file", cfg_string,
7186414dc6dSKonstantin Porotchkin 				sec_opt->csk_key_file[element])) {
7196414dc6dSKonstantin Porotchkin 			fprintf(stderr, "Bad csk_key_file[%d] entry!\n",
7206414dc6dSKonstantin Porotchkin 				element);
7216414dc6dSKonstantin Porotchkin 			goto exit_parse;
7226414dc6dSKonstantin Porotchkin 		}
7236414dc6dSKonstantin Porotchkin 	}
7246414dc6dSKonstantin Porotchkin 
7256414dc6dSKonstantin Porotchkin 	/* JTAG options */
7266414dc6dSKonstantin Porotchkin 	if (config_lookup_bool(&sec_cfg, "jtag.enable",
7276414dc6dSKonstantin Porotchkin 			       &cfg_int32) != CONFIG_TRUE) {
7286414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Error obtaining \"jtag.enable\" element. ");
7296414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Using default - FALSE\n");
7306414dc6dSKonstantin Porotchkin 		cfg_int32 = 0;
7316414dc6dSKonstantin Porotchkin 	}
7326414dc6dSKonstantin Porotchkin 	sec_opt->jtag_enable = cfg_int32;
7336414dc6dSKonstantin Porotchkin 
7346414dc6dSKonstantin Porotchkin 	if (config_lookup_int(&sec_cfg, "jtag.delay",
7356414dc6dSKonstantin Porotchkin 			      &cfg_int32) != CONFIG_TRUE) {
7366414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Error obtaining \"jtag.delay\" element. ");
7376414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Using default - 0us\n");
7386414dc6dSKonstantin Porotchkin 		cfg_int32 = 0;
7396414dc6dSKonstantin Porotchkin 	}
7406414dc6dSKonstantin Porotchkin 	sec_opt->jtag_delay = cfg_int32;
7416414dc6dSKonstantin Porotchkin 
7426414dc6dSKonstantin Porotchkin 	/* eFUSE option */
7436414dc6dSKonstantin Porotchkin 	if (config_lookup_bool(&sec_cfg, "efuse_disable",
7446414dc6dSKonstantin Porotchkin 			       &cfg_int32) != CONFIG_TRUE) {
7456414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Error obtaining \"efuse_disable\" element. ");
7466414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Using default - TRUE\n");
7476414dc6dSKonstantin Porotchkin 		cfg_int32 = 1;
7486414dc6dSKonstantin Porotchkin 	}
7496414dc6dSKonstantin Porotchkin 	sec_opt->efuse_disable = cfg_int32;
7506414dc6dSKonstantin Porotchkin 
7516414dc6dSKonstantin Porotchkin 	/* Box ID option */
7526414dc6dSKonstantin Porotchkin 	if (config_lookup_int(&sec_cfg, "box_id", &cfg_int32) != CONFIG_TRUE) {
7536414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Error obtaining \"box_id\" element. ");
7546414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Using default - 0x0\n");
7556414dc6dSKonstantin Porotchkin 		cfg_int32 = 0;
7566414dc6dSKonstantin Porotchkin 	}
7576414dc6dSKonstantin Porotchkin 	sec_opt->box_id = cfg_int32;
7586414dc6dSKonstantin Porotchkin 
7596414dc6dSKonstantin Porotchkin 	/* Flash ID option */
7606414dc6dSKonstantin Porotchkin 	if (config_lookup_int(&sec_cfg, "flash_id",
7616414dc6dSKonstantin Porotchkin 			      &cfg_int32) != CONFIG_TRUE) {
7626414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Error obtaining \"flash_id\" element. ");
7636414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Using default - 0x0\n");
7646414dc6dSKonstantin Porotchkin 		cfg_int32 = 0;
7656414dc6dSKonstantin Porotchkin 	}
7666414dc6dSKonstantin Porotchkin 	sec_opt->flash_id = cfg_int32;
7676414dc6dSKonstantin Porotchkin 
7686414dc6dSKonstantin Porotchkin 	/* CSK index option */
7696414dc6dSKonstantin Porotchkin 	if (config_lookup_int(&sec_cfg, "csk_key_index",
7706414dc6dSKonstantin Porotchkin 			      &cfg_int32) != CONFIG_TRUE) {
7716414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Error obtaining \"flash_id\" element. ");
7726414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Using default - 0x0\n");
7736414dc6dSKonstantin Porotchkin 		cfg_int32 = 0;
7746414dc6dSKonstantin Porotchkin 	}
7756414dc6dSKonstantin Porotchkin 	sec_opt->csk_index = cfg_int32;
7766414dc6dSKonstantin Porotchkin 
7776414dc6dSKonstantin Porotchkin 	/* Secure boot control array */
7786414dc6dSKonstantin Porotchkin 	control_array = config_lookup(&sec_cfg, "control");
7796414dc6dSKonstantin Porotchkin 	if (control_array != NULL) {
7806414dc6dSKonstantin Porotchkin 		array_sz = config_setting_length(control_array);
7816414dc6dSKonstantin Porotchkin 		if (array_sz == 0)
7826414dc6dSKonstantin Porotchkin 			fprintf(stderr, "The \"control\" array is empty!\n");
7836414dc6dSKonstantin Porotchkin 	} else {
7846414dc6dSKonstantin Porotchkin 		fprintf(stderr, "The \"control\" is undefined!\n");
7856414dc6dSKonstantin Porotchkin 		array_sz = 0;
7866414dc6dSKonstantin Porotchkin 	}
7876414dc6dSKonstantin Porotchkin 
7886414dc6dSKonstantin Porotchkin 	for (element = 0; element < CP_CTRL_EL_ARRAY_SZ; element++) {
7896414dc6dSKonstantin Porotchkin 		sec_opt->cp_ctrl_arr[element] =
7906414dc6dSKonstantin Porotchkin 			config_setting_get_int_elem(control_array, element * 2);
7916414dc6dSKonstantin Porotchkin 		sec_opt->cp_efuse_arr[element] =
7926414dc6dSKonstantin Porotchkin 			config_setting_get_int_elem(control_array,
7936414dc6dSKonstantin Porotchkin 						    element * 2 + 1);
7946414dc6dSKonstantin Porotchkin 	}
7956414dc6dSKonstantin Porotchkin 
7966414dc6dSKonstantin Porotchkin 	opts.sec_opts = sec_opt;
7976414dc6dSKonstantin Porotchkin 	rval = 0;
7986414dc6dSKonstantin Porotchkin 
7996414dc6dSKonstantin Porotchkin exit_parse:
8006414dc6dSKonstantin Porotchkin 	config_destroy(&sec_cfg);
8016414dc6dSKonstantin Porotchkin 	if (sec_opt && (rval != 0))
8026414dc6dSKonstantin Porotchkin 		free(sec_opt);
8036414dc6dSKonstantin Porotchkin 	return rval;
8046414dc6dSKonstantin Porotchkin } /* end of parse_sec_config_file */
8056414dc6dSKonstantin Porotchkin 
8066414dc6dSKonstantin Porotchkin int format_sec_ext(char *filename, FILE *out_fd)
8076414dc6dSKonstantin Porotchkin {
8086414dc6dSKonstantin Porotchkin 	ext_header_t	header;
8096414dc6dSKonstantin Porotchkin 	sec_entry_t	sec_ext;
8106414dc6dSKonstantin Porotchkin 	int		index;
8116414dc6dSKonstantin Porotchkin 	int		written;
8126414dc6dSKonstantin Porotchkin 
8136414dc6dSKonstantin Porotchkin #define DER_BUF_SZ	1600
8146414dc6dSKonstantin Porotchkin 
8156414dc6dSKonstantin Porotchkin 	/* First, parse the configuration file */
8166414dc6dSKonstantin Porotchkin 	if (parse_sec_config_file(filename)) {
8176414dc6dSKonstantin Porotchkin 		fprintf(stderr,
8186414dc6dSKonstantin Porotchkin 			"failed parsing configuration file %s\n", filename);
8196414dc6dSKonstantin Porotchkin 		return 1;
8206414dc6dSKonstantin Porotchkin 	}
8216414dc6dSKonstantin Porotchkin 
8226414dc6dSKonstantin Porotchkin 	/* Everything except signatures can be created at this stage */
8236414dc6dSKonstantin Porotchkin 	header.type = EXT_TYPE_SECURITY;
8246414dc6dSKonstantin Porotchkin 	header.offset = 0;
8256414dc6dSKonstantin Porotchkin 	header.size = sizeof(sec_entry_t);
8266414dc6dSKonstantin Porotchkin 	header.reserved = 0;
8276414dc6dSKonstantin Porotchkin 
8286414dc6dSKonstantin Porotchkin 	/* Bring up RSA context and read private keys from their files */
8296414dc6dSKonstantin Porotchkin 	for (index = 0; index < (CSK_ARR_SZ + 1); index++) {
8306414dc6dSKonstantin Porotchkin 		/* for every private key file */
8316414dc6dSKonstantin Porotchkin 		mbedtls_pk_context	*pk_ctx = (index == CSK_ARR_SZ) ?
8326414dc6dSKonstantin Porotchkin 					&opts.sec_opts->kak_pk :
8336414dc6dSKonstantin Porotchkin 					&opts.sec_opts->csk_pk[index];
8346414dc6dSKonstantin Porotchkin 		char		*fname = (index == CSK_ARR_SZ) ?
8356414dc6dSKonstantin Porotchkin 					opts.sec_opts->kak_key_file :
8366414dc6dSKonstantin Porotchkin 					opts.sec_opts->csk_key_file[index];
8376414dc6dSKonstantin Porotchkin 		uint8_t		*out_der_key = (index == CSK_ARR_SZ) ?
8386414dc6dSKonstantin Porotchkin 					sec_ext.kak_key :
8396414dc6dSKonstantin Porotchkin 					sec_ext.csk_keys[index];
8406414dc6dSKonstantin Porotchkin 		size_t		output_len;
8416414dc6dSKonstantin Porotchkin 		unsigned char	output_buf[DER_BUF_SZ];
8426414dc6dSKonstantin Porotchkin 		unsigned char	*der_buf_start;
8436414dc6dSKonstantin Porotchkin 
8446414dc6dSKonstantin Porotchkin 		/* Handle invalid/reserved file names */
8456414dc6dSKonstantin Porotchkin 		if (strncmp(CSK_ARR_EMPTY_FILE, fname,
8466414dc6dSKonstantin Porotchkin 			    strlen(CSK_ARR_EMPTY_FILE)) == 0) {
8476414dc6dSKonstantin Porotchkin 			if (opts.sec_opts->csk_index == index) {
8486414dc6dSKonstantin Porotchkin 				fprintf(stderr,
8496414dc6dSKonstantin Porotchkin 					"CSK file with index %d cannot be %s\n",
8506414dc6dSKonstantin Porotchkin 					index, CSK_ARR_EMPTY_FILE);
8516414dc6dSKonstantin Porotchkin 				return 1;
8526414dc6dSKonstantin Porotchkin 			} else if (index == CSK_ARR_SZ) {
8536414dc6dSKonstantin Porotchkin 				fprintf(stderr, "KAK file name cannot be %s\n",
8546414dc6dSKonstantin Porotchkin 					CSK_ARR_EMPTY_FILE);
8556414dc6dSKonstantin Porotchkin 				return 1;
8566414dc6dSKonstantin Porotchkin 			}
8576414dc6dSKonstantin Porotchkin 			/* this key will be empty in CSK array */
8586414dc6dSKonstantin Porotchkin 			continue;
8596414dc6dSKonstantin Porotchkin 		}
8606414dc6dSKonstantin Porotchkin 
8616414dc6dSKonstantin Porotchkin 		mbedtls_pk_init(pk_ctx);
8626414dc6dSKonstantin Porotchkin 		/* Read the private RSA key into the context
8636414dc6dSKonstantin Porotchkin 		 * and verify it (no password)
8646414dc6dSKonstantin Porotchkin 		 */
8656414dc6dSKonstantin Porotchkin 		if (mbedtls_pk_parse_keyfile(pk_ctx, fname, "") != 0) {
8666414dc6dSKonstantin Porotchkin 			fprintf(stderr,
8676414dc6dSKonstantin Porotchkin 				"Cannot read RSA private key file %s\n", fname);
8686414dc6dSKonstantin Porotchkin 			return 1;
8696414dc6dSKonstantin Porotchkin 		}
8706414dc6dSKonstantin Porotchkin 
8716414dc6dSKonstantin Porotchkin 		/* Create a public key out of private one
8726414dc6dSKonstantin Porotchkin 		 * and store it in DER format
8736414dc6dSKonstantin Porotchkin 		 */
8746414dc6dSKonstantin Porotchkin 		output_len = mbedtls_pk_write_pubkey_der(pk_ctx,
8756414dc6dSKonstantin Porotchkin 							 output_buf,
8766414dc6dSKonstantin Porotchkin 							 DER_BUF_SZ);
8776414dc6dSKonstantin Porotchkin 		if (output_len < 0) {
8786414dc6dSKonstantin Porotchkin 			fprintf(stderr,
8796414dc6dSKonstantin Porotchkin 				"Failed to create DER coded PUB key (%s)\n",
8806414dc6dSKonstantin Porotchkin 				fname);
8816414dc6dSKonstantin Porotchkin 			return 1;
8826414dc6dSKonstantin Porotchkin 		}
883a79df348SKonstantin Porotchkin 
8846414dc6dSKonstantin Porotchkin 		/* Data in the output buffer is aligned to the buffer end */
8856414dc6dSKonstantin Porotchkin 		der_buf_start = output_buf + sizeof(output_buf) - output_len;
8866414dc6dSKonstantin Porotchkin 		/* In the header DER data is aligned
8876414dc6dSKonstantin Porotchkin 		 * to the start of appropriate field
8886414dc6dSKonstantin Porotchkin 		 */
889a79df348SKonstantin Porotchkin 		bzero(out_der_key, MAX_RSA_DER_BYTE_LEN);
8906414dc6dSKonstantin Porotchkin 		memcpy(out_der_key, der_buf_start, output_len);
8916414dc6dSKonstantin Porotchkin 
8926414dc6dSKonstantin Porotchkin 	} /* for every private key file */
8936414dc6dSKonstantin Porotchkin 
8946414dc6dSKonstantin Porotchkin 	/* The CSK block signature can be created here */
8956414dc6dSKonstantin Porotchkin 	if (create_rsa_signature(&opts.sec_opts->kak_pk,
8966414dc6dSKonstantin Porotchkin 				 &sec_ext.csk_keys[0][0],
8976414dc6dSKonstantin Porotchkin 				 sizeof(sec_ext.csk_keys),
8986414dc6dSKonstantin Porotchkin 				 opts.sec_opts->csk_key_file[
8996414dc6dSKonstantin Porotchkin 					 opts.sec_opts->csk_index],
9006414dc6dSKonstantin Porotchkin 				 sec_ext.csk_sign) != 0) {
9016414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Failed to sign CSK keys block!\n");
9026414dc6dSKonstantin Porotchkin 		return 1;
9036414dc6dSKonstantin Porotchkin 	}
904a79df348SKonstantin Porotchkin 
9056414dc6dSKonstantin Porotchkin 	/* Check that everything is correct */
906a79df348SKonstantin Porotchkin 	if (verify_rsa_signature(sec_ext.kak_key,
907a79df348SKonstantin Porotchkin 				 MAX_RSA_DER_BYTE_LEN,
9086414dc6dSKonstantin Porotchkin 				 &sec_ext.csk_keys[0][0],
9096414dc6dSKonstantin Porotchkin 				 sizeof(sec_ext.csk_keys),
9106414dc6dSKonstantin Porotchkin 				 opts.sec_opts->kak_key_file,
9116414dc6dSKonstantin Porotchkin 				 sec_ext.csk_sign) != 0) {
9126414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Failed to verify CSK keys block signature!\n");
9136414dc6dSKonstantin Porotchkin 		return 1;
9146414dc6dSKonstantin Porotchkin 	}
9156414dc6dSKonstantin Porotchkin 
9166414dc6dSKonstantin Porotchkin 	/* AES encryption stuff */
9176414dc6dSKonstantin Porotchkin 	if (strlen(opts.sec_opts->aes_key_file) != 0) {
9186414dc6dSKonstantin Porotchkin 		FILE		*in_fd;
9196414dc6dSKonstantin Porotchkin 
9206414dc6dSKonstantin Porotchkin 		in_fd = fopen(opts.sec_opts->aes_key_file, "rb");
9216414dc6dSKonstantin Porotchkin 		if (in_fd == NULL) {
9226414dc6dSKonstantin Porotchkin 			fprintf(stderr, "Failed to open AES key file %s\n",
9236414dc6dSKonstantin Porotchkin 				opts.sec_opts->aes_key_file);
9246414dc6dSKonstantin Porotchkin 			return 1;
9256414dc6dSKonstantin Porotchkin 		}
9266414dc6dSKonstantin Porotchkin 
9276414dc6dSKonstantin Porotchkin 		/* Read the AES key in ASCII format byte by byte */
9286414dc6dSKonstantin Porotchkin 		for (index = 0; index < AES_KEY_BYTE_LEN; index++) {
9296414dc6dSKonstantin Porotchkin 			if (fscanf(in_fd, "%02hhx",
9306414dc6dSKonstantin Porotchkin 			    opts.sec_opts->aes_key + index) != 1) {
9316414dc6dSKonstantin Porotchkin 				fprintf(stderr,
9326414dc6dSKonstantin Porotchkin 					"Failed to read AES key byte %d ",
9336414dc6dSKonstantin Porotchkin 					index);
9346414dc6dSKonstantin Porotchkin 				fprintf(stderr,
9356414dc6dSKonstantin Porotchkin 					"from file %s\n",
9366414dc6dSKonstantin Porotchkin 					opts.sec_opts->aes_key_file);
9376414dc6dSKonstantin Porotchkin 				fclose(in_fd);
9386414dc6dSKonstantin Porotchkin 				return 1;
9396414dc6dSKonstantin Porotchkin 			}
9406414dc6dSKonstantin Porotchkin 		}
9416414dc6dSKonstantin Porotchkin 		fclose(in_fd);
9426414dc6dSKonstantin Porotchkin 		sec_ext.encrypt_en = 1;
9436414dc6dSKonstantin Porotchkin 	} else {
9446414dc6dSKonstantin Porotchkin 		sec_ext.encrypt_en = 0;
9456414dc6dSKonstantin Porotchkin 	}
9466414dc6dSKonstantin Porotchkin 
9476414dc6dSKonstantin Porotchkin 	/* Fill the rest of the trusted boot extension fields */
9486414dc6dSKonstantin Porotchkin 	sec_ext.box_id		= opts.sec_opts->box_id;
9496414dc6dSKonstantin Porotchkin 	sec_ext.flash_id	= opts.sec_opts->flash_id;
9506414dc6dSKonstantin Porotchkin 	sec_ext.efuse_dis	= opts.sec_opts->efuse_disable;
9516414dc6dSKonstantin Porotchkin 	sec_ext.jtag_delay	= opts.sec_opts->jtag_delay;
9526414dc6dSKonstantin Porotchkin 	sec_ext.jtag_en		= opts.sec_opts->jtag_enable;
9536414dc6dSKonstantin Porotchkin 
9546414dc6dSKonstantin Porotchkin 	memcpy(sec_ext.cp_ctrl_arr,
9556414dc6dSKonstantin Porotchkin 	       opts.sec_opts->cp_ctrl_arr,
9566414dc6dSKonstantin Porotchkin 	       sizeof(uint32_t) * CP_CTRL_EL_ARRAY_SZ);
9576414dc6dSKonstantin Porotchkin 	memcpy(sec_ext.cp_efuse_arr,
9586414dc6dSKonstantin Porotchkin 	       opts.sec_opts->cp_efuse_arr,
9596414dc6dSKonstantin Porotchkin 	       sizeof(uint32_t) * CP_CTRL_EL_ARRAY_SZ);
9606414dc6dSKonstantin Porotchkin 
9616414dc6dSKonstantin Porotchkin 	/* Write the resulting extension to file
9626414dc6dSKonstantin Porotchkin 	 * (image and header signature fields are still empty)
9636414dc6dSKonstantin Porotchkin 	 */
9646414dc6dSKonstantin Porotchkin 
9656414dc6dSKonstantin Porotchkin 	/* Write extension header */
9666414dc6dSKonstantin Porotchkin 	written = fwrite(&header, sizeof(ext_header_t), 1, out_fd);
9676414dc6dSKonstantin Porotchkin 	if (written != 1) {
9686414dc6dSKonstantin Porotchkin 		fprintf(stderr,
9696414dc6dSKonstantin Porotchkin 			"Failed to write SEC extension header to the file\n");
9706414dc6dSKonstantin Porotchkin 		return 1;
9716414dc6dSKonstantin Porotchkin 	}
9726414dc6dSKonstantin Porotchkin 	/* Write extension body */
9736414dc6dSKonstantin Porotchkin 	written = fwrite(&sec_ext, sizeof(sec_entry_t), 1, out_fd);
9746414dc6dSKonstantin Porotchkin 	if (written != 1) {
9756414dc6dSKonstantin Porotchkin 		fprintf(stderr,
9766414dc6dSKonstantin Porotchkin 			"Failed to write SEC extension body to the file\n");
9776414dc6dSKonstantin Porotchkin 		return 1;
9786414dc6dSKonstantin Porotchkin 	}
9796414dc6dSKonstantin Porotchkin 
9806414dc6dSKonstantin Porotchkin 	return 0;
9816414dc6dSKonstantin Porotchkin }
9826414dc6dSKonstantin Porotchkin 
9836414dc6dSKonstantin Porotchkin /*******************************************************************************
9846414dc6dSKonstantin Porotchkin  *    finalize_secure_ext
9856414dc6dSKonstantin Porotchkin  *          Make final changes to secure extension - calculate image and header
9866414dc6dSKonstantin Porotchkin  *          signatures and encrypt the image if needed.
9876414dc6dSKonstantin Porotchkin  *          The main header checksum and image size fields updated accordingly
9886414dc6dSKonstantin Porotchkin  *    INPUT:
9896414dc6dSKonstantin Porotchkin  *          header       Main header
9906414dc6dSKonstantin Porotchkin  *          prolog_buf   the entire prolog buffer
9916414dc6dSKonstantin Porotchkin  *          prolog_size  prolog buffer length
9926414dc6dSKonstantin Porotchkin  *          image_buf    buffer containing the input binary image
9936414dc6dSKonstantin Porotchkin  *          image_size   image buffer size.
9946414dc6dSKonstantin Porotchkin  *    OUTPUT:
9956414dc6dSKonstantin Porotchkin  *          none
9966414dc6dSKonstantin Porotchkin  *    RETURN:
9976414dc6dSKonstantin Porotchkin  *          0 on success
9986414dc6dSKonstantin Porotchkin  */
9996414dc6dSKonstantin Porotchkin int finalize_secure_ext(header_t *header,
10006414dc6dSKonstantin Porotchkin 			uint8_t *prolog_buf, uint32_t prolog_size,
10016414dc6dSKonstantin Porotchkin 			uint8_t *image_buf, int image_size)
10026414dc6dSKonstantin Porotchkin {
10036414dc6dSKonstantin Porotchkin 	int		cur_ext, offset;
10046414dc6dSKonstantin Porotchkin 	uint8_t		*final_image = image_buf;
10056414dc6dSKonstantin Porotchkin 	uint32_t	final_image_sz = image_size;
10066414dc6dSKonstantin Porotchkin 	uint8_t		hdr_sign[RSA_SIGN_BYTE_LEN];
10076414dc6dSKonstantin Porotchkin 	sec_entry_t	*sec_ext = 0;
10086414dc6dSKonstantin Porotchkin 
10096414dc6dSKonstantin Porotchkin 	/* Find the Trusted Boot Header between available extensions */
10106414dc6dSKonstantin Porotchkin 	for (cur_ext = 0, offset = sizeof(header_t);
10116414dc6dSKonstantin Porotchkin 	     cur_ext < header->ext_count; cur_ext++) {
10126414dc6dSKonstantin Porotchkin 		ext_header_t *ext_hdr = (ext_header_t *)(prolog_buf + offset);
10136414dc6dSKonstantin Porotchkin 
10146414dc6dSKonstantin Porotchkin 		if (ext_hdr->type == EXT_TYPE_SECURITY) {
10156414dc6dSKonstantin Porotchkin 			sec_ext = (sec_entry_t *)(prolog_buf + offset +
10166414dc6dSKonstantin Porotchkin 				   sizeof(ext_header_t) + ext_hdr->offset);
10176414dc6dSKonstantin Porotchkin 			break;
10186414dc6dSKonstantin Porotchkin 		}
10196414dc6dSKonstantin Porotchkin 
10206414dc6dSKonstantin Porotchkin 		offset += sizeof(ext_header_t);
10216414dc6dSKonstantin Porotchkin 		/* If offset is Zero, the extension follows its header */
10226414dc6dSKonstantin Porotchkin 		if (ext_hdr->offset == 0)
10236414dc6dSKonstantin Porotchkin 			offset += ext_hdr->size;
10246414dc6dSKonstantin Porotchkin 	}
10256414dc6dSKonstantin Porotchkin 
10266414dc6dSKonstantin Porotchkin 	if (sec_ext == 0) {
10276414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Error: No Trusted Boot extension found!\n");
10286414dc6dSKonstantin Porotchkin 		return -1;
10296414dc6dSKonstantin Porotchkin 	}
10306414dc6dSKonstantin Porotchkin 
10316414dc6dSKonstantin Porotchkin 	if (sec_ext->encrypt_en) {
10326414dc6dSKonstantin Porotchkin 		/* Encrypt the image if needed */
10336414dc6dSKonstantin Porotchkin 		fprintf(stdout, "Encrypting the image...\n");
10346414dc6dSKonstantin Porotchkin 
10356414dc6dSKonstantin Porotchkin 		if (image_encrypt(image_buf, image_size) != 0) {
10366414dc6dSKonstantin Porotchkin 			fprintf(stderr, "Failed to encrypt the image!\n");
10376414dc6dSKonstantin Porotchkin 			return -1;
10386414dc6dSKonstantin Porotchkin 		}
10396414dc6dSKonstantin Porotchkin 
10406414dc6dSKonstantin Porotchkin 		/* Image size and checksum should be updated after encryption.
10416414dc6dSKonstantin Porotchkin 		 * This way the image could be verified by the BootROM
10426414dc6dSKonstantin Porotchkin 		 * before decryption.
10436414dc6dSKonstantin Porotchkin 		 */
10446414dc6dSKonstantin Porotchkin 		final_image = opts.sec_opts->encrypted_image;
10456414dc6dSKonstantin Porotchkin 		final_image_sz = opts.sec_opts->enc_image_sz;
10466414dc6dSKonstantin Porotchkin 
10476414dc6dSKonstantin Porotchkin 		header->boot_image_size = final_image_sz;
10486414dc6dSKonstantin Porotchkin 		header->boot_image_checksum =
10496414dc6dSKonstantin Porotchkin 			checksum32((uint32_t *)final_image, final_image_sz);
10506414dc6dSKonstantin Porotchkin 	} /* AES encryption */
10516414dc6dSKonstantin Porotchkin 
10526414dc6dSKonstantin Porotchkin 	/* Create the image signature first, since it will be later
10536414dc6dSKonstantin Porotchkin 	 * signed along with the header signature
10546414dc6dSKonstantin Porotchkin 	 */
10556414dc6dSKonstantin Porotchkin 	if (create_rsa_signature(&opts.sec_opts->csk_pk[
10566414dc6dSKonstantin Porotchkin 					opts.sec_opts->csk_index],
10576414dc6dSKonstantin Porotchkin 				 final_image, final_image_sz,
10586414dc6dSKonstantin Porotchkin 				 opts.sec_opts->csk_key_file[
10596414dc6dSKonstantin Porotchkin 					opts.sec_opts->csk_index],
10606414dc6dSKonstantin Porotchkin 				 sec_ext->image_sign) != 0) {
10616414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Failed to sign image!\n");
10626414dc6dSKonstantin Porotchkin 		return -1;
10636414dc6dSKonstantin Porotchkin 	}
10646414dc6dSKonstantin Porotchkin 	/* Check that the image signature is correct */
10656414dc6dSKonstantin Porotchkin 	if (verify_rsa_signature(sec_ext->csk_keys[opts.sec_opts->csk_index],
10666414dc6dSKonstantin Porotchkin 				 MAX_RSA_DER_BYTE_LEN,
10676414dc6dSKonstantin Porotchkin 				 final_image, final_image_sz,
10686414dc6dSKonstantin Porotchkin 				 opts.sec_opts->csk_key_file[
10696414dc6dSKonstantin Porotchkin 					 opts.sec_opts->csk_index],
10706414dc6dSKonstantin Porotchkin 				 sec_ext->image_sign) != 0) {
10716414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Failed to verify image signature!\n");
10726414dc6dSKonstantin Porotchkin 		return -1;
10736414dc6dSKonstantin Porotchkin 	}
10746414dc6dSKonstantin Porotchkin 
10756414dc6dSKonstantin Porotchkin 	/* Sign the headers and all the extensions block
10766414dc6dSKonstantin Porotchkin 	 * when the header signature field is empty
10776414dc6dSKonstantin Porotchkin 	 */
10786414dc6dSKonstantin Porotchkin 	if (create_rsa_signature(&opts.sec_opts->csk_pk[
10796414dc6dSKonstantin Porotchkin 					 opts.sec_opts->csk_index],
10806414dc6dSKonstantin Porotchkin 				 prolog_buf, prolog_size,
10816414dc6dSKonstantin Porotchkin 				 opts.sec_opts->csk_key_file[
10826414dc6dSKonstantin Porotchkin 					 opts.sec_opts->csk_index],
10836414dc6dSKonstantin Porotchkin 				 hdr_sign) != 0) {
10846414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Failed to sign header!\n");
10856414dc6dSKonstantin Porotchkin 		return -1;
10866414dc6dSKonstantin Porotchkin 	}
10876414dc6dSKonstantin Porotchkin 	/* Check that the header signature is correct */
10886414dc6dSKonstantin Porotchkin 	if (verify_rsa_signature(sec_ext->csk_keys[opts.sec_opts->csk_index],
10896414dc6dSKonstantin Porotchkin 				 MAX_RSA_DER_BYTE_LEN,
10906414dc6dSKonstantin Porotchkin 				 prolog_buf, prolog_size,
10916414dc6dSKonstantin Porotchkin 				 opts.sec_opts->csk_key_file[
10926414dc6dSKonstantin Porotchkin 					 opts.sec_opts->csk_index],
10936414dc6dSKonstantin Porotchkin 				 hdr_sign) != 0) {
10946414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Failed to verify header signature!\n");
10956414dc6dSKonstantin Porotchkin 		return -1;
10966414dc6dSKonstantin Porotchkin 	}
10976414dc6dSKonstantin Porotchkin 
10986414dc6dSKonstantin Porotchkin 	/* Finally, copy the header signature into the trusted boot extension */
10996414dc6dSKonstantin Porotchkin 	memcpy(sec_ext->header_sign, hdr_sign, RSA_SIGN_BYTE_LEN);
11006414dc6dSKonstantin Porotchkin 
11016414dc6dSKonstantin Porotchkin 	return 0;
11026414dc6dSKonstantin Porotchkin }
11036414dc6dSKonstantin Porotchkin 
11046414dc6dSKonstantin Porotchkin #endif /* CONFIG_MVEBU_SECURE_BOOT */
11056414dc6dSKonstantin Porotchkin 
11066414dc6dSKonstantin Porotchkin 
11076414dc6dSKonstantin Porotchkin #define FMT_HEX		0
11086414dc6dSKonstantin Porotchkin #define FMT_DEC		1
11096414dc6dSKonstantin Porotchkin #define FMT_BIN		2
11106414dc6dSKonstantin Porotchkin #define FMT_NONE	3
11116414dc6dSKonstantin Porotchkin 
11126414dc6dSKonstantin Porotchkin void do_print_field(unsigned int value, char *name,
11136414dc6dSKonstantin Porotchkin 		    int start, int size, int format)
11146414dc6dSKonstantin Porotchkin {
11156414dc6dSKonstantin Porotchkin 	fprintf(stdout, "[0x%05x : 0x%05x]  %-26s",
11166414dc6dSKonstantin Porotchkin 		start, start + size - 1, name);
11176414dc6dSKonstantin Porotchkin 
11186414dc6dSKonstantin Porotchkin 	switch (format) {
11196414dc6dSKonstantin Porotchkin 	case FMT_HEX:
11206414dc6dSKonstantin Porotchkin 		printf("0x%x\n", value);
11216414dc6dSKonstantin Porotchkin 		break;
11226414dc6dSKonstantin Porotchkin 	case FMT_DEC:
11236414dc6dSKonstantin Porotchkin 		printf("%d\n", value);
11246414dc6dSKonstantin Porotchkin 		break;
11256414dc6dSKonstantin Porotchkin 	default:
11266414dc6dSKonstantin Porotchkin 		printf("\n");
11276414dc6dSKonstantin Porotchkin 		break;
11286414dc6dSKonstantin Porotchkin 	}
11296414dc6dSKonstantin Porotchkin }
11306414dc6dSKonstantin Porotchkin 
11316414dc6dSKonstantin Porotchkin #define print_field(st, type, field, hex, base) \
11326414dc6dSKonstantin Porotchkin 			do_print_field((int)st->field, #field, \
11336414dc6dSKonstantin Porotchkin 			base + offsetof(type, field), sizeof(st->field), hex)
11346414dc6dSKonstantin Porotchkin 
11356414dc6dSKonstantin Porotchkin int print_header(uint8_t *buf, int base)
11366414dc6dSKonstantin Porotchkin {
11376414dc6dSKonstantin Porotchkin 	header_t *main_hdr;
11386414dc6dSKonstantin Porotchkin 
11396414dc6dSKonstantin Porotchkin 	main_hdr = (header_t *)buf;
11406414dc6dSKonstantin Porotchkin 
11416414dc6dSKonstantin Porotchkin 	fprintf(stdout, "########### Header ##############\n");
11426414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, magic, FMT_HEX, base);
11436414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, prolog_size, FMT_DEC, base);
11446414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, prolog_checksum, FMT_HEX, base);
11456414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, boot_image_size, FMT_DEC, base);
11466414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, boot_image_checksum, FMT_HEX, base);
11476414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, rsrvd0, FMT_HEX, base);
11486414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, load_addr, FMT_HEX, base);
11496414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, exec_addr, FMT_HEX, base);
11506414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, uart_cfg, FMT_HEX, base);
11516414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, baudrate, FMT_HEX, base);
11526414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, ext_count, FMT_DEC, base);
11536414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, aux_flags, FMT_HEX, base);
11546414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, io_arg_0, FMT_HEX, base);
11556414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, io_arg_1, FMT_HEX, base);
11566414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, io_arg_2, FMT_HEX, base);
11576414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, io_arg_3, FMT_HEX, base);
11586414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, rsrvd1, FMT_HEX, base);
11596414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, rsrvd2, FMT_HEX, base);
11606414dc6dSKonstantin Porotchkin 	print_field(main_hdr, header_t, rsrvd3, FMT_HEX, base);
11616414dc6dSKonstantin Porotchkin 
11626414dc6dSKonstantin Porotchkin 	return sizeof(header_t);
11636414dc6dSKonstantin Porotchkin }
11646414dc6dSKonstantin Porotchkin 
11656414dc6dSKonstantin Porotchkin int print_ext_hdr(ext_header_t *ext_hdr, int base)
11666414dc6dSKonstantin Porotchkin {
11676414dc6dSKonstantin Porotchkin 	print_field(ext_hdr, ext_header_t, type, FMT_HEX, base);
11686414dc6dSKonstantin Porotchkin 	print_field(ext_hdr, ext_header_t, offset, FMT_HEX, base);
11696414dc6dSKonstantin Porotchkin 	print_field(ext_hdr, ext_header_t, reserved, FMT_HEX, base);
11706414dc6dSKonstantin Porotchkin 	print_field(ext_hdr, ext_header_t, size, FMT_DEC, base);
11716414dc6dSKonstantin Porotchkin 
11726414dc6dSKonstantin Porotchkin 	return base + sizeof(ext_header_t);
11736414dc6dSKonstantin Porotchkin }
11746414dc6dSKonstantin Porotchkin 
11756414dc6dSKonstantin Porotchkin void print_sec_ext(ext_header_t *ext_hdr, int base)
11766414dc6dSKonstantin Porotchkin {
11776414dc6dSKonstantin Porotchkin 	sec_entry_t	*sec_entry;
11786414dc6dSKonstantin Porotchkin 	uint32_t	new_base;
11796414dc6dSKonstantin Porotchkin 
11806414dc6dSKonstantin Porotchkin 	fprintf(stdout, "\n########### Secure extension ###########\n");
11816414dc6dSKonstantin Porotchkin 
11826414dc6dSKonstantin Porotchkin 	new_base = print_ext_hdr(ext_hdr, base);
11836414dc6dSKonstantin Porotchkin 
11846414dc6dSKonstantin Porotchkin 	sec_entry = (sec_entry_t *)(ext_hdr + 1);
11856414dc6dSKonstantin Porotchkin 
11866414dc6dSKonstantin Porotchkin 	do_print_field(0, "KAK key", new_base, MAX_RSA_DER_BYTE_LEN, FMT_NONE);
11876414dc6dSKonstantin Porotchkin 	new_base += MAX_RSA_DER_BYTE_LEN;
11886414dc6dSKonstantin Porotchkin 	print_field(sec_entry, sec_entry_t, jtag_delay, FMT_DEC, base);
11896414dc6dSKonstantin Porotchkin 	print_field(sec_entry, sec_entry_t, box_id, FMT_HEX, base);
11906414dc6dSKonstantin Porotchkin 	print_field(sec_entry, sec_entry_t, flash_id, FMT_HEX, base);
11916414dc6dSKonstantin Porotchkin 	print_field(sec_entry, sec_entry_t, encrypt_en, FMT_DEC, base);
11926414dc6dSKonstantin Porotchkin 	print_field(sec_entry, sec_entry_t, efuse_dis, FMT_DEC, base);
11936414dc6dSKonstantin Porotchkin 	new_base += 6 * sizeof(uint32_t);
11946414dc6dSKonstantin Porotchkin 	do_print_field(0, "header signature",
11956414dc6dSKonstantin Porotchkin 		       new_base, RSA_SIGN_BYTE_LEN, FMT_NONE);
11966414dc6dSKonstantin Porotchkin 	new_base += RSA_SIGN_BYTE_LEN;
11976414dc6dSKonstantin Porotchkin 	do_print_field(0, "image signature",
11986414dc6dSKonstantin Porotchkin 		       new_base, RSA_SIGN_BYTE_LEN, FMT_NONE);
11996414dc6dSKonstantin Porotchkin 	new_base += RSA_SIGN_BYTE_LEN;
12006414dc6dSKonstantin Porotchkin 	do_print_field(0, "CSK keys", new_base,
12016414dc6dSKonstantin Porotchkin 		       CSK_ARR_SZ * MAX_RSA_DER_BYTE_LEN, FMT_NONE);
12026414dc6dSKonstantin Porotchkin 	new_base += CSK_ARR_SZ * MAX_RSA_DER_BYTE_LEN;
12036414dc6dSKonstantin Porotchkin 	do_print_field(0, "CSK block signature",
12046414dc6dSKonstantin Porotchkin 		       new_base, RSA_SIGN_BYTE_LEN, FMT_NONE);
12056414dc6dSKonstantin Porotchkin 	new_base += RSA_SIGN_BYTE_LEN;
12066414dc6dSKonstantin Porotchkin 	do_print_field(0, "control", new_base,
12076414dc6dSKonstantin Porotchkin 		       CP_CTRL_EL_ARRAY_SZ * 2, FMT_NONE);
12086414dc6dSKonstantin Porotchkin 
12096414dc6dSKonstantin Porotchkin }
12106414dc6dSKonstantin Porotchkin 
12116414dc6dSKonstantin Porotchkin void print_bin_ext(ext_header_t *ext_hdr, int base)
12126414dc6dSKonstantin Porotchkin {
12136414dc6dSKonstantin Porotchkin 	fprintf(stdout, "\n########### Binary extension ###########\n");
12146414dc6dSKonstantin Porotchkin 	base = print_ext_hdr(ext_hdr, base);
12156414dc6dSKonstantin Porotchkin 	do_print_field(0, "binary image", base, ext_hdr->size, FMT_NONE);
12166414dc6dSKonstantin Porotchkin }
12176414dc6dSKonstantin Porotchkin 
12186414dc6dSKonstantin Porotchkin int print_extension(void *buf, int base, int count, int ext_size)
12196414dc6dSKonstantin Porotchkin {
12206414dc6dSKonstantin Porotchkin 	ext_header_t *ext_hdr = buf;
12216414dc6dSKonstantin Porotchkin 	int pad = ext_size;
12226414dc6dSKonstantin Porotchkin 	int curr_size;
12236414dc6dSKonstantin Porotchkin 
12246414dc6dSKonstantin Porotchkin 	while (count--) {
12256414dc6dSKonstantin Porotchkin 		if (ext_hdr->type == EXT_TYPE_BINARY)
12266414dc6dSKonstantin Porotchkin 			print_bin_ext(ext_hdr, base);
12276414dc6dSKonstantin Porotchkin 		else if (ext_hdr->type == EXT_TYPE_SECURITY)
12286414dc6dSKonstantin Porotchkin 			print_sec_ext(ext_hdr, base);
12296414dc6dSKonstantin Porotchkin 
12306414dc6dSKonstantin Porotchkin 		curr_size = sizeof(ext_header_t) + ext_hdr->size;
12316414dc6dSKonstantin Porotchkin 		base += curr_size;
12326414dc6dSKonstantin Porotchkin 		pad  -= curr_size;
12336414dc6dSKonstantin Porotchkin 		ext_hdr = (ext_header_t *)((uintptr_t)ext_hdr + curr_size);
12346414dc6dSKonstantin Porotchkin 	}
12356414dc6dSKonstantin Porotchkin 
12366414dc6dSKonstantin Porotchkin 	if (pad)
12376414dc6dSKonstantin Porotchkin 		do_print_field(0, "padding", base, pad, FMT_NONE);
12386414dc6dSKonstantin Porotchkin 
12396414dc6dSKonstantin Porotchkin 	return ext_size;
12406414dc6dSKonstantin Porotchkin }
12416414dc6dSKonstantin Porotchkin 
12426414dc6dSKonstantin Porotchkin int parse_image(uint8_t *buf, int size)
12436414dc6dSKonstantin Porotchkin {
12446414dc6dSKonstantin Porotchkin 	int base = 0;
12456414dc6dSKonstantin Porotchkin 	int ret = 1;
12466414dc6dSKonstantin Porotchkin 	header_t *main_hdr;
12476414dc6dSKonstantin Porotchkin 	uint32_t checksum, prolog_checksum;
12486414dc6dSKonstantin Porotchkin 
12496414dc6dSKonstantin Porotchkin 
12506414dc6dSKonstantin Porotchkin 	fprintf(stdout,
12516414dc6dSKonstantin Porotchkin 		"################### Prolog Start ######################\n\n");
12526414dc6dSKonstantin Porotchkin 	main_hdr = (header_t *)buf;
12536414dc6dSKonstantin Porotchkin 	base += print_header(buf, base);
12546414dc6dSKonstantin Porotchkin 
12556414dc6dSKonstantin Porotchkin 	if (main_hdr->ext_count)
12566414dc6dSKonstantin Porotchkin 		base += print_extension(buf + base, base,
12576414dc6dSKonstantin Porotchkin 					main_hdr->ext_count,
12586414dc6dSKonstantin Porotchkin 					main_hdr->prolog_size -
12596414dc6dSKonstantin Porotchkin 					sizeof(header_t));
12606414dc6dSKonstantin Porotchkin 
12616414dc6dSKonstantin Porotchkin 	if (base < main_hdr->prolog_size) {
12626414dc6dSKonstantin Porotchkin 		fprintf(stdout, "\n########### Padding ##############\n");
12636414dc6dSKonstantin Porotchkin 		do_print_field(0, "prolog padding",
12646414dc6dSKonstantin Porotchkin 			       base, main_hdr->prolog_size - base, FMT_HEX);
12656414dc6dSKonstantin Porotchkin 		base = main_hdr->prolog_size;
12666414dc6dSKonstantin Porotchkin 	}
12676414dc6dSKonstantin Porotchkin 	fprintf(stdout,
12686414dc6dSKonstantin Porotchkin 		"\n################### Prolog End ######################\n");
12696414dc6dSKonstantin Porotchkin 
12706414dc6dSKonstantin Porotchkin 	fprintf(stdout,
12716414dc6dSKonstantin Porotchkin 		"\n################### Boot image ######################\n");
12726414dc6dSKonstantin Porotchkin 
12736414dc6dSKonstantin Porotchkin 	do_print_field(0, "boot image", base, size - base - 4, FMT_NONE);
12746414dc6dSKonstantin Porotchkin 
12756414dc6dSKonstantin Porotchkin 	fprintf(stdout,
12766414dc6dSKonstantin Porotchkin 		"################### Image end ########################\n");
12776414dc6dSKonstantin Porotchkin 
12786414dc6dSKonstantin Porotchkin 	/* Check sanity for certain values */
12796414dc6dSKonstantin Porotchkin 	printf("\nChecking values:\n");
12806414dc6dSKonstantin Porotchkin 
12816414dc6dSKonstantin Porotchkin 	if (main_hdr->magic == MAIN_HDR_MAGIC) {
12826414dc6dSKonstantin Porotchkin 		fprintf(stdout, "Headers magic:    OK!\n");
12836414dc6dSKonstantin Porotchkin 	} else {
12846414dc6dSKonstantin Porotchkin 		fprintf(stderr,
12856414dc6dSKonstantin Porotchkin 			"\n****** ERROR: HEADER MAGIC 0x%08x != 0x%08x\n",
12866414dc6dSKonstantin Porotchkin 			main_hdr->magic, MAIN_HDR_MAGIC);
12876414dc6dSKonstantin Porotchkin 		goto error;
12886414dc6dSKonstantin Porotchkin 	}
12896414dc6dSKonstantin Porotchkin 
12906414dc6dSKonstantin Porotchkin 	/* headers checksum */
12916414dc6dSKonstantin Porotchkin 	/* clear the checksum field in header to calculate checksum */
12926414dc6dSKonstantin Porotchkin 	prolog_checksum = main_hdr->prolog_checksum;
12936414dc6dSKonstantin Porotchkin 	main_hdr->prolog_checksum = 0;
12946414dc6dSKonstantin Porotchkin 	checksum = checksum32((uint32_t *)buf, main_hdr->prolog_size);
12956414dc6dSKonstantin Porotchkin 
12966414dc6dSKonstantin Porotchkin 	if (checksum == prolog_checksum) {
12976414dc6dSKonstantin Porotchkin 		fprintf(stdout, "Headers checksum: OK!\n");
12986414dc6dSKonstantin Porotchkin 	} else {
12996414dc6dSKonstantin Porotchkin 		fprintf(stderr,
13006414dc6dSKonstantin Porotchkin 			"\n***** ERROR: BAD HEADER CHECKSUM 0x%08x != 0x%08x\n",
13016414dc6dSKonstantin Porotchkin 			checksum, prolog_checksum);
13026414dc6dSKonstantin Porotchkin 		goto error;
13036414dc6dSKonstantin Porotchkin 	}
13046414dc6dSKonstantin Porotchkin 
13056414dc6dSKonstantin Porotchkin 	/* boot image checksum */
13066414dc6dSKonstantin Porotchkin 	checksum = checksum32((uint32_t *)(buf + main_hdr->prolog_size),
13076414dc6dSKonstantin Porotchkin 			      main_hdr->boot_image_size);
13086414dc6dSKonstantin Porotchkin 	if (checksum == main_hdr->boot_image_checksum) {
13096414dc6dSKonstantin Porotchkin 		fprintf(stdout, "Image checksum:   OK!\n");
13106414dc6dSKonstantin Porotchkin 	} else {
13116414dc6dSKonstantin Porotchkin 		fprintf(stderr,
13126414dc6dSKonstantin Porotchkin 			"\n****** ERROR: BAD IMAGE CHECKSUM 0x%08x != 0x%08x\n",
13136414dc6dSKonstantin Porotchkin 			checksum, main_hdr->boot_image_checksum);
13146414dc6dSKonstantin Porotchkin 		goto error;
13156414dc6dSKonstantin Porotchkin 	}
13166414dc6dSKonstantin Porotchkin 
13176414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT
13186414dc6dSKonstantin Porotchkin 	/* RSA signatures */
13196414dc6dSKonstantin Porotchkin 	if (main_hdr->ext_count) {
13206414dc6dSKonstantin Porotchkin 		uint8_t		ext_num = main_hdr->ext_count;
13216414dc6dSKonstantin Porotchkin 		ext_header_t	*ext_hdr = (ext_header_t *)(main_hdr + 1);
13226414dc6dSKonstantin Porotchkin 		unsigned char	hash[32];
13236414dc6dSKonstantin Porotchkin 		int		i;
13246414dc6dSKonstantin Porotchkin 
13256414dc6dSKonstantin Porotchkin 		while (ext_num--) {
13266414dc6dSKonstantin Porotchkin 			if (ext_hdr->type == EXT_TYPE_SECURITY) {
13276414dc6dSKonstantin Porotchkin 				sec_entry_t  *sec_entry =
13286414dc6dSKonstantin Porotchkin 						(sec_entry_t *)(ext_hdr + 1);
13296414dc6dSKonstantin Porotchkin 
13306414dc6dSKonstantin Porotchkin 				ret = verify_secure_header_signatures(
13316414dc6dSKonstantin Porotchkin 							main_hdr, sec_entry);
13326414dc6dSKonstantin Porotchkin 				if (ret != 0) {
13336414dc6dSKonstantin Porotchkin 					fprintf(stderr,
13346414dc6dSKonstantin Porotchkin 						"\n****** FAILED TO VERIFY ");
13356414dc6dSKonstantin Porotchkin 					fprintf(stderr,
13366414dc6dSKonstantin Porotchkin 						"RSA SIGNATURES ********\n");
13376414dc6dSKonstantin Porotchkin 					goto error;
13386414dc6dSKonstantin Porotchkin 				}
13396414dc6dSKonstantin Porotchkin 
1340a79df348SKonstantin Porotchkin 				mbedtls_sha256_ret(sec_entry->kak_key,
13416414dc6dSKonstantin Porotchkin 					       MAX_RSA_DER_BYTE_LEN, hash, 0);
13426414dc6dSKonstantin Porotchkin 				fprintf(stdout,
13436414dc6dSKonstantin Porotchkin 					">>>>>>>>>> KAK KEY HASH >>>>>>>>>>\n");
13446414dc6dSKonstantin Porotchkin 				fprintf(stdout, "SHA256: ");
13456414dc6dSKonstantin Porotchkin 				for (i = 0; i < 32; i++)
13466414dc6dSKonstantin Porotchkin 					fprintf(stdout, "%02X", hash[i]);
13476414dc6dSKonstantin Porotchkin 
13486414dc6dSKonstantin Porotchkin 				fprintf(stdout,
13496414dc6dSKonstantin Porotchkin 					"\n<<<<<<<<< KAK KEY HASH <<<<<<<<<\n");
13506414dc6dSKonstantin Porotchkin 
13516414dc6dSKonstantin Porotchkin 				break;
13526414dc6dSKonstantin Porotchkin 			}
13536414dc6dSKonstantin Porotchkin 			ext_hdr =
13546414dc6dSKonstantin Porotchkin 				(ext_header_t *)((uint8_t *)(ext_hdr + 1) +
13556414dc6dSKonstantin Porotchkin 				 ext_hdr->size);
13566414dc6dSKonstantin Porotchkin 		}
13576414dc6dSKonstantin Porotchkin 	}
13586414dc6dSKonstantin Porotchkin #endif
13596414dc6dSKonstantin Porotchkin 
13606414dc6dSKonstantin Porotchkin 	ret = 0;
13616414dc6dSKonstantin Porotchkin error:
13626414dc6dSKonstantin Porotchkin 	return ret;
13636414dc6dSKonstantin Porotchkin }
13646414dc6dSKonstantin Porotchkin 
13656414dc6dSKonstantin Porotchkin int format_bin_ext(char *filename, FILE *out_fd)
13666414dc6dSKonstantin Porotchkin {
13676414dc6dSKonstantin Porotchkin 	ext_header_t header;
13686414dc6dSKonstantin Porotchkin 	FILE *in_fd;
13696414dc6dSKonstantin Porotchkin 	int size, written;
13706414dc6dSKonstantin Porotchkin 	int aligned_size, pad_bytes;
13716414dc6dSKonstantin Porotchkin 	char c;
13726414dc6dSKonstantin Porotchkin 
13736414dc6dSKonstantin Porotchkin 	in_fd = fopen(filename, "rb");
13746414dc6dSKonstantin Porotchkin 	if (in_fd == NULL) {
13756414dc6dSKonstantin Porotchkin 		fprintf(stderr, "failed to open bin extension file %s\n",
13766414dc6dSKonstantin Porotchkin 			filename);
13776414dc6dSKonstantin Porotchkin 		return 1;
13786414dc6dSKonstantin Porotchkin 	}
13796414dc6dSKonstantin Porotchkin 
13806414dc6dSKonstantin Porotchkin 	size = get_file_size(filename);
13816414dc6dSKonstantin Porotchkin 	if (size <= 0) {
13826414dc6dSKonstantin Porotchkin 		fprintf(stderr, "bin extension file size is bad\n");
13836414dc6dSKonstantin Porotchkin 		return 1;
13846414dc6dSKonstantin Porotchkin 	}
13856414dc6dSKonstantin Porotchkin 
13866414dc6dSKonstantin Porotchkin 	/* Align extension size to 8 bytes */
13876414dc6dSKonstantin Porotchkin 	aligned_size = (size + 7) & (~7);
13886414dc6dSKonstantin Porotchkin 	pad_bytes    = aligned_size - size;
13896414dc6dSKonstantin Porotchkin 
13906414dc6dSKonstantin Porotchkin 	header.type = EXT_TYPE_BINARY;
13916414dc6dSKonstantin Porotchkin 	header.offset = 0;
13926414dc6dSKonstantin Porotchkin 	header.size = aligned_size;
13936414dc6dSKonstantin Porotchkin 	header.reserved = 0;
13946414dc6dSKonstantin Porotchkin 
13956414dc6dSKonstantin Porotchkin 	/* Write header */
13966414dc6dSKonstantin Porotchkin 	written = fwrite(&header, sizeof(ext_header_t), 1, out_fd);
13976414dc6dSKonstantin Porotchkin 	if (written != 1) {
13986414dc6dSKonstantin Porotchkin 		fprintf(stderr, "failed writing header to extension file\n");
13996414dc6dSKonstantin Porotchkin 		return 1;
14006414dc6dSKonstantin Porotchkin 	}
14016414dc6dSKonstantin Porotchkin 
14026414dc6dSKonstantin Porotchkin 	/* Write image */
14036414dc6dSKonstantin Porotchkin 	while (size--) {
14046414dc6dSKonstantin Porotchkin 		c = getc(in_fd);
14056414dc6dSKonstantin Porotchkin 		fputc(c, out_fd);
14066414dc6dSKonstantin Porotchkin 	}
14076414dc6dSKonstantin Porotchkin 
14086414dc6dSKonstantin Porotchkin 	while (pad_bytes--)
14096414dc6dSKonstantin Porotchkin 		fputc(0, out_fd);
14106414dc6dSKonstantin Porotchkin 
14116414dc6dSKonstantin Porotchkin 	fclose(in_fd);
14126414dc6dSKonstantin Porotchkin 
14136414dc6dSKonstantin Porotchkin 	return 0;
14146414dc6dSKonstantin Porotchkin }
14156414dc6dSKonstantin Porotchkin 
14166414dc6dSKonstantin Porotchkin /* ****************************************
14176414dc6dSKonstantin Porotchkin  *
14186414dc6dSKonstantin Porotchkin  * Write all extensions (binary, secure
14196414dc6dSKonstantin Porotchkin  * extensions) to file
14206414dc6dSKonstantin Porotchkin  *
14216414dc6dSKonstantin Porotchkin  * ****************************************/
14226414dc6dSKonstantin Porotchkin 
14236414dc6dSKonstantin Porotchkin int format_extensions(char *ext_filename)
14246414dc6dSKonstantin Porotchkin {
14256414dc6dSKonstantin Porotchkin 	FILE *out_fd;
14266414dc6dSKonstantin Porotchkin 	int ret = 0;
14276414dc6dSKonstantin Porotchkin 
14286414dc6dSKonstantin Porotchkin 	out_fd = fopen(ext_filename, "wb");
14296414dc6dSKonstantin Porotchkin 	if (out_fd == NULL) {
14306414dc6dSKonstantin Porotchkin 		fprintf(stderr, "failed to open extension output file %s",
14316414dc6dSKonstantin Porotchkin 			ext_filename);
14326414dc6dSKonstantin Porotchkin 		return 1;
14336414dc6dSKonstantin Porotchkin 	}
14346414dc6dSKonstantin Porotchkin 
14356414dc6dSKonstantin Porotchkin 	if (strncmp(opts.bin_ext_file, "NA", MAX_FILENAME)) {
14366414dc6dSKonstantin Porotchkin 		if (format_bin_ext(opts.bin_ext_file, out_fd)) {
14376414dc6dSKonstantin Porotchkin 			ret = 1;
14386414dc6dSKonstantin Porotchkin 			goto error;
14396414dc6dSKonstantin Porotchkin 		}
14406414dc6dSKonstantin Porotchkin 	}
14416414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT
14426414dc6dSKonstantin Porotchkin 	if (strncmp(opts.sec_cfg_file, "NA", MAX_FILENAME)) {
14436414dc6dSKonstantin Porotchkin 		if (format_sec_ext(opts.sec_cfg_file, out_fd)) {
14446414dc6dSKonstantin Porotchkin 			ret = 1;
14456414dc6dSKonstantin Porotchkin 			goto error;
14466414dc6dSKonstantin Porotchkin 		}
14476414dc6dSKonstantin Porotchkin 	}
14486414dc6dSKonstantin Porotchkin #endif
14496414dc6dSKonstantin Porotchkin 
14506414dc6dSKonstantin Porotchkin error:
14516414dc6dSKonstantin Porotchkin 	fflush(out_fd);
14526414dc6dSKonstantin Porotchkin 	fclose(out_fd);
14536414dc6dSKonstantin Porotchkin 	return ret;
14546414dc6dSKonstantin Porotchkin }
14556414dc6dSKonstantin Porotchkin 
14566414dc6dSKonstantin Porotchkin void update_uart(header_t *header)
14576414dc6dSKonstantin Porotchkin {
14586414dc6dSKonstantin Porotchkin 	header->uart_cfg = 0;
14596414dc6dSKonstantin Porotchkin 	header->baudrate = 0;
14606414dc6dSKonstantin Porotchkin 
14616414dc6dSKonstantin Porotchkin 	if (opts.disable_print)
14626414dc6dSKonstantin Porotchkin 		uart_set_mode(header->uart_cfg, UART_MODE_DISABLE);
14636414dc6dSKonstantin Porotchkin 
14646414dc6dSKonstantin Porotchkin 	if (opts.baudrate)
14656414dc6dSKonstantin Porotchkin 		header->baudrate = (opts.baudrate / 1200);
14666414dc6dSKonstantin Porotchkin }
14676414dc6dSKonstantin Porotchkin 
14686414dc6dSKonstantin Porotchkin /* ****************************************
14696414dc6dSKonstantin Porotchkin  *
14706414dc6dSKonstantin Porotchkin  * Write the image prolog, i.e.
14716414dc6dSKonstantin Porotchkin  * main header and extensions, to file
14726414dc6dSKonstantin Porotchkin  *
14736414dc6dSKonstantin Porotchkin  * ****************************************/
14746414dc6dSKonstantin Porotchkin 
14756414dc6dSKonstantin Porotchkin int write_prolog(int ext_cnt, char *ext_filename,
14766414dc6dSKonstantin Porotchkin 		 uint8_t *image_buf, int image_size, FILE *out_fd)
14776414dc6dSKonstantin Porotchkin {
14786414dc6dSKonstantin Porotchkin 	header_t		*header;
14796414dc6dSKonstantin Porotchkin 	int main_hdr_size = sizeof(header_t);
14806414dc6dSKonstantin Porotchkin 	int prolog_size = main_hdr_size;
14816414dc6dSKonstantin Porotchkin 	FILE *ext_fd;
14826414dc6dSKonstantin Porotchkin 	char *buf;
14836414dc6dSKonstantin Porotchkin 	int written, read;
14846414dc6dSKonstantin Porotchkin 	int ret = 1;
14856414dc6dSKonstantin Porotchkin 
14866414dc6dSKonstantin Porotchkin 
14876414dc6dSKonstantin Porotchkin 	if (ext_cnt)
14886414dc6dSKonstantin Porotchkin 		prolog_size +=  get_file_size(ext_filename);
14896414dc6dSKonstantin Porotchkin 
14906414dc6dSKonstantin Porotchkin 	prolog_size = ((prolog_size + PROLOG_ALIGNMENT) &
14916414dc6dSKonstantin Porotchkin 		     (~(PROLOG_ALIGNMENT-1)));
14926414dc6dSKonstantin Porotchkin 
14936414dc6dSKonstantin Porotchkin 	/* Allocate a zeroed buffer to zero the padding bytes */
14946414dc6dSKonstantin Porotchkin 	buf = calloc(prolog_size, 1);
14956414dc6dSKonstantin Porotchkin 	if (buf == NULL) {
14966414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Error: failed allocating checksum buffer\n");
14976414dc6dSKonstantin Porotchkin 		return 1;
14986414dc6dSKonstantin Porotchkin 	}
14996414dc6dSKonstantin Porotchkin 
15006414dc6dSKonstantin Porotchkin 	header = (header_t *)buf;
15016414dc6dSKonstantin Porotchkin 	header->magic       = MAIN_HDR_MAGIC;
15026414dc6dSKonstantin Porotchkin 	header->prolog_size = prolog_size;
15036414dc6dSKonstantin Porotchkin 	header->load_addr   = opts.load_addr;
15046414dc6dSKonstantin Porotchkin 	header->exec_addr   = opts.exec_addr;
15056414dc6dSKonstantin Porotchkin 	header->io_arg_0    = opts.nfc_io_args;
15066414dc6dSKonstantin Porotchkin 	header->ext_count   = ext_cnt;
15076414dc6dSKonstantin Porotchkin 	header->aux_flags   = 0;
15086414dc6dSKonstantin Porotchkin 	header->boot_image_size = (image_size + 3) & (~0x3);
15096414dc6dSKonstantin Porotchkin 	header->boot_image_checksum = checksum32((uint32_t *)image_buf,
15106414dc6dSKonstantin Porotchkin 						 image_size);
15116414dc6dSKonstantin Porotchkin 
15126414dc6dSKonstantin Porotchkin 	update_uart(header);
15136414dc6dSKonstantin Porotchkin 
15146414dc6dSKonstantin Porotchkin 	/* Populate buffer with main header and extensions */
15156414dc6dSKonstantin Porotchkin 	if (ext_cnt) {
15166414dc6dSKonstantin Porotchkin 		ext_fd = fopen(ext_filename, "rb");
15176414dc6dSKonstantin Porotchkin 		if (ext_fd == NULL) {
15186414dc6dSKonstantin Porotchkin 			fprintf(stderr,
15196414dc6dSKonstantin Porotchkin 				"Error: failed to open extensions file\n");
15206414dc6dSKonstantin Porotchkin 			goto error;
15216414dc6dSKonstantin Porotchkin 		}
15226414dc6dSKonstantin Porotchkin 
15236414dc6dSKonstantin Porotchkin 		read = fread(&buf[main_hdr_size],
15246414dc6dSKonstantin Porotchkin 			     get_file_size(ext_filename), 1, ext_fd);
15256414dc6dSKonstantin Porotchkin 		if (read != 1) {
15266414dc6dSKonstantin Porotchkin 			fprintf(stderr,
15276414dc6dSKonstantin Porotchkin 				"Error: failed to open extensions file\n");
15286414dc6dSKonstantin Porotchkin 			goto error;
15296414dc6dSKonstantin Porotchkin 		}
15306414dc6dSKonstantin Porotchkin 
15316414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT
15326414dc6dSKonstantin Porotchkin 		/* Secure boot mode? */
15336414dc6dSKonstantin Porotchkin 		if (opts.sec_opts != 0) {
15346414dc6dSKonstantin Porotchkin 			ret = finalize_secure_ext(header, (uint8_t *)buf,
15356414dc6dSKonstantin Porotchkin 						  prolog_size, image_buf,
15366414dc6dSKonstantin Porotchkin 						  image_size);
15376414dc6dSKonstantin Porotchkin 			if (ret != 0) {
15386414dc6dSKonstantin Porotchkin 				fprintf(stderr, "Error: failed to handle ");
15396414dc6dSKonstantin Porotchkin 				fprintf(stderr, "secure extension!\n");
15406414dc6dSKonstantin Porotchkin 				goto error;
15416414dc6dSKonstantin Porotchkin 			}
15426414dc6dSKonstantin Porotchkin 		} /* secure boot mode */
15436414dc6dSKonstantin Porotchkin #endif
15446414dc6dSKonstantin Porotchkin 	}
15456414dc6dSKonstantin Porotchkin 
15466414dc6dSKonstantin Porotchkin 	/* Update the total prolog checksum */
15476414dc6dSKonstantin Porotchkin 	header->prolog_checksum = checksum32((uint32_t *)buf, prolog_size);
15486414dc6dSKonstantin Porotchkin 
15496414dc6dSKonstantin Porotchkin 	/* Now spill everything to output file */
15506414dc6dSKonstantin Porotchkin 	written = fwrite(buf, prolog_size, 1, out_fd);
15516414dc6dSKonstantin Porotchkin 	if (written != 1) {
15526414dc6dSKonstantin Porotchkin 		fprintf(stderr,
15536414dc6dSKonstantin Porotchkin 			"Error: failed to write prolog to output file\n");
15546414dc6dSKonstantin Porotchkin 		goto error;
15556414dc6dSKonstantin Porotchkin 	}
15566414dc6dSKonstantin Porotchkin 
15576414dc6dSKonstantin Porotchkin 	ret = 0;
15586414dc6dSKonstantin Porotchkin 
15596414dc6dSKonstantin Porotchkin error:
15606414dc6dSKonstantin Porotchkin 	free(buf);
15616414dc6dSKonstantin Porotchkin 	return ret;
15626414dc6dSKonstantin Porotchkin }
15636414dc6dSKonstantin Porotchkin 
15646414dc6dSKonstantin Porotchkin int write_boot_image(uint8_t *buf, uint32_t image_size, FILE *out_fd)
15656414dc6dSKonstantin Porotchkin {
15666414dc6dSKonstantin Porotchkin 	int written;
15676414dc6dSKonstantin Porotchkin 
1568*5985a1e4SKonstantin Porotchkin 	written = fwrite(buf, image_size, 1, out_fd);
15696414dc6dSKonstantin Porotchkin 	if (written != 1) {
15706414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Error: Failed to write boot image\n");
15716414dc6dSKonstantin Porotchkin 		goto error;
15726414dc6dSKonstantin Porotchkin 	}
15736414dc6dSKonstantin Porotchkin 
15746414dc6dSKonstantin Porotchkin 	return 0;
15756414dc6dSKonstantin Porotchkin error:
15766414dc6dSKonstantin Porotchkin 	return 1;
15776414dc6dSKonstantin Porotchkin }
15786414dc6dSKonstantin Porotchkin 
15796414dc6dSKonstantin Porotchkin int main(int argc, char *argv[])
15806414dc6dSKonstantin Porotchkin {
15816414dc6dSKonstantin Porotchkin 	char in_file[MAX_FILENAME+1] = { 0 };
15826414dc6dSKonstantin Porotchkin 	char out_file[MAX_FILENAME+1] = { 0 };
15836414dc6dSKonstantin Porotchkin 	char ext_file[MAX_FILENAME+1] = { 0 };
15846414dc6dSKonstantin Porotchkin 	FILE *in_fd = NULL;
15856414dc6dSKonstantin Porotchkin 	FILE *out_fd = NULL;
15866414dc6dSKonstantin Porotchkin 	int parse = 0;
15876414dc6dSKonstantin Porotchkin 	int ext_cnt = 0;
15886414dc6dSKonstantin Porotchkin 	int opt;
15896414dc6dSKonstantin Porotchkin 	int ret = 0;
1590*5985a1e4SKonstantin Porotchkin 	int image_size, file_size;
15916414dc6dSKonstantin Porotchkin 	uint8_t *image_buf = NULL;
15926414dc6dSKonstantin Porotchkin 	int read;
15936414dc6dSKonstantin Porotchkin 	size_t len;
15946414dc6dSKonstantin Porotchkin 	uint32_t nand_block_size_kb, mlc_nand;
15956414dc6dSKonstantin Porotchkin 
15966414dc6dSKonstantin Porotchkin 	/* Create temporary file for building extensions
15976414dc6dSKonstantin Porotchkin 	 * Use process ID for allowing multiple parallel runs
15986414dc6dSKonstantin Porotchkin 	 */
15996414dc6dSKonstantin Porotchkin 	snprintf(ext_file, MAX_FILENAME, "/tmp/ext_file-%x", getpid());
16006414dc6dSKonstantin Porotchkin 
16016414dc6dSKonstantin Porotchkin 	while ((opt = getopt(argc, argv, "hpms:i:l:e:a:b:u:n:t:c:k:")) != -1) {
16026414dc6dSKonstantin Porotchkin 		switch (opt) {
16036414dc6dSKonstantin Porotchkin 		case 'h':
16046414dc6dSKonstantin Porotchkin 			usage();
16056414dc6dSKonstantin Porotchkin 			break;
16066414dc6dSKonstantin Porotchkin 		case 'l':
16076414dc6dSKonstantin Porotchkin 			opts.load_addr = strtoul(optarg, NULL, 0);
16086414dc6dSKonstantin Porotchkin 			break;
16096414dc6dSKonstantin Porotchkin 		case 'e':
16106414dc6dSKonstantin Porotchkin 			opts.exec_addr = strtoul(optarg, NULL, 0);
16116414dc6dSKonstantin Porotchkin 			break;
16126414dc6dSKonstantin Porotchkin 		case 'm':
16136414dc6dSKonstantin Porotchkin 			opts.disable_print = 1;
16146414dc6dSKonstantin Porotchkin 			break;
16156414dc6dSKonstantin Porotchkin 		case 'u':
16166414dc6dSKonstantin Porotchkin 			opts.baudrate = strtoul(optarg, NULL, 0);
16176414dc6dSKonstantin Porotchkin 			break;
16186414dc6dSKonstantin Porotchkin 		case 'b':
16196414dc6dSKonstantin Porotchkin 			strncpy(opts.bin_ext_file, optarg, MAX_FILENAME);
16206414dc6dSKonstantin Porotchkin 			ext_cnt++;
16216414dc6dSKonstantin Porotchkin 			break;
16226414dc6dSKonstantin Porotchkin 		case 'p':
16236414dc6dSKonstantin Porotchkin 			parse = 1;
16246414dc6dSKonstantin Porotchkin 			break;
16256414dc6dSKonstantin Porotchkin 		case 'n':
16266414dc6dSKonstantin Porotchkin 			nand_block_size_kb = strtoul(optarg, NULL, 0);
16276414dc6dSKonstantin Porotchkin 			opts.nfc_io_args |= (nand_block_size_kb / 64);
16286414dc6dSKonstantin Porotchkin 			break;
16296414dc6dSKonstantin Porotchkin 		case 't':
16306414dc6dSKonstantin Porotchkin 			mlc_nand = 0;
16316414dc6dSKonstantin Porotchkin 			if (!strncmp("MLC", optarg, 3))
16326414dc6dSKonstantin Porotchkin 				mlc_nand = 1;
16336414dc6dSKonstantin Porotchkin 			opts.nfc_io_args |= (mlc_nand << 8);
16346414dc6dSKonstantin Porotchkin 			break;
16356414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT
16366414dc6dSKonstantin Porotchkin 		case 'c': /* SEC extension */
16376414dc6dSKonstantin Porotchkin 			strncpy(opts.sec_cfg_file, optarg, MAX_FILENAME);
16386414dc6dSKonstantin Porotchkin 			ext_cnt++;
16396414dc6dSKonstantin Porotchkin 			break;
16406414dc6dSKonstantin Porotchkin 		case 'k':
16416414dc6dSKonstantin Porotchkin 			opts.key_index = strtoul(optarg, NULL, 0);
16426414dc6dSKonstantin Porotchkin 			break;
16436414dc6dSKonstantin Porotchkin #endif
16446414dc6dSKonstantin Porotchkin 		default: /* '?' */
16456414dc6dSKonstantin Porotchkin 			usage_err("Unknown argument");
16466414dc6dSKonstantin Porotchkin 			exit(EXIT_FAILURE);
16476414dc6dSKonstantin Porotchkin 		}
16486414dc6dSKonstantin Porotchkin 	}
16496414dc6dSKonstantin Porotchkin 
16506414dc6dSKonstantin Porotchkin 	/* Check validity of inputes */
16516414dc6dSKonstantin Porotchkin 	if (opts.load_addr % 8)
16526414dc6dSKonstantin Porotchkin 		usage_err("Load address must be 8 bytes aligned");
16536414dc6dSKonstantin Porotchkin 
16546414dc6dSKonstantin Porotchkin 	if (opts.baudrate % 1200)
16556414dc6dSKonstantin Porotchkin 		usage_err("Baudrate must be a multiple of 1200");
16566414dc6dSKonstantin Porotchkin 
16576414dc6dSKonstantin Porotchkin 	/* The remaining arguments are the input
16586414dc6dSKonstantin Porotchkin 	 * and potentially output file
16596414dc6dSKonstantin Porotchkin 	 */
16606414dc6dSKonstantin Porotchkin 	/* Input file must exist so exit if not */
16616414dc6dSKonstantin Porotchkin 	if (optind >= argc)
16626414dc6dSKonstantin Porotchkin 		usage_err("missing input file name");
16636414dc6dSKonstantin Porotchkin 
16646414dc6dSKonstantin Porotchkin 	len = strlen(argv[optind]);
16656414dc6dSKonstantin Porotchkin 	if (len > MAX_FILENAME)
16666414dc6dSKonstantin Porotchkin 		usage_err("file name too long");
16676414dc6dSKonstantin Porotchkin 	memcpy(in_file, argv[optind], len);
16686414dc6dSKonstantin Porotchkin 	optind++;
16696414dc6dSKonstantin Porotchkin 
16706414dc6dSKonstantin Porotchkin 	/* Output file must exist in non parse mode */
16716414dc6dSKonstantin Porotchkin 	if (optind < argc) {
16726414dc6dSKonstantin Porotchkin 		len = strlen(argv[optind]);
16736414dc6dSKonstantin Porotchkin 		if (len > MAX_FILENAME)
16746414dc6dSKonstantin Porotchkin 			usage_err("file name too long");
16756414dc6dSKonstantin Porotchkin 		memcpy(out_file, argv[optind], len);
16766414dc6dSKonstantin Porotchkin 	} else if (!parse)
16776414dc6dSKonstantin Porotchkin 		usage_err("missing output file name");
16786414dc6dSKonstantin Porotchkin 
16796414dc6dSKonstantin Porotchkin 	/* open the input file */
16806414dc6dSKonstantin Porotchkin 	in_fd = fopen(in_file, "rb");
16816414dc6dSKonstantin Porotchkin 	if (in_fd == NULL) {
16826414dc6dSKonstantin Porotchkin 		printf("Error: Failed to open input file %s\n", in_file);
16836414dc6dSKonstantin Porotchkin 		goto main_exit;
16846414dc6dSKonstantin Porotchkin 	}
16856414dc6dSKonstantin Porotchkin 
1686*5985a1e4SKonstantin Porotchkin 	/* Read the input file to buffer
1687*5985a1e4SKonstantin Porotchkin 	 * Always align the image to 16 byte boundary
1688*5985a1e4SKonstantin Porotchkin 	 */
1689*5985a1e4SKonstantin Porotchkin 	file_size  = get_file_size(in_file);
1690*5985a1e4SKonstantin Porotchkin 	image_size = (file_size + AES_BLOCK_SZ - 1) & ~(AES_BLOCK_SZ - 1);
1691*5985a1e4SKonstantin Porotchkin 	image_buf  = calloc(image_size, 1);
16926414dc6dSKonstantin Porotchkin 	if (image_buf == NULL) {
16936414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Error: failed allocating input buffer\n");
16946414dc6dSKonstantin Porotchkin 		return 1;
16956414dc6dSKonstantin Porotchkin 	}
16966414dc6dSKonstantin Porotchkin 
1697*5985a1e4SKonstantin Porotchkin 	read = fread(image_buf, file_size, 1, in_fd);
16986414dc6dSKonstantin Porotchkin 	if (read != 1) {
16996414dc6dSKonstantin Porotchkin 		fprintf(stderr, "Error: failed to read input file\n");
17006414dc6dSKonstantin Porotchkin 		goto main_exit;
17016414dc6dSKonstantin Porotchkin 	}
17026414dc6dSKonstantin Porotchkin 
17036414dc6dSKonstantin Porotchkin 	/* Parse the input image and leave */
17046414dc6dSKonstantin Porotchkin 	if (parse) {
17056414dc6dSKonstantin Porotchkin 		if (opts.key_index >= CSK_ARR_SZ) {
17066414dc6dSKonstantin Porotchkin 			fprintf(stderr,
17076414dc6dSKonstantin Porotchkin 				"Wrong key IDX value. Valid values 0 - %d\n",
17086414dc6dSKonstantin Porotchkin 				CSK_ARR_SZ - 1);
17096414dc6dSKonstantin Porotchkin 			goto main_exit;
17106414dc6dSKonstantin Porotchkin 		}
17116414dc6dSKonstantin Porotchkin 		ret = parse_image(image_buf, image_size);
17126414dc6dSKonstantin Porotchkin 		goto main_exit;
17136414dc6dSKonstantin Porotchkin 	}
17146414dc6dSKonstantin Porotchkin 
17156414dc6dSKonstantin Porotchkin 	/* Create a blob file from all extensions */
17166414dc6dSKonstantin Porotchkin 	if (ext_cnt) {
17176414dc6dSKonstantin Porotchkin 		ret = format_extensions(ext_file);
17186414dc6dSKonstantin Porotchkin 		if (ret)
17196414dc6dSKonstantin Porotchkin 			goto main_exit;
17206414dc6dSKonstantin Porotchkin 	}
17216414dc6dSKonstantin Porotchkin 
17226414dc6dSKonstantin Porotchkin 	out_fd = fopen(out_file, "wb");
17236414dc6dSKonstantin Porotchkin 	if (out_fd == NULL) {
17246414dc6dSKonstantin Porotchkin 		fprintf(stderr,
17256414dc6dSKonstantin Porotchkin 			"Error: Failed to open output file %s\n", out_file);
17266414dc6dSKonstantin Porotchkin 		goto main_exit;
17276414dc6dSKonstantin Porotchkin 	}
17286414dc6dSKonstantin Porotchkin 
17296414dc6dSKonstantin Porotchkin 	ret = write_prolog(ext_cnt, ext_file, image_buf, image_size, out_fd);
17306414dc6dSKonstantin Porotchkin 	if (ret)
17316414dc6dSKonstantin Porotchkin 		goto main_exit;
17326414dc6dSKonstantin Porotchkin 
17336414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT
17346414dc6dSKonstantin Porotchkin 	if (opts.sec_opts && (opts.sec_opts->encrypted_image != 0) &&
17356414dc6dSKonstantin Porotchkin 	    (opts.sec_opts->enc_image_sz != 0)) {
17366414dc6dSKonstantin Porotchkin 		ret = write_boot_image(opts.sec_opts->encrypted_image,
17376414dc6dSKonstantin Porotchkin 				       opts.sec_opts->enc_image_sz, out_fd);
17386414dc6dSKonstantin Porotchkin 	} else
17396414dc6dSKonstantin Porotchkin #endif
17406414dc6dSKonstantin Porotchkin 		ret = write_boot_image(image_buf, image_size, out_fd);
17416414dc6dSKonstantin Porotchkin 	if (ret)
17426414dc6dSKonstantin Porotchkin 		goto main_exit;
17436414dc6dSKonstantin Porotchkin 
17446414dc6dSKonstantin Porotchkin main_exit:
17456414dc6dSKonstantin Porotchkin 	if (in_fd)
17466414dc6dSKonstantin Porotchkin 		fclose(in_fd);
17476414dc6dSKonstantin Porotchkin 
17486414dc6dSKonstantin Porotchkin 	if (out_fd)
17496414dc6dSKonstantin Porotchkin 		fclose(out_fd);
17506414dc6dSKonstantin Porotchkin 
17516414dc6dSKonstantin Porotchkin 	if (image_buf)
17526414dc6dSKonstantin Porotchkin 		free(image_buf);
17536414dc6dSKonstantin Porotchkin 
17546414dc6dSKonstantin Porotchkin 	unlink(ext_file);
17556414dc6dSKonstantin Porotchkin 
17566414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT
17576414dc6dSKonstantin Porotchkin 	if (opts.sec_opts) {
17586414dc6dSKonstantin Porotchkin 		if (opts.sec_opts->encrypted_image)
17596414dc6dSKonstantin Porotchkin 			free(opts.sec_opts->encrypted_image);
17606414dc6dSKonstantin Porotchkin 		free(opts.sec_opts);
17616414dc6dSKonstantin Porotchkin 	}
17626414dc6dSKonstantin Porotchkin #endif
17636414dc6dSKonstantin Porotchkin 	exit(ret);
17646414dc6dSKonstantin Porotchkin }
1765