1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759 |
- /*
- * Copyright (C) 2018 Marvell International Ltd.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- * https://spdx.org/licenses
- */
- #include <stdlib.h>
- #include <stdio.h>
- #include <stdint.h>
- #include <stddef.h>
- #include <string.h>
- #include <unistd.h>
- #include <sys/stat.h>
- #include <sys/time.h>
- #ifdef CONFIG_MVEBU_SECURE_BOOT
- #include <libconfig.h> /* for parsing config file */
- /* mbedTLS stuff */
- #include <mbedtls/version.h>
- #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 <mbedtls/error.h>
- #include <mbedtls/entropy.h>
- #include <mbedtls/ctr_drbg.h>
- #include <mbedtls/md.h>
- #include <mbedtls/pk.h>
- #include <mbedtls/sha256.h>
- #include <mbedtls/x509.h>
- #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] <input_file> [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);
- }
|