]>
Commit | Line | Data |
---|---|---|
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" | |
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 | ||
fedc6769 AS |
144 | METHOD(tpm_tss_t, get_version_info, chunk_t, |
145 | private_tpm_tss_tss2_t *this) | |
146 | { | |
147 | return chunk_empty; | |
148 | } | |
149 | ||
c08753bd AS |
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, | |
fedc6769 | 285 | .get_version_info = _get_version_info, |
c08753bd AS |
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 |