linux/security/integrity/ima/ima_modsig.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0+
   2/*
   3 * IMA support for appraising module-style appended signatures.
   4 *
   5 * Copyright (C) 2019  IBM Corporation
   6 *
   7 * Author:
   8 * Thiago Jung Bauermann <bauerman@linux.ibm.com>
   9 */
  10
  11#include <linux/types.h>
  12#include <linux/module_signature.h>
  13#include <keys/asymmetric-type.h>
  14#include <crypto/pkcs7.h>
  15
  16#include "ima.h"
  17
  18struct modsig {
  19        struct pkcs7_message *pkcs7_msg;
  20
  21        enum hash_algo hash_algo;
  22
  23        /* This digest will go in the 'd-modsig' field of the IMA template. */
  24        const u8 *digest;
  25        u32 digest_size;
  26
  27        /*
  28         * This is what will go to the measurement list if the template requires
  29         * storing the signature.
  30         */
  31        int raw_pkcs7_len;
  32        u8 raw_pkcs7[];
  33};
  34
  35/*
  36 * ima_read_modsig - Read modsig from buf.
  37 *
  38 * Return: 0 on success, error code otherwise.
  39 */
  40int ima_read_modsig(enum ima_hooks func, const void *buf, loff_t buf_len,
  41                    struct modsig **modsig)
  42{
  43        const size_t marker_len = strlen(MODULE_SIG_STRING);
  44        const struct module_signature *sig;
  45        struct modsig *hdr;
  46        size_t sig_len;
  47        const void *p;
  48        int rc;
  49
  50        if (buf_len <= marker_len + sizeof(*sig))
  51                return -ENOENT;
  52
  53        p = buf + buf_len - marker_len;
  54        if (memcmp(p, MODULE_SIG_STRING, marker_len))
  55                return -ENOENT;
  56
  57        buf_len -= marker_len;
  58        sig = (const struct module_signature *)(p - sizeof(*sig));
  59
  60        rc = mod_check_sig(sig, buf_len, func_tokens[func]);
  61        if (rc)
  62                return rc;
  63
  64        sig_len = be32_to_cpu(sig->sig_len);
  65        buf_len -= sig_len + sizeof(*sig);
  66
  67        /* Allocate sig_len additional bytes to hold the raw PKCS#7 data. */
  68        hdr = kzalloc(sizeof(*hdr) + sig_len, GFP_KERNEL);
  69        if (!hdr)
  70                return -ENOMEM;
  71
  72        hdr->pkcs7_msg = pkcs7_parse_message(buf + buf_len, sig_len);
  73        if (IS_ERR(hdr->pkcs7_msg)) {
  74                rc = PTR_ERR(hdr->pkcs7_msg);
  75                kfree(hdr);
  76                return rc;
  77        }
  78
  79        memcpy(hdr->raw_pkcs7, buf + buf_len, sig_len);
  80        hdr->raw_pkcs7_len = sig_len;
  81
  82        /* We don't know the hash algorithm yet. */
  83        hdr->hash_algo = HASH_ALGO__LAST;
  84
  85        *modsig = hdr;
  86
  87        return 0;
  88}
  89
  90/**
  91 * ima_collect_modsig - Calculate the file hash without the appended signature.
  92 *
  93 * Since the modsig is part of the file contents, the hash used in its signature
  94 * isn't the same one ordinarily calculated by IMA. Therefore PKCS7 code
  95 * calculates a separate one for signature verification.
  96 */
  97void ima_collect_modsig(struct modsig *modsig, const void *buf, loff_t size)
  98{
  99        int rc;
 100
 101        /*
 102         * Provide the file contents (minus the appended sig) so that the PKCS7
 103         * code can calculate the file hash.
 104         */
 105        size -= modsig->raw_pkcs7_len + strlen(MODULE_SIG_STRING) +
 106                sizeof(struct module_signature);
 107        rc = pkcs7_supply_detached_data(modsig->pkcs7_msg, buf, size);
 108        if (rc)
 109                return;
 110
 111        /* Ask the PKCS7 code to calculate the file hash. */
 112        rc = pkcs7_get_digest(modsig->pkcs7_msg, &modsig->digest,
 113                              &modsig->digest_size, &modsig->hash_algo);
 114}
 115
 116int ima_modsig_verify(struct key *keyring, const struct modsig *modsig)
 117{
 118        return verify_pkcs7_message_sig(NULL, 0, modsig->pkcs7_msg, keyring,
 119                                        VERIFYING_MODULE_SIGNATURE, NULL, NULL);
 120}
 121
 122int ima_get_modsig_digest(const struct modsig *modsig, enum hash_algo *algo,
 123                          const u8 **digest, u32 *digest_size)
 124{
 125        *algo = modsig->hash_algo;
 126        *digest = modsig->digest;
 127        *digest_size = modsig->digest_size;
 128
 129        return 0;
 130}
 131
 132int ima_get_raw_modsig(const struct modsig *modsig, const void **data,
 133                       u32 *data_len)
 134{
 135        *data = &modsig->raw_pkcs7;
 136        *data_len = modsig->raw_pkcs7_len;
 137
 138        return 0;
 139}
 140
 141void ima_free_modsig(struct modsig *modsig)
 142{
 143        if (!modsig)
 144                return;
 145
 146        pkcs7_free_message(modsig->pkcs7_msg);
 147        kfree(modsig);
 148}
 149