]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libtpmtss/tpm_tss_tss2.c
Version bump to 5.6.2dr2
[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);
169 }
170 memset(manufacturer, '\0', sizeof(manufacturer));
171 memset(vendor_string, '\0', sizeof(vendor_string));
172
173 /* print fixed properties */
174 for (i = 0; i < cap_data.data.tpmProperties.count; i++)
175 {
176 tp = cap_data.data.tpmProperties.tpmProperty[i];
177 switch (tp.property)
178 {
179 case TPM_PT_REVISION:
180 revision = tp.value;
181 break;
182 case TPM_PT_YEAR:
183 year = tp.value;
184 break;
185 case TPM_PT_MANUFACTURER:
186 htoun32(manufacturer, tp.value);
187 break;
188 case TPM_PT_VENDOR_STRING_1:
189 case TPM_PT_VENDOR_STRING_2:
190 case TPM_PT_VENDOR_STRING_3:
191 case TPM_PT_VENDOR_STRING_4:
192 offset = 4 * (tp.property - TPM_PT_VENDOR_STRING_1);
193 htoun32(vendor_string + offset, tp.value);
194 break;
195 default:
196 break;
197 }
198 }
199 DBG2(DBG_PTS, "%s manufacturer: %s (%s) rev: %05.2f %u", LABEL, manufacturer,
200 vendor_string, (float)revision/100, year);
201
8301dc85
AS
202 /* get supported algorithms */
203 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ALGS,
204 0, TPM_PT_ALGORITHM_SET, &more_data, &cap_data, 0);
205 if (rval != TPM_RC_SUCCESS)
206 {
207 DBG1(DBG_PTS, "%s GetCapability failed for TPM_CAP_ALGS: 0x%06x",
208 LABEL, rval);
209 return FALSE;
210 }
211
bc67802a
AS
212 /* Number of supported algorithms */
213 this->supported_algs_count = cap_data.data.algorithms.count;
214
215 /* store and print supported algorithms */
216 for (i = 0; i < this->supported_algs_count; i++)
8301dc85 217 {
bc67802a
AS
218 alg = cap_data.data.algorithms.algProperties[i].alg;
219 this->supported_algs[i] = alg;
220
221 written = snprintf(pos, len, " %N", tpm_alg_id_names, alg);
8301dc85
AS
222 if (written < 0 || written >= len)
223 {
224 break;
225 }
226 pos += written;
227 len -= written;
228 }
229 DBG2(DBG_PTS, "%s algorithms:%s", LABEL, buf);
230
231 /* get supported ECC curves */
232 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ECC_CURVES,
233 0, TPM_PT_LOADED_CURVES, &more_data, &cap_data, 0);
234 if (rval != TPM_RC_SUCCESS)
235 {
236 DBG1(DBG_PTS, "%s GetCapability failed for TPM_ECC_CURVES: 0x%06x",
237 LABEL, rval);
238 return FALSE;
239 }
240
241 /* reset print buffer */
242 pos = buf;
243 len = BUF_LEN;
244
245 /* print supported ECC curves */
246 for (i = 0; i < cap_data.data.eccCurves.count; i++)
247 {
248 written = snprintf(pos, len, " %N", tpm_ecc_curve_names,
249 cap_data.data.eccCurves.eccCurves[i]);
250 if (written < 0 || written >= len)
251 {
252 break;
253 }
254 pos += written;
255 len -= written;
256 }
257 DBG2(DBG_PTS, "%s ECC curves:%s", LABEL, buf);
258
259 return TRUE;
260}
261
c08753bd 262/**
eab650d6 263 * Initialize TSS2 TCTI TABRMD context
c08753bd 264 */
eab650d6 265static bool initialize_tcti_tabrmd_context(private_tpm_tss_tss2_t *this)
c08753bd 266{
eab650d6 267#ifdef TSS2_TCTI_TABRMD
c08753bd 268 size_t tcti_context_size;
c08753bd
AS
269 uint32_t rval;
270
eab650d6
AS
271 /* determine size of tcti context */
272 rval = tss2_tcti_tabrmd_init(NULL, &tcti_context_size);
273 if (rval != TSS2_RC_SUCCESS)
274 {
275 DBG1(DBG_PTS, "%s could not get tcti_context size: 0x%06x",
276 LABEL, rval);
277 return FALSE;
278 }
c08753bd 279
eab650d6
AS
280 /* allocate memory for tcti context */
281 this->tcti_context = (TSS2_TCTI_CONTEXT*)malloc(tcti_context_size);
282
283 /* initialize tcti context */
284 rval = tss2_tcti_tabrmd_init(this->tcti_context, &tcti_context_size);
285 if (rval != TSS2_RC_SUCCESS)
286 {
287 DBG1(DBG_PTS, "%s could not get tcti_context: 0x%06x "
288 "via tabrmd interface", LABEL, rval);
289 return FALSE;
290 }
291 return TRUE;
292#else /* TSS2_TCTI_TABRMD */
293 return FALSE;
294#endif /* TSS2_TCTI_TABRMD */
295}
296
297/**
298 * Initialize TSS2 TCTI Socket context
299 */
300static bool initialize_tcti_socket_context(private_tpm_tss_tss2_t *this)
301{
302#ifdef TSS2_TCTI_SOCKET
303 size_t tcti_context_size;
304 uint32_t rval;
305
306 TCTI_SOCKET_CONF rm_if_config = { TCTI_SOCKET_DEFAULT_ADDRESS,
307 TCTI_SOCKET_DEFAULT_PORT
308 };
c08753bd
AS
309
310 /* determine size of tcti context */
311 rval = InitSocketTcti(NULL, &tcti_context_size, &rm_if_config, 0);
312 if (rval != TSS2_RC_SUCCESS)
313 {
314 DBG1(DBG_PTS, "%s could not get tcti_context size: 0x%06x",
315 LABEL, rval);
316 return FALSE;
317 }
318
319 /* allocate memory for tcti context */
320 this->tcti_context = (TSS2_TCTI_CONTEXT*)malloc(tcti_context_size);
321
322 /* initialize tcti context */
323 rval = InitSocketTcti(this->tcti_context, &tcti_context_size,
324 &rm_if_config, 0);
325 if (rval != TSS2_RC_SUCCESS)
326 {
eab650d6
AS
327 DBG1(DBG_PTS, "%s could not get tcti_context: 0x%06x "
328 "via socket interface", LABEL, rval);
c08753bd
AS
329 return FALSE;
330 }
eab650d6
AS
331 return TRUE;
332#else /* TSS2_TCTI_SOCKET */
333 return FALSE;
334#endif /* TSS2_TCTI_SOCKET */
335}
336
337/**
338 * Initialize TSS2 Sys context
339 */
340static bool initialize_sys_context(private_tpm_tss_tss2_t *this)
341{
342 uint32_t sys_context_size;
343 uint32_t rval;
344
345 TSS2_ABI_VERSION abi_version = { TSSWG_INTEROP,
346 TSS_SAPI_FIRST_FAMILY,
347 TSS_SAPI_FIRST_LEVEL,
348 TSS_SAPI_FIRST_VERSION
349 };
c08753bd
AS
350
351 /* determine size of sys context */
352 sys_context_size = Tss2_Sys_GetContextSize(0);
353
354 /* allocate memory for sys context */
355 this->sys_context = malloc(sys_context_size);
356
357 /* initialize sys context */
358 rval = Tss2_Sys_Initialize(this->sys_context, sys_context_size,
359 this->tcti_context, &abi_version);
360 if (rval != TSS2_RC_SUCCESS)
361 {
362 DBG1(DBG_PTS, "%s could not get sys_context: 0x%06x",
363 LABEL, rval);
364 return FALSE;
365 }
8301dc85
AS
366
367 /* get a list of supported algorithms and ECC curves */
368 return get_algs_capability(this);
c08753bd
AS
369}
370
371/**
372 * Finalize TSS context
373 */
374static void finalize_context(private_tpm_tss_tss2_t *this)
375{
376 if (this->tcti_context)
377 {
d1259418
AS
378 tss2_tcti_finalize(this->tcti_context);
379 free(this->tcti_context);
c08753bd
AS
380 }
381 if (this->sys_context)
382 {
383 Tss2_Sys_Finalize(this->sys_context);
384 free(this->sys_context);
385 }
386}
387
388METHOD(tpm_tss_t, get_version, tpm_version_t,
389 private_tpm_tss_tss2_t *this)
390{
391 return TPM_VERSION_2_0;
392}
393
fedc6769
AS
394METHOD(tpm_tss_t, get_version_info, chunk_t,
395 private_tpm_tss_tss2_t *this)
396{
397 return chunk_empty;
398}
399
c08753bd
AS
400/**
401 * read the public key portion of a TSS 2.0 AIK key from NVRAM
402 */
403bool read_public(private_tpm_tss_tss2_t *this, TPMI_DH_OBJECT handle,
404 TPM2B_PUBLIC *public)
405{
406 uint32_t rval;
407
408 TPM2B_NAME name = { { sizeof(TPM2B_NAME)-2, } };
409 TPM2B_NAME qualified_name = { { sizeof(TPM2B_NAME)-2, } };
410
411 TPMS_AUTH_RESPONSE session_data;
412 TSS2_SYS_RSP_AUTHS sessions_data;
413 TPMS_AUTH_RESPONSE *session_data_array[1];
414
415 session_data_array[0] = &session_data;
416 sessions_data.rspAuths = &session_data_array[0];
417 sessions_data.rspAuthsCount = 1;
418
c08753bd
AS
419 /* read public key for a given object handle from TPM 2.0 NVRAM */
420 rval = Tss2_Sys_ReadPublic(this->sys_context, handle, 0, public, &name,
421 &qualified_name, &sessions_data);
c08753bd
AS
422 if (rval != TPM_RC_SUCCESS)
423 {
424 DBG1(DBG_PTS, "%s could not read public key from handle 0x%08x: 0x%06x",
425 LABEL, handle, rval);
426 return FALSE;
427 }
428 return TRUE;
429}
430
431METHOD(tpm_tss_t, generate_aik, bool,
432 private_tpm_tss_tss2_t *this, chunk_t ca_modulus, chunk_t *aik_blob,
433 chunk_t *aik_pubkey, chunk_t *identity_req)
434{
435 return FALSE;
436}
437
438METHOD(tpm_tss_t, get_public, chunk_t,
439 private_tpm_tss_tss2_t *this, uint32_t handle)
440{
441 TPM2B_PUBLIC public = { { 0, } };
2343c483 442 TPM_ALG_ID sig_alg, digest_alg;
c08753bd
AS
443 chunk_t aik_blob, aik_pubkey = chunk_empty;
444
445 if (!read_public(this, handle, &public))
446 {
447 return chunk_empty;
448 }
449
450 aik_blob = chunk_create((u_char*)&public, sizeof(public));
451 DBG3(DBG_LIB, "%s AIK public key blob: %B", LABEL, &aik_blob);
452
453 /* convert TSS 2.0 AIK public key blot into PKCS#1 format */
454 switch (public.t.publicArea.type)
455 {
456 case TPM_ALG_RSA:
457 {
458 TPM2B_PUBLIC_KEY_RSA *rsa;
2343c483 459 TPMT_RSA_SCHEME *scheme;
c08753bd
AS
460 chunk_t aik_exponent, aik_modulus;
461
2343c483
AS
462 scheme = &public.t.publicArea.parameters.rsaDetail.scheme;
463 sig_alg = scheme->scheme;
464 digest_alg = scheme->details.anySig.hashAlg;
465
c08753bd
AS
466 rsa = &public.t.publicArea.unique.rsa;
467 aik_modulus = chunk_create(rsa->t.buffer, rsa->t.size);
468 aik_exponent = chunk_from_chars(0x01, 0x00, 0x01);
469
470 /* subjectPublicKeyInfo encoding of AIK RSA key */
471 if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER,
472 NULL, &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus,
473 CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END))
474 {
475 DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of AIK key "
476 "failed", LABEL);
477 }
478 break;
479 }
480 case TPM_ALG_ECC:
481 {
482 TPMS_ECC_POINT *ecc;
2343c483 483 TPMT_ECC_SCHEME *scheme;
c08753bd
AS
484 chunk_t ecc_point;
485 uint8_t *pos;
486
2343c483
AS
487 scheme = &public.t.publicArea.parameters.eccDetail.scheme;
488 sig_alg = scheme->scheme;
489 digest_alg = scheme->details.anySig.hashAlg;
490
c08753bd
AS
491 ecc = &public.t.publicArea.unique.ecc;
492
493 /* allocate space for bit string */
494 pos = asn1_build_object(&ecc_point, ASN1_BIT_STRING,
495 2 + ecc->x.t.size + ecc->y.t.size);
496 /* bit string length is a multiple of octets */
497 *pos++ = 0x00;
498 /* uncompressed ECC point format */
499 *pos++ = 0x04;
500 /* copy x coordinate of ECC point */
501 memcpy(pos, ecc->x.t.buffer, ecc->x.t.size);
502 pos += ecc->x.t.size;
503 /* copy y coordinate of ECC point */
504 memcpy(pos, ecc->y.t.buffer, ecc->y.t.size);
505 /* subjectPublicKeyInfo encoding of AIK ECC key */
506 aik_pubkey = asn1_wrap(ASN1_SEQUENCE, "mm",
507 asn1_wrap(ASN1_SEQUENCE, "mm",
508 asn1_build_known_oid(OID_EC_PUBLICKEY),
509 asn1_build_known_oid(ecc->x.t.size == 32 ?
510 OID_PRIME256V1 : OID_SECT384R1)),
511 ecc_point);
512 break;
513 }
514 default:
515 DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL);
2343c483 516 return chunk_empty;
c08753bd 517 }
2343c483
AS
518 DBG1(DBG_PTS, "AIK signature algorithm is %N with %N hash",
519 tpm_alg_id_names, sig_alg, tpm_alg_id_names, digest_alg);
c08753bd
AS
520 return aik_pubkey;
521}
522
57e80492
AS
523/**
524 * Configure a PCR Selection assuming a maximum of 24 registers
525 */
526static bool init_pcr_selection(private_tpm_tss_tss2_t *this, uint32_t pcrs,
527 hash_algorithm_t alg, TPML_PCR_SELECTION *pcr_sel)
30d4989a 528{
bc67802a 529 TPM_ALG_ID alg_id;
57e80492 530 uint32_t pcr;
bc67802a 531
57e80492 532 /* check if hash algorithm is supported by TPM */
bc67802a
AS
533 alg_id = hash_alg_to_tpm_alg_id(alg);
534 if (!is_supported_alg(this, alg_id))
535 {
536 DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM",
537 LABEL, hash_algorithm_short_names, alg);
538 return FALSE;
539 }
540
57e80492
AS
541 /* initialize the PCR Selection structure,*/
542 pcr_sel->count = 1;
543 pcr_sel->pcrSelections[0].hash = alg_id;
544 pcr_sel->pcrSelections[0].sizeofSelect = 3;
545 pcr_sel->pcrSelections[0].pcrSelect[0] = 0;
546 pcr_sel->pcrSelections[0].pcrSelect[1] = 0;
547 pcr_sel->pcrSelections[0].pcrSelect[2] = 0;
548
549 /* set the selected PCRs */
550 for (pcr = 0; pcr < PLATFORM_PCR; pcr++)
551 {
552 if (pcrs & (1 << pcr))
553 {
554 pcr_sel->pcrSelections[0].pcrSelect[pcr / 8] |= ( 1 << (pcr % 8) );
555 }
556 }
557 return TRUE;
558}
559
560METHOD(tpm_tss_t, read_pcr, bool,
561 private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
562 hash_algorithm_t alg)
563{
564 TPML_PCR_SELECTION pcr_selection;
565 TPML_DIGEST pcr_values;
566
567 uint32_t pcr_update_counter, rval;
568 uint8_t *pcr_value_ptr;
569 size_t pcr_value_len;
570
bc67802a
AS
571 if (pcr_num >= PLATFORM_PCR)
572 {
573 DBG1(DBG_PTS, "%s maximum number of supported PCR is %d",
574 LABEL, PLATFORM_PCR);
575 return FALSE;
576 }
577
57e80492
AS
578 if (!init_pcr_selection(this, (1 << pcr_num), alg, &pcr_selection))
579 {
580 return FALSE;
581 }
bc67802a
AS
582
583 /* initialize the PCR Digest structure */
584 memset(&pcr_values, 0, sizeof(TPML_DIGEST));
585
586 /* read the PCR value */
57e80492
AS
587 rval = Tss2_Sys_PCR_Read(this->sys_context, 0, &pcr_selection,
588 &pcr_update_counter, &pcr_selection, &pcr_values, 0);
bc67802a
AS
589 if (rval != TPM_RC_SUCCESS)
590 {
591 DBG1(DBG_PTS, "%s PCR bank could not be read: 0x%60x",
592 LABEL, rval);
593 return FALSE;
594 }
595 pcr_value_ptr = (uint8_t *)pcr_values.digests[0].t.buffer;
596 pcr_value_len = (size_t) pcr_values.digests[0].t.size;
597
598 *pcr_value = chunk_clone(chunk_create(pcr_value_ptr, pcr_value_len));
599
600 return TRUE;
30d4989a
AS
601}
602
603METHOD(tpm_tss_t, extend_pcr, bool,
604 private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
605 chunk_t data, hash_algorithm_t alg)
606{
607 /* TODO */
608 return FALSE;
609}
610
611METHOD(tpm_tss_t, quote, bool,
612 private_tpm_tss_tss2_t *this, uint32_t aik_handle, uint32_t pcr_sel,
721ed31b
AS
613 hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t *quote_mode,
614 tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig)
30d4989a 615{
721ed31b
AS
616 chunk_t quoted_chunk, qualified_signer, extra_data, clock_info,
617 firmware_version, pcr_select, pcr_digest;
618 hash_algorithm_t pcr_digest_alg;
619 bio_reader_t *reader;
57e80492
AS
620 uint32_t rval;
621
622 TPM2B_DATA qualifying_data;
623 TPML_PCR_SELECTION pcr_selection;
57e80492 624 TPM2B_ATTEST quoted = { { sizeof(TPM2B_ATTEST)-2, } };
57e80492 625 TPMT_SIG_SCHEME scheme;
721ed31b
AS
626 TPMT_SIGNATURE sig;
627 TPMI_ALG_HASH hash_alg;
57e80492
AS
628 TPMS_AUTH_COMMAND session_data_cmd;
629 TPMS_AUTH_RESPONSE session_data_rsp;
630 TSS2_SYS_CMD_AUTHS sessions_data_cmd;
631 TSS2_SYS_RSP_AUTHS sessions_data_rsp;
632 TPMS_AUTH_COMMAND *session_data_cmd_array[1];
633 TPMS_AUTH_RESPONSE *session_data_rsp_array[1];
634
635 session_data_cmd_array[0] = &session_data_cmd;
636 session_data_rsp_array[0] = &session_data_rsp;
637
638 sessions_data_cmd.cmdAuths = &session_data_cmd_array[0];
639 sessions_data_rsp.rspAuths = &session_data_rsp_array[0];
640
641 sessions_data_cmd.cmdAuthsCount = 1;
642 sessions_data_rsp.rspAuthsCount = 1;
643
644 session_data_cmd.sessionHandle = TPM_RS_PW;
645 session_data_cmd.hmac.t.size = 0;
646 session_data_cmd.nonce.t.size = 0;
647
648 *( (uint8_t *)((void *)&session_data_cmd.sessionAttributes ) ) = 0;
649
650 qualifying_data.t.size = data.len;
651 memcpy(qualifying_data.t.buffer, data.ptr, data.len);
652
653 scheme.scheme = TPM_ALG_NULL;
654 memset(&sig, 0x00, sizeof(sig));
655
721ed31b
AS
656 /* set Quote mode */
657 *quote_mode = TPM_QUOTE_TPM2;
57e80492
AS
658
659 if (!init_pcr_selection(this, pcr_sel, alg, &pcr_selection))
660 {
661 return FALSE;
662 }
663
664 rval = Tss2_Sys_Quote(this->sys_context, aik_handle, &sessions_data_cmd,
665 &qualifying_data, &scheme, &pcr_selection, &quoted,
666 &sig, &sessions_data_rsp);
667 if (rval != TPM_RC_SUCCESS)
668 {
669 DBG1(DBG_PTS,"%s Tss2_Sys_Quote failed: 0x%06x", LABEL, rval);
670 return FALSE;
671 }
721ed31b
AS
672 quoted_chunk = chunk_create(quoted.t.attestationData, quoted.t.size);
673
674 reader = bio_reader_create(chunk_skip(quoted_chunk, 6));
675 if (!reader->read_data16(reader, &qualified_signer) ||
676 !reader->read_data16(reader, &extra_data) ||
677 !reader->read_data (reader, 17, &clock_info) ||
678 !reader->read_data (reader, 8, &firmware_version) ||
679 !reader->read_data (reader, 10, &pcr_select) ||
680 !reader->read_data16(reader, &pcr_digest))
681 {
682 DBG1(DBG_PTS, "%s parsing of quoted struct failed", LABEL);
683 reader->destroy(reader);
684 return FALSE;
685 }
686 reader->destroy(reader);
57e80492 687
721ed31b
AS
688 DBG2(DBG_PTS, "PCR Composite digest: %B", &pcr_digest);
689 DBG2(DBG_PTS, "TPM Quote Info: %B", &quoted_chunk);
690 DBG2(DBG_PTS, "qualifiedSigner: %B", &qualified_signer);
691 DBG2(DBG_PTS, "extraData: %B", &extra_data);
692 DBG2(DBG_PTS, "clockInfo: %B", &clock_info);
693 DBG2(DBG_PTS, "firmwareVersion: %B", &firmware_version);
694 DBG2(DBG_PTS, "pcrSelect: %B", &pcr_select);
57e80492
AS
695
696 /* extract signature */
697 switch (sig.sigAlg)
698 {
699 case TPM_ALG_RSASSA:
700 case TPM_ALG_RSAPSS:
701 *quote_sig = chunk_clone(
702 chunk_create(
703 sig.signature.rsassa.sig.t.buffer,
704 sig.signature.rsassa.sig.t.size));
721ed31b 705 hash_alg = sig.signature.rsassa.hash;
57e80492
AS
706 break;
707 case TPM_ALG_ECDSA:
708 case TPM_ALG_ECDAA:
709 case TPM_ALG_SM2:
710 case TPM_ALG_ECSCHNORR:
711 *quote_sig = chunk_cat("cc",
712 chunk_create(
713 sig.signature.ecdsa.signatureR.t.buffer,
714 sig.signature.ecdsa.signatureR.t.size),
715 chunk_create(
716 sig.signature.ecdsa.signatureS.t.buffer,
717 sig.signature.ecdsa.signatureS.t.size));
721ed31b 718 hash_alg = sig.signature.ecdsa.hash;
57e80492
AS
719 break;
720 default:
721 DBG1(DBG_PTS, "%s unsupported %N signature algorithm",
722 LABEL, tpm_alg_id_names, sig.sigAlg);
723 return FALSE;
724 };
721ed31b
AS
725
726 DBG2(DBG_PTS, "PCR digest algorithm is %N", tpm_alg_id_names, hash_alg);
727 pcr_digest_alg = hash_alg_from_tpm_alg_id(hash_alg);
728
57e80492
AS
729 DBG2(DBG_PTS, "TPM Quote Signature: %B", quote_sig);
730
721ed31b
AS
731 /* Create and initialize Quote Info object */
732 *quote_info = tpm_tss_quote_info_create(*quote_mode, pcr_digest_alg,
733 pcr_digest);
734 (*quote_info)->set_tpm2_info(*quote_info, qualified_signer, clock_info,
735 pcr_select);
736 (*quote_info)->set_version_info(*quote_info, firmware_version);
737
57e80492 738 return TRUE;
30d4989a
AS
739}
740
e8736028
AS
741METHOD(tpm_tss_t, sign, bool,
742 private_tpm_tss_tss2_t *this, uint32_t hierarchy, uint32_t handle,
743 signature_scheme_t scheme, chunk_t data, chunk_t pin, chunk_t *signature)
744{
745 key_type_t key_type;
746 hash_algorithm_t hash_alg;
747 uint32_t rval;
748
749 TPM_ALG_ID alg_id;
750 TPM2B_MAX_BUFFER buffer;
751 TPM2B_DIGEST hash = { { sizeof(TPM2B_DIGEST)-2, } };
752 TPMT_TK_HASHCHECK validation;
753 TPM2B_PUBLIC public = { { 0, } };
754 TPMT_SIG_SCHEME sig_scheme;
755 TPMT_SIGNATURE sig;
756 TPMS_AUTH_COMMAND session_data_cmd;
757 TPMS_AUTH_RESPONSE session_data_rsp;
758 TSS2_SYS_CMD_AUTHS sessions_data_cmd;
759 TSS2_SYS_RSP_AUTHS sessions_data_rsp;
760 TPMS_AUTH_COMMAND *session_data_cmd_array[1];
761 TPMS_AUTH_RESPONSE *session_data_rsp_array[1];
762
763 session_data_cmd_array[0] = &session_data_cmd;
764 session_data_rsp_array[0] = &session_data_rsp;
765
766 sessions_data_cmd.cmdAuths = &session_data_cmd_array[0];
767 sessions_data_rsp.rspAuths = &session_data_rsp_array[0];
768
769 sessions_data_cmd.cmdAuthsCount = 1;
770 sessions_data_rsp.rspAuthsCount = 1;
771
772 session_data_cmd.sessionHandle = TPM_RS_PW;
773 session_data_cmd.nonce.t.size = 0;
774 session_data_cmd.hmac.t.size = 0;
775
776 if (pin.len > 0)
777 {
778 session_data_cmd.hmac.t.size = min(sizeof(session_data_cmd.hmac.t) - 2,
779 pin.len);
780 memcpy(session_data_cmd.hmac.t.buffer, pin.ptr,
781 session_data_cmd.hmac.t.size);
782 }
783 *( (uint8_t *)((void *)&session_data_cmd.sessionAttributes ) ) = 0;
784
785 key_type = key_type_from_signature_scheme(scheme);
0d632555 786 hash_alg = hasher_from_signature_scheme(scheme, NULL);
e8736028
AS
787
788 /* Check if hash algorithm is supported by TPM */
789 alg_id = hash_alg_to_tpm_alg_id(hash_alg);
790 if (!is_supported_alg(this, alg_id))
791 {
792 DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM",
793 LABEL, hash_algorithm_short_names, hash_alg);
794 return FALSE;
795 }
796
797 /* Get public key */
798 if (!read_public(this, handle, &public))
799 {
800 return FALSE;
801 }
802
803 if (key_type == KEY_RSA && public.t.publicArea.type == TPM_ALG_RSA)
804 {
805 sig_scheme.scheme = TPM_ALG_RSASSA;
806 sig_scheme.details.rsassa.hashAlg = alg_id;
807 }
808 else if (key_type == KEY_ECDSA && public.t.publicArea.type == TPM_ALG_ECC)
809 {
810 sig_scheme.scheme = TPM_ALG_ECDSA;
811 sig_scheme.details.ecdsa.hashAlg = alg_id;
812
813 }
814 else
815 {
816 DBG1(DBG_PTS, "%s signature scheme %N not supported by TPM key",
817 LABEL, signature_scheme_names, scheme);
818 return FALSE;
819 }
820
821 if (data.len <= MAX_DIGEST_BUFFER)
822 {
823 memcpy(buffer.t.buffer, data.ptr, data.len);
824 buffer.t.size = data.len;
825
826 rval = Tss2_Sys_Hash(this->sys_context, 0, &buffer, alg_id, hierarchy,
827 &hash, &validation, 0);
828 if (rval != TPM_RC_SUCCESS)
829 {
830 DBG1(DBG_PTS,"%s Tss2_Sys_Hash failed: 0x%06x", LABEL, rval);
831 return FALSE;
832 }
833 }
834 else
835 {
836 TPMI_DH_OBJECT sequence_handle;
837 TPM2B_AUTH null_auth;
838
839 null_auth.t.size = 0;
840 rval = Tss2_Sys_HashSequenceStart(this->sys_context, 0, &null_auth,
841 alg_id, &sequence_handle, 0);
842 if (rval != TPM_RC_SUCCESS)
843 {
844 DBG1(DBG_PTS,"%s Tss2_Sys_HashSequenceStart failed: 0x%06x",
845 LABEL, rval);
846 return FALSE;
847 }
848
849 while (data.len > 0)
850 {
851 buffer.t.size = min(data.len, MAX_DIGEST_BUFFER);
852 memcpy(buffer.t.buffer, data.ptr, buffer.t.size);
853 data.ptr += buffer.t.size;
854 data.len -= buffer.t.size;
855
856 rval = Tss2_Sys_SequenceUpdate(this->sys_context, sequence_handle,
857 &sessions_data_cmd, &buffer, 0);
858 if (rval != TPM_RC_SUCCESS)
859 {
860 DBG1(DBG_PTS,"%s Tss2_Sys_SequenceUpdate failed: 0x%06x",
861 LABEL, rval);
862 return FALSE;
863 }
864 }
865 buffer.t.size = 0;
866
867 rval = Tss2_Sys_SequenceComplete(this->sys_context, sequence_handle,
868 &sessions_data_cmd, &buffer, hierarchy,
869 &hash, &validation, 0);
870 if (rval != TPM_RC_SUCCESS)
871 {
872 DBG1(DBG_PTS,"%s Tss2_Sys_SequenceComplete failed: 0x%06x",
873 LABEL, rval);
874 return FALSE;
875 }
876 }
877
878 rval = Tss2_Sys_Sign(this->sys_context, handle, &sessions_data_cmd, &hash,
879 &sig_scheme, &validation, &sig, &sessions_data_rsp);
880 if (rval != TPM_RC_SUCCESS)
881 {
882 DBG1(DBG_PTS,"%s Tss2_Sys_Sign failed: 0x%06x", LABEL, rval);
883 return FALSE;
884 }
885
886 /* extract signature */
887 switch (scheme)
888 {
889 case SIGN_RSA_EMSA_PKCS1_SHA1:
890 case SIGN_RSA_EMSA_PKCS1_SHA2_256:
891 case SIGN_RSA_EMSA_PKCS1_SHA2_384:
892 case SIGN_RSA_EMSA_PKCS1_SHA2_512:
893 *signature = chunk_clone(
894 chunk_create(
895 sig.signature.rsassa.sig.t.buffer,
896 sig.signature.rsassa.sig.t.size));
897 break;
898 case SIGN_ECDSA_256:
899 case SIGN_ECDSA_384:
900 case SIGN_ECDSA_521:
901 *signature = chunk_cat("cc",
902 chunk_create(
903 sig.signature.ecdsa.signatureR.t.buffer,
904 sig.signature.ecdsa.signatureR.t.size),
905 chunk_create(
906 sig.signature.ecdsa.signatureS.t.buffer,
907 sig.signature.ecdsa.signatureS.t.size));
908 break;
909 case SIGN_ECDSA_WITH_SHA256_DER:
910 case SIGN_ECDSA_WITH_SHA384_DER:
911 case SIGN_ECDSA_WITH_SHA512_DER:
912 *signature = asn1_wrap(ASN1_SEQUENCE, "mm",
913 asn1_integer("c",
914 chunk_create(
915 sig.signature.ecdsa.signatureR.t.buffer,
916 sig.signature.ecdsa.signatureR.t.size)),
917 asn1_integer("c",
918 chunk_create(
919 sig.signature.ecdsa.signatureS.t.buffer,
920 sig.signature.ecdsa.signatureS.t.size)));
921 break;
922 default:
923 DBG1(DBG_PTS, "%s unsupported %N signature scheme",
924 LABEL, signature_scheme_names, scheme);
925 return FALSE;
926 };
927
928 return TRUE;
929}
930
2b233c8a
AS
931METHOD(tpm_tss_t, get_random, bool,
932 private_tpm_tss_tss2_t *this, size_t bytes, uint8_t *buffer)
933{
934 size_t len, random_len= sizeof(TPM2B_DIGEST)-2;
935 TPM2B_DIGEST random = { { random_len, } };
936 uint8_t *pos = buffer;
937 uint32_t rval;
938
939 while (bytes > 0)
940 {
941 len = min(bytes, random_len);
942
943 rval = Tss2_Sys_GetRandom(this->sys_context, NULL, len, &random, NULL);
944 if (rval != TSS2_RC_SUCCESS)
945 {
946 DBG1(DBG_PTS,"%s Tss2_Sys_GetRandom failed: 0x%06x", LABEL, rval);
947 return FALSE;
948 }
949 memcpy(pos, random.t.buffer, random.t.size);
950 pos += random.t.size;
951 bytes -= random.t.size;
952 }
953
954 return TRUE;
955}
956
e850d000
AS
957METHOD(tpm_tss_t, get_data, bool,
958 private_tpm_tss_tss2_t *this, uint32_t hierarchy, uint32_t handle,
959 chunk_t pin, chunk_t *data)
960{
961 uint16_t nv_size, nv_offset = 0;
962 uint32_t rval;
963
964 TPM2B_NAME nv_name = { { sizeof(TPM2B_NAME)-2, } };
965 TPM2B_NV_PUBLIC nv_public = { { 0, } };
966 TPM2B_MAX_NV_BUFFER nv_data = { { sizeof(TPM2B_MAX_NV_BUFFER)-2, } };
967 TPMS_AUTH_COMMAND session_data_cmd;
968 TPMS_AUTH_RESPONSE session_data_rsp;
969 TSS2_SYS_CMD_AUTHS sessions_data_cmd;
970 TSS2_SYS_RSP_AUTHS sessions_data_rsp;
971 TPMS_AUTH_COMMAND *session_data_cmd_array[1];
972 TPMS_AUTH_RESPONSE *session_data_rsp_array[1];
973
974 /* get size of NV object */
975 rval = Tss2_Sys_NV_ReadPublic(this->sys_context, handle, 0, &nv_public,
976 &nv_name, 0);
977 if (rval != TPM_RC_SUCCESS)
978 {
979 DBG1(DBG_PTS,"%s Tss2_Sys_NV_ReadPublic failed: 0x%06x", LABEL, rval);
980 return FALSE;
981 }
982 nv_size = nv_public.t.nvPublic.dataSize;
983 *data = chunk_alloc(nv_size);
984
985 /*prepare NV read session */
986 session_data_cmd_array[0] = &session_data_cmd;
987 session_data_rsp_array[0] = &session_data_rsp;
988
989 sessions_data_cmd.cmdAuths = &session_data_cmd_array[0];
990 sessions_data_rsp.rspAuths = &session_data_rsp_array[0];
991
992 sessions_data_cmd.cmdAuthsCount = 1;
993 sessions_data_rsp.rspAuthsCount = 1;
994
995 session_data_cmd.sessionHandle = TPM_RS_PW;
996 session_data_cmd.nonce.t.size = 0;
997 session_data_cmd.hmac.t.size = 0;
998
999 if (pin.len > 0)
1000 {
1001 session_data_cmd.hmac.t.size = min(sizeof(session_data_cmd.hmac.t) - 2,
1002 pin.len);
1003 memcpy(session_data_cmd.hmac.t.buffer, pin.ptr,
1004 session_data_cmd.hmac.t.size);
1005 }
1006 *( (uint8_t *)((void *)&session_data_cmd.sessionAttributes ) ) = 0;
1007
1008 /* read NV data an NV buffer block at a time */
1009 while (nv_size > 0)
1010 {
1011 rval = Tss2_Sys_NV_Read(this->sys_context, hierarchy, handle,
1012 &sessions_data_cmd, min(nv_size, MAX_NV_BUFFER_SIZE),
1013 nv_offset, &nv_data, &sessions_data_rsp);
1014
1015 if (rval != TPM_RC_SUCCESS)
1016 {
1017 DBG1(DBG_PTS,"%s Tss2_Sys_NV_Read failed: 0x%06x", LABEL, rval);
1018 chunk_free(data);
1019 return FALSE;
1020 }
1021 memcpy(data->ptr + nv_offset, nv_data.t.buffer, nv_data.t.size);
1022 nv_offset += nv_data.t.size;
1023 nv_size -= nv_data.t.size;
1024 }
1025
1026 return TRUE;
1027}
1028
c08753bd
AS
1029METHOD(tpm_tss_t, destroy, void,
1030 private_tpm_tss_tss2_t *this)
1031{
1032 finalize_context(this);
1033 free(this);
1034}
1035
1036/**
1037 * See header
1038 */
1039tpm_tss_t *tpm_tss_tss2_create()
1040{
1041 private_tpm_tss_tss2_t *this;
1042 bool available;
1043
1044 INIT(this,
1045 .public = {
1046 .get_version = _get_version,
fedc6769 1047 .get_version_info = _get_version_info,
c08753bd
AS
1048 .generate_aik = _generate_aik,
1049 .get_public = _get_public,
30d4989a
AS
1050 .read_pcr = _read_pcr,
1051 .extend_pcr = _extend_pcr,
1052 .quote = _quote,
e8736028 1053 .sign = _sign,
2b233c8a 1054 .get_random = _get_random,
e850d000 1055 .get_data = _get_data,
c08753bd
AS
1056 .destroy = _destroy,
1057 },
1058 );
1059
eab650d6
AS
1060 available = initialize_tcti_tabrmd_context(this);
1061 if (!available)
1062 {
1063 available = initialize_tcti_socket_context(this);
1064 }
1065 if (available)
1066 {
1067 available = initialize_sys_context(this);
1068 }
c08753bd
AS
1069 DBG1(DBG_PTS, "TPM 2.0 via TSS2 %savailable", available ? "" : "not ");
1070
1071 if (!available)
1072 {
1073 destroy(this);
1074 return NULL;
1075 }
1076 return &this->public;
1077}
1078
1079#else /* TSS_TSS2 */
1080
1081tpm_tss_t *tpm_tss_tss2_create()
1082{
1083 return NULL;
1084}
1085
1086#endif /* TSS_TSS2 */
1087
1088