1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Copyright (c) International Business Machines Corp., 2009
4 * Copyright (c) 2016-2019 Petr Vorel <pvorel@suse.cz>
5 *
6 * Authors: Mimi Zohar <zohar@us.ibm.com>
7 *
8 * Calculate a SHA1 boot aggregate value based on the TPM 1.2
9 * binary_bios_measurements.
10 */
11
12 #include "config.h"
13 #include <stdio.h>
14 #include <stdlib.h>
15 #include <sys/types.h>
16 #include <sys/stat.h>
17 #include <fcntl.h>
18 #include <string.h>
19 #include <unistd.h>
20 #include <limits.h>
21
22 #include "tst_test.h"
23 #include "tst_safe_stdio.h"
24
25 #if HAVE_LIBCRYPTO
26 #include <openssl/sha.h>
27 #include <openssl/evp.h>
28
29 #define MAX_EVENT_SIZE (1024*1024)
30 #define EVENT_HEADER_SIZE 32
31 #define MAX_EVENT_DATA_SIZE (MAX_EVENT_SIZE - EVENT_HEADER_SIZE)
32 #define NUM_PCRS 8 /* PCR registers 0-7 in boot aggregate */
33
34 static char *debug;
35 static char *file;
36
37 static unsigned char boot_aggregate[SHA_DIGEST_LENGTH];
38
39 static struct {
40 struct {
41 u_int32_t pcr;
42 u_int32_t type;
43 u_int8_t digest[SHA_DIGEST_LENGTH];
44 u_int32_t len;
45 } header __attribute__ ((packed));
46 char *data;
47 } event;
48
49 static struct {
50 unsigned char digest[SHA_DIGEST_LENGTH];
51 } pcr[NUM_PCRS];
52
display_sha1_digest(unsigned char * pcr)53 static void display_sha1_digest(unsigned char *pcr)
54 {
55 int i;
56
57 for (i = 0; i < SHA_DIGEST_LENGTH; i++)
58 printf("%02x", *(pcr + i) & 0xff);
59 printf("\n");
60 }
61
do_test(void)62 static void do_test(void)
63 {
64 FILE *fp;
65 #if OPENSSL_VERSION_NUMBER > 0x030000000L
66 EVP_MD_CTX *c = NULL;
67 #else
68 SHA_CTX c;
69 #endif
70 int i;
71
72 if (!file)
73 tst_brk(TBROK, "missing binary_bios_measurement file, specify with -f");
74
75 fp = SAFE_FOPEN(file, "r");
76
77 /* Initialize psuedo PCR registers 0 - 7 */
78 for (i = 0; i < NUM_PCRS; i++)
79 memset(&pcr[i].digest, 0, SHA_DIGEST_LENGTH);
80
81 event.data = malloc(MAX_EVENT_DATA_SIZE);
82 if (!event.data)
83 tst_brk(TBROK, "cannot allocate memory");
84
85 /* Extend the pseudo PCRs with the event digest */
86 while (fread(&event, sizeof(event.header), 1, fp)) {
87 if (debug) {
88 printf("%03u ", event.header.pcr);
89 display_sha1_digest(event.header.digest);
90 }
91
92 if (event.header.pcr < NUM_PCRS) {
93 #if OPENSSL_VERSION_NUMBER > 0x030000000L
94 if ((c = EVP_MD_CTX_new()) == NULL)
95 tst_brk(TBROK, "can't get new context");
96
97 EVP_DigestInit_ex(c, EVP_sha1(), NULL);
98 EVP_DigestUpdate(c, pcr[event.header.pcr].digest,
99 SHA_DIGEST_LENGTH);
100 EVP_DigestUpdate(c, event.header.digest, SHA_DIGEST_LENGTH);
101 EVP_DigestFinal_ex(c, pcr[event.header.pcr].digest, NULL);
102 EVP_MD_CTX_free(c);
103 #else
104 SHA1_Init(&c);
105 SHA1_Update(&c, pcr[event.header.pcr].digest,
106 SHA_DIGEST_LENGTH);
107 SHA1_Update(&c, event.header.digest,
108 SHA_DIGEST_LENGTH);
109 SHA1_Final(pcr[event.header.pcr].digest, &c);
110 #endif
111 }
112
113 #if MAX_EVENT_DATA_SIZE < USHRT_MAX
114 if (event.header.len > MAX_EVENT_DATA_SIZE) {
115 tst_res(TWARN, "error event too long");
116 break;
117 }
118 #endif
119 if (fread(event.data, event.header.len, 1, fp) != 1)
120 tst_brk(TBROK, "failed to read 1 byte");
121 }
122
123 SAFE_FCLOSE(fp);
124 free(event.data);
125
126 /* Extend the boot aggregate with the pseudo PCR digest values */
127 memset(&boot_aggregate, 0, SHA_DIGEST_LENGTH);
128
129 #if OPENSSL_VERSION_NUMBER > 0x030000000L
130 EVP_DigestInit_ex(c, EVP_sha1(), NULL);
131 #else
132 SHA1_Init(&c);
133 #endif
134
135 for (i = 0; i < NUM_PCRS; i++) {
136 if (debug) {
137 printf("PCR-%2.2x: ", i);
138 display_sha1_digest(pcr[i].digest);
139 }
140 #if OPENSSL_VERSION_NUMBER > 0x030000000L
141 EVP_DigestUpdate(c, pcr[i].digest, SHA_DIGEST_LENGTH);
142 #else
143 SHA1_Update(&c, pcr[i].digest, SHA_DIGEST_LENGTH);
144 #endif
145 }
146
147 #if OPENSSL_VERSION_NUMBER > 0x030000000L
148 EVP_MD_CTX_free(c);
149 #else
150 SHA1_Final(boot_aggregate, &c);
151 #endif
152
153 printf("sha1:");
154 display_sha1_digest(boot_aggregate);
155 tst_res(TPASS, "found sha1 hash");
156 }
157
158 static struct tst_option options[] = {
159 {"d", &debug, "Enable debug"},
160 {"f:", &file, "binary_bios_measurement file (required)\n"},
161 {}
162 };
163
164 static struct tst_test test = {
165 .needs_root = 1,
166 .test_all = do_test,
167 .options = options,
168 };
169
170 #else
171 TST_TEST_TCONF("libcrypto and openssl development packages required");
172 #endif
173