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