blob: 22be23f13b3d2bbd1434bd42bd8f1deb78da6d0e [file] [log] [blame]
Mimi Zohar3323eec92009-02-04 09:06:58 -05001/*
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>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090021#include <linux/slab.h>
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +030022#include <crypto/hash.h>
Dmitry Kasatkinc7c8bb22013-04-25 10:43:56 +030023#include <crypto/hash_info.h>
Mimi Zohar3323eec92009-02-04 09:06:58 -050024#include "ima.h"
25
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +030026static struct crypto_shash *ima_shash_tfm;
Mimi Zohar3323eec92009-02-04 09:06:58 -050027
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +030028int ima_init_crypto(void)
29{
30 long rc;
31
Dmitry Kasatkinc7c8bb22013-04-25 10:43:56 +030032 ima_shash_tfm = crypto_alloc_shash(hash_algo_name[ima_hash_algo], 0, 0);
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +030033 if (IS_ERR(ima_shash_tfm)) {
34 rc = PTR_ERR(ima_shash_tfm);
Dmitry Kasatkinc7c8bb22013-04-25 10:43:56 +030035 pr_err("Can not allocate %s (reason: %ld)\n",
36 hash_algo_name[ima_hash_algo], rc);
Mimi Zohar3323eec92009-02-04 09:06:58 -050037 return rc;
38 }
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +030039 return 0;
Mimi Zohar3323eec92009-02-04 09:06:58 -050040}
41
Dmitry Kasatkin723326b2013-07-04 17:40:01 +030042static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo)
43{
44 struct crypto_shash *tfm = ima_shash_tfm;
45 int rc;
46
47 if (algo != ima_hash_algo && algo < HASH_ALGO__LAST) {
48 tfm = crypto_alloc_shash(hash_algo_name[algo], 0, 0);
49 if (IS_ERR(tfm)) {
50 rc = PTR_ERR(tfm);
51 pr_err("Can not allocate %s (reason: %d)\n",
52 hash_algo_name[algo], rc);
53 }
54 }
55 return tfm;
56}
57
58static void ima_free_tfm(struct crypto_shash *tfm)
59{
60 if (tfm != ima_shash_tfm)
61 crypto_free_shash(tfm);
62}
63
Mimi Zohar3323eec92009-02-04 09:06:58 -050064/*
65 * Calculate the MD5/SHA1 file digest
66 */
Dmitry Kasatkinc7c8bb22013-04-25 10:43:56 +030067static int ima_calc_file_hash_tfm(struct file *file,
68 struct ima_digest_data *hash,
69 struct crypto_shash *tfm)
Mimi Zohar3323eec92009-02-04 09:06:58 -050070{
Mimi Zohar16bfa382009-08-21 14:32:49 -040071 loff_t i_size, offset = 0;
Mimi Zohar3323eec92009-02-04 09:06:58 -050072 char *rbuf;
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -050073 int rc, read = 0;
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +030074 struct {
75 struct shash_desc shash;
Dmitry Kasatkinc7c8bb22013-04-25 10:43:56 +030076 char ctx[crypto_shash_descsize(tfm)];
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +030077 } desc;
Mimi Zohar3323eec92009-02-04 09:06:58 -050078
Dmitry Kasatkinc7c8bb22013-04-25 10:43:56 +030079 desc.shash.tfm = tfm;
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +030080 desc.shash.flags = 0;
81
Dmitry Kasatkin723326b2013-07-04 17:40:01 +030082 hash->length = crypto_shash_digestsize(tfm);
83
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +030084 rc = crypto_shash_init(&desc.shash);
Mimi Zohar3323eec92009-02-04 09:06:58 -050085 if (rc != 0)
86 return rc;
87
88 rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL);
89 if (!rbuf) {
90 rc = -ENOMEM;
91 goto out;
92 }
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -050093 if (!(file->f_mode & FMODE_READ)) {
94 file->f_mode |= FMODE_READ;
95 read = 1;
96 }
Al Viro496ad9a2013-01-23 17:07:38 -050097 i_size = i_size_read(file_inode(file));
Mimi Zohar3323eec92009-02-04 09:06:58 -050098 while (offset < i_size) {
99 int rbuf_len;
100
101 rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE);
102 if (rbuf_len < 0) {
103 rc = rbuf_len;
104 break;
105 }
Mimi Zohar16bfa382009-08-21 14:32:49 -0400106 if (rbuf_len == 0)
107 break;
Mimi Zohar3323eec92009-02-04 09:06:58 -0500108 offset += rbuf_len;
Mimi Zohar3323eec92009-02-04 09:06:58 -0500109
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +0300110 rc = crypto_shash_update(&desc.shash, rbuf, rbuf_len);
Mimi Zohar3323eec92009-02-04 09:06:58 -0500111 if (rc)
112 break;
113 }
114 kfree(rbuf);
115 if (!rc)
Dmitry Kasatkinc7c8bb22013-04-25 10:43:56 +0300116 rc = crypto_shash_final(&desc.shash, hash->digest);
Mimi Zohar2fe5d6d2012-02-13 10:15:05 -0500117 if (read)
118 file->f_mode &= ~FMODE_READ;
Mimi Zohar3323eec92009-02-04 09:06:58 -0500119out:
Mimi Zohar3323eec92009-02-04 09:06:58 -0500120 return rc;
121}
122
Dmitry Kasatkinc7c8bb22013-04-25 10:43:56 +0300123int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash)
124{
Dmitry Kasatkin723326b2013-07-04 17:40:01 +0300125 struct crypto_shash *tfm;
Dmitry Kasatkinc7c8bb22013-04-25 10:43:56 +0300126 int rc;
127
Dmitry Kasatkin723326b2013-07-04 17:40:01 +0300128 tfm = ima_alloc_tfm(hash->algo);
129 if (IS_ERR(tfm))
130 return PTR_ERR(tfm);
Dmitry Kasatkinc7c8bb22013-04-25 10:43:56 +0300131
132 rc = ima_calc_file_hash_tfm(file, hash, tfm);
133
Dmitry Kasatkin723326b2013-07-04 17:40:01 +0300134 ima_free_tfm(tfm);
Dmitry Kasatkinc7c8bb22013-04-25 10:43:56 +0300135
136 return rc;
137}
138
Mimi Zohar3323eec92009-02-04 09:06:58 -0500139/*
Dmitry Kasatkin50af5542012-05-14 14:13:56 +0300140 * Calculate the hash of a given buffer
Mimi Zohar3323eec92009-02-04 09:06:58 -0500141 */
Dmitry Kasatkinea593992013-06-07 12:16:24 +0200142static int ima_calc_buffer_hash_tfm(const void *buf, int len,
143 struct ima_digest_data *hash,
144 struct crypto_shash *tfm)
Mimi Zohar3323eec92009-02-04 09:06:58 -0500145{
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +0300146 struct {
147 struct shash_desc shash;
Dmitry Kasatkinea593992013-06-07 12:16:24 +0200148 char ctx[crypto_shash_descsize(tfm)];
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +0300149 } desc;
Mimi Zohar3323eec92009-02-04 09:06:58 -0500150
Dmitry Kasatkinea593992013-06-07 12:16:24 +0200151 desc.shash.tfm = tfm;
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +0300152 desc.shash.flags = 0;
Mimi Zohar3323eec92009-02-04 09:06:58 -0500153
Dmitry Kasatkinea593992013-06-07 12:16:24 +0200154 hash->length = crypto_shash_digestsize(tfm);
Dmitry Kasatkinc7c8bb22013-04-25 10:43:56 +0300155
156 return crypto_shash_digest(&desc.shash, buf, len, hash->digest);
Mimi Zohar3323eec92009-02-04 09:06:58 -0500157}
158
Dmitry Kasatkinea593992013-06-07 12:16:24 +0200159int ima_calc_buffer_hash(const void *buf, int len, struct ima_digest_data *hash)
160{
161 struct crypto_shash *tfm;
162 int rc;
163
164 tfm = ima_alloc_tfm(hash->algo);
165 if (IS_ERR(tfm))
166 return PTR_ERR(tfm);
167
168 rc = ima_calc_buffer_hash_tfm(buf, len, hash, tfm);
169
170 ima_free_tfm(tfm);
171
172 return rc;
173}
174
Eric Paris932995f2009-05-21 15:43:32 -0400175static void __init ima_pcrread(int idx, u8 *pcr)
Mimi Zohar3323eec92009-02-04 09:06:58 -0500176{
177 if (!ima_used_chip)
178 return;
179
180 if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0)
Eric Pariseb8dae92010-04-22 10:49:36 -0400181 pr_err("IMA: Error Communicating to TPM chip\n");
Mimi Zohar3323eec92009-02-04 09:06:58 -0500182}
183
184/*
185 * Calculate the boot aggregate hash
186 */
Dmitry Kasatkin09ef5432013-06-07 12:16:25 +0200187static int __init ima_calc_boot_aggregate_tfm(char *digest,
188 struct crypto_shash *tfm)
Mimi Zohar3323eec92009-02-04 09:06:58 -0500189{
Mimi Zohar140d8022013-03-11 20:29:47 -0400190 u8 pcr_i[TPM_DIGEST_SIZE];
Mimi Zohar3323eec92009-02-04 09:06:58 -0500191 int rc, i;
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +0300192 struct {
193 struct shash_desc shash;
Dmitry Kasatkin09ef5432013-06-07 12:16:25 +0200194 char ctx[crypto_shash_descsize(tfm)];
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +0300195 } desc;
Mimi Zohar3323eec92009-02-04 09:06:58 -0500196
Dmitry Kasatkin09ef5432013-06-07 12:16:25 +0200197 desc.shash.tfm = tfm;
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +0300198 desc.shash.flags = 0;
199
200 rc = crypto_shash_init(&desc.shash);
Mimi Zohar3323eec92009-02-04 09:06:58 -0500201 if (rc != 0)
202 return rc;
203
204 /* cumulative sha1 over tpm registers 0-7 */
205 for (i = TPM_PCR0; i < TPM_PCR8; i++) {
206 ima_pcrread(i, pcr_i);
207 /* now accumulate with current aggregate */
Mimi Zohar140d8022013-03-11 20:29:47 -0400208 rc = crypto_shash_update(&desc.shash, pcr_i, TPM_DIGEST_SIZE);
Mimi Zohar3323eec92009-02-04 09:06:58 -0500209 }
210 if (!rc)
Dmitry Kasatkin76bb28f2012-06-08 10:42:30 +0300211 crypto_shash_final(&desc.shash, digest);
Mimi Zohar3323eec92009-02-04 09:06:58 -0500212 return rc;
213}
Dmitry Kasatkin09ef5432013-06-07 12:16:25 +0200214
215int __init ima_calc_boot_aggregate(struct ima_digest_data *hash)
216{
217 struct crypto_shash *tfm;
218 int rc;
219
220 tfm = ima_alloc_tfm(hash->algo);
221 if (IS_ERR(tfm))
222 return PTR_ERR(tfm);
223
224 hash->length = crypto_shash_digestsize(tfm);
225 rc = ima_calc_boot_aggregate_tfm(hash->digest, tfm);
226
227 ima_free_tfm(tfm);
228
229 return rc;
230}