libtpmtss: Get TPM 2.0 capabilities
[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
24 #include <tss2/tpm20.h>
25 #include <tcti/tcti_socket.h>
26
27 #define LABEL "TPM 2.0 -"
28
29 typedef struct private_tpm_tss_tss2_t private_tpm_tss_tss2_t;
30
31 /**
32 * Private data of an tpm_tss_tss2_t object.
33 */
34 struct 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
51 };
52
53 /**
54 * Some symbols required by libtctisocket
55 */
56 FILE *outFp;
57 uint8_t simulator = 1;
58
59 int TpmClientPrintf (uint8_t type, const char *format, ...)
60 {
61 return 0;
62 }
63
64 /**
65 * Get a list of supported algorithms
66 */
67 static bool get_algs_capability(private_tpm_tss_tss2_t *this)
68 {
69 TPMS_CAPABILITY_DATA cap_data;
70 TPMI_YES_NO more_data;
71 uint32_t rval, i;
72 size_t len = BUF_LEN;
73 char buf[BUF_LEN];
74 char *pos = buf;
75 int written;
76
77 /* get supported algorithms */
78 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ALGS,
79 0, TPM_PT_ALGORITHM_SET, &more_data, &cap_data, 0);
80 if (rval != TPM_RC_SUCCESS)
81 {
82 DBG1(DBG_PTS, "%s GetCapability failed for TPM_CAP_ALGS: 0x%06x",
83 LABEL, rval);
84 return FALSE;
85 }
86
87 /* print supported algorithms */
88 for (i = 0; i < cap_data.data.algorithms.count; i++)
89 {
90 written = snprintf(pos, len, " %N", tpm_alg_id_names,
91 cap_data.data.algorithms.algProperties[i].alg);
92 if (written < 0 || written >= len)
93 {
94 break;
95 }
96 pos += written;
97 len -= written;
98 }
99 DBG2(DBG_PTS, "%s algorithms:%s", LABEL, buf);
100
101 /* get supported ECC curves */
102 rval = Tss2_Sys_GetCapability(this->sys_context, 0, TPM_CAP_ECC_CURVES,
103 0, TPM_PT_LOADED_CURVES, &more_data, &cap_data, 0);
104 if (rval != TPM_RC_SUCCESS)
105 {
106 DBG1(DBG_PTS, "%s GetCapability failed for TPM_ECC_CURVES: 0x%06x",
107 LABEL, rval);
108 return FALSE;
109 }
110
111 /* reset print buffer */
112 pos = buf;
113 len = BUF_LEN;
114
115 /* print supported ECC curves */
116 for (i = 0; i < cap_data.data.eccCurves.count; i++)
117 {
118 written = snprintf(pos, len, " %N", tpm_ecc_curve_names,
119 cap_data.data.eccCurves.eccCurves[i]);
120 if (written < 0 || written >= len)
121 {
122 break;
123 }
124 pos += written;
125 len -= written;
126 }
127 DBG2(DBG_PTS, "%s ECC curves:%s", LABEL, buf);
128
129 return TRUE;
130 }
131
132 /**
133 * Initialize TSS context
134 */
135 static bool initialize_context(private_tpm_tss_tss2_t *this)
136 {
137 size_t tcti_context_size;
138 uint32_t sys_context_size;
139 uint32_t rval;
140
141 TCTI_SOCKET_CONF rm_if_config = { DEFAULT_HOSTNAME,
142 DEFAULT_RESMGR_TPM_PORT
143 };
144
145 TSS2_ABI_VERSION abi_version = { TSSWG_INTEROP,
146 TSS_SAPI_FIRST_FAMILY,
147 TSS_SAPI_FIRST_LEVEL,
148 TSS_SAPI_FIRST_VERSION
149 };
150
151 /* determine size of tcti context */
152 rval = InitSocketTcti(NULL, &tcti_context_size, &rm_if_config, 0);
153 if (rval != TSS2_RC_SUCCESS)
154 {
155 DBG1(DBG_PTS, "%s could not get tcti_context size: 0x%06x",
156 LABEL, rval);
157 return FALSE;
158 }
159
160 /* allocate memory for tcti context */
161 this->tcti_context = (TSS2_TCTI_CONTEXT*)malloc(tcti_context_size);
162
163 /* initialize tcti context */
164 rval = InitSocketTcti(this->tcti_context, &tcti_context_size,
165 &rm_if_config, 0);
166 if (rval != TSS2_RC_SUCCESS)
167 {
168 DBG1(DBG_PTS, "%s could not get tcti_context: 0x%06x",
169 LABEL, rval);
170 return FALSE;
171 }
172
173 /* determine size of sys context */
174 sys_context_size = Tss2_Sys_GetContextSize(0);
175
176 /* allocate memory for sys context */
177 this->sys_context = malloc(sys_context_size);
178
179 /* initialize sys context */
180 rval = Tss2_Sys_Initialize(this->sys_context, sys_context_size,
181 this->tcti_context, &abi_version);
182 if (rval != TSS2_RC_SUCCESS)
183 {
184 DBG1(DBG_PTS, "%s could not get sys_context: 0x%06x",
185 LABEL, rval);
186 return FALSE;
187 }
188
189 /* get a list of supported algorithms and ECC curves */
190 return get_algs_capability(this);
191 }
192
193 /**
194 * Finalize TSS context
195 */
196 static void finalize_context(private_tpm_tss_tss2_t *this)
197 {
198 if (this->tcti_context)
199 {
200 TeardownSocketTcti(this->tcti_context);
201 }
202 if (this->sys_context)
203 {
204 Tss2_Sys_Finalize(this->sys_context);
205 free(this->sys_context);
206 }
207 }
208
209 METHOD(tpm_tss_t, get_version, tpm_version_t,
210 private_tpm_tss_tss2_t *this)
211 {
212 return TPM_VERSION_2_0;
213 }
214
215 METHOD(tpm_tss_t, get_version_info, chunk_t,
216 private_tpm_tss_tss2_t *this)
217 {
218 return chunk_empty;
219 }
220
221 /**
222 * read the public key portion of a TSS 2.0 AIK key from NVRAM
223 */
224 bool read_public(private_tpm_tss_tss2_t *this, TPMI_DH_OBJECT handle,
225 TPM2B_PUBLIC *public)
226 {
227 uint32_t rval;
228
229 TPM2B_NAME name = { { sizeof(TPM2B_NAME)-2, } };
230 TPM2B_NAME qualified_name = { { sizeof(TPM2B_NAME)-2, } };
231
232 TPMS_AUTH_RESPONSE session_data;
233 TSS2_SYS_RSP_AUTHS sessions_data;
234 TPMS_AUTH_RESPONSE *session_data_array[1];
235
236 session_data_array[0] = &session_data;
237 sessions_data.rspAuths = &session_data_array[0];
238 sessions_data.rspAuthsCount = 1;
239
240 /* always send simulator platform command, ignored by true RM */
241 PlatformCommand(this->tcti_context ,MS_SIM_POWER_ON );
242 PlatformCommand(this->tcti_context, MS_SIM_NV_ON );
243
244 /* read public key for a given object handle from TPM 2.0 NVRAM */
245 rval = Tss2_Sys_ReadPublic(this->sys_context, handle, 0, public, &name,
246 &qualified_name, &sessions_data);
247
248 PlatformCommand(this->tcti_context, MS_SIM_POWER_OFF);
249
250 if (rval != TPM_RC_SUCCESS)
251 {
252 DBG1(DBG_PTS, "%s could not read public key from handle 0x%08x: 0x%06x",
253 LABEL, handle, rval);
254 return FALSE;
255 }
256 return TRUE;
257 }
258
259 METHOD(tpm_tss_t, generate_aik, bool,
260 private_tpm_tss_tss2_t *this, chunk_t ca_modulus, chunk_t *aik_blob,
261 chunk_t *aik_pubkey, chunk_t *identity_req)
262 {
263 return FALSE;
264 }
265
266 METHOD(tpm_tss_t, get_public, chunk_t,
267 private_tpm_tss_tss2_t *this, uint32_t handle)
268 {
269 TPM2B_PUBLIC public = { { 0, } };
270 chunk_t aik_blob, aik_pubkey = chunk_empty;
271
272 if (!read_public(this, handle, &public))
273 {
274 return chunk_empty;
275 }
276
277 aik_blob = chunk_create((u_char*)&public, sizeof(public));
278 DBG3(DBG_LIB, "%s AIK public key blob: %B", LABEL, &aik_blob);
279
280 /* convert TSS 2.0 AIK public key blot into PKCS#1 format */
281 switch (public.t.publicArea.type)
282 {
283 case TPM_ALG_RSA:
284 {
285 TPM2B_PUBLIC_KEY_RSA *rsa;
286 chunk_t aik_exponent, aik_modulus;
287
288 rsa = &public.t.publicArea.unique.rsa;
289 aik_modulus = chunk_create(rsa->t.buffer, rsa->t.size);
290 aik_exponent = chunk_from_chars(0x01, 0x00, 0x01);
291
292 /* subjectPublicKeyInfo encoding of AIK RSA key */
293 if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER,
294 NULL, &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus,
295 CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END))
296 {
297 DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of AIK key "
298 "failed", LABEL);
299 }
300 break;
301 }
302 case TPM_ALG_ECC:
303 {
304 TPMS_ECC_POINT *ecc;
305 chunk_t ecc_point;
306 uint8_t *pos;
307
308 ecc = &public.t.publicArea.unique.ecc;
309
310 /* allocate space for bit string */
311 pos = asn1_build_object(&ecc_point, ASN1_BIT_STRING,
312 2 + ecc->x.t.size + ecc->y.t.size);
313 /* bit string length is a multiple of octets */
314 *pos++ = 0x00;
315 /* uncompressed ECC point format */
316 *pos++ = 0x04;
317 /* copy x coordinate of ECC point */
318 memcpy(pos, ecc->x.t.buffer, ecc->x.t.size);
319 pos += ecc->x.t.size;
320 /* copy y coordinate of ECC point */
321 memcpy(pos, ecc->y.t.buffer, ecc->y.t.size);
322 /* subjectPublicKeyInfo encoding of AIK ECC key */
323 aik_pubkey = asn1_wrap(ASN1_SEQUENCE, "mm",
324 asn1_wrap(ASN1_SEQUENCE, "mm",
325 asn1_build_known_oid(OID_EC_PUBLICKEY),
326 asn1_build_known_oid(ecc->x.t.size == 32 ?
327 OID_PRIME256V1 : OID_SECT384R1)),
328 ecc_point);
329 break;
330 }
331 default:
332 DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL);
333 }
334
335 return aik_pubkey;
336 }
337
338 METHOD(tpm_tss_t, destroy, void,
339 private_tpm_tss_tss2_t *this)
340 {
341 finalize_context(this);
342 free(this);
343 }
344
345 /**
346 * See header
347 */
348 tpm_tss_t *tpm_tss_tss2_create()
349 {
350 private_tpm_tss_tss2_t *this;
351 bool available;
352
353 INIT(this,
354 .public = {
355 .get_version = _get_version,
356 .get_version_info = _get_version_info,
357 .generate_aik = _generate_aik,
358 .get_public = _get_public,
359 .destroy = _destroy,
360 },
361 );
362
363 available = initialize_context(this);
364 DBG1(DBG_PTS, "TPM 2.0 via TSS2 %savailable", available ? "" : "not ");
365
366 if (!available)
367 {
368 destroy(this);
369 return NULL;
370 }
371 return &this->public;
372 }
373
374 #else /* TSS_TSS2 */
375
376 tpm_tss_t *tpm_tss_tss2_create()
377 {
378 return NULL;
379 }
380
381 #endif /* TSS_TSS2 */
382
383