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:", 10)) {
293          if((rc = parse_auth_string(argv[i] + 10, 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:", 8)) {
301          if((rc = parse_auth_string(argv[i] + 8, vtpm_globals.srk_auth)) != 0) {
302             goto err_invalid;
303          }
304       }
305       else if(!strncmp(argv[i], "tpmdriver=", 10)) {
306          if(!strcmp(argv[i] + 10, "tpm_tis")) {
307             opts->tpmdriver = TPMDRV_TPM_TIS;
308          } else if(!strcmp(argv[i] + 10, "tpmfront")) {
309             opts->tpmdriver = TPMDRV_TPMFRONT;
310          } else {
311             goto err_invalid;
312          }
313       }
314       else if(!strncmp(argv[i], "tpmiomem=",9)) {
315          if(sscanf(argv[i] + 9, "0x%lX", &opts->tpmiomem) != 1) {
316             goto err_invalid;
317          }
318       }
319       else if(!strncmp(argv[i], "tpmirq=",7)) {
320          if(!strcmp(argv[i] + 7, "probe")) {
321             opts->tpmirq = TPM_PROBE_IRQ;
322          } else if( sscanf(argv[i] + 7, "%u", &opts->tpmirq) != 1) {
323             goto err_invalid;
324          }
325       }
326       else if(!strncmp(argv[i], "tpmlocality=",12)) {
327          if(sscanf(argv[i] + 12, "%u", &opts->tpmlocality) != 1 || opts->tpmlocality > 4) {
328             goto err_invalid;
329          }
330       }
331    }
332 
333    switch(opts->tpmdriver) {
334       case TPMDRV_TPM_TIS:
335          vtpmloginfo(VTPM_LOG_VTPM, "Option: Using tpm_tis driver\n");
336          break;
337       case TPMDRV_TPMFRONT:
338          vtpmloginfo(VTPM_LOG_VTPM, "Option: Using tpmfront driver\n");
339          break;
340    }
341 
342    return 0;
343 err_invalid:
344    vtpmlogerror(VTPM_LOG_VTPM, "Invalid Option %s\n", argv[i]);
345    return -1;
346 }
347 
348 
349 
vtpmmgr_create(void)350 static TPM_RESULT vtpmmgr_create(void) {
351    TPM_RESULT status = TPM_SUCCESS;
352    TPM_AUTH_SESSION osap = TPM_AUTH_SESSION_INIT;
353    TPM_AUTHDATA sharedsecret;
354 
355    // Take ownership if TPM is unowned
356    TPMTRYRETURN(try_take_ownership());
357 
358    // Generate storage key's auth
359    TPMTRYRETURN( TPM_OSAP(
360             TPM_ET_KEYHANDLE,
361             TPM_SRK_KEYHANDLE,
362             (const TPM_AUTHDATA*)&vtpm_globals.srk_auth,
363             &sharedsecret,
364             &osap) );
365 
366    //Make sure TPM has commited changes
367    TPMTRYRETURN( TPM_SaveState() );
368 
369    //Create new disk image
370    TPMTRYRETURN(vtpm_new_disk());
371 
372    goto egress;
373 abort_egress:
374 egress:
375    vtpmloginfo(VTPM_LOG_VTPM, "Finished initialized new VTPM manager\n");
376 
377    //End the OSAP session
378    if(osap.AuthHandle) {
379       TPM_TerminateHandle(osap.AuthHandle);
380    }
381 
382    return status;
383 }
384 
set_opaque(domid_t domid,unsigned int handle)385 static void set_opaque(domid_t domid, unsigned int handle)
386 {
387 	struct tpm_opaque* opq;
388 
389 	opq = calloc(1, sizeof(*opq));
390 	opq->uuid = (uuid_t*)tpmback_get_uuid(domid, handle);
391 	opq->domid = domid;
392 	opq->handle = handle;
393 	tpmback_set_opaque(domid, handle, opq);
394 }
395 
free_opaque(domid_t domid,unsigned int handle)396 static void free_opaque(domid_t domid, unsigned int handle)
397 {
398 	struct tpm_opaque* opq = tpmback_get_opaque(domid, handle);
399 	if (opq && opq->vtpm)
400 		opq->vtpm->flags &= ~VTPM_FLAG_OPEN;
401 	free(opq);
402 }
403 
vtpmmgr_init(int argc,char ** argv)404 TPM_RESULT vtpmmgr_init(int argc, char** argv) {
405    TPM_RESULT status = TPM_SUCCESS;
406 
407    /* Default commandline options */
408    struct Opts opts = {
409       .tpmdriver = TPMDRV_TPM_TIS,
410       .tpmiomem = TPM_BASEADDR,
411       .tpmirq = 0,
412       .tpmlocality = 0,
413       .gen_owner_auth = 0,
414    };
415 
416    if(parse_cmdline_opts(argc, argv, &opts) != 0) {
417       vtpmlogerror(VTPM_LOG_VTPM, "Command line parsing failed! exiting..\n");
418       status = TPM_BAD_PARAMETER;
419       goto abort_egress;
420    }
421 
422    //Setup storage system
423    if(vtpm_storage_init() != 0) {
424       vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize storage subsystem!\n");
425       status = TPM_IOERROR;
426       goto abort_egress;
427    }
428 
429    //Setup tpmback device
430    init_tpmback(set_opaque, free_opaque);
431 
432    //Setup tpm access
433    switch(opts.tpmdriver) {
434       case TPMDRV_TPM_TIS:
435          {
436             struct tpm_chip* tpm;
437             if((tpm = init_tpm_tis(opts.tpmiomem, TPM_TIS_LOCL_INT_TO_FLAG(opts.tpmlocality), opts.tpmirq)) == NULL) {
438                vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize tpmfront device\n");
439                status = TPM_IOERROR;
440                goto abort_egress;
441             }
442             vtpm_globals.tpm_fd = tpm_tis_open(tpm);
443             tpm_tis_request_locality(tpm, opts.tpmlocality);
444             vtpm_globals.hw_locality = opts.tpmlocality;
445          }
446          break;
447       case TPMDRV_TPMFRONT:
448          {
449             struct tpmfront_dev* tpmfront_dev;
450             if((tpmfront_dev = init_tpmfront(NULL)) == NULL) {
451                vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize tpmfront device\n");
452                status = TPM_IOERROR;
453                goto abort_egress;
454             }
455             vtpm_globals.tpm_fd = tpmfront_open(tpmfront_dev);
456          }
457          break;
458    }
459 
460    //Get the version of the tpm
461    TPMTRYRETURN(check_tpm_version());
462 
463    // Blow away all stale handles left in the tpm
464    if(flush_tpm() != TPM_SUCCESS) {
465       vtpmlogerror(VTPM_LOG_VTPM, "VTPM_FlushResources failed, continuing anyway..\n");
466    }
467 
468    /* Initialize the rng */
469    entropy_init(&vtpm_globals.entropy);
470    entropy_add_source(&vtpm_globals.entropy, tpm_entropy_source, NULL, 0);
471    entropy_gather(&vtpm_globals.entropy);
472    ctr_drbg_init(&vtpm_globals.ctr_drbg, entropy_func, &vtpm_globals.entropy, NULL, 0);
473    ctr_drbg_set_prediction_resistance( &vtpm_globals.ctr_drbg, CTR_DRBG_PR_OFF );
474 
475    // Generate Auth for Owner
476    if(opts.gen_owner_auth) {
477       vtpmmgr_rand(vtpm_globals.owner_auth, sizeof(TPM_AUTHDATA));
478    }
479 
480    // Create OIAP session for service's authorized commands
481    TPMTRYRETURN( TPM_OIAP(&vtpm_globals.oiap) );
482 
483    /* Load the Manager data, if it fails create a new manager */
484    // TODO handle upgrade recovery of auth0
485    if (vtpm_load_disk()) {
486       /* If the OIAP session was closed by an error, create a new one */
487       if(vtpm_globals.oiap.AuthHandle == 0) {
488          TPMTRYRETURN( TPM_OIAP(&vtpm_globals.oiap) );
489       }
490       vtpmloginfo(VTPM_LOG_VTPM, "Failed to read manager file. Assuming first time initialization.\n");
491       TPMTRYRETURN( vtpmmgr_create() );
492    }
493 
494    goto egress;
495 abort_egress:
496    vtpmmgr_shutdown();
497 egress:
498    return status;
499 }
500 
vtpmmgr_shutdown(void)501 void vtpmmgr_shutdown(void)
502 {
503    /* Cleanup TPM resources */
504    TPM_TerminateHandle(vtpm_globals.oiap.AuthHandle);
505 
506    /* Close tpmback */
507    shutdown_tpmback();
508 
509    /* Close tpmfront/tpm_tis */
510    close(vtpm_globals.tpm_fd);
511 
512    vtpmloginfo(VTPM_LOG_VTPM, "VTPM Manager stopped.\n");
513 }
514 
515 /* TPM 2.0 */
516 
tpm2_AuthArea_ctor(const char * authValue,UINT32 authLen,TPM_AuthArea * auth)517 static void tpm2_AuthArea_ctor(const char *authValue, UINT32 authLen,
518                                TPM_AuthArea *auth)
519 {
520     auth->sessionHandle = TPM_RS_PW;
521     auth->nonce.size = 0;
522     auth->sessionAttributes = 1;
523     auth->auth.size = authLen;
524     memcpy(auth->auth.buffer, authValue, authLen);
525     auth->size = 9 + authLen;
526 }
527 
tpm2_take_ownership(void)528 TPM_RC tpm2_take_ownership(void)
529 {
530     TPM_RC status = TPM_SUCCESS;
531 
532     tpm2_AuthArea_ctor(NULL, 0, &vtpm_globals.pw_auth);
533 
534     /* create SRK */
535     TPM2_CreatePrimary_Params_in in = {
536         .inSensitive = {
537             .size = 4,
538             .sensitive = {
539                 .userAuth.size = 0,
540                 .userAuth.buffer = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\
541                                      0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
542                 .data.size = 0,
543             },
544         },
545         .inPublic = {
546             .size = 60,
547             .publicArea = {
548                 .type = TPM2_ALG_RSA,
549                 .nameAlg = TPM2_ALG_SHA256,
550 #define SRK_OBJ_ATTR (fixedTPM | fixedParent  | userWithAuth | \
551                       sensitiveDataOrigin | restricted | decrypt)
552                 .objectAttributes = SRK_OBJ_ATTR,
553                 .authPolicy.size = 0,
554                 .parameters.rsaDetail = {
555                     .symmetric = {
556                     .algorithm = TPM2_ALG_AES,
557                     .keyBits.aes = AES_KEY_SIZES_BITS,
558                     .mode.aes = TPM2_ALG_CFB,
559                     },
560                 .scheme = { TPM2_ALG_NULL },
561                 .keyBits = RSA_KEY_SIZES_BITS,
562                 .exponent = 0,
563                 },
564                 .unique.rsa.size = 0,
565             },
566         },
567             .outsideInfo.size = 0,
568             .creationPCR.count = 0,
569     };
570 
571     TPMTRYRETURN(TPM2_CreatePrimary(TPM_RH_OWNER,&in,
572                                     &vtpm_globals.srk_handle, NULL));
573     vtpmloginfo(VTPM_LOG_VTPM, "SRK handle: 0x%X\n", vtpm_globals.srk_handle);
574     {
575         const char data[20] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\
576                                 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
577         tpm2_AuthArea_ctor(data, 20, &vtpm_globals.srk_auth_area);
578     }
579     /*end create SRK*/
580 
581 abort_egress:
582     return status;
583 }
584 
vtpmmgr2_create(void)585 TPM_RESULT vtpmmgr2_create(void)
586 {
587     TPM_RESULT status = TPM_SUCCESS;
588 
589     TPMTRYRETURN(tpm2_take_ownership());
590 
591    /* create SK */
592     TPM2_Create_Params_out out;
593     TPM2_Create_Params_in in = {
594         .inSensitive = {
595             .size = 4 + 20,
596             .sensitive = {
597                 .userAuth.size = 20,
598                 .userAuth.buffer = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,\
599                                      0, 0, 0, 0, 0, 0, 0, 0, 0, 0 },
600                 .data.size = 0,
601             },
602         },
603         .inPublic = {
604             .size = (60),
605             .publicArea = {
606                  .type = TPM2_ALG_RSA,
607                  .nameAlg = TPM2_ALG_SHA256,
608 #define SK_OBJ_ATTR (fixedTPM | fixedParent | userWithAuth |\
609                      sensitiveDataOrigin |decrypt)
610                  .objectAttributes = SK_OBJ_ATTR,
611                  .authPolicy.size = 0,
612                  .parameters.rsaDetail = {
613                      .symmetric = {
614                          .algorithm = TPM2_ALG_NULL,
615                      },
616                      .scheme = {
617                          TPM2_ALG_OAEP,
618                          .details.oaep.hashAlg = TPM2_ALG_SHA256,
619                      },
620                      .keyBits = RSA_KEY_SIZES_BITS,
621                      .exponent = 0,
622                   },
623                   .unique.rsa.size = 0,
624             },
625         },
626         .outsideInfo.size = 0,
627         .creationPCR.count = 0,
628     };/*end in */
629 
630     TPMTRYRETURN(TPM2_Create(vtpm_globals.srk_handle, &in, &out));
631     TPMTRYRETURN(TPM2_Load(vtpm_globals.srk_handle,
632                            &vtpm_globals.tpm2_storage_key.Private,
633                            &vtpm_globals.tpm2_storage_key.Public,
634                            &vtpm_globals.sk_handle,
635                            &vtpm_globals.sk_name));
636 
637     vtpmloginfo(VTPM_LOG_VTPM, "SK HANDLE: 0x%X\n", vtpm_globals.sk_handle);
638 
639     /*Create new disk image*/
640     TPMTRYRETURN(vtpm_new_disk());
641 
642     goto egress;
643 
644 abort_egress:
645 egress:
646     vtpmloginfo(VTPM_LOG_VTPM, "Finished initialized new VTPM manager\n");
647     return status;
648 }
649 
tpm2_entropy_source(void * dummy,unsigned char * data,size_t len,size_t * olen)650 static int tpm2_entropy_source(void* dummy, unsigned char* data,
651                                size_t len, size_t* olen)
652 {
653     UINT32 sz = len;
654     TPM_RESULT rc = TPM2_GetRandom(&sz, data);
655     *olen = sz;
656     return rc == TPM_SUCCESS ? 0 : POLARSSL_ERR_ENTROPY_SOURCE_FAILED;
657 }
658 
659 /*TPM 2.0 Objects flush */
flush_tpm2(void)660 static TPM_RC flush_tpm2(void)
661 {
662     int i;
663 
664     for (i = TRANSIENT_FIRST; i < TRANSIENT_LAST; i++)
665          TPM2_FlushContext(i);
666 
667     return TPM_SUCCESS;
668 }
669 
vtpmmgr2_init(int argc,char ** argv)670 TPM_RESULT vtpmmgr2_init(int argc, char** argv)
671 {
672     TPM_RESULT status = TPM_SUCCESS;
673 
674     /* Default commandline options */
675     struct Opts opts = {
676         .tpmdriver = TPMDRV_TPM_TIS,
677         .tpmiomem = TPM_BASEADDR,
678         .tpmirq = 0,
679         .tpmlocality = 0,
680         .gen_owner_auth = 0,
681     };
682 
683     if (parse_cmdline_opts(argc, argv, &opts) != 0) {
684         vtpmlogerror(VTPM_LOG_VTPM, "Command line parsing failed! exiting..\n");
685         status = TPM_BAD_PARAMETER;
686         goto abort_egress;
687     }
688 
689     /*Setup storage system*/
690     if (vtpm_storage_init() != 0) {
691         vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize storage subsystem!\n");
692         status = TPM_IOERROR;
693         goto abort_egress;
694     }
695 
696     /*Setup tpmback device*/
697     init_tpmback(set_opaque, free_opaque);
698 
699     /*Setup tpm access*/
700     switch(opts.tpmdriver) {
701         case TPMDRV_TPM_TIS:
702         {
703             struct tpm_chip* tpm;
704             if ((tpm = init_tpm2_tis(opts.tpmiomem, TPM_TIS_LOCL_INT_TO_FLAG(opts.tpmlocality),
705                                      opts.tpmirq)) == NULL) {
706                 vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize tpmfront device\n");
707                 status = TPM_IOERROR;
708                 goto abort_egress;
709             }
710             printk("init_tpm2_tis()       ...ok\n");
711             vtpm_globals.tpm_fd = tpm_tis_open(tpm);
712             tpm_tis_request_locality(tpm, opts.tpmlocality);
713         }
714         break;
715         case TPMDRV_TPMFRONT:
716         {
717             struct tpmfront_dev* tpmfront_dev;
718             if ((tpmfront_dev = init_tpmfront(NULL)) == NULL) {
719                 vtpmlogerror(VTPM_LOG_VTPM, "Unable to initialize tpmfront device\n");
720                 status = TPM_IOERROR;
721                 goto abort_egress;
722             }
723             vtpm_globals.tpm_fd = tpmfront_open(tpmfront_dev);
724         }
725         break;
726     }
727     printk("TPM 2.0 access ...ok\n");
728     /* Blow away all stale handles left in the tpm*/
729     if (flush_tpm2() != TPM_SUCCESS) {
730         vtpmlogerror(VTPM_LOG_VTPM, "VTPM_FlushResources failed, continuing anyway..\n");
731     }
732 
733     /* Initialize the rng */
734     entropy_init(&vtpm_globals.entropy);
735     entropy_add_source(&vtpm_globals.entropy, tpm2_entropy_source, NULL, 0);
736     entropy_gather(&vtpm_globals.entropy);
737     ctr_drbg_init(&vtpm_globals.ctr_drbg, entropy_func, &vtpm_globals.entropy, NULL, 0);
738     ctr_drbg_set_prediction_resistance( &vtpm_globals.ctr_drbg, CTR_DRBG_PR_OFF );
739 
740     /* Generate Auth for Owner*/
741     if (opts.gen_owner_auth) {
742         vtpmmgr_rand(vtpm_globals.owner_auth, sizeof(TPM_AUTHDATA));
743     }
744 
745     /* Load the Manager data, if it fails create a new manager */
746     if (vtpm_load_disk()) {
747         vtpmloginfo(VTPM_LOG_VTPM, "Assuming first time initialization.\n");
748         TPMTRYRETURN(vtpmmgr2_create());
749     }
750 
751     goto egress;
752 
753 abort_egress:
754     vtpmmgr_shutdown();
755 egress:
756     return status;
757 }
758 
tpm2_pcr_read(int index,uint8_t * buf)759 TPM_RC tpm2_pcr_read(int index, uint8_t *buf)
760 {
761     TPM_RESULT status = TPM_SUCCESS;
762     TPML_PCR_SELECTION pcrSelectionIn = {
763         .count = 1,};
764 
765     TPMS_PCR_SELECTION tpms_pcr_selection = {
766         .hash = TPM2_ALG_SHA1,
767         .sizeofSelect = PCR_SELECT_MAX,};
768 
769     UINT32 pcrUpdateCounter;
770     TPML_PCR_SELECTION pcrSelectionOut;
771     TPML_DIGEST pcrValues;
772     TPM2B_DIGEST tpm2b_digest;
773 
774     tpms_pcr_selection.pcrSelect[PCR_SELECT_NUM(index)] = PCR_SELECT_VALUE(index);
775     memcpy(&pcrSelectionIn.pcrSelections[0], &tpms_pcr_selection,
776            sizeof(TPMS_PCR_SELECTION));
777 
778     TPMTRYRETURN(TPM2_PCR_Read(pcrSelectionIn, &pcrUpdateCounter,
779                                &pcrSelectionOut, &pcrValues));
780 
781     if (pcrValues.count < 1)
782         goto egress;
783 
784     unpack_TPM2B_DIGEST((uint8_t *) &pcrValues, &tpm2b_digest);
785     memcpy(buf, tpm2b_digest.buffer, SHA1_DIGEST_SIZE);
786 
787 abort_egress:
788 egress:
789     return status;
790 }
791