Commit | Line | Data |
---|---|---|
3323eec9 MZ |
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 | |
2bb930ab | 13 | * Calculates md5/sha1 file hash, template hash, boot-aggreate hash |
3323eec9 MZ |
14 | */ |
15 | ||
20ee451f JP |
16 | #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
17 | ||
3323eec9 MZ |
18 | #include <linux/kernel.h> |
19 | #include <linux/file.h> | |
20 | #include <linux/crypto.h> | |
21 | #include <linux/scatterlist.h> | |
22 | #include <linux/err.h> | |
5a0e3ad6 | 23 | #include <linux/slab.h> |
76bb28f6 | 24 | #include <crypto/hash.h> |
c7c8bb23 | 25 | #include <crypto/hash_info.h> |
3323eec9 MZ |
26 | #include "ima.h" |
27 | ||
76bb28f6 DK |
28 | static struct crypto_shash *ima_shash_tfm; |
29 | ||
30 | int ima_init_crypto(void) | |
3323eec9 | 31 | { |
76bb28f6 | 32 | long rc; |
3323eec9 | 33 | |
c7c8bb23 | 34 | ima_shash_tfm = crypto_alloc_shash(hash_algo_name[ima_hash_algo], 0, 0); |
76bb28f6 DK |
35 | if (IS_ERR(ima_shash_tfm)) { |
36 | rc = PTR_ERR(ima_shash_tfm); | |
c7c8bb23 DK |
37 | pr_err("Can not allocate %s (reason: %ld)\n", |
38 | hash_algo_name[ima_hash_algo], rc); | |
3323eec9 MZ |
39 | return rc; |
40 | } | |
76bb28f6 | 41 | return 0; |
3323eec9 MZ |
42 | } |
43 | ||
723326b9 DK |
44 | static struct crypto_shash *ima_alloc_tfm(enum hash_algo algo) |
45 | { | |
46 | struct crypto_shash *tfm = ima_shash_tfm; | |
47 | int rc; | |
48 | ||
49 | if (algo != ima_hash_algo && algo < HASH_ALGO__LAST) { | |
50 | tfm = crypto_alloc_shash(hash_algo_name[algo], 0, 0); | |
51 | if (IS_ERR(tfm)) { | |
52 | rc = PTR_ERR(tfm); | |
53 | pr_err("Can not allocate %s (reason: %d)\n", | |
54 | hash_algo_name[algo], rc); | |
55 | } | |
56 | } | |
57 | return tfm; | |
58 | } | |
59 | ||
60 | static void ima_free_tfm(struct crypto_shash *tfm) | |
61 | { | |
62 | if (tfm != ima_shash_tfm) | |
63 | crypto_free_shash(tfm); | |
64 | } | |
65 | ||
3323eec9 MZ |
66 | /* |
67 | * Calculate the MD5/SHA1 file digest | |
68 | */ | |
c7c8bb23 DK |
69 | static int ima_calc_file_hash_tfm(struct file *file, |
70 | struct ima_digest_data *hash, | |
71 | struct crypto_shash *tfm) | |
3323eec9 | 72 | { |
16bfa38b | 73 | loff_t i_size, offset = 0; |
3323eec9 | 74 | char *rbuf; |
2fe5d6de | 75 | int rc, read = 0; |
76bb28f6 DK |
76 | struct { |
77 | struct shash_desc shash; | |
c7c8bb23 | 78 | char ctx[crypto_shash_descsize(tfm)]; |
76bb28f6 | 79 | } desc; |
3323eec9 | 80 | |
c7c8bb23 | 81 | desc.shash.tfm = tfm; |
76bb28f6 DK |
82 | desc.shash.flags = 0; |
83 | ||
723326b9 DK |
84 | hash->length = crypto_shash_digestsize(tfm); |
85 | ||
76bb28f6 | 86 | rc = crypto_shash_init(&desc.shash); |
3323eec9 MZ |
87 | if (rc != 0) |
88 | return rc; | |
89 | ||
1d91ac62 DK |
90 | i_size = i_size_read(file_inode(file)); |
91 | ||
92 | if (i_size == 0) | |
3323eec9 | 93 | goto out; |
1d91ac62 DK |
94 | |
95 | rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL); | |
96 | if (!rbuf) | |
97 | return -ENOMEM; | |
98 | ||
2fe5d6de MZ |
99 | if (!(file->f_mode & FMODE_READ)) { |
100 | file->f_mode |= FMODE_READ; | |
101 | read = 1; | |
102 | } | |
1d91ac62 | 103 | |
3323eec9 MZ |
104 | while (offset < i_size) { |
105 | int rbuf_len; | |
106 | ||
107 | rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE); | |
108 | if (rbuf_len < 0) { | |
109 | rc = rbuf_len; | |
110 | break; | |
111 | } | |
16bfa38b MZ |
112 | if (rbuf_len == 0) |
113 | break; | |
3323eec9 | 114 | offset += rbuf_len; |
3323eec9 | 115 | |
76bb28f6 | 116 | rc = crypto_shash_update(&desc.shash, rbuf, rbuf_len); |
3323eec9 MZ |
117 | if (rc) |
118 | break; | |
119 | } | |
2fe5d6de MZ |
120 | if (read) |
121 | file->f_mode &= ~FMODE_READ; | |
1d91ac62 | 122 | kfree(rbuf); |
3323eec9 | 123 | out: |
1d91ac62 DK |
124 | if (!rc) |
125 | rc = crypto_shash_final(&desc.shash, hash->digest); | |
3323eec9 MZ |
126 | return rc; |
127 | } | |
128 | ||
c7c8bb23 DK |
129 | int ima_calc_file_hash(struct file *file, struct ima_digest_data *hash) |
130 | { | |
723326b9 | 131 | struct crypto_shash *tfm; |
c7c8bb23 DK |
132 | int rc; |
133 | ||
723326b9 DK |
134 | tfm = ima_alloc_tfm(hash->algo); |
135 | if (IS_ERR(tfm)) | |
136 | return PTR_ERR(tfm); | |
c7c8bb23 DK |
137 | |
138 | rc = ima_calc_file_hash_tfm(file, hash, tfm); | |
139 | ||
723326b9 | 140 | ima_free_tfm(tfm); |
c7c8bb23 DK |
141 | |
142 | return rc; | |
143 | } | |
144 | ||
3323eec9 | 145 | /* |
a71dc65d | 146 | * Calculate the hash of template data |
3323eec9 | 147 | */ |
a71dc65d | 148 | static int ima_calc_field_array_hash_tfm(struct ima_field_data *field_data, |
b6f8f16f | 149 | struct ima_template_desc *td, |
a71dc65d RS |
150 | int num_fields, |
151 | struct ima_digest_data *hash, | |
152 | struct crypto_shash *tfm) | |
3323eec9 | 153 | { |
76bb28f6 DK |
154 | struct { |
155 | struct shash_desc shash; | |
ea593993 | 156 | char ctx[crypto_shash_descsize(tfm)]; |
76bb28f6 | 157 | } desc; |
a71dc65d | 158 | int rc, i; |
3323eec9 | 159 | |
ea593993 | 160 | desc.shash.tfm = tfm; |
76bb28f6 | 161 | desc.shash.flags = 0; |
3323eec9 | 162 | |
ea593993 | 163 | hash->length = crypto_shash_digestsize(tfm); |
c7c8bb23 | 164 | |
a71dc65d RS |
165 | rc = crypto_shash_init(&desc.shash); |
166 | if (rc != 0) | |
167 | return rc; | |
168 | ||
169 | for (i = 0; i < num_fields; i++) { | |
e3b64c26 RS |
170 | u8 buffer[IMA_EVENT_NAME_LEN_MAX + 1] = { 0 }; |
171 | u8 *data_to_hash = field_data[i].data; | |
172 | u32 datalen = field_data[i].len; | |
173 | ||
b6f8f16f RS |
174 | if (strcmp(td->name, IMA_TEMPLATE_IMA_NAME) != 0) { |
175 | rc = crypto_shash_update(&desc.shash, | |
176 | (const u8 *) &field_data[i].len, | |
177 | sizeof(field_data[i].len)); | |
178 | if (rc) | |
179 | break; | |
e3b64c26 RS |
180 | } else if (strcmp(td->fields[i]->field_id, "n") == 0) { |
181 | memcpy(buffer, data_to_hash, datalen); | |
182 | data_to_hash = buffer; | |
183 | datalen = IMA_EVENT_NAME_LEN_MAX + 1; | |
b6f8f16f | 184 | } |
e3b64c26 | 185 | rc = crypto_shash_update(&desc.shash, data_to_hash, datalen); |
a71dc65d RS |
186 | if (rc) |
187 | break; | |
188 | } | |
189 | ||
190 | if (!rc) | |
191 | rc = crypto_shash_final(&desc.shash, hash->digest); | |
192 | ||
193 | return rc; | |
3323eec9 MZ |
194 | } |
195 | ||
b6f8f16f RS |
196 | int ima_calc_field_array_hash(struct ima_field_data *field_data, |
197 | struct ima_template_desc *desc, int num_fields, | |
a71dc65d | 198 | struct ima_digest_data *hash) |
ea593993 DK |
199 | { |
200 | struct crypto_shash *tfm; | |
201 | int rc; | |
202 | ||
203 | tfm = ima_alloc_tfm(hash->algo); | |
204 | if (IS_ERR(tfm)) | |
205 | return PTR_ERR(tfm); | |
206 | ||
b6f8f16f RS |
207 | rc = ima_calc_field_array_hash_tfm(field_data, desc, num_fields, |
208 | hash, tfm); | |
ea593993 DK |
209 | |
210 | ima_free_tfm(tfm); | |
211 | ||
212 | return rc; | |
213 | } | |
214 | ||
932995f0 | 215 | static void __init ima_pcrread(int idx, u8 *pcr) |
3323eec9 MZ |
216 | { |
217 | if (!ima_used_chip) | |
218 | return; | |
219 | ||
220 | if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0) | |
20ee451f | 221 | pr_err("Error Communicating to TPM chip\n"); |
3323eec9 MZ |
222 | } |
223 | ||
224 | /* | |
225 | * Calculate the boot aggregate hash | |
226 | */ | |
09ef5435 DK |
227 | static int __init ima_calc_boot_aggregate_tfm(char *digest, |
228 | struct crypto_shash *tfm) | |
3323eec9 | 229 | { |
140d8022 | 230 | u8 pcr_i[TPM_DIGEST_SIZE]; |
3323eec9 | 231 | int rc, i; |
76bb28f6 DK |
232 | struct { |
233 | struct shash_desc shash; | |
09ef5435 | 234 | char ctx[crypto_shash_descsize(tfm)]; |
76bb28f6 DK |
235 | } desc; |
236 | ||
09ef5435 | 237 | desc.shash.tfm = tfm; |
76bb28f6 | 238 | desc.shash.flags = 0; |
3323eec9 | 239 | |
76bb28f6 | 240 | rc = crypto_shash_init(&desc.shash); |
3323eec9 MZ |
241 | if (rc != 0) |
242 | return rc; | |
243 | ||
244 | /* cumulative sha1 over tpm registers 0-7 */ | |
245 | for (i = TPM_PCR0; i < TPM_PCR8; i++) { | |
246 | ima_pcrread(i, pcr_i); | |
247 | /* now accumulate with current aggregate */ | |
140d8022 | 248 | rc = crypto_shash_update(&desc.shash, pcr_i, TPM_DIGEST_SIZE); |
3323eec9 MZ |
249 | } |
250 | if (!rc) | |
76bb28f6 | 251 | crypto_shash_final(&desc.shash, digest); |
3323eec9 MZ |
252 | return rc; |
253 | } | |
09ef5435 DK |
254 | |
255 | int __init ima_calc_boot_aggregate(struct ima_digest_data *hash) | |
256 | { | |
257 | struct crypto_shash *tfm; | |
258 | int rc; | |
259 | ||
260 | tfm = ima_alloc_tfm(hash->algo); | |
261 | if (IS_ERR(tfm)) | |
262 | return PTR_ERR(tfm); | |
263 | ||
264 | hash->length = crypto_shash_digestsize(tfm); | |
265 | rc = ima_calc_boot_aggregate_tfm(hash->digest, tfm); | |
266 | ||
267 | ima_free_tfm(tfm); | |
268 | ||
269 | return rc; | |
270 | } |