/* * Copyright (C) 2018 Marvell International Ltd. * * SPDX-License-Identifier: BSD-3-Clause * https://spdx.org/licenses */ #include #include #include #include #include #include #include #include #ifdef CONFIG_MVEBU_SECURE_BOOT #include /* for parsing config file */ /* mbedTLS stuff */ #include #if defined(MBEDTLS_BIGNUM_C) && defined(MBEDTLS_ENTROPY_C) && \ defined(MBEDTLS_SHA256_C) && \ defined(MBEDTLS_PK_PARSE_C) && defined(MBEDTLS_FS_IO) && \ defined(MBEDTLS_CTR_DRBG_C) #include #include #include #include #include #include #include #else #error "Bad mbedTLS configuration!" #endif #endif /* CONFIG_MVEBU_SECURE_BOOT */ #define MAX_FILENAME 256 #define CSK_ARR_SZ 16 #define CSK_ARR_EMPTY_FILE "*" #define AES_KEY_BIT_LEN 256 #define AES_KEY_BYTE_LEN (AES_KEY_BIT_LEN >> 3) #define AES_BLOCK_SZ 16 #define RSA_SIGN_BYTE_LEN 256 #define MAX_RSA_DER_BYTE_LEN 524 /* Number of address pairs in control array */ #define CP_CTRL_EL_ARRAY_SZ 32 #define VERSION_STRING "Marvell(C) doimage utility version 3.3" /* A8K definitions */ /* Extension header types */ #define EXT_TYPE_SECURITY 0x1 #define EXT_TYPE_BINARY 0x2 #define MAIN_HDR_MAGIC 0xB105B002 /* PROLOG alignment considerations: * 128B: To allow supporting XMODEM protocol. * 8KB: To align the boot image to the largest NAND page size, and simplify * the read operations from NAND. * We choose the largest page size, in order to use a single image for all * NAND page sizes. */ #define PROLOG_ALIGNMENT (8 << 10) /* UART argument bitfield */ #define UART_MODE_UNMODIFIED 0x0 #define UART_MODE_DISABLE 0x1 #define UART_MODE_UPDATE 0x2 typedef struct _main_header { uint32_t magic; /* 0-3 */ uint32_t prolog_size; /* 4-7 */ uint32_t prolog_checksum; /* 8-11 */ uint32_t boot_image_size; /* 12-15 */ uint32_t boot_image_checksum; /* 16-19 */ uint32_t rsrvd0; /* 20-23 */ uint32_t load_addr; /* 24-27 */ uint32_t exec_addr; /* 28-31 */ uint8_t uart_cfg; /* 32 */ uint8_t baudrate; /* 33 */ uint8_t ext_count; /* 34 */ uint8_t aux_flags; /* 35 */ uint32_t io_arg_0; /* 36-39 */ uint32_t io_arg_1; /* 40-43 */ uint32_t io_arg_2; /* 43-47 */ uint32_t io_arg_3; /* 48-51 */ uint32_t rsrvd1; /* 52-55 */ uint32_t rsrvd2; /* 56-59 */ uint32_t rsrvd3; /* 60-63 */ } header_t; typedef struct _ext_header { uint8_t type; uint8_t offset; uint16_t reserved; uint32_t size; } ext_header_t; typedef struct _sec_entry { uint8_t kak_key[MAX_RSA_DER_BYTE_LEN]; uint32_t jtag_delay; uint32_t box_id; uint32_t flash_id; uint32_t jtag_en; uint32_t encrypt_en; uint32_t efuse_dis; uint8_t header_sign[RSA_SIGN_BYTE_LEN]; uint8_t image_sign[RSA_SIGN_BYTE_LEN]; uint8_t csk_keys[CSK_ARR_SZ][MAX_RSA_DER_BYTE_LEN]; uint8_t csk_sign[RSA_SIGN_BYTE_LEN]; uint32_t cp_ctrl_arr[CP_CTRL_EL_ARRAY_SZ]; uint32_t cp_efuse_arr[CP_CTRL_EL_ARRAY_SZ]; } sec_entry_t; /* A8K definitions end */ /* UART argument bitfield */ #define UART_MODE_UNMODIFIED 0x0 #define UART_MODE_DISABLE 0x1 #define UART_MODE_UPDATE 0x2 #define uart_set_mode(arg, mode) (arg |= (mode & 0x3)) typedef struct _sec_options { #ifdef CONFIG_MVEBU_SECURE_BOOT char aes_key_file[MAX_FILENAME+1]; char kak_key_file[MAX_FILENAME+1]; char csk_key_file[CSK_ARR_SZ][MAX_FILENAME+1]; uint32_t box_id; uint32_t flash_id; uint32_t jtag_delay; uint8_t csk_index; uint8_t jtag_enable; uint8_t efuse_disable; uint32_t cp_ctrl_arr[CP_CTRL_EL_ARRAY_SZ]; uint32_t cp_efuse_arr[CP_CTRL_EL_ARRAY_SZ]; mbedtls_pk_context kak_pk; mbedtls_pk_context csk_pk[CSK_ARR_SZ]; uint8_t aes_key[AES_KEY_BYTE_LEN]; uint8_t *encrypted_image; uint32_t enc_image_sz; #endif } sec_options; typedef struct _options { char bin_ext_file[MAX_FILENAME+1]; char sec_cfg_file[MAX_FILENAME+1]; sec_options *sec_opts; uint32_t load_addr; uint32_t exec_addr; uint32_t baudrate; uint8_t disable_print; int8_t key_index; /* For header signatures verification only */ uint32_t nfc_io_args; } options_t; void usage_err(char *msg) { fprintf(stderr, "Error: %s\n", msg); fprintf(stderr, "run 'doimage -h' to get usage information\n"); exit(-1); } void usage(void) { printf("\n\n%s\n\n", VERSION_STRING); printf("Usage: doimage [options] [output_file]\n"); printf("create bootrom image from u-boot and boot extensions\n\n"); printf("Arguments\n"); printf(" input_file name of boot image file.\n"); printf(" if -p is used, name of the bootrom image file"); printf(" to parse.\n"); printf(" output_file name of output bootrom image file\n"); printf("\nOptions\n"); printf(" -s target SOC name. supports a8020,a7020\n"); printf(" different SOCs may have different boot image\n"); printf(" format so it's mandatory to know the target SOC\n"); printf(" -i boot I/F name. supports nand, spi, nor\n"); printf(" This affects certain parameters coded in the\n"); printf(" image header\n"); printf(" -l boot image load address. default is 0x0\n"); printf(" -e boot image entry address. default is 0x0\n"); printf(" -b binary extension image file.\n"); printf(" This image is executed before the boot image.\n"); printf(" This is typically used to initialize the memory "); printf(" controller.\n"); printf(" Currently supports only a single file.\n"); #ifdef CONFIG_MVEBU_SECURE_BOOT printf(" -c Make trusted boot image using parameters\n"); printf(" from the configuration file.\n"); #endif printf(" -p Parse and display a pre-built boot image\n"); #ifdef CONFIG_MVEBU_SECURE_BOOT printf(" -k Key index for RSA signatures verification\n"); printf(" when parsing the boot image\n"); #endif printf(" -m Disable prints of bootrom and binary extension\n"); printf(" -u UART baudrate used for bootrom prints.\n"); printf(" Must be multiple of 1200\n"); printf(" -h Show this help message\n"); printf(" IO-ROM NFC-NAND boot parameters:\n"); printf(" -n NAND device block size in KB [Default is 64KB].\n"); printf(" -t NAND cell technology (SLC [Default] or MLC)\n"); exit(-1); } /* globals */ static options_t opts = { .bin_ext_file = "NA", .sec_cfg_file = "NA", .sec_opts = 0, .load_addr = 0x0, .exec_addr = 0x0, .disable_print = 0, .baudrate = 0, .key_index = -1, }; int get_file_size(char *filename) { struct stat st; if (stat(filename, &st) == 0) return st.st_size; return -1; } uint32_t checksum32(uint32_t *start, int len) { uint32_t sum = 0; uint32_t *startp = start; do { sum += *startp; startp++; len -= 4; } while (len > 0); return sum; } /******************************************************************************* * create_rsa_signature (memory buffer content) * Create RSASSA-PSS/SHA-256 signature for memory buffer * using RSA Private Key * INPUT: * pk_ctx Private Key context * input memory buffer * ilen buffer length * pers personalization string for seeding the RNG. * For instance a private key file name. * OUTPUT: * signature RSA-2048 signature * RETURN: * 0 on success */ #ifdef CONFIG_MVEBU_SECURE_BOOT int create_rsa_signature(mbedtls_pk_context *pk_ctx, const unsigned char *input, size_t ilen, const char *pers, uint8_t *signature) { mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; unsigned char hash[32]; unsigned char buf[MBEDTLS_MPI_MAX_SIZE]; int rval; /* Not sure this is required, * but it's safer to start with empty buffers */ memset(hash, 0, sizeof(hash)); memset(buf, 0, sizeof(buf)); mbedtls_ctr_drbg_init(&ctr_drbg); mbedtls_entropy_init(&entropy); /* Seed the random number generator */ rval = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)); if (rval != 0) { fprintf(stderr, " Failed in ctr_drbg_init call (%d)!\n", rval); goto sign_exit; } /* The PK context should be already initialized. * Set the padding type for this PK context */ mbedtls_rsa_set_padding(mbedtls_pk_rsa(*pk_ctx), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256); /* First compute the SHA256 hash for the input blob */ mbedtls_sha256_ret(input, ilen, hash, 0); /* Then calculate the hash signature */ rval = mbedtls_rsa_rsassa_pss_sign(mbedtls_pk_rsa(*pk_ctx), mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PRIVATE, MBEDTLS_MD_SHA256, 0, hash, buf); if (rval != 0) { fprintf(stderr, "Failed to create RSA signature for %s. Error %d\n", pers, rval); goto sign_exit; } memcpy(signature, buf, 256); sign_exit: mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); return rval; } /* end of create_rsa_signature */ /******************************************************************************* * verify_rsa_signature (memory buffer content) * Verify RSASSA-PSS/SHA-256 signature for memory buffer * using RSA Public Key * INPUT: * pub_key Public Key buffer * ilen Public Key buffer length * input memory buffer * ilen buffer length * pers personalization string for seeding the RNG. * signature RSA-2048 signature * OUTPUT: * none * RETURN: * 0 on success */ int verify_rsa_signature(const unsigned char *pub_key, size_t klen, const unsigned char *input, size_t ilen, const char *pers, uint8_t *signature) { mbedtls_entropy_context entropy; mbedtls_ctr_drbg_context ctr_drbg; mbedtls_pk_context pk_ctx; unsigned char hash[32]; int rval; unsigned char *pkey = (unsigned char *)pub_key; /* Not sure this is required, * but it's safer to start with empty buffer */ memset(hash, 0, sizeof(hash)); mbedtls_pk_init(&pk_ctx); mbedtls_ctr_drbg_init(&ctr_drbg); mbedtls_entropy_init(&entropy); /* Seed the random number generator */ rval = mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, (const unsigned char *)pers, strlen(pers)); if (rval != 0) { fprintf(stderr, " Failed in ctr_drbg_init call (%d)!\n", rval); goto verify_exit; } /* Check ability to read the public key */ rval = mbedtls_pk_parse_subpubkey(&pkey, pub_key + klen, &pk_ctx); if (rval != 0) { fprintf(stderr, " Failed in pk_parse_public_key (%#x)!\n", rval); goto verify_exit; } /* Set the padding type for the new PK context */ mbedtls_rsa_set_padding(mbedtls_pk_rsa(pk_ctx), MBEDTLS_RSA_PKCS_V21, MBEDTLS_MD_SHA256); /* Compute the SHA256 hash for the input buffer */ mbedtls_sha256_ret(input, ilen, hash, 0); rval = mbedtls_rsa_rsassa_pss_verify(mbedtls_pk_rsa(pk_ctx), mbedtls_ctr_drbg_random, &ctr_drbg, MBEDTLS_RSA_PUBLIC, MBEDTLS_MD_SHA256, 0, hash, signature); if (rval != 0) fprintf(stderr, "Failed to verify signature (%d)!\n", rval); verify_exit: mbedtls_pk_free(&pk_ctx); mbedtls_ctr_drbg_free(&ctr_drbg); mbedtls_entropy_free(&entropy); return rval; } /* end of verify_rsa_signature */ /******************************************************************************* * image_encrypt * Encrypt image buffer using AES-256-CBC scheme. * The resulting image is saved into opts.sec_opts->encrypted_image * and the adjusted image size into opts.sec_opts->enc_image_sz * First AES_BLOCK_SZ bytes of the output image contain IV * INPUT: * buf Source buffer to encrypt * blen Source buffer length * OUTPUT: * none * RETURN: * 0 on success */ int image_encrypt(uint8_t *buf, uint32_t blen) { struct timeval tv; char *ptmp = (char *)&tv; unsigned char digest[32]; unsigned char IV[AES_BLOCK_SZ]; int i, k; mbedtls_aes_context aes_ctx; int rval = -1; uint8_t *test_img = 0; if (AES_BLOCK_SZ > 32) { fprintf(stderr, "Unsupported AES block size %d\n", AES_BLOCK_SZ); return rval; } mbedtls_aes_init(&aes_ctx); memset(IV, 0, AES_BLOCK_SZ); memset(digest, 0, 32); /* Generate initialization vector and init the AES engine * Use file name XOR current time and finally SHA-256 * [0...AES_BLOCK_SZ-1] */ k = strlen(opts.sec_opts->aes_key_file); if (k > AES_BLOCK_SZ) k = AES_BLOCK_SZ; memcpy(IV, opts.sec_opts->aes_key_file, k); gettimeofday(&tv, 0); for (i = 0, k = 0; i < AES_BLOCK_SZ; i++, k = (k+1) % sizeof(struct timeval)) IV[i] ^= ptmp[k]; /* compute SHA-256 digest of the results * and use it as the init vector (IV) */ mbedtls_sha256_ret(IV, AES_BLOCK_SZ, digest, 0); memcpy(IV, digest, AES_BLOCK_SZ); mbedtls_aes_setkey_enc(&aes_ctx, opts.sec_opts->aes_key, AES_KEY_BIT_LEN); /* The output image has to include extra space for IV * and to be aligned to the AES block size. * The input image buffer has to be already aligned to AES_BLOCK_SZ * and padded with zeroes */ opts.sec_opts->enc_image_sz = (blen + 2 * AES_BLOCK_SZ - 1) & ~(AES_BLOCK_SZ - 1); opts.sec_opts->encrypted_image = calloc(opts.sec_opts->enc_image_sz, 1); if (opts.sec_opts->encrypted_image == 0) { fprintf(stderr, "Failed to allocate encrypted image!\n"); goto encrypt_exit; } /* Put IV into the output buffer next to the encrypted image * Since the IV is modified by the encryption function, * this should be done now */ memcpy(opts.sec_opts->encrypted_image + opts.sec_opts->enc_image_sz - AES_BLOCK_SZ, IV, AES_BLOCK_SZ); rval = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_ENCRYPT, opts.sec_opts->enc_image_sz - AES_BLOCK_SZ, IV, buf, opts.sec_opts->encrypted_image); if (rval != 0) { fprintf(stderr, "Failed to encrypt the image! Error %d\n", rval); goto encrypt_exit; } mbedtls_aes_free(&aes_ctx); /* Try to decrypt the image and compare it with the original data */ mbedtls_aes_init(&aes_ctx); mbedtls_aes_setkey_dec(&aes_ctx, opts.sec_opts->aes_key, AES_KEY_BIT_LEN); test_img = calloc(opts.sec_opts->enc_image_sz - AES_BLOCK_SZ, 1); if (test_img == 0) { fprintf(stderr, "Failed to allocate test image!d\n"); rval = -1; goto encrypt_exit; } memcpy(IV, opts.sec_opts->encrypted_image + opts.sec_opts->enc_image_sz - AES_BLOCK_SZ, AES_BLOCK_SZ); rval = mbedtls_aes_crypt_cbc(&aes_ctx, MBEDTLS_AES_DECRYPT, opts.sec_opts->enc_image_sz - AES_BLOCK_SZ, IV, opts.sec_opts->encrypted_image, test_img); if (rval != 0) { fprintf(stderr, "Failed to decrypt the image! Error %d\n", rval); goto encrypt_exit; } for (i = 0; i < blen; i++) { if (buf[i] != test_img[i]) { fprintf(stderr, "Failed to compare the image after"); fprintf(stderr, " decryption! Byte count is %d\n", i); rval = -1; goto encrypt_exit; } } encrypt_exit: mbedtls_aes_free(&aes_ctx); if (test_img) free(test_img); return rval; } /* end of image_encrypt */ /******************************************************************************* * verify_secure_header_signatures * Verify CSK array, header and image signatures and print results * INPUT: * main_hdr Main header * sec_ext Secure extension * OUTPUT: * none * RETURN: * 0 on success */ int verify_secure_header_signatures(header_t *main_hdr, sec_entry_t *sec_ext) { uint8_t *image = (uint8_t *)main_hdr + main_hdr->prolog_size; uint8_t signature[RSA_SIGN_BYTE_LEN]; int rval = -1; /* Save headers signature and reset it in the secure header */ memcpy(signature, sec_ext->header_sign, RSA_SIGN_BYTE_LEN); memset(sec_ext->header_sign, 0, RSA_SIGN_BYTE_LEN); fprintf(stdout, "\nCheck RSA Signatures\n"); fprintf(stdout, "#########################\n"); fprintf(stdout, "CSK Block Signature: "); if (verify_rsa_signature(sec_ext->kak_key, MAX_RSA_DER_BYTE_LEN, &sec_ext->csk_keys[0][0], sizeof(sec_ext->csk_keys), "CSK Block Signature: ", sec_ext->csk_sign) != 0) { fprintf(stdout, "ERROR\n"); goto ver_error; } fprintf(stdout, "OK\n"); if (opts.key_index != -1) { fprintf(stdout, "Image Signature: "); if (verify_rsa_signature(sec_ext->csk_keys[opts.key_index], MAX_RSA_DER_BYTE_LEN, image, main_hdr->boot_image_size, "Image Signature: ", sec_ext->image_sign) != 0) { fprintf(stdout, "ERROR\n"); goto ver_error; } fprintf(stdout, "OK\n"); fprintf(stdout, "Header Signature: "); if (verify_rsa_signature(sec_ext->csk_keys[opts.key_index], MAX_RSA_DER_BYTE_LEN, (uint8_t *)main_hdr, main_hdr->prolog_size, "Header Signature: ", signature) != 0) { fprintf(stdout, "ERROR\n"); goto ver_error; } fprintf(stdout, "OK\n"); } else { fprintf(stdout, "SKIP Image and Header Signatures"); fprintf(stdout, " check (undefined key index)\n"); } rval = 0; ver_error: memcpy(sec_ext->header_sign, signature, RSA_SIGN_BYTE_LEN); return rval; } /******************************************************************************* * verify_and_copy_file_name_entry * INPUT: * element_name * element * OUTPUT: * copy_to * RETURN: * 0 on success */ int verify_and_copy_file_name_entry(const char *element_name, const char *element, char *copy_to) { int element_length = strlen(element); if (element_length >= MAX_FILENAME) { fprintf(stderr, "The file name %s for %s is too long (%d). ", element, element_name, element_length); fprintf(stderr, "Maximum allowed %d characters!\n", MAX_FILENAME); return -1; } else if (element_length == 0) { fprintf(stderr, "The file name for %s is empty!\n", element_name); return -1; } memcpy(copy_to, element, element_length); return 0; } /******************************************************************************* * parse_sec_config_file * Read the secure boot configuration from a file * into internal structures * INPUT: * filename File name * OUTPUT: * none * RETURN: * 0 on success */ int parse_sec_config_file(char *filename) { config_t sec_cfg; int array_sz, element, rval = -1; const char *cfg_string; int32_t cfg_int32; const config_setting_t *csk_array, *control_array; sec_options *sec_opt = 0; config_init(&sec_cfg); if (config_read_file(&sec_cfg, filename) != CONFIG_TRUE) { fprintf(stderr, "Failed to read data from config file "); fprintf(stderr, "%s\n\t%s at line %d\n", filename, config_error_text(&sec_cfg), config_error_line(&sec_cfg)); goto exit_parse; } sec_opt = (sec_options *)calloc(sizeof(sec_options), 1); if (sec_opt == 0) { fprintf(stderr, "Cannot allocate memory for secure boot options!\n"); goto exit_parse; } /* KAK file name */ if (config_lookup_string(&sec_cfg, "kak_key_file", &cfg_string) != CONFIG_TRUE) { fprintf(stderr, "The \"kak_key_file\" undefined!\n"); goto exit_parse; } if (verify_and_copy_file_name_entry("kak_key_file", cfg_string, sec_opt->kak_key_file)) goto exit_parse; /* AES file name - can be empty/undefined */ if (config_lookup_string(&sec_cfg, "aes_key_file", &cfg_string) == CONFIG_TRUE) { if (verify_and_copy_file_name_entry("aes_key_file", cfg_string, sec_opt->aes_key_file)) goto exit_parse; } /* CSK file names array */ csk_array = config_lookup(&sec_cfg, "csk_key_file"); if (csk_array == NULL) { fprintf(stderr, "The \"csk_key_file\" undefined!\n"); goto exit_parse; } array_sz = config_setting_length(csk_array); if (array_sz > CSK_ARR_SZ) { fprintf(stderr, "The \"csk_key_file\" array is too big! "); fprintf(stderr, "Only first %d elements will be used\n", CSK_ARR_SZ); array_sz = CSK_ARR_SZ; } else if (array_sz == 0) { fprintf(stderr, "The \"csk_key_file\" array is empty!\n"); goto exit_parse; } for (element = 0; element < array_sz; element++) { cfg_string = config_setting_get_string_elem(csk_array, element); if (verify_and_copy_file_name_entry( "csk_key_file", cfg_string, sec_opt->csk_key_file[element])) { fprintf(stderr, "Bad csk_key_file[%d] entry!\n", element); goto exit_parse; } } /* JTAG options */ if (config_lookup_bool(&sec_cfg, "jtag.enable", &cfg_int32) != CONFIG_TRUE) { fprintf(stderr, "Error obtaining \"jtag.enable\" element. "); fprintf(stderr, "Using default - FALSE\n"); cfg_int32 = 0; } sec_opt->jtag_enable = cfg_int32; if (config_lookup_int(&sec_cfg, "jtag.delay", &cfg_int32) != CONFIG_TRUE) { fprintf(stderr, "Error obtaining \"jtag.delay\" element. "); fprintf(stderr, "Using default - 0us\n"); cfg_int32 = 0; } sec_opt->jtag_delay = cfg_int32; /* eFUSE option */ if (config_lookup_bool(&sec_cfg, "efuse_disable", &cfg_int32) != CONFIG_TRUE) { fprintf(stderr, "Error obtaining \"efuse_disable\" element. "); fprintf(stderr, "Using default - TRUE\n"); cfg_int32 = 1; } sec_opt->efuse_disable = cfg_int32; /* Box ID option */ if (config_lookup_int(&sec_cfg, "box_id", &cfg_int32) != CONFIG_TRUE) { fprintf(stderr, "Error obtaining \"box_id\" element. "); fprintf(stderr, "Using default - 0x0\n"); cfg_int32 = 0; } sec_opt->box_id = cfg_int32; /* Flash ID option */ if (config_lookup_int(&sec_cfg, "flash_id", &cfg_int32) != CONFIG_TRUE) { fprintf(stderr, "Error obtaining \"flash_id\" element. "); fprintf(stderr, "Using default - 0x0\n"); cfg_int32 = 0; } sec_opt->flash_id = cfg_int32; /* CSK index option */ if (config_lookup_int(&sec_cfg, "csk_key_index", &cfg_int32) != CONFIG_TRUE) { fprintf(stderr, "Error obtaining \"flash_id\" element. "); fprintf(stderr, "Using default - 0x0\n"); cfg_int32 = 0; } sec_opt->csk_index = cfg_int32; /* Secure boot control array */ control_array = config_lookup(&sec_cfg, "control"); if (control_array != NULL) { array_sz = config_setting_length(control_array); if (array_sz == 0) fprintf(stderr, "The \"control\" array is empty!\n"); } else { fprintf(stderr, "The \"control\" is undefined!\n"); array_sz = 0; } for (element = 0; element < CP_CTRL_EL_ARRAY_SZ; element++) { sec_opt->cp_ctrl_arr[element] = config_setting_get_int_elem(control_array, element * 2); sec_opt->cp_efuse_arr[element] = config_setting_get_int_elem(control_array, element * 2 + 1); } opts.sec_opts = sec_opt; rval = 0; exit_parse: config_destroy(&sec_cfg); if (sec_opt && (rval != 0)) free(sec_opt); return rval; } /* end of parse_sec_config_file */ int format_sec_ext(char *filename, FILE *out_fd) { ext_header_t header; sec_entry_t sec_ext; int index; int written; #define DER_BUF_SZ 1600 /* First, parse the configuration file */ if (parse_sec_config_file(filename)) { fprintf(stderr, "failed parsing configuration file %s\n", filename); return 1; } /* Everything except signatures can be created at this stage */ header.type = EXT_TYPE_SECURITY; header.offset = 0; header.size = sizeof(sec_entry_t); header.reserved = 0; /* Bring up RSA context and read private keys from their files */ for (index = 0; index < (CSK_ARR_SZ + 1); index++) { /* for every private key file */ mbedtls_pk_context *pk_ctx = (index == CSK_ARR_SZ) ? &opts.sec_opts->kak_pk : &opts.sec_opts->csk_pk[index]; char *fname = (index == CSK_ARR_SZ) ? opts.sec_opts->kak_key_file : opts.sec_opts->csk_key_file[index]; uint8_t *out_der_key = (index == CSK_ARR_SZ) ? sec_ext.kak_key : sec_ext.csk_keys[index]; size_t output_len; unsigned char output_buf[DER_BUF_SZ]; unsigned char *der_buf_start; /* Handle invalid/reserved file names */ if (strncmp(CSK_ARR_EMPTY_FILE, fname, strlen(CSK_ARR_EMPTY_FILE)) == 0) { if (opts.sec_opts->csk_index == index) { fprintf(stderr, "CSK file with index %d cannot be %s\n", index, CSK_ARR_EMPTY_FILE); return 1; } else if (index == CSK_ARR_SZ) { fprintf(stderr, "KAK file name cannot be %s\n", CSK_ARR_EMPTY_FILE); return 1; } /* this key will be empty in CSK array */ continue; } mbedtls_pk_init(pk_ctx); /* Read the private RSA key into the context * and verify it (no password) */ if (mbedtls_pk_parse_keyfile(pk_ctx, fname, "") != 0) { fprintf(stderr, "Cannot read RSA private key file %s\n", fname); return 1; } /* Create a public key out of private one * and store it in DER format */ output_len = mbedtls_pk_write_pubkey_der(pk_ctx, output_buf, DER_BUF_SZ); if (output_len < 0) { fprintf(stderr, "Failed to create DER coded PUB key (%s)\n", fname); return 1; } /* Data in the output buffer is aligned to the buffer end */ der_buf_start = output_buf + sizeof(output_buf) - output_len; /* In the header DER data is aligned * to the start of appropriate field */ bzero(out_der_key, MAX_RSA_DER_BYTE_LEN); memcpy(out_der_key, der_buf_start, output_len); } /* for every private key file */ /* The CSK block signature can be created here */ if (create_rsa_signature(&opts.sec_opts->kak_pk, &sec_ext.csk_keys[0][0], sizeof(sec_ext.csk_keys), opts.sec_opts->csk_key_file[ opts.sec_opts->csk_index], sec_ext.csk_sign) != 0) { fprintf(stderr, "Failed to sign CSK keys block!\n"); return 1; } /* Check that everything is correct */ if (verify_rsa_signature(sec_ext.kak_key, MAX_RSA_DER_BYTE_LEN, &sec_ext.csk_keys[0][0], sizeof(sec_ext.csk_keys), opts.sec_opts->kak_key_file, sec_ext.csk_sign) != 0) { fprintf(stderr, "Failed to verify CSK keys block signature!\n"); return 1; } /* AES encryption stuff */ if (strlen(opts.sec_opts->aes_key_file) != 0) { FILE *in_fd; in_fd = fopen(opts.sec_opts->aes_key_file, "rb"); if (in_fd == NULL) { fprintf(stderr, "Failed to open AES key file %s\n", opts.sec_opts->aes_key_file); return 1; } /* Read the AES key in ASCII format byte by byte */ for (index = 0; index < AES_KEY_BYTE_LEN; index++) { if (fscanf(in_fd, "%02hhx", opts.sec_opts->aes_key + index) != 1) { fprintf(stderr, "Failed to read AES key byte %d ", index); fprintf(stderr, "from file %s\n", opts.sec_opts->aes_key_file); fclose(in_fd); return 1; } } fclose(in_fd); sec_ext.encrypt_en = 1; } else { sec_ext.encrypt_en = 0; } /* Fill the rest of the trusted boot extension fields */ sec_ext.box_id = opts.sec_opts->box_id; sec_ext.flash_id = opts.sec_opts->flash_id; sec_ext.efuse_dis = opts.sec_opts->efuse_disable; sec_ext.jtag_delay = opts.sec_opts->jtag_delay; sec_ext.jtag_en = opts.sec_opts->jtag_enable; memcpy(sec_ext.cp_ctrl_arr, opts.sec_opts->cp_ctrl_arr, sizeof(uint32_t) * CP_CTRL_EL_ARRAY_SZ); memcpy(sec_ext.cp_efuse_arr, opts.sec_opts->cp_efuse_arr, sizeof(uint32_t) * CP_CTRL_EL_ARRAY_SZ); /* Write the resulting extension to file * (image and header signature fields are still empty) */ /* Write extension header */ written = fwrite(&header, sizeof(ext_header_t), 1, out_fd); if (written != 1) { fprintf(stderr, "Failed to write SEC extension header to the file\n"); return 1; } /* Write extension body */ written = fwrite(&sec_ext, sizeof(sec_entry_t), 1, out_fd); if (written != 1) { fprintf(stderr, "Failed to write SEC extension body to the file\n"); return 1; } return 0; } /******************************************************************************* * finalize_secure_ext * Make final changes to secure extension - calculate image and header * signatures and encrypt the image if needed. * The main header checksum and image size fields updated accordingly * INPUT: * header Main header * prolog_buf the entire prolog buffer * prolog_size prolog buffer length * image_buf buffer containing the input binary image * image_size image buffer size. * OUTPUT: * none * RETURN: * 0 on success */ int finalize_secure_ext(header_t *header, uint8_t *prolog_buf, uint32_t prolog_size, uint8_t *image_buf, int image_size) { int cur_ext, offset; uint8_t *final_image = image_buf; uint32_t final_image_sz = image_size; uint8_t hdr_sign[RSA_SIGN_BYTE_LEN]; sec_entry_t *sec_ext = 0; /* Find the Trusted Boot Header between available extensions */ for (cur_ext = 0, offset = sizeof(header_t); cur_ext < header->ext_count; cur_ext++) { ext_header_t *ext_hdr = (ext_header_t *)(prolog_buf + offset); if (ext_hdr->type == EXT_TYPE_SECURITY) { sec_ext = (sec_entry_t *)(prolog_buf + offset + sizeof(ext_header_t) + ext_hdr->offset); break; } offset += sizeof(ext_header_t); /* If offset is Zero, the extension follows its header */ if (ext_hdr->offset == 0) offset += ext_hdr->size; } if (sec_ext == 0) { fprintf(stderr, "Error: No Trusted Boot extension found!\n"); return -1; } if (sec_ext->encrypt_en) { /* Encrypt the image if needed */ fprintf(stdout, "Encrypting the image...\n"); if (image_encrypt(image_buf, image_size) != 0) { fprintf(stderr, "Failed to encrypt the image!\n"); return -1; } /* Image size and checksum should be updated after encryption. * This way the image could be verified by the BootROM * before decryption. */ final_image = opts.sec_opts->encrypted_image; final_image_sz = opts.sec_opts->enc_image_sz; header->boot_image_size = final_image_sz; header->boot_image_checksum = checksum32((uint32_t *)final_image, final_image_sz); } /* AES encryption */ /* Create the image signature first, since it will be later * signed along with the header signature */ if (create_rsa_signature(&opts.sec_opts->csk_pk[ opts.sec_opts->csk_index], final_image, final_image_sz, opts.sec_opts->csk_key_file[ opts.sec_opts->csk_index], sec_ext->image_sign) != 0) { fprintf(stderr, "Failed to sign image!\n"); return -1; } /* Check that the image signature is correct */ if (verify_rsa_signature(sec_ext->csk_keys[opts.sec_opts->csk_index], MAX_RSA_DER_BYTE_LEN, final_image, final_image_sz, opts.sec_opts->csk_key_file[ opts.sec_opts->csk_index], sec_ext->image_sign) != 0) { fprintf(stderr, "Failed to verify image signature!\n"); return -1; } /* Sign the headers and all the extensions block * when the header signature field is empty */ if (create_rsa_signature(&opts.sec_opts->csk_pk[ opts.sec_opts->csk_index], prolog_buf, prolog_size, opts.sec_opts->csk_key_file[ opts.sec_opts->csk_index], hdr_sign) != 0) { fprintf(stderr, "Failed to sign header!\n"); return -1; } /* Check that the header signature is correct */ if (verify_rsa_signature(sec_ext->csk_keys[opts.sec_opts->csk_index], MAX_RSA_DER_BYTE_LEN, prolog_buf, prolog_size, opts.sec_opts->csk_key_file[ opts.sec_opts->csk_index], hdr_sign) != 0) { fprintf(stderr, "Failed to verify header signature!\n"); return -1; } /* Finally, copy the header signature into the trusted boot extension */ memcpy(sec_ext->header_sign, hdr_sign, RSA_SIGN_BYTE_LEN); return 0; } #endif /* CONFIG_MVEBU_SECURE_BOOT */ #define FMT_HEX 0 #define FMT_DEC 1 #define FMT_BIN 2 #define FMT_NONE 3 void do_print_field(unsigned int value, char *name, int start, int size, int format) { fprintf(stdout, "[0x%05x : 0x%05x] %-26s", start, start + size - 1, name); switch (format) { case FMT_HEX: printf("0x%x\n", value); break; case FMT_DEC: printf("%d\n", value); break; default: printf("\n"); break; } } #define print_field(st, type, field, hex, base) \ do_print_field((int)st->field, #field, \ base + offsetof(type, field), sizeof(st->field), hex) int print_header(uint8_t *buf, int base) { header_t *main_hdr; main_hdr = (header_t *)buf; fprintf(stdout, "########### Header ##############\n"); print_field(main_hdr, header_t, magic, FMT_HEX, base); print_field(main_hdr, header_t, prolog_size, FMT_DEC, base); print_field(main_hdr, header_t, prolog_checksum, FMT_HEX, base); print_field(main_hdr, header_t, boot_image_size, FMT_DEC, base); print_field(main_hdr, header_t, boot_image_checksum, FMT_HEX, base); print_field(main_hdr, header_t, rsrvd0, FMT_HEX, base); print_field(main_hdr, header_t, load_addr, FMT_HEX, base); print_field(main_hdr, header_t, exec_addr, FMT_HEX, base); print_field(main_hdr, header_t, uart_cfg, FMT_HEX, base); print_field(main_hdr, header_t, baudrate, FMT_HEX, base); print_field(main_hdr, header_t, ext_count, FMT_DEC, base); print_field(main_hdr, header_t, aux_flags, FMT_HEX, base); print_field(main_hdr, header_t, io_arg_0, FMT_HEX, base); print_field(main_hdr, header_t, io_arg_1, FMT_HEX, base); print_field(main_hdr, header_t, io_arg_2, FMT_HEX, base); print_field(main_hdr, header_t, io_arg_3, FMT_HEX, base); print_field(main_hdr, header_t, rsrvd1, FMT_HEX, base); print_field(main_hdr, header_t, rsrvd2, FMT_HEX, base); print_field(main_hdr, header_t, rsrvd3, FMT_HEX, base); return sizeof(header_t); } int print_ext_hdr(ext_header_t *ext_hdr, int base) { print_field(ext_hdr, ext_header_t, type, FMT_HEX, base); print_field(ext_hdr, ext_header_t, offset, FMT_HEX, base); print_field(ext_hdr, ext_header_t, reserved, FMT_HEX, base); print_field(ext_hdr, ext_header_t, size, FMT_DEC, base); return base + sizeof(ext_header_t); } void print_sec_ext(ext_header_t *ext_hdr, int base) { sec_entry_t *sec_entry; uint32_t new_base; fprintf(stdout, "\n########### Secure extension ###########\n"); new_base = print_ext_hdr(ext_hdr, base); sec_entry = (sec_entry_t *)(ext_hdr + 1); do_print_field(0, "KAK key", new_base, MAX_RSA_DER_BYTE_LEN, FMT_NONE); new_base += MAX_RSA_DER_BYTE_LEN; print_field(sec_entry, sec_entry_t, jtag_delay, FMT_DEC, base); print_field(sec_entry, sec_entry_t, box_id, FMT_HEX, base); print_field(sec_entry, sec_entry_t, flash_id, FMT_HEX, base); print_field(sec_entry, sec_entry_t, encrypt_en, FMT_DEC, base); print_field(sec_entry, sec_entry_t, efuse_dis, FMT_DEC, base); new_base += 6 * sizeof(uint32_t); do_print_field(0, "header signature", new_base, RSA_SIGN_BYTE_LEN, FMT_NONE); new_base += RSA_SIGN_BYTE_LEN; do_print_field(0, "image signature", new_base, RSA_SIGN_BYTE_LEN, FMT_NONE); new_base += RSA_SIGN_BYTE_LEN; do_print_field(0, "CSK keys", new_base, CSK_ARR_SZ * MAX_RSA_DER_BYTE_LEN, FMT_NONE); new_base += CSK_ARR_SZ * MAX_RSA_DER_BYTE_LEN; do_print_field(0, "CSK block signature", new_base, RSA_SIGN_BYTE_LEN, FMT_NONE); new_base += RSA_SIGN_BYTE_LEN; do_print_field(0, "control", new_base, CP_CTRL_EL_ARRAY_SZ * 2, FMT_NONE); } void print_bin_ext(ext_header_t *ext_hdr, int base) { fprintf(stdout, "\n########### Binary extension ###########\n"); base = print_ext_hdr(ext_hdr, base); do_print_field(0, "binary image", base, ext_hdr->size, FMT_NONE); } int print_extension(void *buf, int base, int count, int ext_size) { ext_header_t *ext_hdr = buf; int pad = ext_size; int curr_size; while (count--) { if (ext_hdr->type == EXT_TYPE_BINARY) print_bin_ext(ext_hdr, base); else if (ext_hdr->type == EXT_TYPE_SECURITY) print_sec_ext(ext_hdr, base); curr_size = sizeof(ext_header_t) + ext_hdr->size; base += curr_size; pad -= curr_size; ext_hdr = (ext_header_t *)((uintptr_t)ext_hdr + curr_size); } if (pad) do_print_field(0, "padding", base, pad, FMT_NONE); return ext_size; } int parse_image(uint8_t *buf, int size) { int base = 0; int ret = 1; header_t *main_hdr; uint32_t checksum, prolog_checksum; fprintf(stdout, "################### Prolog Start ######################\n\n"); main_hdr = (header_t *)buf; base += print_header(buf, base); if (main_hdr->ext_count) base += print_extension(buf + base, base, main_hdr->ext_count, main_hdr->prolog_size - sizeof(header_t)); if (base < main_hdr->prolog_size) { fprintf(stdout, "\n########### Padding ##############\n"); do_print_field(0, "prolog padding", base, main_hdr->prolog_size - base, FMT_HEX); base = main_hdr->prolog_size; } fprintf(stdout, "\n################### Prolog End ######################\n"); fprintf(stdout, "\n################### Boot image ######################\n"); do_print_field(0, "boot image", base, size - base - 4, FMT_NONE); fprintf(stdout, "################### Image end ########################\n"); /* Check sanity for certain values */ printf("\nChecking values:\n"); if (main_hdr->magic == MAIN_HDR_MAGIC) { fprintf(stdout, "Headers magic: OK!\n"); } else { fprintf(stderr, "\n****** ERROR: HEADER MAGIC 0x%08x != 0x%08x\n", main_hdr->magic, MAIN_HDR_MAGIC); goto error; } /* headers checksum */ /* clear the checksum field in header to calculate checksum */ prolog_checksum = main_hdr->prolog_checksum; main_hdr->prolog_checksum = 0; checksum = checksum32((uint32_t *)buf, main_hdr->prolog_size); if (checksum == prolog_checksum) { fprintf(stdout, "Headers checksum: OK!\n"); } else { fprintf(stderr, "\n***** ERROR: BAD HEADER CHECKSUM 0x%08x != 0x%08x\n", checksum, prolog_checksum); goto error; } /* boot image checksum */ checksum = checksum32((uint32_t *)(buf + main_hdr->prolog_size), main_hdr->boot_image_size); if (checksum == main_hdr->boot_image_checksum) { fprintf(stdout, "Image checksum: OK!\n"); } else { fprintf(stderr, "\n****** ERROR: BAD IMAGE CHECKSUM 0x%08x != 0x%08x\n", checksum, main_hdr->boot_image_checksum); goto error; } #ifdef CONFIG_MVEBU_SECURE_BOOT /* RSA signatures */ if (main_hdr->ext_count) { uint8_t ext_num = main_hdr->ext_count; ext_header_t *ext_hdr = (ext_header_t *)(main_hdr + 1); unsigned char hash[32]; int i; while (ext_num--) { if (ext_hdr->type == EXT_TYPE_SECURITY) { sec_entry_t *sec_entry = (sec_entry_t *)(ext_hdr + 1); ret = verify_secure_header_signatures( main_hdr, sec_entry); if (ret != 0) { fprintf(stderr, "\n****** FAILED TO VERIFY "); fprintf(stderr, "RSA SIGNATURES ********\n"); goto error; } mbedtls_sha256_ret(sec_entry->kak_key, MAX_RSA_DER_BYTE_LEN, hash, 0); fprintf(stdout, ">>>>>>>>>> KAK KEY HASH >>>>>>>>>>\n"); fprintf(stdout, "SHA256: "); for (i = 0; i < 32; i++) fprintf(stdout, "%02X", hash[i]); fprintf(stdout, "\n<<<<<<<<< KAK KEY HASH <<<<<<<<<\n"); break; } ext_hdr = (ext_header_t *)((uint8_t *)(ext_hdr + 1) + ext_hdr->size); } } #endif ret = 0; error: return ret; } int format_bin_ext(char *filename, FILE *out_fd) { ext_header_t header; FILE *in_fd; int size, written; int aligned_size, pad_bytes; char c; in_fd = fopen(filename, "rb"); if (in_fd == NULL) { fprintf(stderr, "failed to open bin extension file %s\n", filename); return 1; } size = get_file_size(filename); if (size <= 0) { fprintf(stderr, "bin extension file size is bad\n"); return 1; } /* Align extension size to 8 bytes */ aligned_size = (size + 7) & (~7); pad_bytes = aligned_size - size; header.type = EXT_TYPE_BINARY; header.offset = 0; header.size = aligned_size; header.reserved = 0; /* Write header */ written = fwrite(&header, sizeof(ext_header_t), 1, out_fd); if (written != 1) { fprintf(stderr, "failed writing header to extension file\n"); return 1; } /* Write image */ while (size--) { c = getc(in_fd); fputc(c, out_fd); } while (pad_bytes--) fputc(0, out_fd); fclose(in_fd); return 0; } /* **************************************** * * Write all extensions (binary, secure * extensions) to file * * ****************************************/ int format_extensions(char *ext_filename) { FILE *out_fd; int ret = 0; out_fd = fopen(ext_filename, "wb"); if (out_fd == NULL) { fprintf(stderr, "failed to open extension output file %s", ext_filename); return 1; } if (strncmp(opts.bin_ext_file, "NA", MAX_FILENAME)) { if (format_bin_ext(opts.bin_ext_file, out_fd)) { ret = 1; goto error; } } #ifdef CONFIG_MVEBU_SECURE_BOOT if (strncmp(opts.sec_cfg_file, "NA", MAX_FILENAME)) { if (format_sec_ext(opts.sec_cfg_file, out_fd)) { ret = 1; goto error; } } #endif error: fflush(out_fd); fclose(out_fd); return ret; } void update_uart(header_t *header) { header->uart_cfg = 0; header->baudrate = 0; if (opts.disable_print) uart_set_mode(header->uart_cfg, UART_MODE_DISABLE); if (opts.baudrate) header->baudrate = (opts.baudrate / 1200); } /* **************************************** * * Write the image prolog, i.e. * main header and extensions, to file * * ****************************************/ int write_prolog(int ext_cnt, char *ext_filename, uint8_t *image_buf, int image_size, FILE *out_fd) { header_t *header; int main_hdr_size = sizeof(header_t); int prolog_size = main_hdr_size; FILE *ext_fd; char *buf; int written, read; int ret = 1; if (ext_cnt) prolog_size += get_file_size(ext_filename); prolog_size = ((prolog_size + PROLOG_ALIGNMENT) & (~(PROLOG_ALIGNMENT-1))); /* Allocate a zeroed buffer to zero the padding bytes */ buf = calloc(prolog_size, 1); if (buf == NULL) { fprintf(stderr, "Error: failed allocating checksum buffer\n"); return 1; } header = (header_t *)buf; header->magic = MAIN_HDR_MAGIC; header->prolog_size = prolog_size; header->load_addr = opts.load_addr; header->exec_addr = opts.exec_addr; header->io_arg_0 = opts.nfc_io_args; header->ext_count = ext_cnt; header->aux_flags = 0; header->boot_image_size = (image_size + 3) & (~0x3); header->boot_image_checksum = checksum32((uint32_t *)image_buf, image_size); update_uart(header); /* Populate buffer with main header and extensions */ if (ext_cnt) { ext_fd = fopen(ext_filename, "rb"); if (ext_fd == NULL) { fprintf(stderr, "Error: failed to open extensions file\n"); goto error; } read = fread(&buf[main_hdr_size], get_file_size(ext_filename), 1, ext_fd); if (read != 1) { fprintf(stderr, "Error: failed to open extensions file\n"); goto error; } #ifdef CONFIG_MVEBU_SECURE_BOOT /* Secure boot mode? */ if (opts.sec_opts != 0) { ret = finalize_secure_ext(header, (uint8_t *)buf, prolog_size, image_buf, image_size); if (ret != 0) { fprintf(stderr, "Error: failed to handle "); fprintf(stderr, "secure extension!\n"); goto error; } } /* secure boot mode */ #endif } /* Update the total prolog checksum */ header->prolog_checksum = checksum32((uint32_t *)buf, prolog_size); /* Now spill everything to output file */ written = fwrite(buf, prolog_size, 1, out_fd); if (written != 1) { fprintf(stderr, "Error: failed to write prolog to output file\n"); goto error; } ret = 0; error: free(buf); return ret; } int write_boot_image(uint8_t *buf, uint32_t image_size, FILE *out_fd) { int written; written = fwrite(buf, image_size, 1, out_fd); if (written != 1) { fprintf(stderr, "Error: Failed to write boot image\n"); goto error; } return 0; error: return 1; } int main(int argc, char *argv[]) { char in_file[MAX_FILENAME+1] = { 0 }; char out_file[MAX_FILENAME+1] = { 0 }; char ext_file[MAX_FILENAME+1] = { 0 }; FILE *in_fd = NULL; FILE *out_fd = NULL; int parse = 0; int ext_cnt = 0; int opt; int ret = 0; int image_size, file_size; uint8_t *image_buf = NULL; int read; size_t len; uint32_t nand_block_size_kb, mlc_nand; /* Create temporary file for building extensions * Use process ID for allowing multiple parallel runs */ snprintf(ext_file, MAX_FILENAME, "/tmp/ext_file-%x", getpid()); while ((opt = getopt(argc, argv, "hpms:i:l:e:a:b:u:n:t:c:k:")) != -1) { switch (opt) { case 'h': usage(); break; case 'l': opts.load_addr = strtoul(optarg, NULL, 0); break; case 'e': opts.exec_addr = strtoul(optarg, NULL, 0); break; case 'm': opts.disable_print = 1; break; case 'u': opts.baudrate = strtoul(optarg, NULL, 0); break; case 'b': strncpy(opts.bin_ext_file, optarg, MAX_FILENAME); ext_cnt++; break; case 'p': parse = 1; break; case 'n': nand_block_size_kb = strtoul(optarg, NULL, 0); opts.nfc_io_args |= (nand_block_size_kb / 64); break; case 't': mlc_nand = 0; if (!strncmp("MLC", optarg, 3)) mlc_nand = 1; opts.nfc_io_args |= (mlc_nand << 8); break; #ifdef CONFIG_MVEBU_SECURE_BOOT case 'c': /* SEC extension */ strncpy(opts.sec_cfg_file, optarg, MAX_FILENAME); ext_cnt++; break; case 'k': opts.key_index = strtoul(optarg, NULL, 0); break; #endif default: /* '?' */ usage_err("Unknown argument"); exit(EXIT_FAILURE); } } /* Check validity of inputes */ if (opts.load_addr % 8) usage_err("Load address must be 8 bytes aligned"); if (opts.baudrate % 1200) usage_err("Baudrate must be a multiple of 1200"); /* The remaining arguments are the input * and potentially output file */ /* Input file must exist so exit if not */ if (optind >= argc) usage_err("missing input file name"); len = strlen(argv[optind]); if (len > MAX_FILENAME) usage_err("file name too long"); memcpy(in_file, argv[optind], len); optind++; /* Output file must exist in non parse mode */ if (optind < argc) { len = strlen(argv[optind]); if (len > MAX_FILENAME) usage_err("file name too long"); memcpy(out_file, argv[optind], len); } else if (!parse) usage_err("missing output file name"); /* open the input file */ in_fd = fopen(in_file, "rb"); if (in_fd == NULL) { printf("Error: Failed to open input file %s\n", in_file); goto main_exit; } /* Read the input file to buffer * Always align the image to 16 byte boundary */ file_size = get_file_size(in_file); image_size = (file_size + AES_BLOCK_SZ - 1) & ~(AES_BLOCK_SZ - 1); image_buf = calloc(image_size, 1); if (image_buf == NULL) { fprintf(stderr, "Error: failed allocating input buffer\n"); return 1; } read = fread(image_buf, file_size, 1, in_fd); if (read != 1) { fprintf(stderr, "Error: failed to read input file\n"); goto main_exit; } /* Parse the input image and leave */ if (parse) { if (opts.key_index >= CSK_ARR_SZ) { fprintf(stderr, "Wrong key IDX value. Valid values 0 - %d\n", CSK_ARR_SZ - 1); goto main_exit; } ret = parse_image(image_buf, image_size); goto main_exit; } /* Create a blob file from all extensions */ if (ext_cnt) { ret = format_extensions(ext_file); if (ret) goto main_exit; } out_fd = fopen(out_file, "wb"); if (out_fd == NULL) { fprintf(stderr, "Error: Failed to open output file %s\n", out_file); goto main_exit; } ret = write_prolog(ext_cnt, ext_file, image_buf, image_size, out_fd); if (ret) goto main_exit; #ifdef CONFIG_MVEBU_SECURE_BOOT if (opts.sec_opts && (opts.sec_opts->encrypted_image != 0) && (opts.sec_opts->enc_image_sz != 0)) { ret = write_boot_image(opts.sec_opts->encrypted_image, opts.sec_opts->enc_image_sz, out_fd); } else #endif ret = write_boot_image(image_buf, image_size, out_fd); if (ret) goto main_exit; main_exit: if (in_fd) fclose(in_fd); if (out_fd) fclose(out_fd); if (image_buf) free(image_buf); unlink(ext_file); #ifdef CONFIG_MVEBU_SECURE_BOOT if (opts.sec_opts) { if (opts.sec_opts->encrypted_image) free(opts.sec_opts->encrypted_image); free(opts.sec_opts); } #endif exit(ret); }