1 /*
2 * Copyright (c) 2010-2012 United States Government, as represented by
3 * the Secretary of Defense. All rights reserved.
4 *
5 * THIS SOFTWARE AND ITS DOCUMENTATION ARE PROVIDED AS IS AND WITHOUT
6 * ANY EXPRESS OR IMPLIED WARRANTIES WHATSOEVER. ALL WARRANTIES
7 * INCLUDING, BUT NOT LIMITED TO, PERFORMANCE, MERCHANTABILITY, FITNESS
8 * FOR A PARTICULAR PURPOSE, AND NONINFRINGEMENT ARE HEREBY
9 * DISCLAIMED. USERS ASSUME THE ENTIRE RISK AND LIABILITY OF USING THE
10 * SOFTWARE.
11 */
12
13 #include <mini-os/byteorder.h>
14 #include "vtpmblk.h"
15 #include "tpm/tpm_marshalling.h"
16 #include "vtpm_cmd.h"
17 #include "polarssl/aes.h"
18 #include "polarssl/sha1.h"
19 #include <blkfront.h>
20 #include <unistd.h>
21 #include <errno.h>
22 #include <fcntl.h>
23
24 /*Encryption key and block sizes */
25 #define BLKSZ 16
26
27 static struct blkfront_dev* blkdev = NULL;
28 static int blkfront_fd = -1;
29 static uint64_t slot_size = 0;
30
init_vtpmblk(struct tpmfront_dev * tpmfront_dev)31 int init_vtpmblk(struct tpmfront_dev* tpmfront_dev)
32 {
33 struct blkfront_info blkinfo;
34 info("Initializing persistent NVM storage\n");
35
36 if((blkdev = init_blkfront(NULL, &blkinfo)) == NULL) {
37 error("BLKIO: ERROR Unable to initialize blkfront");
38 return -1;
39 }
40 if (blkinfo.info & VDISK_READONLY || blkinfo.mode != O_RDWR) {
41 error("BLKIO: ERROR block device is read only!");
42 goto error;
43 }
44 if((blkfront_fd = blkfront_open(blkdev)) == -1) {
45 error("Unable to open blkfront file descriptor!");
46 goto error;
47 }
48
49 slot_size = blkinfo.sectors * blkinfo.sector_size / 2;
50
51 return 0;
52 error:
53 shutdown_blkfront(blkdev);
54 blkdev = NULL;
55 return -1;
56 }
57
shutdown_vtpmblk(void)58 void shutdown_vtpmblk(void)
59 {
60 close(blkfront_fd);
61 blkfront_fd = -1;
62 blkdev = NULL;
63 }
64
write_vtpmblk_raw(uint8_t * data,size_t data_length,int slot)65 static int write_vtpmblk_raw(uint8_t *data, size_t data_length, int slot)
66 {
67 int rc;
68 uint32_t lenbuf;
69 debug("Begin Write data=%p len=%u slot=%u ssize=%u", data, data_length, slot, slot_size);
70
71 if (data_length > slot_size - 4) {
72 error("vtpm data cannot fit in data slot (%d/%d).", data_length, slot_size - 4);
73 return -1;
74 }
75
76 lenbuf = cpu_to_be32((uint32_t)data_length);
77
78 lseek(blkfront_fd, slot * slot_size, SEEK_SET);
79 if((rc = write(blkfront_fd, (uint8_t*)&lenbuf, 4)) != 4) {
80 error("write(length) failed! error was %s", strerror(errno));
81 return -1;
82 }
83 if((rc = write(blkfront_fd, data, data_length)) != data_length) {
84 error("write(data) failed! error was %s", strerror(errno));
85 return -1;
86 }
87
88 info("Wrote %u bytes to NVM persistent storage", data_length);
89
90 return 0;
91 }
92
read_vtpmblk_raw(uint8_t ** data,size_t * data_length,int slot)93 static int read_vtpmblk_raw(uint8_t **data, size_t *data_length, int slot)
94 {
95 int rc;
96 uint32_t lenbuf;
97
98 lseek(blkfront_fd, slot * slot_size, SEEK_SET);
99 if(( rc = read(blkfront_fd, (uint8_t*)&lenbuf, 4)) != 4) {
100 error("read(length) failed! error was %s", strerror(errno));
101 return -1;
102 }
103 *data_length = (size_t) cpu_to_be32(lenbuf);
104 if(*data_length == 0) {
105 error("read 0 data_length for NVM");
106 return -1;
107 }
108 if(*data_length > slot_size - 4) {
109 error("read invalid data_length for NVM");
110 return -1;
111 }
112
113 *data = tpm_malloc(*data_length);
114 if((rc = read(blkfront_fd, *data, *data_length)) != *data_length) {
115 error("read(data) failed! error was %s", strerror(errno));
116 return -1;
117 }
118
119 info("Read %u bytes from NVM persistent storage (slot %d)", *data_length, slot);
120 return 0;
121 }
122
encrypt_vtpmblk(uint8_t * clear,size_t clear_len,uint8_t ** cipher,size_t * cipher_len,uint8_t * symkey)123 int encrypt_vtpmblk(uint8_t* clear, size_t clear_len, uint8_t** cipher, size_t* cipher_len, uint8_t* symkey)
124 {
125 int rc = 0;
126 uint8_t iv[BLKSZ];
127 aes_context aes_ctx;
128 UINT32 temp;
129 int mod;
130
131 uint8_t* clbuf = NULL;
132
133 uint8_t* ivptr;
134 int ivlen;
135
136 uint8_t* cptr; //Cipher block pointer
137 int clen; //Cipher block length
138
139 /*Create a new 256 bit encryption key */
140 if(symkey == NULL) {
141 rc = -1;
142 goto abort_egress;
143 }
144 tpm_get_extern_random_bytes(symkey, NVMKEYSZ);
145
146 /*Setup initialization vector - random bits and then 4 bytes clear text size at the end*/
147 temp = sizeof(UINT32);
148 ivlen = BLKSZ - temp;
149 tpm_get_extern_random_bytes(iv, ivlen);
150 ivptr = iv + ivlen;
151 tpm_marshal_UINT32(&ivptr, &temp, (UINT32) clear_len);
152
153 /*The clear text needs to be padded out to a multiple of BLKSZ */
154 mod = clear_len % BLKSZ;
155 clen = mod ? clear_len + BLKSZ - mod : clear_len;
156 clbuf = malloc(clen);
157 if (clbuf == NULL) {
158 rc = -1;
159 goto abort_egress;
160 }
161 memcpy(clbuf, clear, clear_len);
162 /* zero out the padding bits - FIXME: better / more secure way to handle these? */
163 if(clen - clear_len) {
164 memset(clbuf + clear_len, 0, clen - clear_len);
165 }
166
167 /* Setup the ciphertext buffer */
168 *cipher_len = BLKSZ + clen; /*iv + ciphertext */
169 cptr = *cipher = malloc(*cipher_len);
170 if (*cipher == NULL) {
171 rc = -1;
172 goto abort_egress;
173 }
174
175 /* Copy the IV to cipher text blob*/
176 memcpy(cptr, iv, BLKSZ);
177 cptr += BLKSZ;
178
179 /* Setup encryption */
180 aes_setkey_enc(&aes_ctx, symkey, 256);
181
182 /* Do encryption now */
183 aes_crypt_cbc(&aes_ctx, AES_ENCRYPT, clen, iv, clbuf, cptr);
184
185 goto egress;
186 abort_egress:
187 egress:
188 free(clbuf);
189 return rc;
190 }
decrypt_vtpmblk(uint8_t * cipher,size_t cipher_len,uint8_t ** clear,size_t * clear_len,uint8_t * symkey)191 int decrypt_vtpmblk(uint8_t* cipher, size_t cipher_len, uint8_t** clear, size_t* clear_len, uint8_t* symkey)
192 {
193 int rc = 0;
194 uint8_t iv[BLKSZ];
195 uint8_t* ivptr;
196 UINT32 u32, temp;
197 aes_context aes_ctx;
198
199 uint8_t* cptr = cipher; //cipher block pointer
200 int clen = cipher_len; //cipher block length
201
202 /* Pull out the initialization vector */
203 memcpy(iv, cipher, BLKSZ);
204 cptr += BLKSZ;
205 clen -= BLKSZ;
206
207 /* Setup the clear text buffer */
208 if((*clear = malloc(clen)) == NULL) {
209 rc = -1;
210 goto abort_egress;
211 }
212
213 /* Get the length of clear text from last 4 bytes of iv */
214 temp = sizeof(UINT32);
215 ivptr = iv + BLKSZ - temp;
216 tpm_unmarshal_UINT32(&ivptr, &temp, &u32);
217 *clear_len = u32;
218
219 /* Setup decryption */
220 aes_setkey_dec(&aes_ctx, symkey, 256);
221
222 /* Do decryption now */
223 if ((clen % BLKSZ) != 0) {
224 error("Decryption Error: Cipher block size was not a multiple of %u", BLKSZ);
225 rc = -1;
226 goto abort_egress;
227 }
228 aes_crypt_cbc(&aes_ctx, AES_DECRYPT, clen, iv, cptr, *clear);
229
230 goto egress;
231 abort_egress:
232 egress:
233 return rc;
234 }
235
236 /* Current active state slot, or -1 if no valid saved state exists */
237 static int active_slot = -1;
238
write_vtpmblk(struct tpmfront_dev * tpmfront_dev,uint8_t * data,size_t data_length)239 int write_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t* data, size_t data_length) {
240 int rc;
241 uint8_t* cipher = NULL;
242 size_t cipher_len = 0;
243 uint8_t hashkey[HASHKEYSZ];
244 uint8_t* symkey = hashkey + HASHSZ;
245
246 /* Switch to the other slot. Note that in a new vTPM, the read will not
247 * succeed, so active_slot will be -1 and we will write to slot 0.
248 */
249 active_slot = !active_slot;
250
251 /* Encrypt the data */
252 if((rc = encrypt_vtpmblk(data, data_length, &cipher, &cipher_len, symkey))) {
253 goto abort_egress;
254 }
255 /* Write to disk */
256 if((rc = write_vtpmblk_raw(cipher, cipher_len, active_slot))) {
257 goto abort_egress;
258 }
259 /* Get sha1 hash of data */
260 sha1(cipher, cipher_len, hashkey);
261
262 /* Send hash and key to manager */
263 if((rc = VTPM_SaveHashKey(tpmfront_dev, hashkey, HASHKEYSZ)) != TPM_SUCCESS) {
264 goto abort_egress;
265 }
266 goto egress;
267 abort_egress:
268 egress:
269 free(cipher);
270 return rc;
271 }
272
read_vtpmblk(struct tpmfront_dev * tpmfront_dev,uint8_t ** data,size_t * data_length)273 int read_vtpmblk(struct tpmfront_dev* tpmfront_dev, uint8_t** data, size_t *data_length) {
274 int rc;
275 uint8_t* cipher = NULL;
276 size_t cipher_len = 0;
277 size_t keysize;
278 uint8_t* hashkey = NULL;
279 uint8_t hash0[HASHSZ];
280 uint8_t hash1[HASHSZ];
281 uint8_t* symkey;
282
283 /* Retreive the hash and the key from the manager */
284 if((rc = VTPM_LoadHashKey(tpmfront_dev, &hashkey, &keysize)) != TPM_SUCCESS) {
285 goto abort_egress;
286 }
287 if(keysize != HASHKEYSZ) {
288 error("Manager returned a hashkey of invalid size! expected %d, actual %d", NVMKEYSZ, keysize);
289 rc = -1;
290 goto abort_egress;
291 }
292 symkey = hashkey + HASHSZ;
293
294 active_slot = 0;
295 debug("Reading slot 0 from disk\n");
296 if((rc = read_vtpmblk_raw(&cipher, &cipher_len, 0))) {
297 goto abort_egress;
298 }
299
300 /* Compute the hash of the cipher text and compare */
301 sha1(cipher, cipher_len, hash0);
302 if(!memcmp(hash0, hashkey, HASHSZ))
303 goto valid;
304
305 free(cipher);
306 cipher = NULL;
307
308 active_slot = 1;
309 debug("Reading slot 1 from disk (offset=%u)\n", slot_size);
310 if((rc = read_vtpmblk_raw(&cipher, &cipher_len, 1))) {
311 goto abort_egress;
312 }
313
314 /* Compute the hash of the cipher text and compare */
315 sha1(cipher, cipher_len, hash1);
316 if(!memcmp(hash1, hashkey, HASHSZ))
317 goto valid;
318
319 {
320 int i;
321 error("NVM Storage Checksum failed!");
322 printf("Expected: ");
323 for(i = 0; i < HASHSZ; ++i) {
324 printf("%02hhX ", hashkey[i]);
325 }
326 printf("\n");
327 printf("Slot 0: ");
328 for(i = 0; i < HASHSZ; ++i) {
329 printf("%02hhX ", hash0[i]);
330 }
331 printf("\n");
332 printf("Slot 1: ");
333 for(i = 0; i < HASHSZ; ++i) {
334 printf("%02hhX ", hash1[i]);
335 }
336 printf("\n");
337 rc = -1;
338 goto abort_egress;
339 }
340 valid:
341
342 /* Decrypt the blob */
343 if((rc = decrypt_vtpmblk(cipher, cipher_len, data, data_length, symkey))) {
344 goto abort_egress;
345 }
346 goto egress;
347 abort_egress:
348 active_slot = -1;
349 egress:
350 free(cipher);
351 free(hashkey);
352 return rc;
353 }
354