doc: fix mistyped "env flags" command
[pandora-u-boot.git] / boot / image-fit-sig.c
index 9b1d38b..1236989 100644 (file)
@@ -65,9 +65,10 @@ struct image_region *fit_region_make_list(const void *fit,
 
 static int fit_image_setup_verify(struct image_sign_info *info,
                                  const void *fit, int noffset,
-                                 int required_keynode, char **err_msgp)
+                                 const void *key_blob, int required_keynode,
+                                 char **err_msgp)
 {
-       char *algo_name;
+       const char *algo_name;
        const char *padding_name;
 
        if (fdt_totalsize(fit) > CONFIG_VAL(FIT_SIGNATURE_MAX_SIZE)) {
@@ -91,7 +92,7 @@ static int fit_image_setup_verify(struct image_sign_info *info,
        info->checksum = image_get_checksum_algo(algo_name);
        info->crypto = image_get_crypto_algo(algo_name);
        info->padding = image_get_padding_algo(padding_name);
-       info->fdt_blob = gd_fdt_blob();
+       info->fdt_blob = key_blob;
        info->required_keynode = required_keynode;
        printf("%s:%s", algo_name, info->keyname);
 
@@ -104,7 +105,8 @@ static int fit_image_setup_verify(struct image_sign_info *info,
 }
 
 int fit_image_check_sig(const void *fit, int noffset, const void *data,
-                       size_t size, int required_keynode, char **err_msgp)
+                       size_t size, const void *key_blob, int required_keynode,
+                       char **err_msgp)
 {
        struct image_sign_info info;
        struct image_region region;
@@ -112,8 +114,8 @@ int fit_image_check_sig(const void *fit, int noffset, const void *data,
        int fit_value_len;
 
        *err_msgp = NULL;
-       if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
-                                  err_msgp))
+       if (fit_image_setup_verify(&info, fit, noffset, key_blob,
+                                  required_keynode, err_msgp))
                return -1;
 
        if (fit_image_hash_get_value(fit, noffset, &fit_value,
@@ -135,7 +137,7 @@ int fit_image_check_sig(const void *fit, int noffset, const void *data,
 
 static int fit_image_verify_sig(const void *fit, int image_noffset,
                                const char *data, size_t size,
-                               const void *sig_blob, int sig_offset)
+                               const void *key_blob, int key_offset)
 {
        int noffset;
        char *err_msg = "";
@@ -156,8 +158,8 @@ static int fit_image_verify_sig(const void *fit, int image_noffset,
                }
                if (!strncmp(name, FIT_SIG_NODENAME,
                             strlen(FIT_SIG_NODENAME))) {
-                       ret = fit_image_check_sig(fit, noffset, data,
-                                                 size, -1, &err_msg);
+                       ret = fit_image_check_sig(fit, noffset, data, size,
+                                                 key_blob, -1, &err_msg);
                        if (ret) {
                                puts("- ");
                        } else {
@@ -184,34 +186,34 @@ error:
 
 int fit_image_verify_required_sigs(const void *fit, int image_noffset,
                                   const char *data, size_t size,
-                                  const void *sig_blob, int *no_sigsp)
+                                  const void *key_blob, int *no_sigsp)
 {
        int verify_count = 0;
        int noffset;
-       int sig_node;
+       int key_node;
 
        /* Work out what we need to verify */
        *no_sigsp = 1;
-       sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
-       if (sig_node < 0) {
+       key_node = fdt_subnode_offset(key_blob, 0, FIT_SIG_NODENAME);
+       if (key_node < 0) {
                debug("%s: No signature node found: %s\n", __func__,
-                     fdt_strerror(sig_node));
+                     fdt_strerror(key_node));
                return 0;
        }
 
-       fdt_for_each_subnode(noffset, sig_blob, sig_node) {
+       fdt_for_each_subnode(noffset, key_blob, key_node) {
                const char *required;
                int ret;
 
-               required = fdt_getprop(sig_blob, noffset, FIT_KEY_REQUIRED,
+               required = fdt_getprop(key_blob, noffset, FIT_KEY_REQUIRED,
                                       NULL);
                if (!required || strcmp(required, "image"))
                        continue;
                ret = fit_image_verify_sig(fit, image_noffset, data, size,
-                                          sig_blob, noffset);
+                                          key_blob, noffset);
                if (ret) {
                        printf("Failed to verify required signature '%s'\n",
-                              fit_get_name(sig_blob, noffset, NULL));
+                              fit_get_name(key_blob, noffset, NULL));
                        return ret;
                }
                verify_count++;
@@ -226,27 +228,42 @@ int fit_image_verify_required_sigs(const void *fit, int image_noffset,
 /**
  * fit_config_check_sig() - Check the signature of a config
  *
+ * Here we are looking at a particular signature that needs verification (here
+ * signature-1):
+ *
+ *     configurations {
+ *             default = "conf-1";
+ *             conf-1 {
+ *                     kernel = "kernel-1";
+ *                     fdt = "fdt-1";
+ *                     signature-1 {
+ *                             algo = "sha1,rsa2048";
+ *                             value = <...conf 1 signature...>;
+ *                     };
+ *             };
+ *
  * @fit: FIT to check
- * @noffset: Offset of configuration node (e.g. /configurations/conf-1)
- * @required_keynode:  Offset in the control FDT of the required key node,
+ * @noffset: Offset of the signature node being checked (e.g.
+ *      /configurations/conf-1/signature-1)
+ * @conf_noffset: Offset of configuration node (e.g. /configurations/conf-1)
+ * @key_blob: Blob containing the keys to check against
+ * @required_keynode:  Offset in @key_blob of the required key node,
  *                     if any. If this is given, then the configuration wil not
  *                     pass verification unless that key is used. If this is
  *                     -1 then any signature will do.
- * @conf_noffset: Offset of the configuration subnode being checked (e.g.
- *      /configurations/conf-1/kernel)
  * @err_msgp:          In the event of an error, this will be pointed to a
  *                     help error string to display to the user.
  * Return: 0 if all verified ok, <0 on error
  */
-static int fit_config_check_sig(const void *fit, int noffset,
-                               int required_keynode, int conf_noffset,
+static int fit_config_check_sig(const void *fit, int noffset, int conf_noffset,
+                               const void *key_blob, int required_keynode,
                                char **err_msgp)
 {
        static char * const exc_prop[] = {
-               "data",
-               "data-size",
-               "data-position",
-               "data-offset"
+               FIT_DATA_PROP,
+               FIT_DATA_SIZE_PROP,
+               FIT_DATA_POSITION_PROP,
+               FIT_DATA_OFFSET_PROP,
        };
 
        const char *prop, *end, *name;
@@ -262,12 +279,12 @@ static int fit_config_check_sig(const void *fit, int noffset,
        int count;
 
        config_name = fit_get_name(fit, conf_noffset, NULL);
-       debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, gd_fdt_blob(),
+       debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, key_blob,
              fit_get_name(fit, noffset, NULL),
-             fit_get_name(gd_fdt_blob(), required_keynode, NULL));
+             fit_get_name(key_blob, required_keynode, NULL));
        *err_msgp = NULL;
-       if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
-                                  err_msgp))
+       if (fit_image_setup_verify(&info, fit, noffset, key_blob,
+                                  required_keynode, err_msgp))
                return -1;
 
        if (fit_image_hash_get_value(fit, noffset, &fit_value,
@@ -368,8 +385,35 @@ static int fit_config_check_sig(const void *fit, int noffset,
        return 0;
 }
 
-static int fit_config_verify_sig(const void *fit, int conf_noffset,
-                                const void *sig_blob, int sig_offset)
+/**
+ * fit_config_verify_key() - Verify that a configuration is signed with a key
+ *
+ * Here we are looking at a particular configuration that needs verification:
+ *
+ *     configurations {
+ *             default = "conf-1";
+ *             conf-1 {
+ *                     kernel = "kernel-1";
+ *                     fdt = "fdt-1";
+ *                     signature-1 {
+ *                             algo = "sha1,rsa2048";
+ *                             value = <...conf 1 signature...>;
+ *                     };
+ *             };
+ *
+ * We must check each of the signature subnodes of conf-1. Hopefully one of them
+ * will match the key at key_offset.
+ *
+ * @fit: FIT to check
+ * @conf_noffset: Offset of the configuration node to check (e.g.
+ *     /configurations/conf-1)
+ * @key_blob: Blob containing the keys to check against
+ * @key_offset: Offset of the key to check within @key_blob
+ * @return 0 if OK, -EPERM if any signatures did not verify, or the
+ *     configuration node has an invalid name
+ */
+static int fit_config_verify_key(const void *fit, int conf_noffset,
+                                const void *key_blob, int key_offset)
 {
        int noffset;
        char *err_msg = "No 'signature' subnode found";
@@ -382,8 +426,9 @@ static int fit_config_verify_sig(const void *fit, int conf_noffset,
 
                if (!strncmp(name, FIT_SIG_NODENAME,
                             strlen(FIT_SIG_NODENAME))) {
-                       ret = fit_config_check_sig(fit, noffset, sig_offset,
-                                                  conf_noffset, &err_msg);
+                       ret = fit_config_check_sig(fit, noffset, conf_noffset,
+                                                  key_blob, key_offset,
+                                                  &err_msg);
                        if (ret) {
                                puts("- ");
                        } else {
@@ -409,12 +454,25 @@ error:
        return -EPERM;
 }
 
-static int fit_config_verify_required_sigs(const void *fit, int conf_noffset,
-                                          const void *sig_blob)
+/**
+ * fit_config_verify_required_keys() - verify any required signatures for config
+ *
+ * This looks through all the signatures we expect and verifies that at least
+ * all the required ones are valid signatures for the configuration
+ *
+ * @fit: FIT to check
+ * @conf_noffset: Offset of the configuration node to check (e.g.
+ *     /configurations/conf-1)
+ * @key_blob: Blob containing the keys to check against
+ * @return 0 if OK, -EPERM if any signatures did not verify, or the
+ *     configuration node has an invalid name
+ */
+static int fit_config_verify_required_keys(const void *fit, int conf_noffset,
+                                          const void *key_blob)
 {
        const char *name = fit_get_name(fit, conf_noffset, NULL);
        int noffset;
-       int sig_node;
+       int key_node;
        int verified = 0;
        int reqd_sigs = 0;
        bool reqd_policy_all = true;
@@ -430,38 +488,45 @@ static int fit_config_verify_required_sigs(const void *fit, int conf_noffset,
        }
 
        /* Work out what we need to verify */
-       sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
-       if (sig_node < 0) {
+       key_node = fdt_subnode_offset(key_blob, 0, FIT_SIG_NODENAME);
+       if (key_node < 0) {
                debug("%s: No signature node found: %s\n", __func__,
-                     fdt_strerror(sig_node));
+                     fdt_strerror(key_node));
                return 0;
        }
 
        /* Get required-mode policy property from DTB */
-       reqd_mode = fdt_getprop(sig_blob, sig_node, "required-mode", NULL);
+       reqd_mode = fdt_getprop(key_blob, key_node, "required-mode", NULL);
        if (reqd_mode && !strcmp(reqd_mode, "any"))
                reqd_policy_all = false;
 
        debug("%s: required-mode policy set to '%s'\n", __func__,
              reqd_policy_all ? "all" : "any");
 
-       fdt_for_each_subnode(noffset, sig_blob, sig_node) {
+       /*
+        * The algorithm here is a little convoluted due to how we want it to
+        * work. Here we work through each of the signature nodes in the
+        * public-key area. These are in the U-Boot control devicetree. Each
+        * node was created by signing a configuration, so we check if it is
+        * 'required' and if so, request that it be verified.
+        */
+       fdt_for_each_subnode(noffset, key_blob, key_node) {
                const char *required;
                int ret;
 
-               required = fdt_getprop(sig_blob, noffset, FIT_KEY_REQUIRED,
+               required = fdt_getprop(key_blob, noffset, FIT_KEY_REQUIRED,
                                       NULL);
                if (!required || strcmp(required, "conf"))
                        continue;
 
                reqd_sigs++;
 
-               ret = fit_config_verify_sig(fit, conf_noffset, sig_blob,
+               ret = fit_config_verify_key(fit, conf_noffset, key_blob,
                                            noffset);
                if (ret) {
                        if (reqd_policy_all) {
                                printf("Failed to verify required signature '%s'\n",
-                                      fit_get_name(sig_blob, noffset, NULL));
+                                      fit_get_name(key_blob, noffset, NULL));
                                return ret;
                        }
                } else {
@@ -481,6 +546,6 @@ static int fit_config_verify_required_sigs(const void *fit, int conf_noffset,
 
 int fit_config_verify(const void *fit, int conf_noffset)
 {
-       return fit_config_verify_required_sigs(fit, conf_noffset,
+       return fit_config_verify_required_keys(fit, conf_noffset,
                                               gd_fdt_blob());
 }