linux/crypto/asymmetric_keys/verify_pefile.c
<<
>>
Prefs
   1/* Parse a signed PE binary
   2 *
   3 * Copyright (C) 2014 Red Hat, Inc. All Rights Reserved.
   4 * Written by David Howells (dhowells@redhat.com)
   5 *
   6 * This program is free software; you can redistribute it and/or
   7 * modify it under the terms of the GNU General Public Licence
   8 * as published by the Free Software Foundation; either version
   9 * 2 of the Licence, or (at your option) any later version.
  10 */
  11
  12#define pr_fmt(fmt) "PEFILE: "fmt
  13#include <linux/module.h>
  14#include <linux/kernel.h>
  15#include <linux/slab.h>
  16#include <linux/err.h>
  17#include <linux/pe.h>
  18#include <linux/asn1.h>
  19#include <linux/verification.h>
  20#include <crypto/hash.h>
  21#include "verify_pefile.h"
  22
  23/*
  24 * Parse a PE binary.
  25 */
  26static int pefile_parse_binary(const void *pebuf, unsigned int pelen,
  27                               struct pefile_context *ctx)
  28{
  29        const struct mz_hdr *mz = pebuf;
  30        const struct pe_hdr *pe;
  31        const struct pe32_opt_hdr *pe32;
  32        const struct pe32plus_opt_hdr *pe64;
  33        const struct data_directory *ddir;
  34        const struct data_dirent *dde;
  35        const struct section_header *secs, *sec;
  36        size_t cursor, datalen = pelen;
  37
  38        kenter("");
  39
  40#define chkaddr(base, x, s)                                             \
  41        do {                                                            \
  42                if ((x) < base || (s) >= datalen || (x) > datalen - (s)) \
  43                        return -ELIBBAD;                                \
  44        } while (0)
  45
  46        chkaddr(0, 0, sizeof(*mz));
  47        if (mz->magic != MZ_MAGIC)
  48                return -ELIBBAD;
  49        cursor = sizeof(*mz);
  50
  51        chkaddr(cursor, mz->peaddr, sizeof(*pe));
  52        pe = pebuf + mz->peaddr;
  53        if (pe->magic != PE_MAGIC)
  54                return -ELIBBAD;
  55        cursor = mz->peaddr + sizeof(*pe);
  56
  57        chkaddr(0, cursor, sizeof(pe32->magic));
  58        pe32 = pebuf + cursor;
  59        pe64 = pebuf + cursor;
  60
  61        switch (pe32->magic) {
  62        case PE_OPT_MAGIC_PE32:
  63                chkaddr(0, cursor, sizeof(*pe32));
  64                ctx->image_checksum_offset =
  65                        (unsigned long)&pe32->csum - (unsigned long)pebuf;
  66                ctx->header_size = pe32->header_size;
  67                cursor += sizeof(*pe32);
  68                ctx->n_data_dirents = pe32->data_dirs;
  69                break;
  70
  71        case PE_OPT_MAGIC_PE32PLUS:
  72                chkaddr(0, cursor, sizeof(*pe64));
  73                ctx->image_checksum_offset =
  74                        (unsigned long)&pe64->csum - (unsigned long)pebuf;
  75                ctx->header_size = pe64->header_size;
  76                cursor += sizeof(*pe64);
  77                ctx->n_data_dirents = pe64->data_dirs;
  78                break;
  79
  80        default:
  81                pr_debug("Unknown PEOPT magic = %04hx\n", pe32->magic);
  82                return -ELIBBAD;
  83        }
  84
  85        pr_debug("checksum @ %x\n", ctx->image_checksum_offset);
  86        pr_debug("header size = %x\n", ctx->header_size);
  87
  88        if (cursor >= ctx->header_size || ctx->header_size >= datalen)
  89                return -ELIBBAD;
  90
  91        if (ctx->n_data_dirents > (ctx->header_size - cursor) / sizeof(*dde))
  92                return -ELIBBAD;
  93
  94        ddir = pebuf + cursor;
  95        cursor += sizeof(*dde) * ctx->n_data_dirents;
  96
  97        ctx->cert_dirent_offset =
  98                (unsigned long)&ddir->certs - (unsigned long)pebuf;
  99        ctx->certs_size = ddir->certs.size;
 100
 101        if (!ddir->certs.virtual_address || !ddir->certs.size) {
 102                pr_debug("Unsigned PE binary\n");
 103                return -EKEYREJECTED;
 104        }
 105
 106        chkaddr(ctx->header_size, ddir->certs.virtual_address,
 107                ddir->certs.size);
 108        ctx->sig_offset = ddir->certs.virtual_address;
 109        ctx->sig_len = ddir->certs.size;
 110        pr_debug("cert = %x @%x [%*ph]\n",
 111                 ctx->sig_len, ctx->sig_offset,
 112                 ctx->sig_len, pebuf + ctx->sig_offset);
 113
 114        ctx->n_sections = pe->sections;
 115        if (ctx->n_sections > (ctx->header_size - cursor) / sizeof(*sec))
 116                return -ELIBBAD;
 117        ctx->secs = secs = pebuf + cursor;
 118
 119        return 0;
 120}
 121
 122/*
 123 * Check and strip the PE wrapper from around the signature and check that the
 124 * remnant looks something like PKCS#7.
 125 */
 126static int pefile_strip_sig_wrapper(const void *pebuf,
 127                                    struct pefile_context *ctx)
 128{
 129        struct win_certificate wrapper;
 130        const u8 *pkcs7;
 131        unsigned len;
 132
 133        if (ctx->sig_len < sizeof(wrapper)) {
 134                pr_debug("Signature wrapper too short\n");
 135                return -ELIBBAD;
 136        }
 137
 138        memcpy(&wrapper, pebuf + ctx->sig_offset, sizeof(wrapper));
 139        pr_debug("sig wrapper = { %x, %x, %x }\n",
 140                 wrapper.length, wrapper.revision, wrapper.cert_type);
 141
 142        /* Both pesign and sbsign round up the length of certificate table
 143         * (in optional header data directories) to 8 byte alignment.
 144         */
 145        if (round_up(wrapper.length, 8) != ctx->sig_len) {
 146                pr_debug("Signature wrapper len wrong\n");
 147                return -ELIBBAD;
 148        }
 149        if (wrapper.revision != WIN_CERT_REVISION_2_0) {
 150                pr_debug("Signature is not revision 2.0\n");
 151                return -ENOTSUPP;
 152        }
 153        if (wrapper.cert_type != WIN_CERT_TYPE_PKCS_SIGNED_DATA) {
 154                pr_debug("Signature certificate type is not PKCS\n");
 155                return -ENOTSUPP;
 156        }
 157
 158        /* It looks like the pkcs signature length in wrapper->length and the
 159         * size obtained from the data dir entries, which lists the total size
 160         * of certificate table, are both aligned to an octaword boundary, so
 161         * we may have to deal with some padding.
 162         */
 163        ctx->sig_len = wrapper.length;
 164        ctx->sig_offset += sizeof(wrapper);
 165        ctx->sig_len -= sizeof(wrapper);
 166        if (ctx->sig_len < 4) {
 167                pr_debug("Signature data missing\n");
 168                return -EKEYREJECTED;
 169        }
 170
 171        /* What's left should be a PKCS#7 cert */
 172        pkcs7 = pebuf + ctx->sig_offset;
 173        if (pkcs7[0] != (ASN1_CONS_BIT | ASN1_SEQ))
 174                goto not_pkcs7;
 175
 176        switch (pkcs7[1]) {
 177        case 0 ... 0x7f:
 178                len = pkcs7[1] + 2;
 179                goto check_len;
 180        case ASN1_INDEFINITE_LENGTH:
 181                return 0;
 182        case 0x81:
 183                len = pkcs7[2] + 3;
 184                goto check_len;
 185        case 0x82:
 186                len = ((pkcs7[2] << 8) | pkcs7[3]) + 4;
 187                goto check_len;
 188        case 0x83 ... 0xff:
 189                return -EMSGSIZE;
 190        default:
 191                goto not_pkcs7;
 192        }
 193
 194check_len:
 195        if (len <= ctx->sig_len) {
 196                /* There may be padding */
 197                ctx->sig_len = len;
 198                return 0;
 199        }
 200not_pkcs7:
 201        pr_debug("Signature data not PKCS#7\n");
 202        return -ELIBBAD;
 203}
 204
 205/*
 206 * Compare two sections for canonicalisation.
 207 */
 208static int pefile_compare_shdrs(const void *a, const void *b)
 209{
 210        const struct section_header *shdra = a;
 211        const struct section_header *shdrb = b;
 212        int rc;
 213
 214        if (shdra->data_addr > shdrb->data_addr)
 215                return 1;
 216        if (shdrb->data_addr > shdra->data_addr)
 217                return -1;
 218
 219        if (shdra->virtual_address > shdrb->virtual_address)
 220                return 1;
 221        if (shdrb->virtual_address > shdra->virtual_address)
 222                return -1;
 223
 224        rc = strcmp(shdra->name, shdrb->name);
 225        if (rc != 0)
 226                return rc;
 227
 228        if (shdra->virtual_size > shdrb->virtual_size)
 229                return 1;
 230        if (shdrb->virtual_size > shdra->virtual_size)
 231                return -1;
 232
 233        if (shdra->raw_data_size > shdrb->raw_data_size)
 234                return 1;
 235        if (shdrb->raw_data_size > shdra->raw_data_size)
 236                return -1;
 237
 238        return 0;
 239}
 240
 241/*
 242 * Load the contents of the PE binary into the digest, leaving out the image
 243 * checksum and the certificate data block.
 244 */
 245static int pefile_digest_pe_contents(const void *pebuf, unsigned int pelen,
 246                                     struct pefile_context *ctx,
 247                                     struct shash_desc *desc)
 248{
 249        unsigned *canon, tmp, loop, i, hashed_bytes;
 250        int ret;
 251
 252        /* Digest the header and data directory, but leave out the image
 253         * checksum and the data dirent for the signature.
 254         */
 255        ret = crypto_shash_update(desc, pebuf, ctx->image_checksum_offset);
 256        if (ret < 0)
 257                return ret;
 258
 259        tmp = ctx->image_checksum_offset + sizeof(uint32_t);
 260        ret = crypto_shash_update(desc, pebuf + tmp,
 261                                  ctx->cert_dirent_offset - tmp);
 262        if (ret < 0)
 263                return ret;
 264
 265        tmp = ctx->cert_dirent_offset + sizeof(struct data_dirent);
 266        ret = crypto_shash_update(desc, pebuf + tmp, ctx->header_size - tmp);
 267        if (ret < 0)
 268                return ret;
 269
 270        canon = kcalloc(ctx->n_sections, sizeof(unsigned), GFP_KERNEL);
 271        if (!canon)
 272                return -ENOMEM;
 273
 274        /* We have to canonicalise the section table, so we perform an
 275         * insertion sort.
 276         */
 277        canon[0] = 0;
 278        for (loop = 1; loop < ctx->n_sections; loop++) {
 279                for (i = 0; i < loop; i++) {
 280                        if (pefile_compare_shdrs(&ctx->secs[canon[i]],
 281                                                 &ctx->secs[loop]) > 0) {
 282                                memmove(&canon[i + 1], &canon[i],
 283                                        (loop - i) * sizeof(canon[0]));
 284                                break;
 285                        }
 286                }
 287                canon[i] = loop;
 288        }
 289
 290        hashed_bytes = ctx->header_size;
 291        for (loop = 0; loop < ctx->n_sections; loop++) {
 292                i = canon[loop];
 293                if (ctx->secs[i].raw_data_size == 0)
 294                        continue;
 295                ret = crypto_shash_update(desc,
 296                                          pebuf + ctx->secs[i].data_addr,
 297                                          ctx->secs[i].raw_data_size);
 298                if (ret < 0) {
 299                        kfree(canon);
 300                        return ret;
 301                }
 302                hashed_bytes += ctx->secs[i].raw_data_size;
 303        }
 304        kfree(canon);
 305
 306        if (pelen > hashed_bytes) {
 307                tmp = hashed_bytes + ctx->certs_size;
 308                ret = crypto_shash_update(desc,
 309                                          pebuf + hashed_bytes,
 310                                          pelen - tmp);
 311                if (ret < 0)
 312                        return ret;
 313        }
 314
 315        return 0;
 316}
 317
 318/*
 319 * Digest the contents of the PE binary, leaving out the image checksum and the
 320 * certificate data block.
 321 */
 322static int pefile_digest_pe(const void *pebuf, unsigned int pelen,
 323                            struct pefile_context *ctx)
 324{
 325        struct crypto_shash *tfm;
 326        struct shash_desc *desc;
 327        size_t digest_size, desc_size;
 328        void *digest;
 329        int ret;
 330
 331        kenter(",%s", ctx->digest_algo);
 332
 333        /* Allocate the hashing algorithm we're going to need and find out how
 334         * big the hash operational data will be.
 335         */
 336        tfm = crypto_alloc_shash(ctx->digest_algo, 0, 0);
 337        if (IS_ERR(tfm))
 338                return (PTR_ERR(tfm) == -ENOENT) ? -ENOPKG : PTR_ERR(tfm);
 339
 340        desc_size = crypto_shash_descsize(tfm) + sizeof(*desc);
 341        digest_size = crypto_shash_digestsize(tfm);
 342
 343        if (digest_size != ctx->digest_len) {
 344                pr_debug("Digest size mismatch (%zx != %x)\n",
 345                         digest_size, ctx->digest_len);
 346                ret = -EBADMSG;
 347                goto error_no_desc;
 348        }
 349        pr_debug("Digest: desc=%zu size=%zu\n", desc_size, digest_size);
 350
 351        ret = -ENOMEM;
 352        desc = kzalloc(desc_size + digest_size, GFP_KERNEL);
 353        if (!desc)
 354                goto error_no_desc;
 355
 356        desc->tfm   = tfm;
 357        desc->flags = CRYPTO_TFM_REQ_MAY_SLEEP;
 358        ret = crypto_shash_init(desc);
 359        if (ret < 0)
 360                goto error;
 361
 362        ret = pefile_digest_pe_contents(pebuf, pelen, ctx, desc);
 363        if (ret < 0)
 364                goto error;
 365
 366        digest = (void *)desc + desc_size;
 367        ret = crypto_shash_final(desc, digest);
 368        if (ret < 0)
 369                goto error;
 370
 371        pr_debug("Digest calc = [%*ph]\n", ctx->digest_len, digest);
 372
 373        /* Check that the PE file digest matches that in the MSCODE part of the
 374         * PKCS#7 certificate.
 375         */
 376        if (memcmp(digest, ctx->digest, ctx->digest_len) != 0) {
 377                pr_debug("Digest mismatch\n");
 378                ret = -EKEYREJECTED;
 379        } else {
 380                pr_debug("The digests match!\n");
 381        }
 382
 383error:
 384        kzfree(desc);
 385error_no_desc:
 386        crypto_free_shash(tfm);
 387        kleave(" = %d", ret);
 388        return ret;
 389}
 390
 391/**
 392 * verify_pefile_signature - Verify the signature on a PE binary image
 393 * @pebuf: Buffer containing the PE binary image
 394 * @pelen: Length of the binary image
 395 * @trust_keys: Signing certificate(s) to use as starting points
 396 * @usage: The use to which the key is being put.
 397 *
 398 * Validate that the certificate chain inside the PKCS#7 message inside the PE
 399 * binary image intersects keys we already know and trust.
 400 *
 401 * Returns, in order of descending priority:
 402 *
 403 *  (*) -ELIBBAD if the image cannot be parsed, or:
 404 *
 405 *  (*) -EKEYREJECTED if a signature failed to match for which we have a valid
 406 *      key, or:
 407 *
 408 *  (*) 0 if at least one signature chain intersects with the keys in the trust
 409 *      keyring, or:
 410 *
 411 *  (*) -ENOPKG if a suitable crypto module couldn't be found for a check on a
 412 *      chain.
 413 *
 414 *  (*) -ENOKEY if we couldn't find a match for any of the signature chains in
 415 *      the message.
 416 *
 417 * May also return -ENOMEM.
 418 */
 419int verify_pefile_signature(const void *pebuf, unsigned pelen,
 420                            struct key *trusted_keys,
 421                            enum key_being_used_for usage)
 422{
 423        struct pefile_context ctx;
 424        int ret;
 425
 426        kenter("");
 427
 428        memset(&ctx, 0, sizeof(ctx));
 429        ret = pefile_parse_binary(pebuf, pelen, &ctx);
 430        if (ret < 0)
 431                return ret;
 432
 433        ret = pefile_strip_sig_wrapper(pebuf, &ctx);
 434        if (ret < 0)
 435                return ret;
 436
 437        ret = verify_pkcs7_signature(NULL, 0,
 438                                     pebuf + ctx.sig_offset, ctx.sig_len,
 439                                     trusted_keys, usage,
 440                                     mscode_parse, &ctx);
 441        if (ret < 0)
 442                goto error;
 443
 444        pr_debug("Digest: %u [%*ph]\n",
 445                 ctx.digest_len, ctx.digest_len, ctx.digest);
 446
 447        /* Generate the digest and check against the PKCS7 certificate
 448         * contents.
 449         */
 450        ret = pefile_digest_pe(pebuf, pelen, &ctx);
 451
 452error:
 453        kzfree(ctx.digest);
 454        return ret;
 455}
 456