1 /*
2  * Copyright (c) 2010-2012 United States Government, as represented by
3  * the Secretary of Defense.  All rights reserved.
4  *
5  * based off of the original tools/vtpm_manager code base which is:
6  * Copyright (c) 2005, Intel Corp.
7  * All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  *   * Redistributions of source code must retain the above copyright
14  *     notice, this list of conditions and the following disclaimer.
15  *   * Redistributions in binary form must reproduce the above
16  *     copyright notice, this list of conditions and the following
17  *     disclaimer in the documentation and/or other materials provided
18  *     with the distribution.
19  *   * Neither the name of Intel Corporation nor the names of its
20  *     contributors may be used to endorse or promote products derived
21  *     from this software without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
24  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
25  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
26  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
27  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
29  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
30  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
32  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
34  * OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36 #include <stdint.h>
37 #include <stdlib.h>
38 
39 #include <xen/xen.h>
40 #include <mini-os/tpmback.h>
41 #include <mini-os/tpmfront.h>
42 #include <mini-os/tpm_tis.h>
43 #include <unistd.h>
44 #include <stdio.h>
45 #include <string.h>
46 #include <stdlib.h>
47 #include <polarssl/sha1.h>
48 
49 #include "log.h"
50 #include "vtpmmgr.h"
51 #include "vtpm_disk.h"
52 #include "tpm.h"
53 #include "marshal.h"
54 #include "tpm2_marshal.h"
55 #include "tpm2.h"
56 
57 struct Opts {
58    enum {
59       TPMDRV_TPM_TIS,
60       TPMDRV_TPMFRONT,
61    } tpmdriver;
62    unsigned long tpmiomem;
63    unsigned int tpmirq;
64    unsigned int tpmlocality;
65    int gen_owner_auth;
66 };
67 
68 // --------------------------- Well Known Auths --------------------------
69 const TPM_AUTHDATA WELLKNOWN_AUTH = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
70    0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
71 
72 struct vtpm_globals vtpm_globals = {
73    .tpm_fd = -1,
74    .oiap = { .AuthHandle = 0 },
75    .hw_locality = 0
76 };
77 
tpm_entropy_source(void * dummy,unsigned char * data,size_t len,size_t * olen)78 static int tpm_entropy_source(void* dummy, unsigned char* data, size_t len, size_t* olen) {
79    UINT32 sz = len;
80    TPM_RESULT rc = TPM_GetRandom(&sz, data);
81    *olen = sz;
82    return rc == TPM_SUCCESS ? 0 : POLARSSL_ERR_ENTROPY_SOURCE_FAILED;
83 }
84 
check_tpm_version(void)85 static TPM_RESULT check_tpm_version(void) {
86    TPM_RESULT status;
87    UINT32 rsize;
88    BYTE* res = NULL;
89    TPM_CAP_VERSION_INFO vinfo;
90 
91    TPMTRYRETURN(TPM_GetCapability(
92             TPM_CAP_VERSION_VAL,
93             0,
94             NULL,
95             &rsize,
96             &res));
97    if(rsize < 4) {
98       vtpmlogerror(VTPM_LOG_VTPM, "Invalid size returned by GetCapability!\n");
99       status = TPM_BAD_PARAMETER;
100       goto abort_egress;
101    }
102 
103    unpack_TPM_CAP_VERSION_INFO(res, &vinfo, UNPACK_ALIAS);
104 
105    vtpmloginfo(VTPM_LOG_VTPM, "Hardware TPM:\n");
106    vtpmloginfo(VTPM_LOG_VTPM, " version: %hhd %hhd %hhd %hhd\n",
107          vinfo.version.major, vinfo.version.minor, vinfo.version.revMajor, vinfo.version.revMinor);
108    vtpmloginfo(VTPM_LOG_VTPM, " specLevel: %hd\n", vinfo.specLevel);
109    vtpmloginfo(VTPM_LOG_VTPM, " errataRev: %hhd\n", vinfo.errataRev);
110    vtpmloginfo(VTPM_LOG_VTPM, " vendorID: %c%c%c%c\n",
111          vinfo.tpmVendorID[0], vinfo.tpmVendorID[1],
112          vinfo.tpmVendorID[2], vinfo.tpmVendorID[3]);
113    vtpmloginfo(VTPM_LOG_VTPM, " vendorSpecificSize: %hd\n", vinfo.vendorSpecificSize);
114    vtpmloginfo(VTPM_LOG_VTPM, " vendorSpecific: ");
115    for(int i = 0; i < vinfo.vendorSpecificSize; ++i) {
116       vtpmloginfomore(VTPM_LOG_VTPM, "%02hhx", vinfo.vendorSpecific[i]);
117    }
118    vtpmloginfomore(VTPM_LOG_VTPM, "\n");
119 
120 abort_egress:
121    free(res);
122    return status;
123 }
124 
flush_tpm(void)125 static TPM_RESULT flush_tpm(void) {
126    TPM_RESULT status = TPM_SUCCESS;
127    const TPM_RESOURCE_TYPE reslist[] = { TPM_RT_KEY, TPM_RT_AUTH, TPM_RT_TRANS, TPM_RT_COUNTER, TPM_RT_DAA_TPM, TPM_RT_CONTEXT };
128    BYTE* keylist = NULL;
129    UINT32 keylistSize;
130    BYTE* ptr;
131 
132    //Iterate through each resource type and flush all handles
133    for(int i = 0; i < sizeof(reslist) / sizeof(TPM_RESOURCE_TYPE); ++i) {
134       TPM_RESOURCE_TYPE beres = cpu_to_be32(reslist[i]);
135       UINT16 size;
136       TPMTRYRETURN(TPM_GetCapability(
137                TPM_CAP_HANDLE,
138                sizeof(TPM_RESOURCE_TYPE),
139                (BYTE*)(&beres),
140                &keylistSize,
141                &keylist));
142 
143       ptr = keylist;
144       ptr = unpack_UINT16(ptr, &size);
145 
146       //Flush each handle
147       if(size) {
148          vtpmloginfo(VTPM_LOG_VTPM, "Flushing %u handle(s) of type %lu\n", size, (unsigned long) reslist[i]);
149          for(int j = 0; j < size; ++j) {
150             TPM_HANDLE h;
151             ptr = unpack_TPM_HANDLE(ptr, &h);
152             TPMTRYRETURN(TPM_FlushSpecific(h, reslist[i]));
153          }
154       }
155 
156       free(keylist);
157       keylist = NULL;
158    }
159 
160    goto egress;
161 abort_egress:
162    free(keylist);
163 egress:
164    return status;
165 }
166 
167 
try_take_ownership(void)168 static TPM_RESULT try_take_ownership(void) {
169    TPM_RESULT status = TPM_SUCCESS;
170    TPM_PUBKEY pubEK = TPM_PUBKEY_INIT;
171 
172    // If we can read PubEK then there is no owner and we should take it.
173    status = TPM_ReadPubek(&pubEK);
174 
175    switch(status) {
176       case TPM_DISABLED_CMD:
177          //Cannot read ek? TPM has owner
178          vtpmloginfo(VTPM_LOG_VTPM, "Failed to readEK meaning TPM has an owner. Creating Keys off existing SRK.\n");
179          status = TPM_SUCCESS;
180          break;
181       case TPM_NO_ENDORSEMENT:
182          {
183             //If theres no ek, we have to create one
184             TPM_KEY_PARMS keyInfo = {
185                .algorithmID = TPM_ALG_RSA,
186                .encScheme = TPM_ES_RSAESOAEP_SHA1_MGF1,
187                .sigScheme = TPM_SS_NONE,
188                .parmSize = 12,
189                .parms.rsa = {
190                   .keyLength = RSA_KEY_SIZE,
191                   .numPrimes = 2,
192                   .exponentSize = 0,
193                   .exponent = NULL,
194                },
195             };
196             TPMTRYRETURN(TPM_CreateEndorsementKeyPair(&keyInfo, &pubEK));
197          }
198          //fall through to take ownership
199       case TPM_SUCCESS:
200          {
201             //Construct the Srk
202             TPM_KEY srk = {
203                .ver = TPM_STRUCT_VER_1_1,
204                .keyUsage = TPM_KEY_STORAGE,
205                .keyFlags = 0x00,
206                .authDataUsage = TPM_AUTH_ALWAYS,
207                .algorithmParms = {
208                   .algorithmID = TPM_ALG_RSA,
209                   .encScheme = TPM_ES_RSAESOAEP_SHA1_MGF1,
210                   .sigScheme =  TPM_SS_NONE,
211                   .parmSize = 12,
212                   .parms.rsa = {
213                      .keyLength = RSA_KEY_SIZE,
214                      .numPrimes = 2,
215                      .exponentSize = 0,
216                      .exponent = NULL,
217                   },
218                },
219                .PCRInfoSize = 0,
220                .pubKey = {
221                   .keyLength = 0,
222                   .key = NULL,
223                },
224                .encDataSize = 0,
225             };
226 
227             TPMTRYRETURN(TPM_TakeOwnership(
228                      &pubEK,
229                      (const TPM_AUTHDATA*)&vtpm_globals.owner_auth,
230                      (const TPM_AUTHDATA*)&vtpm_globals.srk_auth,
231                      &srk,
232                      NULL,
233                      &vtpm_globals.oiap));
234 
235             TPMTRYRETURN(TPM_DisablePubekRead(
236                      (const TPM_AUTHDATA*)&vtpm_globals.owner_auth,
237                      &vtpm_globals.oiap));
238          }
239          break;
240       default:
241          break;
242    }
243 abort_egress:
244    free_TPM_PUBKEY(&pubEK);
245    return status;
246 }
247 
parse_auth_string(char * authstr,BYTE * target)248 static int parse_auth_string(char* authstr, BYTE* target) {
249    int rc;
250    /* well known owner auth */
251    if(!strcmp(authstr, "well-known")) {
252 	   return 0;
253    }
254    /* owner auth is a raw hash */
255    else if(!strncmp(authstr, "hash:", 5)) {
256       authstr += 5;
257       if((rc = strlen(authstr)) != 40) {
258          vtpmlogerror(VTPM_LOG_VTPM, "Supplied owner auth hex string `%s' must be exactly 40 characters (20 bytes) long, length=%d\n", authstr, rc);
259          return -1;
260       }
261       for(int j = 0; j < 20; ++j) {
262          if(sscanf(authstr, "%hhX", target + j) != 1) {
263             vtpmlogerror(VTPM_LOG_VTPM, "Supplied owner auth string `%s' is not a valid hex string\n", authstr);
264             return -1;
265          }
266          authstr += 2;
267       }
268    }
269    /* owner auth is a string that will be hashed */
270    else if(!strncmp(authstr, "text:", 5)) {
271       authstr += 5;
272       sha1((const unsigned char*)authstr, strlen(authstr), target);
273    }
274    else {
275       vtpmlogerror(VTPM_LOG_VTPM, "Invalid auth string %s\n", authstr);
276       return -1;
277    }
278 
279    return 0;
280 }
281 
parse_cmdline_opts(int argc,char ** argv,struct Opts * opts)282 int parse_cmdline_opts(int argc, char** argv, struct Opts* opts)
283 {
284    int rc;
285    int i;
286 
287    //Set defaults
288    memcpy(vtpm_globals.owner_auth, WELLKNOWN_AUTH, sizeof(TPM_AUTHDATA));
289    memcpy(vtpm_globals.srk_auth, WELLKNOWN_AUTH, sizeof(TPM_AUTHDATA));
290 
291    for(i = 1; i < argc; ++i) {
292       if(!strncmp(argv[i], "owner_auth=", 11)) {
293          if((rc = parse_auth_string(argv[i] + 11, vtpm_globals.owner_auth)) < 0) {
294             goto err_invalid;
295          }
296          if(rc == 1) {
297             opts->gen_owner_auth = 1;
298          }
299       }
300       else if(!strncmp(argv[i], "srk_auth=", 9)) {
301          if((rc = parse_auth_string(argv[i] + 9, vtpm_globals.srk_auth)) != 0) {
302             goto err_invalid;
303          }
304       }
305       else if(!strncmp(argv[i], "srk_handle=", 11)) {
306          if(sscanf(argv[i] + 11, "%x", &vtpm_globals.srk_handle) != 1) {
307             goto err_invalid;
308          }
309       }
310       else if(!strncmp(argv[i], "tpmdriver=", 10)) {
311          if(!strcmp(argv[i] + 10, "tpm_tis")) {
312             opts->tpmdriver = TPMDRV_TPM_TIS;
313          } else if(!strcmp(argv[i] + 10, "tpmfront")) {
314             opts->tpmdriver = TPMDRV_TPMFRONT;
315          } else {
316             goto err_invalid;
317          }
318       }
319       else if(!strncmp(argv[i], "tpmiomem=",9)) {
320          if(sscanf(argv[i] + 9, "0x%lX", &opts->tpmiomem) != 1) {
321             goto err_invalid;
322          }
323       }
324       else if(!strncmp(argv[i], "tpmirq=",7)) {
325          if(!strcmp(argv[i] + 7, "probe")) {
326             opts->tpmirq = TPM_PROBE_IRQ;
327          } else if( sscanf(argv[i] + 7, "%u", &opts->tpmirq) != 1) {
328             goto err_invalid;
329          }
330       }
331       else if(!strncmp(argv[i], "tpmlocality=",12)) {
332          if(sscanf(argv[i] + 12, "%u", &opts->tpmlocality) != 1 || opts->tpmlocality > 4) {
333             goto err_invalid;
334          }
335       }
336    }
337 
338    switch(opts->tpmdriver) {
339       case TPMDRV_TPM_TIS:
340          vtpmloginfo(VTPM_LOG_VTPM, "Option: Using tpm_tis driver\n");
341          break;
342       case TPMDRV_TPMFRONT:
343          vtpmloginfo(VTPM_LOG_VTPM, "Option: Using tpmfront driver\n");
344          break;
345    }
346 
347    return 0;
348 err_invalid:
349    vtpmlogerror(VTPM_LOG_VTPM, "Invalid Option %s\n", argv[i]);
350    return -1;
351 }
352 
353 
354 
vtpmmgr_create(void)355 static TPM_RESULT vtpmmgr_create(void) {
356    TPM_RESULT status = TPM_SUCCESS;
357    TPM_AUTH_SESSION osap = TPM_AUTH_SESSION_INIT;
358    TPM_AUTHDATA sharedsecret;
359 
360    // Take ownership if TPM is unowned
361    TPMTRYRETURN(try_take_ownership());
362 
363    // Generate storage key's auth
364    TPMTRYRETURN( TPM_OSAP(
365             TPM_ET_KEYHANDLE,
366             TPM_SRK_KEYHANDLE,
367             (const TPM_AUTHDATA*)&vtpm_globals.srk_auth,
368             &sharedsecret,
369             &osap) );
370 
371    //Make sure TPM has commited changes
372    TPMTRYRETURN( TPM_SaveState() );
373 
374    //Create new disk image
375    TPMTRYRETURN(vtpm_new_disk());
376 
377    goto egress;
378 abort_egress:
379 egress:
380    vtpmloginfo(VTPM_LOG_VTPM, "Finished initialized new VTPM manager\n");
381 
382    //End the OSAP session
383    if(osap.AuthHandle) {
384       TPM_TerminateHandle(osap.AuthHandle);
385    }
386 
387    return status;
388 }
389 
set_opaque(domid_t domid,unsigned int handle)390 static void set_opaque(domid_t domid, unsigned int handle)
391 {
392 	struct tpm_opaque* opq;
393 
394 	opq = calloc(1, sizeof(*opq));
395 	opq->uuid = (uuid_t*)tpmback_get_uuid(domid, handle);
396 	opq->domid = domid;
397 	opq->handle = handle;
398 	tpmback_set_opaque(domid, handle, opq);
399 }
400 
free_opaque(domid_t domid,unsigned int handle)401 static void free_opaque(domid_t domid, unsigned int handle)
402 {
403 	struct tpm_opaque* opq = tpmback_get_opaque(domid, handle);
404 	if (opq && opq->vtpm)
405 		opq->vtpm->flags &= ~VTPM_FLAG_OPEN;
406 	free(opq);
407 }
408 
vtpmmgr_init(int argc,char ** argv)409 TPM_RESULT vtpmmgr_init(int argc, char** argv) {
410    TPM_RESULT status = TPM_SUCCESS;
411 
412    /* Default commandline options */
413    struct Opts opts = {
414       .tpmdriver = TPMDRV_TPM_TIS,
415       .tpmiomem = TPM_BASEADDR,
416       .tpmirq = 0,
417       .tpmlocality = 0,
418       .gen_owner_auth = 0,
419    };
420 
421    if(parse_cmdline_opts(argc, argv, &opts) != 0) {
422       vtpmlogerror(VTPM_LOG_VTPM, "Command line parsing failed! exiting..\n");
423       status = TPM_BAD_PARAMETER;
424       goto abort_egress;
425    }
426 
427    //Setup storage system
428    if(vtpm_storage_init() != 0) {
429       vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize storage subsystem!\n");
430       status = TPM_IOERROR;
431       goto abort_egress;
432    }
433 
434    //Setup tpmback device
435    init_tpmback(set_opaque, free_opaque);
436 
437    //Setup tpm access
438    switch(opts.tpmdriver) {
439       case TPMDRV_TPM_TIS:
440          {
441             struct tpm_chip* tpm;
442             if((tpm = init_tpm_tis(opts.tpmiomem, TPM_TIS_LOCL_INT_TO_FLAG(opts.tpmlocality), opts.tpmirq)) == NULL) {
443                vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize tpmfront device\n");
444                status = TPM_IOERROR;
445                goto abort_egress;
446             }
447             vtpm_globals.tpm_fd = tpm_tis_open(tpm);
448             tpm_tis_request_locality(tpm, opts.tpmlocality);
449             vtpm_globals.hw_locality = opts.tpmlocality;
450          }
451          break;
452       case TPMDRV_TPMFRONT:
453          {
454             struct tpmfront_dev* tpmfront_dev;
455             if((tpmfront_dev = init_tpmfront(NULL)) == NULL) {
456                vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize tpmfront device\n");
457                status = TPM_IOERROR;
458                goto abort_egress;
459             }
460             vtpm_globals.tpm_fd = tpmfront_open(tpmfront_dev);
461          }
462          break;
463    }
464 
465    //Get the version of the tpm
466    TPMTRYRETURN(check_tpm_version());
467 
468    // Blow away all stale handles left in the tpm
469    if(flush_tpm() != TPM_SUCCESS) {
470       vtpmlogerror(VTPM_LOG_VTPM, "VTPM_FlushResources failed, continuing anyway..\n");
471    }
472 
473    /* Initialize the rng */
474    entropy_init(&vtpm_globals.entropy);
475    entropy_add_source(&vtpm_globals.entropy, tpm_entropy_source, NULL, 0);
476    entropy_gather(&vtpm_globals.entropy);
477    ctr_drbg_init(&vtpm_globals.ctr_drbg, entropy_func, &vtpm_globals.entropy, NULL, 0);
478    ctr_drbg_set_prediction_resistance( &vtpm_globals.ctr_drbg, CTR_DRBG_PR_OFF );
479 
480    // Generate Auth for Owner
481    if(opts.gen_owner_auth) {
482       vtpmmgr_rand(vtpm_globals.owner_auth, sizeof(TPM_AUTHDATA));
483    }
484 
485    // Create OIAP session for service's authorized commands
486    TPMTRYRETURN( TPM_OIAP(&vtpm_globals.oiap) );
487 
488    /* Load the Manager data, if it fails create a new manager */
489    // TODO handle upgrade recovery of auth0
490    if (vtpm_load_disk()) {
491       /* If the OIAP session was closed by an error, create a new one */
492       if(vtpm_globals.oiap.AuthHandle == 0) {
493          TPMTRYRETURN( TPM_OIAP(&vtpm_globals.oiap) );
494       }
495       vtpmloginfo(VTPM_LOG_VTPM, "Failed to read manager file. Assuming first time initialization.\n");
496       TPMTRYRETURN( vtpmmgr_create() );
497    }
498 
499    goto egress;
500 abort_egress:
501    vtpmmgr_shutdown();
502 egress:
503    return status;
504 }
505 
506 /* TPM 2.0 */
507 
tpm2_AuthArea_ctor(const char * authValue,UINT32 authLen,TPM_AuthArea * auth)508 static void tpm2_AuthArea_ctor(const char *authValue, UINT32 authLen,
509                                TPM_AuthArea *auth)
510 {
511     auth->sessionHandle = TPM_RS_PW;
512     auth->nonce.size = 0;
513     auth->sessionAttributes = 1;
514     auth->auth.size = authLen;
515     memcpy(auth->auth.buffer, authValue, authLen);
516     auth->size = 9 + authLen;
517 }
518 
tpm2_take_ownership(void)519 TPM_RC tpm2_take_ownership(void)
520 {
521     TPM_RC status = TPM_SUCCESS;
522 
523     tpm2_AuthArea_ctor(NULL, 0, &vtpm_globals.pw_auth);
524 
525     /* create SRK */
526     TPM2_CreatePrimary_Params_in in = {
527         .inSensitive = {
528             .size = 4,
529             .sensitive = {
530                 .userAuth.size = 0,
531                 .userAuth.buffer = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\
532                                      0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
533                 .data.size = 0,
534             },
535         },
536         .inPublic = {
537             .size = 60,
538             .publicArea = {
539                 .type = TPM2_ALG_RSA,
540                 .nameAlg = TPM2_ALG_SHA256,
541 #define SRK_OBJ_ATTR (fixedTPM | fixedParent  | userWithAuth | \
542                       sensitiveDataOrigin | restricted | decrypt)
543                 .objectAttributes = SRK_OBJ_ATTR,
544                 .authPolicy.size = 0,
545                 .parameters.rsaDetail = {
546                     .symmetric = {
547                     .algorithm = TPM2_ALG_AES,
548                     .keyBits.aes = AES_KEY_SIZES_BITS,
549                     .mode.aes = TPM2_ALG_CFB,
550                     },
551                 .scheme = { TPM2_ALG_NULL },
552                 .keyBits = RSA_KEY_SIZES_BITS,
553                 .exponent = 0,
554                 },
555                 .unique.rsa.size = 0,
556             },
557         },
558             .outsideInfo.size = 0,
559             .creationPCR.count = 0,
560     };
561 
562     TPMTRYRETURN(TPM2_CreatePrimary(TPM_RH_OWNER,&in,
563                                     &vtpm_globals.srk_handle, NULL));
564     vtpmloginfo(VTPM_LOG_VTPM, "SRK handle: 0x%X\n", vtpm_globals.srk_handle);
565     {
566         const char data[20] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\
567                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
568         tpm2_AuthArea_ctor(data, 20, &vtpm_globals.srk_auth_area);
569     }
570     /*end create SRK*/
571 
572 abort_egress:
573     return status;
574 }
575 
vtpmmgr2_create(void)576 TPM_RESULT vtpmmgr2_create(void)
577 {
578     TPM_RESULT status = TPM_SUCCESS;
579 
580     if ( vtpm_globals.srk_handle == 0 ) {
581         TPMTRYRETURN(tpm2_take_ownership());
582     } else {
583         tpm2_AuthArea_ctor(NULL, 0, &vtpm_globals.srk_auth_area);
584     }
585 
586    /* create SK */
587     TPM2_Create_Params_out out;
588     TPM2_Create_Params_in in = {
589         .inSensitive = {
590             .size = 4 + 20,
591             .sensitive = {
592                 .userAuth.size = 20,
593                 .userAuth.buffer = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\
594                                      0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
595                 .data.size = 0,
596             },
597         },
598         .inPublic = {
599             .size = (60),
600             .publicArea = {
601                  .type = TPM2_ALG_RSA,
602                  .nameAlg = TPM2_ALG_SHA256,
603 #define SK_OBJ_ATTR (fixedTPM | fixedParent | userWithAuth |\
604                      sensitiveDataOrigin |decrypt)
605                  .objectAttributes = SK_OBJ_ATTR,
606                  .authPolicy.size = 0,
607                  .parameters.rsaDetail = {
608                      .symmetric = {
609                          .algorithm = TPM2_ALG_NULL,
610                      },
611                      .scheme = {
612                          TPM2_ALG_OAEP,
613                          .details.oaep.hashAlg = TPM2_ALG_SHA256,
614                      },
615                      .keyBits = RSA_KEY_SIZES_BITS,
616                      .exponent = 0,
617                   },
618                   .unique.rsa.size = 0,
619             },
620         },
621         .outsideInfo.size = 0,
622         .creationPCR.count = 0,
623     };/*end in */
624 
625     TPMTRYRETURN(TPM2_Create(vtpm_globals.srk_handle, &in, &out));
626     TPMTRYRETURN(TPM2_Load(vtpm_globals.srk_handle,
627                            &vtpm_globals.tpm2_storage_key.Private,
628                            &vtpm_globals.tpm2_storage_key.Public,
629                            &vtpm_globals.sk_handle,
630                            &vtpm_globals.sk_name));
631 
632     vtpmloginfo(VTPM_LOG_VTPM, "SK HANDLE: 0x%X\n", vtpm_globals.sk_handle);
633 
634     /*Create new disk image*/
635     TPMTRYRETURN(vtpm_new_disk());
636 
637     goto egress;
638 
639 abort_egress:
640 egress:
641     vtpmloginfo(VTPM_LOG_VTPM, "Finished initialized new VTPM manager\n");
642     return status;
643 }
644 
tpm2_entropy_source(void * dummy,unsigned char * data,size_t len,size_t * olen)645 static int tpm2_entropy_source(void* dummy, unsigned char* data,
646                                size_t len, size_t* olen)
647 {
648     UINT32 sz = len;
649     TPM_RESULT rc = TPM2_GetRandom(&sz, data);
650     *olen = sz;
651     return rc == TPM_SUCCESS ? 0 : POLARSSL_ERR_ENTROPY_SOURCE_FAILED;
652 }
653 
654 /*TPM 2.0 Objects flush */
flush_tpm2(void)655 static TPM_RC flush_tpm2(void)
656 {
657     int i;
658 
659     for (i = TRANSIENT_FIRST; i <= TRANSIENT_LAST; i++)
660          TPM2_FlushContext(i);
661 
662     return TPM_SUCCESS;
663 }
664 
vtpmmgr2_init(int argc,char ** argv)665 TPM_RESULT vtpmmgr2_init(int argc, char** argv)
666 {
667     TPM_RESULT status = TPM_SUCCESS;
668 
669     /* Default commandline options */
670     struct Opts opts = {
671         .tpmdriver = TPMDRV_TPM_TIS,
672         .tpmiomem = TPM_BASEADDR,
673         .tpmirq = 0,
674         .tpmlocality = 0,
675         .gen_owner_auth = 0,
676     };
677 
678     if (parse_cmdline_opts(argc, argv, &opts) != 0) {
679         vtpmlogerror(VTPM_LOG_VTPM, "Command line parsing failed! exiting..\n");
680         status = TPM_BAD_PARAMETER;
681         goto abort_egress;
682     }
683 
684     /*Setup storage system*/
685     if (vtpm_storage_init() != 0) {
686         vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize storage subsystem!\n");
687         status = TPM_IOERROR;
688         goto abort_egress;
689     }
690 
691     /*Setup tpmback device*/
692     init_tpmback(set_opaque, free_opaque);
693 
694     /*Setup tpm access*/
695     switch(opts.tpmdriver) {
696         case TPMDRV_TPM_TIS:
697         {
698             struct tpm_chip* tpm;
699             if ((tpm = init_tpm2_tis(opts.tpmiomem, TPM_TIS_LOCL_INT_TO_FLAG(opts.tpmlocality),
700                                      opts.tpmirq)) == NULL) {
701                 vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize tpmfront device\n");
702                 status = TPM_IOERROR;
703                 goto abort_egress;
704             }
705             printk("init_tpm2_tis()       ...ok\n");
706             vtpm_globals.tpm_fd = tpm_tis_open(tpm);
707             tpm_tis_request_locality(tpm, opts.tpmlocality);
708         }
709         break;
710         case TPMDRV_TPMFRONT:
711         {
712             struct tpmfront_dev* tpmfront_dev;
713             if ((tpmfront_dev = init_tpmfront(NULL)) == NULL) {
714                 vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize tpmfront device\n");
715                 status = TPM_IOERROR;
716                 goto abort_egress;
717             }
718             vtpm_globals.tpm_fd = tpmfront_open(tpmfront_dev);
719         }
720         break;
721     }
722     printk("TPM 2.0 access ...ok\n");
723     /* Blow away all stale handles left in the tpm*/
724     if (flush_tpm2() != TPM_SUCCESS) {
725         vtpmlogerror(VTPM_LOG_VTPM, "VTPM_FlushResources failed, continuing anyway..\n");
726     }
727 
728     /* Initialize the rng */
729     entropy_init(&vtpm_globals.entropy);
730     entropy_add_source(&vtpm_globals.entropy, tpm2_entropy_source, NULL, 0);
731     entropy_gather(&vtpm_globals.entropy);
732     ctr_drbg_init(&vtpm_globals.ctr_drbg, entropy_func, &vtpm_globals.entropy, NULL, 0);
733     ctr_drbg_set_prediction_resistance( &vtpm_globals.ctr_drbg, CTR_DRBG_PR_OFF );
734 
735     /* Generate Auth for Owner*/
736     if (opts.gen_owner_auth) {
737         vtpmmgr_rand(vtpm_globals.owner_auth, sizeof(TPM_AUTHDATA));
738     }
739 
740     /* Load the Manager data, if it fails create a new manager */
741     if (vtpm_load_disk()) {
742         vtpmloginfo(VTPM_LOG_VTPM, "Assuming first time initialization.\n");
743         TPMTRYRETURN(vtpmmgr2_create());
744     }
745 
746     goto egress;
747 
748 abort_egress:
749     vtpmmgr_shutdown();
750 egress:
751     return status;
752 }
753 
tpm2_pcr_read(int index,uint8_t * buf)754 TPM_RC tpm2_pcr_read(int index, uint8_t *buf)
755 {
756     TPM_RESULT status = TPM_SUCCESS;
757     TPML_PCR_SELECTION pcrSelectionIn = {
758         .count = 1,};
759 
760     TPMS_PCR_SELECTION tpms_pcr_selection = {
761         .hash = TPM2_ALG_SHA1,
762         .sizeofSelect = PCR_SELECT_MAX,};
763 
764     UINT32 pcrUpdateCounter;
765     TPML_PCR_SELECTION pcrSelectionOut;
766     TPML_DIGEST pcrValues;
767     TPM2B_DIGEST tpm2b_digest;
768 
769     tpms_pcr_selection.pcrSelect[PCR_SELECT_NUM(index)] = PCR_SELECT_VALUE(index);
770     memcpy(&pcrSelectionIn.pcrSelections[0], &tpms_pcr_selection,
771            sizeof(TPMS_PCR_SELECTION));
772 
773     TPMTRYRETURN(TPM2_PCR_Read(pcrSelectionIn, &pcrUpdateCounter,
774                                &pcrSelectionOut, &pcrValues));
775 
776     if (pcrValues.count < 1)
777         goto egress;
778 
779     unpack_TPM2B_DIGEST((uint8_t *) &pcrValues, &tpm2b_digest);
780     memcpy(buf, tpm2b_digest.buffer, SHA1_DIGEST_SIZE);
781 
782 abort_egress:
783 egress:
784     return status;
785 }
786 
vtpmmgr_shutdown(void)787 void vtpmmgr_shutdown(void)
788 {
789    /* Cleanup TPM resources */
790    TPM_TerminateHandle(vtpm_globals.oiap.AuthHandle);
791 
792    /* Close tpmback */
793    shutdown_tpmback();
794 
795     if (hw_is_tpm2()) {
796         /* Blow away all stale handles left in the tpm*/
797         if (flush_tpm2() != TPM_SUCCESS) {
798             vtpmlogerror(VTPM_LOG_TPM,
799                          "TPM2_FlushResources failed, continuing shutdown..\n");
800         }
801     }
802 
803    /* Close tpmfront/tpm_tis */
804    close(vtpm_globals.tpm_fd);
805 
806    vtpmloginfo(VTPM_LOG_VTPM, "VTPM Manager stopped.\n");
807 }
808