linux/security/integrity/ima/ima_crypto.c
<<
>>
Prefs
   1/*
   2 * Copyright (C) 2005,2006,2007,2008 IBM Corporation
   3 *
   4 * Authors:
   5 * Mimi Zohar <zohar@us.ibm.com>
   6 * Kylene Hall <kjhall@us.ibm.com>
   7 *
   8 * This program is free software; you can redistribute it and/or modify
   9 * it under the terms of the GNU General Public License as published by
  10 * the Free Software Foundation, version 2 of the License.
  11 *
  12 * File: ima_crypto.c
  13 *      Calculates md5/sha1 file hash, template hash, boot-aggreate hash
  14 */
  15
  16#include <linux/kernel.h>
  17#include <linux/file.h>
  18#include <linux/crypto.h>
  19#include <linux/scatterlist.h>
  20#include <linux/err.h>
  21#include <linux/slab.h>
  22#include "ima.h"
  23
  24static int init_desc(struct hash_desc *desc)
  25{
  26        int rc;
  27
  28        desc->tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC);
  29        if (IS_ERR(desc->tfm)) {
  30                pr_info("IMA: failed to load %s transform: %ld\n",
  31                        ima_hash, PTR_ERR(desc->tfm));
  32                rc = PTR_ERR(desc->tfm);
  33                return rc;
  34        }
  35        desc->flags = 0;
  36        rc = crypto_hash_init(desc);
  37        if (rc)
  38                crypto_free_hash(desc->tfm);
  39        return rc;
  40}
  41
  42/*
  43 * Calculate the MD5/SHA1 file digest
  44 */
  45int ima_calc_hash(struct file *file, char *digest)
  46{
  47        struct hash_desc desc;
  48        struct scatterlist sg[1];
  49        loff_t i_size, offset = 0;
  50        char *rbuf;
  51        int rc;
  52
  53        rc = init_desc(&desc);
  54        if (rc != 0)
  55                return rc;
  56
  57        rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL);
  58        if (!rbuf) {
  59                rc = -ENOMEM;
  60                goto out;
  61        }
  62        i_size = i_size_read(file->f_dentry->d_inode);
  63        while (offset < i_size) {
  64                int rbuf_len;
  65
  66                rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE);
  67                if (rbuf_len < 0) {
  68                        rc = rbuf_len;
  69                        break;
  70                }
  71                if (rbuf_len == 0)
  72                        break;
  73                offset += rbuf_len;
  74                sg_init_one(sg, rbuf, rbuf_len);
  75
  76                rc = crypto_hash_update(&desc, sg, rbuf_len);
  77                if (rc)
  78                        break;
  79        }
  80        kfree(rbuf);
  81        if (!rc)
  82                rc = crypto_hash_final(&desc, digest);
  83out:
  84        crypto_free_hash(desc.tfm);
  85        return rc;
  86}
  87
  88/*
  89 * Calculate the hash of a given template
  90 */
  91int ima_calc_template_hash(int template_len, void *template, char *digest)
  92{
  93        struct hash_desc desc;
  94        struct scatterlist sg[1];
  95        int rc;
  96
  97        rc = init_desc(&desc);
  98        if (rc != 0)
  99                return rc;
 100
 101        sg_init_one(sg, template, template_len);
 102        rc = crypto_hash_update(&desc, sg, template_len);
 103        if (!rc)
 104                rc = crypto_hash_final(&desc, digest);
 105        crypto_free_hash(desc.tfm);
 106        return rc;
 107}
 108
 109static void __init ima_pcrread(int idx, u8 *pcr)
 110{
 111        if (!ima_used_chip)
 112                return;
 113
 114        if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0)
 115                pr_err("IMA: Error Communicating to TPM chip\n");
 116}
 117
 118/*
 119 * Calculate the boot aggregate hash
 120 */
 121int __init ima_calc_boot_aggregate(char *digest)
 122{
 123        struct hash_desc desc;
 124        struct scatterlist sg;
 125        u8 pcr_i[IMA_DIGEST_SIZE];
 126        int rc, i;
 127
 128        rc = init_desc(&desc);
 129        if (rc != 0)
 130                return rc;
 131
 132        /* cumulative sha1 over tpm registers 0-7 */
 133        for (i = TPM_PCR0; i < TPM_PCR8; i++) {
 134                ima_pcrread(i, pcr_i);
 135                /* now accumulate with current aggregate */
 136                sg_init_one(&sg, pcr_i, IMA_DIGEST_SIZE);
 137                rc = crypto_hash_update(&desc, &sg, IMA_DIGEST_SIZE);
 138        }
 139        if (!rc)
 140                crypto_hash_final(&desc, digest);
 141        crypto_free_hash(desc.tfm);
 142        return rc;
 143}
 144