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 "ima.h"
22 
23 static int init_desc(struct hash_desc *desc)
24 {
25 	int rc;
26 
27 	desc->tfm = crypto_alloc_hash(ima_hash, 0, CRYPTO_ALG_ASYNC);
28 	if (IS_ERR(desc->tfm)) {
29 		pr_info("failed to load %s transform: %ld\n",
30 			ima_hash, PTR_ERR(desc->tfm));
31 		rc = PTR_ERR(desc->tfm);
32 		return rc;
33 	}
34 	desc->flags = 0;
35 	rc = crypto_hash_init(desc);
36 	if (rc)
37 		crypto_free_hash(desc->tfm);
38 	return rc;
39 }
40 
41 /*
42  * Calculate the MD5/SHA1 file digest
43  */
44 int ima_calc_hash(struct file *file, char *digest)
45 {
46 	struct hash_desc desc;
47 	struct scatterlist sg[1];
48 	loff_t i_size, offset = 0;
49 	char *rbuf;
50 	int rc;
51 
52 	rc = init_desc(&desc);
53 	if (rc != 0)
54 		return rc;
55 
56 	rbuf = kzalloc(PAGE_SIZE, GFP_KERNEL);
57 	if (!rbuf) {
58 		rc = -ENOMEM;
59 		goto out;
60 	}
61 	i_size = i_size_read(file->f_dentry->d_inode);
62 	while (offset < i_size) {
63 		int rbuf_len;
64 
65 		rbuf_len = kernel_read(file, offset, rbuf, PAGE_SIZE);
66 		if (rbuf_len < 0) {
67 			rc = rbuf_len;
68 			break;
69 		}
70 		if (rbuf_len == 0)
71 			break;
72 		offset += rbuf_len;
73 		sg_init_one(sg, rbuf, rbuf_len);
74 
75 		rc = crypto_hash_update(&desc, sg, rbuf_len);
76 		if (rc)
77 			break;
78 	}
79 	kfree(rbuf);
80 	if (!rc)
81 		rc = crypto_hash_final(&desc, digest);
82 out:
83 	crypto_free_hash(desc.tfm);
84 	return rc;
85 }
86 
87 /*
88  * Calculate the hash of a given template
89  */
90 int ima_calc_template_hash(int template_len, void *template, char *digest)
91 {
92 	struct hash_desc desc;
93 	struct scatterlist sg[1];
94 	int rc;
95 
96 	rc = init_desc(&desc);
97 	if (rc != 0)
98 		return rc;
99 
100 	sg_init_one(sg, template, template_len);
101 	rc = crypto_hash_update(&desc, sg, template_len);
102 	if (!rc)
103 		rc = crypto_hash_final(&desc, digest);
104 	crypto_free_hash(desc.tfm);
105 	return rc;
106 }
107 
108 static void __init ima_pcrread(int idx, u8 *pcr)
109 {
110 	if (!ima_used_chip)
111 		return;
112 
113 	if (tpm_pcr_read(TPM_ANY_NUM, idx, pcr) != 0)
114 		pr_err("Error Communicating to TPM chip\n");
115 }
116 
117 /*
118  * Calculate the boot aggregate hash
119  */
120 int __init ima_calc_boot_aggregate(char *digest)
121 {
122 	struct hash_desc desc;
123 	struct scatterlist sg;
124 	u8 pcr_i[IMA_DIGEST_SIZE];
125 	int rc, i;
126 
127 	rc = init_desc(&desc);
128 	if (rc != 0)
129 		return rc;
130 
131 	/* cumulative sha1 over tpm registers 0-7 */
132 	for (i = TPM_PCR0; i < TPM_PCR8; i++) {
133 		ima_pcrread(i, pcr_i);
134 		/* now accumulate with current aggregate */
135 		sg_init_one(&sg, pcr_i, IMA_DIGEST_SIZE);
136 		rc = crypto_hash_update(&desc, &sg, IMA_DIGEST_SIZE);
137 	}
138 	if (!rc)
139 		crypto_hash_final(&desc, digest);
140 	crypto_free_hash(desc.tfm);
141 	return rc;
142 }
143