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