Implement signatures with private keys bound to TPM 2.0
[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 #include <tcti_socket.h>
27
28 #define LABEL "TPM 2.0 -"
29
30 typedef struct private_tpm_tss_tss2_t private_tpm_tss_tss2_t;
31
32 /**
33 * Private data of an tpm_tss_tss2_t object.
34 */
35 struct private_tpm_tss_tss2_t {
36
37 /**
38 * Public tpm_tss_tss2_t interface.
39 */
40 tpm_tss_t public;
41
42 /**
43 * TCTI context
44 */
45 TSS2_TCTI_CONTEXT *tcti_context;
46
47 /**
48 * SYS context
49 */
50 TSS2_SYS_CONTEXT *sys_context;
51
52 /**
53 * Number of supported algorithms
54 */
55 size_t supported_algs_count;
56
57 /**
58 * List of supported algorithms
59 */
60 TPM_ALG_ID supported_algs[TPM_PT_ALGORITHM_SET];
61 };
62
63 /**
64 * Some symbols required by libtctisocket
65 */
66 FILE *outFp;
67 uint8_t simulator = 1;
68
69 int TpmClientPrintf (uint8_t type, const char *format, ...)
70 {
71 return 0;
72 }
73
74 /**
75 * Convert hash algorithm to TPM_ALG_ID
76 */
77 static TPM_ALG_ID hash_alg_to_tpm_alg_id(hash_algorithm_t alg)
78 {
79 switch (alg)
80 {
81 case HASH_SHA1:
82 return TPM_ALG_SHA1;
83 case HASH_SHA256:
84 return TPM_ALG_SHA256;
85 case HASH_SHA384:
86 return TPM_ALG_SHA384;
87 case HASH_SHA512:
88 return TPM_ALG_SHA512;
89 default:
90 return TPM_ALG_ERROR;
91 }
92 }
93
94 /**
95 * Convert TPM_ALG_ID to hash algorithm
96 */
97 static hash_algorithm_t hash_alg_from_tpm_alg_id(TPM_ALG_ID alg)
98 {
99 switch (alg)
100 {
101 case TPM_ALG_SHA1:
102 return HASH_SHA1;
103 case TPM_ALG_SHA256:
104 return HASH_SHA256;
105 case TPM_ALG_SHA384:
106 return HASH_SHA384;
107 case TPM_ALG_SHA512:
108 return HASH_SHA512;
109 default:
110 return HASH_UNKNOWN;
111 }
112 }
113
114 /**
115 * Check if an algorithm given by its TPM_ALG_ID is supported by the TPM
116 */
117 static bool is_supported_alg(private_tpm_tss_tss2_t *this, TPM_ALG_ID alg_id)
118 {
119 int i;
120
121 if (alg_id == TPM_ALG_ERROR)
122 {
123 return FALSE;
124 }
125
126 for (i = 0; i < this->supported_algs_count; i++)
127 {
128 if (this->supported_algs[i] == alg_id)
129 {
130 return TRUE;
131 }
132 }
133
134 return FALSE;
135 }
136
137 /**
138 * Get a list of supported algorithms
139 */
140 static bool get_algs_capability(private_tpm_tss_tss2_t *this)
141 {
142 TPMS_CAPABILITY_DATA cap_data;
143 TPMI_YES_NO more_data;
144 TPM_ALG_ID alg;
145 uint32_t rval, i;
146 size_t len = BUF_LEN;
147 char buf[BUF_LEN];
148 char *pos = buf;
149 int written;
150
151 /* get supported algorithms */
152 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ALGS,
153 0, TPM_PT_ALGORITHM_SET, &more_data, &cap_data, 0);
154 if (rval != TPM_RC_SUCCESS)
155 {
156 DBG1(DBG_PTS, "%s GetCapability failed for TPM_CAP_ALGS: 0x%06x",
157 LABEL, rval);
158 return FALSE;
159 }
160
161 /* Number of supported algorithms */
162 this->supported_algs_count = cap_data.data.algorithms.count;
163
164 /* store and print supported algorithms */
165 for (i = 0; i < this->supported_algs_count; i++)
166 {
167 alg = cap_data.data.algorithms.algProperties[i].alg;
168 this->supported_algs[i] = alg;
169
170 written = snprintf(pos, len, " %N", tpm_alg_id_names, alg);
171 if (written < 0 || written >= len)
172 {
173 break;
174 }
175 pos += written;
176 len -= written;
177 }
178 DBG2(DBG_PTS, "%s algorithms:%s", LABEL, buf);
179
180 /* get supported ECC curves */
181 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ECC_CURVES,
182 0, TPM_PT_LOADED_CURVES, &more_data, &cap_data, 0);
183 if (rval != TPM_RC_SUCCESS)
184 {
185 DBG1(DBG_PTS, "%s GetCapability failed for TPM_ECC_CURVES: 0x%06x",
186 LABEL, rval);
187 return FALSE;
188 }
189
190 /* reset print buffer */
191 pos = buf;
192 len = BUF_LEN;
193
194 /* print supported ECC curves */
195 for (i = 0; i < cap_data.data.eccCurves.count; i++)
196 {
197 written = snprintf(pos, len, " %N", tpm_ecc_curve_names,
198 cap_data.data.eccCurves.eccCurves[i]);
199 if (written < 0 || written >= len)
200 {
201 break;
202 }
203 pos += written;
204 len -= written;
205 }
206 DBG2(DBG_PTS, "%s ECC curves:%s", LABEL, buf);
207
208 return TRUE;
209 }
210
211 /**
212 * Initialize TSS context
213 */
214 static bool initialize_context(private_tpm_tss_tss2_t *this)
215 {
216 size_t tcti_context_size;
217 uint32_t sys_context_size;
218 uint32_t rval;
219
220 TCTI_SOCKET_CONF rm_if_config = { DEFAULT_HOSTNAME,
221 DEFAULT_RESMGR_TPM_PORT
222 };
223
224 TSS2_ABI_VERSION abi_version = { TSSWG_INTEROP,
225 TSS_SAPI_FIRST_FAMILY,
226 TSS_SAPI_FIRST_LEVEL,
227 TSS_SAPI_FIRST_VERSION
228 };
229
230 /* determine size of tcti context */
231 rval = InitSocketTcti(NULL, &tcti_context_size, &rm_if_config, 0);
232 if (rval != TSS2_RC_SUCCESS)
233 {
234 DBG1(DBG_PTS, "%s could not get tcti_context size: 0x%06x",
235 LABEL, rval);
236 return FALSE;
237 }
238
239 /* allocate memory for tcti context */
240 this->tcti_context = (TSS2_TCTI_CONTEXT*)malloc(tcti_context_size);
241
242 /* initialize tcti context */
243 rval = InitSocketTcti(this->tcti_context, &tcti_context_size,
244 &rm_if_config, 0);
245 if (rval != TSS2_RC_SUCCESS)
246 {
247 DBG1(DBG_PTS, "%s could not get tcti_context: 0x%06x",
248 LABEL, rval);
249 return FALSE;
250 }
251
252 /* determine size of sys context */
253 sys_context_size = Tss2_Sys_GetContextSize(0);
254
255 /* allocate memory for sys context */
256 this->sys_context = malloc(sys_context_size);
257
258 /* initialize sys context */
259 rval = Tss2_Sys_Initialize(this->sys_context, sys_context_size,
260 this->tcti_context, &abi_version);
261 if (rval != TSS2_RC_SUCCESS)
262 {
263 DBG1(DBG_PTS, "%s could not get sys_context: 0x%06x",
264 LABEL, rval);
265 return FALSE;
266 }
267
268 /* get a list of supported algorithms and ECC curves */
269 return get_algs_capability(this);
270 }
271
272 /**
273 * Finalize TSS context
274 */
275 static void finalize_context(private_tpm_tss_tss2_t *this)
276 {
277 if (this->tcti_context)
278 {
279 tss2_tcti_finalize(this->tcti_context);
280 free(this->tcti_context);
281 }
282 if (this->sys_context)
283 {
284 Tss2_Sys_Finalize(this->sys_context);
285 free(this->sys_context);
286 }
287 }
288
289 METHOD(tpm_tss_t, get_version, tpm_version_t,
290 private_tpm_tss_tss2_t *this)
291 {
292 return TPM_VERSION_2_0;
293 }
294
295 METHOD(tpm_tss_t, get_version_info, chunk_t,
296 private_tpm_tss_tss2_t *this)
297 {
298 return chunk_empty;
299 }
300
301 /**
302 * read the public key portion of a TSS 2.0 AIK key from NVRAM
303 */
304 bool read_public(private_tpm_tss_tss2_t *this, TPMI_DH_OBJECT handle,
305 TPM2B_PUBLIC *public)
306 {
307 uint32_t rval;
308
309 TPM2B_NAME name = { { sizeof(TPM2B_NAME)-2, } };
310 TPM2B_NAME qualified_name = { { sizeof(TPM2B_NAME)-2, } };
311
312 TPMS_AUTH_RESPONSE session_data;
313 TSS2_SYS_RSP_AUTHS sessions_data;
314 TPMS_AUTH_RESPONSE *session_data_array[1];
315
316 session_data_array[0] = &session_data;
317 sessions_data.rspAuths = &session_data_array[0];
318 sessions_data.rspAuthsCount = 1;
319
320 /* read public key for a given object handle from TPM 2.0 NVRAM */
321 rval = Tss2_Sys_ReadPublic(this->sys_context, handle, 0, public, &name,
322 &qualified_name, &sessions_data);
323 if (rval != TPM_RC_SUCCESS)
324 {
325 DBG1(DBG_PTS, "%s could not read public key from handle 0x%08x: 0x%06x",
326 LABEL, handle, rval);
327 return FALSE;
328 }
329 return TRUE;
330 }
331
332 METHOD(tpm_tss_t, generate_aik, bool,
333 private_tpm_tss_tss2_t *this, chunk_t ca_modulus, chunk_t *aik_blob,
334 chunk_t *aik_pubkey, chunk_t *identity_req)
335 {
336 return FALSE;
337 }
338
339 METHOD(tpm_tss_t, get_public, chunk_t,
340 private_tpm_tss_tss2_t *this, uint32_t handle)
341 {
342 TPM2B_PUBLIC public = { { 0, } };
343 TPM_ALG_ID sig_alg, digest_alg;
344 chunk_t aik_blob, aik_pubkey = chunk_empty;
345
346 if (!read_public(this, handle, &public))
347 {
348 return chunk_empty;
349 }
350
351 aik_blob = chunk_create((u_char*)&public, sizeof(public));
352 DBG3(DBG_LIB, "%s AIK public key blob: %B", LABEL, &aik_blob);
353
354 /* convert TSS 2.0 AIK public key blot into PKCS#1 format */
355 switch (public.t.publicArea.type)
356 {
357 case TPM_ALG_RSA:
358 {
359 TPM2B_PUBLIC_KEY_RSA *rsa;
360 TPMT_RSA_SCHEME *scheme;
361 chunk_t aik_exponent, aik_modulus;
362
363 scheme = &public.t.publicArea.parameters.rsaDetail.scheme;
364 sig_alg = scheme->scheme;
365 digest_alg = scheme->details.anySig.hashAlg;
366
367 rsa = &public.t.publicArea.unique.rsa;
368 aik_modulus = chunk_create(rsa->t.buffer, rsa->t.size);
369 aik_exponent = chunk_from_chars(0x01, 0x00, 0x01);
370
371 /* subjectPublicKeyInfo encoding of AIK RSA key */
372 if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER,
373 NULL, &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus,
374 CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END))
375 {
376 DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of AIK key "
377 "failed", LABEL);
378 }
379 break;
380 }
381 case TPM_ALG_ECC:
382 {
383 TPMS_ECC_POINT *ecc;
384 TPMT_ECC_SCHEME *scheme;
385 chunk_t ecc_point;
386 uint8_t *pos;
387
388 scheme = &public.t.publicArea.parameters.eccDetail.scheme;
389 sig_alg = scheme->scheme;
390 digest_alg = scheme->details.anySig.hashAlg;
391
392 ecc = &public.t.publicArea.unique.ecc;
393
394 /* allocate space for bit string */
395 pos = asn1_build_object(&ecc_point, ASN1_BIT_STRING,
396 2 + ecc->x.t.size + ecc->y.t.size);
397 /* bit string length is a multiple of octets */
398 *pos++ = 0x00;
399 /* uncompressed ECC point format */
400 *pos++ = 0x04;
401 /* copy x coordinate of ECC point */
402 memcpy(pos, ecc->x.t.buffer, ecc->x.t.size);
403 pos += ecc->x.t.size;
404 /* copy y coordinate of ECC point */
405 memcpy(pos, ecc->y.t.buffer, ecc->y.t.size);
406 /* subjectPublicKeyInfo encoding of AIK ECC key */
407 aik_pubkey = asn1_wrap(ASN1_SEQUENCE, "mm",
408 asn1_wrap(ASN1_SEQUENCE, "mm",
409 asn1_build_known_oid(OID_EC_PUBLICKEY),
410 asn1_build_known_oid(ecc->x.t.size == 32 ?
411 OID_PRIME256V1 : OID_SECT384R1)),
412 ecc_point);
413 break;
414 }
415 default:
416 DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL);
417 return chunk_empty;
418 }
419 DBG1(DBG_PTS, "AIK signature algorithm is %N with %N hash",
420 tpm_alg_id_names, sig_alg, tpm_alg_id_names, digest_alg);
421 return aik_pubkey;
422 }
423
424 /**
425 * Configure a PCR Selection assuming a maximum of 24 registers
426 */
427 static bool init_pcr_selection(private_tpm_tss_tss2_t *this, uint32_t pcrs,
428 hash_algorithm_t alg, TPML_PCR_SELECTION *pcr_sel)
429 {
430 TPM_ALG_ID alg_id;
431 uint32_t pcr;
432
433 /* check if hash algorithm is supported by TPM */
434 alg_id = hash_alg_to_tpm_alg_id(alg);
435 if (!is_supported_alg(this, alg_id))
436 {
437 DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM",
438 LABEL, hash_algorithm_short_names, alg);
439 return FALSE;
440 }
441
442 /* initialize the PCR Selection structure,*/
443 pcr_sel->count = 1;
444 pcr_sel->pcrSelections[0].hash = alg_id;
445 pcr_sel->pcrSelections[0].sizeofSelect = 3;
446 pcr_sel->pcrSelections[0].pcrSelect[0] = 0;
447 pcr_sel->pcrSelections[0].pcrSelect[1] = 0;
448 pcr_sel->pcrSelections[0].pcrSelect[2] = 0;
449
450 /* set the selected PCRs */
451 for (pcr = 0; pcr < PLATFORM_PCR; pcr++)
452 {
453 if (pcrs & (1 << pcr))
454 {
455 pcr_sel->pcrSelections[0].pcrSelect[pcr / 8] |= ( 1 << (pcr % 8) );
456 }
457 }
458 return TRUE;
459 }
460
461 METHOD(tpm_tss_t, read_pcr, bool,
462 private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
463 hash_algorithm_t alg)
464 {
465 TPML_PCR_SELECTION pcr_selection;
466 TPML_DIGEST pcr_values;
467
468 uint32_t pcr_update_counter, rval;
469 uint8_t *pcr_value_ptr;
470 size_t pcr_value_len;
471
472 if (pcr_num >= PLATFORM_PCR)
473 {
474 DBG1(DBG_PTS, "%s maximum number of supported PCR is %d",
475 LABEL, PLATFORM_PCR);
476 return FALSE;
477 }
478
479 if (!init_pcr_selection(this, (1 << pcr_num), alg, &pcr_selection))
480 {
481 return FALSE;
482 }
483
484 /* initialize the PCR Digest structure */
485 memset(&pcr_values, 0, sizeof(TPML_DIGEST));
486
487 /* read the PCR value */
488 rval = Tss2_Sys_PCR_Read(this->sys_context, 0, &pcr_selection,
489 &pcr_update_counter, &pcr_selection, &pcr_values, 0);
490 if (rval != TPM_RC_SUCCESS)
491 {
492 DBG1(DBG_PTS, "%s PCR bank could not be read: 0x%60x",
493 LABEL, rval);
494 return FALSE;
495 }
496 pcr_value_ptr = (uint8_t *)pcr_values.digests[0].t.buffer;
497 pcr_value_len = (size_t) pcr_values.digests[0].t.size;
498
499 *pcr_value = chunk_clone(chunk_create(pcr_value_ptr, pcr_value_len));
500
501 return TRUE;
502 }
503
504 METHOD(tpm_tss_t, extend_pcr, bool,
505 private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
506 chunk_t data, hash_algorithm_t alg)
507 {
508 /* TODO */
509 return FALSE;
510 }
511
512 METHOD(tpm_tss_t, quote, bool,
513 private_tpm_tss_tss2_t *this, uint32_t aik_handle, uint32_t pcr_sel,
514 hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t *quote_mode,
515 tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig)
516 {
517 chunk_t quoted_chunk, qualified_signer, extra_data, clock_info,
518 firmware_version, pcr_select, pcr_digest;
519 hash_algorithm_t pcr_digest_alg;
520 bio_reader_t *reader;
521 uint32_t rval;
522
523 TPM2B_DATA qualifying_data;
524 TPML_PCR_SELECTION pcr_selection;
525 TPM2B_ATTEST quoted = { { sizeof(TPM2B_ATTEST)-2, } };
526 TPMT_SIG_SCHEME scheme;
527 TPMT_SIGNATURE sig;
528 TPMI_ALG_HASH hash_alg;
529 TPMS_AUTH_COMMAND session_data_cmd;
530 TPMS_AUTH_RESPONSE session_data_rsp;
531 TSS2_SYS_CMD_AUTHS sessions_data_cmd;
532 TSS2_SYS_RSP_AUTHS sessions_data_rsp;
533 TPMS_AUTH_COMMAND *session_data_cmd_array[1];
534 TPMS_AUTH_RESPONSE *session_data_rsp_array[1];
535
536 session_data_cmd_array[0] = &session_data_cmd;
537 session_data_rsp_array[0] = &session_data_rsp;
538
539 sessions_data_cmd.cmdAuths = &session_data_cmd_array[0];
540 sessions_data_rsp.rspAuths = &session_data_rsp_array[0];
541
542 sessions_data_cmd.cmdAuthsCount = 1;
543 sessions_data_rsp.rspAuthsCount = 1;
544
545 session_data_cmd.sessionHandle = TPM_RS_PW;
546 session_data_cmd.hmac.t.size = 0;
547 session_data_cmd.nonce.t.size = 0;
548
549 *( (uint8_t *)((void *)&session_data_cmd.sessionAttributes ) ) = 0;
550
551 qualifying_data.t.size = data.len;
552 memcpy(qualifying_data.t.buffer, data.ptr, data.len);
553
554 scheme.scheme = TPM_ALG_NULL;
555 memset(&sig, 0x00, sizeof(sig));
556
557 /* set Quote mode */
558 *quote_mode = TPM_QUOTE_TPM2;
559
560 if (!init_pcr_selection(this, pcr_sel, alg, &pcr_selection))
561 {
562 return FALSE;
563 }
564
565 rval = Tss2_Sys_Quote(this->sys_context, aik_handle, &sessions_data_cmd,
566 &qualifying_data, &scheme, &pcr_selection, &quoted,
567 &sig, &sessions_data_rsp);
568 if (rval != TPM_RC_SUCCESS)
569 {
570 DBG1(DBG_PTS,"%s Tss2_Sys_Quote failed: 0x%06x", LABEL, rval);
571 return FALSE;
572 }
573 quoted_chunk = chunk_create(quoted.t.attestationData, quoted.t.size);
574
575 reader = bio_reader_create(chunk_skip(quoted_chunk, 6));
576 if (!reader->read_data16(reader, &qualified_signer) ||
577 !reader->read_data16(reader, &extra_data) ||
578 !reader->read_data (reader, 17, &clock_info) ||
579 !reader->read_data (reader, 8, &firmware_version) ||
580 !reader->read_data (reader, 10, &pcr_select) ||
581 !reader->read_data16(reader, &pcr_digest))
582 {
583 DBG1(DBG_PTS, "%s parsing of quoted struct failed", LABEL);
584 reader->destroy(reader);
585 return FALSE;
586 }
587 reader->destroy(reader);
588
589 DBG2(DBG_PTS, "PCR Composite digest: %B", &pcr_digest);
590 DBG2(DBG_PTS, "TPM Quote Info: %B", &quoted_chunk);
591 DBG2(DBG_PTS, "qualifiedSigner: %B", &qualified_signer);
592 DBG2(DBG_PTS, "extraData: %B", &extra_data);
593 DBG2(DBG_PTS, "clockInfo: %B", &clock_info);
594 DBG2(DBG_PTS, "firmwareVersion: %B", &firmware_version);
595 DBG2(DBG_PTS, "pcrSelect: %B", &pcr_select);
596
597 /* extract signature */
598 switch (sig.sigAlg)
599 {
600 case TPM_ALG_RSASSA:
601 case TPM_ALG_RSAPSS:
602 *quote_sig = chunk_clone(
603 chunk_create(
604 sig.signature.rsassa.sig.t.buffer,
605 sig.signature.rsassa.sig.t.size));
606 hash_alg = sig.signature.rsassa.hash;
607 break;
608 case TPM_ALG_ECDSA:
609 case TPM_ALG_ECDAA:
610 case TPM_ALG_SM2:
611 case TPM_ALG_ECSCHNORR:
612 *quote_sig = chunk_cat("cc",
613 chunk_create(
614 sig.signature.ecdsa.signatureR.t.buffer,
615 sig.signature.ecdsa.signatureR.t.size),
616 chunk_create(
617 sig.signature.ecdsa.signatureS.t.buffer,
618 sig.signature.ecdsa.signatureS.t.size));
619 hash_alg = sig.signature.ecdsa.hash;
620 break;
621 default:
622 DBG1(DBG_PTS, "%s unsupported %N signature algorithm",
623 LABEL, tpm_alg_id_names, sig.sigAlg);
624 return FALSE;
625 };
626
627 DBG2(DBG_PTS, "PCR digest algorithm is %N", tpm_alg_id_names, hash_alg);
628 pcr_digest_alg = hash_alg_from_tpm_alg_id(hash_alg);
629
630 DBG2(DBG_PTS, "TPM Quote Signature: %B", quote_sig);
631
632 /* Create and initialize Quote Info object */
633 *quote_info = tpm_tss_quote_info_create(*quote_mode, pcr_digest_alg,
634 pcr_digest);
635 (*quote_info)->set_tpm2_info(*quote_info, qualified_signer, clock_info,
636 pcr_select);
637 (*quote_info)->set_version_info(*quote_info, firmware_version);
638
639 return TRUE;
640 }
641
642 METHOD(tpm_tss_t, sign, bool,
643 private_tpm_tss_tss2_t *this, uint32_t hierarchy, uint32_t handle,
644 signature_scheme_t scheme, chunk_t data, chunk_t pin, chunk_t *signature)
645 {
646 key_type_t key_type;
647 hash_algorithm_t hash_alg;
648 uint32_t rval;
649
650 TPM_ALG_ID alg_id;
651 TPM2B_MAX_BUFFER buffer;
652 TPM2B_DIGEST hash = { { sizeof(TPM2B_DIGEST)-2, } };
653 TPMT_TK_HASHCHECK validation;
654 TPM2B_PUBLIC public = { { 0, } };
655 TPMT_SIG_SCHEME sig_scheme;
656 TPMT_SIGNATURE sig;
657 TPMS_AUTH_COMMAND session_data_cmd;
658 TPMS_AUTH_RESPONSE session_data_rsp;
659 TSS2_SYS_CMD_AUTHS sessions_data_cmd;
660 TSS2_SYS_RSP_AUTHS sessions_data_rsp;
661 TPMS_AUTH_COMMAND *session_data_cmd_array[1];
662 TPMS_AUTH_RESPONSE *session_data_rsp_array[1];
663
664 session_data_cmd_array[0] = &session_data_cmd;
665 session_data_rsp_array[0] = &session_data_rsp;
666
667 sessions_data_cmd.cmdAuths = &session_data_cmd_array[0];
668 sessions_data_rsp.rspAuths = &session_data_rsp_array[0];
669
670 sessions_data_cmd.cmdAuthsCount = 1;
671 sessions_data_rsp.rspAuthsCount = 1;
672
673 session_data_cmd.sessionHandle = TPM_RS_PW;
674 session_data_cmd.nonce.t.size = 0;
675 session_data_cmd.hmac.t.size = 0;
676
677 if (pin.len > 0)
678 {
679 session_data_cmd.hmac.t.size = min(sizeof(session_data_cmd.hmac.t) - 2,
680 pin.len);
681 memcpy(session_data_cmd.hmac.t.buffer, pin.ptr,
682 session_data_cmd.hmac.t.size);
683 }
684 *( (uint8_t *)((void *)&session_data_cmd.sessionAttributes ) ) = 0;
685
686 key_type = key_type_from_signature_scheme(scheme);
687 hash_alg = hasher_from_signature_scheme(scheme);
688
689 /* Check if hash algorithm is supported by TPM */
690 alg_id = hash_alg_to_tpm_alg_id(hash_alg);
691 if (!is_supported_alg(this, alg_id))
692 {
693 DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM",
694 LABEL, hash_algorithm_short_names, hash_alg);
695 return FALSE;
696 }
697
698 /* Get public key */
699 if (!read_public(this, handle, &public))
700 {
701 return FALSE;
702 }
703
704 if (key_type == KEY_RSA && public.t.publicArea.type == TPM_ALG_RSA)
705 {
706 sig_scheme.scheme = TPM_ALG_RSASSA;
707 sig_scheme.details.rsassa.hashAlg = alg_id;
708 }
709 else if (key_type == KEY_ECDSA && public.t.publicArea.type == TPM_ALG_ECC)
710 {
711 sig_scheme.scheme = TPM_ALG_ECDSA;
712 sig_scheme.details.ecdsa.hashAlg = alg_id;
713
714 }
715 else
716 {
717 DBG1(DBG_PTS, "%s signature scheme %N not supported by TPM key",
718 LABEL, signature_scheme_names, scheme);
719 return FALSE;
720 }
721
722 if (data.len <= MAX_DIGEST_BUFFER)
723 {
724 memcpy(buffer.t.buffer, data.ptr, data.len);
725 buffer.t.size = data.len;
726
727 rval = Tss2_Sys_Hash(this->sys_context, 0, &buffer, alg_id, hierarchy,
728 &hash, &validation, 0);
729 if (rval != TPM_RC_SUCCESS)
730 {
731 DBG1(DBG_PTS,"%s Tss2_Sys_Hash failed: 0x%06x", LABEL, rval);
732 return FALSE;
733 }
734 }
735 else
736 {
737 TPMI_DH_OBJECT sequence_handle;
738 TPM2B_AUTH null_auth;
739
740 null_auth.t.size = 0;
741 rval = Tss2_Sys_HashSequenceStart(this->sys_context, 0, &null_auth,
742 alg_id, &sequence_handle, 0);
743 if (rval != TPM_RC_SUCCESS)
744 {
745 DBG1(DBG_PTS,"%s Tss2_Sys_HashSequenceStart failed: 0x%06x",
746 LABEL, rval);
747 return FALSE;
748 }
749
750 while (data.len > 0)
751 {
752 buffer.t.size = min(data.len, MAX_DIGEST_BUFFER);
753 memcpy(buffer.t.buffer, data.ptr, buffer.t.size);
754 data.ptr += buffer.t.size;
755 data.len -= buffer.t.size;
756
757 rval = Tss2_Sys_SequenceUpdate(this->sys_context, sequence_handle,
758 &sessions_data_cmd, &buffer, 0);
759 if (rval != TPM_RC_SUCCESS)
760 {
761 DBG1(DBG_PTS,"%s Tss2_Sys_SequenceUpdate failed: 0x%06x",
762 LABEL, rval);
763 return FALSE;
764 }
765 }
766 buffer.t.size = 0;
767
768 rval = Tss2_Sys_SequenceComplete(this->sys_context, sequence_handle,
769 &sessions_data_cmd, &buffer, hierarchy,
770 &hash, &validation, 0);
771 if (rval != TPM_RC_SUCCESS)
772 {
773 DBG1(DBG_PTS,"%s Tss2_Sys_SequenceComplete failed: 0x%06x",
774 LABEL, rval);
775 return FALSE;
776 }
777 }
778
779 rval = Tss2_Sys_Sign(this->sys_context, handle, &sessions_data_cmd, &hash,
780 &sig_scheme, &validation, &sig, &sessions_data_rsp);
781 if (rval != TPM_RC_SUCCESS)
782 {
783 DBG1(DBG_PTS,"%s Tss2_Sys_Sign failed: 0x%06x", LABEL, rval);
784 return FALSE;
785 }
786
787 /* extract signature */
788 switch (scheme)
789 {
790 case SIGN_RSA_EMSA_PKCS1_SHA1:
791 case SIGN_RSA_EMSA_PKCS1_SHA2_256:
792 case SIGN_RSA_EMSA_PKCS1_SHA2_384:
793 case SIGN_RSA_EMSA_PKCS1_SHA2_512:
794 *signature = chunk_clone(
795 chunk_create(
796 sig.signature.rsassa.sig.t.buffer,
797 sig.signature.rsassa.sig.t.size));
798 break;
799 case SIGN_ECDSA_256:
800 case SIGN_ECDSA_384:
801 case SIGN_ECDSA_521:
802 *signature = chunk_cat("cc",
803 chunk_create(
804 sig.signature.ecdsa.signatureR.t.buffer,
805 sig.signature.ecdsa.signatureR.t.size),
806 chunk_create(
807 sig.signature.ecdsa.signatureS.t.buffer,
808 sig.signature.ecdsa.signatureS.t.size));
809 break;
810 case SIGN_ECDSA_WITH_SHA256_DER:
811 case SIGN_ECDSA_WITH_SHA384_DER:
812 case SIGN_ECDSA_WITH_SHA512_DER:
813 *signature = asn1_wrap(ASN1_SEQUENCE, "mm",
814 asn1_integer("c",
815 chunk_create(
816 sig.signature.ecdsa.signatureR.t.buffer,
817 sig.signature.ecdsa.signatureR.t.size)),
818 asn1_integer("c",
819 chunk_create(
820 sig.signature.ecdsa.signatureS.t.buffer,
821 sig.signature.ecdsa.signatureS.t.size)));
822 break;
823 default:
824 DBG1(DBG_PTS, "%s unsupported %N signature scheme",
825 LABEL, signature_scheme_names, scheme);
826 return FALSE;
827 };
828
829 return TRUE;
830 }
831
832 METHOD(tpm_tss_t, destroy, void,
833 private_tpm_tss_tss2_t *this)
834 {
835 finalize_context(this);
836 free(this);
837 }
838
839 /**
840 * See header
841 */
842 tpm_tss_t *tpm_tss_tss2_create()
843 {
844 private_tpm_tss_tss2_t *this;
845 bool available;
846
847 INIT(this,
848 .public = {
849 .get_version = _get_version,
850 .get_version_info = _get_version_info,
851 .generate_aik = _generate_aik,
852 .get_public = _get_public,
853 .read_pcr = _read_pcr,
854 .extend_pcr = _extend_pcr,
855 .quote = _quote,
856 .sign = _sign,
857 .destroy = _destroy,
858 },
859 );
860
861 available = initialize_context(this);
862 DBG1(DBG_PTS, "TPM 2.0 via TSS2 %savailable", available ? "" : "not ");
863
864 if (!available)
865 {
866 destroy(this);
867 return NULL;
868 }
869 return &this->public;
870 }
871
872 #else /* TSS_TSS2 */
873
874 tpm_tss_t *tpm_tss_tss2_create()
875 {
876 return NULL;
877 }
878
879 #endif /* TSS_TSS2 */
880
881