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 */ 21*8eb4efe7SHenrik 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 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 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 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 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 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 */ 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 */ 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]; 4246414dc6dSKonstantin Porotchkin int 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"); 5196414dc6dSKonstantin Porotchkin fprintf(stderr, " decryption! Byte count is %d\n", i); 5206414dc6dSKonstantin Porotchkin rval = -1; 5216414dc6dSKonstantin Porotchkin goto encrypt_exit; 5226414dc6dSKonstantin Porotchkin } 5236414dc6dSKonstantin Porotchkin } 5246414dc6dSKonstantin Porotchkin 5256414dc6dSKonstantin Porotchkin encrypt_exit: 5266414dc6dSKonstantin Porotchkin 5276414dc6dSKonstantin Porotchkin mbedtls_aes_free(&aes_ctx); 5286414dc6dSKonstantin Porotchkin if (test_img) 5296414dc6dSKonstantin Porotchkin free(test_img); 5306414dc6dSKonstantin Porotchkin 5316414dc6dSKonstantin Porotchkin return rval; 5326414dc6dSKonstantin Porotchkin } /* end of image_encrypt */ 5336414dc6dSKonstantin Porotchkin 5346414dc6dSKonstantin Porotchkin /******************************************************************************* 5356414dc6dSKonstantin Porotchkin * verify_secure_header_signatures 5366414dc6dSKonstantin Porotchkin * Verify CSK array, header and image signatures and print results 5376414dc6dSKonstantin Porotchkin * INPUT: 5386414dc6dSKonstantin Porotchkin * main_hdr Main header 5396414dc6dSKonstantin Porotchkin * sec_ext Secure extension 5406414dc6dSKonstantin Porotchkin * OUTPUT: 5416414dc6dSKonstantin Porotchkin * none 5426414dc6dSKonstantin Porotchkin * RETURN: 5436414dc6dSKonstantin Porotchkin * 0 on success 5446414dc6dSKonstantin Porotchkin */ 5456414dc6dSKonstantin Porotchkin int verify_secure_header_signatures(header_t *main_hdr, sec_entry_t *sec_ext) 5466414dc6dSKonstantin Porotchkin { 5476414dc6dSKonstantin Porotchkin uint8_t *image = (uint8_t *)main_hdr + main_hdr->prolog_size; 5486414dc6dSKonstantin Porotchkin uint8_t signature[RSA_SIGN_BYTE_LEN]; 5496414dc6dSKonstantin Porotchkin int rval = -1; 5506414dc6dSKonstantin Porotchkin 5516414dc6dSKonstantin Porotchkin /* Save headers signature and reset it in the secure header */ 5526414dc6dSKonstantin Porotchkin memcpy(signature, sec_ext->header_sign, RSA_SIGN_BYTE_LEN); 5536414dc6dSKonstantin Porotchkin memset(sec_ext->header_sign, 0, RSA_SIGN_BYTE_LEN); 5546414dc6dSKonstantin Porotchkin 5556414dc6dSKonstantin Porotchkin fprintf(stdout, "\nCheck RSA Signatures\n"); 5566414dc6dSKonstantin Porotchkin fprintf(stdout, "#########################\n"); 5576414dc6dSKonstantin Porotchkin fprintf(stdout, "CSK Block Signature: "); 5586414dc6dSKonstantin Porotchkin if (verify_rsa_signature(sec_ext->kak_key, 5596414dc6dSKonstantin Porotchkin MAX_RSA_DER_BYTE_LEN, 5606414dc6dSKonstantin Porotchkin &sec_ext->csk_keys[0][0], 5616414dc6dSKonstantin Porotchkin sizeof(sec_ext->csk_keys), 5626414dc6dSKonstantin Porotchkin "CSK Block Signature: ", 5636414dc6dSKonstantin Porotchkin sec_ext->csk_sign) != 0) { 5646414dc6dSKonstantin Porotchkin fprintf(stdout, "ERROR\n"); 5656414dc6dSKonstantin Porotchkin goto ver_error; 5666414dc6dSKonstantin Porotchkin } 5676414dc6dSKonstantin Porotchkin fprintf(stdout, "OK\n"); 5686414dc6dSKonstantin Porotchkin 5696414dc6dSKonstantin Porotchkin if (opts.key_index != -1) { 5706414dc6dSKonstantin Porotchkin fprintf(stdout, "Image Signature: "); 5716414dc6dSKonstantin Porotchkin if (verify_rsa_signature(sec_ext->csk_keys[opts.key_index], 5726414dc6dSKonstantin Porotchkin MAX_RSA_DER_BYTE_LEN, 5736414dc6dSKonstantin Porotchkin image, main_hdr->boot_image_size, 5746414dc6dSKonstantin Porotchkin "Image Signature: ", 5756414dc6dSKonstantin Porotchkin sec_ext->image_sign) != 0) { 5766414dc6dSKonstantin Porotchkin fprintf(stdout, "ERROR\n"); 5776414dc6dSKonstantin Porotchkin goto ver_error; 5786414dc6dSKonstantin Porotchkin } 5796414dc6dSKonstantin Porotchkin fprintf(stdout, "OK\n"); 5806414dc6dSKonstantin Porotchkin 5816414dc6dSKonstantin Porotchkin fprintf(stdout, "Header Signature: "); 5826414dc6dSKonstantin Porotchkin if (verify_rsa_signature(sec_ext->csk_keys[opts.key_index], 5836414dc6dSKonstantin Porotchkin MAX_RSA_DER_BYTE_LEN, 5846414dc6dSKonstantin Porotchkin (uint8_t *)main_hdr, 5856414dc6dSKonstantin Porotchkin main_hdr->prolog_size, 5866414dc6dSKonstantin Porotchkin "Header Signature: ", 5876414dc6dSKonstantin Porotchkin signature) != 0) { 5886414dc6dSKonstantin Porotchkin fprintf(stdout, "ERROR\n"); 5896414dc6dSKonstantin Porotchkin goto ver_error; 5906414dc6dSKonstantin Porotchkin } 5916414dc6dSKonstantin Porotchkin fprintf(stdout, "OK\n"); 5926414dc6dSKonstantin Porotchkin } else { 5936414dc6dSKonstantin Porotchkin fprintf(stdout, "SKIP Image and Header Signatures"); 5946414dc6dSKonstantin Porotchkin fprintf(stdout, " check (undefined key index)\n"); 5956414dc6dSKonstantin Porotchkin } 5966414dc6dSKonstantin Porotchkin 5976414dc6dSKonstantin Porotchkin rval = 0; 5986414dc6dSKonstantin Porotchkin 5996414dc6dSKonstantin Porotchkin ver_error: 6006414dc6dSKonstantin Porotchkin memcpy(sec_ext->header_sign, signature, RSA_SIGN_BYTE_LEN); 6016414dc6dSKonstantin Porotchkin return rval; 6026414dc6dSKonstantin Porotchkin } 6036414dc6dSKonstantin Porotchkin 6046414dc6dSKonstantin Porotchkin /******************************************************************************* 6056414dc6dSKonstantin Porotchkin * verify_and_copy_file_name_entry 6066414dc6dSKonstantin Porotchkin * INPUT: 6076414dc6dSKonstantin Porotchkin * element_name 6086414dc6dSKonstantin Porotchkin * element 6096414dc6dSKonstantin Porotchkin * OUTPUT: 6106414dc6dSKonstantin Porotchkin * copy_to 6116414dc6dSKonstantin Porotchkin * RETURN: 6126414dc6dSKonstantin Porotchkin * 0 on success 6136414dc6dSKonstantin Porotchkin */ 6146414dc6dSKonstantin Porotchkin int verify_and_copy_file_name_entry(const char *element_name, 6156414dc6dSKonstantin Porotchkin const char *element, char *copy_to) 6166414dc6dSKonstantin Porotchkin { 6176414dc6dSKonstantin Porotchkin int element_length = strlen(element); 6186414dc6dSKonstantin Porotchkin 6196414dc6dSKonstantin Porotchkin if (element_length >= MAX_FILENAME) { 6206414dc6dSKonstantin Porotchkin fprintf(stderr, "The file name %s for %s is too long (%d). ", 6216414dc6dSKonstantin Porotchkin element, element_name, element_length); 6226414dc6dSKonstantin Porotchkin fprintf(stderr, "Maximum allowed %d characters!\n", 6236414dc6dSKonstantin Porotchkin MAX_FILENAME); 6246414dc6dSKonstantin Porotchkin return -1; 6256414dc6dSKonstantin Porotchkin } else if (element_length == 0) { 6266414dc6dSKonstantin Porotchkin fprintf(stderr, "The file name for %s is empty!\n", 6276414dc6dSKonstantin Porotchkin element_name); 6286414dc6dSKonstantin Porotchkin return -1; 6296414dc6dSKonstantin Porotchkin } 6306414dc6dSKonstantin Porotchkin memcpy(copy_to, element, element_length); 6316414dc6dSKonstantin Porotchkin 6326414dc6dSKonstantin Porotchkin return 0; 6336414dc6dSKonstantin Porotchkin } 6346414dc6dSKonstantin Porotchkin 6356414dc6dSKonstantin Porotchkin /******************************************************************************* 6366414dc6dSKonstantin Porotchkin * parse_sec_config_file 6376414dc6dSKonstantin Porotchkin * Read the secure boot configuration from a file 6386414dc6dSKonstantin Porotchkin * into internal structures 6396414dc6dSKonstantin Porotchkin * INPUT: 6406414dc6dSKonstantin Porotchkin * filename File name 6416414dc6dSKonstantin Porotchkin * OUTPUT: 6426414dc6dSKonstantin Porotchkin * none 6436414dc6dSKonstantin Porotchkin * RETURN: 6446414dc6dSKonstantin Porotchkin * 0 on success 6456414dc6dSKonstantin Porotchkin */ 6466414dc6dSKonstantin Porotchkin int parse_sec_config_file(char *filename) 6476414dc6dSKonstantin Porotchkin { 6486414dc6dSKonstantin Porotchkin config_t sec_cfg; 6496414dc6dSKonstantin Porotchkin int array_sz, element, rval = -1; 6506414dc6dSKonstantin Porotchkin const char *cfg_string; 6516414dc6dSKonstantin Porotchkin int32_t cfg_int32; 6526414dc6dSKonstantin Porotchkin const config_setting_t *csk_array, *control_array; 6536414dc6dSKonstantin Porotchkin sec_options *sec_opt = 0; 6546414dc6dSKonstantin Porotchkin 6556414dc6dSKonstantin Porotchkin config_init(&sec_cfg); 6566414dc6dSKonstantin Porotchkin 6576414dc6dSKonstantin Porotchkin if (config_read_file(&sec_cfg, filename) != CONFIG_TRUE) { 6586414dc6dSKonstantin Porotchkin fprintf(stderr, "Failed to read data from config file "); 6596414dc6dSKonstantin Porotchkin fprintf(stderr, "%s\n\t%s at line %d\n", 6606414dc6dSKonstantin Porotchkin filename, config_error_text(&sec_cfg), 6616414dc6dSKonstantin Porotchkin config_error_line(&sec_cfg)); 6626414dc6dSKonstantin Porotchkin goto exit_parse; 6636414dc6dSKonstantin Porotchkin } 6646414dc6dSKonstantin Porotchkin 6656414dc6dSKonstantin Porotchkin sec_opt = (sec_options *)calloc(sizeof(sec_options), 1); 6666414dc6dSKonstantin Porotchkin if (sec_opt == 0) { 6676414dc6dSKonstantin Porotchkin fprintf(stderr, 6686414dc6dSKonstantin Porotchkin "Cannot allocate memory for secure boot options!\n"); 6696414dc6dSKonstantin Porotchkin goto exit_parse; 6706414dc6dSKonstantin Porotchkin } 6716414dc6dSKonstantin Porotchkin 6726414dc6dSKonstantin Porotchkin /* KAK file name */ 6736414dc6dSKonstantin Porotchkin if (config_lookup_string(&sec_cfg, "kak_key_file", 6746414dc6dSKonstantin Porotchkin &cfg_string) != CONFIG_TRUE) { 6756414dc6dSKonstantin Porotchkin fprintf(stderr, "The \"kak_key_file\" undefined!\n"); 6766414dc6dSKonstantin Porotchkin goto exit_parse; 6776414dc6dSKonstantin Porotchkin } 6786414dc6dSKonstantin Porotchkin if (verify_and_copy_file_name_entry("kak_key_file", 6796414dc6dSKonstantin Porotchkin cfg_string, sec_opt->kak_key_file)) 6806414dc6dSKonstantin Porotchkin goto exit_parse; 6816414dc6dSKonstantin Porotchkin 6826414dc6dSKonstantin Porotchkin 6836414dc6dSKonstantin Porotchkin /* AES file name - can be empty/undefined */ 6846414dc6dSKonstantin Porotchkin if (config_lookup_string(&sec_cfg, "aes_key_file", 6856414dc6dSKonstantin Porotchkin &cfg_string) == CONFIG_TRUE) { 6866414dc6dSKonstantin Porotchkin if (verify_and_copy_file_name_entry("aes_key_file", 6876414dc6dSKonstantin Porotchkin cfg_string, 6886414dc6dSKonstantin Porotchkin sec_opt->aes_key_file)) 6896414dc6dSKonstantin Porotchkin goto exit_parse; 6906414dc6dSKonstantin Porotchkin } 6916414dc6dSKonstantin Porotchkin 6926414dc6dSKonstantin Porotchkin /* CSK file names array */ 6936414dc6dSKonstantin Porotchkin csk_array = config_lookup(&sec_cfg, "csk_key_file"); 6946414dc6dSKonstantin Porotchkin if (csk_array == NULL) { 6956414dc6dSKonstantin Porotchkin fprintf(stderr, "The \"csk_key_file\" undefined!\n"); 6966414dc6dSKonstantin Porotchkin goto exit_parse; 6976414dc6dSKonstantin Porotchkin } 6986414dc6dSKonstantin Porotchkin array_sz = config_setting_length(csk_array); 6996414dc6dSKonstantin Porotchkin if (array_sz > CSK_ARR_SZ) { 7006414dc6dSKonstantin Porotchkin fprintf(stderr, "The \"csk_key_file\" array is too big! "); 7016414dc6dSKonstantin Porotchkin fprintf(stderr, "Only first %d elements will be used\n", 7026414dc6dSKonstantin Porotchkin CSK_ARR_SZ); 7036414dc6dSKonstantin Porotchkin array_sz = CSK_ARR_SZ; 7046414dc6dSKonstantin Porotchkin } else if (array_sz == 0) { 7056414dc6dSKonstantin Porotchkin fprintf(stderr, "The \"csk_key_file\" array is empty!\n"); 7066414dc6dSKonstantin Porotchkin goto exit_parse; 7076414dc6dSKonstantin Porotchkin } 7086414dc6dSKonstantin Porotchkin 7096414dc6dSKonstantin Porotchkin for (element = 0; element < array_sz; element++) { 7106414dc6dSKonstantin Porotchkin cfg_string = config_setting_get_string_elem(csk_array, element); 7116414dc6dSKonstantin Porotchkin if (verify_and_copy_file_name_entry( 7126414dc6dSKonstantin Porotchkin "csk_key_file", cfg_string, 7136414dc6dSKonstantin Porotchkin sec_opt->csk_key_file[element])) { 7146414dc6dSKonstantin Porotchkin fprintf(stderr, "Bad csk_key_file[%d] entry!\n", 7156414dc6dSKonstantin Porotchkin element); 7166414dc6dSKonstantin Porotchkin goto exit_parse; 7176414dc6dSKonstantin Porotchkin } 7186414dc6dSKonstantin Porotchkin } 7196414dc6dSKonstantin Porotchkin 7206414dc6dSKonstantin Porotchkin /* JTAG options */ 7216414dc6dSKonstantin Porotchkin if (config_lookup_bool(&sec_cfg, "jtag.enable", 7226414dc6dSKonstantin Porotchkin &cfg_int32) != CONFIG_TRUE) { 7236414dc6dSKonstantin Porotchkin fprintf(stderr, "Error obtaining \"jtag.enable\" element. "); 7246414dc6dSKonstantin Porotchkin fprintf(stderr, "Using default - FALSE\n"); 7256414dc6dSKonstantin Porotchkin cfg_int32 = 0; 7266414dc6dSKonstantin Porotchkin } 7276414dc6dSKonstantin Porotchkin sec_opt->jtag_enable = cfg_int32; 7286414dc6dSKonstantin Porotchkin 7296414dc6dSKonstantin Porotchkin if (config_lookup_int(&sec_cfg, "jtag.delay", 7306414dc6dSKonstantin Porotchkin &cfg_int32) != CONFIG_TRUE) { 7316414dc6dSKonstantin Porotchkin fprintf(stderr, "Error obtaining \"jtag.delay\" element. "); 7326414dc6dSKonstantin Porotchkin fprintf(stderr, "Using default - 0us\n"); 7336414dc6dSKonstantin Porotchkin cfg_int32 = 0; 7346414dc6dSKonstantin Porotchkin } 7356414dc6dSKonstantin Porotchkin sec_opt->jtag_delay = cfg_int32; 7366414dc6dSKonstantin Porotchkin 7376414dc6dSKonstantin Porotchkin /* eFUSE option */ 7386414dc6dSKonstantin Porotchkin if (config_lookup_bool(&sec_cfg, "efuse_disable", 7396414dc6dSKonstantin Porotchkin &cfg_int32) != CONFIG_TRUE) { 7406414dc6dSKonstantin Porotchkin fprintf(stderr, "Error obtaining \"efuse_disable\" element. "); 7416414dc6dSKonstantin Porotchkin fprintf(stderr, "Using default - TRUE\n"); 7426414dc6dSKonstantin Porotchkin cfg_int32 = 1; 7436414dc6dSKonstantin Porotchkin } 7446414dc6dSKonstantin Porotchkin sec_opt->efuse_disable = cfg_int32; 7456414dc6dSKonstantin Porotchkin 7466414dc6dSKonstantin Porotchkin /* Box ID option */ 7476414dc6dSKonstantin Porotchkin if (config_lookup_int(&sec_cfg, "box_id", &cfg_int32) != CONFIG_TRUE) { 7486414dc6dSKonstantin Porotchkin fprintf(stderr, "Error obtaining \"box_id\" element. "); 7496414dc6dSKonstantin Porotchkin fprintf(stderr, "Using default - 0x0\n"); 7506414dc6dSKonstantin Porotchkin cfg_int32 = 0; 7516414dc6dSKonstantin Porotchkin } 7526414dc6dSKonstantin Porotchkin sec_opt->box_id = cfg_int32; 7536414dc6dSKonstantin Porotchkin 7546414dc6dSKonstantin Porotchkin /* Flash ID option */ 7556414dc6dSKonstantin Porotchkin if (config_lookup_int(&sec_cfg, "flash_id", 7566414dc6dSKonstantin Porotchkin &cfg_int32) != CONFIG_TRUE) { 7576414dc6dSKonstantin Porotchkin fprintf(stderr, "Error obtaining \"flash_id\" element. "); 7586414dc6dSKonstantin Porotchkin fprintf(stderr, "Using default - 0x0\n"); 7596414dc6dSKonstantin Porotchkin cfg_int32 = 0; 7606414dc6dSKonstantin Porotchkin } 7616414dc6dSKonstantin Porotchkin sec_opt->flash_id = cfg_int32; 7626414dc6dSKonstantin Porotchkin 7636414dc6dSKonstantin Porotchkin /* CSK index option */ 7646414dc6dSKonstantin Porotchkin if (config_lookup_int(&sec_cfg, "csk_key_index", 7656414dc6dSKonstantin Porotchkin &cfg_int32) != CONFIG_TRUE) { 7666414dc6dSKonstantin Porotchkin fprintf(stderr, "Error obtaining \"flash_id\" element. "); 7676414dc6dSKonstantin Porotchkin fprintf(stderr, "Using default - 0x0\n"); 7686414dc6dSKonstantin Porotchkin cfg_int32 = 0; 7696414dc6dSKonstantin Porotchkin } 7706414dc6dSKonstantin Porotchkin sec_opt->csk_index = cfg_int32; 7716414dc6dSKonstantin Porotchkin 7726414dc6dSKonstantin Porotchkin /* Secure boot control array */ 7736414dc6dSKonstantin Porotchkin control_array = config_lookup(&sec_cfg, "control"); 7746414dc6dSKonstantin Porotchkin if (control_array != NULL) { 7756414dc6dSKonstantin Porotchkin array_sz = config_setting_length(control_array); 7766414dc6dSKonstantin Porotchkin if (array_sz == 0) 7776414dc6dSKonstantin Porotchkin fprintf(stderr, "The \"control\" array is empty!\n"); 7786414dc6dSKonstantin Porotchkin } else { 7796414dc6dSKonstantin Porotchkin fprintf(stderr, "The \"control\" is undefined!\n"); 7806414dc6dSKonstantin Porotchkin array_sz = 0; 7816414dc6dSKonstantin Porotchkin } 7826414dc6dSKonstantin Porotchkin 7836414dc6dSKonstantin Porotchkin for (element = 0; element < CP_CTRL_EL_ARRAY_SZ; element++) { 7846414dc6dSKonstantin Porotchkin sec_opt->cp_ctrl_arr[element] = 7856414dc6dSKonstantin Porotchkin config_setting_get_int_elem(control_array, element * 2); 7866414dc6dSKonstantin Porotchkin sec_opt->cp_efuse_arr[element] = 7876414dc6dSKonstantin Porotchkin config_setting_get_int_elem(control_array, 7886414dc6dSKonstantin Porotchkin element * 2 + 1); 7896414dc6dSKonstantin Porotchkin } 7906414dc6dSKonstantin Porotchkin 7916414dc6dSKonstantin Porotchkin opts.sec_opts = sec_opt; 7926414dc6dSKonstantin Porotchkin rval = 0; 7936414dc6dSKonstantin Porotchkin 7946414dc6dSKonstantin Porotchkin exit_parse: 7956414dc6dSKonstantin Porotchkin config_destroy(&sec_cfg); 7966414dc6dSKonstantin Porotchkin if (sec_opt && (rval != 0)) 7976414dc6dSKonstantin Porotchkin free(sec_opt); 7986414dc6dSKonstantin Porotchkin return rval; 7996414dc6dSKonstantin Porotchkin } /* end of parse_sec_config_file */ 8006414dc6dSKonstantin Porotchkin 8016414dc6dSKonstantin Porotchkin int format_sec_ext(char *filename, FILE *out_fd) 8026414dc6dSKonstantin Porotchkin { 8036414dc6dSKonstantin Porotchkin ext_header_t header; 8046414dc6dSKonstantin Porotchkin sec_entry_t sec_ext; 8056414dc6dSKonstantin Porotchkin int index; 8066414dc6dSKonstantin Porotchkin int written; 8076414dc6dSKonstantin Porotchkin 8086414dc6dSKonstantin Porotchkin #define DER_BUF_SZ 1600 8096414dc6dSKonstantin Porotchkin 8106414dc6dSKonstantin Porotchkin /* First, parse the configuration file */ 8116414dc6dSKonstantin Porotchkin if (parse_sec_config_file(filename)) { 8126414dc6dSKonstantin Porotchkin fprintf(stderr, 8136414dc6dSKonstantin Porotchkin "failed parsing configuration file %s\n", filename); 8146414dc6dSKonstantin Porotchkin return 1; 8156414dc6dSKonstantin Porotchkin } 8166414dc6dSKonstantin Porotchkin 8176414dc6dSKonstantin Porotchkin /* Everything except signatures can be created at this stage */ 8186414dc6dSKonstantin Porotchkin header.type = EXT_TYPE_SECURITY; 8196414dc6dSKonstantin Porotchkin header.offset = 0; 8206414dc6dSKonstantin Porotchkin header.size = sizeof(sec_entry_t); 8216414dc6dSKonstantin Porotchkin header.reserved = 0; 8226414dc6dSKonstantin Porotchkin 8236414dc6dSKonstantin Porotchkin /* Bring up RSA context and read private keys from their files */ 8246414dc6dSKonstantin Porotchkin for (index = 0; index < (CSK_ARR_SZ + 1); index++) { 8256414dc6dSKonstantin Porotchkin /* for every private key file */ 8266414dc6dSKonstantin Porotchkin mbedtls_pk_context *pk_ctx = (index == CSK_ARR_SZ) ? 8276414dc6dSKonstantin Porotchkin &opts.sec_opts->kak_pk : 8286414dc6dSKonstantin Porotchkin &opts.sec_opts->csk_pk[index]; 8296414dc6dSKonstantin Porotchkin char *fname = (index == CSK_ARR_SZ) ? 8306414dc6dSKonstantin Porotchkin opts.sec_opts->kak_key_file : 8316414dc6dSKonstantin Porotchkin opts.sec_opts->csk_key_file[index]; 8326414dc6dSKonstantin Porotchkin uint8_t *out_der_key = (index == CSK_ARR_SZ) ? 8336414dc6dSKonstantin Porotchkin sec_ext.kak_key : 8346414dc6dSKonstantin Porotchkin sec_ext.csk_keys[index]; 8356414dc6dSKonstantin Porotchkin size_t output_len; 8366414dc6dSKonstantin Porotchkin unsigned char output_buf[DER_BUF_SZ]; 8376414dc6dSKonstantin Porotchkin unsigned char *der_buf_start; 8386414dc6dSKonstantin Porotchkin 8396414dc6dSKonstantin Porotchkin /* Handle invalid/reserved file names */ 8406414dc6dSKonstantin Porotchkin if (strncmp(CSK_ARR_EMPTY_FILE, fname, 8416414dc6dSKonstantin Porotchkin strlen(CSK_ARR_EMPTY_FILE)) == 0) { 8426414dc6dSKonstantin Porotchkin if (opts.sec_opts->csk_index == index) { 8436414dc6dSKonstantin Porotchkin fprintf(stderr, 8446414dc6dSKonstantin Porotchkin "CSK file with index %d cannot be %s\n", 8456414dc6dSKonstantin Porotchkin index, CSK_ARR_EMPTY_FILE); 8466414dc6dSKonstantin Porotchkin return 1; 8476414dc6dSKonstantin Porotchkin } else if (index == CSK_ARR_SZ) { 8486414dc6dSKonstantin Porotchkin fprintf(stderr, "KAK file name cannot be %s\n", 8496414dc6dSKonstantin Porotchkin CSK_ARR_EMPTY_FILE); 8506414dc6dSKonstantin Porotchkin return 1; 8516414dc6dSKonstantin Porotchkin } 8526414dc6dSKonstantin Porotchkin /* this key will be empty in CSK array */ 8536414dc6dSKonstantin Porotchkin continue; 8546414dc6dSKonstantin Porotchkin } 8556414dc6dSKonstantin Porotchkin 8566414dc6dSKonstantin Porotchkin mbedtls_pk_init(pk_ctx); 8576414dc6dSKonstantin Porotchkin /* Read the private RSA key into the context 8586414dc6dSKonstantin Porotchkin * and verify it (no password) 8596414dc6dSKonstantin Porotchkin */ 8606414dc6dSKonstantin Porotchkin if (mbedtls_pk_parse_keyfile(pk_ctx, fname, "") != 0) { 8616414dc6dSKonstantin Porotchkin fprintf(stderr, 8626414dc6dSKonstantin Porotchkin "Cannot read RSA private key file %s\n", fname); 8636414dc6dSKonstantin Porotchkin return 1; 8646414dc6dSKonstantin Porotchkin } 8656414dc6dSKonstantin Porotchkin 8666414dc6dSKonstantin Porotchkin /* Create a public key out of private one 8676414dc6dSKonstantin Porotchkin * and store it in DER format 8686414dc6dSKonstantin Porotchkin */ 8696414dc6dSKonstantin Porotchkin output_len = mbedtls_pk_write_pubkey_der(pk_ctx, 8706414dc6dSKonstantin Porotchkin output_buf, 8716414dc6dSKonstantin Porotchkin DER_BUF_SZ); 8726414dc6dSKonstantin Porotchkin if (output_len < 0) { 8736414dc6dSKonstantin Porotchkin fprintf(stderr, 8746414dc6dSKonstantin Porotchkin "Failed to create DER coded PUB key (%s)\n", 8756414dc6dSKonstantin Porotchkin fname); 8766414dc6dSKonstantin Porotchkin return 1; 8776414dc6dSKonstantin Porotchkin } 878a79df348SKonstantin Porotchkin 8796414dc6dSKonstantin Porotchkin /* Data in the output buffer is aligned to the buffer end */ 8806414dc6dSKonstantin Porotchkin der_buf_start = output_buf + sizeof(output_buf) - output_len; 8816414dc6dSKonstantin Porotchkin /* In the header DER data is aligned 8826414dc6dSKonstantin Porotchkin * to the start of appropriate field 8836414dc6dSKonstantin Porotchkin */ 884a79df348SKonstantin Porotchkin bzero(out_der_key, MAX_RSA_DER_BYTE_LEN); 8856414dc6dSKonstantin Porotchkin memcpy(out_der_key, der_buf_start, output_len); 8866414dc6dSKonstantin Porotchkin 8876414dc6dSKonstantin Porotchkin } /* for every private key file */ 8886414dc6dSKonstantin Porotchkin 8896414dc6dSKonstantin Porotchkin /* The CSK block signature can be created here */ 8906414dc6dSKonstantin Porotchkin if (create_rsa_signature(&opts.sec_opts->kak_pk, 8916414dc6dSKonstantin Porotchkin &sec_ext.csk_keys[0][0], 8926414dc6dSKonstantin Porotchkin sizeof(sec_ext.csk_keys), 8936414dc6dSKonstantin Porotchkin opts.sec_opts->csk_key_file[ 8946414dc6dSKonstantin Porotchkin opts.sec_opts->csk_index], 8956414dc6dSKonstantin Porotchkin sec_ext.csk_sign) != 0) { 8966414dc6dSKonstantin Porotchkin fprintf(stderr, "Failed to sign CSK keys block!\n"); 8976414dc6dSKonstantin Porotchkin return 1; 8986414dc6dSKonstantin Porotchkin } 899a79df348SKonstantin Porotchkin 9006414dc6dSKonstantin Porotchkin /* Check that everything is correct */ 901a79df348SKonstantin Porotchkin if (verify_rsa_signature(sec_ext.kak_key, 902a79df348SKonstantin Porotchkin MAX_RSA_DER_BYTE_LEN, 9036414dc6dSKonstantin Porotchkin &sec_ext.csk_keys[0][0], 9046414dc6dSKonstantin Porotchkin sizeof(sec_ext.csk_keys), 9056414dc6dSKonstantin Porotchkin opts.sec_opts->kak_key_file, 9066414dc6dSKonstantin Porotchkin sec_ext.csk_sign) != 0) { 9076414dc6dSKonstantin Porotchkin fprintf(stderr, "Failed to verify CSK keys block signature!\n"); 9086414dc6dSKonstantin Porotchkin return 1; 9096414dc6dSKonstantin Porotchkin } 9106414dc6dSKonstantin Porotchkin 9116414dc6dSKonstantin Porotchkin /* AES encryption stuff */ 9126414dc6dSKonstantin Porotchkin if (strlen(opts.sec_opts->aes_key_file) != 0) { 9136414dc6dSKonstantin Porotchkin FILE *in_fd; 9146414dc6dSKonstantin Porotchkin 9156414dc6dSKonstantin Porotchkin in_fd = fopen(opts.sec_opts->aes_key_file, "rb"); 9166414dc6dSKonstantin Porotchkin if (in_fd == NULL) { 9176414dc6dSKonstantin Porotchkin fprintf(stderr, "Failed to open AES key file %s\n", 9186414dc6dSKonstantin Porotchkin opts.sec_opts->aes_key_file); 9196414dc6dSKonstantin Porotchkin return 1; 9206414dc6dSKonstantin Porotchkin } 9216414dc6dSKonstantin Porotchkin 9226414dc6dSKonstantin Porotchkin /* Read the AES key in ASCII format byte by byte */ 9236414dc6dSKonstantin Porotchkin for (index = 0; index < AES_KEY_BYTE_LEN; index++) { 9246414dc6dSKonstantin Porotchkin if (fscanf(in_fd, "%02hhx", 9256414dc6dSKonstantin Porotchkin opts.sec_opts->aes_key + index) != 1) { 9266414dc6dSKonstantin Porotchkin fprintf(stderr, 9276414dc6dSKonstantin Porotchkin "Failed to read AES key byte %d ", 9286414dc6dSKonstantin Porotchkin index); 9296414dc6dSKonstantin Porotchkin fprintf(stderr, 9306414dc6dSKonstantin Porotchkin "from file %s\n", 9316414dc6dSKonstantin Porotchkin opts.sec_opts->aes_key_file); 9326414dc6dSKonstantin Porotchkin fclose(in_fd); 9336414dc6dSKonstantin Porotchkin return 1; 9346414dc6dSKonstantin Porotchkin } 9356414dc6dSKonstantin Porotchkin } 9366414dc6dSKonstantin Porotchkin fclose(in_fd); 9376414dc6dSKonstantin Porotchkin sec_ext.encrypt_en = 1; 9386414dc6dSKonstantin Porotchkin } else { 9396414dc6dSKonstantin Porotchkin sec_ext.encrypt_en = 0; 9406414dc6dSKonstantin Porotchkin } 9416414dc6dSKonstantin Porotchkin 9426414dc6dSKonstantin Porotchkin /* Fill the rest of the trusted boot extension fields */ 9436414dc6dSKonstantin Porotchkin sec_ext.box_id = opts.sec_opts->box_id; 9446414dc6dSKonstantin Porotchkin sec_ext.flash_id = opts.sec_opts->flash_id; 9456414dc6dSKonstantin Porotchkin sec_ext.efuse_dis = opts.sec_opts->efuse_disable; 9466414dc6dSKonstantin Porotchkin sec_ext.jtag_delay = opts.sec_opts->jtag_delay; 9476414dc6dSKonstantin Porotchkin sec_ext.jtag_en = opts.sec_opts->jtag_enable; 9486414dc6dSKonstantin Porotchkin 9496414dc6dSKonstantin Porotchkin memcpy(sec_ext.cp_ctrl_arr, 9506414dc6dSKonstantin Porotchkin opts.sec_opts->cp_ctrl_arr, 9516414dc6dSKonstantin Porotchkin sizeof(uint32_t) * CP_CTRL_EL_ARRAY_SZ); 9526414dc6dSKonstantin Porotchkin memcpy(sec_ext.cp_efuse_arr, 9536414dc6dSKonstantin Porotchkin opts.sec_opts->cp_efuse_arr, 9546414dc6dSKonstantin Porotchkin sizeof(uint32_t) * CP_CTRL_EL_ARRAY_SZ); 9556414dc6dSKonstantin Porotchkin 9566414dc6dSKonstantin Porotchkin /* Write the resulting extension to file 9576414dc6dSKonstantin Porotchkin * (image and header signature fields are still empty) 9586414dc6dSKonstantin Porotchkin */ 9596414dc6dSKonstantin Porotchkin 9606414dc6dSKonstantin Porotchkin /* Write extension header */ 9616414dc6dSKonstantin Porotchkin written = fwrite(&header, sizeof(ext_header_t), 1, out_fd); 9626414dc6dSKonstantin Porotchkin if (written != 1) { 9636414dc6dSKonstantin Porotchkin fprintf(stderr, 9646414dc6dSKonstantin Porotchkin "Failed to write SEC extension header to the file\n"); 9656414dc6dSKonstantin Porotchkin return 1; 9666414dc6dSKonstantin Porotchkin } 9676414dc6dSKonstantin Porotchkin /* Write extension body */ 9686414dc6dSKonstantin Porotchkin written = fwrite(&sec_ext, sizeof(sec_entry_t), 1, out_fd); 9696414dc6dSKonstantin Porotchkin if (written != 1) { 9706414dc6dSKonstantin Porotchkin fprintf(stderr, 9716414dc6dSKonstantin Porotchkin "Failed to write SEC extension body to the file\n"); 9726414dc6dSKonstantin Porotchkin return 1; 9736414dc6dSKonstantin Porotchkin } 9746414dc6dSKonstantin Porotchkin 9756414dc6dSKonstantin Porotchkin return 0; 9766414dc6dSKonstantin Porotchkin } 9776414dc6dSKonstantin Porotchkin 9786414dc6dSKonstantin Porotchkin /******************************************************************************* 9796414dc6dSKonstantin Porotchkin * finalize_secure_ext 9806414dc6dSKonstantin Porotchkin * Make final changes to secure extension - calculate image and header 9816414dc6dSKonstantin Porotchkin * signatures and encrypt the image if needed. 9826414dc6dSKonstantin Porotchkin * The main header checksum and image size fields updated accordingly 9836414dc6dSKonstantin Porotchkin * INPUT: 9846414dc6dSKonstantin Porotchkin * header Main header 9856414dc6dSKonstantin Porotchkin * prolog_buf the entire prolog buffer 9866414dc6dSKonstantin Porotchkin * prolog_size prolog buffer length 9876414dc6dSKonstantin Porotchkin * image_buf buffer containing the input binary image 9886414dc6dSKonstantin Porotchkin * image_size image buffer size. 9896414dc6dSKonstantin Porotchkin * OUTPUT: 9906414dc6dSKonstantin Porotchkin * none 9916414dc6dSKonstantin Porotchkin * RETURN: 9926414dc6dSKonstantin Porotchkin * 0 on success 9936414dc6dSKonstantin Porotchkin */ 9946414dc6dSKonstantin Porotchkin int finalize_secure_ext(header_t *header, 9956414dc6dSKonstantin Porotchkin uint8_t *prolog_buf, uint32_t prolog_size, 9966414dc6dSKonstantin Porotchkin uint8_t *image_buf, int image_size) 9976414dc6dSKonstantin Porotchkin { 9986414dc6dSKonstantin Porotchkin int cur_ext, offset; 9996414dc6dSKonstantin Porotchkin uint8_t *final_image = image_buf; 10006414dc6dSKonstantin Porotchkin uint32_t final_image_sz = image_size; 10016414dc6dSKonstantin Porotchkin uint8_t hdr_sign[RSA_SIGN_BYTE_LEN]; 10026414dc6dSKonstantin Porotchkin sec_entry_t *sec_ext = 0; 10036414dc6dSKonstantin Porotchkin 10046414dc6dSKonstantin Porotchkin /* Find the Trusted Boot Header between available extensions */ 10056414dc6dSKonstantin Porotchkin for (cur_ext = 0, offset = sizeof(header_t); 10066414dc6dSKonstantin Porotchkin cur_ext < header->ext_count; cur_ext++) { 10076414dc6dSKonstantin Porotchkin ext_header_t *ext_hdr = (ext_header_t *)(prolog_buf + offset); 10086414dc6dSKonstantin Porotchkin 10096414dc6dSKonstantin Porotchkin if (ext_hdr->type == EXT_TYPE_SECURITY) { 10106414dc6dSKonstantin Porotchkin sec_ext = (sec_entry_t *)(prolog_buf + offset + 10116414dc6dSKonstantin Porotchkin sizeof(ext_header_t) + ext_hdr->offset); 10126414dc6dSKonstantin Porotchkin break; 10136414dc6dSKonstantin Porotchkin } 10146414dc6dSKonstantin Porotchkin 10156414dc6dSKonstantin Porotchkin offset += sizeof(ext_header_t); 10166414dc6dSKonstantin Porotchkin /* If offset is Zero, the extension follows its header */ 10176414dc6dSKonstantin Porotchkin if (ext_hdr->offset == 0) 10186414dc6dSKonstantin Porotchkin offset += ext_hdr->size; 10196414dc6dSKonstantin Porotchkin } 10206414dc6dSKonstantin Porotchkin 10216414dc6dSKonstantin Porotchkin if (sec_ext == 0) { 10226414dc6dSKonstantin Porotchkin fprintf(stderr, "Error: No Trusted Boot extension found!\n"); 10236414dc6dSKonstantin Porotchkin return -1; 10246414dc6dSKonstantin Porotchkin } 10256414dc6dSKonstantin Porotchkin 10266414dc6dSKonstantin Porotchkin if (sec_ext->encrypt_en) { 10276414dc6dSKonstantin Porotchkin /* Encrypt the image if needed */ 10286414dc6dSKonstantin Porotchkin fprintf(stdout, "Encrypting the image...\n"); 10296414dc6dSKonstantin Porotchkin 10306414dc6dSKonstantin Porotchkin if (image_encrypt(image_buf, image_size) != 0) { 10316414dc6dSKonstantin Porotchkin fprintf(stderr, "Failed to encrypt the image!\n"); 10326414dc6dSKonstantin Porotchkin return -1; 10336414dc6dSKonstantin Porotchkin } 10346414dc6dSKonstantin Porotchkin 10356414dc6dSKonstantin Porotchkin /* Image size and checksum should be updated after encryption. 10366414dc6dSKonstantin Porotchkin * This way the image could be verified by the BootROM 10376414dc6dSKonstantin Porotchkin * before decryption. 10386414dc6dSKonstantin Porotchkin */ 10396414dc6dSKonstantin Porotchkin final_image = opts.sec_opts->encrypted_image; 10406414dc6dSKonstantin Porotchkin final_image_sz = opts.sec_opts->enc_image_sz; 10416414dc6dSKonstantin Porotchkin 10426414dc6dSKonstantin Porotchkin header->boot_image_size = final_image_sz; 10436414dc6dSKonstantin Porotchkin header->boot_image_checksum = 10446414dc6dSKonstantin Porotchkin checksum32((uint32_t *)final_image, final_image_sz); 10456414dc6dSKonstantin Porotchkin } /* AES encryption */ 10466414dc6dSKonstantin Porotchkin 10476414dc6dSKonstantin Porotchkin /* Create the image signature first, since it will be later 10486414dc6dSKonstantin Porotchkin * signed along with the header signature 10496414dc6dSKonstantin Porotchkin */ 10506414dc6dSKonstantin Porotchkin if (create_rsa_signature(&opts.sec_opts->csk_pk[ 10516414dc6dSKonstantin Porotchkin opts.sec_opts->csk_index], 10526414dc6dSKonstantin Porotchkin final_image, final_image_sz, 10536414dc6dSKonstantin Porotchkin opts.sec_opts->csk_key_file[ 10546414dc6dSKonstantin Porotchkin opts.sec_opts->csk_index], 10556414dc6dSKonstantin Porotchkin sec_ext->image_sign) != 0) { 10566414dc6dSKonstantin Porotchkin fprintf(stderr, "Failed to sign image!\n"); 10576414dc6dSKonstantin Porotchkin return -1; 10586414dc6dSKonstantin Porotchkin } 10596414dc6dSKonstantin Porotchkin /* Check that the image signature is correct */ 10606414dc6dSKonstantin Porotchkin if (verify_rsa_signature(sec_ext->csk_keys[opts.sec_opts->csk_index], 10616414dc6dSKonstantin Porotchkin MAX_RSA_DER_BYTE_LEN, 10626414dc6dSKonstantin Porotchkin final_image, final_image_sz, 10636414dc6dSKonstantin Porotchkin opts.sec_opts->csk_key_file[ 10646414dc6dSKonstantin Porotchkin opts.sec_opts->csk_index], 10656414dc6dSKonstantin Porotchkin sec_ext->image_sign) != 0) { 10666414dc6dSKonstantin Porotchkin fprintf(stderr, "Failed to verify image signature!\n"); 10676414dc6dSKonstantin Porotchkin return -1; 10686414dc6dSKonstantin Porotchkin } 10696414dc6dSKonstantin Porotchkin 10706414dc6dSKonstantin Porotchkin /* Sign the headers and all the extensions block 10716414dc6dSKonstantin Porotchkin * when the header signature field is empty 10726414dc6dSKonstantin Porotchkin */ 10736414dc6dSKonstantin Porotchkin if (create_rsa_signature(&opts.sec_opts->csk_pk[ 10746414dc6dSKonstantin Porotchkin opts.sec_opts->csk_index], 10756414dc6dSKonstantin Porotchkin prolog_buf, prolog_size, 10766414dc6dSKonstantin Porotchkin opts.sec_opts->csk_key_file[ 10776414dc6dSKonstantin Porotchkin opts.sec_opts->csk_index], 10786414dc6dSKonstantin Porotchkin hdr_sign) != 0) { 10796414dc6dSKonstantin Porotchkin fprintf(stderr, "Failed to sign header!\n"); 10806414dc6dSKonstantin Porotchkin return -1; 10816414dc6dSKonstantin Porotchkin } 10826414dc6dSKonstantin Porotchkin /* Check that the header signature is correct */ 10836414dc6dSKonstantin Porotchkin if (verify_rsa_signature(sec_ext->csk_keys[opts.sec_opts->csk_index], 10846414dc6dSKonstantin Porotchkin MAX_RSA_DER_BYTE_LEN, 10856414dc6dSKonstantin Porotchkin prolog_buf, prolog_size, 10866414dc6dSKonstantin Porotchkin opts.sec_opts->csk_key_file[ 10876414dc6dSKonstantin Porotchkin opts.sec_opts->csk_index], 10886414dc6dSKonstantin Porotchkin hdr_sign) != 0) { 10896414dc6dSKonstantin Porotchkin fprintf(stderr, "Failed to verify header signature!\n"); 10906414dc6dSKonstantin Porotchkin return -1; 10916414dc6dSKonstantin Porotchkin } 10926414dc6dSKonstantin Porotchkin 10936414dc6dSKonstantin Porotchkin /* Finally, copy the header signature into the trusted boot extension */ 10946414dc6dSKonstantin Porotchkin memcpy(sec_ext->header_sign, hdr_sign, RSA_SIGN_BYTE_LEN); 10956414dc6dSKonstantin Porotchkin 10966414dc6dSKonstantin Porotchkin return 0; 10976414dc6dSKonstantin Porotchkin } 10986414dc6dSKonstantin Porotchkin 10996414dc6dSKonstantin Porotchkin #endif /* CONFIG_MVEBU_SECURE_BOOT */ 11006414dc6dSKonstantin Porotchkin 11016414dc6dSKonstantin Porotchkin 11026414dc6dSKonstantin Porotchkin #define FMT_HEX 0 11036414dc6dSKonstantin Porotchkin #define FMT_DEC 1 11046414dc6dSKonstantin Porotchkin #define FMT_BIN 2 11056414dc6dSKonstantin Porotchkin #define FMT_NONE 3 11066414dc6dSKonstantin Porotchkin 11076414dc6dSKonstantin Porotchkin void do_print_field(unsigned int value, char *name, 11086414dc6dSKonstantin Porotchkin int start, int size, int format) 11096414dc6dSKonstantin Porotchkin { 11106414dc6dSKonstantin Porotchkin fprintf(stdout, "[0x%05x : 0x%05x] %-26s", 11116414dc6dSKonstantin Porotchkin start, start + size - 1, name); 11126414dc6dSKonstantin Porotchkin 11136414dc6dSKonstantin Porotchkin switch (format) { 11146414dc6dSKonstantin Porotchkin case FMT_HEX: 11156414dc6dSKonstantin Porotchkin printf("0x%x\n", value); 11166414dc6dSKonstantin Porotchkin break; 11176414dc6dSKonstantin Porotchkin case FMT_DEC: 11186414dc6dSKonstantin Porotchkin printf("%d\n", value); 11196414dc6dSKonstantin Porotchkin break; 11206414dc6dSKonstantin Porotchkin default: 11216414dc6dSKonstantin Porotchkin printf("\n"); 11226414dc6dSKonstantin Porotchkin break; 11236414dc6dSKonstantin Porotchkin } 11246414dc6dSKonstantin Porotchkin } 11256414dc6dSKonstantin Porotchkin 11266414dc6dSKonstantin Porotchkin #define print_field(st, type, field, hex, base) \ 11276414dc6dSKonstantin Porotchkin do_print_field((int)st->field, #field, \ 11286414dc6dSKonstantin Porotchkin base + offsetof(type, field), sizeof(st->field), hex) 11296414dc6dSKonstantin Porotchkin 11306414dc6dSKonstantin Porotchkin int print_header(uint8_t *buf, int base) 11316414dc6dSKonstantin Porotchkin { 11326414dc6dSKonstantin Porotchkin header_t *main_hdr; 11336414dc6dSKonstantin Porotchkin 11346414dc6dSKonstantin Porotchkin main_hdr = (header_t *)buf; 11356414dc6dSKonstantin Porotchkin 11366414dc6dSKonstantin Porotchkin fprintf(stdout, "########### Header ##############\n"); 11376414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, magic, FMT_HEX, base); 11386414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, prolog_size, FMT_DEC, base); 11396414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, prolog_checksum, FMT_HEX, base); 11406414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, boot_image_size, FMT_DEC, base); 11416414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, boot_image_checksum, FMT_HEX, base); 11426414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, rsrvd0, FMT_HEX, base); 11436414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, load_addr, FMT_HEX, base); 11446414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, exec_addr, FMT_HEX, base); 11456414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, uart_cfg, FMT_HEX, base); 11466414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, baudrate, FMT_HEX, base); 11476414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, ext_count, FMT_DEC, base); 11486414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, aux_flags, FMT_HEX, base); 11496414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, io_arg_0, FMT_HEX, base); 11506414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, io_arg_1, FMT_HEX, base); 11516414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, io_arg_2, FMT_HEX, base); 11526414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, io_arg_3, FMT_HEX, base); 11536414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, rsrvd1, FMT_HEX, base); 11546414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, rsrvd2, FMT_HEX, base); 11556414dc6dSKonstantin Porotchkin print_field(main_hdr, header_t, rsrvd3, FMT_HEX, base); 11566414dc6dSKonstantin Porotchkin 11576414dc6dSKonstantin Porotchkin return sizeof(header_t); 11586414dc6dSKonstantin Porotchkin } 11596414dc6dSKonstantin Porotchkin 11606414dc6dSKonstantin Porotchkin int print_ext_hdr(ext_header_t *ext_hdr, int base) 11616414dc6dSKonstantin Porotchkin { 11626414dc6dSKonstantin Porotchkin print_field(ext_hdr, ext_header_t, type, FMT_HEX, base); 11636414dc6dSKonstantin Porotchkin print_field(ext_hdr, ext_header_t, offset, FMT_HEX, base); 11646414dc6dSKonstantin Porotchkin print_field(ext_hdr, ext_header_t, reserved, FMT_HEX, base); 11656414dc6dSKonstantin Porotchkin print_field(ext_hdr, ext_header_t, size, FMT_DEC, base); 11666414dc6dSKonstantin Porotchkin 11676414dc6dSKonstantin Porotchkin return base + sizeof(ext_header_t); 11686414dc6dSKonstantin Porotchkin } 11696414dc6dSKonstantin Porotchkin 11706414dc6dSKonstantin Porotchkin void print_sec_ext(ext_header_t *ext_hdr, int base) 11716414dc6dSKonstantin Porotchkin { 11726414dc6dSKonstantin Porotchkin sec_entry_t *sec_entry; 11736414dc6dSKonstantin Porotchkin uint32_t new_base; 11746414dc6dSKonstantin Porotchkin 11756414dc6dSKonstantin Porotchkin fprintf(stdout, "\n########### Secure extension ###########\n"); 11766414dc6dSKonstantin Porotchkin 11776414dc6dSKonstantin Porotchkin new_base = print_ext_hdr(ext_hdr, base); 11786414dc6dSKonstantin Porotchkin 11796414dc6dSKonstantin Porotchkin sec_entry = (sec_entry_t *)(ext_hdr + 1); 11806414dc6dSKonstantin Porotchkin 11816414dc6dSKonstantin Porotchkin do_print_field(0, "KAK key", new_base, MAX_RSA_DER_BYTE_LEN, FMT_NONE); 11826414dc6dSKonstantin Porotchkin new_base += MAX_RSA_DER_BYTE_LEN; 11836414dc6dSKonstantin Porotchkin print_field(sec_entry, sec_entry_t, jtag_delay, FMT_DEC, base); 11846414dc6dSKonstantin Porotchkin print_field(sec_entry, sec_entry_t, box_id, FMT_HEX, base); 11856414dc6dSKonstantin Porotchkin print_field(sec_entry, sec_entry_t, flash_id, FMT_HEX, base); 11866414dc6dSKonstantin Porotchkin print_field(sec_entry, sec_entry_t, encrypt_en, FMT_DEC, base); 11876414dc6dSKonstantin Porotchkin print_field(sec_entry, sec_entry_t, efuse_dis, FMT_DEC, base); 11886414dc6dSKonstantin Porotchkin new_base += 6 * sizeof(uint32_t); 11896414dc6dSKonstantin Porotchkin do_print_field(0, "header signature", 11906414dc6dSKonstantin Porotchkin new_base, RSA_SIGN_BYTE_LEN, FMT_NONE); 11916414dc6dSKonstantin Porotchkin new_base += RSA_SIGN_BYTE_LEN; 11926414dc6dSKonstantin Porotchkin do_print_field(0, "image signature", 11936414dc6dSKonstantin Porotchkin new_base, RSA_SIGN_BYTE_LEN, FMT_NONE); 11946414dc6dSKonstantin Porotchkin new_base += RSA_SIGN_BYTE_LEN; 11956414dc6dSKonstantin Porotchkin do_print_field(0, "CSK keys", new_base, 11966414dc6dSKonstantin Porotchkin CSK_ARR_SZ * MAX_RSA_DER_BYTE_LEN, FMT_NONE); 11976414dc6dSKonstantin Porotchkin new_base += CSK_ARR_SZ * MAX_RSA_DER_BYTE_LEN; 11986414dc6dSKonstantin Porotchkin do_print_field(0, "CSK block signature", 11996414dc6dSKonstantin Porotchkin new_base, RSA_SIGN_BYTE_LEN, FMT_NONE); 12006414dc6dSKonstantin Porotchkin new_base += RSA_SIGN_BYTE_LEN; 12016414dc6dSKonstantin Porotchkin do_print_field(0, "control", new_base, 12026414dc6dSKonstantin Porotchkin CP_CTRL_EL_ARRAY_SZ * 2, FMT_NONE); 12036414dc6dSKonstantin Porotchkin 12046414dc6dSKonstantin Porotchkin } 12056414dc6dSKonstantin Porotchkin 12066414dc6dSKonstantin Porotchkin void print_bin_ext(ext_header_t *ext_hdr, int base) 12076414dc6dSKonstantin Porotchkin { 12086414dc6dSKonstantin Porotchkin fprintf(stdout, "\n########### Binary extension ###########\n"); 12096414dc6dSKonstantin Porotchkin base = print_ext_hdr(ext_hdr, base); 12106414dc6dSKonstantin Porotchkin do_print_field(0, "binary image", base, ext_hdr->size, FMT_NONE); 12116414dc6dSKonstantin Porotchkin } 12126414dc6dSKonstantin Porotchkin 12136414dc6dSKonstantin Porotchkin int print_extension(void *buf, int base, int count, int ext_size) 12146414dc6dSKonstantin Porotchkin { 12156414dc6dSKonstantin Porotchkin ext_header_t *ext_hdr = buf; 12166414dc6dSKonstantin Porotchkin int pad = ext_size; 12176414dc6dSKonstantin Porotchkin int curr_size; 12186414dc6dSKonstantin Porotchkin 12196414dc6dSKonstantin Porotchkin while (count--) { 12206414dc6dSKonstantin Porotchkin if (ext_hdr->type == EXT_TYPE_BINARY) 12216414dc6dSKonstantin Porotchkin print_bin_ext(ext_hdr, base); 12226414dc6dSKonstantin Porotchkin else if (ext_hdr->type == EXT_TYPE_SECURITY) 12236414dc6dSKonstantin Porotchkin print_sec_ext(ext_hdr, base); 12246414dc6dSKonstantin Porotchkin 12256414dc6dSKonstantin Porotchkin curr_size = sizeof(ext_header_t) + ext_hdr->size; 12266414dc6dSKonstantin Porotchkin base += curr_size; 12276414dc6dSKonstantin Porotchkin pad -= curr_size; 12286414dc6dSKonstantin Porotchkin ext_hdr = (ext_header_t *)((uintptr_t)ext_hdr + curr_size); 12296414dc6dSKonstantin Porotchkin } 12306414dc6dSKonstantin Porotchkin 12316414dc6dSKonstantin Porotchkin if (pad) 12326414dc6dSKonstantin Porotchkin do_print_field(0, "padding", base, pad, FMT_NONE); 12336414dc6dSKonstantin Porotchkin 12346414dc6dSKonstantin Porotchkin return ext_size; 12356414dc6dSKonstantin Porotchkin } 12366414dc6dSKonstantin Porotchkin 12376414dc6dSKonstantin Porotchkin int parse_image(uint8_t *buf, int size) 12386414dc6dSKonstantin Porotchkin { 12396414dc6dSKonstantin Porotchkin int base = 0; 12406414dc6dSKonstantin Porotchkin int ret = 1; 12416414dc6dSKonstantin Porotchkin header_t *main_hdr; 12426414dc6dSKonstantin Porotchkin uint32_t checksum, prolog_checksum; 12436414dc6dSKonstantin Porotchkin 12446414dc6dSKonstantin Porotchkin 12456414dc6dSKonstantin Porotchkin fprintf(stdout, 12466414dc6dSKonstantin Porotchkin "################### Prolog Start ######################\n\n"); 12476414dc6dSKonstantin Porotchkin main_hdr = (header_t *)buf; 12486414dc6dSKonstantin Porotchkin base += print_header(buf, base); 12496414dc6dSKonstantin Porotchkin 12506414dc6dSKonstantin Porotchkin if (main_hdr->ext_count) 12516414dc6dSKonstantin Porotchkin base += print_extension(buf + base, base, 12526414dc6dSKonstantin Porotchkin main_hdr->ext_count, 12536414dc6dSKonstantin Porotchkin main_hdr->prolog_size - 12546414dc6dSKonstantin Porotchkin sizeof(header_t)); 12556414dc6dSKonstantin Porotchkin 12566414dc6dSKonstantin Porotchkin if (base < main_hdr->prolog_size) { 12576414dc6dSKonstantin Porotchkin fprintf(stdout, "\n########### Padding ##############\n"); 12586414dc6dSKonstantin Porotchkin do_print_field(0, "prolog padding", 12596414dc6dSKonstantin Porotchkin base, main_hdr->prolog_size - base, FMT_HEX); 12606414dc6dSKonstantin Porotchkin base = main_hdr->prolog_size; 12616414dc6dSKonstantin Porotchkin } 12626414dc6dSKonstantin Porotchkin fprintf(stdout, 12636414dc6dSKonstantin Porotchkin "\n################### Prolog End ######################\n"); 12646414dc6dSKonstantin Porotchkin 12656414dc6dSKonstantin Porotchkin fprintf(stdout, 12666414dc6dSKonstantin Porotchkin "\n################### Boot image ######################\n"); 12676414dc6dSKonstantin Porotchkin 12686414dc6dSKonstantin Porotchkin do_print_field(0, "boot image", base, size - base - 4, FMT_NONE); 12696414dc6dSKonstantin Porotchkin 12706414dc6dSKonstantin Porotchkin fprintf(stdout, 12716414dc6dSKonstantin Porotchkin "################### Image end ########################\n"); 12726414dc6dSKonstantin Porotchkin 12736414dc6dSKonstantin Porotchkin /* Check sanity for certain values */ 12746414dc6dSKonstantin Porotchkin printf("\nChecking values:\n"); 12756414dc6dSKonstantin Porotchkin 12766414dc6dSKonstantin Porotchkin if (main_hdr->magic == MAIN_HDR_MAGIC) { 12776414dc6dSKonstantin Porotchkin fprintf(stdout, "Headers magic: OK!\n"); 12786414dc6dSKonstantin Porotchkin } else { 12796414dc6dSKonstantin Porotchkin fprintf(stderr, 12806414dc6dSKonstantin Porotchkin "\n****** ERROR: HEADER MAGIC 0x%08x != 0x%08x\n", 12816414dc6dSKonstantin Porotchkin main_hdr->magic, MAIN_HDR_MAGIC); 12826414dc6dSKonstantin Porotchkin goto error; 12836414dc6dSKonstantin Porotchkin } 12846414dc6dSKonstantin Porotchkin 12856414dc6dSKonstantin Porotchkin /* headers checksum */ 12866414dc6dSKonstantin Porotchkin /* clear the checksum field in header to calculate checksum */ 12876414dc6dSKonstantin Porotchkin prolog_checksum = main_hdr->prolog_checksum; 12886414dc6dSKonstantin Porotchkin main_hdr->prolog_checksum = 0; 12896414dc6dSKonstantin Porotchkin checksum = checksum32((uint32_t *)buf, main_hdr->prolog_size); 12906414dc6dSKonstantin Porotchkin 12916414dc6dSKonstantin Porotchkin if (checksum == prolog_checksum) { 12926414dc6dSKonstantin Porotchkin fprintf(stdout, "Headers checksum: OK!\n"); 12936414dc6dSKonstantin Porotchkin } else { 12946414dc6dSKonstantin Porotchkin fprintf(stderr, 12956414dc6dSKonstantin Porotchkin "\n***** ERROR: BAD HEADER CHECKSUM 0x%08x != 0x%08x\n", 12966414dc6dSKonstantin Porotchkin checksum, prolog_checksum); 12976414dc6dSKonstantin Porotchkin goto error; 12986414dc6dSKonstantin Porotchkin } 12996414dc6dSKonstantin Porotchkin 13006414dc6dSKonstantin Porotchkin /* boot image checksum */ 13016414dc6dSKonstantin Porotchkin checksum = checksum32((uint32_t *)(buf + main_hdr->prolog_size), 13026414dc6dSKonstantin Porotchkin main_hdr->boot_image_size); 13036414dc6dSKonstantin Porotchkin if (checksum == main_hdr->boot_image_checksum) { 13046414dc6dSKonstantin Porotchkin fprintf(stdout, "Image checksum: OK!\n"); 13056414dc6dSKonstantin Porotchkin } else { 13066414dc6dSKonstantin Porotchkin fprintf(stderr, 13076414dc6dSKonstantin Porotchkin "\n****** ERROR: BAD IMAGE CHECKSUM 0x%08x != 0x%08x\n", 13086414dc6dSKonstantin Porotchkin checksum, main_hdr->boot_image_checksum); 13096414dc6dSKonstantin Porotchkin goto error; 13106414dc6dSKonstantin Porotchkin } 13116414dc6dSKonstantin Porotchkin 13126414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT 13136414dc6dSKonstantin Porotchkin /* RSA signatures */ 13146414dc6dSKonstantin Porotchkin if (main_hdr->ext_count) { 13156414dc6dSKonstantin Porotchkin uint8_t ext_num = main_hdr->ext_count; 13166414dc6dSKonstantin Porotchkin ext_header_t *ext_hdr = (ext_header_t *)(main_hdr + 1); 13176414dc6dSKonstantin Porotchkin unsigned char hash[32]; 13186414dc6dSKonstantin Porotchkin int i; 13196414dc6dSKonstantin Porotchkin 13206414dc6dSKonstantin Porotchkin while (ext_num--) { 13216414dc6dSKonstantin Porotchkin if (ext_hdr->type == EXT_TYPE_SECURITY) { 13226414dc6dSKonstantin Porotchkin sec_entry_t *sec_entry = 13236414dc6dSKonstantin Porotchkin (sec_entry_t *)(ext_hdr + 1); 13246414dc6dSKonstantin Porotchkin 13256414dc6dSKonstantin Porotchkin ret = verify_secure_header_signatures( 13266414dc6dSKonstantin Porotchkin main_hdr, sec_entry); 13276414dc6dSKonstantin Porotchkin if (ret != 0) { 13286414dc6dSKonstantin Porotchkin fprintf(stderr, 13296414dc6dSKonstantin Porotchkin "\n****** FAILED TO VERIFY "); 13306414dc6dSKonstantin Porotchkin fprintf(stderr, 13316414dc6dSKonstantin Porotchkin "RSA SIGNATURES ********\n"); 13326414dc6dSKonstantin Porotchkin goto error; 13336414dc6dSKonstantin Porotchkin } 13346414dc6dSKonstantin Porotchkin 1335a79df348SKonstantin Porotchkin mbedtls_sha256_ret(sec_entry->kak_key, 13366414dc6dSKonstantin Porotchkin MAX_RSA_DER_BYTE_LEN, hash, 0); 13376414dc6dSKonstantin Porotchkin fprintf(stdout, 13386414dc6dSKonstantin Porotchkin ">>>>>>>>>> KAK KEY HASH >>>>>>>>>>\n"); 13396414dc6dSKonstantin Porotchkin fprintf(stdout, "SHA256: "); 13406414dc6dSKonstantin Porotchkin for (i = 0; i < 32; i++) 13416414dc6dSKonstantin Porotchkin fprintf(stdout, "%02X", hash[i]); 13426414dc6dSKonstantin Porotchkin 13436414dc6dSKonstantin Porotchkin fprintf(stdout, 13446414dc6dSKonstantin Porotchkin "\n<<<<<<<<< KAK KEY HASH <<<<<<<<<\n"); 13456414dc6dSKonstantin Porotchkin 13466414dc6dSKonstantin Porotchkin break; 13476414dc6dSKonstantin Porotchkin } 13486414dc6dSKonstantin Porotchkin ext_hdr = 13496414dc6dSKonstantin Porotchkin (ext_header_t *)((uint8_t *)(ext_hdr + 1) + 13506414dc6dSKonstantin Porotchkin ext_hdr->size); 13516414dc6dSKonstantin Porotchkin } 13526414dc6dSKonstantin Porotchkin } 13536414dc6dSKonstantin Porotchkin #endif 13546414dc6dSKonstantin Porotchkin 13556414dc6dSKonstantin Porotchkin ret = 0; 13566414dc6dSKonstantin Porotchkin error: 13576414dc6dSKonstantin Porotchkin return ret; 13586414dc6dSKonstantin Porotchkin } 13596414dc6dSKonstantin Porotchkin 13606414dc6dSKonstantin Porotchkin int format_bin_ext(char *filename, FILE *out_fd) 13616414dc6dSKonstantin Porotchkin { 13626414dc6dSKonstantin Porotchkin ext_header_t header; 13636414dc6dSKonstantin Porotchkin FILE *in_fd; 13646414dc6dSKonstantin Porotchkin int size, written; 13656414dc6dSKonstantin Porotchkin int aligned_size, pad_bytes; 13666414dc6dSKonstantin Porotchkin char c; 13676414dc6dSKonstantin Porotchkin 13686414dc6dSKonstantin Porotchkin in_fd = fopen(filename, "rb"); 13696414dc6dSKonstantin Porotchkin if (in_fd == NULL) { 13706414dc6dSKonstantin Porotchkin fprintf(stderr, "failed to open bin extension file %s\n", 13716414dc6dSKonstantin Porotchkin filename); 13726414dc6dSKonstantin Porotchkin return 1; 13736414dc6dSKonstantin Porotchkin } 13746414dc6dSKonstantin Porotchkin 13756414dc6dSKonstantin Porotchkin size = get_file_size(filename); 13766414dc6dSKonstantin Porotchkin if (size <= 0) { 13776414dc6dSKonstantin Porotchkin fprintf(stderr, "bin extension file size is bad\n"); 13786414dc6dSKonstantin Porotchkin return 1; 13796414dc6dSKonstantin Porotchkin } 13806414dc6dSKonstantin Porotchkin 13816414dc6dSKonstantin Porotchkin /* Align extension size to 8 bytes */ 13826414dc6dSKonstantin Porotchkin aligned_size = (size + 7) & (~7); 13836414dc6dSKonstantin Porotchkin pad_bytes = aligned_size - size; 13846414dc6dSKonstantin Porotchkin 13856414dc6dSKonstantin Porotchkin header.type = EXT_TYPE_BINARY; 13866414dc6dSKonstantin Porotchkin header.offset = 0; 13876414dc6dSKonstantin Porotchkin header.size = aligned_size; 13886414dc6dSKonstantin Porotchkin header.reserved = 0; 13896414dc6dSKonstantin Porotchkin 13906414dc6dSKonstantin Porotchkin /* Write header */ 13916414dc6dSKonstantin Porotchkin written = fwrite(&header, sizeof(ext_header_t), 1, out_fd); 13926414dc6dSKonstantin Porotchkin if (written != 1) { 13936414dc6dSKonstantin Porotchkin fprintf(stderr, "failed writing header to extension file\n"); 13946414dc6dSKonstantin Porotchkin return 1; 13956414dc6dSKonstantin Porotchkin } 13966414dc6dSKonstantin Porotchkin 13976414dc6dSKonstantin Porotchkin /* Write image */ 13986414dc6dSKonstantin Porotchkin while (size--) { 13996414dc6dSKonstantin Porotchkin c = getc(in_fd); 14006414dc6dSKonstantin Porotchkin fputc(c, out_fd); 14016414dc6dSKonstantin Porotchkin } 14026414dc6dSKonstantin Porotchkin 14036414dc6dSKonstantin Porotchkin while (pad_bytes--) 14046414dc6dSKonstantin Porotchkin fputc(0, out_fd); 14056414dc6dSKonstantin Porotchkin 14066414dc6dSKonstantin Porotchkin fclose(in_fd); 14076414dc6dSKonstantin Porotchkin 14086414dc6dSKonstantin Porotchkin return 0; 14096414dc6dSKonstantin Porotchkin } 14106414dc6dSKonstantin Porotchkin 14116414dc6dSKonstantin Porotchkin /* **************************************** 14126414dc6dSKonstantin Porotchkin * 14136414dc6dSKonstantin Porotchkin * Write all extensions (binary, secure 14146414dc6dSKonstantin Porotchkin * extensions) to file 14156414dc6dSKonstantin Porotchkin * 14166414dc6dSKonstantin Porotchkin * ****************************************/ 14176414dc6dSKonstantin Porotchkin 14186414dc6dSKonstantin Porotchkin int format_extensions(char *ext_filename) 14196414dc6dSKonstantin Porotchkin { 14206414dc6dSKonstantin Porotchkin FILE *out_fd; 14216414dc6dSKonstantin Porotchkin int ret = 0; 14226414dc6dSKonstantin Porotchkin 14236414dc6dSKonstantin Porotchkin out_fd = fopen(ext_filename, "wb"); 14246414dc6dSKonstantin Porotchkin if (out_fd == NULL) { 14256414dc6dSKonstantin Porotchkin fprintf(stderr, "failed to open extension output file %s", 14266414dc6dSKonstantin Porotchkin ext_filename); 14276414dc6dSKonstantin Porotchkin return 1; 14286414dc6dSKonstantin Porotchkin } 14296414dc6dSKonstantin Porotchkin 14306414dc6dSKonstantin Porotchkin if (strncmp(opts.bin_ext_file, "NA", MAX_FILENAME)) { 14316414dc6dSKonstantin Porotchkin if (format_bin_ext(opts.bin_ext_file, out_fd)) { 14326414dc6dSKonstantin Porotchkin ret = 1; 14336414dc6dSKonstantin Porotchkin goto error; 14346414dc6dSKonstantin Porotchkin } 14356414dc6dSKonstantin Porotchkin } 14366414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT 14376414dc6dSKonstantin Porotchkin if (strncmp(opts.sec_cfg_file, "NA", MAX_FILENAME)) { 14386414dc6dSKonstantin Porotchkin if (format_sec_ext(opts.sec_cfg_file, out_fd)) { 14396414dc6dSKonstantin Porotchkin ret = 1; 14406414dc6dSKonstantin Porotchkin goto error; 14416414dc6dSKonstantin Porotchkin } 14426414dc6dSKonstantin Porotchkin } 14436414dc6dSKonstantin Porotchkin #endif 14446414dc6dSKonstantin Porotchkin 14456414dc6dSKonstantin Porotchkin error: 14466414dc6dSKonstantin Porotchkin fflush(out_fd); 14476414dc6dSKonstantin Porotchkin fclose(out_fd); 14486414dc6dSKonstantin Porotchkin return ret; 14496414dc6dSKonstantin Porotchkin } 14506414dc6dSKonstantin Porotchkin 14516414dc6dSKonstantin Porotchkin void update_uart(header_t *header) 14526414dc6dSKonstantin Porotchkin { 14536414dc6dSKonstantin Porotchkin header->uart_cfg = 0; 14546414dc6dSKonstantin Porotchkin header->baudrate = 0; 14556414dc6dSKonstantin Porotchkin 14566414dc6dSKonstantin Porotchkin if (opts.disable_print) 14576414dc6dSKonstantin Porotchkin uart_set_mode(header->uart_cfg, UART_MODE_DISABLE); 14586414dc6dSKonstantin Porotchkin 14596414dc6dSKonstantin Porotchkin if (opts.baudrate) 14606414dc6dSKonstantin Porotchkin header->baudrate = (opts.baudrate / 1200); 14616414dc6dSKonstantin Porotchkin } 14626414dc6dSKonstantin Porotchkin 14636414dc6dSKonstantin Porotchkin /* **************************************** 14646414dc6dSKonstantin Porotchkin * 14656414dc6dSKonstantin Porotchkin * Write the image prolog, i.e. 14666414dc6dSKonstantin Porotchkin * main header and extensions, to file 14676414dc6dSKonstantin Porotchkin * 14686414dc6dSKonstantin Porotchkin * ****************************************/ 14696414dc6dSKonstantin Porotchkin 14706414dc6dSKonstantin Porotchkin int write_prolog(int ext_cnt, char *ext_filename, 14716414dc6dSKonstantin Porotchkin uint8_t *image_buf, int image_size, FILE *out_fd) 14726414dc6dSKonstantin Porotchkin { 14736414dc6dSKonstantin Porotchkin header_t *header; 14746414dc6dSKonstantin Porotchkin int main_hdr_size = sizeof(header_t); 14756414dc6dSKonstantin Porotchkin int prolog_size = main_hdr_size; 14766414dc6dSKonstantin Porotchkin FILE *ext_fd; 14776414dc6dSKonstantin Porotchkin char *buf; 14786414dc6dSKonstantin Porotchkin int written, read; 14796414dc6dSKonstantin Porotchkin int ret = 1; 14806414dc6dSKonstantin Porotchkin 14816414dc6dSKonstantin Porotchkin 14826414dc6dSKonstantin Porotchkin if (ext_cnt) 14836414dc6dSKonstantin Porotchkin prolog_size += get_file_size(ext_filename); 14846414dc6dSKonstantin Porotchkin 14856414dc6dSKonstantin Porotchkin prolog_size = ((prolog_size + PROLOG_ALIGNMENT) & 14866414dc6dSKonstantin Porotchkin (~(PROLOG_ALIGNMENT-1))); 14876414dc6dSKonstantin Porotchkin 14886414dc6dSKonstantin Porotchkin /* Allocate a zeroed buffer to zero the padding bytes */ 14896414dc6dSKonstantin Porotchkin buf = calloc(prolog_size, 1); 14906414dc6dSKonstantin Porotchkin if (buf == NULL) { 14916414dc6dSKonstantin Porotchkin fprintf(stderr, "Error: failed allocating checksum buffer\n"); 14926414dc6dSKonstantin Porotchkin return 1; 14936414dc6dSKonstantin Porotchkin } 14946414dc6dSKonstantin Porotchkin 14956414dc6dSKonstantin Porotchkin header = (header_t *)buf; 14966414dc6dSKonstantin Porotchkin header->magic = MAIN_HDR_MAGIC; 14976414dc6dSKonstantin Porotchkin header->prolog_size = prolog_size; 14986414dc6dSKonstantin Porotchkin header->load_addr = opts.load_addr; 14996414dc6dSKonstantin Porotchkin header->exec_addr = opts.exec_addr; 15006414dc6dSKonstantin Porotchkin header->io_arg_0 = opts.nfc_io_args; 15016414dc6dSKonstantin Porotchkin header->ext_count = ext_cnt; 15026414dc6dSKonstantin Porotchkin header->aux_flags = 0; 15036414dc6dSKonstantin Porotchkin header->boot_image_size = (image_size + 3) & (~0x3); 15046414dc6dSKonstantin Porotchkin header->boot_image_checksum = checksum32((uint32_t *)image_buf, 15056414dc6dSKonstantin Porotchkin image_size); 15066414dc6dSKonstantin Porotchkin 15076414dc6dSKonstantin Porotchkin update_uart(header); 15086414dc6dSKonstantin Porotchkin 15096414dc6dSKonstantin Porotchkin /* Populate buffer with main header and extensions */ 15106414dc6dSKonstantin Porotchkin if (ext_cnt) { 15116414dc6dSKonstantin Porotchkin ext_fd = fopen(ext_filename, "rb"); 15126414dc6dSKonstantin Porotchkin if (ext_fd == NULL) { 15136414dc6dSKonstantin Porotchkin fprintf(stderr, 15146414dc6dSKonstantin Porotchkin "Error: failed to open extensions file\n"); 15156414dc6dSKonstantin Porotchkin goto error; 15166414dc6dSKonstantin Porotchkin } 15176414dc6dSKonstantin Porotchkin 15186414dc6dSKonstantin Porotchkin read = fread(&buf[main_hdr_size], 15196414dc6dSKonstantin Porotchkin get_file_size(ext_filename), 1, ext_fd); 15206414dc6dSKonstantin Porotchkin if (read != 1) { 15216414dc6dSKonstantin Porotchkin fprintf(stderr, 15226414dc6dSKonstantin Porotchkin "Error: failed to open extensions file\n"); 15236414dc6dSKonstantin Porotchkin goto error; 15246414dc6dSKonstantin Porotchkin } 15256414dc6dSKonstantin Porotchkin 15266414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT 15276414dc6dSKonstantin Porotchkin /* Secure boot mode? */ 15286414dc6dSKonstantin Porotchkin if (opts.sec_opts != 0) { 15296414dc6dSKonstantin Porotchkin ret = finalize_secure_ext(header, (uint8_t *)buf, 15306414dc6dSKonstantin Porotchkin prolog_size, image_buf, 15316414dc6dSKonstantin Porotchkin image_size); 15326414dc6dSKonstantin Porotchkin if (ret != 0) { 15336414dc6dSKonstantin Porotchkin fprintf(stderr, "Error: failed to handle "); 15346414dc6dSKonstantin Porotchkin fprintf(stderr, "secure extension!\n"); 15356414dc6dSKonstantin Porotchkin goto error; 15366414dc6dSKonstantin Porotchkin } 15376414dc6dSKonstantin Porotchkin } /* secure boot mode */ 15386414dc6dSKonstantin Porotchkin #endif 15396414dc6dSKonstantin Porotchkin } 15406414dc6dSKonstantin Porotchkin 15416414dc6dSKonstantin Porotchkin /* Update the total prolog checksum */ 15426414dc6dSKonstantin Porotchkin header->prolog_checksum = checksum32((uint32_t *)buf, prolog_size); 15436414dc6dSKonstantin Porotchkin 15446414dc6dSKonstantin Porotchkin /* Now spill everything to output file */ 15456414dc6dSKonstantin Porotchkin written = fwrite(buf, prolog_size, 1, out_fd); 15466414dc6dSKonstantin Porotchkin if (written != 1) { 15476414dc6dSKonstantin Porotchkin fprintf(stderr, 15486414dc6dSKonstantin Porotchkin "Error: failed to write prolog to output file\n"); 15496414dc6dSKonstantin Porotchkin goto error; 15506414dc6dSKonstantin Porotchkin } 15516414dc6dSKonstantin Porotchkin 15526414dc6dSKonstantin Porotchkin ret = 0; 15536414dc6dSKonstantin Porotchkin 15546414dc6dSKonstantin Porotchkin error: 15556414dc6dSKonstantin Porotchkin free(buf); 15566414dc6dSKonstantin Porotchkin return ret; 15576414dc6dSKonstantin Porotchkin } 15586414dc6dSKonstantin Porotchkin 15596414dc6dSKonstantin Porotchkin int write_boot_image(uint8_t *buf, uint32_t image_size, FILE *out_fd) 15606414dc6dSKonstantin Porotchkin { 15616414dc6dSKonstantin Porotchkin int written; 15626414dc6dSKonstantin Porotchkin 15635985a1e4SKonstantin Porotchkin written = fwrite(buf, image_size, 1, out_fd); 15646414dc6dSKonstantin Porotchkin if (written != 1) { 15656414dc6dSKonstantin Porotchkin fprintf(stderr, "Error: Failed to write boot image\n"); 15666414dc6dSKonstantin Porotchkin goto error; 15676414dc6dSKonstantin Porotchkin } 15686414dc6dSKonstantin Porotchkin 15696414dc6dSKonstantin Porotchkin return 0; 15706414dc6dSKonstantin Porotchkin error: 15716414dc6dSKonstantin Porotchkin return 1; 15726414dc6dSKonstantin Porotchkin } 15736414dc6dSKonstantin Porotchkin 15746414dc6dSKonstantin Porotchkin int main(int argc, char *argv[]) 15756414dc6dSKonstantin Porotchkin { 15766414dc6dSKonstantin Porotchkin char in_file[MAX_FILENAME+1] = { 0 }; 15776414dc6dSKonstantin Porotchkin char out_file[MAX_FILENAME+1] = { 0 }; 15786414dc6dSKonstantin Porotchkin char ext_file[MAX_FILENAME+1] = { 0 }; 15796414dc6dSKonstantin Porotchkin FILE *in_fd = NULL; 15806414dc6dSKonstantin Porotchkin FILE *out_fd = NULL; 15816414dc6dSKonstantin Porotchkin int parse = 0; 15826414dc6dSKonstantin Porotchkin int ext_cnt = 0; 15836414dc6dSKonstantin Porotchkin int opt; 15846414dc6dSKonstantin Porotchkin int ret = 0; 15855985a1e4SKonstantin Porotchkin int image_size, file_size; 15866414dc6dSKonstantin Porotchkin uint8_t *image_buf = NULL; 15876414dc6dSKonstantin Porotchkin int read; 15886414dc6dSKonstantin Porotchkin size_t len; 15896414dc6dSKonstantin Porotchkin uint32_t nand_block_size_kb, mlc_nand; 15906414dc6dSKonstantin Porotchkin 15916414dc6dSKonstantin Porotchkin /* Create temporary file for building extensions 15926414dc6dSKonstantin Porotchkin * Use process ID for allowing multiple parallel runs 15936414dc6dSKonstantin Porotchkin */ 15946414dc6dSKonstantin Porotchkin snprintf(ext_file, MAX_FILENAME, "/tmp/ext_file-%x", getpid()); 15956414dc6dSKonstantin Porotchkin 15966414dc6dSKonstantin Porotchkin while ((opt = getopt(argc, argv, "hpms:i:l:e:a:b:u:n:t:c:k:")) != -1) { 15976414dc6dSKonstantin Porotchkin switch (opt) { 15986414dc6dSKonstantin Porotchkin case 'h': 15996414dc6dSKonstantin Porotchkin usage(); 16006414dc6dSKonstantin Porotchkin break; 16016414dc6dSKonstantin Porotchkin case 'l': 16026414dc6dSKonstantin Porotchkin opts.load_addr = strtoul(optarg, NULL, 0); 16036414dc6dSKonstantin Porotchkin break; 16046414dc6dSKonstantin Porotchkin case 'e': 16056414dc6dSKonstantin Porotchkin opts.exec_addr = strtoul(optarg, NULL, 0); 16066414dc6dSKonstantin Porotchkin break; 16076414dc6dSKonstantin Porotchkin case 'm': 16086414dc6dSKonstantin Porotchkin opts.disable_print = 1; 16096414dc6dSKonstantin Porotchkin break; 16106414dc6dSKonstantin Porotchkin case 'u': 16116414dc6dSKonstantin Porotchkin opts.baudrate = strtoul(optarg, NULL, 0); 16126414dc6dSKonstantin Porotchkin break; 16136414dc6dSKonstantin Porotchkin case 'b': 16146414dc6dSKonstantin Porotchkin strncpy(opts.bin_ext_file, optarg, MAX_FILENAME); 16156414dc6dSKonstantin Porotchkin ext_cnt++; 16166414dc6dSKonstantin Porotchkin break; 16176414dc6dSKonstantin Porotchkin case 'p': 16186414dc6dSKonstantin Porotchkin parse = 1; 16196414dc6dSKonstantin Porotchkin break; 16206414dc6dSKonstantin Porotchkin case 'n': 16216414dc6dSKonstantin Porotchkin nand_block_size_kb = strtoul(optarg, NULL, 0); 16226414dc6dSKonstantin Porotchkin opts.nfc_io_args |= (nand_block_size_kb / 64); 16236414dc6dSKonstantin Porotchkin break; 16246414dc6dSKonstantin Porotchkin case 't': 16256414dc6dSKonstantin Porotchkin mlc_nand = 0; 16266414dc6dSKonstantin Porotchkin if (!strncmp("MLC", optarg, 3)) 16276414dc6dSKonstantin Porotchkin mlc_nand = 1; 16286414dc6dSKonstantin Porotchkin opts.nfc_io_args |= (mlc_nand << 8); 16296414dc6dSKonstantin Porotchkin break; 16306414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT 16316414dc6dSKonstantin Porotchkin case 'c': /* SEC extension */ 16326414dc6dSKonstantin Porotchkin strncpy(opts.sec_cfg_file, optarg, MAX_FILENAME); 16336414dc6dSKonstantin Porotchkin ext_cnt++; 16346414dc6dSKonstantin Porotchkin break; 16356414dc6dSKonstantin Porotchkin case 'k': 16366414dc6dSKonstantin Porotchkin opts.key_index = strtoul(optarg, NULL, 0); 16376414dc6dSKonstantin Porotchkin break; 16386414dc6dSKonstantin Porotchkin #endif 16396414dc6dSKonstantin Porotchkin default: /* '?' */ 16406414dc6dSKonstantin Porotchkin usage_err("Unknown argument"); 16416414dc6dSKonstantin Porotchkin exit(EXIT_FAILURE); 16426414dc6dSKonstantin Porotchkin } 16436414dc6dSKonstantin Porotchkin } 16446414dc6dSKonstantin Porotchkin 16456414dc6dSKonstantin Porotchkin /* Check validity of inputes */ 16466414dc6dSKonstantin Porotchkin if (opts.load_addr % 8) 16476414dc6dSKonstantin Porotchkin usage_err("Load address must be 8 bytes aligned"); 16486414dc6dSKonstantin Porotchkin 16496414dc6dSKonstantin Porotchkin if (opts.baudrate % 1200) 16506414dc6dSKonstantin Porotchkin usage_err("Baudrate must be a multiple of 1200"); 16516414dc6dSKonstantin Porotchkin 16526414dc6dSKonstantin Porotchkin /* The remaining arguments are the input 16536414dc6dSKonstantin Porotchkin * and potentially output file 16546414dc6dSKonstantin Porotchkin */ 16556414dc6dSKonstantin Porotchkin /* Input file must exist so exit if not */ 16566414dc6dSKonstantin Porotchkin if (optind >= argc) 16576414dc6dSKonstantin Porotchkin usage_err("missing input file name"); 16586414dc6dSKonstantin Porotchkin 16596414dc6dSKonstantin Porotchkin len = strlen(argv[optind]); 16606414dc6dSKonstantin Porotchkin if (len > MAX_FILENAME) 16616414dc6dSKonstantin Porotchkin usage_err("file name too long"); 16626414dc6dSKonstantin Porotchkin memcpy(in_file, argv[optind], len); 16636414dc6dSKonstantin Porotchkin optind++; 16646414dc6dSKonstantin Porotchkin 16656414dc6dSKonstantin Porotchkin /* Output file must exist in non parse mode */ 16666414dc6dSKonstantin Porotchkin if (optind < argc) { 16676414dc6dSKonstantin Porotchkin len = strlen(argv[optind]); 16686414dc6dSKonstantin Porotchkin if (len > MAX_FILENAME) 16696414dc6dSKonstantin Porotchkin usage_err("file name too long"); 16706414dc6dSKonstantin Porotchkin memcpy(out_file, argv[optind], len); 16716414dc6dSKonstantin Porotchkin } else if (!parse) 16726414dc6dSKonstantin Porotchkin usage_err("missing output file name"); 16736414dc6dSKonstantin Porotchkin 16746414dc6dSKonstantin Porotchkin /* open the input file */ 16756414dc6dSKonstantin Porotchkin in_fd = fopen(in_file, "rb"); 16766414dc6dSKonstantin Porotchkin if (in_fd == NULL) { 16776414dc6dSKonstantin Porotchkin printf("Error: Failed to open input file %s\n", in_file); 16786414dc6dSKonstantin Porotchkin goto main_exit; 16796414dc6dSKonstantin Porotchkin } 16806414dc6dSKonstantin Porotchkin 16815985a1e4SKonstantin Porotchkin /* Read the input file to buffer 16825985a1e4SKonstantin Porotchkin * Always align the image to 16 byte boundary 16835985a1e4SKonstantin Porotchkin */ 16845985a1e4SKonstantin Porotchkin file_size = get_file_size(in_file); 16855985a1e4SKonstantin Porotchkin image_size = (file_size + AES_BLOCK_SZ - 1) & ~(AES_BLOCK_SZ - 1); 16865985a1e4SKonstantin Porotchkin image_buf = calloc(image_size, 1); 16876414dc6dSKonstantin Porotchkin if (image_buf == NULL) { 16886414dc6dSKonstantin Porotchkin fprintf(stderr, "Error: failed allocating input buffer\n"); 16896414dc6dSKonstantin Porotchkin return 1; 16906414dc6dSKonstantin Porotchkin } 16916414dc6dSKonstantin Porotchkin 16925985a1e4SKonstantin Porotchkin read = fread(image_buf, file_size, 1, in_fd); 16936414dc6dSKonstantin Porotchkin if (read != 1) { 16946414dc6dSKonstantin Porotchkin fprintf(stderr, "Error: failed to read input file\n"); 16956414dc6dSKonstantin Porotchkin goto main_exit; 16966414dc6dSKonstantin Porotchkin } 16976414dc6dSKonstantin Porotchkin 16986414dc6dSKonstantin Porotchkin /* Parse the input image and leave */ 16996414dc6dSKonstantin Porotchkin if (parse) { 17006414dc6dSKonstantin Porotchkin if (opts.key_index >= CSK_ARR_SZ) { 17016414dc6dSKonstantin Porotchkin fprintf(stderr, 17026414dc6dSKonstantin Porotchkin "Wrong key IDX value. Valid values 0 - %d\n", 17036414dc6dSKonstantin Porotchkin CSK_ARR_SZ - 1); 17046414dc6dSKonstantin Porotchkin goto main_exit; 17056414dc6dSKonstantin Porotchkin } 17066414dc6dSKonstantin Porotchkin ret = parse_image(image_buf, image_size); 17076414dc6dSKonstantin Porotchkin goto main_exit; 17086414dc6dSKonstantin Porotchkin } 17096414dc6dSKonstantin Porotchkin 17106414dc6dSKonstantin Porotchkin /* Create a blob file from all extensions */ 17116414dc6dSKonstantin Porotchkin if (ext_cnt) { 17126414dc6dSKonstantin Porotchkin ret = format_extensions(ext_file); 17136414dc6dSKonstantin Porotchkin if (ret) 17146414dc6dSKonstantin Porotchkin goto main_exit; 17156414dc6dSKonstantin Porotchkin } 17166414dc6dSKonstantin Porotchkin 17176414dc6dSKonstantin Porotchkin out_fd = fopen(out_file, "wb"); 17186414dc6dSKonstantin Porotchkin if (out_fd == NULL) { 17196414dc6dSKonstantin Porotchkin fprintf(stderr, 17206414dc6dSKonstantin Porotchkin "Error: Failed to open output file %s\n", out_file); 17216414dc6dSKonstantin Porotchkin goto main_exit; 17226414dc6dSKonstantin Porotchkin } 17236414dc6dSKonstantin Porotchkin 17246414dc6dSKonstantin Porotchkin ret = write_prolog(ext_cnt, ext_file, image_buf, image_size, out_fd); 17256414dc6dSKonstantin Porotchkin if (ret) 17266414dc6dSKonstantin Porotchkin goto main_exit; 17276414dc6dSKonstantin Porotchkin 17286414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT 17296414dc6dSKonstantin Porotchkin if (opts.sec_opts && (opts.sec_opts->encrypted_image != 0) && 17306414dc6dSKonstantin Porotchkin (opts.sec_opts->enc_image_sz != 0)) { 17316414dc6dSKonstantin Porotchkin ret = write_boot_image(opts.sec_opts->encrypted_image, 17326414dc6dSKonstantin Porotchkin opts.sec_opts->enc_image_sz, out_fd); 17336414dc6dSKonstantin Porotchkin } else 17346414dc6dSKonstantin Porotchkin #endif 17356414dc6dSKonstantin Porotchkin ret = write_boot_image(image_buf, image_size, out_fd); 17366414dc6dSKonstantin Porotchkin if (ret) 17376414dc6dSKonstantin Porotchkin goto main_exit; 17386414dc6dSKonstantin Porotchkin 17396414dc6dSKonstantin Porotchkin main_exit: 17406414dc6dSKonstantin Porotchkin if (in_fd) 17416414dc6dSKonstantin Porotchkin fclose(in_fd); 17426414dc6dSKonstantin Porotchkin 17436414dc6dSKonstantin Porotchkin if (out_fd) 17446414dc6dSKonstantin Porotchkin fclose(out_fd); 17456414dc6dSKonstantin Porotchkin 17466414dc6dSKonstantin Porotchkin if (image_buf) 17476414dc6dSKonstantin Porotchkin free(image_buf); 17486414dc6dSKonstantin Porotchkin 17496414dc6dSKonstantin Porotchkin unlink(ext_file); 17506414dc6dSKonstantin Porotchkin 17516414dc6dSKonstantin Porotchkin #ifdef CONFIG_MVEBU_SECURE_BOOT 17526414dc6dSKonstantin Porotchkin if (opts.sec_opts) { 17536414dc6dSKonstantin Porotchkin if (opts.sec_opts->encrypted_image) 17546414dc6dSKonstantin Porotchkin free(opts.sec_opts->encrypted_image); 17556414dc6dSKonstantin Porotchkin free(opts.sec_opts); 17566414dc6dSKonstantin Porotchkin } 17576414dc6dSKonstantin Porotchkin #endif 17586414dc6dSKonstantin Porotchkin exit(ret); 17596414dc6dSKonstantin Porotchkin } 1760