Return to tpm_tss_tss2_v2.c CVS log | Up to [ELWIX - Embedded LightWeight unIX -] / embedaddon / strongswan / src / libtpmtss |
1.1 ! misho 1: /* ! 2: * Copyright (C) 2018 Tobias Brunner ! 3: * Copyright (C) 2018-2019 Andreas Steffen ! 4: * HSR Hochschule fuer Technik Rapperswil ! 5: * ! 6: * This program is free software; you can redistribute it and/or modify it ! 7: * under the terms of the GNU General Public License as published by the ! 8: * Free Software Foundation; either version 2 of the License, or (at your ! 9: * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>. ! 10: * ! 11: * This program is distributed in the hope that it will be useful, but ! 12: * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY ! 13: * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License ! 14: * for more details. ! 15: */ ! 16: ! 17: #include "tpm_tss_tss2.h" ! 18: #include "tpm_tss_tss2_names.h" ! 19: ! 20: #ifdef TSS_TSS2_V2 ! 21: ! 22: #include <asn1/asn1.h> ! 23: #include <asn1/oid.h> ! 24: #include <bio/bio_reader.h> ! 25: #include <threading/mutex.h> ! 26: ! 27: #include <tss2/tss2_sys.h> ! 28: ! 29: #include <dlfcn.h> ! 30: #include <sys/types.h> ! 31: #include <sys/stat.h> ! 32: #include <unistd.h> ! 33: ! 34: #define LABEL "TPM 2.0 -" ! 35: ! 36: #define PLATFORM_PCR 24 ! 37: ! 38: typedef struct private_tpm_tss_tss2_t private_tpm_tss_tss2_t; ! 39: ! 40: /** ! 41: * Private data of an tpm_tss_tss2_t object. ! 42: */ ! 43: struct private_tpm_tss_tss2_t { ! 44: ! 45: /** ! 46: * Public tpm_tss_tss2_t interface. ! 47: */ ! 48: tpm_tss_t public; ! 49: ! 50: /** ! 51: * TCTI context ! 52: */ ! 53: TSS2_TCTI_CONTEXT *tcti_context; ! 54: ! 55: /** ! 56: * SYS context ! 57: */ ! 58: TSS2_SYS_CONTEXT *sys_context; ! 59: ! 60: /** ! 61: * Number of supported algorithms ! 62: */ ! 63: size_t supported_algs_count; ! 64: ! 65: /** ! 66: * List of supported algorithms ! 67: */ ! 68: TPM2_ALG_ID supported_algs[TPM2_PT_ALGORITHM_SET]; ! 69: ! 70: /** ! 71: * Is TPM FIPS 186-4 compliant ? ! 72: */ ! 73: bool fips_186_4; ! 74: ! 75: /** ! 76: * Mutex controlling access to the TPM 2.0 context ! 77: */ ! 78: mutex_t *mutex; ! 79: ! 80: }; ! 81: ! 82: /** ! 83: * Global TCTI dynamic library handle and init function ! 84: */ ! 85: static void *tcti_handle; ! 86: ! 87: static TSS2_TCTI_INIT_FUNC tcti_init; ! 88: ! 89: static char *tcti_opts; ! 90: ! 91: /** ! 92: * Empty AUTH_COMMAND ! 93: */ ! 94: static const TPMS_AUTH_COMMAND auth_cmd_empty; ! 95: ! 96: /** ! 97: * Convert hash algorithm to TPM2_ALG_ID ! 98: */ ! 99: static TPM2_ALG_ID hash_alg_to_tpm_alg_id(hash_algorithm_t alg) ! 100: { ! 101: switch (alg) ! 102: { ! 103: case HASH_SHA1: ! 104: return TPM2_ALG_SHA1; ! 105: case HASH_SHA256: ! 106: return TPM2_ALG_SHA256; ! 107: case HASH_SHA384: ! 108: return TPM2_ALG_SHA384; ! 109: case HASH_SHA512: ! 110: return TPM2_ALG_SHA512; ! 111: default: ! 112: return TPM2_ALG_ERROR; ! 113: } ! 114: } ! 115: ! 116: /** ! 117: * Convert TPM2_ALG_ID to hash algorithm ! 118: */ ! 119: static hash_algorithm_t hash_alg_from_tpm_alg_id(TPM2_ALG_ID alg) ! 120: { ! 121: switch (alg) ! 122: { ! 123: case TPM2_ALG_SHA1: ! 124: return HASH_SHA1; ! 125: case TPM2_ALG_SHA256: ! 126: return HASH_SHA256; ! 127: case TPM2_ALG_SHA384: ! 128: return HASH_SHA384; ! 129: case TPM2_ALG_SHA512: ! 130: return HASH_SHA512; ! 131: default: ! 132: return HASH_UNKNOWN; ! 133: } ! 134: } ! 135: ! 136: /** ! 137: * Check if an algorithm given by its TPM2_ALG_ID is supported by the TPM ! 138: */ ! 139: static bool is_supported_alg(private_tpm_tss_tss2_t *this, TPM2_ALG_ID alg_id) ! 140: { ! 141: int i; ! 142: ! 143: if (alg_id == TPM2_ALG_ERROR) ! 144: { ! 145: return FALSE; ! 146: } ! 147: ! 148: for (i = 0; i < this->supported_algs_count; i++) ! 149: { ! 150: if (this->supported_algs[i] == alg_id) ! 151: { ! 152: return TRUE; ! 153: } ! 154: } ! 155: ! 156: return FALSE; ! 157: } ! 158: ! 159: /** ! 160: * Get a list of supported algorithms ! 161: */ ! 162: static bool get_algs_capability(private_tpm_tss_tss2_t *this) ! 163: { ! 164: TPMS_CAPABILITY_DATA cap_data; ! 165: TPMS_TAGGED_PROPERTY tp; ! 166: TPMI_YES_NO more_data; ! 167: TPM2_ALG_ID alg; ! 168: bool fips_140_2 = FALSE; ! 169: uint32_t rval, i, offset, revision = 0, year = 0; ! 170: size_t len = BUF_LEN; ! 171: char buf[BUF_LEN], manufacturer[5], vendor_string[17]; ! 172: char *pos = buf; ! 173: int written; ! 174: ! 175: /* get fixed properties */ ! 176: this->mutex->lock(this->mutex); ! 177: rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM2_CAP_TPM_PROPERTIES, ! 178: TPM2_PT_FIXED, TPM2_MAX_TPM_PROPERTIES, ! 179: &more_data, &cap_data, 0); ! 180: this->mutex->unlock(this->mutex); ! 181: if (rval != TPM2_RC_SUCCESS) ! 182: { ! 183: DBG1(DBG_PTS, "%s GetCapability failed for TPM2_CAP_TPM_PROPERTIES: 0x%06x", ! 184: LABEL, rval); ! 185: return FALSE; ! 186: } ! 187: memset(manufacturer, '\0', sizeof(manufacturer)); ! 188: memset(vendor_string, '\0', sizeof(vendor_string)); ! 189: ! 190: /* print fixed properties */ ! 191: for (i = 0; i < cap_data.data.tpmProperties.count; i++) ! 192: { ! 193: tp = cap_data.data.tpmProperties.tpmProperty[i]; ! 194: switch (tp.property) ! 195: { ! 196: case TPM2_PT_REVISION: ! 197: revision = tp.value; ! 198: break; ! 199: case TPM2_PT_YEAR: ! 200: year = tp.value; ! 201: break; ! 202: case TPM2_PT_MANUFACTURER: ! 203: htoun32(manufacturer, tp.value); ! 204: break; ! 205: case TPM2_PT_VENDOR_STRING_1: ! 206: case TPM2_PT_VENDOR_STRING_2: ! 207: case TPM2_PT_VENDOR_STRING_3: ! 208: case TPM2_PT_VENDOR_STRING_4: ! 209: offset = 4 * (tp.property - TPM2_PT_VENDOR_STRING_1); ! 210: htoun32(vendor_string + offset, tp.value); ! 211: break; ! 212: case TPM2_PT_MODES: ! 213: if (tp.value & TPMA_MODES_FIPS_140_2) ! 214: { ! 215: this->fips_186_4 = fips_140_2 = TRUE; ! 216: } ! 217: break; ! 218: default: ! 219: break; ! 220: } ! 221: } ! 222: ! 223: if (!fips_140_2) ! 224: { ! 225: this->fips_186_4 = lib->settings->get_bool(lib->settings, ! 226: "%s.plugins.tpm.fips_186_4", FALSE, lib->ns); ! 227: } ! 228: DBG2(DBG_PTS, "%s manufacturer: %s (%s) rev: %05.2f %u %s", LABEL, ! 229: manufacturer, vendor_string, (float)revision/100, year, ! 230: fips_140_2 ? "FIPS 140-2" : (this->fips_186_4 ? "FIPS 186-4" : "")); ! 231: ! 232: /* get supported algorithms */ ! 233: this->mutex->lock(this->mutex); ! 234: rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM2_CAP_ALGS, ! 235: 0, TPM2_PT_ALGORITHM_SET, &more_data, &cap_data, 0); ! 236: this->mutex->unlock(this->mutex); ! 237: if (rval != TPM2_RC_SUCCESS) ! 238: { ! 239: DBG1(DBG_PTS, "%s GetCapability failed for TPM2_CAP_ALGS: 0x%06x", ! 240: LABEL, rval); ! 241: return FALSE; ! 242: } ! 243: ! 244: /* Number of supported algorithms */ ! 245: this->supported_algs_count = cap_data.data.algorithms.count; ! 246: ! 247: /* store and print supported algorithms */ ! 248: for (i = 0; i < this->supported_algs_count; i++) ! 249: { ! 250: alg = cap_data.data.algorithms.algProperties[i].alg; ! 251: this->supported_algs[i] = alg; ! 252: ! 253: written = snprintf(pos, len, " %N", tpm_alg_id_names, alg); ! 254: if (written < 0 || written >= len) ! 255: { ! 256: break; ! 257: } ! 258: pos += written; ! 259: len -= written; ! 260: } ! 261: DBG2(DBG_PTS, "%s algorithms:%s", LABEL, buf); ! 262: ! 263: /* get supported ECC curves */ ! 264: this->mutex->lock(this->mutex); ! 265: rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM2_CAP_ECC_CURVES, ! 266: 0, TPM2_PT_LOADED_CURVES, &more_data, &cap_data, 0); ! 267: this->mutex->unlock(this->mutex); ! 268: if (rval != TPM2_RC_SUCCESS) ! 269: { ! 270: DBG1(DBG_PTS, "%s GetCapability failed for TPM2_ECC_CURVES: 0x%06x", ! 271: LABEL, rval); ! 272: return FALSE; ! 273: } ! 274: ! 275: /* reset print buffer */ ! 276: pos = buf; ! 277: len = BUF_LEN; ! 278: ! 279: /* print supported ECC curves */ ! 280: for (i = 0; i < cap_data.data.eccCurves.count; i++) ! 281: { ! 282: written = snprintf(pos, len, " %N", tpm_ecc_curve_names, ! 283: cap_data.data.eccCurves.eccCurves[i]); ! 284: if (written < 0 || written >= len) ! 285: { ! 286: break; ! 287: } ! 288: pos += written; ! 289: len -= written; ! 290: } ! 291: DBG2(DBG_PTS, "%s ECC curves:%s", LABEL, buf); ! 292: ! 293: return TRUE; ! 294: } ! 295: ! 296: /** ! 297: * Initialize TSS2 TCTI context ! 298: */ ! 299: static bool initialize_tcti_context(private_tpm_tss_tss2_t *this) ! 300: { ! 301: size_t tcti_context_size; ! 302: uint32_t rval; ! 303: ! 304: if (!tcti_init) ! 305: { ! 306: return FALSE; ! 307: } ! 308: ! 309: /* determine size of tcti context */ ! 310: rval = tcti_init(NULL, &tcti_context_size, tcti_opts); ! 311: if (rval != TSS2_RC_SUCCESS) ! 312: { ! 313: DBG1(DBG_PTS, "%s tcti init setup failed: 0x%06x", LABEL, rval); ! 314: return FALSE; ! 315: } ! 316: ! 317: /* allocate and initialize memory for tcti context */ ! 318: this->tcti_context = (TSS2_TCTI_CONTEXT*)malloc(tcti_context_size); ! 319: memset(this->tcti_context, 0x00, tcti_context_size); ! 320: ! 321: /* initialize tcti context */ ! 322: rval = tcti_init(this->tcti_context, &tcti_context_size, tcti_opts); ! 323: if (rval != TSS2_RC_SUCCESS) ! 324: { ! 325: DBG1(DBG_PTS, "%s tcti init allocation failed: 0x%06x", LABEL,rval); ! 326: return FALSE; ! 327: } ! 328: return TRUE; ! 329: } ! 330: ! 331: /** ! 332: * Initialize TSS2 Sys context ! 333: */ ! 334: static bool initialize_sys_context(private_tpm_tss_tss2_t *this) ! 335: { ! 336: uint32_t sys_context_size; ! 337: uint32_t rval; ! 338: ! 339: TSS2_ABI_VERSION abi_version = { ! 340: .tssCreator = 1, ! 341: .tssFamily = 2, ! 342: .tssLevel = 1, ! 343: .tssVersion = 108 ! 344: }; ! 345: ! 346: /* determine size of sys context */ ! 347: sys_context_size = Tss2_Sys_GetContextSize(0); ! 348: ! 349: /* allocate memory for sys context */ ! 350: this->sys_context = (TSS2_SYS_CONTEXT*)malloc(sys_context_size); ! 351: ! 352: /* initialize sys context */ ! 353: rval = Tss2_Sys_Initialize(this->sys_context, sys_context_size, ! 354: this->tcti_context, &abi_version); ! 355: if (rval != TSS2_RC_SUCCESS) ! 356: { ! 357: DBG1(DBG_PTS, "%s could not get sys_context: 0x%06x", ! 358: LABEL, rval); ! 359: return FALSE; ! 360: } ! 361: ! 362: /* get a list of supported algorithms and ECC curves */ ! 363: return get_algs_capability(this); ! 364: } ! 365: ! 366: /** ! 367: * Finalize TSS context ! 368: */ ! 369: static void finalize_context(private_tpm_tss_tss2_t *this) ! 370: { ! 371: if (this->tcti_context) ! 372: { ! 373: Tss2_Tcti_Finalize(this->tcti_context); ! 374: free(this->tcti_context); ! 375: } ! 376: if (this->sys_context) ! 377: { ! 378: Tss2_Sys_Finalize(this->sys_context); ! 379: free(this->sys_context); ! 380: } ! 381: } ! 382: ! 383: METHOD(tpm_tss_t, get_version, tpm_version_t, ! 384: private_tpm_tss_tss2_t *this) ! 385: { ! 386: return TPM_VERSION_2_0; ! 387: } ! 388: ! 389: METHOD(tpm_tss_t, get_version_info, chunk_t, ! 390: private_tpm_tss_tss2_t *this) ! 391: { ! 392: return chunk_empty; ! 393: } ! 394: ! 395: /** ! 396: * read the public key portion of a TSS 2.0 key from NVRAM ! 397: */ ! 398: bool read_public(private_tpm_tss_tss2_t *this, TPMI_DH_OBJECT handle, ! 399: TPM2B_PUBLIC *public) ! 400: { ! 401: uint32_t rval; ! 402: ! 403: TPM2B_NAME name = { sizeof(TPM2B_NAME)-2, }; ! 404: TPM2B_NAME qualified_name = { sizeof(TPM2B_NAME)-2, }; ! 405: TSS2L_SYS_AUTH_RESPONSE auth_rsp; ! 406: ! 407: ! 408: /* read public key for a given object handle from TPM 2.0 NVRAM */ ! 409: this->mutex->lock(this->mutex); ! 410: rval = Tss2_Sys_ReadPublic(this->sys_context, handle, 0, public, &name, ! 411: &qualified_name, &auth_rsp); ! 412: this->mutex->unlock(this->mutex); ! 413: if (rval != TPM2_RC_SUCCESS) ! 414: { ! 415: DBG1(DBG_PTS, "%s could not read public key from handle 0x%08x: 0x%06x", ! 416: LABEL, handle, rval); ! 417: return FALSE; ! 418: } ! 419: return TRUE; ! 420: } ! 421: ! 422: METHOD(tpm_tss_t, generate_aik, bool, ! 423: private_tpm_tss_tss2_t *this, chunk_t ca_modulus, chunk_t *aik_blob, ! 424: chunk_t *aik_pubkey, chunk_t *identity_req) ! 425: { ! 426: return FALSE; ! 427: } ! 428: ! 429: METHOD(tpm_tss_t, get_public, chunk_t, ! 430: private_tpm_tss_tss2_t *this, uint32_t handle) ! 431: { ! 432: TPM2B_PUBLIC public = { 0, }; ! 433: TPM2_ALG_ID sig_alg, digest_alg; ! 434: chunk_t aik_blob, aik_pubkey = chunk_empty; ! 435: ! 436: if (!read_public(this, handle, &public)) ! 437: { ! 438: return chunk_empty; ! 439: } ! 440: ! 441: aik_blob = chunk_create((u_char*)&public, sizeof(public)); ! 442: DBG3(DBG_LIB, "%s public key blob: %B", LABEL, &aik_blob); ! 443: ! 444: /* convert TSS 2.0 public key blot into PKCS#1 format */ ! 445: switch (public.publicArea.type) ! 446: { ! 447: case TPM2_ALG_RSA: ! 448: { ! 449: TPM2B_PUBLIC_KEY_RSA *rsa; ! 450: TPMT_RSA_SCHEME *scheme; ! 451: chunk_t aik_exponent = chunk_from_chars(0x01, 0x00, 0x01); ! 452: chunk_t aik_modulus; ! 453: uint32_t exponent; ! 454: ! 455: scheme = &public.publicArea.parameters.rsaDetail.scheme; ! 456: sig_alg = scheme->scheme; ! 457: digest_alg = scheme->details.anySig.hashAlg; ! 458: ! 459: rsa = &public.publicArea.unique.rsa; ! 460: aik_modulus = chunk_create(rsa->buffer, rsa->size); ! 461: exponent = htonl(public.publicArea.parameters.rsaDetail.exponent); ! 462: if (exponent) ! 463: { ! 464: aik_exponent = chunk_from_thing(exponent); ! 465: } ! 466: ! 467: /* subjectPublicKeyInfo encoding of RSA public key */ ! 468: if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER, ! 469: NULL, &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus, ! 470: CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END)) ! 471: { ! 472: DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of public key " ! 473: "failed", LABEL); ! 474: return chunk_empty; ! 475: } ! 476: break; ! 477: } ! 478: case TPM2_ALG_ECC: ! 479: { ! 480: TPMS_ECC_POINT *ecc; ! 481: TPMT_ECC_SCHEME *scheme; ! 482: chunk_t ecc_point; ! 483: uint8_t *pos; ! 484: ! 485: scheme = &public.publicArea.parameters.eccDetail.scheme; ! 486: sig_alg = scheme->scheme; ! 487: digest_alg = scheme->details.anySig.hashAlg; ! 488: ! 489: ecc = &public.publicArea.unique.ecc; ! 490: ! 491: /* allocate space for bit string */ ! 492: pos = asn1_build_object(&ecc_point, ASN1_BIT_STRING, ! 493: 2 + ecc->x.size + ecc->y.size); ! 494: /* bit string length is a multiple of octets */ ! 495: *pos++ = 0x00; ! 496: /* uncompressed ECC point format */ ! 497: *pos++ = 0x04; ! 498: /* copy x coordinate of ECC point */ ! 499: memcpy(pos, ecc->x.buffer, ecc->x.size); ! 500: pos += ecc->x.size; ! 501: /* copy y coordinate of ECC point */ ! 502: memcpy(pos, ecc->y.buffer, ecc->y.size); ! 503: /* subjectPublicKeyInfo encoding of ECC public key */ ! 504: aik_pubkey = asn1_wrap(ASN1_SEQUENCE, "mm", ! 505: asn1_wrap(ASN1_SEQUENCE, "mm", ! 506: asn1_build_known_oid(OID_EC_PUBLICKEY), ! 507: asn1_build_known_oid(ecc->x.size == 32 ? ! 508: OID_PRIME256V1 : OID_SECT384R1)), ! 509: ecc_point); ! 510: break; ! 511: } ! 512: default: ! 513: DBG1(DBG_PTS, "%s unsupported key type", LABEL); ! 514: return chunk_empty; ! 515: } ! 516: DBG1(DBG_PTS, "signature algorithm is %N with %N hash", ! 517: tpm_alg_id_names, sig_alg, tpm_alg_id_names, digest_alg); ! 518: return aik_pubkey; ! 519: } ! 520: ! 521: METHOD(tpm_tss_t, supported_signature_schemes, enumerator_t*, ! 522: private_tpm_tss_tss2_t *this, uint32_t handle) ! 523: { ! 524: TPM2B_PUBLIC public = { 0, }; ! 525: hash_algorithm_t digest; ! 526: signature_params_t supported_scheme; ! 527: ! 528: if (!read_public(this, handle, &public)) ! 529: { ! 530: return enumerator_create_empty(); ! 531: } ! 532: ! 533: switch (public.publicArea.type) ! 534: { ! 535: case TPM2_ALG_RSA: ! 536: { ! 537: TPMS_RSA_PARMS *rsa; ! 538: TPMT_RSA_SCHEME *scheme; ! 539: ! 540: rsa = &public.publicArea.parameters.rsaDetail; ! 541: scheme = &rsa->scheme; ! 542: digest = hash_alg_from_tpm_alg_id(scheme->details.anySig.hashAlg); ! 543: ! 544: switch (scheme->scheme) ! 545: { ! 546: case TPM2_ALG_RSAPSS: ! 547: { ! 548: ssize_t salt_len; ! 549: ! 550: salt_len = this->fips_186_4 ? RSA_PSS_SALT_LEN_DEFAULT : ! 551: RSA_PSS_SALT_LEN_MAX; ! 552: rsa_pss_params_t pss_params = { ! 553: .hash = digest, ! 554: .mgf1_hash = digest, ! 555: .salt_len = salt_len, ! 556: }; ! 557: supported_scheme = (signature_params_t){ ! 558: .scheme = SIGN_RSA_EMSA_PSS, ! 559: .params = &pss_params, ! 560: }; ! 561: if (!rsa_pss_params_set_salt_len(&pss_params, rsa->keyBits)) ! 562: { ! 563: return enumerator_create_empty(); ! 564: } ! 565: break; ! 566: } ! 567: case TPM2_ALG_RSASSA: ! 568: supported_scheme = (signature_params_t){ ! 569: .scheme = signature_scheme_from_oid( ! 570: hasher_signature_algorithm_to_oid(digest, ! 571: KEY_RSA)), ! 572: }; ! 573: break; ! 574: default: ! 575: return enumerator_create_empty(); ! 576: } ! 577: break; ! 578: } ! 579: case TPM2_ALG_ECC: ! 580: { ! 581: TPMT_ECC_SCHEME *scheme; ! 582: ! 583: scheme = &public.publicArea.parameters.eccDetail.scheme; ! 584: digest = hash_alg_from_tpm_alg_id(scheme->details.anySig.hashAlg); ! 585: ! 586: switch (scheme->scheme) ! 587: { ! 588: case TPM2_ALG_ECDSA: ! 589: supported_scheme = (signature_params_t){ ! 590: .scheme = signature_scheme_from_oid( ! 591: hasher_signature_algorithm_to_oid(digest, ! 592: KEY_ECDSA)), ! 593: }; ! 594: break; ! 595: default: ! 596: return enumerator_create_empty(); ! 597: } ! 598: break; ! 599: } ! 600: default: ! 601: DBG1(DBG_PTS, "%s unsupported key type", LABEL); ! 602: return enumerator_create_empty(); ! 603: } ! 604: return enumerator_create_single(signature_params_clone(&supported_scheme), ! 605: (void*)signature_params_destroy); ! 606: } ! 607: ! 608: /** ! 609: * Configure a PCR Selection assuming a maximum of 24 registers ! 610: */ ! 611: static bool init_pcr_selection(private_tpm_tss_tss2_t *this, uint32_t pcrs, ! 612: hash_algorithm_t alg, TPML_PCR_SELECTION *pcr_sel) ! 613: { ! 614: TPM2_ALG_ID alg_id; ! 615: uint32_t pcr; ! 616: ! 617: /* check if hash algorithm is supported by TPM */ ! 618: alg_id = hash_alg_to_tpm_alg_id(alg); ! 619: if (!is_supported_alg(this, alg_id)) ! 620: { ! 621: DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM", ! 622: LABEL, hash_algorithm_short_names, alg); ! 623: return FALSE; ! 624: } ! 625: ! 626: /* initialize the PCR Selection structure,*/ ! 627: pcr_sel->count = 1; ! 628: pcr_sel->pcrSelections[0].hash = alg_id; ! 629: pcr_sel->pcrSelections[0].sizeofSelect = 3; ! 630: pcr_sel->pcrSelections[0].pcrSelect[0] = 0; ! 631: pcr_sel->pcrSelections[0].pcrSelect[1] = 0; ! 632: pcr_sel->pcrSelections[0].pcrSelect[2] = 0; ! 633: ! 634: /* set the selected PCRs */ ! 635: for (pcr = 0; pcr < PLATFORM_PCR; pcr++) ! 636: { ! 637: if (pcrs & (1 << pcr)) ! 638: { ! 639: pcr_sel->pcrSelections[0].pcrSelect[pcr / 8] |= ( 1 << (pcr % 8) ); ! 640: } ! 641: } ! 642: return TRUE; ! 643: } ! 644: ! 645: METHOD(tpm_tss_t, read_pcr, bool, ! 646: private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value, ! 647: hash_algorithm_t alg) ! 648: { ! 649: TPML_PCR_SELECTION pcr_selection; ! 650: TPML_DIGEST pcr_values; ! 651: ! 652: uint32_t pcr_update_counter, rval; ! 653: uint8_t *pcr_value_ptr; ! 654: size_t pcr_value_len; ! 655: ! 656: if (pcr_num >= PLATFORM_PCR) ! 657: { ! 658: DBG1(DBG_PTS, "%s maximum number of supported PCR is %d", ! 659: LABEL, PLATFORM_PCR); ! 660: return FALSE; ! 661: } ! 662: ! 663: if (!init_pcr_selection(this, (1 << pcr_num), alg, &pcr_selection)) ! 664: { ! 665: return FALSE; ! 666: } ! 667: ! 668: /* initialize the PCR Digest structure */ ! 669: memset(&pcr_values, 0, sizeof(TPML_DIGEST)); ! 670: ! 671: /* read the PCR value */ ! 672: this->mutex->lock(this->mutex); ! 673: rval = Tss2_Sys_PCR_Read(this->sys_context, 0, &pcr_selection, ! 674: &pcr_update_counter, &pcr_selection, &pcr_values, 0); ! 675: this->mutex->unlock(this->mutex); ! 676: if (rval != TPM2_RC_SUCCESS) ! 677: { ! 678: DBG1(DBG_PTS, "%s PCR bank could not be read: 0x%60x", ! 679: LABEL, rval); ! 680: return FALSE; ! 681: } ! 682: pcr_value_ptr = (uint8_t *)pcr_values.digests[0].buffer; ! 683: pcr_value_len = (size_t) pcr_values.digests[0].size; ! 684: ! 685: *pcr_value = chunk_clone(chunk_create(pcr_value_ptr, pcr_value_len)); ! 686: ! 687: return TRUE; ! 688: } ! 689: ! 690: METHOD(tpm_tss_t, extend_pcr, bool, ! 691: private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value, ! 692: chunk_t data, hash_algorithm_t alg) ! 693: { ! 694: uint32_t rval; ! 695: TPM2_ALG_ID alg_id; ! 696: TPML_DIGEST_VALUES digest_values; ! 697: TSS2L_SYS_AUTH_COMMAND auth_cmd = { 1, { auth_cmd_empty } }; ! 698: TSS2L_SYS_AUTH_RESPONSE auth_rsp; ! 699: ! 700: auth_cmd.auths[0].sessionHandle = TPM2_RS_PW; ! 701: ! 702: /* check if hash algorithm is supported by TPM */ ! 703: alg_id = hash_alg_to_tpm_alg_id(alg); ! 704: if (!is_supported_alg(this, alg_id)) ! 705: { ! 706: DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM", ! 707: LABEL, hash_algorithm_short_names, alg); ! 708: return FALSE; ! 709: } ! 710: ! 711: digest_values.count = 1; ! 712: digest_values.digests[0].hashAlg = alg_id; ! 713: ! 714: switch (alg) ! 715: { ! 716: case HASH_SHA1: ! 717: if (data.len != HASH_SIZE_SHA1) ! 718: { ! 719: return FALSE; ! 720: } ! 721: memcpy(digest_values.digests[0].digest.sha1, data.ptr, ! 722: HASH_SIZE_SHA1); ! 723: break; ! 724: case HASH_SHA256: ! 725: if (data.len != HASH_SIZE_SHA256) ! 726: { ! 727: return FALSE; ! 728: } ! 729: memcpy(digest_values.digests[0].digest.sha256, data.ptr, ! 730: HASH_SIZE_SHA256); ! 731: break; ! 732: case HASH_SHA384: ! 733: if (data.len != HASH_SIZE_SHA384) ! 734: { ! 735: return FALSE; ! 736: } ! 737: memcpy(digest_values.digests[0].digest.sha384, data.ptr, ! 738: HASH_SIZE_SHA384); ! 739: break; ! 740: case HASH_SHA512: ! 741: if (data.len != HASH_SIZE_SHA512) ! 742: { ! 743: return FALSE; ! 744: } ! 745: memcpy(digest_values.digests[0].digest.sha512, data.ptr, ! 746: HASH_SIZE_SHA512); ! 747: break; ! 748: default: ! 749: return FALSE; ! 750: } ! 751: ! 752: /* extend PCR */ ! 753: this->mutex->lock(this->mutex); ! 754: rval = Tss2_Sys_PCR_Extend(this->sys_context, pcr_num, &auth_cmd, ! 755: &digest_values, &auth_rsp); ! 756: this->mutex->unlock(this->mutex); ! 757: if (rval != TPM2_RC_SUCCESS) ! 758: { ! 759: DBG1(DBG_PTS, "%s PCR %02u could not be extended: 0x%06x", ! 760: LABEL, pcr_num, rval); ! 761: return FALSE; ! 762: } ! 763: ! 764: /* get updated PCR value */ ! 765: return read_pcr(this, pcr_num, pcr_value, alg); ! 766: } ! 767: ! 768: METHOD(tpm_tss_t, quote, bool, ! 769: private_tpm_tss_tss2_t *this, uint32_t aik_handle, uint32_t pcr_sel, ! 770: hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t *quote_mode, ! 771: tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig) ! 772: { ! 773: chunk_t quoted_chunk, qualified_signer, extra_data, clock_info, ! 774: firmware_version, pcr_select, pcr_digest; ! 775: hash_algorithm_t pcr_digest_alg; ! 776: bio_reader_t *reader; ! 777: uint32_t rval; ! 778: ! 779: TPM2B_DATA qualifying_data; ! 780: TPML_PCR_SELECTION pcr_selection; ! 781: TPM2B_ATTEST quoted = { sizeof(TPM2B_ATTEST)-2, }; ! 782: TPMT_SIG_SCHEME scheme; ! 783: TPMT_SIGNATURE sig; ! 784: TPMI_ALG_HASH hash_alg; ! 785: TSS2L_SYS_AUTH_COMMAND auth_cmd = { 1, { auth_cmd_empty } }; ! 786: TSS2L_SYS_AUTH_RESPONSE auth_rsp; ! 787: ! 788: auth_cmd.auths[0].sessionHandle = TPM2_RS_PW; ! 789: ! 790: qualifying_data.size = data.len; ! 791: memcpy(qualifying_data.buffer, data.ptr, data.len); ! 792: ! 793: scheme.scheme = TPM2_ALG_NULL; ! 794: memset(&sig, 0x00, sizeof(sig)); ! 795: ! 796: /* set Quote mode */ ! 797: *quote_mode = TPM_QUOTE_TPM2; ! 798: ! 799: if (!init_pcr_selection(this, pcr_sel, alg, &pcr_selection)) ! 800: { ! 801: return FALSE; ! 802: } ! 803: ! 804: this->mutex->lock(this->mutex); ! 805: rval = Tss2_Sys_Quote(this->sys_context, aik_handle, &auth_cmd, ! 806: &qualifying_data, &scheme, &pcr_selection, "ed, ! 807: &sig, &auth_rsp); ! 808: this->mutex->unlock(this->mutex); ! 809: if (rval != TPM2_RC_SUCCESS) ! 810: { ! 811: DBG1(DBG_PTS,"%s Tss2_Sys_Quote failed: 0x%06x", LABEL, rval); ! 812: return FALSE; ! 813: } ! 814: quoted_chunk = chunk_create(quoted.attestationData, quoted.size); ! 815: ! 816: reader = bio_reader_create(chunk_skip(quoted_chunk, 6)); ! 817: if (!reader->read_data16(reader, &qualified_signer) || ! 818: !reader->read_data16(reader, &extra_data) || ! 819: !reader->read_data (reader, 17, &clock_info) || ! 820: !reader->read_data (reader, 8, &firmware_version) || ! 821: !reader->read_data (reader, 10, &pcr_select) || ! 822: !reader->read_data16(reader, &pcr_digest)) ! 823: { ! 824: DBG1(DBG_PTS, "%s parsing of quoted struct failed", LABEL); ! 825: reader->destroy(reader); ! 826: return FALSE; ! 827: } ! 828: reader->destroy(reader); ! 829: ! 830: DBG2(DBG_PTS, "PCR Composite digest: %B", &pcr_digest); ! 831: DBG2(DBG_PTS, "TPM Quote Info: %B", "ed_chunk); ! 832: DBG2(DBG_PTS, "qualifiedSigner: %B", &qualified_signer); ! 833: DBG2(DBG_PTS, "extraData: %B", &extra_data); ! 834: DBG2(DBG_PTS, "clockInfo: %B", &clock_info); ! 835: DBG2(DBG_PTS, "firmwareVersion: %B", &firmware_version); ! 836: DBG2(DBG_PTS, "pcrSelect: %B", &pcr_select); ! 837: ! 838: /* extract signature */ ! 839: switch (sig.sigAlg) ! 840: { ! 841: case TPM2_ALG_RSASSA: ! 842: case TPM2_ALG_RSAPSS: ! 843: *quote_sig = chunk_clone( ! 844: chunk_create( ! 845: sig.signature.rsassa.sig.buffer, ! 846: sig.signature.rsassa.sig.size)); ! 847: hash_alg = sig.signature.rsassa.hash; ! 848: break; ! 849: case TPM2_ALG_ECDSA: ! 850: case TPM2_ALG_ECDAA: ! 851: case TPM2_ALG_SM2: ! 852: case TPM2_ALG_ECSCHNORR: ! 853: *quote_sig = chunk_cat("cc", ! 854: chunk_create( ! 855: sig.signature.ecdsa.signatureR.buffer, ! 856: sig.signature.ecdsa.signatureR.size), ! 857: chunk_create( ! 858: sig.signature.ecdsa.signatureS.buffer, ! 859: sig.signature.ecdsa.signatureS.size)); ! 860: hash_alg = sig.signature.ecdsa.hash; ! 861: break; ! 862: default: ! 863: DBG1(DBG_PTS, "%s unsupported %N signature algorithm", ! 864: LABEL, tpm_alg_id_names, sig.sigAlg); ! 865: return FALSE; ! 866: } ! 867: ! 868: DBG2(DBG_PTS, "PCR digest algorithm is %N", tpm_alg_id_names, hash_alg); ! 869: pcr_digest_alg = hash_alg_from_tpm_alg_id(hash_alg); ! 870: ! 871: DBG2(DBG_PTS, "TPM Quote Signature: %B", quote_sig); ! 872: ! 873: /* Create and initialize Quote Info object */ ! 874: *quote_info = tpm_tss_quote_info_create(*quote_mode, pcr_digest_alg, ! 875: pcr_digest); ! 876: (*quote_info)->set_tpm2_info(*quote_info, qualified_signer, clock_info, ! 877: pcr_select); ! 878: (*quote_info)->set_version_info(*quote_info, firmware_version); ! 879: ! 880: return TRUE; ! 881: } ! 882: ! 883: METHOD(tpm_tss_t, sign, bool, ! 884: private_tpm_tss_tss2_t *this, uint32_t hierarchy, uint32_t handle, ! 885: signature_scheme_t scheme, void *params, chunk_t data, chunk_t pin, ! 886: chunk_t *signature) ! 887: { ! 888: key_type_t key_type; ! 889: hash_algorithm_t hash_alg; ! 890: rsa_pss_params_t *rsa_pss_params; ! 891: uint32_t rval; ! 892: ! 893: TPM2_ALG_ID alg_id; ! 894: TPM2B_MAX_BUFFER buffer; ! 895: TPM2B_DIGEST hash = { sizeof(TPM2B_DIGEST)-2, }; ! 896: TPMT_TK_HASHCHECK validation; ! 897: TPM2B_PUBLIC public = { 0, }; ! 898: TPMT_SIG_SCHEME sig_scheme; ! 899: TPMT_SIGNATURE sig; ! 900: TPMS_AUTH_COMMAND *cmd; ! 901: TSS2L_SYS_AUTH_COMMAND auth_cmd = { 1, { auth_cmd_empty } }; ! 902: TSS2L_SYS_AUTH_RESPONSE auth_rsp; ! 903: ! 904: cmd = &auth_cmd.auths[0]; ! 905: cmd->sessionHandle = TPM2_RS_PW; ! 906: ! 907: if (pin.len > 0) ! 908: { ! 909: cmd->hmac.size = min(sizeof(cmd->hmac)-2, pin.len); ! 910: memcpy(cmd->hmac.buffer, pin.ptr, cmd->hmac.size); ! 911: } ! 912: ! 913: if (scheme == SIGN_RSA_EMSA_PSS) ! 914: { ! 915: key_type = KEY_RSA; ! 916: rsa_pss_params = (rsa_pss_params_t *)params; ! 917: hash_alg = rsa_pss_params->hash; ! 918: } ! 919: else ! 920: { ! 921: key_type = key_type_from_signature_scheme(scheme); ! 922: hash_alg = hasher_from_signature_scheme(scheme, NULL); ! 923: } ! 924: ! 925: /* Check if hash algorithm is supported by TPM */ ! 926: alg_id = hash_alg_to_tpm_alg_id(hash_alg); ! 927: if (!is_supported_alg(this, alg_id)) ! 928: { ! 929: DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM", ! 930: LABEL, hash_algorithm_short_names, hash_alg); ! 931: return FALSE; ! 932: } ! 933: ! 934: /* Get public key */ ! 935: if (!read_public(this, handle, &public)) ! 936: { ! 937: return FALSE; ! 938: } ! 939: ! 940: if (key_type == KEY_RSA && public.publicArea.type == TPM2_ALG_RSA) ! 941: { ! 942: if (scheme == SIGN_RSA_EMSA_PSS) ! 943: { ! 944: sig_scheme.scheme = TPM2_ALG_RSAPSS; ! 945: sig_scheme.details.rsapss.hashAlg = alg_id; ! 946: } ! 947: else ! 948: { ! 949: sig_scheme.scheme = TPM2_ALG_RSASSA; ! 950: sig_scheme.details.rsassa.hashAlg = alg_id; ! 951: } ! 952: } ! 953: else if (key_type == KEY_ECDSA && public.publicArea.type == TPM2_ALG_ECC) ! 954: { ! 955: sig_scheme.scheme = TPM2_ALG_ECDSA; ! 956: sig_scheme.details.ecdsa.hashAlg = alg_id; ! 957: ! 958: } ! 959: else ! 960: { ! 961: DBG1(DBG_PTS, "%s signature scheme %N not supported by TPM key", ! 962: LABEL, signature_scheme_names, scheme); ! 963: return FALSE; ! 964: } ! 965: ! 966: if (data.len <= TPM2_MAX_DIGEST_BUFFER) ! 967: { ! 968: memcpy(buffer.buffer, data.ptr, data.len); ! 969: buffer.size = data.len; ! 970: ! 971: this->mutex->lock(this->mutex); ! 972: rval = Tss2_Sys_Hash(this->sys_context, 0, &buffer, alg_id, hierarchy, ! 973: &hash, &validation, 0); ! 974: this->mutex->unlock(this->mutex); ! 975: if (rval != TPM2_RC_SUCCESS) ! 976: { ! 977: DBG1(DBG_PTS,"%s Tss2_Sys_Hash failed: 0x%06x", LABEL, rval); ! 978: return FALSE; ! 979: } ! 980: } ! 981: else ! 982: { ! 983: TPMI_DH_OBJECT sequence_handle; ! 984: TPM2B_AUTH null_auth; ! 985: ! 986: null_auth.size = 0; ! 987: this->mutex->lock(this->mutex); ! 988: rval = Tss2_Sys_HashSequenceStart(this->sys_context, 0, &null_auth, ! 989: alg_id, &sequence_handle, 0); ! 990: if (rval != TPM2_RC_SUCCESS) ! 991: { ! 992: DBG1(DBG_PTS,"%s Tss2_Sys_HashSequenceStart failed: 0x%06x", ! 993: LABEL, rval); ! 994: this->mutex->unlock(this->mutex); ! 995: return FALSE; ! 996: } ! 997: ! 998: while (data.len > 0) ! 999: { ! 1000: buffer.size = min(data.len, TPM2_MAX_DIGEST_BUFFER); ! 1001: memcpy(buffer.buffer, data.ptr, buffer.size); ! 1002: data.ptr += buffer.size; ! 1003: data.len -= buffer.size; ! 1004: ! 1005: rval = Tss2_Sys_SequenceUpdate(this->sys_context, sequence_handle, ! 1006: &auth_cmd, &buffer, 0); ! 1007: if (rval != TPM2_RC_SUCCESS) ! 1008: { ! 1009: DBG1(DBG_PTS,"%s Tss2_Sys_SequenceUpdate failed: 0x%06x", ! 1010: LABEL, rval); ! 1011: this->mutex->unlock(this->mutex); ! 1012: return FALSE; ! 1013: } ! 1014: } ! 1015: buffer.size = 0; ! 1016: ! 1017: rval = Tss2_Sys_SequenceComplete(this->sys_context, sequence_handle, ! 1018: &auth_cmd, &buffer, hierarchy, ! 1019: &hash, &validation, 0); ! 1020: this->mutex->unlock(this->mutex); ! 1021: if (rval != TPM2_RC_SUCCESS) ! 1022: { ! 1023: DBG1(DBG_PTS,"%s Tss2_Sys_SequenceComplete failed: 0x%06x", ! 1024: LABEL, rval); ! 1025: return FALSE; ! 1026: } ! 1027: } ! 1028: ! 1029: this->mutex->lock(this->mutex); ! 1030: rval = Tss2_Sys_Sign(this->sys_context, handle, &auth_cmd, &hash, ! 1031: &sig_scheme, &validation, &sig, &auth_rsp); ! 1032: this->mutex->unlock(this->mutex); ! 1033: if (rval != TPM2_RC_SUCCESS) ! 1034: { ! 1035: DBG1(DBG_PTS,"%s Tss2_Sys_Sign failed: 0x%06x", LABEL, rval); ! 1036: return FALSE; ! 1037: } ! 1038: ! 1039: /* extract signature */ ! 1040: switch (scheme) ! 1041: { ! 1042: case SIGN_RSA_EMSA_PKCS1_SHA1: ! 1043: case SIGN_RSA_EMSA_PKCS1_SHA2_256: ! 1044: case SIGN_RSA_EMSA_PKCS1_SHA2_384: ! 1045: case SIGN_RSA_EMSA_PKCS1_SHA2_512: ! 1046: *signature = chunk_clone( ! 1047: chunk_create( ! 1048: sig.signature.rsassa.sig.buffer, ! 1049: sig.signature.rsassa.sig.size)); ! 1050: break; ! 1051: case SIGN_RSA_EMSA_PSS: ! 1052: *signature = chunk_clone( ! 1053: chunk_create( ! 1054: sig.signature.rsapss.sig.buffer, ! 1055: sig.signature.rsapss.sig.size)); ! 1056: break; ! 1057: case SIGN_ECDSA_256: ! 1058: case SIGN_ECDSA_384: ! 1059: case SIGN_ECDSA_521: ! 1060: *signature = chunk_cat("cc", ! 1061: chunk_create( ! 1062: sig.signature.ecdsa.signatureR.buffer, ! 1063: sig.signature.ecdsa.signatureR.size), ! 1064: chunk_create( ! 1065: sig.signature.ecdsa.signatureS.buffer, ! 1066: sig.signature.ecdsa.signatureS.size)); ! 1067: break; ! 1068: case SIGN_ECDSA_WITH_SHA256_DER: ! 1069: case SIGN_ECDSA_WITH_SHA384_DER: ! 1070: case SIGN_ECDSA_WITH_SHA512_DER: ! 1071: *signature = asn1_wrap(ASN1_SEQUENCE, "mm", ! 1072: asn1_integer("c", ! 1073: chunk_create( ! 1074: sig.signature.ecdsa.signatureR.buffer, ! 1075: sig.signature.ecdsa.signatureR.size)), ! 1076: asn1_integer("c", ! 1077: chunk_create( ! 1078: sig.signature.ecdsa.signatureS.buffer, ! 1079: sig.signature.ecdsa.signatureS.size))); ! 1080: break; ! 1081: default: ! 1082: DBG1(DBG_PTS, "%s unsupported %N signature scheme", ! 1083: LABEL, signature_scheme_names, scheme); ! 1084: return FALSE; ! 1085: } ! 1086: ! 1087: return TRUE; ! 1088: } ! 1089: ! 1090: METHOD(tpm_tss_t, get_random, bool, ! 1091: private_tpm_tss_tss2_t *this, size_t bytes, uint8_t *buffer) ! 1092: { ! 1093: size_t len, random_len= sizeof(TPM2B_DIGEST)-2; ! 1094: TPM2B_DIGEST random = { random_len, }; ! 1095: uint8_t *pos = buffer; ! 1096: uint32_t rval; ! 1097: ! 1098: while (bytes > 0) ! 1099: { ! 1100: len = min(bytes, random_len); ! 1101: ! 1102: this->mutex->lock(this->mutex); ! 1103: rval = Tss2_Sys_GetRandom(this->sys_context, NULL, len, &random, NULL); ! 1104: this->mutex->unlock(this->mutex); ! 1105: if (rval != TSS2_RC_SUCCESS) ! 1106: { ! 1107: DBG1(DBG_PTS,"%s Tss2_Sys_GetRandom failed: 0x%06x", LABEL, rval); ! 1108: return FALSE; ! 1109: } ! 1110: memcpy(pos, random.buffer, random.size); ! 1111: pos += random.size; ! 1112: bytes -= random.size; ! 1113: } ! 1114: ! 1115: return TRUE; ! 1116: } ! 1117: ! 1118: METHOD(tpm_tss_t, get_data, bool, ! 1119: private_tpm_tss_tss2_t *this, uint32_t hierarchy, uint32_t handle, ! 1120: chunk_t pin, chunk_t *data) ! 1121: { ! 1122: uint16_t max_data_size, nv_size, nv_offset = 0; ! 1123: uint32_t rval; ! 1124: ! 1125: TPMS_CAPABILITY_DATA cap_data; ! 1126: TPMI_YES_NO more_data; ! 1127: TPM2B_NAME nv_name = { sizeof(TPM2B_NAME)-2, }; ! 1128: TPM2B_NV_PUBLIC nv_public = { 0, }; ! 1129: TPM2B_MAX_NV_BUFFER nv_data = { TPM2_MAX_NV_BUFFER_SIZE, }; ! 1130: TPMS_AUTH_COMMAND *cmd; ! 1131: TSS2L_SYS_AUTH_COMMAND auth_cmd = { 1, { auth_cmd_empty } }; ! 1132: TSS2L_SYS_AUTH_RESPONSE auth_rsp; ! 1133: ! 1134: /* query maximum TPM data transmission size */ ! 1135: this->mutex->lock(this->mutex); ! 1136: rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM2_CAP_TPM_PROPERTIES, ! 1137: TPM2_PT_NV_BUFFER_MAX, 1, &more_data, &cap_data, 0); ! 1138: this->mutex->unlock(this->mutex); ! 1139: if (rval != TPM2_RC_SUCCESS) ! 1140: { ! 1141: DBG1(DBG_PTS,"%s Tss2_Sys_GetCapability failed for " ! 1142: "TPM2_CAP_TPM_PROPERTIES: 0x%06x", LABEL, rval); ! 1143: return FALSE; ! 1144: } ! 1145: max_data_size = min(cap_data.data.tpmProperties.tpmProperty[0].value, ! 1146: TPM2_MAX_NV_BUFFER_SIZE); ! 1147: ! 1148: /* get size of NV object */ ! 1149: this->mutex->lock(this->mutex); ! 1150: rval = Tss2_Sys_NV_ReadPublic(this->sys_context, handle, 0, &nv_public, ! 1151: &nv_name, 0); ! 1152: this->mutex->unlock(this->mutex); ! 1153: if (rval != TPM2_RC_SUCCESS) ! 1154: { ! 1155: DBG1(DBG_PTS,"%s Tss2_Sys_NV_ReadPublic failed: 0x%06x", LABEL, rval); ! 1156: return FALSE; ! 1157: } ! 1158: nv_size = nv_public.nvPublic.dataSize; ! 1159: *data = chunk_alloc(nv_size); ! 1160: ! 1161: /* prepare NV read session */ ! 1162: cmd = &auth_cmd.auths[0]; ! 1163: cmd->sessionHandle = TPM2_RS_PW; ! 1164: ! 1165: if (pin.len > 0) ! 1166: { ! 1167: cmd->hmac.size = min(sizeof(cmd->hmac)-2, pin.len); ! 1168: memcpy(cmd->hmac.buffer, pin.ptr, cmd->hmac.size); ! 1169: } ! 1170: ! 1171: /* read NV data a maximum data size block at a time */ ! 1172: while (nv_size > 0) ! 1173: { ! 1174: this->mutex->lock(this->mutex); ! 1175: rval = Tss2_Sys_NV_Read(this->sys_context, hierarchy, handle, &auth_cmd, ! 1176: min(nv_size, max_data_size), nv_offset, &nv_data, &auth_rsp); ! 1177: this->mutex->unlock(this->mutex); ! 1178: if (rval != TPM2_RC_SUCCESS) ! 1179: { ! 1180: DBG1(DBG_PTS,"%s Tss2_Sys_NV_Read failed: 0x%06x", LABEL, rval); ! 1181: chunk_free(data); ! 1182: return FALSE; ! 1183: } ! 1184: memcpy(data->ptr + nv_offset, nv_data.buffer, nv_data.size); ! 1185: nv_offset += nv_data.size; ! 1186: nv_size -= nv_data.size; ! 1187: } ! 1188: ! 1189: return TRUE; ! 1190: } ! 1191: ! 1192: METHOD(tpm_tss_t, destroy, void, ! 1193: private_tpm_tss_tss2_t *this) ! 1194: { ! 1195: finalize_context(this); ! 1196: this->mutex->destroy(this->mutex); ! 1197: free(this); ! 1198: } ! 1199: ! 1200: /** ! 1201: * See header ! 1202: */ ! 1203: tpm_tss_t *tpm_tss_tss2_create() ! 1204: { ! 1205: private_tpm_tss_tss2_t *this; ! 1206: bool available; ! 1207: ! 1208: INIT(this, ! 1209: .public = { ! 1210: .get_version = _get_version, ! 1211: .get_version_info = _get_version_info, ! 1212: .generate_aik = _generate_aik, ! 1213: .get_public = _get_public, ! 1214: .supported_signature_schemes = _supported_signature_schemes, ! 1215: .read_pcr = _read_pcr, ! 1216: .extend_pcr = _extend_pcr, ! 1217: .quote = _quote, ! 1218: .sign = _sign, ! 1219: .get_random = _get_random, ! 1220: .get_data = _get_data, ! 1221: .destroy = _destroy, ! 1222: }, ! 1223: .mutex = mutex_create(MUTEX_TYPE_DEFAULT), ! 1224: ); ! 1225: ! 1226: available = initialize_tcti_context(this); ! 1227: if (available) ! 1228: { ! 1229: available = initialize_sys_context(this); ! 1230: } ! 1231: DBG1(DBG_PTS, "TPM 2.0 via TSS2 v2 %savailable", available ? "" : "not "); ! 1232: ! 1233: if (!available) ! 1234: { ! 1235: destroy(this); ! 1236: return NULL; ! 1237: } ! 1238: return &this->public; ! 1239: } ! 1240: ! 1241: /** ! 1242: * See header ! 1243: */ ! 1244: bool tpm_tss_tss2_init(void) ! 1245: { ! 1246: TSS2_TCTI_INFO_FUNC infofn; ! 1247: const TSS2_TCTI_INFO *info; ! 1248: char tcti_lib_format[] = "libtss2-tcti-%s.so.0"; ! 1249: char tcti_lib[BUF_LEN]; ! 1250: char *tcti_names[] = { "device", "tabrmd", "mssim" }; ! 1251: char *tcti_options[] = { "/dev/tpmrm0", "", "" }; ! 1252: char *tcti_name; ! 1253: bool match = FALSE; ! 1254: struct stat st; ! 1255: int i = 0; ! 1256: ! 1257: /* check for the existence of an in-kernel TPM resource manager */ ! 1258: if (stat(tcti_options[i], &st)) ! 1259: { ! 1260: i = 1; ! 1261: } ! 1262: DBG2(DBG_PTS, "%s \"%s\" in-kernel resource manager is %spresent", ! 1263: LABEL, tcti_options[0], i ? "not " : ""); ! 1264: ! 1265: /* select a dynamic TCTI library (device, tabrmd or mssim) */ ! 1266: tcti_name = lib->settings->get_str(lib->settings, ! 1267: "%s.plugins.tpm.tcti.name", tcti_names[i], lib->ns); ! 1268: snprintf(tcti_lib, BUF_LEN, tcti_lib_format, tcti_name); ! 1269: ! 1270: for (i = 0; i < countof(tcti_names); i++) ! 1271: { ! 1272: if (streq(tcti_name, tcti_names[i])) ! 1273: { ! 1274: match = TRUE; ! 1275: break; ! 1276: } ! 1277: } ! 1278: if (!match) ! 1279: { ! 1280: DBG1(DBG_PTS, "%s \"%s\" is not a valid TCTI library name", ! 1281: LABEL, tcti_lib); ! 1282: return FALSE; ! 1283: } ! 1284: ! 1285: tcti_opts = lib->settings->get_str(lib->settings, ! 1286: "%s.plugins.tpm.tcti.opts", tcti_options[i], lib->ns); ! 1287: ! 1288: /* open the selected dynamic TCTI library */ ! 1289: tcti_handle = dlopen(tcti_lib, RTLD_LAZY); ! 1290: if (!tcti_handle) ! 1291: { ! 1292: DBG1(DBG_PTS, "%s could not load \"%s\"", LABEL, tcti_lib); ! 1293: return FALSE; ! 1294: } ! 1295: ! 1296: infofn = (TSS2_TCTI_INFO_FUNC)dlsym(tcti_handle, TSS2_TCTI_INFO_SYMBOL); ! 1297: if (!infofn) ! 1298: { ! 1299: DBG1(DBG_PTS, "%s symbol \"%s\" not found in \"%s\"", LABEL, ! 1300: TSS2_TCTI_INFO_SYMBOL, tcti_lib); ! 1301: tpm_tss_tss2_deinit(); ! 1302: ! 1303: return FALSE; ! 1304: } ! 1305: DBG2(DBG_PTS, "%s \"%s\" successfully loaded", LABEL, tcti_lib); ! 1306: info = infofn(); ! 1307: tcti_init = info->init; ! 1308: ! 1309: return TRUE; ! 1310: } ! 1311: ! 1312: /** ! 1313: * See header ! 1314: */ ! 1315: void tpm_tss_tss2_deinit(void) ! 1316: { ! 1317: dlclose(tcti_handle); ! 1318: tcti_handle = NULL; ! 1319: tcti_init = NULL; ! 1320: tcti_opts = NULL; ! 1321: } ! 1322: ! 1323: #else /* TSS_TSS2_V2 */ ! 1324: ! 1325: /** ! 1326: * See header ! 1327: */ ! 1328: bool tpm_tss_tss2_init(void) ! 1329: { ! 1330: return TRUE; ! 1331: } ! 1332: ! 1333: /** ! 1334: * See header ! 1335: */ ! 1336: void tpm_tss_tss2_deinit(void) ! 1337: { ! 1338: /* empty */ ! 1339: } ! 1340: ! 1341: #endif /* TSS_TSS2_V2 */ ! 1342: