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