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 <stdio.h>
14 #include <stdint.h>
15 #include <inttypes.h>
16 #include <stdlib.h>
17 #include <unistd.h>
18 #include <string.h>
19 #include <syslog.h>
20 #include <stdbool.h>
21 #include <errno.h>
22 #include <sys/time.h>
23 #include <xen/xen.h>
24 #include <tpmback.h>
25 #include <tpmfront.h>
26 
27 #include <polarssl/entropy.h>
28 #include <polarssl/ctr_drbg.h>
29 
30 #include "tpm/tpm_emulator_extern.h"
31 #include "tpm/tpm_marshalling.h"
32 #include "vtpm.h"
33 #include "vtpm_cmd.h"
34 #include "vtpm_pcrs.h"
35 #include "vtpmblk.h"
36 #include "vtpm_manager.h"
37 
38 #define TPM_LOG_INFO LOG_INFO
39 #define TPM_LOG_ERROR LOG_ERR
40 #define TPM_LOG_DEBUG LOG_DEBUG
41 
42 /* Global commandline options - default values */
43 struct Opt_args opt_args = {
44    .startup = ST_CLEAR,
45    .loglevel = TPM_LOG_INFO,
46    .hwinitpcrs = VTPM_PCRNONE,
47    .tpmconf = 0,
48    .enable_maint_cmds = false,
49 };
50 
51 static uint32_t badords[32];
52 static unsigned int n_badords = 0;
53 
54 entropy_context entropy;
55 ctr_drbg_context ctr_drbg;
56 
57 struct tpmfront_dev* tpmfront_dev;
58 
vtpm_get_extern_random_bytes(void * buf,size_t nbytes)59 void vtpm_get_extern_random_bytes(void *buf, size_t nbytes)
60 {
61    ctr_drbg_random(&ctr_drbg, buf, nbytes);
62 }
63 
vtpm_read_from_file(uint8_t ** data,size_t * data_length)64 int vtpm_read_from_file(uint8_t **data, size_t *data_length) {
65    return read_vtpmblk(tpmfront_dev, data, data_length);
66 }
67 
vtpm_write_to_file(uint8_t * data,size_t data_length)68 int vtpm_write_to_file(uint8_t *data, size_t data_length) {
69    return write_vtpmblk(tpmfront_dev, data, data_length);
70 }
71 
vtpm_extern_init_fake(void)72 int vtpm_extern_init_fake(void) {
73    return 0;
74 }
75 
vtpm_extern_release_fake(void)76 void vtpm_extern_release_fake(void) {
77 }
78 
79 
vtpm_log(int priority,const char * fmt,...)80 void vtpm_log(int priority, const char *fmt, ...)
81 {
82    if(opt_args.loglevel >= priority) {
83       va_list v;
84       va_start(v, fmt);
85       vprintf(fmt, v);
86       va_end(v);
87    }
88 }
89 
vtpm_get_ticks(void)90 static uint64_t vtpm_get_ticks(void)
91 {
92   static uint64_t old_t = 0;
93   uint64_t new_t, res_t;
94   struct timeval tv;
95   gettimeofday(&tv, NULL);
96   new_t = (uint64_t)tv.tv_sec * 1000000 + (uint64_t)tv.tv_usec;
97   res_t = (old_t > 0) ? new_t - old_t : 0;
98   old_t = new_t;
99   return res_t;
100 }
101 
102 
tpm_entropy_source(void * dummy,unsigned char * data,size_t len,size_t * olen)103 static int tpm_entropy_source(void* dummy, unsigned char* data, size_t len, size_t* olen) {
104    UINT32 sz = len;
105    TPM_RESULT rc = VTPM_GetRandom(tpmfront_dev, data, &sz);
106    *olen = sz;
107    return rc == TPM_SUCCESS ? 0 : POLARSSL_ERR_ENTROPY_SOURCE_FAILED;
108 }
109 
init_random(void)110 int init_random(void) {
111    /* Initialize the rng */
112    entropy_init(&entropy);
113    entropy_add_source(&entropy, tpm_entropy_source, NULL, 0);
114    entropy_gather(&entropy);
115    ctr_drbg_init(&ctr_drbg, entropy_func, &entropy, NULL, 0);
116    ctr_drbg_set_prediction_resistance( &ctr_drbg, CTR_DRBG_PR_OFF );
117 
118    return 0;
119 }
120 
check_passthru(tpmcmd_t * tpmcmd)121 int check_passthru(tpmcmd_t* tpmcmd) {
122    TPM_TAG tag;
123    UINT32 len = 10;
124    BYTE* ptr;
125    size_t size;
126 
127    if(tpmcmd->req_len < 10) {
128       return false;
129    }
130 
131    ptr = tpmcmd->req;
132    tpm_unmarshal_UINT16(&ptr, &len, &tag);
133 
134    if (tag == VTPM_TAG_REQ2) {
135       info("VTPM passthru: %d bytes", (int)tpmcmd->req_len);
136       tpmfront_cmd(tpmfront_dev, tpmcmd->req, tpmcmd->req_len, &tpmcmd->resp, &size);
137       tpmcmd->resp_len = size;
138       info("VTPM passthru return: %d bytes", (int)size);
139       return true;
140    }
141 
142    if (tag == VTPM_TAG_REQ) {
143       info("VTPM pTPM-cmd: %d bytes", (int)tpmcmd->req_len);
144       ptr = tpmcmd->req;
145       tpm_marshal_UINT16(&ptr, &len, TPM_TAG_RQU_COMMAND);
146       tpmfront_cmd(tpmfront_dev, tpmcmd->req, tpmcmd->req_len, &tpmcmd->resp, &size);
147       tpmcmd->resp_len = size;
148       info("VTPM pTPM-cmd return: %d bytes", (int)size);
149       return true;
150    }
151 
152    return false;
153 }
154 
check_ordinal(tpmcmd_t * tpmcmd)155 int check_ordinal(tpmcmd_t* tpmcmd) {
156    TPM_COMMAND_CODE ord;
157    UINT32 len = 4;
158    BYTE* ptr;
159    unsigned int i;
160 
161    if(tpmcmd->req_len < 10) {
162       return true;
163    }
164 
165    ptr = tpmcmd->req + 6;
166    tpm_unmarshal_UINT32(&ptr, &len, &ord);
167 
168    for(i = 0; i < n_badords; ++i) {
169       if(ord == badords[i]) {
170          error("Disabled command ordinal (%" PRIu32") requested!\n");
171          return false;
172       }
173    }
174    return true;
175 }
176 
177 struct locality_item {
178 	char* lbl;
179 	uint8_t mask[32];
180 };
181 #define MAX_CLIENT_LOCALITIES 16
182 static struct locality_item client_locality[MAX_CLIENT_LOCALITIES];
183 static int nr_client_localities = 0;
184 
generate_locality_mask(domid_t domid,unsigned int handle)185 static void *generate_locality_mask(domid_t domid, unsigned int handle)
186 {
187    char label[512];
188    int i;
189    if (tpmback_get_peercontext(domid, handle, label, sizeof(label)))
190       BUG();
191    for(i=0; i < nr_client_localities; i++) {
192       if (!strcmp(client_locality[i].lbl, label))
193          goto found;
194       if (client_locality[i].lbl[0] == '*') {
195 	 char * f = strstr(label, 1 + client_locality[i].lbl);
196 	 if (!strcmp(f, 1 + client_locality[i].lbl))
197 	    goto found;
198       }
199    }
200    return NULL;
201  found:
202    tpmback_set_opaque(domid, handle, client_locality[i].mask);
203    return client_locality[i].mask;
204 }
205 
main_loop(void)206 static void main_loop(void) {
207    tpmcmd_t* tpmcmd = NULL;
208    int res = -1;
209 
210    info("VTPM Initializing\n");
211 
212    /* Set required tpm config args */
213    opt_args.tpmconf |= TPM_CONF_STRONG_PERSISTENCE;
214    opt_args.tpmconf &= ~TPM_CONF_USE_INTERNAL_PRNG;
215    opt_args.tpmconf |= TPM_CONF_GENERATE_EK;
216    opt_args.tpmconf |= TPM_CONF_GENERATE_SEED_DAA;
217 
218    /* Initialize the emulator */
219    tpm_emulator_init(opt_args.startup, opt_args.tpmconf);
220 
221    /* Initialize any requested PCRs with hardware TPM values */
222    if(vtpm_initialize_hw_pcrs(tpmfront_dev, opt_args.hwinitpcrs) != TPM_SUCCESS) {
223       error("Failed to initialize PCRs with hardware TPM values");
224       goto abort_postpcrs;
225    }
226 
227    tpmcmd = tpmback_req_any();
228    while(tpmcmd) {
229       /* Handle the request */
230       if(tpmcmd->req_len) {
231 	 uint8_t* locality_mask = tpmcmd->opaque;
232 	 uint8_t locality_bit = (1 << (tpmcmd->locality & 7));
233 	 int locality_byte = tpmcmd->locality >> 3;
234 	 tpmcmd->resp = NULL;
235 	 tpmcmd->resp_len = 0;
236 
237 	 if (nr_client_localities && !locality_mask)
238 	    locality_mask = generate_locality_mask(tpmcmd->domid, tpmcmd->handle);
239 	 if (nr_client_localities && !locality_mask) {
240             error("Unknown client label in tpm_handle_command");
241             create_error_response(tpmcmd, TPM_FAIL);
242 	 }
243 	 else if (nr_client_localities && !(locality_mask[locality_byte] & locality_bit)) {
244             error("Invalid locality (%d) for client in tpm_handle_command", tpmcmd->locality);
245             create_error_response(tpmcmd, TPM_FAIL);
246 	 }
247          /* Check for TPM Manager passthrough command */
248          else if(check_passthru(tpmcmd)) {
249 	 }
250          /* Check for disabled ordinals */
251          else if(!check_ordinal(tpmcmd)) {
252             create_error_response(tpmcmd, TPM_BAD_ORDINAL);
253          }
254          /* If not disabled, do the command */
255          else {
256             if((res = tpm_handle_command(tpmcmd->req, tpmcmd->req_len, &tpmcmd->resp, &tpmcmd->resp_len, tpmcmd->locality)) != 0) {
257                error("tpm_handle_command() failed");
258                create_error_response(tpmcmd, TPM_FAIL);
259             }
260          }
261       }
262 
263       /* Send the response */
264       tpmback_resp(tpmcmd);
265 
266       /* Wait for the next request */
267       tpmcmd = tpmback_req_any();
268 
269    }
270 
271 abort_postpcrs:
272    info("VTPM Shutting down");
273 
274    tpm_emulator_shutdown();
275 }
276 
parse_cmd_line(int argc,char ** argv)277 int parse_cmd_line(int argc, char** argv)
278 {
279    char sval[25];
280    char* logstr = NULL;
281    /* Parse the command strings */
282    for(unsigned int i = 1; i < argc; ++i) {
283       if (sscanf(argv[i], "loglevel=%25s", sval) == 1){
284 	 if (!strcmp(sval, "debug")) {
285 	    opt_args.loglevel = TPM_LOG_DEBUG;
286 	    logstr = "debug";
287 	 }
288 	 else if (!strcmp(sval, "info")) {
289 	    logstr = "info";
290 	    opt_args.loglevel = TPM_LOG_INFO;
291 	 }
292 	 else if (!strcmp(sval, "error")) {
293 	    logstr = "error";
294 	    opt_args.loglevel = TPM_LOG_ERROR;
295 	 }
296       }
297       else if (!strcmp(argv[i], "clear")) {
298 	 opt_args.startup = ST_CLEAR;
299       }
300       else if (!strcmp(argv[i], "save")) {
301 	 opt_args.startup = ST_SAVE;
302       }
303       else if (!strcmp(argv[i], "deactivated")) {
304 	 opt_args.startup = ST_DEACTIVATED;
305       }
306       else if (!strncmp(argv[i], "maintcmds=", 10)) {
307          if(!strcmp(argv[i] + 10, "1")) {
308             opt_args.enable_maint_cmds = true;
309          } else if(!strcmp(argv[i] + 10, "0")) {
310             opt_args.enable_maint_cmds = false;
311          }
312       }
313       else if(!strncmp(argv[i], "hwinitpcr=", 10)) {
314          char *pch = argv[i] + 10;
315          unsigned int v1, v2;
316          pch = strtok(pch, ",");
317          while(pch != NULL) {
318             if(!strcmp(pch, "all")) {
319                //Set all
320                opt_args.hwinitpcrs = VTPM_PCRALL;
321             } else if(!strcmp(pch, "none")) {
322                //Set none
323                opt_args.hwinitpcrs = VTPM_PCRNONE;
324             } else if(sscanf(pch, "%u", &v1) == 1) {
325                //Set one
326                if(v1 >= TPM_NUM_PCR) {
327                   error("hwinitpcr error: Invalid PCR index %u", v1);
328                   return -1;
329                }
330                opt_args.hwinitpcrs |= (1 << v1);
331             } else if(sscanf(pch, "%u-%u", &v1, &v2) == 2) {
332                //Set range
333                if(v1 >= TPM_NUM_PCR) {
334                   error("hwinitpcr error: Invalid PCR index %u", v1);
335                   return -1;
336                }
337                if(v2 >= TPM_NUM_PCR) {
338                   error("hwinitpcr error: Invalid PCR index %u", v1);
339                   return -1;
340                }
341                if(v2 < v1) {
342                   unsigned tp = v1;
343                   v1 = v2;
344                   v2 = tp;
345                }
346                for(unsigned int i = v1; i <= v2; ++i) {
347                   opt_args.hwinitpcrs |= (1 << i);
348                }
349             } else {
350                error("hwintipcr error: Invalid PCR specification : %s", pch);
351                return -1;
352             }
353             pch = strtok(NULL, ",");
354          }
355       }
356       else if(!strncmp(argv[i], "locality=", 9)) {
357         char *lbl = argv[i] + 9;
358 	char *pch = strchr(lbl, '=');
359 	uint8_t* locality_mask = client_locality[nr_client_localities].mask;
360 	if (pch == NULL) {
361 		 error("Invalid locality specification: %s", lbl);
362 		 return -1;
363 	}
364 	if (nr_client_localities == MAX_CLIENT_LOCALITIES) {
365 		error("Too many locality specifications");
366 		return -1;
367 	}
368 	client_locality[nr_client_localities].lbl = lbl;
369 	memset(locality_mask, 0, 32);
370 	nr_client_localities++;
371 	*pch = 0;
372 	pch = strtok(pch + 1, ",");
373 	while (pch != NULL) {
374 		unsigned int loc;
375 		if (sscanf(pch, "%u", &loc) == 1 && loc < 256) {
376 			uint8_t locality_bit = (1 << (loc & 7));
377 			int locality_byte = loc >> 3;
378 			locality_mask[locality_byte] |= locality_bit;
379 		} else {
380 			error("Invalid locality item: %s", pch);
381 			return -1;
382 		}
383 		pch = strtok(NULL, ",");
384 	}
385       }
386       else {
387 	 error("Invalid command line option `%s'", argv[i]);
388       }
389 
390    }
391 
392    /* Check Errors and print results */
393    switch(opt_args.startup) {
394       case ST_CLEAR:
395 	 info("Startup mode is `clear'");
396 	 break;
397       case ST_SAVE:
398 	 info("Startup mode is `save'");
399 	 break;
400       case ST_DEACTIVATED:
401 	 info("Startup mode is `deactivated'");
402 	 break;
403       default:
404 	 error("Invalid startup mode %d", opt_args.startup);
405 	 return -1;
406    }
407 
408    if(opt_args.hwinitpcrs & (VTPM_PCRALL))
409    {
410       char pcrstr[1024];
411       char* ptr = pcrstr;
412 
413       pcrstr[0] = '\0';
414       info("The following PCRs will be initialized with values from the hardware TPM:");
415       for(unsigned int i = 0; i < TPM_NUM_PCR; ++i) {
416          if(opt_args.hwinitpcrs & (1 << i)) {
417             ptr += sprintf(ptr, "%u, ", i);
418          }
419       }
420       /* get rid of the last comma if any numbers were printed */
421       *(ptr -2) = '\0';
422 
423       info("\t%s", pcrstr);
424    } else {
425       info("All PCRs initialized to default values");
426    }
427 
428    if(!opt_args.enable_maint_cmds) {
429       info("TPM Maintenance Commands disabled");
430       badords[n_badords++] = TPM_ORD_CreateMaintenanceArchive;
431       badords[n_badords++] = TPM_ORD_LoadMaintenanceArchive;
432       badords[n_badords++] = TPM_ORD_KillMaintenanceFeature;
433       badords[n_badords++] = TPM_ORD_LoadManuMaintPub;
434       badords[n_badords++] = TPM_ORD_ReadManuMaintPub;
435    } else {
436       info("TPM Maintenance Commands enabled");
437    }
438 
439    info("Log level set to %s", logstr);
440 
441    return 0;
442 }
443 
cleanup_opt_args(void)444 void cleanup_opt_args(void) {
445 }
446 
main(int argc,char ** argv)447 int main(int argc, char **argv)
448 {
449    //FIXME: initializing blkfront without this sleep causes the domain to crash on boot
450    sleep(2);
451 
452    /* Setup extern function pointers */
453    tpm_extern_init = vtpm_extern_init_fake;
454    tpm_extern_release = vtpm_extern_release_fake;
455    tpm_malloc = malloc;
456    tpm_free = free;
457    tpm_log = vtpm_log;
458    tpm_get_ticks = vtpm_get_ticks;
459    tpm_get_extern_random_bytes = vtpm_get_extern_random_bytes;
460    tpm_write_to_storage = vtpm_write_to_file;
461    tpm_read_from_storage = vtpm_read_from_file;
462 
463    info("starting TPM Emulator (1.2.%d.%d-%d)", VERSION_MAJOR, VERSION_MINOR, VERSION_BUILD);
464    if(parse_cmd_line(argc, argv)) {
465       error("Error parsing commandline\n");
466       return -1;
467    }
468 
469    /* Initialize devices */
470    init_tpmback(NULL, NULL);
471    if((tpmfront_dev = init_tpmfront(NULL)) == NULL) {
472       error("Unable to initialize tpmfront device");
473       goto abort_posttpmfront;
474    }
475 
476    /* Seed the RNG with entropy from hardware TPM */
477    if(init_random()) {
478       error("Unable to initialize RNG");
479       goto abort_postrng;
480    }
481 
482    /* Initialize blkfront device */
483    if(init_vtpmblk(tpmfront_dev)) {
484       error("Unable to initialize Blkfront persistent storage");
485       goto abort_postvtpmblk;
486    }
487 
488    /* Run main loop */
489    main_loop();
490 
491    /* Shutdown blkfront */
492    shutdown_vtpmblk();
493 abort_postvtpmblk:
494 abort_postrng:
495 
496    /* Close devices */
497    shutdown_tpmfront(tpmfront_dev);
498 abort_posttpmfront:
499    shutdown_tpmback();
500 
501    cleanup_opt_args();
502 
503    return 0;
504 }
505