uboot/boot/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        if (!IS_ENABLED(CONFIG_SPL_BUILD) && !region)
  53                region = calloc(sizeof(*region), count);
  54        if (!region)
  55                return NULL;
  56        for (i = 0; i < count; i++) {
  57                debug("%10x %10x\n", fdt_regions[i].offset,
  58                      fdt_regions[i].size);
  59                region[i].data = fit + fdt_regions[i].offset;
  60                region[i].size = fdt_regions[i].size;
  61        }
  62
  63        return region;
  64}
  65
  66static int fit_image_setup_verify(struct image_sign_info *info,
  67                                  const void *fit, int noffset,
  68                                  const void *key_blob, int required_keynode,
  69                                  char **err_msgp)
  70{
  71        const char *algo_name;
  72        const char *padding_name;
  73
  74        if (fdt_totalsize(fit) > CONFIG_VAL(FIT_SIGNATURE_MAX_SIZE)) {
  75                *err_msgp = "Total size too large";
  76                return 1;
  77        }
  78        if (fit_image_hash_get_algo(fit, noffset, &algo_name)) {
  79                *err_msgp = "Can't get hash algo property";
  80                return -1;
  81        }
  82
  83        padding_name = fdt_getprop(fit, noffset, "padding", NULL);
  84        if (!padding_name)
  85                padding_name = RSA_DEFAULT_PADDING_NAME;
  86
  87        memset(info, '\0', sizeof(*info));
  88        info->keyname = fdt_getprop(fit, noffset, FIT_KEY_HINT, NULL);
  89        info->fit = fit;
  90        info->node_offset = noffset;
  91        info->name = algo_name;
  92        info->checksum = image_get_checksum_algo(algo_name);
  93        info->crypto = image_get_crypto_algo(algo_name);
  94        info->padding = image_get_padding_algo(padding_name);
  95        info->fdt_blob = key_blob;
  96        info->required_keynode = required_keynode;
  97        printf("%s:%s", algo_name, info->keyname);
  98
  99        if (!info->checksum || !info->crypto || !info->padding) {
 100                *err_msgp = "Unknown signature algorithm";
 101                return -1;
 102        }
 103
 104        return 0;
 105}
 106
 107int fit_image_check_sig(const void *fit, int noffset, const void *data,
 108                        size_t size, const void *key_blob, int required_keynode,
 109                        char **err_msgp)
 110{
 111        struct image_sign_info info;
 112        struct image_region region;
 113        uint8_t *fit_value;
 114        int fit_value_len;
 115
 116        *err_msgp = NULL;
 117        if (fit_image_setup_verify(&info, fit, noffset, key_blob,
 118                                   required_keynode, err_msgp))
 119                return -1;
 120
 121        if (fit_image_hash_get_value(fit, noffset, &fit_value,
 122                                     &fit_value_len)) {
 123                *err_msgp = "Can't get hash value property";
 124                return -1;
 125        }
 126
 127        region.data = data;
 128        region.size = size;
 129
 130        if (info.crypto->verify(&info, &region, 1, fit_value, fit_value_len)) {
 131                *err_msgp = "Verification failed";
 132                return -1;
 133        }
 134
 135        return 0;
 136}
 137
 138static int fit_image_verify_sig(const void *fit, int image_noffset,
 139                                const char *data, size_t size,
 140                                const void *key_blob, int key_offset)
 141{
 142        int noffset;
 143        char *err_msg = "";
 144        int verified = 0;
 145        int ret;
 146
 147        /* Process all hash subnodes of the component image node */
 148        fdt_for_each_subnode(noffset, fit, image_noffset) {
 149                const char *name = fit_get_name(fit, noffset, NULL);
 150
 151                /*
 152                 * We don't support this since libfdt considers names with the
 153                 * name root but different @ suffix to be equal
 154                 */
 155                if (strchr(name, '@')) {
 156                        err_msg = "Node name contains @";
 157                        goto error;
 158                }
 159                if (!strncmp(name, FIT_SIG_NODENAME,
 160                             strlen(FIT_SIG_NODENAME))) {
 161                        ret = fit_image_check_sig(fit, noffset, data, size,
 162                                                  key_blob, -1, &err_msg);
 163                        if (ret) {
 164                                puts("- ");
 165                        } else {
 166                                puts("+ ");
 167                                verified = 1;
 168                                break;
 169                        }
 170                }
 171        }
 172
 173        if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
 174                err_msg = "Corrupted or truncated tree";
 175                goto error;
 176        }
 177
 178        return verified ? 0 : -EPERM;
 179
 180error:
 181        printf(" error!\n%s for '%s' hash node in '%s' image node\n",
 182               err_msg, fit_get_name(fit, noffset, NULL),
 183               fit_get_name(fit, image_noffset, NULL));
 184        return -1;
 185}
 186
 187int fit_image_verify_required_sigs(const void *fit, int image_noffset,
 188                                   const char *data, size_t size,
 189                                   const void *key_blob, int *no_sigsp)
 190{
 191        int verify_count = 0;
 192        int noffset;
 193        int key_node;
 194
 195        /* Work out what we need to verify */
 196        *no_sigsp = 1;
 197        key_node = fdt_subnode_offset(key_blob, 0, FIT_SIG_NODENAME);
 198        if (key_node < 0) {
 199                debug("%s: No signature node found: %s\n", __func__,
 200                      fdt_strerror(key_node));
 201                return 0;
 202        }
 203
 204        fdt_for_each_subnode(noffset, key_blob, key_node) {
 205                const char *required;
 206                int ret;
 207
 208                required = fdt_getprop(key_blob, noffset, FIT_KEY_REQUIRED,
 209                                       NULL);
 210                if (!required || strcmp(required, "image"))
 211                        continue;
 212                ret = fit_image_verify_sig(fit, image_noffset, data, size,
 213                                           key_blob, noffset);
 214                if (ret) {
 215                        printf("Failed to verify required signature '%s'\n",
 216                               fit_get_name(key_blob, noffset, NULL));
 217                        return ret;
 218                }
 219                verify_count++;
 220        }
 221
 222        if (verify_count)
 223                *no_sigsp = 0;
 224
 225        return 0;
 226}
 227
 228/**
 229 * fit_config_check_sig() - Check the signature of a config
 230 *
 231 * Here we are looking at a particular signature that needs verification (here
 232 * signature-1):
 233 *
 234 *      configurations {
 235 *              default = "conf-1";
 236 *              conf-1 {
 237 *                      kernel = "kernel-1";
 238 *                      fdt = "fdt-1";
 239 *                      signature-1 {
 240 *                              algo = "sha1,rsa2048";
 241 *                              value = <...conf 1 signature...>;
 242 *                      };
 243 *              };
 244 *
 245 * @fit: FIT to check
 246 * @noffset: Offset of the signature node being checked (e.g.
 247 *       /configurations/conf-1/signature-1)
 248 * @conf_noffset: Offset of configuration node (e.g. /configurations/conf-1)
 249 * @key_blob: Blob containing the keys to check against
 250 * @required_keynode:   Offset in @key_blob of the required key node,
 251 *                      if any. If this is given, then the configuration wil not
 252 *                      pass verification unless that key is used. If this is
 253 *                      -1 then any signature will do.
 254 * @err_msgp:           In the event of an error, this will be pointed to a
 255 *                      help error string to display to the user.
 256 * Return: 0 if all verified ok, <0 on error
 257 */
 258static int fit_config_check_sig(const void *fit, int noffset, int conf_noffset,
 259                                const void *key_blob, int required_keynode,
 260                                char **err_msgp)
 261{
 262        static char * const exc_prop[] = {
 263                "data",
 264                "data-size",
 265                "data-position",
 266                "data-offset"
 267        };
 268
 269        const char *prop, *end, *name;
 270        struct image_sign_info info;
 271        const uint32_t *strings;
 272        const char *config_name;
 273        uint8_t *fit_value;
 274        int fit_value_len;
 275        bool found_config;
 276        int max_regions;
 277        int i, prop_len;
 278        char path[200];
 279        int count;
 280
 281        config_name = fit_get_name(fit, conf_noffset, NULL);
 282        debug("%s: fdt=%p, conf='%s', sig='%s'\n", __func__, key_blob,
 283              fit_get_name(fit, noffset, NULL),
 284              fit_get_name(key_blob, required_keynode, NULL));
 285        *err_msgp = NULL;
 286        if (fit_image_setup_verify(&info, fit, noffset, key_blob,
 287                                   required_keynode, err_msgp))
 288                return -1;
 289
 290        if (fit_image_hash_get_value(fit, noffset, &fit_value,
 291                                     &fit_value_len)) {
 292                *err_msgp = "Can't get hash value property";
 293                return -1;
 294        }
 295
 296        /* Count the number of strings in the property */
 297        prop = fdt_getprop(fit, noffset, "hashed-nodes", &prop_len);
 298        end = prop ? prop + prop_len : prop;
 299        for (name = prop, count = 0; name < end; name++)
 300                if (!*name)
 301                        count++;
 302        if (!count) {
 303                *err_msgp = "Can't get hashed-nodes property";
 304                return -1;
 305        }
 306
 307        if (prop && prop_len > 0 && prop[prop_len - 1] != '\0') {
 308                *err_msgp = "hashed-nodes property must be null-terminated";
 309                return -1;
 310        }
 311
 312        /* Add a sanity check here since we are using the stack */
 313        if (count > IMAGE_MAX_HASHED_NODES) {
 314                *err_msgp = "Number of hashed nodes exceeds maximum";
 315                return -1;
 316        }
 317
 318        /* Create a list of node names from those strings */
 319        char *node_inc[count];
 320
 321        debug("Hash nodes (%d):\n", count);
 322        found_config = false;
 323        for (name = prop, i = 0; name < end; name += strlen(name) + 1, i++) {
 324                debug("   '%s'\n", name);
 325                node_inc[i] = (char *)name;
 326                if (!strncmp(FIT_CONFS_PATH, name, strlen(FIT_CONFS_PATH)) &&
 327                    name[sizeof(FIT_CONFS_PATH) - 1] == '/' &&
 328                    !strcmp(name + sizeof(FIT_CONFS_PATH), config_name)) {
 329                        debug("      (found config node %s)", config_name);
 330                        found_config = true;
 331                }
 332        }
 333        if (!found_config) {
 334                *err_msgp = "Selected config not in hashed nodes";
 335                return -1;
 336        }
 337
 338        /*
 339         * Each node can generate one region for each sub-node. Allow for
 340         * 7 sub-nodes (hash-1, signature-1, etc.) and some extra.
 341         */
 342        max_regions = 20 + count * 7;
 343        struct fdt_region fdt_regions[max_regions];
 344
 345        /* Get a list of regions to hash */
 346        count = fdt_find_regions(fit, node_inc, count,
 347                                 exc_prop, ARRAY_SIZE(exc_prop),
 348                                 fdt_regions, max_regions - 1,
 349                                 path, sizeof(path), 0);
 350        if (count < 0) {
 351                *err_msgp = "Failed to hash configuration";
 352                return -1;
 353        }
 354        if (count == 0) {
 355                *err_msgp = "No data to hash";
 356                return -1;
 357        }
 358        if (count >= max_regions - 1) {
 359                *err_msgp = "Too many hash regions";
 360                return -1;
 361        }
 362
 363        /* Add the strings */
 364        strings = fdt_getprop(fit, noffset, "hashed-strings", NULL);
 365        if (strings) {
 366                /*
 367                 * The strings region offset must be a static 0x0.
 368                 * This is set in tool/image-host.c
 369                 */
 370                fdt_regions[count].offset = fdt_off_dt_strings(fit);
 371                fdt_regions[count].size = fdt32_to_cpu(strings[1]);
 372                count++;
 373        }
 374
 375        /* Allocate the region list on the stack */
 376        struct image_region region[count];
 377
 378        fit_region_make_list(fit, fdt_regions, count, region);
 379        if (info.crypto->verify(&info, region, count, fit_value,
 380                                fit_value_len)) {
 381                *err_msgp = "Verification failed";
 382                return -1;
 383        }
 384
 385        return 0;
 386}
 387
 388/**
 389 * fit_config_verify_key() - Verify that a configuration is signed with a key
 390 *
 391 * Here we are looking at a particular configuration that needs verification:
 392 *
 393 *      configurations {
 394 *              default = "conf-1";
 395 *              conf-1 {
 396 *                      kernel = "kernel-1";
 397 *                      fdt = "fdt-1";
 398 *                      signature-1 {
 399 *                              algo = "sha1,rsa2048";
 400 *                              value = <...conf 1 signature...>;
 401 *                      };
 402 *              };
 403 *
 404 * We must check each of the signature subnodes of conf-1. Hopefully one of them
 405 * will match the key at key_offset.
 406 *
 407 * @fit: FIT to check
 408 * @conf_noffset: Offset of the configuration node to check (e.g.
 409 *      /configurations/conf-1)
 410 * @key_blob: Blob containing the keys to check against
 411 * @key_offset: Offset of the key to check within @key_blob
 412 * @return 0 if OK, -EPERM if any signatures did not verify, or the
 413 *      configuration node has an invalid name
 414 */
 415static int fit_config_verify_key(const void *fit, int conf_noffset,
 416                                 const void *key_blob, int key_offset)
 417{
 418        int noffset;
 419        char *err_msg = "No 'signature' subnode found";
 420        int verified = 0;
 421        int ret;
 422
 423        /* Process all hash subnodes of the component conf node */
 424        fdt_for_each_subnode(noffset, fit, conf_noffset) {
 425                const char *name = fit_get_name(fit, noffset, NULL);
 426
 427                if (!strncmp(name, FIT_SIG_NODENAME,
 428                             strlen(FIT_SIG_NODENAME))) {
 429                        ret = fit_config_check_sig(fit, noffset, conf_noffset,
 430                                                   key_blob, key_offset,
 431                                                   &err_msg);
 432                        if (ret) {
 433                                puts("- ");
 434                        } else {
 435                                puts("+ ");
 436                                verified = 1;
 437                                break;
 438                        }
 439                }
 440        }
 441
 442        if (noffset == -FDT_ERR_TRUNCATED || noffset == -FDT_ERR_BADSTRUCTURE) {
 443                err_msg = "Corrupted or truncated tree";
 444                goto error;
 445        }
 446
 447        if (verified)
 448                return 0;
 449
 450error:
 451        printf(" error!\n%s for '%s' hash node in '%s' config node\n",
 452               err_msg, fit_get_name(fit, noffset, NULL),
 453               fit_get_name(fit, conf_noffset, NULL));
 454        return -EPERM;
 455}
 456
 457/**
 458 * fit_config_verify_required_keys() - verify any required signatures for config
 459 *
 460 * This looks through all the signatures we expect and verifies that at least
 461 * all the required ones are valid signatures for the configuration
 462 *
 463 * @fit: FIT to check
 464 * @conf_noffset: Offset of the configuration node to check (e.g.
 465 *      /configurations/conf-1)
 466 * @key_blob: Blob containing the keys to check against
 467 * @return 0 if OK, -EPERM if any signatures did not verify, or the
 468 *      configuration node has an invalid name
 469 */
 470static int fit_config_verify_required_keys(const void *fit, int conf_noffset,
 471                                           const void *key_blob)
 472{
 473        const char *name = fit_get_name(fit, conf_noffset, NULL);
 474        int noffset;
 475        int key_node;
 476        int verified = 0;
 477        int reqd_sigs = 0;
 478        bool reqd_policy_all = true;
 479        const char *reqd_mode;
 480
 481        /*
 482         * We don't support this since libfdt considers names with the
 483         * name root but different @ suffix to be equal
 484         */
 485        if (strchr(name, '@')) {
 486                printf("Configuration node '%s' contains '@'\n", name);
 487                return -EPERM;
 488        }
 489
 490        /* Work out what we need to verify */
 491        key_node = fdt_subnode_offset(key_blob, 0, FIT_SIG_NODENAME);
 492        if (key_node < 0) {
 493                debug("%s: No signature node found: %s\n", __func__,
 494                      fdt_strerror(key_node));
 495                return 0;
 496        }
 497
 498        /* Get required-mode policy property from DTB */
 499        reqd_mode = fdt_getprop(key_blob, key_node, "required-mode", NULL);
 500        if (reqd_mode && !strcmp(reqd_mode, "any"))
 501                reqd_policy_all = false;
 502
 503        debug("%s: required-mode policy set to '%s'\n", __func__,
 504              reqd_policy_all ? "all" : "any");
 505
 506        /*
 507         * The algorithm here is a little convoluted due to how we want it to
 508         * work. Here we work through each of the signature nodes in the
 509         * public-key area. These are in the U-Boot control devicetree. Each
 510         * node was created by signing a configuration, so we check if it is
 511         * 'required' and if so, request that it be verified.
 512         */
 513        fdt_for_each_subnode(noffset, key_blob, key_node) {
 514                const char *required;
 515                int ret;
 516
 517                required = fdt_getprop(key_blob, noffset, FIT_KEY_REQUIRED,
 518                                       NULL);
 519                if (!required || strcmp(required, "conf"))
 520                        continue;
 521
 522                reqd_sigs++;
 523
 524                ret = fit_config_verify_key(fit, conf_noffset, key_blob,
 525                                            noffset);
 526                if (ret) {
 527                        if (reqd_policy_all) {
 528                                printf("Failed to verify required signature '%s'\n",
 529                                       fit_get_name(key_blob, noffset, NULL));
 530                                return ret;
 531                        }
 532                } else {
 533                        verified++;
 534                        if (!reqd_policy_all)
 535                                break;
 536                }
 537        }
 538
 539        if (reqd_sigs && !verified) {
 540                printf("Failed to verify 'any' of the required signature(s)\n");
 541                return -EPERM;
 542        }
 543
 544        return 0;
 545}
 546
 547int fit_config_verify(const void *fit, int conf_noffset)
 548{
 549        return fit_config_verify_required_keys(fit, conf_noffset,
 550                                               gd_fdt_blob());
 551}
 552