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