| /* |
| * Copyright (c) International Business Machines Corp., 2008 |
| * |
| * Authors: |
| * Reiner Sailer <sailer@watson.ibm.com> |
| * Mimi Zohar <zohar@us.ibm.com> |
| * |
| * This program is free software; you can redistribute it and/or |
| * modify it under the terms of the GNU General Public License as |
| * published by the Free Software Foundation, version 2 of the |
| * License. |
| * |
| * File: ima_measure.c |
| * |
| * Calculate the SHA1 aggregate-pcr value based on the IMA runtime |
| * binary measurements. |
| */ |
| #include <stdio.h> |
| #include <stdlib.h> |
| #include <sys/types.h> |
| #include <sys/stat.h> |
| #include <fcntl.h> |
| #include <string.h> |
| #include <unistd.h> |
| |
| #include "config.h" |
| #include "test.h" |
| |
| char *TCID = "ima_measure"; |
| |
| #if HAVE_LIBCRYPTO |
| #include <openssl/sha.h> |
| |
| #define TCG_EVENT_NAME_LEN_MAX 255 |
| |
| int TST_TOTAL = 1; |
| |
| static int verbose; |
| |
| #define print_info(format, arg...) \ |
| if (verbose) \ |
| printf(format, ##arg) |
| |
| static u_int8_t zero[SHA_DIGEST_LENGTH]; |
| static u_int8_t fox[SHA_DIGEST_LENGTH]; |
| |
| struct event { |
| struct { |
| u_int32_t pcr; |
| u_int8_t digest[SHA_DIGEST_LENGTH]; |
| u_int32_t name_len; |
| } header; |
| char name[TCG_EVENT_NAME_LEN_MAX + 1]; |
| struct { |
| u_int8_t digest[SHA_DIGEST_LENGTH]; |
| char filename[TCG_EVENT_NAME_LEN_MAX + 1]; |
| } ima_data; |
| int filename_len; |
| }; |
| |
| static void display_sha1_digest(u_int8_t * digest) |
| { |
| int i; |
| |
| for (i = 0; i < 20; i++) |
| print_info(" %02X", (*(digest + i) & 0xff)); |
| } |
| |
| /* |
| * Calculate the sha1 hash of data |
| */ |
| static void calc_digest(u_int8_t * digest, int len, void *data) |
| { |
| SHA_CTX c; |
| |
| /* Calc template hash for an ima entry */ |
| memset(digest, 0, sizeof *digest); |
| SHA1_Init(&c); |
| SHA1_Update(&c, data, len); |
| SHA1_Final(digest, &c); |
| } |
| |
| static int verify_template_hash(struct event *template) |
| { |
| int rc; |
| |
| rc = memcmp(fox, template->header.digest, sizeof fox); |
| if (rc != 0) { |
| u_int8_t digest[SHA_DIGEST_LENGTH]; |
| |
| memset(digest, 0, sizeof digest); |
| calc_digest(digest, sizeof template->ima_data, |
| &template->ima_data); |
| rc = memcmp(digest, template->header.digest, sizeof digest); |
| return rc != 0 ? 1 : 0; |
| } |
| return 0; |
| } |
| |
| /* |
| * ima_measurements.c - calculate the SHA1 aggregate-pcr value based |
| * on the IMA runtime binary measurements. |
| * |
| * format: ima_measurement [--validate] [--verify] [--verbose] |
| * |
| * --validate: forces validation of the aggregrate pcr value |
| * for an invalidated PCR. Replace all entries in the |
| * runtime binary measurement list with 0x00 hash values, |
| * which indicate the PCR was invalidated, either for |
| * "a time of measure, time of use"(ToMToU) error, or a |
| * file open for read was already open for write, with |
| * 0xFF's hash value, when calculating the aggregate |
| * pcr value. |
| * |
| * --verify: for all IMA template entries in the runtime binary |
| * measurement list, calculate the template hash value |
| * and compare it with the actual template hash value. |
| * Return the number of incorrect hash measurements. |
| * |
| * --verbose: For all entries in the runtime binary measurement |
| * list, display the template information. |
| * |
| * template info: list #, PCR-register #, template hash, template name |
| * IMA info: IMA hash, filename hint |
| * |
| * Ouput: displays the aggregate-pcr value |
| * Return code: if verification enabled, returns number of verification |
| * errors. |
| */ |
| int main(int argc, char *argv[]) |
| { |
| FILE *fp; |
| struct event template; |
| u_int8_t pcr[SHA_DIGEST_LENGTH]; |
| int i, count = 0; |
| |
| int validate = 0; |
| int verify = 0; |
| |
| if (argc < 2) { |
| printf("format: %s binary_runtime_measurements" |
| " [--validate] [--verbose] [--verify]\n", argv[0]); |
| return 1; |
| } |
| |
| for (i = 2; i < argc; i++) { |
| if (strncmp(argv[i], "--validate", 8) == 0) |
| validate = 1; |
| if (strncmp(argv[i], "--verbose", 7) == 0) |
| verbose = 1; |
| if (strncmp(argv[i], "--verify", 6) == 0) |
| verify = 1; |
| } |
| |
| fp = fopen(argv[1], "r"); |
| if (!fp) { |
| printf("fn: %s\n", argv[1]); |
| perror("Unable to open file\n"); |
| return 1; |
| } |
| memset(pcr, 0, SHA_DIGEST_LENGTH); /* initial PCR content 0..0 */ |
| memset(zero, 0, SHA_DIGEST_LENGTH); |
| memset(fox, 0xff, SHA_DIGEST_LENGTH); |
| |
| print_info("### PCR HASH " |
| "TEMPLATE-NAME\n"); |
| while (fread(&template.header, sizeof template.header, 1, fp)) { |
| SHA_CTX c; |
| |
| /* Extend simulated PCR with new template digest */ |
| SHA1_Init(&c); |
| SHA1_Update(&c, pcr, SHA_DIGEST_LENGTH); |
| if (validate) { |
| if (memcmp(template.header.digest, zero, 20) == 0) |
| memset(template.header.digest, 0xFF, 20); |
| } |
| SHA1_Update(&c, template.header.digest, 20); |
| SHA1_Final(pcr, &c); |
| |
| print_info("%3d %03u ", count++, template.header.pcr); |
| display_sha1_digest(template.header.digest); |
| if (template.header.name_len > TCG_EVENT_NAME_LEN_MAX) { |
| printf("%d ERROR: event name too long!\n", |
| template.header.name_len); |
| exit(1); |
| } |
| memset(template.name, 0, sizeof template.name); |
| fread(template.name, template.header.name_len, 1, fp); |
| print_info(" %s ", template.name); |
| |
| memset(&template.ima_data, 0, sizeof template.ima_data); |
| fread(&template.ima_data.digest, |
| sizeof template.ima_data.digest, 1, fp); |
| display_sha1_digest(template.ima_data.digest); |
| |
| fread(&template.filename_len, |
| sizeof template.filename_len, 1, fp); |
| fread(template.ima_data.filename, template.filename_len, 1, fp); |
| print_info(" %s\n", template.ima_data.filename); |
| |
| if (verify) |
| if (verify_template_hash(&template) != 0) { |
| tst_resm(TFAIL, "Hash failed"); |
| } |
| } |
| fclose(fp); |
| |
| verbose = 1; |
| print_info("PCRAggr (re-calculated):"); |
| display_sha1_digest(pcr); |
| tst_exit(); |
| } |
| |
| #else |
| int main(void) |
| { |
| tst_brkm(TCONF, NULL, "test requires libcrypto and openssl development packages"); |
| } |
| #endif |