libtpmtss: Retrieve TPM 1.2 version info
[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
18 #ifdef TSS_TSS2
19
20 #include <asn1/asn1.h>
21 #include <asn1/oid.h>
22
23 #include <tss2/tpm20.h>
24 #include <tcti/tcti_socket.h>
25
26 #define LABEL "TPM 2.0 -"
27
28 typedef struct private_tpm_tss_tss2_t private_tpm_tss_tss2_t;
29
30 /**
31 * Private data of an tpm_tss_tss2_t object.
32 */
33 struct private_tpm_tss_tss2_t {
34
35 /**
36 * Public tpm_tss_tss2_t interface.
37 */
38 tpm_tss_t public;
39
40 /**
41 * TCTI context
42 */
43 TSS2_TCTI_CONTEXT *tcti_context;
44
45 /**
46 * SYS context
47 */
48 TSS2_SYS_CONTEXT *sys_context;
49
50 };
51
52 /**
53 * Some symbols required by libtctisocket
54 */
55 FILE *outFp;
56 uint8_t simulator = 1;
57
58 int TpmClientPrintf (uint8_t type, const char *format, ...)
59 {
60 return 0;
61 }
62
63 /**
64 * Initialize TSS context
65 */
66 static bool initialize_context(private_tpm_tss_tss2_t *this)
67 {
68 size_t tcti_context_size;
69 uint32_t sys_context_size;
70 uint32_t rval;
71
72 TCTI_SOCKET_CONF rm_if_config = { DEFAULT_HOSTNAME,
73 DEFAULT_RESMGR_TPM_PORT
74 };
75
76 TSS2_ABI_VERSION abi_version = { TSSWG_INTEROP,
77 TSS_SAPI_FIRST_FAMILY,
78 TSS_SAPI_FIRST_LEVEL,
79 TSS_SAPI_FIRST_VERSION
80 };
81
82 /* determine size of tcti context */
83 rval = InitSocketTcti(NULL, &tcti_context_size, &rm_if_config, 0);
84 if (rval != TSS2_RC_SUCCESS)
85 {
86 DBG1(DBG_PTS, "%s could not get tcti_context size: 0x%06x",
87 LABEL, rval);
88 return FALSE;
89 }
90
91 /* allocate memory for tcti context */
92 this->tcti_context = (TSS2_TCTI_CONTEXT*)malloc(tcti_context_size);
93
94 /* initialize tcti context */
95 rval = InitSocketTcti(this->tcti_context, &tcti_context_size,
96 &rm_if_config, 0);
97 if (rval != TSS2_RC_SUCCESS)
98 {
99 DBG1(DBG_PTS, "%s could not get tcti_context: 0x%06x",
100 LABEL, rval);
101 return FALSE;
102 }
103
104 /* determine size of sys context */
105 sys_context_size = Tss2_Sys_GetContextSize(0);
106
107 /* allocate memory for sys context */
108 this->sys_context = malloc(sys_context_size);
109
110 /* initialize sys context */
111 rval = Tss2_Sys_Initialize(this->sys_context, sys_context_size,
112 this->tcti_context, &abi_version);
113 if (rval != TSS2_RC_SUCCESS)
114 {
115 DBG1(DBG_PTS, "%s could not get sys_context: 0x%06x",
116 LABEL, rval);
117 return FALSE;
118 }
119 return TRUE;
120 }
121
122 /**
123 * Finalize TSS context
124 */
125 static void finalize_context(private_tpm_tss_tss2_t *this)
126 {
127 if (this->tcti_context)
128 {
129 TeardownSocketTcti(this->tcti_context);
130 }
131 if (this->sys_context)
132 {
133 Tss2_Sys_Finalize(this->sys_context);
134 free(this->sys_context);
135 }
136 }
137
138 METHOD(tpm_tss_t, get_version, tpm_version_t,
139 private_tpm_tss_tss2_t *this)
140 {
141 return TPM_VERSION_2_0;
142 }
143
144 METHOD(tpm_tss_t, get_version_info, chunk_t,
145 private_tpm_tss_tss2_t *this)
146 {
147 return chunk_empty;
148 }
149
150 /**
151 * read the public key portion of a TSS 2.0 AIK key from NVRAM
152 */
153 bool read_public(private_tpm_tss_tss2_t *this, TPMI_DH_OBJECT handle,
154 TPM2B_PUBLIC *public)
155 {
156 uint32_t rval;
157
158 TPM2B_NAME name = { { sizeof(TPM2B_NAME)-2, } };
159 TPM2B_NAME qualified_name = { { sizeof(TPM2B_NAME)-2, } };
160
161 TPMS_AUTH_RESPONSE session_data;
162 TSS2_SYS_RSP_AUTHS sessions_data;
163 TPMS_AUTH_RESPONSE *session_data_array[1];
164
165 session_data_array[0] = &session_data;
166 sessions_data.rspAuths = &session_data_array[0];
167 sessions_data.rspAuthsCount = 1;
168
169 /* always send simulator platform command, ignored by true RM */
170 PlatformCommand(this->tcti_context ,MS_SIM_POWER_ON );
171 PlatformCommand(this->tcti_context, MS_SIM_NV_ON );
172
173 /* read public key for a given object handle from TPM 2.0 NVRAM */
174 rval = Tss2_Sys_ReadPublic(this->sys_context, handle, 0, public, &name,
175 &qualified_name, &sessions_data);
176
177 PlatformCommand(this->tcti_context, MS_SIM_POWER_OFF);
178
179 if (rval != TPM_RC_SUCCESS)
180 {
181 DBG1(DBG_PTS, "%s could not read public key from handle 0x%08x: 0x%06x",
182 LABEL, handle, rval);
183 return FALSE;
184 }
185 return TRUE;
186 }
187
188 METHOD(tpm_tss_t, generate_aik, bool,
189 private_tpm_tss_tss2_t *this, chunk_t ca_modulus, chunk_t *aik_blob,
190 chunk_t *aik_pubkey, chunk_t *identity_req)
191 {
192 return FALSE;
193 }
194
195 METHOD(tpm_tss_t, get_public, chunk_t,
196 private_tpm_tss_tss2_t *this, uint32_t handle)
197 {
198 TPM2B_PUBLIC public = { { 0, } };
199 chunk_t aik_blob, aik_pubkey = chunk_empty;
200
201 if (!read_public(this, handle, &public))
202 {
203 return chunk_empty;
204 }
205
206 aik_blob = chunk_create((u_char*)&public, sizeof(public));
207 DBG3(DBG_LIB, "%s AIK public key blob: %B", LABEL, &aik_blob);
208
209 /* convert TSS 2.0 AIK public key blot into PKCS#1 format */
210 switch (public.t.publicArea.type)
211 {
212 case TPM_ALG_RSA:
213 {
214 TPM2B_PUBLIC_KEY_RSA *rsa;
215 chunk_t aik_exponent, aik_modulus;
216
217 rsa = &public.t.publicArea.unique.rsa;
218 aik_modulus = chunk_create(rsa->t.buffer, rsa->t.size);
219 aik_exponent = chunk_from_chars(0x01, 0x00, 0x01);
220
221 /* subjectPublicKeyInfo encoding of AIK RSA key */
222 if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER,
223 NULL, &aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus,
224 CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END))
225 {
226 DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of AIK key "
227 "failed", LABEL);
228 }
229 break;
230 }
231 case TPM_ALG_ECC:
232 {
233 TPMS_ECC_POINT *ecc;
234 chunk_t ecc_point;
235 uint8_t *pos;
236
237 ecc = &public.t.publicArea.unique.ecc;
238
239 /* allocate space for bit string */
240 pos = asn1_build_object(&ecc_point, ASN1_BIT_STRING,
241 2 + ecc->x.t.size + ecc->y.t.size);
242 /* bit string length is a multiple of octets */
243 *pos++ = 0x00;
244 /* uncompressed ECC point format */
245 *pos++ = 0x04;
246 /* copy x coordinate of ECC point */
247 memcpy(pos, ecc->x.t.buffer, ecc->x.t.size);
248 pos += ecc->x.t.size;
249 /* copy y coordinate of ECC point */
250 memcpy(pos, ecc->y.t.buffer, ecc->y.t.size);
251 /* subjectPublicKeyInfo encoding of AIK ECC key */
252 aik_pubkey = asn1_wrap(ASN1_SEQUENCE, "mm",
253 asn1_wrap(ASN1_SEQUENCE, "mm",
254 asn1_build_known_oid(OID_EC_PUBLICKEY),
255 asn1_build_known_oid(ecc->x.t.size == 32 ?
256 OID_PRIME256V1 : OID_SECT384R1)),
257 ecc_point);
258 break;
259 }
260 default:
261 DBG1(DBG_PTS, "%s unsupported AIK key type", LABEL);
262 }
263
264 return aik_pubkey;
265 }
266
267 METHOD(tpm_tss_t, destroy, void,
268 private_tpm_tss_tss2_t *this)
269 {
270 finalize_context(this);
271 free(this);
272 }
273
274 /**
275 * See header
276 */
277 tpm_tss_t *tpm_tss_tss2_create()
278 {
279 private_tpm_tss_tss2_t *this;
280 bool available;
281
282 INIT(this,
283 .public = {
284 .get_version = _get_version,
285 .get_version_info = _get_version_info,
286 .generate_aik = _generate_aik,
287 .get_public = _get_public,
288 .destroy = _destroy,
289 },
290 );
291
292 available = initialize_context(this);
293 DBG1(DBG_PTS, "TPM 2.0 via TSS2 %savailable", available ? "" : "not ");
294
295 if (!available)
296 {
297 destroy(this);
298 return NULL;
299 }
300 return &this->public;
301 }
302
303 #else /* TSS_TSS2 */
304
305 tpm_tss_t *tpm_tss_tss2_create()
306 {
307 return NULL;
308 }
309
310 #endif /* TSS_TSS2 */
311
312