]>
Commit | Line | Data |
---|---|---|
c08753bd | 1 | /* |
d647a8f9 | 2 | * Copyright (C) 2016-2020 Andreas Steffen |
c08753bd AS |
3 | * HSR Hochschule fuer Technik Rapperswil |
4 | * | |
5 | * Copyright (c) 2008 Hal Finney | |
6 | * | |
7 | * Permission is hereby granted, free of charge, to any person obtaining a copy | |
8 | * of this software and associated documentation files (the "Software"), to deal | |
9 | * in the Software without restriction, including without limitation the rights | |
10 | * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell | |
11 | * copies of the Software, and to permit persons to whom the Software is | |
12 | * furnished to do so, subject to the following conditions: | |
13 | * | |
14 | * The above copyright notice and this permission notice shall be included in | |
15 | * all copies or substantial portions of the Software. | |
16 | * | |
17 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | |
18 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | |
19 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | |
20 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | |
21 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, | |
22 | * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN | |
23 | * THE SOFTWARE. | |
24 | */ | |
25 | ||
26 | #include "tpm_tss_trousers.h" | |
27 | ||
28 | #ifdef TSS_TROUSERS | |
29 | ||
30d4989a AS |
30 | #ifdef _BASETSD_H_ |
31 | /* MinGW defines _BASETSD_H_, but TSS checks for _BASETSD_H */ | |
32 | # define _BASETSD_H | |
33 | #endif | |
34 | ||
c08753bd AS |
35 | #include <trousers/tss.h> |
36 | #include <trousers/trousers.h> | |
37 | ||
d647a8f9 AS |
38 | #include <unistd.h> |
39 | ||
c08753bd AS |
40 | #define LABEL "TPM 1.2 -" |
41 | ||
42 | /* size in bytes of a TSS AIK public key blob */ | |
30d4989a AS |
43 | #define AIK_PUBKEY_BLOB_SIZE 284 |
44 | ||
45 | /* maximum number of PCR registers */ | |
46 | #define PCR_NUM_MAX 24 | |
c08753bd AS |
47 | |
48 | typedef struct private_tpm_tss_trousers_t private_tpm_tss_trousers_t; | |
30d4989a | 49 | typedef struct aik_t aik_t; |
c08753bd AS |
50 | |
51 | /** | |
52 | * Private data of an tpm_tss_trousers_t object. | |
53 | */ | |
54 | struct private_tpm_tss_trousers_t { | |
55 | ||
56 | /** | |
57 | * Public tpm_tss_trousers_t interface. | |
58 | */ | |
30d4989a | 59 | tpm_tss_trousers_t interface; |
c08753bd AS |
60 | |
61 | /** | |
62 | * TSS context | |
63 | */ | |
64 | TSS_HCONTEXT hContext; | |
65 | ||
30d4989a AS |
66 | /** |
67 | * TPM handle | |
68 | */ | |
69 | TSS_HTPM hTPM; | |
70 | ||
fedc6769 AS |
71 | /** |
72 | * TPM version info | |
73 | */ | |
74 | chunk_t version_info; | |
75 | ||
30d4989a AS |
76 | /** |
77 | * List of AIKs retrievable by an object handle | |
78 | */ | |
79 | linked_list_t *aik_list; | |
80 | ||
c08753bd AS |
81 | }; |
82 | ||
30d4989a AS |
83 | struct aik_t { |
84 | /** AIK object handle */ | |
85 | uint32_t handle; | |
86 | ||
87 | /** AIK private key blob */ | |
88 | chunk_t blob; | |
89 | ||
90 | /** AIK public key */ | |
91 | chunk_t pubkey; | |
92 | }; | |
93 | ||
94 | static void free_aik(aik_t *this) | |
95 | { | |
96 | free(this->blob.ptr); | |
97 | free(this->pubkey.ptr); | |
98 | free(this); | |
99 | } | |
100 | ||
c08753bd AS |
101 | /** |
102 | * Initialize TSS context | |
fedc6769 AS |
103 | * |
104 | * TPM 1.2 Specification, Part 2 TPM Structures, 21.6 TPM_CAP_VERSION_INFO | |
105 | * | |
106 | * typedef struct tdTPM_VERSION { | |
107 | * TPM_VERSION_BYTE major; | |
108 | * TPM_VERSION_BYTE minor; | |
109 | * BYTE revMajor; | |
110 | * BYTE revMinor; | |
111 | * } TPM_VERSION; | |
112 | * | |
113 | * typedef struct tdTPM_CAP_VERSION_INFO { | |
114 | * TPM_STRUCTURE_TAG tag; | |
115 | * TPM_VERSION version; | |
116 | * UINT16 specLevel; | |
117 | * BYTE errataRev; | |
118 | * BYTE tpmVendorID[4]; | |
119 | * UINT16 vendorSpecificSize; | |
120 | * [size_is(vendorSpecificSize)] BYTE* vendorSpecific; | |
121 | * } TPM_CAP_VERSION_INFO; | |
c08753bd AS |
122 | */ |
123 | static bool initialize_context(private_tpm_tss_trousers_t *this) | |
124 | { | |
fedc6769 AS |
125 | uint8_t *version_ptr; |
126 | uint32_t version_len; | |
127 | ||
c08753bd | 128 | TSS_RESULT result; |
fedc6769 | 129 | TPM_CAP_VERSION_INFO *info; |
c08753bd AS |
130 | |
131 | result = Tspi_Context_Create(&this->hContext); | |
132 | if (result != TSS_SUCCESS) | |
133 | { | |
fedc6769 AS |
134 | DBG1(DBG_PTS, "%s could not created context: 0x%x", |
135 | LABEL, result); | |
c08753bd AS |
136 | return FALSE; |
137 | } | |
138 | ||
139 | result = Tspi_Context_Connect(this->hContext, NULL); | |
140 | if (result != TSS_SUCCESS) | |
141 | { | |
fedc6769 AS |
142 | DBG1(DBG_PTS, "%s could not connect with context: 0x%x", |
143 | LABEL, result); | |
c08753bd AS |
144 | return FALSE; |
145 | } | |
146 | ||
30d4989a | 147 | result = Tspi_Context_GetTpmObject (this->hContext, &this->hTPM); |
c08753bd AS |
148 | if (result != TSS_SUCCESS) |
149 | { | |
fedc6769 AS |
150 | DBG1(DBG_PTS, "%s could not get TPM object: 0x%x", |
151 | LABEL, result); | |
152 | return FALSE; | |
153 | } | |
154 | ||
30d4989a AS |
155 | result = Tspi_TPM_GetCapability(this->hTPM, TSS_TPMCAP_VERSION_VAL, 0, |
156 | NULL, &version_len, &version_ptr); | |
fedc6769 AS |
157 | if (result != TSS_SUCCESS) |
158 | { | |
159 | DBG1(DBG_PTS, "%s Tspi_TPM_GetCapability failed: 0x%x", | |
160 | LABEL, result); | |
c08753bd AS |
161 | return FALSE; |
162 | } | |
fedc6769 AS |
163 | |
164 | info = (TPM_CAP_VERSION_INFO *)version_ptr; | |
165 | DBG2(DBG_PTS, "TPM Version Info: Chip Version: %u.%u.%u.%u, " | |
166 | "Spec Level: %u, Errata Rev: %u, Vendor ID: %.4s", | |
167 | info->version.major, info->version.minor, | |
168 | info->version.revMajor, info->version.revMinor, | |
169 | untoh16(&info->specLevel), info->errataRev, info->tpmVendorID); | |
170 | ||
171 | this->version_info = chunk_clone(chunk_create(version_ptr, version_len)); | |
172 | ||
c08753bd AS |
173 | return TRUE; |
174 | } | |
175 | ||
176 | /** | |
177 | * Finalize TSS context | |
178 | */ | |
179 | static void finalize_context(private_tpm_tss_trousers_t *this) | |
180 | { | |
181 | if (this->hContext) | |
182 | { | |
183 | Tspi_Context_FreeMemory(this->hContext, NULL); | |
184 | Tspi_Context_Close(this->hContext); | |
185 | } | |
186 | } | |
187 | ||
188 | METHOD(tpm_tss_t, get_version, tpm_version_t, | |
189 | private_tpm_tss_trousers_t *this) | |
190 | { | |
191 | return TPM_VERSION_1_2; | |
192 | } | |
193 | ||
fedc6769 AS |
194 | METHOD(tpm_tss_t, get_version_info, chunk_t, |
195 | private_tpm_tss_trousers_t *this) | |
196 | { | |
197 | return this->version_info; | |
198 | } | |
199 | ||
c08753bd AS |
200 | METHOD(tpm_tss_t, generate_aik, bool, |
201 | private_tpm_tss_trousers_t *this, chunk_t ca_modulus, chunk_t *aik_blob, | |
202 | chunk_t *aik_pubkey, chunk_t *identity_req) | |
203 | { | |
204 | chunk_t aik_pubkey_blob; | |
205 | chunk_t aik_modulus; | |
206 | chunk_t aik_exponent; | |
207 | ||
208 | TSS_RESULT result; | |
c08753bd AS |
209 | TSS_HKEY hSRK; |
210 | TSS_HKEY hPCAKey; | |
211 | TSS_HPOLICY hSrkPolicy; | |
212 | TSS_HPOLICY hTPMPolicy; | |
213 | TSS_HKEY hIdentKey; | |
214 | TSS_UUID SRK_UUID = TSS_UUID_SRK; | |
215 | BYTE secret[] = TSS_WELL_KNOWN_SECRET; | |
216 | BYTE *IdentityReq; | |
217 | UINT32 IdentityReqLen; | |
218 | BYTE *blob; | |
219 | UINT32 blobLen; | |
220 | ||
221 | /* get SRK plus SRK policy and set SRK secret */ | |
222 | result = Tspi_Context_LoadKeyByUUID(this->hContext, TSS_PS_TYPE_SYSTEM, | |
223 | SRK_UUID, &hSRK); | |
224 | if (result != TSS_SUCCESS) | |
225 | { | |
226 | DBG1(DBG_PTS, "%s Tspi_Context_LoadKeyByUUID for SRK failed: 0x%x", | |
227 | LABEL, result); | |
228 | return FALSE; | |
229 | } | |
230 | result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &hSrkPolicy); | |
231 | if (result != TSS_SUCCESS) | |
232 | { | |
233 | DBG1(DBG_PTS, "%s Tspi_GetPolicyObject or SRK failed: 0x%x ", | |
234 | LABEL, result); | |
235 | return FALSE; | |
236 | } | |
237 | result = Tspi_Policy_SetSecret(hSrkPolicy, TSS_SECRET_MODE_SHA1, 20, secret); | |
238 | if (result != TSS_SUCCESS) | |
239 | { | |
240 | DBG1(DBG_PTS, "%s Tspi_Policy_SetSecret for SRK failed: 0x%x ", | |
241 | LABEL, result); | |
242 | return FALSE; | |
243 | } | |
244 | ||
245 | /* get TPM plus TPM policy and set TPM secret */ | |
30d4989a | 246 | result = Tspi_Context_GetTpmObject (this->hContext, &this->hTPM); |
c08753bd AS |
247 | if (result != TSS_SUCCESS) |
248 | { | |
249 | DBG1(DBG_PTS, "%s Tspi_Context_GetTpmObject failed: 0x%x", | |
250 | LABEL, result); | |
251 | return FALSE; | |
252 | } | |
30d4989a | 253 | result = Tspi_GetPolicyObject(this->hTPM, TSS_POLICY_USAGE, &hTPMPolicy); |
c08753bd AS |
254 | if (result != TSS_SUCCESS) |
255 | { | |
256 | DBG1(DBG_PTS, "%s Tspi_GetPolicyObject for TPM failed: 0x%x", | |
257 | LABEL, result); | |
258 | return FALSE; | |
259 | } | |
260 | result = Tspi_Policy_SetSecret(hTPMPolicy, TSS_SECRET_MODE_SHA1, 20, secret); | |
261 | if (result != TSS_SUCCESS) | |
262 | { | |
263 | DBG1(DBG_PTS,"%s Tspi_Policy_SetSecret for TPM failed: 0x%x", | |
264 | LABEL, result); | |
265 | return FALSE; | |
266 | } | |
267 | ||
268 | /* create context for a 2048 bit AIK */ | |
269 | result = Tspi_Context_CreateObject(this->hContext, TSS_OBJECT_TYPE_RSAKEY, | |
270 | TSS_KEY_TYPE_IDENTITY | TSS_KEY_SIZE_2048 | | |
271 | TSS_KEY_VOLATILE | TSS_KEY_NOT_MIGRATABLE, &hIdentKey); | |
272 | if (result != TSS_SUCCESS) | |
273 | { | |
274 | DBG1(DBG_PTS, "%s Tspi_Context_CreateObject for key failed: 0x%x", | |
275 | LABEL, result); | |
276 | return FALSE; | |
277 | } | |
278 | ||
279 | /* create context for the Privacy CA public key and assign modulus */ | |
280 | result = Tspi_Context_CreateObject(this->hContext, TSS_OBJECT_TYPE_RSAKEY, | |
281 | TSS_KEY_TYPE_LEGACY|TSS_KEY_SIZE_2048, &hPCAKey); | |
282 | if (result != TSS_SUCCESS) | |
283 | { | |
284 | DBG1(DBG_PTS, "%s Tspi_Context_CreateObject for PCA failed: 0x%x", | |
285 | LABEL, result); | |
286 | return FALSE; | |
287 | } | |
288 | result = Tspi_SetAttribData (hPCAKey, TSS_TSPATTRIB_RSAKEY_INFO, | |
289 | TSS_TSPATTRIB_KEYINFO_RSA_MODULUS, ca_modulus.len, | |
290 | ca_modulus.ptr); | |
291 | if (result != TSS_SUCCESS) | |
292 | { | |
293 | DBG1(DBG_PTS, "%s Tspi_SetAttribData for PCA modulus failed: 0x%x", | |
294 | LABEL, result); | |
295 | return FALSE; | |
296 | } | |
297 | result = Tspi_SetAttribUint32(hPCAKey, TSS_TSPATTRIB_KEY_INFO, | |
298 | TSS_TSPATTRIB_KEYINFO_ENCSCHEME, TSS_ES_RSAESPKCSV15); | |
299 | if (result != TSS_SUCCESS) | |
300 | { | |
301 | DBG1(DBG_PTS,"%s Tspi_SetAttribUint32 for PCA encryption scheme " | |
302 | "failed: 0x%x", LABEL, result); | |
303 | return FALSE; | |
304 | } | |
305 | ||
306 | /* generate AIK */ | |
307 | DBG1(DBG_LIB, "Generating identity key..."); | |
30d4989a | 308 | result = Tspi_TPM_CollateIdentityRequest(this->hTPM, hSRK, hPCAKey, 0, NULL, |
c08753bd AS |
309 | hIdentKey, TSS_ALG_AES, &IdentityReqLen, &IdentityReq); |
310 | if (result != TSS_SUCCESS) | |
311 | { | |
312 | DBG1(DBG_PTS, "%s Tspi_TPM_CollateIdentityRequest failed: 0x%x", | |
313 | LABEL, result); | |
314 | return FALSE; | |
315 | } | |
316 | *identity_req = chunk_create(IdentityReq, IdentityReqLen); | |
317 | DBG3(DBG_LIB, "%s Identity Request: %B", LABEL, identity_req); | |
318 | ||
319 | /* load identity key */ | |
320 | result = Tspi_Key_LoadKey (hIdentKey, hSRK); | |
321 | if (result != TSS_SUCCESS) | |
322 | { | |
323 | DBG1(DBG_PTS, "%s Tspi_Key_LoadKey for AIK failed: 0x%x", | |
324 | LABEL, result); | |
325 | return FALSE; | |
326 | } | |
327 | ||
328 | /* output AIK private key in TSS blob format */ | |
329 | result = Tspi_GetAttribData (hIdentKey, TSS_TSPATTRIB_KEY_BLOB, | |
330 | TSS_TSPATTRIB_KEYBLOB_BLOB, &blobLen, &blob); | |
331 | if (result != TSS_SUCCESS) | |
332 | { | |
333 | DBG1(DBG_PTS, "%s Tspi_GetAttribData for private key blob failed: 0x%x", | |
334 | LABEL, result); | |
335 | return FALSE; | |
336 | } | |
337 | *aik_blob = chunk_create(blob, blobLen); | |
338 | DBG3(DBG_LIB, "%s AIK private key blob: %B", LABEL, aik_blob); | |
339 | ||
340 | /* output AIK Public Key in TSS blob format */ | |
341 | result = Tspi_GetAttribData (hIdentKey, TSS_TSPATTRIB_KEY_BLOB, | |
342 | TSS_TSPATTRIB_KEYBLOB_PUBLIC_KEY, &blobLen, &blob); | |
343 | if (result != TSS_SUCCESS) | |
344 | { | |
345 | DBG1(DBG_PTS, "%s Tspi_GetAttribData for public key blob failed: 0x%x", | |
346 | LABEL, result); | |
347 | return FALSE; | |
348 | } | |
349 | aik_pubkey_blob = chunk_create(blob, blobLen); | |
350 | DBG3(DBG_LIB, "%s AIK public key blob: %B", LABEL, &aik_pubkey_blob); | |
351 | ||
352 | /* create a trusted AIK public key */ | |
353 | if (aik_pubkey_blob.len != AIK_PUBKEY_BLOB_SIZE) | |
354 | { | |
355 | DBG1(DBG_PTS, "%s AIK public key is not in TSS blob format", | |
356 | LABEL); | |
357 | return FALSE; | |
358 | } | |
359 | aik_modulus = chunk_skip(aik_pubkey_blob, AIK_PUBKEY_BLOB_SIZE - 256); | |
360 | aik_exponent = chunk_from_chars(0x01, 0x00, 0x01); | |
361 | ||
362 | /* output subjectPublicKeyInfo encoding of AIK public key */ | |
363 | if (!lib->encoding->encode(lib->encoding, PUBKEY_SPKI_ASN1_DER, NULL, | |
364 | aik_pubkey, CRED_PART_RSA_MODULUS, aik_modulus, | |
365 | CRED_PART_RSA_PUB_EXP, aik_exponent, CRED_PART_END)) | |
366 | { | |
367 | DBG1(DBG_PTS, "%s subjectPublicKeyInfo encoding of AIK key failed", | |
368 | LABEL); | |
369 | return FALSE; | |
370 | } | |
371 | return TRUE; | |
372 | } | |
373 | ||
374 | METHOD(tpm_tss_t, get_public, chunk_t, | |
375 | private_tpm_tss_trousers_t *this, uint32_t handle) | |
376 | { | |
30d4989a AS |
377 | enumerator_t *enumerator; |
378 | chunk_t aik_pubkey = chunk_empty; | |
379 | aik_t *aik; | |
380 | ||
381 | enumerator = this->aik_list->create_enumerator(this->aik_list); | |
382 | while (enumerator->enumerate(enumerator, &aik)) | |
383 | { | |
384 | if (aik->handle == handle) | |
385 | { | |
386 | aik_pubkey = chunk_clone(aik->pubkey); | |
387 | break; | |
388 | } | |
389 | } | |
390 | enumerator->destroy(enumerator); | |
391 | ||
392 | return aik_pubkey; | |
393 | } | |
394 | ||
7ca3b3da TB |
395 | METHOD(tpm_tss_t, supported_signature_schemes, enumerator_t*, |
396 | private_tpm_tss_trousers_t *this, uint32_t handle) | |
397 | { | |
398 | return enumerator_create_empty(); | |
399 | } | |
400 | ||
30d4989a AS |
401 | METHOD(tpm_tss_t, read_pcr, bool, |
402 | private_tpm_tss_trousers_t *this, uint32_t pcr_num, chunk_t *pcr_value, | |
403 | hash_algorithm_t alg) | |
404 | { | |
405 | TSS_RESULT result; | |
406 | uint8_t *value; | |
407 | uint32_t len; | |
408 | ||
409 | result = Tspi_TPM_PcrRead(this->hTPM, pcr_num, &len, &value); | |
410 | if (result != TSS_SUCCESS) | |
411 | { | |
412 | DBG1(DBG_PTS, "%s Tspi_TPM_PcrRead failed: 0x%x", LABEL, result); | |
413 | return FALSE; | |
414 | } | |
415 | *pcr_value = chunk_clone(chunk_create(value, len)); | |
416 | ||
417 | return TRUE; | |
418 | } | |
419 | ||
420 | METHOD(tpm_tss_t, extend_pcr, bool, | |
421 | private_tpm_tss_trousers_t *this, uint32_t pcr_num, chunk_t *pcr_value, | |
422 | chunk_t data, hash_algorithm_t alg) | |
423 | { | |
424 | TSS_RESULT result; | |
425 | uint32_t pcr_len; | |
426 | uint8_t *pcr_ptr; | |
427 | ||
428 | result = Tspi_TPM_PcrExtend(this->hTPM, pcr_num, data.len, data.ptr, | |
429 | NULL, &pcr_len, &pcr_ptr); | |
430 | if (result != TSS_SUCCESS) | |
431 | { | |
432 | DBG1(DBG_PTS, "%s Tspi_TPM_PcrExtend failed: 0x%x", LABEL, result); | |
433 | return FALSE; | |
434 | } | |
435 | *pcr_value = chunk_clone(chunk_create(pcr_ptr, pcr_len)); | |
436 | ||
437 | return TRUE; | |
438 | } | |
439 | ||
440 | METHOD(tpm_tss_t, quote, bool, | |
441 | private_tpm_tss_trousers_t *this, uint32_t aik_handle, uint32_t pcr_sel, | |
721ed31b AS |
442 | hash_algorithm_t alg, chunk_t data, tpm_quote_mode_t *quote_mode, |
443 | tpm_tss_quote_info_t **quote_info, chunk_t *quote_sig) | |
30d4989a AS |
444 | { |
445 | TSS_HKEY hAIK; | |
446 | TSS_HKEY hSRK; | |
447 | TSS_HPOLICY srkUsagePolicy; | |
448 | TSS_UUID SRK_UUID = TSS_UUID_SRK; | |
449 | TSS_HPCRS hPcrComposite; | |
450 | TSS_VALIDATION valData; | |
451 | TSS_RESULT result; | |
452 | uint8_t secret[] = TSS_WELL_KNOWN_SECRET; | |
453 | uint8_t *version_info, *comp_hash; | |
454 | uint32_t version_info_size, pcr; | |
455 | aik_t *aik; | |
456 | chunk_t aik_blob = chunk_empty; | |
721ed31b | 457 | chunk_t quote_chunk, pcr_digest; |
30d4989a AS |
458 | enumerator_t *enumerator; |
459 | bool success = FALSE; | |
460 | ||
461 | /* Retrieve SRK from TPM and set the authentication to well known secret*/ | |
462 | result = Tspi_Context_LoadKeyByUUID(this->hContext, TSS_PS_TYPE_SYSTEM, | |
463 | SRK_UUID, &hSRK); | |
464 | if (result != TSS_SUCCESS) | |
465 | { | |
466 | DBG1(DBG_PTS, "%s Tspi_Context_LoadKeyByUUID for SRK failed: 0x%x", | |
467 | LABEL, result); | |
468 | return FALSE; | |
469 | } | |
470 | result = Tspi_GetPolicyObject(hSRK, TSS_POLICY_USAGE, &srkUsagePolicy); | |
471 | if (result != TSS_SUCCESS) | |
472 | { | |
473 | DBG1(DBG_PTS, "%s Tspi_GetPolicyObject for SRK failed: 0x%x", | |
474 | LABEL, result); | |
475 | return FALSE; | |
476 | } | |
477 | result = Tspi_Policy_SetSecret(srkUsagePolicy, TSS_SECRET_MODE_SHA1, | |
478 | 20, secret); | |
479 | if (result != TSS_SUCCESS) | |
480 | { | |
481 | DBG1(DBG_PTS, "%s Tspi_Policy_SetSecret for SRK failed: 0x%x", | |
482 | LABEL, result); | |
483 | return FALSE; | |
484 | } | |
485 | ||
486 | /* Retrieve AIK using its handle and load private key into TPM 1.2 */ | |
487 | enumerator = this->aik_list->create_enumerator(this->aik_list); | |
488 | while (enumerator->enumerate(enumerator, &aik)) | |
489 | { | |
490 | if (aik->handle == aik_handle) | |
491 | { | |
492 | aik_blob = aik->blob; | |
493 | break; | |
494 | } | |
495 | } | |
496 | enumerator->destroy(enumerator); | |
497 | ||
498 | if (aik_blob.len == 0) | |
499 | { | |
500 | DBG1(DBG_PTS, "%s AIK private key for handle 0x%80x not found", LABEL); | |
501 | return FALSE; | |
502 | } | |
503 | result = Tspi_Context_LoadKeyByBlob(this->hContext, hSRK, aik_blob.len, | |
504 | aik_blob.ptr, &hAIK); | |
505 | if (result != TSS_SUCCESS) | |
506 | { | |
507 | DBG1(DBG_PTS, "%s Tspi_Context_LoadKeyByBlob for AIK failed: 0x%x", | |
508 | LABEL, result); | |
509 | return FALSE; | |
510 | } | |
511 | ||
512 | /* Create PCR composite object */ | |
513 | result = Tspi_Context_CreateObject(this->hContext, TSS_OBJECT_TYPE_PCRS, | |
721ed31b AS |
514 | (*quote_mode == TPM_QUOTE) ? TSS_PCRS_STRUCT_INFO : |
515 | TSS_PCRS_STRUCT_INFO_SHORT, | |
30d4989a AS |
516 | &hPcrComposite); |
517 | if (result != TSS_SUCCESS) | |
518 | { | |
519 | DBG1(DBG_PTS, "%s Tspi_Context_CreateObject for pcrComposite failed: " | |
520 | "0x%x", LABEL, result); | |
521 | goto err1; | |
522 | } | |
523 | ||
524 | /* Select PCRs */ | |
525 | for (pcr = 0; pcr < PCR_NUM_MAX; pcr++) | |
526 | { | |
527 | if (pcr_sel & (1 << pcr)) | |
528 | { | |
721ed31b | 529 | result = (*quote_mode == TPM_QUOTE) ? |
30d4989a AS |
530 | Tspi_PcrComposite_SelectPcrIndex(hPcrComposite, pcr) : |
531 | Tspi_PcrComposite_SelectPcrIndexEx(hPcrComposite, pcr, | |
532 | TSS_PCRS_DIRECTION_RELEASE); | |
533 | if (result != TSS_SUCCESS) | |
534 | { | |
535 | DBG1(DBG_PTS, "%s Tspi_PcrComposite_SelectPcrIndex failed: " | |
536 | "0x%x", LABEL, result); | |
537 | goto err2; | |
538 | } | |
539 | } | |
540 | } | |
541 | ||
542 | /* Set the Validation Data */ | |
543 | valData.ulExternalDataLength = data.len; | |
544 | valData.rgbExternalData = data.ptr; | |
545 | ||
546 | /* TPM Quote */ | |
721ed31b | 547 | result = (*quote_mode == TPM_QUOTE) ? |
30d4989a | 548 | Tspi_TPM_Quote (this->hTPM, hAIK, hPcrComposite, &valData) : |
721ed31b AS |
549 | Tspi_TPM_Quote2(this->hTPM, hAIK, |
550 | *quote_mode == TPM_QUOTE2_VERSION_INFO, | |
30d4989a AS |
551 | hPcrComposite, &valData, &version_info_size, |
552 | &version_info); | |
553 | if (result != TSS_SUCCESS) | |
554 | { | |
555 | DBG1(DBG_PTS, "%s Tspi_TPM_Quote%s failed: 0x%x", LABEL, | |
721ed31b | 556 | (*quote_mode == TPM_QUOTE) ? "" : "2", result); |
30d4989a AS |
557 | goto err2; |
558 | } | |
559 | ||
721ed31b | 560 | if (*quote_mode == TPM_QUOTE) |
30d4989a AS |
561 | { |
562 | /* TPM_Composite_Hash starts at byte 8 of TPM_Quote_Info structure */ | |
563 | comp_hash = valData.rgbData + 8; | |
564 | } | |
565 | else | |
566 | { | |
567 | /* TPM_Composite_Hash is last 20 bytes of TPM_Quote_Info2 structure */ | |
568 | comp_hash = valData.rgbData + valData.ulDataLength - version_info_size - | |
569 | HASH_SIZE_SHA1; | |
570 | } | |
721ed31b AS |
571 | pcr_digest = chunk_create(comp_hash, HASH_SIZE_SHA1); |
572 | DBG2(DBG_PTS, "PCR composite digest: %B", &pcr_digest); | |
573 | ||
574 | quote_chunk = chunk_create(valData.rgbData, valData.ulDataLength); | |
575 | DBG2(DBG_PTS, "TPM Quote Info: %B", "e_chunk); | |
30d4989a | 576 | |
721ed31b | 577 | *quote_info = tpm_tss_quote_info_create(*quote_mode, HASH_SHA1, pcr_digest); |
30d4989a AS |
578 | |
579 | *quote_sig = chunk_clone(chunk_create(valData.rgbValidationData, | |
580 | valData.ulValidationDataLength)); | |
721ed31b | 581 | DBG2(DBG_PTS, "TPM Quote Signature: %B", quote_sig); |
30d4989a AS |
582 | |
583 | success = TRUE; | |
584 | ||
585 | err2: | |
586 | Tspi_Context_CloseObject(this->hContext, hPcrComposite); | |
587 | err1: | |
588 | Tspi_Context_CloseObject(this->hContext, hAIK); | |
589 | ||
590 | return success; | |
c08753bd AS |
591 | } |
592 | ||
e8736028 AS |
593 | METHOD(tpm_tss_t, sign, bool, |
594 | private_tpm_tss_trousers_t *this, uint32_t hierarchy, uint32_t handle, | |
fd21c40b AS |
595 | signature_scheme_t scheme, void *params, chunk_t data, chunk_t pin, |
596 | chunk_t *signature) | |
e8736028 AS |
597 | { |
598 | return FALSE; | |
599 | } | |
600 | ||
2b233c8a AS |
601 | METHOD(tpm_tss_t, get_random, bool, |
602 | private_tpm_tss_trousers_t *this, size_t bytes, uint8_t *buffer) | |
603 | { | |
604 | return FALSE; | |
605 | } | |
606 | ||
e850d000 AS |
607 | METHOD(tpm_tss_t, get_data, bool, |
608 | private_tpm_tss_trousers_t *this, uint32_t hierarchy, uint32_t handle, | |
609 | chunk_t pin, chunk_t *data) | |
610 | { | |
611 | return FALSE; | |
612 | } | |
613 | ||
d647a8f9 AS |
614 | METHOD(tpm_tss_t, get_event_digest, bool, |
615 | private_tpm_tss_trousers_t *this, int fd, chunk_t *digest) | |
616 | { | |
617 | *digest = chunk_alloc(HASH_SIZE_SHA1); | |
618 | ||
619 | return read(fd, digest->ptr, digest->len) == digest->len; | |
620 | } | |
621 | ||
c08753bd AS |
622 | METHOD(tpm_tss_t, destroy, void, |
623 | private_tpm_tss_trousers_t *this) | |
624 | { | |
625 | finalize_context(this); | |
30d4989a | 626 | this->aik_list->destroy_function(this->aik_list, (void*)free_aik); |
fedc6769 | 627 | free(this->version_info.ptr); |
c08753bd AS |
628 | free(this); |
629 | } | |
630 | ||
30d4989a AS |
631 | METHOD(tpm_tss_trousers_t, load_aik, void, |
632 | private_tpm_tss_trousers_t *this, chunk_t blob, chunk_t pubkey, | |
633 | uint32_t handle) | |
634 | { | |
635 | aik_t *item; | |
636 | ||
637 | INIT(item, | |
638 | .handle = handle, | |
639 | .blob = blob, | |
640 | .pubkey = pubkey, | |
641 | ); | |
642 | ||
643 | this->aik_list->insert_last(this->aik_list, item); | |
644 | } | |
645 | ||
c08753bd AS |
646 | /** |
647 | * See header | |
648 | */ | |
649 | tpm_tss_t *tpm_tss_trousers_create() | |
650 | { | |
651 | private_tpm_tss_trousers_t *this; | |
652 | bool available; | |
653 | ||
654 | INIT(this, | |
30d4989a AS |
655 | .interface = { |
656 | .public = { | |
657 | .get_version = _get_version, | |
658 | .get_version_info = _get_version_info, | |
659 | .generate_aik = _generate_aik, | |
660 | .get_public = _get_public, | |
7ca3b3da | 661 | .supported_signature_schemes = _supported_signature_schemes, |
30d4989a | 662 | .read_pcr = _read_pcr, |
30d4989a | 663 | .extend_pcr = _extend_pcr, |
e8736028 AS |
664 | .quote = _quote, |
665 | .sign = _sign, | |
2b233c8a | 666 | .get_random = _get_random, |
e850d000 | 667 | .get_data = _get_data, |
d647a8f9 | 668 | .get_event_digest = _get_event_digest, |
30d4989a AS |
669 | .destroy = _destroy, |
670 | }, | |
671 | .load_aik = _load_aik, | |
c08753bd | 672 | }, |
30d4989a | 673 | .aik_list = linked_list_create(), |
c08753bd AS |
674 | ); |
675 | ||
676 | available = initialize_context(this); | |
677 | DBG1(DBG_PTS, "TPM 1.2 via TrouSerS %savailable", available ? "" : "not "); | |
678 | ||
679 | if (!available) | |
680 | { | |
681 | destroy(this); | |
682 | return NULL; | |
683 | } | |
30d4989a | 684 | return &this->interface.public; |
c08753bd AS |
685 | } |
686 | ||
687 | #else /* TSS_TROUSERS */ | |
688 | ||
689 | tpm_tss_t *tpm_tss_trousers_create() | |
690 | { | |
691 | return NULL; | |
692 | } | |
693 | ||
694 | #endif /* TSS_TROUSERS */ | |
695 | ||
696 | ||
697 |