Home | History | Annotate | Download | only in src
      1 /*
      2  * Copyright (c) International Business Machines  Corp., 2008
      3  *
      4  * Authors:
      5  * Reiner Sailer <sailer (at) watson.ibm.com>
      6  * Mimi Zohar <zohar (at) 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 
     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  */
     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 
     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  */
    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
    215 int main(void)
    216 {
    217 	tst_brkm(TCONF, NULL, "test requires libcrypto and openssl development packages");
    218 }
    219 #endif
    220