@@ -50,6 +50,7 @@ struct option cbootcmd[] = {
{"odmdata", 1, NULL, 'o'},
{"soc", 1, NULL, 's'},
{"update", 0, NULL, 'u'},
+ {"sign", 0, NULL, 'n'},
{0, 0, 0, 0},
};
@@ -80,9 +81,13 @@ usage(void)
printf(" -u|--update Copy input image data and update bct\n");
printf(" configs into new image file.\n");
printf(" This feature is only for tegra114/124/210.\n");
+ printf(" -n|--sign Sign input image data on specified\n");
+ printf(" offset and length. Then save image\n");
+ printf(" along with signature to output file\n");
printf(" configfile File with configuration information\n");
printf(" inputimage Input image name. This is required\n");
- printf(" if -u|--update option is used.\n");
+ printf(" if either -u|--update option or \n");
+ printf(" -n|--sign option is used.\n");
printf(" outputimage Output image name\n");
}
@@ -93,7 +98,7 @@ process_command_line(int argc, char *argv[], build_image_context *context)
context->generate_bct = 0;
- while ((c = getopt_long(argc, argv, "hdg:t:o:s:u", cbootcmd, NULL)) != -1) {
+ while ((c = getopt_long(argc, argv, "hdg:t:o:s:un", cbootcmd, NULL)) != -1) {
switch (c) {
case 'h':
help_only = 1;
@@ -146,6 +151,10 @@ process_command_line(int argc, char *argv[], build_image_context *context)
context->update_image = 1;
num_filenames = 3;
break;
+ case 'n':
+ context->sign_image = 1;
+ num_filenames = 3;
+ break;
}
}
@@ -180,6 +189,12 @@ process_command_line(int argc, char *argv[], build_image_context *context)
context->input_image_filename = argv[optind++];
}
+ /* Record the input image filename if signing image */
+ if (context->sign_image)
+ {
+ context->input_image_filename = argv[optind++];
+ }
+
/* Record the output filename */
context->output_image_filename = argv[optind++];
@@ -279,6 +294,16 @@ main(int argc, char *argv[])
context.output_image_filename);
goto fail;
}
+ else if (context.sign_image) {
+ process_config_file(&context, 1);
+ if (save_rsa_signed_image(&context))
+ printf("Error writing image file %s.\n",
+ context.output_image_filename);
+ else
+ printf("Image file %s has been successfully generated!\n",
+ context.output_image_filename);
+ goto fail;
+ }
/* If we aren't generating the bct, read in config file */
else if (context.generate_bct == 0)
process_config_file(&context, 1);
@@ -54,6 +54,12 @@
#define NVBOOT_CONFIG_TABLE_SIZE_MAX (10 * 1024)
+#define INVALID_VALUE (0x01 << 31)
+#define DATA_BLOCK_SIZE 0x8000
+
+#define is_overlapping(s1, l1, s2, l2) \
+ (((s1 + l1) > s2) && (s1 < (s2 + l2)))
+
/*
* Enumerations
*/
@@ -128,6 +134,12 @@ typedef struct build_image_context_rec
u_int8_t secure_jtag_control; /* The flag for enabling jtag control */
u_int32_t secure_debug_control; /* The flag for enabling jtag control */
u_int8_t update_image; /* The flag for updating image */
+ u_int8_t sign_image; /* The flag for sign image */
+ u_int32_t sign_offset;
+ u_int32_t sign_length;
+ u_int32_t signature_offset;
+ u_int32_t modulus_offset;
+ void *rsa_signature;
} build_image_context;
/* Function prototypes */
@@ -258,7 +258,8 @@ sign_data_block(u_int8_t *source,
signature);
}
-static u_int8_t *pkc_get_pubkey(void *key)
+u_int8_t
+*pkc_get_pubkey(void *key)
{
NvTegraPkcKey *pPkcKey = (NvTegraPkcKey *)key;
return (u_int8_t *)pPkcKey->Modulus.Number;
@@ -273,6 +274,11 @@ pkc_sign_buffer(void *key, u_int8_t *buffer, u_int32_t size, u_int8_t **pSign)
NvTegraPkcKey *pPkcKey = (NvTegraPkcKey *)key;
+ if (pPkcKey == NULL) {
+ printf("Error: No valid pkc keys found\n");
+ return -ENODATA;
+ }
+
/* TODO: define constant for ssk.len */
ssk.len = (UINT)pPkcKey->Modulus.Digits; /* length in digits of modulus in term of 32 bits */
ssk.modulus = malloc(NBYTE(ssk.len));
@@ -94,6 +94,9 @@ int pkckey_set(u_int8_t *key_buffer,
void **pkckey,
int save);
+u_int8_t
+*pkc_get_pubkey(void *key);
+
int
pkc_sign_buffer(void *key,
u_int8_t *buffer,
@@ -1134,3 +1134,235 @@ int resign_bl(build_image_context *context)
free (image);
return ret;
}
+
+int rsa_sign_image(build_image_context *context)
+{
+ int ret;
+ struct stat stats;
+ u_int8_t *image = NULL;
+ u_int32_t image_actual_size; /* In bytes */
+ u_int8_t *sign;
+
+ if (stat(context->input_image_filename, &stats) != 0) {
+ printf("Error: Unable to query info on input file %s\n",
+ context->input_image_filename);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (enable_debug) {
+ printf(" image size %#x\n"
+ " sign_offset %#x, sign_length %#x\n"
+ " signature location %#x\n",
+ (unsigned int)stats.st_size,
+ context->sign_offset,
+ context->sign_length,
+ context->signature_offset);
+
+ if (context->modulus_offset != INVALID_VALUE)
+ printf(" rsa key modulus location %#x\n",
+ context->modulus_offset);
+ }
+
+ /* check signing section and signature location */
+ if (((context->sign_offset + context->sign_length) > stats.st_size) ||
+ ((context->signature_offset + RSA_KEY_BYTE_SIZE) >
+ stats.st_size)) {
+ printf("Error: Incorrect parameters are specified:\n"
+ " image size %#x\n"
+ " sign_offset %#x, sign_length %#x\n"
+ " signature location %#x\n",
+ (unsigned int)stats.st_size,
+ context->sign_offset,
+ context->sign_length,
+ context->signature_offset);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ /* check modulus location if specified */
+ if ((context->modulus_offset != INVALID_VALUE) &&
+ ((context->modulus_offset + RSA_KEY_BYTE_SIZE) > stats.st_size)) {
+ printf("Error: Incorrect modulus location specified: "
+ "%#x in file %s\n",
+ context->modulus_offset,
+ context->input_image_filename);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ /* update sign_length if default value is given */
+ if (context->sign_length == 0)
+ context->sign_length = stats.st_size - context->sign_offset;
+
+ /* check overlapping between signing section and signature location */
+ if (is_overlapping(context->signature_offset, RSA_KEY_BYTE_SIZE,
+ context->sign_offset, context->sign_length)) {
+ printf("Error: signature overlaps signed sections: "
+ "signed offset %#x length %#x, signature location %#x\n",
+ context->sign_offset,
+ context->sign_length,
+ context->signature_offset);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ /*
+ * check overlapping between modulus location and signature location
+ * and overlapping between modulus location and signing section
+ */
+ if (context->modulus_offset != INVALID_VALUE) {
+ if (is_overlapping(context->modulus_offset, RSA_KEY_BYTE_SIZE,
+ context->signature_offset, RSA_KEY_BYTE_SIZE)) {
+ printf("Error: modulus overlaps signature: "
+ "signature location %#x length %#x, modulus "
+ "location %#x length %#x\n",
+ context->signature_offset, RSA_KEY_BYTE_SIZE,
+ context->modulus_offset, RSA_KEY_BYTE_SIZE);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ if (is_overlapping(context->modulus_offset, RSA_KEY_BYTE_SIZE,
+ context->sign_offset, context->sign_length)) {
+ printf("Error: modulus overlaps signed sections: "
+ "signed offset %#x length %#x, modulus "
+ "location %#x length %#x\n",
+ context->sign_offset,
+ context->sign_length,
+ context->modulus_offset, RSA_KEY_BYTE_SIZE);
+ ret = -EINVAL;
+ goto fail;
+ }
+ }
+
+ ret = read_from_image(context->input_image_filename,
+ context->sign_offset,
+ context->sign_length,
+ &image, &image_actual_size, file_type_blocks);
+
+ if (ret || (image_actual_size != context->sign_length)) {
+ printf("Error reading image file %s: offset %#x, length %#x\n",
+ context->input_image_filename,
+ context->sign_offset,
+ context->sign_length);
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ /* sign image */
+ if ((ret = pkc_sign_buffer(context->pkckey,
+ image,
+ image_actual_size,
+ &sign)) != 0)
+ goto fail;
+
+ /* return signature location */
+ context->rsa_signature = sign;
+
+ fail:
+ if (image)
+ free(image);
+
+ return ret;
+}
+
+/*
+ * To write output image:
+ * Loop over all blocks:
+ * read in a block (adjust size if necessary)
+ * if signature section is in, fill in signature
+ * save data block
+ * then loop
+ *
+ * @param context The main context pointer
+ * @return 0 for success
+ */
+int
+save_rsa_signed_image(build_image_context *context)
+{
+ int ret = 0;
+ u_int32_t offset = 0, req_size, actual_size;
+ u_int8_t *data_block;
+ struct stat stats;
+
+ if (stat(context->input_image_filename, &stats) != 0) {
+ printf("Error: Unable to query info on input file path %s\n",
+ context->input_image_filename);
+ ret = -1;
+ goto fail;
+ }
+
+ while (stats.st_size > offset) {
+ if ((stats.st_size - offset) > DATA_BLOCK_SIZE)
+ req_size = DATA_BLOCK_SIZE;
+ else
+ req_size = stats.st_size - offset;
+
+ /* make sure signature's completion */
+ if (((offset + req_size) > context->signature_offset) &&
+ ((offset + req_size) <
+ (context->signature_offset + RSA_KEY_BYTE_SIZE))) {
+ req_size = context->signature_offset + RSA_KEY_BYTE_SIZE
+ - offset;
+ }
+
+ /* if modulus is needed, make sure mudulus's completion */
+ if ((context->modulus_offset != INVALID_VALUE) &&
+ (((offset + req_size) > context->modulus_offset) &&
+ ((offset + req_size) <
+ (context->modulus_offset + RSA_KEY_BYTE_SIZE)))) {
+ req_size = context->modulus_offset + RSA_KEY_BYTE_SIZE
+ - offset;
+ }
+
+ /* Read a block of data into memory */
+ ret = read_from_image(context->input_image_filename,
+ offset,
+ req_size,
+ &data_block,
+ &actual_size,
+ file_type_blocks);
+ if (ret || (req_size != actual_size)) {
+ printf("Error reading image file %s.\n",
+ context->input_image_filename);
+ ret = -1;
+ goto fail;
+ }
+
+ /* fill in signature section */
+ if ((offset <= context->signature_offset) &&
+ ((offset + req_size) >=
+ (context->signature_offset + RSA_KEY_BYTE_SIZE))) {
+ memcpy(data_block + (context->signature_offset - offset),
+ context->rsa_signature,
+ RSA_KEY_BYTE_SIZE);
+ }
+
+ /* if modulus is needed, fill in mudulus section */
+ if ((context->modulus_offset != INVALID_VALUE) &&
+ ((offset <= context->modulus_offset) &&
+ ((offset + req_size) >=
+ (context->modulus_offset + RSA_KEY_BYTE_SIZE)))) {
+ memcpy(data_block + (context->modulus_offset - offset),
+ pkc_get_pubkey(context->pkckey),
+ RSA_KEY_BYTE_SIZE);
+ }
+
+ /* Write the block of data to file */
+ if (actual_size != write_data_block(context->raw_file, offset,
+ actual_size, data_block)) {
+ printf("Error writing image file %s.\n",
+ context->output_image_filename);
+ goto fail;
+ }
+
+ offset += actual_size;
+ free(data_block);
+ data_block = NULL;
+ }
+ fail:
+ if (data_block)
+ free(data_block);
+ return ret;
+}
@@ -64,5 +64,12 @@ get_bct_size_from_image(build_image_context *context);
int
begin_update(build_image_context *context);
-int resign_bl(build_image_context *context);
+int
+resign_bl(build_image_context *context);
+
+int
+rsa_sign_image(build_image_context *context);
+
+int
+save_rsa_signed_image(build_image_context *context);
#endif /* #ifndef INCLUDED_DATA_LAYOUT_H */
@@ -76,6 +76,8 @@ static int
parse_bct_file(build_image_context *context, parse_token token, char *rest);
static int
parse_pkckey_file(build_image_context *context, parse_token token, char *rest);
+static int
+parse_rsa_sign_image(build_image_context *context, parse_token token, char *rest);
static char
*parse_end_state(char *str, char *uname, int chars_remaining);
static int
@@ -96,6 +98,7 @@ static parse_item parse_simple_items[] =
{ "Redundancy=", token_redundancy, parse_value_u32 },
{ "Bctcopy=", token_bct_copy, parse_value_u32 },
{ "PkcKey=", token_pkckey_file, parse_pkckey_file},
+ { "RsaSign=", token_rsa_sign_image, parse_rsa_sign_image},
{ "MtsPreboot=", token_mts_preboot, parse_mts_image},
{ "Mts=", token_mts, parse_mts_image},
{ "Version=", token_version, parse_value_u32 },
@@ -437,6 +440,66 @@ static int parse_bootloader(build_image_context *context,
}
/*
+ * Parse the given string and find signing offset, length and signature location
+ *
+ * @param context The main context pointer
+ * @param token The parse token value
+ * @param rest String to parse
+ * @return 0 and 1 for success and failure
+ */
+static int parse_rsa_sign_image(build_image_context *context,
+ parse_token token,
+ char *rest)
+{
+ char e_state[MAX_STR_LEN];
+
+ assert(context != NULL);
+ assert(rest != NULL);
+
+ /* Parse the sign section starting address. */
+ rest = parse_u32(rest, &context->sign_offset);
+ if (rest == NULL)
+ return 1;
+
+ PARSE_COMMA(1);
+
+ /* Parse the sign section length. */
+ rest = parse_u32(rest, &context->sign_length);
+ if (rest == NULL)
+ return 1;
+
+ PARSE_COMMA(1);
+
+ /* Parse the signature store location. */
+ rest = parse_u32(rest, &context->signature_offset);
+ if (rest == NULL)
+ return 1;
+
+ PARSE_COMMA(1);
+
+ /* parse the optional modulus location */
+ rest = parse_u32(rest, &context->modulus_offset);
+ if (rest == NULL)
+ return 1;
+
+ if (*rest == ',') {
+ /* modulus location is specified */
+ ++rest;
+ } else
+ context->modulus_offset = INVALID_VALUE;
+
+ /* Parse the end state. */
+ rest = parse_end_state(rest, e_state, MAX_STR_LEN);
+ if (rest == NULL)
+ return 1;
+ if (strncmp(e_state, "Complete", strlen("Complete")))
+ return 1;
+
+ /* Parsing has finished - sign on specified image sections */
+ return rsa_sign_image(context);
+}
+
+/*
* Parse the given string and find the MTS file name, load address and
* entry point information then call set_mts_image function.
*
@@ -42,6 +42,7 @@ typedef enum
token_attribute,
token_bootloader,
token_pkckey_file,
+ token_rsa_sign_image,
token_mts_preboot,
token_mts,
token_block_size,
This option allows cbootimage to run as signing utility. Command line option "--sign" syntax: $ cbootimage --sign <sign.cfg> <input_image> <output_image> Where sign.cfg is the configuration file. Keyword "RsaSign" specifies signing details such as signing sections starting offset, length, and the location to store signature and pubkey. Keyword "RsaSign" syntax: RsaSign = <sign_offset>, <sign_length>, <signature_loc>, [modulus_loc,] Complete; If no values are specified, default values are assigned as: sign_offset: 0 sign_length: input_image_size - sign_offset signature_loc: 0 modulus_loc: 0 Parameter <modulus_loc> is optional. A sample configuration file sign.cfg: PkcKey = rsa_priv.txt; RsaSign = 0x220,, 288, 16, Complete; Command line example: $ cbootimage --sign sign.cfg image.bin image.bin-signed Signed-off-by: Jimmy Zhang <jimmzhang@nvidia.com> --- src/cbootimage.c | 29 ++++++- src/cbootimage.h | 12 +++ src/crypto.c | 8 +- src/crypto.h | 3 + src/data_layout.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/data_layout.h | 9 ++- src/parse.c | 63 +++++++++++++++ src/parse.h | 1 + 8 files changed, 353 insertions(+), 4 deletions(-)