1
2 /*
3 * Licensed Materials - Property of IBM
4 *
5 * trousers - An open source TCG Software Stack
6 *
7 * (C) Copyright International Business Machines Corp. 2004-2006
8 *
9 */
10
11
12 #include <string.h>
13
14 #include "trousers/tss.h"
15 #include "trousers_types.h"
16 #include "req_mgr.h"
17 #include "tcs_tsp.h"
18 #include "tcslog.h"
19 #include "tcs_utils.h"
20 #include "tcs_int_literals.h"
21
22 struct key_mem_cache *key_mem_cache_head = NULL;
23
24 TSS_UUID NULL_UUID = { 0, 0, 0, 0, 0, { 0, 0, 0, 0, 0, 0 } };
25
26
27 TSS_RESULT
add_cache_entry(TCS_CONTEXT_HANDLE hContext,BYTE * blob,TCS_KEY_HANDLE hParent,TPM_KEY_HANDLE hSlot,TCS_KEY_HANDLE * new)28 add_cache_entry(TCS_CONTEXT_HANDLE hContext,
29 BYTE* blob,
30 TCS_KEY_HANDLE hParent,
31 TPM_KEY_HANDLE hSlot,
32 TCS_KEY_HANDLE* new)
33 {
34 UINT64 offset;
35 TSS_RESULT result;
36 TCS_KEY_HANDLE tcsHandle;
37 TSS_KEY key, *pKey;
38
39 if (!blob) {
40 pKey = NULL;
41 } else {
42 offset = 0;
43 if ((result = UnloadBlob_TSS_KEY(&offset, blob, &key)))
44 return result;
45
46 if ((tcsHandle = mc_get_handle_by_pub(&key.pubKey, hParent)) == NULL_TCS_HANDLE) {
47 pKey = &key;
48 } else {
49 mc_set_slot_by_handle(tcsHandle, hSlot);
50 *new = tcsHandle;
51 goto done;
52 }
53 }
54
55 LogDebugFn("No existing key handle for this key, creating new one...");
56 /* Get a new TCS Key Handle */
57 tcsHandle = getNextTcsKeyHandle();
58 LogDebugFn("calling mc_add_entry, TCS handle: 0x%x, TPM handle 0x%x", tcsHandle, hSlot);
59
60 if ((result = mc_add_entry(tcsHandle, hSlot, pKey)))
61 goto done;
62
63 LogDebugFn("ctx_mark_key_loaded");
64 if (ctx_mark_key_loaded(hContext, tcsHandle)) {
65 LogError("Error marking key as loaded");
66 result = TCSERR(TSS_E_INTERNAL_ERROR);
67 goto done;
68 }
69
70 if ((result = mc_set_parent_by_handle(tcsHandle, hParent))) {
71 LogError("mc_set_parent_by_handle failed.");
72 goto done;
73 }
74
75 *new = tcsHandle;
76 done:
77 if (blob)
78 destroy_key_refs(&key);
79 return result;
80 }
81
82 /* Check that the context has this key loaded and return the associated slot. Do not search PS if
83 * the key is not found */
84 TSS_RESULT
get_slot_lite(TCS_CONTEXT_HANDLE hContext,TCS_KEY_HANDLE hKey,TPM_KEY_HANDLE * out)85 get_slot_lite(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE hKey, TPM_KEY_HANDLE *out)
86 {
87 if (ctx_has_key_loaded(hContext, hKey)) {
88 if ((*out = mc_get_slot_by_handle(hKey)) == NULL_TPM_HANDLE)
89 return TCSERR(TCS_E_INVALID_KEY);
90
91 return TSS_SUCCESS;
92 }
93
94 return TCSERR(TCS_E_INVALID_KEY);
95 }
96
97 /* XXX Can get_slot be merged with ensureKeyIsLoaded? */
98
99 /* Given a handle, get_slot searches the mem cache for a mapping to a TPM handle. If there is no
100 * mapping, it looks up the pub key of the handle and attempts to load it by finding its pub key
101 * in the persistent store. If that's not found, return error. */
102 TSS_RESULT
get_slot(TCS_CONTEXT_HANDLE hContext,TCS_KEY_HANDLE hKey,TPM_KEY_HANDLE * out)103 get_slot(TCS_CONTEXT_HANDLE hContext, TCS_KEY_HANDLE hKey, TPM_KEY_HANDLE *out)
104 {
105 TSS_RESULT result = TSS_SUCCESS;
106 TPM_STORE_PUBKEY *pub = NULL;
107 TPM_KEY_HANDLE slot;
108
109 LogDebugFn("calling mc_get_slot_by_handle");
110 if ((slot = mc_get_slot_by_handle(hKey)) == NULL_TPM_HANDLE) {
111 LogDebugFn("calling mc_get_pub_by_slot");
112 if ((pub = mc_get_pub_by_slot(hKey)) == NULL)
113 return TCSERR(TCS_E_KM_LOADFAILED);
114
115 LogDebugFn("calling LoadKeyShim");
116 /* Otherwise, try to load it using the shim */
117 result = LoadKeyShim(hContext, pub, NULL, &slot);
118 }
119
120 if (!result)
121 *out = slot;
122
123 return result;
124 }
125
126 /* load_key_init is the common entry point for all load key requests to the TCSD. These can come in
127 * as straight load or load2 requests, or through a transport session.
128 *
129 * We'll always attempt to load the key if
130 * A) It requires auth (load should fail if auth is bad, even when its already been loaded by
131 * another thread)
132 * B) Its in a transport session (the key blob is encrypted)
133 *
134 * Otherwise if the key is already loaded by another thread and it doesn't require auth, then we
135 * will just set *load_key to FALSE, telling the caller that there's no need to send anything to
136 * the TPM.
137 */
138 TSS_RESULT
load_key_init(TPM_COMMAND_CODE ord,TCS_CONTEXT_HANDLE hContext,TCS_KEY_HANDLE parent_handle,UINT32 blob_size,BYTE * blob,TSS_BOOL encrypted,TPM_AUTH * auth,TSS_BOOL * load_key,UINT64 * out_len,BYTE * out,TCS_KEY_HANDLE * handle,TPM_KEY_HANDLE * slot)139 load_key_init(TPM_COMMAND_CODE ord,
140 TCS_CONTEXT_HANDLE hContext,
141 TCS_KEY_HANDLE parent_handle,
142 UINT32 blob_size,
143 BYTE* blob,
144 TSS_BOOL encrypted,
145 TPM_AUTH* auth,
146 TSS_BOOL* load_key,
147 UINT64* out_len,
148 BYTE* out,
149 TCS_KEY_HANDLE* handle,
150 TPM_KEY_HANDLE* slot)
151 {
152 TSS_RESULT result = TSS_SUCCESS;
153 TSS_KEY key;
154 UINT64 offset;
155 TPM_KEY_HANDLE tpm_slot;
156 TCS_KEY_HANDLE tcs_handle;
157 TSS_BOOL canLoad;
158
159
160 if (!encrypted) {
161 offset = 0;
162 memset(&key, 0, sizeof(TSS_KEY));
163 if ((result = UnloadBlob_TSS_KEY(&offset, blob, &key)))
164 return result;
165 }
166
167 if (!auth && !encrypted) {
168 LogDebugFn("Checking if LoadKeyByBlob can be avoided by using existing key");
169
170 if ((tcs_handle = mc_get_handle_by_pub(&key.pubKey, parent_handle))) {
171 LogDebugFn("tcs key handle exists");
172
173 tpm_slot = mc_get_slot_by_handle(tcs_handle);
174 if (tpm_slot && (isKeyLoaded(tpm_slot) == TRUE)) {
175 LogDebugFn("Don't need to reload this key.");
176 *handle = tcs_handle;
177 *slot = tpm_slot;
178 *load_key = FALSE;
179 goto done;
180 }
181 }
182 }
183 *load_key = TRUE;
184
185 LogDebugFn("calling canILoadThisKey");
186 if (!encrypted) {
187 if ((result = canILoadThisKey(&(key.algorithmParms), &canLoad)))
188 goto error;
189
190 if (canLoad == FALSE) {
191 LogDebugFn("calling evictFirstKey");
192 /* Evict a key that isn't the parent */
193 if ((result = evictFirstKey(parent_handle)))
194 goto error;
195 }
196 }
197
198 error:
199 if (!encrypted)
200 destroy_key_refs(&key);
201 done:
202 return result;
203 }
204
205 TSS_RESULT
load_key_final(TCS_CONTEXT_HANDLE hContext,TCS_KEY_HANDLE parent_handle,TCS_KEY_HANDLE * tcs_handle,BYTE * blob,TPM_KEY_HANDLE slot)206 load_key_final(TCS_CONTEXT_HANDLE hContext,
207 TCS_KEY_HANDLE parent_handle,
208 TCS_KEY_HANDLE* tcs_handle,
209 BYTE* blob,
210 TPM_KEY_HANDLE slot)
211 {
212 if (*tcs_handle == NULL_TCS_HANDLE)
213 return add_cache_entry(hContext, blob, parent_handle, slot, tcs_handle);
214 else
215 return mc_set_slot_by_handle(*tcs_handle, slot);
216 }
217
218 TSS_RESULT
canILoadThisKey(TCPA_KEY_PARMS * parms,TSS_BOOL * b)219 canILoadThisKey(TCPA_KEY_PARMS *parms, TSS_BOOL *b)
220 {
221 UINT16 subCapLength;
222 UINT64 offset;
223 BYTE subCap[100];
224 TCPA_RESULT result;
225 UINT32 respDataLength;
226 BYTE *respData;
227
228 offset = 0;
229 LoadBlob_KEY_PARMS(&offset, subCap, parms);
230 subCapLength = offset;
231
232 if ((result = TCSP_GetCapability_Internal(InternalContext, TCPA_CAP_CHECK_LOADED,
233 subCapLength, subCap, &respDataLength,
234 &respData))) {
235 *b = FALSE;
236 LogDebugFn("NO");
237 return result;
238 }
239
240 *b = respData[0];
241 free(respData);
242 LogDebugFn("%s", *b ? "YES" : "NO");
243
244 return TSS_SUCCESS;
245 }
246
247 TCPA_RESULT
internal_EvictByKeySlot(TCPA_KEY_HANDLE slot)248 internal_EvictByKeySlot(TCPA_KEY_HANDLE slot)
249 {
250 TCPA_RESULT result;
251 UINT32 paramSize;
252 UINT64 offset;
253 BYTE txBlob[TSS_TPM_TXBLOB_SIZE];
254
255 LogDebug("Entering Evict Key");
256
257 #ifdef TSS_BUILD_TSS12
258 if (TPM_VERSION_IS(1,2)) {
259 LogDebugFn("Evicting key using FlushSpecific for TPM 1.2");
260
261 return TCSP_FlushSpecific_Common(slot, TPM_RT_KEY);
262 }
263 #endif
264
265 offset = 10;
266 LoadBlob_UINT32(&offset, slot, txBlob);
267 LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_EvictKey, txBlob);
268
269 if ((result = req_mgr_submit_req(txBlob)))
270 return result;
271
272 result = UnloadBlob_Header(txBlob, ¶mSize);
273
274 LogResult("Evict Key", result);
275 return result;
276 }
277
278 TSS_RESULT
clearUnknownKeys(TCS_CONTEXT_HANDLE hContext,UINT32 * cleared)279 clearUnknownKeys(TCS_CONTEXT_HANDLE hContext, UINT32 *cleared)
280 {
281 TSS_RESULT result = TSS_SUCCESS;
282 TCPA_KEY_HANDLE_LIST keyList = { 0, NULL };
283 int i;
284 BYTE *respData = NULL;
285 UINT32 respDataSize = 0, count = 0;
286 TCPA_CAPABILITY_AREA capArea = -1;
287 UINT64 offset = 0;
288 TSS_BOOL found = FALSE;
289 struct key_mem_cache *tmp;
290
291 capArea = TCPA_CAP_KEY_HANDLE;
292
293 if ((result = TCSP_GetCapability_Internal(hContext, capArea, 0, NULL, &respDataSize,
294 &respData)))
295 return result;
296
297 if ((result = UnloadBlob_KEY_HANDLE_LIST(&offset, respData, &keyList)))
298 goto done;
299
300 #ifdef TSS_DEBUG
301 LogDebug("Loaded TPM key handles:");
302 for (i = 0; i < keyList.loaded; i++) {
303 LogDebugFn("%d: %x", i, keyList.handle[i]);
304 }
305
306 LogDebug("Loaded TCSD key handles:");
307 i=0;
308 for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) {
309 LogDebugFn("%d: 0x%x -> 0x%x", i++, tmp->tpm_handle,
310 tmp->tcs_handle);
311 }
312 #endif
313
314 for (i = 0; i < keyList.loaded; i++) {
315 /* as long as we're only called from evictFirstKey(), we don't
316 * need to lock here */
317 for (tmp = key_mem_cache_head; tmp; tmp = tmp->next) {
318 if (tmp->tpm_handle == keyList.handle[i]) {
319 found = TRUE;
320 break;
321 }
322 }
323 if (found)
324 found = FALSE;
325 else {
326 if ((result = internal_EvictByKeySlot(keyList.handle[i])))
327 goto done;
328 else
329 count++;
330 }
331 }
332
333 *cleared = count;
334 done:
335 free(keyList.handle);
336 free(respData);
337
338 return TSS_SUCCESS;
339 }
340
341 #if 0
342 TCPA_RESULT
343 clearKeysFromChip(TCS_CONTEXT_HANDLE hContext)
344 {
345 TCPA_RESULT result;
346 TCPA_KEY_HANDLE_LIST keyList;
347 UINT32 i;
348 BYTE *respData = 0;
349 UINT32 respDataSize = 0;
350 TCPA_CAPABILITY_AREA capArea = -1;
351 UINT64 offset = 0;
352
353 capArea = TCPA_CAP_KEY_HANDLE;
354
355 if ((result = TCSP_GetCapability_Internal(hContext, capArea, 0, NULL,
356 &respDataSize, &respData)))
357 return result;
358
359 if ((result = UnloadBlob_KEY_HANDLE_LIST(&offset, respData, &keyList)))
360 return result;
361 for (i = 0; i < keyList.loaded; i++) {
362 if (keyList.handle[i] == SRK_TPM_HANDLE || /*can't evict SRK */
363 keyList.handle[i] == EK_TPM_HANDLE) /*can't evict EK */
364 continue;
365 if ((result = internal_EvictByKeySlot(keyList.handle[i])))
366 return result;
367 }
368 return TSS_SUCCESS;
369 }
370 #endif
371
372 void
LoadBlob_KEY_PARMS(UINT64 * offset,BYTE * blob,TCPA_KEY_PARMS * keyInfo)373 LoadBlob_KEY_PARMS(UINT64 *offset, BYTE *blob, TCPA_KEY_PARMS *keyInfo)
374 {
375 LoadBlob_UINT32(offset, keyInfo->algorithmID, blob);
376 LoadBlob_UINT16(offset, keyInfo->encScheme, blob);
377 LoadBlob_UINT16(offset, keyInfo->sigScheme, blob);
378 LoadBlob_UINT32(offset, keyInfo->parmSize, blob);
379 LoadBlob(offset, keyInfo->parmSize, blob, keyInfo->parms);
380 }
381
382 TSS_RESULT
UnloadBlob_STORE_PUBKEY(UINT64 * offset,BYTE * blob,TCPA_STORE_PUBKEY * store)383 UnloadBlob_STORE_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_STORE_PUBKEY *store)
384 {
385 if (!store) {
386 UINT32 keyLength;
387
388 UnloadBlob_UINT32(offset, &keyLength, blob);
389
390 if (keyLength > 0)
391 UnloadBlob(offset, keyLength, blob, NULL);
392
393 return TSS_SUCCESS;
394 }
395
396 UnloadBlob_UINT32(offset, &store->keyLength, blob);
397
398 if (store->keyLength == 0) {
399 store->key = NULL;
400 LogWarn("Unloading a public key of size 0!");
401 } else {
402 store->key = (BYTE *)malloc(store->keyLength);
403 if (store->key == NULL) {
404 LogError("malloc of %u bytes failed.", store->keyLength);
405 store->keyLength = 0;
406 return TCSERR(TSS_E_OUTOFMEMORY);
407 }
408
409 UnloadBlob(offset, store->keyLength, blob, store->key);
410 }
411
412 return TSS_SUCCESS;
413 }
414
415 void
LoadBlob_STORE_PUBKEY(UINT64 * offset,BYTE * blob,TCPA_STORE_PUBKEY * store)416 LoadBlob_STORE_PUBKEY(UINT64 *offset, BYTE * blob, TCPA_STORE_PUBKEY * store)
417 {
418 LoadBlob_UINT32(offset, store->keyLength, blob);
419 LoadBlob(offset, store->keyLength, blob, store->key);
420 }
421
422 TSS_RESULT
UnloadBlob_TSS_KEY(UINT64 * offset,BYTE * blob,TSS_KEY * key)423 UnloadBlob_TSS_KEY(UINT64 *offset, BYTE *blob, TSS_KEY *key)
424 {
425 TSS_RESULT rc;
426
427 if (!key) {
428 UINT32 size;
429
430 /* TPM_KEY's ver and TPM_KEY12's tag/file are
431 the same size, so... */
432 UnloadBlob_VERSION(offset, blob, NULL);
433 UnloadBlob_UINT16(offset, NULL, blob);
434 UnloadBlob_KEY_FLAGS(offset, blob, NULL);
435 UnloadBlob_BOOL(offset, NULL, blob);
436 if ((rc = UnloadBlob_KEY_PARMS(offset, blob, NULL)))
437 return rc;
438 UnloadBlob_UINT32(offset, &size, blob);
439
440 if (size > 0)
441 UnloadBlob(offset, size, blob, NULL);
442
443 if ((rc = UnloadBlob_STORE_PUBKEY(offset, blob, NULL)))
444 return rc;
445
446 UnloadBlob_UINT32(offset, &size, blob);
447
448 if (size > 0)
449 UnloadBlob(offset, size, blob, NULL);
450
451 return TSS_SUCCESS;
452 }
453
454 if (key->hdr.key12.tag == TPM_TAG_KEY12) {
455 UnloadBlob_UINT16(offset, &key->hdr.key12.tag, blob);
456 UnloadBlob_UINT16(offset, &key->hdr.key12.fill, blob);
457 } else
458 UnloadBlob_TCPA_VERSION(offset, blob, &key->hdr.key11.ver);
459 UnloadBlob_UINT16(offset, &key->keyUsage, blob);
460 UnloadBlob_KEY_FLAGS(offset, blob, &key->keyFlags);
461 UnloadBlob_BOOL(offset, (TSS_BOOL *)&key->authDataUsage, blob);
462 if ((rc = UnloadBlob_KEY_PARMS(offset, blob, &key->algorithmParms)))
463 return rc;
464 UnloadBlob_UINT32(offset, &key->PCRInfoSize, blob);
465
466 if (key->PCRInfoSize == 0)
467 key->PCRInfo = NULL;
468 else {
469 key->PCRInfo = malloc(key->PCRInfoSize);
470 if (key->PCRInfo == NULL) {
471 LogError("malloc of %u bytes failed.", key->PCRInfoSize);
472 key->PCRInfoSize = 0;
473 free(key->algorithmParms.parms);
474 key->algorithmParms.parms = NULL;
475 key->algorithmParms.parmSize = 0;
476 return TCSERR(TSS_E_OUTOFMEMORY);
477 }
478 UnloadBlob(offset, key->PCRInfoSize, blob, key->PCRInfo);
479 }
480
481 if ((rc = UnloadBlob_STORE_PUBKEY(offset, blob, &key->pubKey))) {
482 free(key->PCRInfo);
483 key->PCRInfo = NULL;
484 key->PCRInfoSize = 0;
485 free(key->algorithmParms.parms);
486 key->algorithmParms.parms = NULL;
487 key->algorithmParms.parmSize = 0;
488 return rc;
489 }
490 UnloadBlob_UINT32(offset, &key->encSize, blob);
491
492 if (key->encSize == 0)
493 key->encData = NULL;
494 else {
495 key->encData = (BYTE *)malloc(key->encSize);
496 if (key->encData == NULL) {
497 LogError("malloc of %d bytes failed.", key->encSize);
498 key->encSize = 0;
499 free(key->algorithmParms.parms);
500 key->algorithmParms.parms = NULL;
501 key->algorithmParms.parmSize = 0;
502 free(key->PCRInfo);
503 key->PCRInfo = NULL;
504 key->PCRInfoSize = 0;
505 free(key->pubKey.key);
506 key->pubKey.key = NULL;
507 key->pubKey.keyLength = 0;
508 return TCSERR(TSS_E_OUTOFMEMORY);
509 }
510 UnloadBlob(offset, key->encSize, blob, key->encData);
511 }
512
513 return TSS_SUCCESS;
514 }
515
516 void
LoadBlob_TSS_KEY(UINT64 * offset,BYTE * blob,TSS_KEY * key)517 LoadBlob_TSS_KEY(UINT64 *offset, BYTE * blob, TSS_KEY * key)
518 {
519 if (key->hdr.key12.tag == TPM_TAG_KEY12) {
520 LoadBlob_UINT16(offset, key->hdr.key12.tag, blob);
521 LoadBlob_UINT16(offset, key->hdr.key12.fill, blob);
522 } else
523 LoadBlob_TCPA_VERSION(offset, blob, &key->hdr.key11.ver);
524 LoadBlob_UINT16(offset, key->keyUsage, blob);
525 LoadBlob_KEY_FLAGS(offset, blob, &key->keyFlags);
526 LoadBlob_BOOL(offset, key->authDataUsage, blob);
527 LoadBlob_KEY_PARMS(offset, blob, &key->algorithmParms);
528 LoadBlob_UINT32(offset, key->PCRInfoSize, blob);
529 LoadBlob(offset, key->PCRInfoSize, blob, key->PCRInfo);
530 LoadBlob_STORE_PUBKEY(offset, blob, &key->pubKey);
531 LoadBlob_UINT32(offset, key->encSize, blob);
532 LoadBlob(offset, key->encSize, blob, key->encData);
533 }
534
535 void
LoadBlob_PUBKEY(UINT64 * offset,BYTE * blob,TCPA_PUBKEY * key)536 LoadBlob_PUBKEY(UINT64 *offset, BYTE * blob, TCPA_PUBKEY * key)
537 {
538 LoadBlob_KEY_PARMS(offset, blob, &(key->algorithmParms));
539 LoadBlob_STORE_PUBKEY(offset, blob, &(key->pubKey));
540 }
541
542 TSS_RESULT
UnloadBlob_PUBKEY(UINT64 * offset,BYTE * blob,TCPA_PUBKEY * key)543 UnloadBlob_PUBKEY(UINT64 *offset, BYTE *blob, TCPA_PUBKEY *key)
544 {
545 TSS_RESULT rc;
546
547 if (!key) {
548 if ((rc = UnloadBlob_KEY_PARMS(offset, blob, NULL)))
549 return rc;
550 return UnloadBlob_STORE_PUBKEY(offset, blob, NULL);
551 }
552
553 if ((rc = UnloadBlob_KEY_PARMS(offset, blob, &key->algorithmParms)))
554 return rc;
555 if ((rc = UnloadBlob_STORE_PUBKEY(offset, blob, &key->pubKey))) {
556 free(key->algorithmParms.parms);
557 key->algorithmParms.parms = NULL;
558 key->algorithmParms.parmSize = 0;
559 }
560
561 return rc;
562 }
563
564 void
LoadBlob_KEY_FLAGS(UINT64 * offset,BYTE * blob,TCPA_KEY_FLAGS * flags)565 LoadBlob_KEY_FLAGS(UINT64 *offset, BYTE * blob, TCPA_KEY_FLAGS * flags)
566 {
567 LoadBlob_UINT32(offset, *flags, blob);
568 }
569
570 void
destroy_key_refs(TSS_KEY * key)571 destroy_key_refs(TSS_KEY *key)
572 {
573 free(key->algorithmParms.parms);
574 key->algorithmParms.parms = NULL;
575 key->algorithmParms.parmSize = 0;
576
577 free(key->pubKey.key);
578 key->pubKey.key = NULL;
579 key->pubKey.keyLength = 0;
580
581 free(key->encData);
582 key->encData = NULL;
583 key->encSize = 0;
584
585 free(key->PCRInfo);
586 key->PCRInfo = NULL;
587 key->PCRInfoSize = 0;
588 }
589