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 <[email protected]>
---
 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(-)

diff --git a/src/cbootimage.c b/src/cbootimage.c
index 9b696519377a..4ff4ce52a490 100644
--- a/src/cbootimage.c
+++ b/src/cbootimage.c
@@ -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);
diff --git a/src/cbootimage.h b/src/cbootimage.h
index afb72741c8d8..a8ed07ce3e4e 100644
--- a/src/cbootimage.h
+++ b/src/cbootimage.h
@@ -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 */
diff --git a/src/crypto.c b/src/crypto.c
index c88573208ec6..6dadda10030c 100644
--- a/src/crypto.c
+++ b/src/crypto.c
@@ -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));
diff --git a/src/crypto.h b/src/crypto.h
index 53a0d20f3441..c8ea0b66efaf 100644
--- a/src/crypto.h
+++ b/src/crypto.h
@@ -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,
diff --git a/src/data_layout.c b/src/data_layout.c
index ce3739ac67d9..050f2bb9d2d1 100644
--- a/src/data_layout.c
+++ b/src/data_layout.c
@@ -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;
+}
diff --git a/src/data_layout.h b/src/data_layout.h
index 3b2cfb58f3e9..eb38bfab27b8 100644
--- a/src/data_layout.h
+++ b/src/data_layout.h
@@ -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 */
diff --git a/src/parse.c b/src/parse.c
index d37a442030c0..d21387943f28 100644
--- a/src/parse.c
+++ b/src/parse.c
@@ -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.
  *
diff --git a/src/parse.h b/src/parse.h
index 26618edf9c87..133d8ab4ae29 100644
--- a/src/parse.h
+++ b/src/parse.h
@@ -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,
-- 
1.8.1.5

--
To unsubscribe from this list: send the line "unsubscribe linux-tegra" in
the body of a message to [email protected]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to