1 /*
2 * Copyright (c) International Business Machines Corp., 2008
3 *
4 * Authors:
5 * Reiner Sailer <sailer@watson.ibm.com>
6 * Mimi Zohar <zohar@us.ibm.com>
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License as
10 * published by the Free Software Foundation, version 2 of the
11 * License.
12 *
13 * File: ima_measure.c
14 *
15 * Calculate the SHA1 aggregate-pcr value based on the IMA runtime
16 * binary measurements.
17 */
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <sys/types.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include "config.h"
27 #include "test.h"
28
29 char *TCID = "ima_measure";
30
31 #if HAVE_LIBCRYPTO
32 #include <openssl/sha.h>
33
34 #define TCG_EVENT_NAME_LEN_MAX 255
35
36 int TST_TOTAL = 1;
37
38 static int verbose;
39
40 #define print_info(format, arg...) \
41 if (verbose) \
42 printf(format, ##arg)
43
44 static u_int8_t zero[SHA_DIGEST_LENGTH];
45 static u_int8_t fox[SHA_DIGEST_LENGTH];
46
47 struct event {
48 struct {
49 u_int32_t pcr;
50 u_int8_t digest[SHA_DIGEST_LENGTH];
51 u_int32_t name_len;
52 } header;
53 char name[TCG_EVENT_NAME_LEN_MAX + 1];
54 struct {
55 u_int8_t digest[SHA_DIGEST_LENGTH];
56 char filename[TCG_EVENT_NAME_LEN_MAX + 1];
57 } ima_data;
58 int filename_len;
59 };
60
display_sha1_digest(u_int8_t * digest)61 static void display_sha1_digest(u_int8_t * digest)
62 {
63 int i;
64
65 for (i = 0; i < 20; i++)
66 print_info(" %02X", (*(digest + i) & 0xff));
67 }
68
69 /*
70 * Calculate the sha1 hash of data
71 */
calc_digest(u_int8_t * digest,int len,void * data)72 static void calc_digest(u_int8_t * digest, int len, void *data)
73 {
74 SHA_CTX c;
75
76 /* Calc template hash for an ima entry */
77 memset(digest, 0, sizeof *digest);
78 SHA1_Init(&c);
79 SHA1_Update(&c, data, len);
80 SHA1_Final(digest, &c);
81 }
82
verify_template_hash(struct event * template)83 static int verify_template_hash(struct event *template)
84 {
85 int rc;
86
87 rc = memcmp(fox, template->header.digest, sizeof fox);
88 if (rc != 0) {
89 u_int8_t digest[SHA_DIGEST_LENGTH];
90
91 memset(digest, 0, sizeof digest);
92 calc_digest(digest, sizeof template->ima_data,
93 &template->ima_data);
94 rc = memcmp(digest, template->header.digest, sizeof digest);
95 return rc != 0 ? 1 : 0;
96 }
97 return 0;
98 }
99
100 /*
101 * ima_measurements.c - calculate the SHA1 aggregate-pcr value based
102 * on the IMA runtime binary measurements.
103 *
104 * format: ima_measurement [--validate] [--verify] [--verbose]
105 *
106 * --validate: forces validation of the aggregrate pcr value
107 * for an invalidated PCR. Replace all entries in the
108 * runtime binary measurement list with 0x00 hash values,
109 * which indicate the PCR was invalidated, either for
110 * "a time of measure, time of use"(ToMToU) error, or a
111 * file open for read was already open for write, with
112 * 0xFF's hash value, when calculating the aggregate
113 * pcr value.
114 *
115 * --verify: for all IMA template entries in the runtime binary
116 * measurement list, calculate the template hash value
117 * and compare it with the actual template hash value.
118 * Return the number of incorrect hash measurements.
119 *
120 * --verbose: For all entries in the runtime binary measurement
121 * list, display the template information.
122 *
123 * template info: list #, PCR-register #, template hash, template name
124 * IMA info: IMA hash, filename hint
125 *
126 * Ouput: displays the aggregate-pcr value
127 * Return code: if verification enabled, returns number of verification
128 * errors.
129 */
main(int argc,char * argv[])130 int main(int argc, char *argv[])
131 {
132 FILE *fp;
133 struct event template;
134 u_int8_t pcr[SHA_DIGEST_LENGTH];
135 int i, count = 0;
136
137 int validate = 0;
138 int verify = 0;
139
140 if (argc < 2) {
141 printf("format: %s binary_runtime_measurements"
142 " [--validate] [--verbose] [--verify]\n", argv[0]);
143 return 1;
144 }
145
146 for (i = 2; i < argc; i++) {
147 if (strncmp(argv[i], "--validate", 8) == 0)
148 validate = 1;
149 if (strncmp(argv[i], "--verbose", 7) == 0)
150 verbose = 1;
151 if (strncmp(argv[i], "--verify", 6) == 0)
152 verify = 1;
153 }
154
155 fp = fopen(argv[1], "r");
156 if (!fp) {
157 printf("fn: %s\n", argv[1]);
158 perror("Unable to open file\n");
159 return 1;
160 }
161 memset(pcr, 0, SHA_DIGEST_LENGTH); /* initial PCR content 0..0 */
162 memset(zero, 0, SHA_DIGEST_LENGTH);
163 memset(fox, 0xff, SHA_DIGEST_LENGTH);
164
165 print_info("### PCR HASH "
166 "TEMPLATE-NAME\n");
167 while (fread(&template.header, sizeof template.header, 1, fp)) {
168 SHA_CTX c;
169
170 /* Extend simulated PCR with new template digest */
171 SHA1_Init(&c);
172 SHA1_Update(&c, pcr, SHA_DIGEST_LENGTH);
173 if (validate) {
174 if (memcmp(template.header.digest, zero, 20) == 0)
175 memset(template.header.digest, 0xFF, 20);
176 }
177 SHA1_Update(&c, template.header.digest, 20);
178 SHA1_Final(pcr, &c);
179
180 print_info("%3d %03u ", count++, template.header.pcr);
181 display_sha1_digest(template.header.digest);
182 if (template.header.name_len > TCG_EVENT_NAME_LEN_MAX) {
183 printf("%d ERROR: event name too long!\n",
184 template.header.name_len);
185 exit(1);
186 }
187 memset(template.name, 0, sizeof template.name);
188 fread(template.name, template.header.name_len, 1, fp);
189 print_info(" %s ", template.name);
190
191 memset(&template.ima_data, 0, sizeof template.ima_data);
192 fread(&template.ima_data.digest,
193 sizeof template.ima_data.digest, 1, fp);
194 display_sha1_digest(template.ima_data.digest);
195
196 fread(&template.filename_len,
197 sizeof template.filename_len, 1, fp);
198 fread(template.ima_data.filename, template.filename_len, 1, fp);
199 print_info(" %s\n", template.ima_data.filename);
200
201 if (verify)
202 if (verify_template_hash(&template) != 0) {
203 tst_resm(TFAIL, "Hash failed");
204 }
205 }
206 fclose(fp);
207
208 verbose = 1;
209 print_info("PCRAggr (re-calculated):");
210 display_sha1_digest(pcr);
211 tst_exit();
212 }
213
214 #else
main(void)215 int main(void)
216 {
217 tst_brkm(TCONF, NULL, "test requires libcrypto and openssl development packages");
218 }
219 #endif
220