]>
Commit | Line | Data |
---|---|---|
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 AS |
24 | |
25 | #include <tss2/tpm20.h> | |
26 | #include <tcti/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 | ||
bc67802a AS |
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]; | |
c08753bd AS |
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 | ||
bc67802a AS |
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 | ||
721ed31b AS |
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 | ||
bc67802a AS |
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 | ||
8301dc85 AS |
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; | |
bc67802a | 144 | TPM_ALG_ID alg; |
8301dc85 AS |
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 | ||
bc67802a AS |
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++) | |
8301dc85 | 166 | { |
bc67802a AS |
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); | |
8301dc85 AS |
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 | ||
c08753bd AS |
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 | } | |
8301dc85 AS |
267 | |
268 | /* get a list of supported algorithms and ECC curves */ | |
269 | return get_algs_capability(this); | |
c08753bd AS |
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 | TeardownSocketTcti(this->tcti_context); | |
280 | } | |
281 | if (this->sys_context) | |
282 | { | |
283 | Tss2_Sys_Finalize(this->sys_context); | |
284 | free(this->sys_context); | |
285 | } | |
286 | } | |
287 | ||
288 | METHOD(tpm_tss_t, get_version, tpm_version_t, | |
289 | private_tpm_tss_tss2_t *this) | |
290 | { | |
291 | return TPM_VERSION_2_0; | |
292 | } | |
293 | ||
fedc6769 AS |
294 | METHOD(tpm_tss_t, get_version_info, chunk_t, |
295 | private_tpm_tss_tss2_t *this) | |
296 | { | |
297 | return chunk_empty; | |
298 | } | |
299 | ||
c08753bd AS |
300 | /** |
301 | * read the public key portion of a TSS 2.0 AIK key from NVRAM | |
302 | */ | |
303 | bool read_public(private_tpm_tss_tss2_t *this, TPMI_DH_OBJECT handle, | |
304 | TPM2B_PUBLIC *public) | |
305 | { | |
306 | uint32_t rval; | |
307 | ||
308 | TPM2B_NAME name = { { sizeof(TPM2B_NAME)-2, } }; | |
309 | TPM2B_NAME qualified_name = { { sizeof(TPM2B_NAME)-2, } }; | |
310 | ||
311 | TPMS_AUTH_RESPONSE session_data; | |
312 | TSS2_SYS_RSP_AUTHS sessions_data; | |
313 | TPMS_AUTH_RESPONSE *session_data_array[1]; | |
314 | ||
315 | session_data_array[0] = &session_data; | |
316 | sessions_data.rspAuths = &session_data_array[0]; | |
317 | sessions_data.rspAuthsCount = 1; | |
318 | ||
319 | /* always send simulator platform command, ignored by true RM */ | |
320 | PlatformCommand(this->tcti_context ,MS_SIM_POWER_ON ); | |
321 | PlatformCommand(this->tcti_context, MS_SIM_NV_ON ); | |
322 | ||
323 | /* read public key for a given object handle from TPM 2.0 NVRAM */ | |
324 | rval = Tss2_Sys_ReadPublic(this->sys_context, handle, 0, public, &name, | |
325 | &qualified_name, &sessions_data); | |
326 | ||
327 | PlatformCommand(this->tcti_context, MS_SIM_POWER_OFF); | |
328 | ||
329 | if (rval != TPM_RC_SUCCESS) | |
330 | { | |
331 | DBG1(DBG_PTS, "%s could not read public key from handle 0x%08x: 0x%06x", | |
332 | LABEL, handle, rval); | |
333 | return FALSE; | |
334 | } | |
335 | return TRUE; | |
336 | } | |
337 | ||
338 | METHOD(tpm_tss_t, generate_aik, bool, | |
339 | private_tpm_tss_tss2_t *this, chunk_t ca_modulus, chunk_t *aik_blob, | |
340 | chunk_t *aik_pubkey, chunk_t *identity_req) | |
341 | { | |
342 | return FALSE; | |
343 | } | |
344 | ||
345 | METHOD(tpm_tss_t, get_public, chunk_t, | |
346 | private_tpm_tss_tss2_t *this, uint32_t handle) | |
347 | { | |
348 | TPM2B_PUBLIC public = { { 0, } }; | |
2343c483 | 349 | TPM_ALG_ID sig_alg, digest_alg; |
c08753bd AS |
350 | chunk_t aik_blob, aik_pubkey = chunk_empty; |
351 | ||
352 | if (!read_public(this, handle, &public)) | |
353 | { | |
354 | return chunk_empty; | |
355 | } | |
356 | ||
357 | aik_blob = chunk_create((u_char*)&public, sizeof(public)); | |
358 | DBG3(DBG_LIB, "%s AIK public key blob: %B", LABEL, &aik_blob); | |
359 | ||
360 | /* convert TSS 2.0 AIK public key blot into PKCS#1 format */ | |
361 | switch (public.t.publicArea.type) | |
362 | { | |
363 | case TPM_ALG_RSA: | |
364 | { | |
365 | TPM2B_PUBLIC_KEY_RSA *rsa; | |
2343c483 | 366 | TPMT_RSA_SCHEME *scheme; |
c08753bd AS |
367 | chunk_t aik_exponent, aik_modulus; |
368 | ||
2343c483 AS |
369 | scheme = &public.t.publicArea.parameters.rsaDetail.scheme; |
370 | sig_alg = scheme->scheme; | |
371 | digest_alg = scheme->details.anySig.hashAlg; | |
372 | ||
c08753bd AS |
373 | rsa = &public.t.publicArea.unique.rsa; |
374 | aik_modulus = chunk_create(rsa->t.buffer, rsa->t.size); | |
375 | aik_exponent = chunk_from_chars(0x01, 0x00, 0x01); | |
376 | ||
377 | /* subjectPublicKeyInfo encoding of AIK RSA key */ | |
378 | if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER, | |
379 | NULL, &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus, | |
380 | CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END)) | |
381 | { | |
382 | DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of AIK key " | |
383 | "failed", LABEL); | |
384 | } | |
385 | break; | |
386 | } | |
387 | case TPM_ALG_ECC: | |
388 | { | |
389 | TPMS_ECC_POINT *ecc; | |
2343c483 | 390 | TPMT_ECC_SCHEME *scheme; |
c08753bd AS |
391 | chunk_t ecc_point; |
392 | uint8_t *pos; | |
393 | ||
2343c483 AS |
394 | scheme = &public.t.publicArea.parameters.eccDetail.scheme; |
395 | sig_alg = scheme->scheme; | |
396 | digest_alg = scheme->details.anySig.hashAlg; | |
397 | ||
c08753bd AS |
398 | ecc = &public.t.publicArea.unique.ecc; |
399 | ||
400 | /* allocate space for bit string */ | |
401 | pos = asn1_build_object(&ecc_point, ASN1_BIT_STRING, | |
402 | 2 + ecc->x.t.size + ecc->y.t.size); | |
403 | /* bit string length is a multiple of octets */ | |
404 | *pos++ = 0x00; | |
405 | /* uncompressed ECC point format */ | |
406 | *pos++ = 0x04; | |
407 | /* copy x coordinate of ECC point */ | |
408 | memcpy(pos, ecc->x.t.buffer, ecc->x.t.size); | |
409 | pos += ecc->x.t.size; | |
410 | /* copy y coordinate of ECC point */ | |
411 | memcpy(pos, ecc->y.t.buffer, ecc->y.t.size); | |
412 | /* subjectPublicKeyInfo encoding of AIK ECC key */ | |
413 | aik_pubkey = asn1_wrap(ASN1_SEQUENCE, "mm", | |
414 | asn1_wrap(ASN1_SEQUENCE, "mm", | |
415 | asn1_build_known_oid(OID_EC_PUBLICKEY), | |
416 | asn1_build_known_oid(ecc->x.t.size == 32 ? | |
417 | OID_PRIME256V1 : OID_SECT384R1)), | |
418 | ecc_point); | |
419 | break; | |
420 | } | |
421 | default: | |
422 | DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL); | |
2343c483 | 423 | return chunk_empty; |
c08753bd | 424 | } |
2343c483 AS |
425 | DBG1(DBG_PTS, "AIK signature algorithm is %N with %N hash", |
426 | tpm_alg_id_names, sig_alg, tpm_alg_id_names, digest_alg); | |
c08753bd AS |
427 | return aik_pubkey; |
428 | } | |
429 | ||
57e80492 AS |
430 | /** |
431 | * Configure a PCR Selection assuming a maximum of 24 registers | |
432 | */ | |
433 | static bool init_pcr_selection(private_tpm_tss_tss2_t *this, uint32_t pcrs, | |
434 | hash_algorithm_t alg, TPML_PCR_SELECTION *pcr_sel) | |
30d4989a | 435 | { |
bc67802a | 436 | TPM_ALG_ID alg_id; |
57e80492 | 437 | uint32_t pcr; |
bc67802a | 438 | |
57e80492 | 439 | /* check if hash algorithm is supported by TPM */ |
bc67802a AS |
440 | alg_id = hash_alg_to_tpm_alg_id(alg); |
441 | if (!is_supported_alg(this, alg_id)) | |
442 | { | |
443 | DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM", | |
444 | LABEL, hash_algorithm_short_names, alg); | |
445 | return FALSE; | |
446 | } | |
447 | ||
57e80492 AS |
448 | /* initialize the PCR Selection structure,*/ |
449 | pcr_sel->count = 1; | |
450 | pcr_sel->pcrSelections[0].hash = alg_id; | |
451 | pcr_sel->pcrSelections[0].sizeofSelect = 3; | |
452 | pcr_sel->pcrSelections[0].pcrSelect[0] = 0; | |
453 | pcr_sel->pcrSelections[0].pcrSelect[1] = 0; | |
454 | pcr_sel->pcrSelections[0].pcrSelect[2] = 0; | |
455 | ||
456 | /* set the selected PCRs */ | |
457 | for (pcr = 0; pcr < PLATFORM_PCR; pcr++) | |
458 | { | |
459 | if (pcrs & (1 << pcr)) | |
460 | { | |
461 | pcr_sel->pcrSelections[0].pcrSelect[pcr / 8] |= ( 1 << (pcr % 8) ); | |
462 | } | |
463 | } | |
464 | return TRUE; | |
465 | } | |
466 | ||
467 | METHOD(tpm_tss_t, read_pcr, bool, | |
468 | private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value, | |
469 | hash_algorithm_t alg) | |
470 | { | |
471 | TPML_PCR_SELECTION pcr_selection; | |
472 | TPML_DIGEST pcr_values; | |
473 | ||
474 | uint32_t pcr_update_counter, rval; | |
475 | uint8_t *pcr_value_ptr; | |
476 | size_t pcr_value_len; | |
477 | ||
bc67802a AS |
478 | if (pcr_num >= PLATFORM_PCR) |
479 | { | |
480 | DBG1(DBG_PTS, "%s maximum number of supported PCR is %d", | |
481 | LABEL, PLATFORM_PCR); | |
482 | return FALSE; | |
483 | } | |
484 | ||
57e80492 AS |
485 | if (!init_pcr_selection(this, (1 << pcr_num), alg, &pcr_selection)) |
486 | { | |
487 | return FALSE; | |
488 | } | |
bc67802a AS |
489 | |
490 | /* initialize the PCR Digest structure */ | |
491 | memset(&pcr_values, 0, sizeof(TPML_DIGEST)); | |
492 | ||
493 | /* read the PCR value */ | |
57e80492 AS |
494 | rval = Tss2_Sys_PCR_Read(this->sys_context, 0, &pcr_selection, |
495 | &pcr_update_counter, &pcr_selection, &pcr_values, 0); | |
bc67802a AS |
496 | if (rval != TPM_RC_SUCCESS) |
497 | { | |
498 | DBG1(DBG_PTS, "%s PCR bank could not be read: 0x%60x", | |
499 | LABEL, rval); | |
500 | return FALSE; | |
501 | } | |
502 | pcr_value_ptr = (uint8_t *)pcr_values.digests[0].t.buffer; | |
503 | pcr_value_len = (size_t) pcr_values.digests[0].t.size; | |
504 | ||
505 | *pcr_value = chunk_clone(chunk_create(pcr_value_ptr, pcr_value_len)); | |
506 | ||
507 | return TRUE; | |
30d4989a AS |
508 | } |
509 | ||
510 | METHOD(tpm_tss_t, extend_pcr, bool, | |
511 | private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value, | |
512 | chunk_t data, hash_algorithm_t alg) | |
513 | { | |
514 | /* TODO */ | |
515 | return FALSE; | |
516 | } | |
517 | ||
518 | METHOD(tpm_tss_t, quote, bool, | |
519 | private_tpm_tss_tss2_t *this, uint32_t aik_handle, uint32_t pcr_sel, | |
721ed31b AS |
520 | hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t *quote_mode, |
521 | tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig) | |
30d4989a | 522 | { |
721ed31b AS |
523 | chunk_t quoted_chunk, qualified_signer, extra_data, clock_info, |
524 | firmware_version, pcr_select, pcr_digest; | |
525 | hash_algorithm_t pcr_digest_alg; | |
526 | bio_reader_t *reader; | |
57e80492 AS |
527 | uint32_t rval; |
528 | ||
529 | TPM2B_DATA qualifying_data; | |
530 | TPML_PCR_SELECTION pcr_selection; | |
57e80492 | 531 | TPM2B_ATTEST quoted = { { sizeof(TPM2B_ATTEST)-2, } }; |
57e80492 | 532 | TPMT_SIG_SCHEME scheme; |
721ed31b AS |
533 | TPMT_SIGNATURE sig; |
534 | TPMI_ALG_HASH hash_alg; | |
57e80492 AS |
535 | TPMS_AUTH_COMMAND session_data_cmd; |
536 | TPMS_AUTH_RESPONSE session_data_rsp; | |
537 | TSS2_SYS_CMD_AUTHS sessions_data_cmd; | |
538 | TSS2_SYS_RSP_AUTHS sessions_data_rsp; | |
539 | TPMS_AUTH_COMMAND *session_data_cmd_array[1]; | |
540 | TPMS_AUTH_RESPONSE *session_data_rsp_array[1]; | |
541 | ||
542 | session_data_cmd_array[0] = &session_data_cmd; | |
543 | session_data_rsp_array[0] = &session_data_rsp; | |
544 | ||
545 | sessions_data_cmd.cmdAuths = &session_data_cmd_array[0]; | |
546 | sessions_data_rsp.rspAuths = &session_data_rsp_array[0]; | |
547 | ||
548 | sessions_data_cmd.cmdAuthsCount = 1; | |
549 | sessions_data_rsp.rspAuthsCount = 1; | |
550 | ||
551 | session_data_cmd.sessionHandle = TPM_RS_PW; | |
552 | session_data_cmd.hmac.t.size = 0; | |
553 | session_data_cmd.nonce.t.size = 0; | |
554 | ||
555 | *( (uint8_t *)((void *)&session_data_cmd.sessionAttributes ) ) = 0; | |
556 | ||
557 | qualifying_data.t.size = data.len; | |
558 | memcpy(qualifying_data.t.buffer, data.ptr, data.len); | |
559 | ||
560 | scheme.scheme = TPM_ALG_NULL; | |
561 | memset(&sig, 0x00, sizeof(sig)); | |
562 | ||
721ed31b AS |
563 | /* set Quote mode */ |
564 | *quote_mode = TPM_QUOTE_TPM2; | |
57e80492 AS |
565 | |
566 | if (!init_pcr_selection(this, pcr_sel, alg, &pcr_selection)) | |
567 | { | |
568 | return FALSE; | |
569 | } | |
570 | ||
571 | rval = Tss2_Sys_Quote(this->sys_context, aik_handle, &sessions_data_cmd, | |
572 | &qualifying_data, &scheme, &pcr_selection, "ed, | |
573 | &sig, &sessions_data_rsp); | |
574 | if (rval != TPM_RC_SUCCESS) | |
575 | { | |
576 | DBG1(DBG_PTS,"%s Tss2_Sys_Quote failed: 0x%06x", LABEL, rval); | |
577 | return FALSE; | |
578 | } | |
721ed31b AS |
579 | quoted_chunk = chunk_create(quoted.t.attestationData, quoted.t.size); |
580 | ||
581 | reader = bio_reader_create(chunk_skip(quoted_chunk, 6)); | |
582 | if (!reader->read_data16(reader, &qualified_signer) || | |
583 | !reader->read_data16(reader, &extra_data) || | |
584 | !reader->read_data (reader, 17, &clock_info) || | |
585 | !reader->read_data (reader, 8, &firmware_version) || | |
586 | !reader->read_data (reader, 10, &pcr_select) || | |
587 | !reader->read_data16(reader, &pcr_digest)) | |
588 | { | |
589 | DBG1(DBG_PTS, "%s parsing of quoted struct failed", LABEL); | |
590 | reader->destroy(reader); | |
591 | return FALSE; | |
592 | } | |
593 | reader->destroy(reader); | |
57e80492 | 594 | |
721ed31b AS |
595 | DBG2(DBG_PTS, "PCR Composite digest: %B", &pcr_digest); |
596 | DBG2(DBG_PTS, "TPM Quote Info: %B", "ed_chunk); | |
597 | DBG2(DBG_PTS, "qualifiedSigner: %B", &qualified_signer); | |
598 | DBG2(DBG_PTS, "extraData: %B", &extra_data); | |
599 | DBG2(DBG_PTS, "clockInfo: %B", &clock_info); | |
600 | DBG2(DBG_PTS, "firmwareVersion: %B", &firmware_version); | |
601 | DBG2(DBG_PTS, "pcrSelect: %B", &pcr_select); | |
57e80492 AS |
602 | |
603 | /* extract signature */ | |
604 | switch (sig.sigAlg) | |
605 | { | |
606 | case TPM_ALG_RSASSA: | |
607 | case TPM_ALG_RSAPSS: | |
608 | *quote_sig = chunk_clone( | |
609 | chunk_create( | |
610 | sig.signature.rsassa.sig.t.buffer, | |
611 | sig.signature.rsassa.sig.t.size)); | |
721ed31b | 612 | hash_alg = sig.signature.rsassa.hash; |
57e80492 AS |
613 | break; |
614 | case TPM_ALG_ECDSA: | |
615 | case TPM_ALG_ECDAA: | |
616 | case TPM_ALG_SM2: | |
617 | case TPM_ALG_ECSCHNORR: | |
618 | *quote_sig = chunk_cat("cc", | |
619 | chunk_create( | |
620 | sig.signature.ecdsa.signatureR.t.buffer, | |
621 | sig.signature.ecdsa.signatureR.t.size), | |
622 | chunk_create( | |
623 | sig.signature.ecdsa.signatureS.t.buffer, | |
624 | sig.signature.ecdsa.signatureS.t.size)); | |
721ed31b | 625 | hash_alg = sig.signature.ecdsa.hash; |
57e80492 AS |
626 | break; |
627 | default: | |
628 | DBG1(DBG_PTS, "%s unsupported %N signature algorithm", | |
629 | LABEL, tpm_alg_id_names, sig.sigAlg); | |
630 | return FALSE; | |
631 | }; | |
721ed31b AS |
632 | |
633 | DBG2(DBG_PTS, "PCR digest algorithm is %N", tpm_alg_id_names, hash_alg); | |
634 | pcr_digest_alg = hash_alg_from_tpm_alg_id(hash_alg); | |
635 | ||
57e80492 AS |
636 | DBG2(DBG_PTS, "TPM Quote Signature: %B", quote_sig); |
637 | ||
721ed31b AS |
638 | /* Create and initialize Quote Info object */ |
639 | *quote_info = tpm_tss_quote_info_create(*quote_mode, pcr_digest_alg, | |
640 | pcr_digest); | |
641 | (*quote_info)->set_tpm2_info(*quote_info, qualified_signer, clock_info, | |
642 | pcr_select); | |
643 | (*quote_info)->set_version_info(*quote_info, firmware_version); | |
644 | ||
57e80492 | 645 | return TRUE; |
30d4989a AS |
646 | } |
647 | ||
c08753bd AS |
648 | METHOD(tpm_tss_t, destroy, void, |
649 | private_tpm_tss_tss2_t *this) | |
650 | { | |
651 | finalize_context(this); | |
652 | free(this); | |
653 | } | |
654 | ||
655 | /** | |
656 | * See header | |
657 | */ | |
658 | tpm_tss_t *tpm_tss_tss2_create() | |
659 | { | |
660 | private_tpm_tss_tss2_t *this; | |
661 | bool available; | |
662 | ||
663 | INIT(this, | |
664 | .public = { | |
665 | .get_version = _get_version, | |
fedc6769 | 666 | .get_version_info = _get_version_info, |
c08753bd AS |
667 | .generate_aik = _generate_aik, |
668 | .get_public = _get_public, | |
30d4989a AS |
669 | .read_pcr = _read_pcr, |
670 | .extend_pcr = _extend_pcr, | |
671 | .quote = _quote, | |
c08753bd AS |
672 | .destroy = _destroy, |
673 | }, | |
674 | ); | |
675 | ||
676 | available = initialize_context(this); | |
677 | DBG1(DBG_PTS, "TPM 2.0 via TSS2 %savailable", available ? "" : "not "); | |
678 | ||
679 | if (!available) | |
680 | { | |
681 | destroy(this); | |
682 | return NULL; | |
683 | } | |
684 | return &this->public; | |
685 | } | |
686 | ||
687 | #else /* TSS_TSS2 */ | |
688 | ||
689 | tpm_tss_t *tpm_tss_tss2_create() | |
690 | { | |
691 | return NULL; | |
692 | } | |
693 | ||
694 | #endif /* TSS_TSS2 */ | |
695 | ||
696 |