]> git.ipfire.org Git - thirdparty/strongswan.git/blame - src/libtpmtss/tpm_tss_tss2.c
libtpmtss: Implemented TSS2 read_pcr() method
[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 *
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"
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>
23
24#include <tss2/tpm20.h>
25#include <tcti/tcti_socket.h>
26
27#define LABEL "TPM 2.0 -"
28
29typedef struct private_tpm_tss_tss2_t private_tpm_tss_tss2_t;
30
31/**
32 * Private data of an tpm_tss_tss2_t object.
33 */
34struct private_tpm_tss_tss2_t {
35
36 /**
37 * Public tpm_tss_tss2_t interface.
38 */
39 tpm_tss_t public;
40
41 /**
42 * TCTI context
43 */
44 TSS2_TCTI_CONTEXT *tcti_context;
45
46 /**
47 * SYS context
48 */
49 TSS2_SYS_CONTEXT *sys_context;
50
bc67802a
AS
51 /**
52 * Number of supported algorithms
53 */
54 size_t supported_algs_count;
55
56 /**
57 * List of supported algorithms
58 */
59 TPM_ALG_ID supported_algs[TPM_PT_ALGORITHM_SET];
c08753bd
AS
60};
61
62/**
63 * Some symbols required by libtctisocket
64 */
65FILE *outFp;
66uint8_t simulator = 1;
67
68int TpmClientPrintf (uint8_t type, const char *format, ...)
69{
70 return 0;
71}
72
bc67802a
AS
73/**
74 * Convert hash algorithm to TPM_ALG_ID
75 */
76static TPM_ALG_ID hash_alg_to_tpm_alg_id(hash_algorithm_t alg)
77{
78 switch (alg)
79 {
80 case HASH_SHA1:
81 return TPM_ALG_SHA1;
82 case HASH_SHA256:
83 return TPM_ALG_SHA256;
84 case HASH_SHA384:
85 return TPM_ALG_SHA384;
86 case HASH_SHA512:
87 return TPM_ALG_SHA512;
88 default:
89 return TPM_ALG_ERROR;
90 }
91}
92
93/**
94 * Check if an algorithm given by its TPM_ALG_ID is supported by the TPM
95 */
96static bool is_supported_alg(private_tpm_tss_tss2_t *this, TPM_ALG_ID alg_id)
97{
98 int i;
99
100 if (alg_id == TPM_ALG_ERROR)
101 {
102 return FALSE;
103 }
104
105 for (i = 0; i < this->supported_algs_count; i++)
106 {
107 if (this->supported_algs[i] == alg_id)
108 {
109 return TRUE;
110 }
111 }
112
113 return FALSE;
114}
115
8301dc85
AS
116/**
117 * Get a list of supported algorithms
118 */
119static bool get_algs_capability(private_tpm_tss_tss2_t *this)
120{
121 TPMS_CAPABILITY_DATA cap_data;
122 TPMI_YES_NO more_data;
bc67802a 123 TPM_ALG_ID alg;
8301dc85
AS
124 uint32_t rval, i;
125 size_t len = BUF_LEN;
126 char buf[BUF_LEN];
127 char *pos = buf;
128 int written;
129
130 /* get supported algorithms */
131 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ALGS,
132 0, TPM_PT_ALGORITHM_SET, &more_data, &cap_data, 0);
133 if (rval != TPM_RC_SUCCESS)
134 {
135 DBG1(DBG_PTS, "%s GetCapability failed for TPM_CAP_ALGS: 0x%06x",
136 LABEL, rval);
137 return FALSE;
138 }
139
bc67802a
AS
140 /* Number of supported algorithms */
141 this->supported_algs_count = cap_data.data.algorithms.count;
142
143 /* store and print supported algorithms */
144 for (i = 0; i < this->supported_algs_count; i++)
8301dc85 145 {
bc67802a
AS
146 alg = cap_data.data.algorithms.algProperties[i].alg;
147 this->supported_algs[i] = alg;
148
149 written = snprintf(pos, len, " %N", tpm_alg_id_names, alg);
8301dc85
AS
150 if (written < 0 || written >= len)
151 {
152 break;
153 }
154 pos += written;
155 len -= written;
156 }
157 DBG2(DBG_PTS, "%s algorithms:%s", LABEL, buf);
158
159 /* get supported ECC curves */
160 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ECC_CURVES,
161 0, TPM_PT_LOADED_CURVES, &more_data, &cap_data, 0);
162 if (rval != TPM_RC_SUCCESS)
163 {
164 DBG1(DBG_PTS, "%s GetCapability failed for TPM_ECC_CURVES: 0x%06x",
165 LABEL, rval);
166 return FALSE;
167 }
168
169 /* reset print buffer */
170 pos = buf;
171 len = BUF_LEN;
172
173 /* print supported ECC curves */
174 for (i = 0; i < cap_data.data.eccCurves.count; i++)
175 {
176 written = snprintf(pos, len, " %N", tpm_ecc_curve_names,
177 cap_data.data.eccCurves.eccCurves[i]);
178 if (written < 0 || written >= len)
179 {
180 break;
181 }
182 pos += written;
183 len -= written;
184 }
185 DBG2(DBG_PTS, "%s ECC curves:%s", LABEL, buf);
186
187 return TRUE;
188}
189
c08753bd
AS
190/**
191 * Initialize TSS context
192 */
193static bool initialize_context(private_tpm_tss_tss2_t *this)
194{
195 size_t tcti_context_size;
196 uint32_t sys_context_size;
197 uint32_t rval;
198
199 TCTI_SOCKET_CONF rm_if_config = { DEFAULT_HOSTNAME,
200 DEFAULT_RESMGR_TPM_PORT
201 };
202
203 TSS2_ABI_VERSION abi_version = { TSSWG_INTEROP,
204 TSS_SAPI_FIRST_FAMILY,
205 TSS_SAPI_FIRST_LEVEL,
206 TSS_SAPI_FIRST_VERSION
207 };
208
209 /* determine size of tcti context */
210 rval = InitSocketTcti(NULL, &tcti_context_size, &rm_if_config, 0);
211 if (rval != TSS2_RC_SUCCESS)
212 {
213 DBG1(DBG_PTS, "%s could not get tcti_context size: 0x%06x",
214 LABEL, rval);
215 return FALSE;
216 }
217
218 /* allocate memory for tcti context */
219 this->tcti_context = (TSS2_TCTI_CONTEXT*)malloc(tcti_context_size);
220
221 /* initialize tcti context */
222 rval = InitSocketTcti(this->tcti_context, &tcti_context_size,
223 &rm_if_config, 0);
224 if (rval != TSS2_RC_SUCCESS)
225 {
226 DBG1(DBG_PTS, "%s could not get tcti_context: 0x%06x",
227 LABEL, rval);
228 return FALSE;
229 }
230
231 /* determine size of sys context */
232 sys_context_size = Tss2_Sys_GetContextSize(0);
233
234 /* allocate memory for sys context */
235 this->sys_context = malloc(sys_context_size);
236
237 /* initialize sys context */
238 rval = Tss2_Sys_Initialize(this->sys_context, sys_context_size,
239 this->tcti_context, &abi_version);
240 if (rval != TSS2_RC_SUCCESS)
241 {
242 DBG1(DBG_PTS, "%s could not get sys_context: 0x%06x",
243 LABEL, rval);
244 return FALSE;
245 }
8301dc85
AS
246
247 /* get a list of supported algorithms and ECC curves */
248 return get_algs_capability(this);
c08753bd
AS
249}
250
251/**
252 * Finalize TSS context
253 */
254static void finalize_context(private_tpm_tss_tss2_t *this)
255{
256 if (this->tcti_context)
257 {
258 TeardownSocketTcti(this->tcti_context);
259 }
260 if (this->sys_context)
261 {
262 Tss2_Sys_Finalize(this->sys_context);
263 free(this->sys_context);
264 }
265}
266
267METHOD(tpm_tss_t, get_version, tpm_version_t,
268 private_tpm_tss_tss2_t *this)
269{
270 return TPM_VERSION_2_0;
271}
272
fedc6769
AS
273METHOD(tpm_tss_t, get_version_info, chunk_t,
274 private_tpm_tss_tss2_t *this)
275{
276 return chunk_empty;
277}
278
c08753bd
AS
279/**
280 * read the public key portion of a TSS 2.0 AIK key from NVRAM
281 */
282bool read_public(private_tpm_tss_tss2_t *this, TPMI_DH_OBJECT handle,
283 TPM2B_PUBLIC *public)
284{
285 uint32_t rval;
286
287 TPM2B_NAME name = { { sizeof(TPM2B_NAME)-2, } };
288 TPM2B_NAME qualified_name = { { sizeof(TPM2B_NAME)-2, } };
289
290 TPMS_AUTH_RESPONSE session_data;
291 TSS2_SYS_RSP_AUTHS sessions_data;
292 TPMS_AUTH_RESPONSE *session_data_array[1];
293
294 session_data_array[0] = &session_data;
295 sessions_data.rspAuths = &session_data_array[0];
296 sessions_data.rspAuthsCount = 1;
297
298 /* always send simulator platform command, ignored by true RM */
299 PlatformCommand(this->tcti_context ,MS_SIM_POWER_ON );
300 PlatformCommand(this->tcti_context, MS_SIM_NV_ON );
301
302 /* read public key for a given object handle from TPM 2.0 NVRAM */
303 rval = Tss2_Sys_ReadPublic(this->sys_context, handle, 0, public, &name,
304 &qualified_name, &sessions_data);
305
306 PlatformCommand(this->tcti_context, MS_SIM_POWER_OFF);
307
308 if (rval != TPM_RC_SUCCESS)
309 {
310 DBG1(DBG_PTS, "%s could not read public key from handle 0x%08x: 0x%06x",
311 LABEL, handle, rval);
312 return FALSE;
313 }
314 return TRUE;
315}
316
317METHOD(tpm_tss_t, generate_aik, bool,
318 private_tpm_tss_tss2_t *this, chunk_t ca_modulus, chunk_t *aik_blob,
319 chunk_t *aik_pubkey, chunk_t *identity_req)
320{
321 return FALSE;
322}
323
324METHOD(tpm_tss_t, get_public, chunk_t,
325 private_tpm_tss_tss2_t *this, uint32_t handle)
326{
327 TPM2B_PUBLIC public = { { 0, } };
328 chunk_t aik_blob, aik_pubkey = chunk_empty;
329
330 if (!read_public(this, handle, &public))
331 {
332 return chunk_empty;
333 }
334
335 aik_blob = chunk_create((u_char*)&public, sizeof(public));
336 DBG3(DBG_LIB, "%s AIK public key blob: %B", LABEL, &aik_blob);
337
338 /* convert TSS 2.0 AIK public key blot into PKCS#1 format */
339 switch (public.t.publicArea.type)
340 {
341 case TPM_ALG_RSA:
342 {
343 TPM2B_PUBLIC_KEY_RSA *rsa;
344 chunk_t aik_exponent, aik_modulus;
345
346 rsa = &public.t.publicArea.unique.rsa;
347 aik_modulus = chunk_create(rsa->t.buffer, rsa->t.size);
348 aik_exponent = chunk_from_chars(0x01, 0x00, 0x01);
349
350 /* subjectPublicKeyInfo encoding of AIK RSA key */
351 if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER,
352 NULL, &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus,
353 CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END))
354 {
355 DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of AIK key "
356 "failed", LABEL);
357 }
358 break;
359 }
360 case TPM_ALG_ECC:
361 {
362 TPMS_ECC_POINT *ecc;
363 chunk_t ecc_point;
364 uint8_t *pos;
365
366 ecc = &public.t.publicArea.unique.ecc;
367
368 /* allocate space for bit string */
369 pos = asn1_build_object(&ecc_point, ASN1_BIT_STRING,
370 2 + ecc->x.t.size + ecc->y.t.size);
371 /* bit string length is a multiple of octets */
372 *pos++ = 0x00;
373 /* uncompressed ECC point format */
374 *pos++ = 0x04;
375 /* copy x coordinate of ECC point */
376 memcpy(pos, ecc->x.t.buffer, ecc->x.t.size);
377 pos += ecc->x.t.size;
378 /* copy y coordinate of ECC point */
379 memcpy(pos, ecc->y.t.buffer, ecc->y.t.size);
380 /* subjectPublicKeyInfo encoding of AIK ECC key */
381 aik_pubkey = asn1_wrap(ASN1_SEQUENCE, "mm",
382 asn1_wrap(ASN1_SEQUENCE, "mm",
383 asn1_build_known_oid(OID_EC_PUBLICKEY),
384 asn1_build_known_oid(ecc->x.t.size == 32 ?
385 OID_PRIME256V1 : OID_SECT384R1)),
386 ecc_point);
387 break;
388 }
389 default:
390 DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL);
391 }
392
393 return aik_pubkey;
394}
395
30d4989a
AS
396METHOD(tpm_tss_t, read_pcr, bool,
397 private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
398 hash_algorithm_t alg)
399{
bc67802a
AS
400 TPML_PCR_SELECTION pcr_sel_in, pcr_sel_out;
401 TPML_DIGEST pcr_values;
402 TPM_ALG_ID alg_id;
403
404 uint32_t pcr_update_counter, rval;
405 uint8_t *pcr_value_ptr;
406 size_t pcr_value_len;
407
408 alg_id = hash_alg_to_tpm_alg_id(alg);
409 if (!is_supported_alg(this, alg_id))
410 {
411 DBG1(DBG_PTS, "%s %N hash algorithm not supported by TPM",
412 LABEL, hash_algorithm_short_names, alg);
413 return FALSE;
414 }
415
416 if (pcr_num >= PLATFORM_PCR)
417 {
418 DBG1(DBG_PTS, "%s maximum number of supported PCR is %d",
419 LABEL, PLATFORM_PCR);
420 return FALSE;
421 }
422
423 /* initialize the PCR Selection structure */
424 pcr_sel_in.count = 1;
425 pcr_sel_in.pcrSelections[0].hash = alg_id;
426 pcr_sel_in.pcrSelections[0].sizeofSelect = 3;
427 pcr_sel_in.pcrSelections[0].pcrSelect[0] = 0;
428 pcr_sel_in.pcrSelections[0].pcrSelect[1] = 0;
429 pcr_sel_in.pcrSelections[0].pcrSelect[2] = 0;
430
431 /* set the desired PCR */
432 pcr_sel_in.pcrSelections[0].pcrSelect[pcr_num / 8] = 1 << (pcr_num % 8);
433
434 /* initialize the PCR Digest structure */
435 memset(&pcr_values, 0, sizeof(TPML_DIGEST));
436
437 /* read the PCR value */
438 rval = Tss2_Sys_PCR_Read(this->sys_context, 0, &pcr_sel_in,
439 &pcr_update_counter, &pcr_sel_out, &pcr_values, 0);
440 if (rval != TPM_RC_SUCCESS)
441 {
442 DBG1(DBG_PTS, "%s PCR bank could not be read: 0x%60x",
443 LABEL, rval);
444 return FALSE;
445 }
446 pcr_value_ptr = (uint8_t *)pcr_values.digests[0].t.buffer;
447 pcr_value_len = (size_t) pcr_values.digests[0].t.size;
448
449 *pcr_value = chunk_clone(chunk_create(pcr_value_ptr, pcr_value_len));
450
451 return TRUE;
30d4989a
AS
452}
453
454METHOD(tpm_tss_t, extend_pcr, bool,
455 private_tpm_tss_tss2_t *this, uint32_t pcr_num, chunk_t *pcr_value,
456 chunk_t data, hash_algorithm_t alg)
457{
458 /* TODO */
459 return FALSE;
460}
461
462METHOD(tpm_tss_t, quote, bool,
463 private_tpm_tss_tss2_t *this, uint32_t aik_handle, uint32_t pcr_sel,
464 hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t mode, chunk_t *pcr_comp,
465 chunk_t *quote_sig)
466{
467 /* TODO */
468 return FALSE;
469}
470
c08753bd
AS
471METHOD(tpm_tss_t, destroy, void,
472 private_tpm_tss_tss2_t *this)
473{
474 finalize_context(this);
475 free(this);
476}
477
478/**
479 * See header
480 */
481tpm_tss_t *tpm_tss_tss2_create()
482{
483 private_tpm_tss_tss2_t *this;
484 bool available;
485
486 INIT(this,
487 .public = {
488 .get_version = _get_version,
fedc6769 489 .get_version_info = _get_version_info,
c08753bd
AS
490 .generate_aik = _generate_aik,
491 .get_public = _get_public,
30d4989a
AS
492 .read_pcr = _read_pcr,
493 .extend_pcr = _extend_pcr,
494 .quote = _quote,
c08753bd
AS
495 .destroy = _destroy,
496 },
497 );
498
499 available = initialize_context(this);
500 DBG1(DBG_PTS, "TPM 2.0 via TSS2 %savailable", available ? "" : "not ");
501
502 if (!available)
503 {
504 destroy(this);
505 return NULL;
506 }
507 return &this->public;
508}
509
510#else /* TSS_TSS2 */
511
512tpm_tss_t *tpm_tss_tss2_create()
513{
514 return NULL;
515}
516
517#endif /* TSS_TSS2 */
518
519