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