uboot/common/image-fit-sig.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * Copyright (c) 2013, Google Inc.
   4 */
   5
   6#ifdef USE_HOSTCC
   7#include "mkimage.h"
   8#include <time.h>
   9#else
  10#include <common.h>
  11#include <log.h>
  12#include <malloc.h>
  13#include <asm/global_data.h>
  14DECLARE_GLOBAL_DATA_PTR;
  15#endif /* !USE_HOSTCC*/
  16#include <fdt_region.h>
  17#include <image.h>
  18#include <u-boot/rsa.h>
  19#include <u-boot/hash-checksum.h>
  20
  21#define IMAGE_MAX_HASHED_NODES          100
  22
  23/**
  24 * fit_region_make_list() - Make a list of image regions
  25 *
  26 * Given a list of fdt_regions, create a list of image_regions. This is a
  27 * simple conversion routine since the FDT and image code use different
  28 * structures.
  29 *
  30 * @fit: FIT image
  31 * @fdt_regions: Pointer to FDT regions
  32 * @count: Number of FDT regions
  33 * @region: Pointer to image regions, which must hold @count records. If
  34 * region is NULL, then (except for an SPL build) the array will be
  35 * allocated.
  36 * @return: Pointer to image regions
  37 */
  38struct image_region *fit_region_make_list(const void *fit,
  39                                          struct fdt_region *fdt_regions,
  40                                          int count,
  41                                          struct image_region *region)
  42{
  43        int i;
  44
  45        debug("Hash regions:\n");
  46        debug("%10s %10s\n", "Offset", "Size");
  47
  48        /*
  49         * Use malloc() except in SPL (to save code size). In SPL the caller
  50         * must allocate the array.
  51         */
  52#ifndef CONFIG_SPL_BUILD
  53        if (!region)
  54                region = calloc(sizeof(*region), count);
  55#endif
  56        if (!region)
  57                return NULL;
  58        for (i = 0; i < count; i++) {
  59                debug("%10x %10x\n", fdt_regions[i].offset,
  60                      fdt_regions[i].size);
  61                region[i].data = fit + fdt_regions[i].offset;
  62                region[i].size = fdt_regions[i].size;
  63        }
  64
  65        return region;
  66}
  67
  68static int fit_image_setup_verify(struct image_sign_info *info,
  69                                  const void *fit, int noffset,
  70                                  int required_keynode, char **err_msgp)
  71{
  72        char *algo_name;
  73        const char *padding_name;
  74
  75        if (fdt_totalsize(fit) > CONFIG_FIT_SIGNATURE_MAX_SIZE) {
  76                *err_msgp = "Total size too large";
  77                return 1;
  78        }
  79
  80        if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
  81                *err_msgp = "Can't get hash algo property";
  82                return -1;
  83        }
  84
  85        padding_name = fdt_getprop(fit, noffset, "padding", NULL);
  86        if (!padding_name)
  87                padding_name = RSA_DEFAULT_PADDING_NAME;
  88
  89        memset(info, '\0', sizeof(*info));
  90        info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
  91        info->fit = (void *)fit;
  92        info->node_offset = noffset;
  93        info->name = algo_name;
  94        info->checksum = image_get_checksum_algo(algo_name);
  95        info->crypto = image_get_crypto_algo(algo_name);
  96        info->padding = image_get_padding_algo(padding_name);
  97        info->fdt_blob = gd_fdt_blob();
  98        info->required_keynode = required_keynode;
  99        printf("%s:%s", algo_name, info->keyname);
 100
 101        if (!info->checksum || !info->crypto || !info->padding) {
 102                *err_msgp = "Unknown signature algorithm";
 103                return -1;
 104        }
 105
 106        return 0;
 107}
 108
 109int fit_image_check_sig(const void *fit, int noffset, const void *data,
 110                        size_t size, int required_keynode, char **err_msgp)
 111{
 112        struct image_sign_info info;
 113        struct image_region region;
 114        uint8_t *fit_value;
 115        int fit_value_len;
 116
 117        *err_msgp = NULL;
 118        if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
 119                                   err_msgp))
 120                return -1;
 121
 122        if (fit_image_hash_get_value(fit, noffset, &fit_value,
 123                                     &fit_value_len)) {
 124                *err_msgp = "Can't get hash value property";
 125                return -1;
 126        }
 127
 128        region.data = data;
 129        region.size = size;
 130
 131        if (info.crypto->verify(&info, &region, 1, fit_value, fit_value_len)) {
 132                *err_msgp = "Verification failed";
 133                return -1;
 134        }
 135
 136        return 0;
 137}
 138
 139static int fit_image_verify_sig(const void *fit, int image_noffset,
 140                                const char *data, size_t size,
 141                                const void *sig_blob, int sig_offset)
 142{
 143        int noffset;
 144        char *err_msg = "";
 145        int verified = 0;
 146        int ret;
 147
 148        /* Process all hash subnodes of the component image node */
 149        fdt_for_each_subnode(noffset, fit, image_noffset) {
 150                const char *name = fit_get_name(fit, noffset, NULL);
 151
 152                /*
 153                 * We don't support this since libfdt considers names with the
 154                 * name root but different @ suffix to be equal
 155                 */
 156                if (strchr(name, '@')) {
 157                        err_msg = "Node name contains @";
 158                        goto error;
 159                }
 160                if (!strncmp(name, FIT_SIG_NODENAME,
 161                             strlen(FIT_SIG_NODENAME))) {
 162                        ret = fit_image_check_sig(fit, noffset, data,
 163                                                  size, -1, &err_msg);
 164                        if (ret) {
 165                                puts("- ");
 166                        } else {
 167                                puts("+ ");
 168                                verified = 1;
 169                                break;
 170                        }
 171                }
 172        }
 173
 174        if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
 175                err_msg = "Corrupted or truncated tree";
 176                goto error;
 177        }
 178
 179        return verified ? 0 : -EPERM;
 180
 181error:
 182        printf(" error!\n%s for '%s' hash node in '%s' image node\n",
 183               err_msg, fit_get_name(fit, noffset, NULL),
 184               fit_get_name(fit, image_noffset, NULL));
 185        return -1;
 186}
 187
 188int fit_image_verify_required_sigs(const void *fit, int image_noffset,
 189                                   const char *data, size_t size,
 190                                   const void *sig_blob, int *no_sigsp)
 191{
 192        int verify_count = 0;
 193        int noffset;
 194        int sig_node;
 195
 196        /* Work out what we need to verify */
 197        *no_sigsp = 1;
 198        sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
 199        if (sig_node < 0) {
 200                debug("%s: No signature node found: %s\n", __func__,
 201                      fdt_strerror(sig_node));
 202                return 0;
 203        }
 204
 205        fdt_for_each_subnode(noffset, sig_blob, sig_node) {
 206                const char *required;
 207                int ret;
 208
 209                required = fdt_getprop(sig_blob, noffset, FIT_KEY_REQUIRED,
 210                                       NULL);
 211                if (!required || strcmp(required, "image"))
 212                        continue;
 213                ret = fit_image_verify_sig(fit, image_noffset, data, size,
 214                                           sig_blob, noffset);
 215                if (ret) {
 216                        printf("Failed to verify required signature '%s'\n",
 217                               fit_get_name(sig_blob, noffset, NULL));
 218                        return ret;
 219                }
 220                verify_count++;
 221        }
 222
 223        if (verify_count)
 224                *no_sigsp = 0;
 225
 226        return 0;
 227}
 228
 229/**
 230 * fit_config_check_sig() - Check the signature of a config
 231 *
 232 * @fit: FIT to check
 233 * @noffset: Offset of configuration node (e.g. /configurations/conf-1)
 234 * @required_keynode:   Offset in the control FDT of the required key node,
 235 *                      if any. If this is given, then the configuration wil not
 236 *                      pass verification unless that key is used. If this is
 237 *                      -1 then any signature will do.
 238 * @conf_noffset: Offset of the configuration subnode being checked (e.g.
 239 *       /configurations/conf-1/kernel)
 240 * @err_msgp:           In the event of an error, this will be pointed to a
 241 *                      help error string to display to the user.
 242 * @return 0 if all verified ok, <0 on error
 243 */
 244static int fit_config_check_sig(const void *fit, int noffset,
 245                                int required_keynode, int conf_noffset,
 246                                char **err_msgp)
 247{
 248        static char * const exc_prop[] = {
 249                "data",
 250                "data-size",
 251                "data-position",
 252                "data-offset"
 253        };
 254
 255        const char *prop, *end, *name;
 256        struct image_sign_info info;
 257        const uint32_t *strings;
 258        const char *config_name;
 259        uint8_t *fit_value;
 260        int fit_value_len;
 261        bool found_config;
 262        int max_regions;
 263        int i, prop_len;
 264        char path[200];
 265        int count;
 266
 267        config_name = fit_get_name(fit, conf_noffset, NULL);
 268        debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, gd_fdt_blob(),
 269              fit_get_name(fit, noffset, NULL),
 270              fit_get_name(gd_fdt_blob(), required_keynode, NULL));
 271        *err_msgp = NULL;
 272        if (fit_image_setup_verify(&info, fit, noffset, required_keynode,
 273                                   err_msgp))
 274                return -1;
 275
 276        if (fit_image_hash_get_value(fit, noffset, &fit_value,
 277                                     &fit_value_len)) {
 278                *err_msgp = "Can't get hash value property";
 279                return -1;
 280        }
 281
 282        /* Count the number of strings in the property */
 283        prop = fdt_getprop(fit, noffset, "hashed-nodes", &prop_len);
 284        end = prop ? prop + prop_len : prop;
 285        for (name = prop, count = 0; name < end; name++)
 286                if (!*name)
 287                        count++;
 288        if (!count) {
 289                *err_msgp = "Can't get hashed-nodes property";
 290                return -1;
 291        }
 292
 293        if (prop && prop_len > 0 && prop[prop_len - 1] != '\0') {
 294                *err_msgp = "hashed-nodes property must be null-terminated";
 295                return -1;
 296        }
 297
 298        /* Add a sanity check here since we are using the stack */
 299        if (count > IMAGE_MAX_HASHED_NODES) {
 300                *err_msgp = "Number of hashed nodes exceeds maximum";
 301                return -1;
 302        }
 303
 304        /* Create a list of node names from those strings */
 305        char *node_inc[count];
 306
 307        debug("Hash nodes (%d):\n", count);
 308        found_config = false;
 309        for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) {
 310                debug("   '%s'\n", name);
 311                node_inc[i] = (char *)name;
 312                if (!strncmp(FIT_CONFS_PATH, name, strlen(FIT_CONFS_PATH)) &&
 313                    name[sizeof(FIT_CONFS_PATH) - 1] == '/' &&
 314                    !strcmp(name + sizeof(FIT_CONFS_PATH), config_name)) {
 315                        debug("      (found config node %s)", config_name);
 316                        found_config = true;
 317                }
 318        }
 319        if (!found_config) {
 320                *err_msgp = "Selected config not in hashed nodes";
 321                return -1;
 322        }
 323
 324        /*
 325         * Each node can generate one region for each sub-node. Allow for
 326         * 7 sub-nodes (hash-1, signature-1, etc.) and some extra.
 327         */
 328        max_regions = 20 + count * 7;
 329        struct fdt_region fdt_regions[max_regions];
 330
 331        /* Get a list of regions to hash */
 332        count = fdt_find_regions(fit, node_inc, count,
 333                                 exc_prop, ARRAY_SIZE(exc_prop),
 334                                 fdt_regions, max_regions - 1,
 335                                 path, sizeof(path), 0);
 336        if (count < 0) {
 337                *err_msgp = "Failed to hash configuration";
 338                return -1;
 339        }
 340        if (count == 0) {
 341                *err_msgp = "No data to hash";
 342                return -1;
 343        }
 344        if (count >= max_regions - 1) {
 345                *err_msgp = "Too many hash regions";
 346                return -1;
 347        }
 348
 349        /* Add the strings */
 350        strings = fdt_getprop(fit, noffset, "hashed-strings", NULL);
 351        if (strings) {
 352                /*
 353                 * The strings region offset must be a static 0x0.
 354                 * This is set in tool/image-host.c
 355                 */
 356                fdt_regions[count].offset = fdt_off_dt_strings(fit);
 357                fdt_regions[count].size = fdt32_to_cpu(strings[1]);
 358                count++;
 359        }
 360
 361        /* Allocate the region list on the stack */
 362        struct image_region region[count];
 363
 364        fit_region_make_list(fit, fdt_regions, count, region);
 365        if (info.crypto->verify(&info, region, count, fit_value,
 366                                fit_value_len)) {
 367                *err_msgp = "Verification failed";
 368                return -1;
 369        }
 370
 371        return 0;
 372}
 373
 374static int fit_config_verify_sig(const void *fit, int conf_noffset,
 375                                 const void *sig_blob, int sig_offset)
 376{
 377        int noffset;
 378        char *err_msg = "No 'signature' subnode found";
 379        int verified = 0;
 380        int ret;
 381
 382        /* Process all hash subnodes of the component conf node */
 383        fdt_for_each_subnode(noffset, fit, conf_noffset) {
 384                const char *name = fit_get_name(fit, noffset, NULL);
 385
 386                if (!strncmp(name, FIT_SIG_NODENAME,
 387                             strlen(FIT_SIG_NODENAME))) {
 388                        ret = fit_config_check_sig(fit, noffset, sig_offset,
 389                                                   conf_noffset, &err_msg);
 390                        if (ret) {
 391                                puts("- ");
 392                        } else {
 393                                puts("+ ");
 394                                verified = 1;
 395                                break;
 396                        }
 397                }
 398        }
 399
 400        if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
 401                err_msg = "Corrupted or truncated tree";
 402                goto error;
 403        }
 404
 405        if (verified)
 406                return 0;
 407
 408error:
 409        printf(" error!\n%s for '%s' hash node in '%s' config node\n",
 410               err_msg, fit_get_name(fit, noffset, NULL),
 411               fit_get_name(fit, conf_noffset, NULL));
 412        return -EPERM;
 413}
 414
 415static int fit_config_verify_required_sigs(const void *fit, int conf_noffset,
 416                                           const void *sig_blob)
 417{
 418        const char *name = fit_get_name(fit, conf_noffset, NULL);
 419        int noffset;
 420        int sig_node;
 421        int verified = 0;
 422        int reqd_sigs = 0;
 423        bool reqd_policy_all = true;
 424        const char *reqd_mode;
 425
 426        /*
 427         * We don't support this since libfdt considers names with the
 428         * name root but different @ suffix to be equal
 429         */
 430        if (strchr(name, '@')) {
 431                printf("Configuration node '%s' contains '@'\n", name);
 432                return -EPERM;
 433        }
 434
 435        /* Work out what we need to verify */
 436        sig_node = fdt_subnode_offset(sig_blob, 0, FIT_SIG_NODENAME);
 437        if (sig_node < 0) {
 438                debug("%s: No signature node found: %s\n", __func__,
 439                      fdt_strerror(sig_node));
 440                return 0;
 441        }
 442
 443        /* Get required-mode policy property from DTB */
 444        reqd_mode = fdt_getprop(sig_blob, sig_node, "required-mode", NULL);
 445        if (reqd_mode && !strcmp(reqd_mode, "any"))
 446                reqd_policy_all = false;
 447
 448        debug("%s: required-mode policy set to '%s'\n", __func__,
 449              reqd_policy_all ? "all" : "any");
 450
 451        fdt_for_each_subnode(noffset, sig_blob, sig_node) {
 452                const char *required;
 453                int ret;
 454
 455                required = fdt_getprop(sig_blob, noffset, FIT_KEY_REQUIRED,
 456                                       NULL);
 457                if (!required || strcmp(required, "conf"))
 458                        continue;
 459
 460                reqd_sigs++;
 461
 462                ret = fit_config_verify_sig(fit, conf_noffset, sig_blob,
 463                                            noffset);
 464                if (ret) {
 465                        if (reqd_policy_all) {
 466                                printf("Failed to verify required signature '%s'\n",
 467                                       fit_get_name(sig_blob, noffset, NULL));
 468                                return ret;
 469                        }
 470                } else {
 471                        verified++;
 472                        if (!reqd_policy_all)
 473                                break;
 474                }
 475        }
 476
 477        if (reqd_sigs && !verified) {
 478                printf("Failed to verify 'any' of the required signature(s)\n");
 479                return -EPERM;
 480        }
 481
 482        return 0;
 483}
 484
 485int fit_config_verify(const void *fit, int conf_noffset)
 486{
 487        return fit_config_verify_required_sigs(fit, conf_noffset,
 488                                               gd_fdt_blob());
 489}
 490