]> git.ipfire.org Git - thirdparty/strongswan.git/blob - src/libtpmtss/tpm_tss_tss2.c
90a16c103ed86d018cce546e0c1986e594f2e165
[thirdparty/strongswan.git] / src / libtpmtss / tpm_tss_tss2.c
1 /*
2 * Copyright (C) 2016 Andreas Steffen
3 * HSR Hochschule fuer Technik Rapperswil
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License as published by the
7 * Free Software Foundation; either version 2 of the License, or (at your
8 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
9 *
10 * This program is distributed in the hope that it will be useful, but
11 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
12 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
13 * for more details.
14 */
15
16 #include "tpm_tss_tss2.h"
17 #include "tpm_tss_tss2_names.h"
18
19 #ifdef TSS_TSS2
20
21 #include <asn1/asn1.h>
22 #include <asn1/oid.h>
23 #include <bio/bio_reader.h>
24
25 #include <tpm20.h>
26
27 #ifdef TSS2_TCTI_TABRMD
28 #include <tcti/tcti-tabrmd.h>
29 #endif /* TSS2_TCTI_TABRMD */
30
31 #ifdef TSS2_TCTI_SOCKET
32 #include <tcti_socket.h>
33
34 #define TCTI_SOCKET_DEFAULT_ADDRESS "127.0.0.1"
35 #define TCTI_SOCKET_DEFAULT_PORT 2323
36 #endif /* TSS2_TCTI_SOCKET */
37
38 #define LABEL "TPM 2.0 -"
39
40 typedef struct private_tpm_tss_tss2_t private_tpm_tss_tss2_t;
41
42 /**
43 * Private data of an tpm_tss_tss2_t object.
44 */
45 struct private_tpm_tss_tss2_t {
46
47 /**
48 * Public tpm_tss_tss2_t interface.
49 */
50 tpm_tss_t public;
51
52 /**
53 * TCTI context
54 */
55 TSS2_TCTI_CONTEXT *tcti_context;
56
57 /**
58 * SYS context
59 */
60 TSS2_SYS_CONTEXT *sys_context;
61
62 /**
63 * Number of supported algorithms
64 */
65 size_t supported_algs_count;
66
67 /**
68 * List of supported algorithms
69 */
70 TPM_ALG_ID supported_algs[TPM_PT_ALGORITHM_SET];
71 };
72
73 /**
74 * Some symbols required by libtctisocket
75 */
76 FILE *outFp;
77 uint8_t simulator = 1;
78
79 int TpmClientPrintf (uint8_t type, const char *format, ...)
80 {
81 return 0;
82 }
83
84 /**
85 * Convert hash algorithm to TPM_ALG_ID
86 */
87 static TPM_ALG_ID hash_alg_to_tpm_alg_id(hash_algorithm_t alg)
88 {
89 switch (alg)
90 {
91 case HASH_SHA1:
92 return TPM_ALG_SHA1;
93 case HASH_SHA256:
94 return TPM_ALG_SHA256;
95 case HASH_SHA384:
96 return TPM_ALG_SHA384;
97 case HASH_SHA512:
98 return TPM_ALG_SHA512;
99 default:
100 return TPM_ALG_ERROR;
101 }
102 }
103
104 /**
105 * Convert TPM_ALG_ID to hash algorithm
106 */
107 static hash_algorithm_t hash_alg_from_tpm_alg_id(TPM_ALG_ID alg)
108 {
109 switch (alg)
110 {
111 case TPM_ALG_SHA1:
112 return HASH_SHA1;
113 case TPM_ALG_SHA256:
114 return HASH_SHA256;
115 case TPM_ALG_SHA384:
116 return HASH_SHA384;
117 case TPM_ALG_SHA512:
118 return HASH_SHA512;
119 default:
120 return HASH_UNKNOWN;
121 }
122 }
123
124 /**
125 * Check if an algorithm given by its TPM_ALG_ID is supported by the TPM
126 */
127 static bool is_supported_alg(private_tpm_tss_tss2_t *this, TPM_ALG_ID alg_id)
128 {
129 int i;
130
131 if (alg_id == TPM_ALG_ERROR)
132 {
133 return FALSE;
134 }
135
136 for (i = 0; i < this->supported_algs_count; i++)
137 {
138 if (this->supported_algs[i] == alg_id)
139 {
140 return TRUE;
141 }
142 }
143
144 return FALSE;
145 }
146
147 /**
148 * Get a list of supported algorithms
149 */
150 static bool get_algs_capability(private_tpm_tss_tss2_t *this)
151 {
152 TPMS_CAPABILITY_DATA cap_data;
153 TPMS_TAGGED_PROPERTY tp;
154 TPMI_YES_NO more_data;
155 TPM_ALG_ID alg;
156 uint32_t rval, i, offset, revision = 0, year = 0;
157 size_t len = BUF_LEN;
158 char buf[BUF_LEN], manufacturer[5], vendor_string[17];
159 char *pos = buf;
160 int written;
161
162 /* get fixed properties */
163 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_TPM_PROPERTIES,
164 PT_FIXED, MAX_TPM_PROPERTIES, &more_data, &cap_data, 0);
165 if (rval != TPM_RC_SUCCESS)
166 {
167 DBG1(DBG_PTS, "%s GetCapability failed for TPM_CAP_TPM_PROPERTIES: 0x%06x",
168 LABEL, rval);
169 return FALSE;
170 }
171 memset(manufacturer, '\0', sizeof(manufacturer));
172 memset(vendor_string, '\0', sizeof(vendor_string));
173
174 /* print fixed properties */
175 for (i = 0; i < cap_data.data.tpmProperties.count; i++)
176 {
177 tp = cap_data.data.tpmProperties.tpmProperty[i];
178 switch (tp.property)
179 {
180 case TPM_PT_REVISION:
181 revision = tp.value;
182 break;
183 case TPM_PT_YEAR:
184 year = tp.value;
185 break;
186 case TPM_PT_MANUFACTURER:
187 htoun32(manufacturer, tp.value);
188 break;
189 case TPM_PT_VENDOR_STRING_1:
190 case TPM_PT_VENDOR_STRING_2:
191 case TPM_PT_VENDOR_STRING_3:
192 case TPM_PT_VENDOR_STRING_4:
193 offset = 4 * (tp.property - TPM_PT_VENDOR_STRING_1);
194 htoun32(vendor_string + offset, tp.value);
195 break;
196 default:
197 break;
198 }
199 }
200 DBG2(DBG_PTS, "%s manufacturer: %s (%s) rev: %05.2f %u", LABEL, manufacturer,
201 vendor_string, (float)revision/100, year);
202
203 /* get supported algorithms */
204 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ALGS,
205 0, TPM_PT_ALGORITHM_SET, &more_data, &cap_data, 0);
206 if (rval != TPM_RC_SUCCESS)
207 {
208 DBG1(DBG_PTS, "%s GetCapability failed for TPM_CAP_ALGS: 0x%06x",
209 LABEL, rval);
210 return FALSE;
211 }
212
213 /* Number of supported algorithms */
214 this->supported_algs_count = cap_data.data.algorithms.count;
215
216 /* store and print supported algorithms */
217 for (i = 0; i < this->supported_algs_count; i++)
218 {
219 alg = cap_data.data.algorithms.algProperties[i].alg;
220 this->supported_algs[i] = alg;
221
222 written = snprintf(pos, len, " %N", tpm_alg_id_names, alg);
223 if (written < 0 || written >= len)
224 {
225 break;
226 }
227 pos += written;
228 len -= written;
229 }
230 DBG2(DBG_PTS, "%s algorithms:%s", LABEL, buf);
231
232 /* get supported ECC curves */
233 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ECC_CURVES,
234 0, TPM_PT_LOADED_CURVES, &more_data, &cap_data, 0);
235 if (rval != TPM_RC_SUCCESS)
236 {
237 DBG1(DBG_PTS, "%s GetCapability failed for TPM_ECC_CURVES: 0x%06x",
238 LABEL, rval);
239 return FALSE;
240 }
241
242 /* reset print buffer */
243 pos = buf;
244 len = BUF_LEN;
245
246 /* print supported ECC curves */
247 for (i = 0; i < cap_data.data.eccCurves.count; i++)
248 {
249 written = snprintf(pos, len, " %N", tpm_ecc_curve_names,
250 cap_data.data.eccCurves.eccCurves[i]);
251 if (written < 0 || written >= len)
252 {
253 break;
254 }
255 pos += written;
256 len -= written;
257 }
258 DBG2(DBG_PTS, "%s ECC curves:%s", LABEL, buf);
259
260 return TRUE;
261 }
262
263 /**
264 * Initialize TSS2 TCTI TABRMD context
265 */
266 static bool initialize_tcti_tabrmd_context(private_tpm_tss_tss2_t *this)
267 {
268 #ifdef TSS2_TCTI_TABRMD
269 size_t tcti_context_size;
270 uint32_t rval;
271
272 /* determine size of tcti context */
273 rval = tss2_tcti_tabrmd_init(NULL, &tcti_context_size);
274 if (rval != TSS2_RC_SUCCESS)
275 {
276 DBG1(DBG_PTS, "%s could not get tcti_context size: 0x%06x",
277 LABEL, rval);
278 return FALSE;
279 }
280
281 /* allocate and initialize memory for tcti context */
282 this->tcti_context = (TSS2_TCTI_CONTEXT*)malloc(tcti_context_size);
283 memset(this->tcti_context, 0x00, tcti_context_size);
284
285 /* initialize tcti context */
286 rval = tss2_tcti_tabrmd_init(this->tcti_context, &tcti_context_size);
287 if (rval != TSS2_RC_SUCCESS)
288 {
289 DBG1(DBG_PTS, "%s could not get tcti_context: 0x%06x "
290 "via tabrmd interface", LABEL, rval);
291 return FALSE;
292 }
293 return TRUE;
294 #else /* TSS2_TCTI_TABRMD */
295 return FALSE;
296 #endif /* TSS2_TCTI_TABRMD */
297 }
298
299 /**
300 * Initialize TSS2 TCTI Socket context
301 */
302 static bool initialize_tcti_socket_context(private_tpm_tss_tss2_t *this)
303 {
304 #ifdef TSS2_TCTI_SOCKET
305 size_t tcti_context_size;
306 uint32_t rval;
307
308 TCTI_SOCKET_CONF rm_if_config = { TCTI_SOCKET_DEFAULT_ADDRESS,
309 TCTI_SOCKET_DEFAULT_PORT
310 };
311
312 /* determine size of tcti context */
313 rval = InitSocketTcti(NULL, &tcti_context_size, &rm_if_config, 0);
314 if (rval != TSS2_RC_SUCCESS)
315 {
316 DBG1(DBG_PTS, "%s could not get tcti_context size: 0x%06x",
317 LABEL, rval);
318 return FALSE;
319 }
320
321 /* allocate memory for tcti context */
322 this->tcti_context = (TSS2_TCTI_CONTEXT*)malloc(tcti_context_size);
323
324 /* initialize tcti context */
325 rval = InitSocketTcti(this->tcti_context, &tcti_context_size,
326 &rm_if_config, 0);
327 if (rval != TSS2_RC_SUCCESS)
328 {
329 DBG1(DBG_PTS, "%s could not get tcti_context: 0x%06x "
330 "via socket interface", LABEL, rval);
331 return FALSE;
332 }
333 return TRUE;
334 #else /* TSS2_TCTI_SOCKET */
335 return FALSE;
336 #endif /* TSS2_TCTI_SOCKET */
337 }
338
339 /**
340 * Initialize TSS2 Sys context
341 */
342 static bool initialize_sys_context(private_tpm_tss_tss2_t *this)
343 {
344 uint32_t sys_context_size;
345 uint32_t rval;
346
347 TSS2_ABI_VERSION abi_version = { TSSWG_INTEROP,
348 TSS_SAPI_FIRST_FAMILY,
349 TSS_SAPI_FIRST_LEVEL,
350 TSS_SAPI_FIRST_VERSION
351 };
352
353 /* determine size of sys context */
354 sys_context_size = Tss2_Sys_GetContextSize(0);
355
356 /* allocate memory for sys context */
357 this->sys_context = malloc(sys_context_size);
358
359 /* initialize sys context */
360 rval = Tss2_Sys_Initialize(this->sys_context, sys_context_size,
361 this->tcti_context, &abi_version);
362 if (rval != TSS2_RC_SUCCESS)
363 {
364 DBG1(DBG_PTS, "%s could not get sys_context: 0x%06x",
365 LABEL, rval);
366 return FALSE;
367 }
368
369 /* get a list of supported algorithms and ECC curves */
370 return get_algs_capability(this);
371 }
372
373 /**
374 * Finalize TSS context
375 */
376 static void finalize_context(private_tpm_tss_tss2_t *this)
377 {
378 if (this->tcti_context)
379 {
380 tss2_tcti_finalize(this->tcti_context);
381 free(this->tcti_context);
382 }
383 if (this->sys_context)
384 {
385 Tss2_Sys_Finalize(this->sys_context);
386 free(this->sys_context);
387 }
388 }
389
390 METHOD(tpm_tss_t, get_version, tpm_version_t,
391 private_tpm_tss_tss2_t *this)
392 {
393 return TPM_VERSION_2_0;
394 }
395
396 METHOD(tpm_tss_t, get_version_info, chunk_t,
397 private_tpm_tss_tss2_t *this)
398 {
399 return chunk_empty;
400 }
401
402 /**
403 * read the public key portion of a TSS 2.0 AIK key from NVRAM
404 */
405 bool read_public(private_tpm_tss_tss2_t *this, TPMI_DH_OBJECT handle,
406 TPM2B_PUBLIC *public)
407 {
408 uint32_t rval;
409
410 TPM2B_NAME name = { { sizeof(TPM2B_NAME)-2, } };
411 TPM2B_NAME qualified_name = { { sizeof(TPM2B_NAME)-2, } };
412
413 TPMS_AUTH_RESPONSE session_data;
414 TSS2_SYS_RSP_AUTHS sessions_data;
415 TPMS_AUTH_RESPONSE *session_data_array[1];
416
417 session_data_array[0] = &session_data;
418 sessions_data.rspAuths = &session_data_array[0];
419 sessions_data.rspAuthsCount = 1;
420
421 /* read public key for a given object handle from TPM 2.0 NVRAM */
422 rval = Tss2_Sys_ReadPublic(this->sys_context, handle, 0, public, &name,
423 &qualified_name, &sessions_data);
424 if (rval != TPM_RC_SUCCESS)
425 {
426 DBG1(DBG_PTS, "%s could not read public key from handle 0x%08x: 0x%06x",
427 LABEL, handle, rval);
428 return FALSE;
429 }
430 return TRUE;
431 }
432
433 METHOD(tpm_tss_t, generate_aik, bool,
434 private_tpm_tss_tss2_t *this, chunk_t ca_modulus, chunk_t *aik_blob,
435 chunk_t *aik_pubkey, chunk_t *identity_req)
436 {
437 return FALSE;
438 }
439
440 METHOD(tpm_tss_t, get_public, chunk_t,
441 private_tpm_tss_tss2_t *this, uint32_t handle)
442 {
443 TPM2B_PUBLIC public = { { 0, } };
444 TPM_ALG_ID sig_alg, digest_alg;
445 chunk_t aik_blob, aik_pubkey = chunk_empty;
446
447 if (!read_public(this, handle, &public))
448 {
449 return chunk_empty;
450 }
451
452 aik_blob = chunk_create((u_char*)&public, sizeof(public));
453 DBG3(DBG_LIB, "%s AIK public key blob: %B", LABEL, &aik_blob);
454
455 /* convert TSS 2.0 AIK public key blot into PKCS#1 format */
456 switch (public.t.publicArea.type)
457 {
458 case TPM_ALG_RSA:
459 {
460 TPM2B_PUBLIC_KEY_RSA *rsa;
461 TPMT_RSA_SCHEME *scheme;
462 chunk_t aik_exponent, aik_modulus;
463
464 scheme = &public.t.publicArea.parameters.rsaDetail.scheme;
465 sig_alg = scheme->scheme;
466 digest_alg = scheme->details.anySig.hashAlg;
467
468 rsa = &public.t.publicArea.unique.rsa;
469 aik_modulus = chunk_create(rsa->t.buffer, rsa->t.size);
470 aik_exponent = chunk_from_chars(0x01, 0x00, 0x01);
471
472 /* subjectPublicKeyInfo encoding of AIK RSA key */
473 if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER,
474 NULL, &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus,
475 CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END))
476 {
477 DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of AIK key "
478 "failed", LABEL);
479 return chunk_empty;
480 }
481 break;
482 }
483 case TPM_ALG_ECC:
484 {
485 TPMS_ECC_POINT *ecc;
486 TPMT_ECC_SCHEME *scheme;
487 chunk_t ecc_point;
488 uint8_t *pos;
489
490 scheme = &public.t.publicArea.parameters.eccDetail.scheme;
491 sig_alg = scheme->scheme;
492 digest_alg = scheme->details.anySig.hashAlg;
493
494 ecc = &public.t.publicArea.unique.ecc;
495
496 /* allocate space for bit string */
497 pos = asn1_build_object(&ecc_point, ASN1_BIT_STRING,
498 2 + ecc->x.t.size + ecc->y.t.size);
499 /* bit string length is a multiple of octets */
500 *pos++ = 0x00;
501 /* uncompressed ECC point format */
502 *pos++ = 0x04;
503 /* copy x coordinate of ECC point */
504 memcpy(pos, ecc->x.t.buffer, ecc->x.t.size);
505 pos += ecc->x.t.size;
506 /* copy y coordinate of ECC point */
507 memcpy(pos, ecc->y.t.buffer, ecc->y.t.size);
508 /* subjectPublicKeyInfo encoding of AIK ECC key */
509 aik_pubkey = asn1_wrap(ASN1_SEQUENCE, "mm",
510 asn1_wrap(ASN1_SEQUENCE, "mm",
511 asn1_build_known_oid(OID_EC_PUBLICKEY),
512 asn1_build_known_oid(ecc->x.t.size == 32 ?
513 OID_PRIME256V1 : OID_SECT384R1)),
514 ecc_point);
515 break;
516 }
517 default:
518 DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL);
519 return chunk_empty;
520 }
521 DBG1(DBG_PTS, "AIK signature algorithm is %N with %N hash",
522 tpm_alg_id_names, sig_alg, tpm_alg_id_names, digest_alg);
523 return aik_pubkey;
524 }
525
526 /**
527 * Configure a PCR Selection assuming a maximum of 24 registers
528 */
529 static bool init_pcr_selection(private_tpm_tss_tss2_t *this, uint32_t pcrs,
530 hash_algorithm_t alg, TPML_PCR_SELECTION *pcr_sel)
531 {
532 TPM_ALG_ID alg_id;
533 uint32_t pcr;
534
535 /* check if hash algorithm is supported by TPM */
536 alg_id = hash_alg_to_tpm_alg_id(alg);
537 if (!is_supported_alg(this, alg_id))
538 {
539 DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM",
540 LABEL, hash_algorithm_short_names, alg);
541 return FALSE;
542 }
543
544 /* initialize the PCR Selection structure,*/
545 pcr_sel->count = 1;
546 pcr_sel->pcrSelections[0].hash = alg_id;
547 pcr_sel->pcrSelections[0].sizeofSelect = 3;
548 pcr_sel->pcrSelections[0].pcrSelect[0] = 0;
549 pcr_sel->pcrSelections[0].pcrSelect[1] = 0;
550 pcr_sel->pcrSelections[0].pcrSelect[2] = 0;
551
552 /* set the selected PCRs */
553 for (pcr = 0; pcr < PLATFORM_PCR; pcr++)
554 {
555 if (pcrs & (1 << pcr))
556 {
557 pcr_sel->pcrSelections[0].pcrSelect[pcr / 8] |= ( 1 << (pcr % 8) );
558 }
559 }
560 return TRUE;
561 }
562
563 METHOD(tpm_tss_t, read_pcr, bool,
564 private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
565 hash_algorithm_t alg)
566 {
567 TPML_PCR_SELECTION pcr_selection;
568 TPML_DIGEST pcr_values;
569
570 uint32_t pcr_update_counter, rval;
571 uint8_t *pcr_value_ptr;
572 size_t pcr_value_len;
573
574 if (pcr_num >= PLATFORM_PCR)
575 {
576 DBG1(DBG_PTS, "%s maximum number of supported PCR is %d",
577 LABEL, PLATFORM_PCR);
578 return FALSE;
579 }
580
581 if (!init_pcr_selection(this, (1 << pcr_num), alg, &pcr_selection))
582 {
583 return FALSE;
584 }
585
586 /* initialize the PCR Digest structure */
587 memset(&pcr_values, 0, sizeof(TPML_DIGEST));
588
589 /* read the PCR value */
590 rval = Tss2_Sys_PCR_Read(this->sys_context, 0, &pcr_selection,
591 &pcr_update_counter, &pcr_selection, &pcr_values, 0);
592 if (rval != TPM_RC_SUCCESS)
593 {
594 DBG1(DBG_PTS, "%s PCR bank could not be read: 0x%60x",
595 LABEL, rval);
596 return FALSE;
597 }
598 pcr_value_ptr = (uint8_t *)pcr_values.digests[0].t.buffer;
599 pcr_value_len = (size_t) pcr_values.digests[0].t.size;
600
601 *pcr_value = chunk_clone(chunk_create(pcr_value_ptr, pcr_value_len));
602
603 return TRUE;
604 }
605
606 METHOD(tpm_tss_t, extend_pcr, bool,
607 private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
608 chunk_t data, hash_algorithm_t alg)
609 {
610 uint32_t rval;
611 TPM_ALG_ID alg_id;
612 TPML_DIGEST_VALUES digest_values;
613 TPMS_AUTH_COMMAND session_data_cmd;
614 TPMS_AUTH_RESPONSE session_data_rsp;
615 TSS2_SYS_CMD_AUTHS sessions_data_cmd;
616 TSS2_SYS_RSP_AUTHS sessions_data_rsp;
617 TPMS_AUTH_COMMAND *session_data_cmd_array[1];
618 TPMS_AUTH_RESPONSE *session_data_rsp_array[1];
619
620 session_data_cmd_array[0] = &session_data_cmd;
621 session_data_rsp_array[0] = &session_data_rsp;
622
623 sessions_data_cmd.cmdAuths = &session_data_cmd_array[0];
624 sessions_data_rsp.rspAuths = &session_data_rsp_array[0];
625
626 sessions_data_cmd.cmdAuthsCount = 1;
627 sessions_data_rsp.rspAuthsCount = 1;
628
629 session_data_cmd.sessionHandle = TPM_RS_PW;
630 session_data_cmd.hmac.t.size = 0;
631 session_data_cmd.nonce.t.size = 0;
632
633 *( (uint8_t *)((void *)&session_data_cmd.sessionAttributes ) ) = 0;
634
635 /* check if hash algorithm is supported by TPM */
636 alg_id = hash_alg_to_tpm_alg_id(alg);
637 if (!is_supported_alg(this, alg_id))
638 {
639 DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM",
640 LABEL, hash_algorithm_short_names, alg);
641 return FALSE;
642 }
643
644 digest_values.count = 1;
645 digest_values.digests[0].hashAlg = alg_id;
646
647 switch (alg)
648 {
649 case HASH_SHA1:
650 if (data.len != HASH_SIZE_SHA1)
651 {
652 return FALSE;
653 }
654 memcpy(digest_values.digests[0].digest.sha1, data.ptr,
655 HASH_SIZE_SHA1);
656 break;
657 case HASH_SHA256:
658 if (data.len != HASH_SIZE_SHA256)
659 {
660 return FALSE;
661 }
662 memcpy(digest_values.digests[0].digest.sha256, data.ptr,
663 HASH_SIZE_SHA256);
664 break;
665 case HASH_SHA384:
666 if (data.len != HASH_SIZE_SHA384)
667 {
668 return FALSE;
669 }
670 memcpy(digest_values.digests[0].digest.sha384, data.ptr,
671 HASH_SIZE_SHA384);
672 break;
673 case HASH_SHA512:
674 if (data.len != HASH_SIZE_SHA512)
675 {
676 return FALSE;
677 }
678 memcpy(digest_values.digests[0].digest.sha512, data.ptr,
679 HASH_SIZE_SHA512);
680 break;
681 default:
682 return FALSE;
683 }
684
685 /* extend PCR */
686 rval = Tss2_Sys_PCR_Extend(this->sys_context, pcr_num, &sessions_data_cmd,
687 &digest_values, &sessions_data_rsp);
688 if (rval != TPM_RC_SUCCESS)
689 {
690 DBG1(DBG_PTS, "%s PCR %02u could not be extended: 0x%06x",
691 LABEL, pcr_num, rval);
692 return FALSE;
693 }
694
695 /* get updated PCR value */
696 return read_pcr(this, pcr_num, pcr_value, alg);
697 }
698
699 METHOD(tpm_tss_t, quote, bool,
700 private_tpm_tss_tss2_t *this, uint32_t aik_handle, uint32_t pcr_sel,
701 hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t *quote_mode,
702 tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig)
703 {
704 chunk_t quoted_chunk, qualified_signer, extra_data, clock_info,
705 firmware_version, pcr_select, pcr_digest;
706 hash_algorithm_t pcr_digest_alg;
707 bio_reader_t *reader;
708 uint32_t rval;
709
710 TPM2B_DATA qualifying_data;
711 TPML_PCR_SELECTION pcr_selection;
712 TPM2B_ATTEST quoted = { { sizeof(TPM2B_ATTEST)-2, } };
713 TPMT_SIG_SCHEME scheme;
714 TPMT_SIGNATURE sig;
715 TPMI_ALG_HASH hash_alg;
716 TPMS_AUTH_COMMAND session_data_cmd;
717 TPMS_AUTH_RESPONSE session_data_rsp;
718 TSS2_SYS_CMD_AUTHS sessions_data_cmd;
719 TSS2_SYS_RSP_AUTHS sessions_data_rsp;
720 TPMS_AUTH_COMMAND *session_data_cmd_array[1];
721 TPMS_AUTH_RESPONSE *session_data_rsp_array[1];
722
723 session_data_cmd_array[0] = &session_data_cmd;
724 session_data_rsp_array[0] = &session_data_rsp;
725
726 sessions_data_cmd.cmdAuths = &session_data_cmd_array[0];
727 sessions_data_rsp.rspAuths = &session_data_rsp_array[0];
728
729 sessions_data_cmd.cmdAuthsCount = 1;
730 sessions_data_rsp.rspAuthsCount = 1;
731
732 session_data_cmd.sessionHandle = TPM_RS_PW;
733 session_data_cmd.hmac.t.size = 0;
734 session_data_cmd.nonce.t.size = 0;
735
736 *( (uint8_t *)((void *)&session_data_cmd.sessionAttributes ) ) = 0;
737
738 qualifying_data.t.size = data.len;
739 memcpy(qualifying_data.t.buffer, data.ptr, data.len);
740
741 scheme.scheme = TPM_ALG_NULL;
742 memset(&sig, 0x00, sizeof(sig));
743
744 /* set Quote mode */
745 *quote_mode = TPM_QUOTE_TPM2;
746
747 if (!init_pcr_selection(this, pcr_sel, alg, &pcr_selection))
748 {
749 return FALSE;
750 }
751
752 rval = Tss2_Sys_Quote(this->sys_context, aik_handle, &sessions_data_cmd,
753 &qualifying_data, &scheme, &pcr_selection, &quoted,
754 &sig, &sessions_data_rsp);
755 if (rval != TPM_RC_SUCCESS)
756 {
757 DBG1(DBG_PTS,"%s Tss2_Sys_Quote failed: 0x%06x", LABEL, rval);
758 return FALSE;
759 }
760 quoted_chunk = chunk_create(quoted.t.attestationData, quoted.t.size);
761
762 reader = bio_reader_create(chunk_skip(quoted_chunk, 6));
763 if (!reader->read_data16(reader, &qualified_signer) ||
764 !reader->read_data16(reader, &extra_data) ||
765 !reader->read_data (reader, 17, &clock_info) ||
766 !reader->read_data (reader, 8, &firmware_version) ||
767 !reader->read_data (reader, 10, &pcr_select) ||
768 !reader->read_data16(reader, &pcr_digest))
769 {
770 DBG1(DBG_PTS, "%s parsing of quoted struct failed", LABEL);
771 reader->destroy(reader);
772 return FALSE;
773 }
774 reader->destroy(reader);
775
776 DBG2(DBG_PTS, "PCR Composite digest: %B", &pcr_digest);
777 DBG2(DBG_PTS, "TPM Quote Info: %B", &quoted_chunk);
778 DBG2(DBG_PTS, "qualifiedSigner: %B", &qualified_signer);
779 DBG2(DBG_PTS, "extraData: %B", &extra_data);
780 DBG2(DBG_PTS, "clockInfo: %B", &clock_info);
781 DBG2(DBG_PTS, "firmwareVersion: %B", &firmware_version);
782 DBG2(DBG_PTS, "pcrSelect: %B", &pcr_select);
783
784 /* extract signature */
785 switch (sig.sigAlg)
786 {
787 case TPM_ALG_RSASSA:
788 case TPM_ALG_RSAPSS:
789 *quote_sig = chunk_clone(
790 chunk_create(
791 sig.signature.rsassa.sig.t.buffer,
792 sig.signature.rsassa.sig.t.size));
793 hash_alg = sig.signature.rsassa.hash;
794 break;
795 case TPM_ALG_ECDSA:
796 case TPM_ALG_ECDAA:
797 case TPM_ALG_SM2:
798 case TPM_ALG_ECSCHNORR:
799 *quote_sig = chunk_cat("cc",
800 chunk_create(
801 sig.signature.ecdsa.signatureR.t.buffer,
802 sig.signature.ecdsa.signatureR.t.size),
803 chunk_create(
804 sig.signature.ecdsa.signatureS.t.buffer,
805 sig.signature.ecdsa.signatureS.t.size));
806 hash_alg = sig.signature.ecdsa.hash;
807 break;
808 default:
809 DBG1(DBG_PTS, "%s unsupported %N signature algorithm",
810 LABEL, tpm_alg_id_names, sig.sigAlg);
811 return FALSE;
812 };
813
814 DBG2(DBG_PTS, "PCR digest algorithm is %N", tpm_alg_id_names, hash_alg);
815 pcr_digest_alg = hash_alg_from_tpm_alg_id(hash_alg);
816
817 DBG2(DBG_PTS, "TPM Quote Signature: %B", quote_sig);
818
819 /* Create and initialize Quote Info object */
820 *quote_info = tpm_tss_quote_info_create(*quote_mode, pcr_digest_alg,
821 pcr_digest);
822 (*quote_info)->set_tpm2_info(*quote_info, qualified_signer, clock_info,
823 pcr_select);
824 (*quote_info)->set_version_info(*quote_info, firmware_version);
825
826 return TRUE;
827 }
828
829 METHOD(tpm_tss_t, sign, bool,
830 private_tpm_tss_tss2_t *this, uint32_t hierarchy, uint32_t handle,
831 signature_scheme_t scheme, chunk_t data, chunk_t pin, chunk_t *signature)
832 {
833 key_type_t key_type;
834 hash_algorithm_t hash_alg;
835 uint32_t rval;
836
837 TPM_ALG_ID alg_id;
838 TPM2B_MAX_BUFFER buffer;
839 TPM2B_DIGEST hash = { { sizeof(TPM2B_DIGEST)-2, } };
840 TPMT_TK_HASHCHECK validation;
841 TPM2B_PUBLIC public = { { 0, } };
842 TPMT_SIG_SCHEME sig_scheme;
843 TPMT_SIGNATURE sig;
844 TPMS_AUTH_COMMAND session_data_cmd;
845 TPMS_AUTH_RESPONSE session_data_rsp;
846 TSS2_SYS_CMD_AUTHS sessions_data_cmd;
847 TSS2_SYS_RSP_AUTHS sessions_data_rsp;
848 TPMS_AUTH_COMMAND *session_data_cmd_array[1];
849 TPMS_AUTH_RESPONSE *session_data_rsp_array[1];
850
851 session_data_cmd_array[0] = &session_data_cmd;
852 session_data_rsp_array[0] = &session_data_rsp;
853
854 sessions_data_cmd.cmdAuths = &session_data_cmd_array[0];
855 sessions_data_rsp.rspAuths = &session_data_rsp_array[0];
856
857 sessions_data_cmd.cmdAuthsCount = 1;
858 sessions_data_rsp.rspAuthsCount = 1;
859
860 session_data_cmd.sessionHandle = TPM_RS_PW;
861 session_data_cmd.nonce.t.size = 0;
862 session_data_cmd.hmac.t.size = 0;
863
864 if (pin.len > 0)
865 {
866 session_data_cmd.hmac.t.size = min(sizeof(session_data_cmd.hmac.t) - 2,
867 pin.len);
868 memcpy(session_data_cmd.hmac.t.buffer, pin.ptr,
869 session_data_cmd.hmac.t.size);
870 }
871 *( (uint8_t *)((void *)&session_data_cmd.sessionAttributes ) ) = 0;
872
873 key_type = key_type_from_signature_scheme(scheme);
874 hash_alg = hasher_from_signature_scheme(scheme, NULL);
875
876 /* Check if hash algorithm is supported by TPM */
877 alg_id = hash_alg_to_tpm_alg_id(hash_alg);
878 if (!is_supported_alg(this, alg_id))
879 {
880 DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM",
881 LABEL, hash_algorithm_short_names, hash_alg);
882 return FALSE;
883 }
884
885 /* Get public key */
886 if (!read_public(this, handle, &public))
887 {
888 return FALSE;
889 }
890
891 if (key_type == KEY_RSA && public.t.publicArea.type == TPM_ALG_RSA)
892 {
893 sig_scheme.scheme = TPM_ALG_RSASSA;
894 sig_scheme.details.rsassa.hashAlg = alg_id;
895 }
896 else if (key_type == KEY_ECDSA && public.t.publicArea.type == TPM_ALG_ECC)
897 {
898 sig_scheme.scheme = TPM_ALG_ECDSA;
899 sig_scheme.details.ecdsa.hashAlg = alg_id;
900
901 }
902 else
903 {
904 DBG1(DBG_PTS, "%s signature scheme %N not supported by TPM key",
905 LABEL, signature_scheme_names, scheme);
906 return FALSE;
907 }
908
909 if (data.len <= MAX_DIGEST_BUFFER)
910 {
911 memcpy(buffer.t.buffer, data.ptr, data.len);
912 buffer.t.size = data.len;
913
914 rval = Tss2_Sys_Hash(this->sys_context, 0, &buffer, alg_id, hierarchy,
915 &hash, &validation, 0);
916 if (rval != TPM_RC_SUCCESS)
917 {
918 DBG1(DBG_PTS,"%s Tss2_Sys_Hash failed: 0x%06x", LABEL, rval);
919 return FALSE;
920 }
921 }
922 else
923 {
924 TPMI_DH_OBJECT sequence_handle;
925 TPM2B_AUTH null_auth;
926
927 null_auth.t.size = 0;
928 rval = Tss2_Sys_HashSequenceStart(this->sys_context, 0, &null_auth,
929 alg_id, &sequence_handle, 0);
930 if (rval != TPM_RC_SUCCESS)
931 {
932 DBG1(DBG_PTS,"%s Tss2_Sys_HashSequenceStart failed: 0x%06x",
933 LABEL, rval);
934 return FALSE;
935 }
936
937 while (data.len > 0)
938 {
939 buffer.t.size = min(data.len, MAX_DIGEST_BUFFER);
940 memcpy(buffer.t.buffer, data.ptr, buffer.t.size);
941 data.ptr += buffer.t.size;
942 data.len -= buffer.t.size;
943
944 rval = Tss2_Sys_SequenceUpdate(this->sys_context, sequence_handle,
945 &sessions_data_cmd, &buffer, 0);
946 if (rval != TPM_RC_SUCCESS)
947 {
948 DBG1(DBG_PTS,"%s Tss2_Sys_SequenceUpdate failed: 0x%06x",
949 LABEL, rval);
950 return FALSE;
951 }
952 }
953 buffer.t.size = 0;
954
955 rval = Tss2_Sys_SequenceComplete(this->sys_context, sequence_handle,
956 &sessions_data_cmd, &buffer, hierarchy,
957 &hash, &validation, 0);
958 if (rval != TPM_RC_SUCCESS)
959 {
960 DBG1(DBG_PTS,"%s Tss2_Sys_SequenceComplete failed: 0x%06x",
961 LABEL, rval);
962 return FALSE;
963 }
964 }
965
966 rval = Tss2_Sys_Sign(this->sys_context, handle, &sessions_data_cmd, &hash,
967 &sig_scheme, &validation, &sig, &sessions_data_rsp);
968 if (rval != TPM_RC_SUCCESS)
969 {
970 DBG1(DBG_PTS,"%s Tss2_Sys_Sign failed: 0x%06x", LABEL, rval);
971 return FALSE;
972 }
973
974 /* extract signature */
975 switch (scheme)
976 {
977 case SIGN_RSA_EMSA_PKCS1_SHA1:
978 case SIGN_RSA_EMSA_PKCS1_SHA2_256:
979 case SIGN_RSA_EMSA_PKCS1_SHA2_384:
980 case SIGN_RSA_EMSA_PKCS1_SHA2_512:
981 *signature = chunk_clone(
982 chunk_create(
983 sig.signature.rsassa.sig.t.buffer,
984 sig.signature.rsassa.sig.t.size));
985 break;
986 case SIGN_ECDSA_256:
987 case SIGN_ECDSA_384:
988 case SIGN_ECDSA_521:
989 *signature = chunk_cat("cc",
990 chunk_create(
991 sig.signature.ecdsa.signatureR.t.buffer,
992 sig.signature.ecdsa.signatureR.t.size),
993 chunk_create(
994 sig.signature.ecdsa.signatureS.t.buffer,
995 sig.signature.ecdsa.signatureS.t.size));
996 break;
997 case SIGN_ECDSA_WITH_SHA256_DER:
998 case SIGN_ECDSA_WITH_SHA384_DER:
999 case SIGN_ECDSA_WITH_SHA512_DER:
1000 *signature = asn1_wrap(ASN1_SEQUENCE, "mm",
1001 asn1_integer("c",
1002 chunk_create(
1003 sig.signature.ecdsa.signatureR.t.buffer,
1004 sig.signature.ecdsa.signatureR.t.size)),
1005 asn1_integer("c",
1006 chunk_create(
1007 sig.signature.ecdsa.signatureS.t.buffer,
1008 sig.signature.ecdsa.signatureS.t.size)));
1009 break;
1010 default:
1011 DBG1(DBG_PTS, "%s unsupported %N signature scheme",
1012 LABEL, signature_scheme_names, scheme);
1013 return FALSE;
1014 };
1015
1016 return TRUE;
1017 }
1018
1019 METHOD(tpm_tss_t, get_random, bool,
1020 private_tpm_tss_tss2_t *this, size_t bytes, uint8_t *buffer)
1021 {
1022 size_t len, random_len= sizeof(TPM2B_DIGEST)-2;
1023 TPM2B_DIGEST random = { { random_len, } };
1024 uint8_t *pos = buffer;
1025 uint32_t rval;
1026
1027 while (bytes > 0)
1028 {
1029 len = min(bytes, random_len);
1030
1031 rval = Tss2_Sys_GetRandom(this->sys_context, NULL, len, &random, NULL);
1032 if (rval != TSS2_RC_SUCCESS)
1033 {
1034 DBG1(DBG_PTS,"%s Tss2_Sys_GetRandom failed: 0x%06x", LABEL, rval);
1035 return FALSE;
1036 }
1037 memcpy(pos, random.t.buffer, random.t.size);
1038 pos += random.t.size;
1039 bytes -= random.t.size;
1040 }
1041
1042 return TRUE;
1043 }
1044
1045 METHOD(tpm_tss_t, get_data, bool,
1046 private_tpm_tss_tss2_t *this, uint32_t hierarchy, uint32_t handle,
1047 chunk_t pin, chunk_t *data)
1048 {
1049 uint16_t nv_size, nv_offset = 0;
1050 uint32_t rval;
1051
1052 TPM2B_NAME nv_name = { { sizeof(TPM2B_NAME)-2, } };
1053 TPM2B_NV_PUBLIC nv_public = { { 0, } };
1054 TPM2B_MAX_NV_BUFFER nv_data = { { sizeof(TPM2B_MAX_NV_BUFFER)-2, } };
1055 TPMS_AUTH_COMMAND session_data_cmd;
1056 TPMS_AUTH_RESPONSE session_data_rsp;
1057 TSS2_SYS_CMD_AUTHS sessions_data_cmd;
1058 TSS2_SYS_RSP_AUTHS sessions_data_rsp;
1059 TPMS_AUTH_COMMAND *session_data_cmd_array[1];
1060 TPMS_AUTH_RESPONSE *session_data_rsp_array[1];
1061
1062 /* get size of NV object */
1063 rval = Tss2_Sys_NV_ReadPublic(this->sys_context, handle, 0, &nv_public,
1064 &nv_name, 0);
1065 if (rval != TPM_RC_SUCCESS)
1066 {
1067 DBG1(DBG_PTS,"%s Tss2_Sys_NV_ReadPublic failed: 0x%06x", LABEL, rval);
1068 return FALSE;
1069 }
1070 nv_size = nv_public.t.nvPublic.dataSize;
1071 *data = chunk_alloc(nv_size);
1072
1073 /*prepare NV read session */
1074 session_data_cmd_array[0] = &session_data_cmd;
1075 session_data_rsp_array[0] = &session_data_rsp;
1076
1077 sessions_data_cmd.cmdAuths = &session_data_cmd_array[0];
1078 sessions_data_rsp.rspAuths = &session_data_rsp_array[0];
1079
1080 sessions_data_cmd.cmdAuthsCount = 1;
1081 sessions_data_rsp.rspAuthsCount = 1;
1082
1083 session_data_cmd.sessionHandle = TPM_RS_PW;
1084 session_data_cmd.nonce.t.size = 0;
1085 session_data_cmd.hmac.t.size = 0;
1086
1087 if (pin.len > 0)
1088 {
1089 session_data_cmd.hmac.t.size = min(sizeof(session_data_cmd.hmac.t) - 2,
1090 pin.len);
1091 memcpy(session_data_cmd.hmac.t.buffer, pin.ptr,
1092 session_data_cmd.hmac.t.size);
1093 }
1094 *( (uint8_t *)((void *)&session_data_cmd.sessionAttributes ) ) = 0;
1095
1096 /* read NV data an NV buffer block at a time */
1097 while (nv_size > 0)
1098 {
1099 rval = Tss2_Sys_NV_Read(this->sys_context, hierarchy, handle,
1100 &sessions_data_cmd, min(nv_size, MAX_NV_BUFFER_SIZE),
1101 nv_offset, &nv_data, &sessions_data_rsp);
1102
1103 if (rval != TPM_RC_SUCCESS)
1104 {
1105 DBG1(DBG_PTS,"%s Tss2_Sys_NV_Read failed: 0x%06x", LABEL, rval);
1106 chunk_free(data);
1107 return FALSE;
1108 }
1109 memcpy(data->ptr + nv_offset, nv_data.t.buffer, nv_data.t.size);
1110 nv_offset += nv_data.t.size;
1111 nv_size -= nv_data.t.size;
1112 }
1113
1114 return TRUE;
1115 }
1116
1117 METHOD(tpm_tss_t, destroy, void,
1118 private_tpm_tss_tss2_t *this)
1119 {
1120 finalize_context(this);
1121 free(this);
1122 }
1123
1124 /**
1125 * See header
1126 */
1127 tpm_tss_t *tpm_tss_tss2_create()
1128 {
1129 private_tpm_tss_tss2_t *this;
1130 bool available;
1131
1132 INIT(this,
1133 .public = {
1134 .get_version = _get_version,
1135 .get_version_info = _get_version_info,
1136 .generate_aik = _generate_aik,
1137 .get_public = _get_public,
1138 .read_pcr = _read_pcr,
1139 .extend_pcr = _extend_pcr,
1140 .quote = _quote,
1141 .sign = _sign,
1142 .get_random = _get_random,
1143 .get_data = _get_data,
1144 .destroy = _destroy,
1145 },
1146 );
1147
1148 available = initialize_tcti_tabrmd_context(this);
1149 if (!available)
1150 {
1151 available = initialize_tcti_socket_context(this);
1152 }
1153 if (available)
1154 {
1155 available = initialize_sys_context(this);
1156 }
1157 DBG1(DBG_PTS, "TPM 2.0 via TSS2 %savailable", available ? "" : "not ");
1158
1159 if (!available)
1160 {
1161 destroy(this);
1162 return NULL;
1163 }
1164 return &this->public;
1165 }
1166
1167 #else /* TSS_TSS2 */
1168
1169 tpm_tss_t *tpm_tss_tss2_create()
1170 {
1171 return NULL;
1172 }
1173
1174 #endif /* TSS_TSS2 */
1175
1176