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. 2007
8  *
9  */
10 
11 
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <string.h>
15 
16 #include "trousers/tss.h"
17 #include "trousers_types.h"
18 #include "tcs_tsp.h"
19 #include "tcs_utils.h"
20 #include "tcs_int_literals.h"
21 #include "capabilities.h"
22 #include "tcslog.h"
23 #include "tcsps.h"
24 #include "req_mgr.h"
25 
26 
27 TSS_RESULT
TCSP_EstablishTransport_Internal(TCS_CONTEXT_HANDLE hContext,UINT32 ulTransControlFlags,TCS_KEY_HANDLE hEncKey,UINT32 ulTransSessionInfoSize,BYTE * rgbTransSessionInfo,UINT32 ulSecretSize,BYTE * rgbSecret,TPM_AUTH * pEncKeyAuth,TPM_MODIFIER_INDICATOR * pbLocality,TCS_HANDLE * hTransSession,UINT32 * ulCurrentTicks,BYTE ** prgbCurrentTicks,TPM_NONCE * pTransNonce)28 TCSP_EstablishTransport_Internal(TCS_CONTEXT_HANDLE      hContext,
29 				 UINT32                  ulTransControlFlags,
30 				 TCS_KEY_HANDLE          hEncKey,
31 				 UINT32                  ulTransSessionInfoSize,
32 				 BYTE*                   rgbTransSessionInfo,
33 				 UINT32                  ulSecretSize,
34 				 BYTE*                   rgbSecret,
35 				 TPM_AUTH*               pEncKeyAuth,
36 				 TPM_MODIFIER_INDICATOR* pbLocality,
37 				 TCS_HANDLE*             hTransSession,
38 				 UINT32*                 ulCurrentTicks,
39 				 BYTE**                  prgbCurrentTicks,
40 				 TPM_NONCE*              pTransNonce)
41 {
42 	TSS_RESULT result;
43 	UINT32 paramSize;
44 	UINT64 offset;
45 	TPM_KEY_HANDLE keySlot = TPM_KH_TRANSPORT;
46 	BYTE txBlob[TSS_TPM_TXBLOB_SIZE];
47 
48 	if ((result = ctx_verify_context(hContext)))
49 		return result;
50 
51 	if (ulTransControlFlags == TSS_TCSATTRIB_TRANSPORT_EXCLUSIVE) {
52 		if ((result = ctx_req_exclusive_transport(hContext)))
53 			return result;
54 	}
55 
56 	if (pEncKeyAuth) {
57 		if ((result = auth_mgr_check(hContext, &pEncKeyAuth->AuthHandle)))
58 			return result;
59 	}
60 
61 	/* if hEncKey is set to TPM_KH_TRANSPORT, that's the signal to the TPM that this will be
62 	 * an unencrypted transport session, so we don't need to check that its loaded */
63 	if (hEncKey != TPM_KH_TRANSPORT) {
64 		if ((result = ensureKeyIsLoaded(hContext, hEncKey, &keySlot)))
65 			return result;
66 	}
67 
68 	offset = TSS_TPM_TXBLOB_HDR_LEN;
69 	LoadBlob_UINT32(&offset, keySlot, txBlob);
70 	LoadBlob(&offset, ulTransSessionInfoSize, txBlob, rgbTransSessionInfo);
71 	LoadBlob_UINT32(&offset, ulSecretSize, txBlob);
72 	LoadBlob(&offset, ulSecretSize, txBlob, rgbSecret);
73 	if (pEncKeyAuth) {
74 		LoadBlob_Auth(&offset, txBlob, pEncKeyAuth);
75 		LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, offset, TPM_ORD_EstablishTransport,
76 				txBlob);
77 	} else
78 		LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_EstablishTransport, txBlob);
79 
80 	if ((result = req_mgr_submit_req(txBlob)))
81 		goto done;
82 
83 	if ((result = UnloadBlob_Header(txBlob, &paramSize))) {
84 		LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result);
85 		goto done;
86 	}
87 
88 	offset = TSS_TPM_TXBLOB_HDR_LEN;
89 	UnloadBlob_UINT32(&offset, hTransSession, txBlob);
90 	UnloadBlob_UINT32(&offset, pbLocality, txBlob);
91 
92 	*ulCurrentTicks = sizeof(TPM_STRUCTURE_TAG)
93 			  + sizeof(UINT64)
94 			  + sizeof(UINT16)
95 			  + sizeof(TPM_NONCE);
96 
97 	*prgbCurrentTicks = malloc(*ulCurrentTicks);
98 	if (*prgbCurrentTicks == NULL) {
99 		result = TCSERR(TSS_E_OUTOFMEMORY);
100 		goto done;
101 	}
102 
103 	UnloadBlob(&offset, *ulCurrentTicks, txBlob, *prgbCurrentTicks);
104 	UnloadBlob(&offset, sizeof(TPM_NONCE), txBlob, (BYTE *)pTransNonce);
105 	if (pEncKeyAuth)
106 		UnloadBlob_Auth(&offset, txBlob, pEncKeyAuth);
107 
108 	ctx_set_transport_enabled(hContext, *hTransSession);
109 done:
110 	auth_mgr_release_auth(pEncKeyAuth, NULL, hContext);
111 	return result;
112 }
113 
114 TSS_RESULT
TCSP_ExecuteTransport_Internal(TCS_CONTEXT_HANDLE hContext,TPM_COMMAND_CODE unWrappedCommandOrdinal,UINT32 ulWrappedCmdParamInSize,BYTE * rgbWrappedCmdParamIn,UINT32 * pulHandleListSize,TCS_HANDLE ** rghHandles,TPM_AUTH * pWrappedCmdAuth1,TPM_AUTH * pWrappedCmdAuth2,TPM_AUTH * pTransAuth,UINT64 * punCurrentTicks,TPM_MODIFIER_INDICATOR * pbLocality,TPM_RESULT * pulWrappedCmdReturnCode,UINT32 * ulWrappedCmdParamOutSize,BYTE ** rgbWrappedCmdParamOut)115 TCSP_ExecuteTransport_Internal(TCS_CONTEXT_HANDLE      hContext,
116 			       TPM_COMMAND_CODE        unWrappedCommandOrdinal,
117 			       UINT32                  ulWrappedCmdParamInSize,
118 			       BYTE*                   rgbWrappedCmdParamIn,
119 			       UINT32*                 pulHandleListSize,	/* in, out */
120 			       TCS_HANDLE**            rghHandles,		/* in, out */
121 			       TPM_AUTH*               pWrappedCmdAuth1,	/* in, out */
122 			       TPM_AUTH*               pWrappedCmdAuth2,	/* in, out */
123 			       TPM_AUTH*               pTransAuth,		/* in, out */
124 			       UINT64*                 punCurrentTicks,
125 			       TPM_MODIFIER_INDICATOR* pbLocality,
126 			       TPM_RESULT*             pulWrappedCmdReturnCode,
127 			       UINT32*                 ulWrappedCmdParamOutSize,
128 			       BYTE**                  rgbWrappedCmdParamOut)
129 {
130 	TSS_RESULT result;
131 	UINT32 paramSize, wrappedSize, val1 = 0, val2 = 0, *pVal1 = NULL, *pVal2 = NULL;
132 	TCS_HANDLE handle1 = 0, handle2 = 0;
133 	UINT64 offset, wrappedOffset = 0;
134 	BYTE txBlob[TSS_TPM_TXBLOB_SIZE];
135 
136 
137 	if (*pulHandleListSize > 2) {
138 		LogDebugFn("************ EXPAND KEYSLOT SIZE *********");
139 		return TCSERR(TSS_E_INTERNAL_ERROR);
140 	}
141 
142 	if ((result = ctx_verify_context(hContext)))
143 		return result;
144 
145 	if (pWrappedCmdAuth1)
146 		if ((result = auth_mgr_check(hContext, &pWrappedCmdAuth1->AuthHandle)))
147 			goto done;
148 
149 	if (pWrappedCmdAuth2)
150 		if ((result = auth_mgr_check(hContext, &pWrappedCmdAuth2->AuthHandle)))
151 			goto done;
152 
153 	switch (unWrappedCommandOrdinal) {
154 	/* If the command is FlushSpecific, we get handle that needs to be freed, but we don't know
155 	 * what type it is. */
156 	case TPM_ORD_FlushSpecific:
157 		if (*pulHandleListSize == 0) { /* invalid */
158 			result = TCSERR(TSS_E_BAD_PARAMETER);
159 			goto done;
160 		}
161 
162 		/* If this is a transport handle, remove the context's reference to the session */
163 		ctx_set_transport_disabled(hContext, rghHandles[0]);
164 
165 		/* Is it a key? If so, jump to the get_slot_lite and key management calls below */
166 		if (ctx_has_key_loaded(hContext, *rghHandles[0]))
167 			goto map_key_handles;
168 
169 		/* fall through */
170 	case TPM_ORD_Terminate_Handle:
171 		if (!auth_mgr_check(hContext, rghHandles[0]))
172 			auth_mgr_release_auth_handle(*rghHandles[0], hContext, FALSE);
173 
174 		/* If the handle is an auth handle or any other kind of handle, there's no
175 		 * mapping done in the TCS, so pass its value straight to the TPM and jump over
176 		 * the switch statement below where we assume FLushSpecific is being done on a
177 		 * key */
178 		handle1 = val1 = *rghHandles[0];
179 		pVal1 = &val1;
180 
181 		goto build_command;
182 	default:
183 		break;
184 	}
185 
186 map_key_handles:
187 	if (*pulHandleListSize == 2) {
188 		handle2 = (*rghHandles)[1];
189 
190 		if ((result = get_slot_lite(hContext, handle2, &val2))) {
191 			*pulHandleListSize = 0;
192 			goto done;
193 		}
194 
195 		pVal2 = &val2;
196 	}
197 
198 	if (*pulHandleListSize >= 1) {
199 		handle1 = *rghHandles[0];
200 
201 		*pulHandleListSize = 0;
202 
203 		if ((result = get_slot_lite(hContext, handle1, &val1)))
204 			goto done;
205 
206 		pVal1 = &val1;
207 	}
208 
209 	switch (unWrappedCommandOrdinal) {
210 	case TPM_ORD_EvictKey:
211 	case TPM_ORD_FlushSpecific:
212 	{
213 		if ((result = ctx_remove_key_loaded(hContext, handle1)))
214 			goto done;
215 
216 		if ((result = key_mgr_dec_ref_count(handle1)))
217 			goto done;
218 
219 		/* we can't call key_mgr_ref_cnt() here since it calls TPM_EvictKey directly */
220 		mc_set_slot_by_handle(handle1, NULL_TPM_HANDLE);
221 		break;
222 	}
223 	case TPM_ORD_OIAP:
224 	{
225 		/* are the maximum number of auth sessions open? */
226 		if (auth_mgr_req_new(hContext) == FALSE) {
227 			if ((result = auth_mgr_swap_out(hContext)))
228 				goto done;
229 		}
230 
231 		break;
232 	}
233 	case TPM_ORD_OSAP:
234 	{
235 		UINT16 entityType;
236 		UINT32 entityValue, newEntValue;
237 
238 		/* are the maximum number of auth sessions open? */
239 		if (auth_mgr_req_new(hContext) == FALSE) {
240 			if ((result = auth_mgr_swap_out(hContext)))
241 				goto done;
242 		}
243 
244 		offset = 0;
245 		UnloadBlob_UINT16(&offset, &entityType, rgbWrappedCmdParamIn);
246 		UnloadBlob_UINT32(&offset, &entityValue, rgbWrappedCmdParamIn);
247 
248 		if (entityType == TCPA_ET_KEYHANDLE || entityType == TCPA_ET_KEY) {
249 			if (ensureKeyIsLoaded(hContext, entityValue, &newEntValue))
250 				return TCSERR(TSS_E_KEY_NOT_LOADED);
251 
252 			/* OSAP is never encrypted in a transport session, so changing
253 			 * rgbWrappedCmdParamIn is ok here */
254 			offset = sizeof(UINT16);
255 			LoadBlob_UINT32(&offset, newEntValue, rgbWrappedCmdParamIn);
256 		}
257 
258 		break;
259 	}
260 	case TPM_ORD_DSAP:
261 	{
262 		UINT16 entityType;
263 		UINT32 keyHandle, tpmKeyHandle;
264 
265 		/* are the maximum number of auth sessions open? */
266 		if (auth_mgr_req_new(hContext) == FALSE) {
267 			if ((result = auth_mgr_swap_out(hContext)))
268 				goto done;
269 		}
270 
271 		offset = 0;
272 		UnloadBlob_UINT16(&offset, &entityType, rgbWrappedCmdParamIn);
273 		UnloadBlob_UINT32(&offset, &keyHandle, rgbWrappedCmdParamIn);
274 
275 		if (ensureKeyIsLoaded(hContext, keyHandle, &tpmKeyHandle)) {
276 			result = TCSERR(TSS_E_KEY_NOT_LOADED);
277 			goto done;
278 		}
279 
280 		/* DSAP's only encrypted paramter is entityValue, so replacing keyHandle inside
281 		 * rgbWrappedCmdParamIn is ok */
282 		offset = sizeof(UINT16);
283 		LoadBlob_UINT32(&offset, tpmKeyHandle, rgbWrappedCmdParamIn);
284 	}
285 	default:
286 		break;
287 	}
288 
289 build_command:
290 	if ((result = tpm_rqu_build(TPM_ORD_ExecuteTransport, &wrappedOffset,
291 				    &txBlob[TSS_TXBLOB_WRAPPEDCMD_OFFSET], unWrappedCommandOrdinal,
292 				    pVal1, pVal2, ulWrappedCmdParamInSize, rgbWrappedCmdParamIn,
293 				    pWrappedCmdAuth1, pWrappedCmdAuth2)))
294 		goto done;
295 
296 	/* The blob we'll load here looks like this:
297 	 *
298 	 * |TAGet|LENet|ORDet|wrappedCmdSize|wrappedCmd|AUTHet|
299 	 *
300 	 * wrappedCmd looks like this:
301 	 *
302 	 * |TAGw|LENw|ORDw|HANDLESw|DATAw|AUTH1w|AUTH2w|
303 	 *
304 	 * w = wrapped command info
305 	 * et = execute transport command info
306 	 *
307 	 * Note that the wrapped command was loaded into the blob by the tpm_rqu_build call
308 	 * above.
309 	 *
310 	 */
311 	offset = TSS_TPM_TXBLOB_HDR_LEN;
312 	/* Load wrapped command size: |wrappedCmdSize| */
313 	LoadBlob_UINT32(&offset, wrappedOffset, txBlob);
314 
315 	/* offset + wrappedOffset is the position of the execute transport auth struct */
316 	offset += wrappedOffset;
317 
318 	if (pTransAuth) {
319 		/* Load the auth for the execute transport command: |AUTHet| */
320 		LoadBlob_Auth(&offset, txBlob, pTransAuth);
321 		/* Load the outer header: |TAGet|LENet|ORDet| */
322 		LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, offset, TPM_ORD_ExecuteTransport,
323 				txBlob);
324 	} else {
325 		/* Load the outer header: |TAGet|LENet|ORDet| */
326 		LoadBlob_Header(TPM_TAG_RQU_COMMAND, offset, TPM_ORD_ExecuteTransport, txBlob);
327 	}
328 
329 	if ((result = req_mgr_submit_req(txBlob)))
330 		goto done;
331 
332 	/* Unload the Execute Transport (outer) header */
333 	if ((result = UnloadBlob_Header(txBlob, &paramSize))) {
334 		LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result);
335 		goto done;
336 	}
337 
338 	/* The response from the TPM looks like this:
339 	 *
340 	 * |TAGet|LENet|RCet|currentTicks|locality|wrappedRspSize|wrappedRsp|AUTHet|
341 	 *
342 	 * and wrappedRsp looks like:
343 	 *
344 	 * |TAGw|LENw|RCw|HANDLESw|DATAw|AUTH1w|AUTH2w|
345 	 */
346 
347 	offset = TSS_TPM_TXBLOB_HDR_LEN;
348 	UnloadBlob_UINT64(&offset, punCurrentTicks, txBlob);
349 	UnloadBlob_UINT32(&offset, pbLocality, txBlob);
350 
351 	/* Unload the wrapped response size: |wrappedRspSize| */
352 	UnloadBlob_UINT32(&offset, &wrappedSize, txBlob);
353 
354 	/* We've parsed right up to wrappedRsp, so save off this offset for later */
355 	wrappedOffset = offset;
356 
357 	/* The current offset + the response size will be the offset of |AUTHet| */
358 	offset += wrappedSize;
359 	if (pTransAuth)
360 		UnloadBlob_Auth(&offset, txBlob, pTransAuth);
361 
362 	/* Now parse through the returned response @ wrappedOffset */
363 	if ((result = UnloadBlob_Header(&txBlob[wrappedOffset], &paramSize))) {
364 		LogDebugFn("Wrapped command (Ordinal 0x%x) failed: rc=0x%x",
365 			   unWrappedCommandOrdinal, result);
366 
367 		/* This is the result of the wrapped command. If its not success, return its value
368 		 * in the pulWrappedCmdReturnCode variable and return indicating that the execute
369 		 * transport command was successful */
370 		*pulWrappedCmdReturnCode = result;
371 		*ulWrappedCmdParamOutSize = 0;
372 		*rgbWrappedCmdParamOut = NULL;
373 		auth_mgr_release_auth(pWrappedCmdAuth1, pWrappedCmdAuth2, hContext);
374 
375 		return TSS_SUCCESS;
376 	}
377 
378 	*pulWrappedCmdReturnCode = TSS_SUCCESS;
379 
380 	pVal1 = pVal2 = NULL;
381 	switch (unWrappedCommandOrdinal) {
382 		/* The commands below have 1 outgoing handle */
383 		case TPM_ORD_LoadKey2:
384 			pVal1 = &val1;
385 			break;
386 		default:
387 			break;
388 	}
389 
390 	result = tpm_rsp_parse(TPM_ORD_ExecuteTransport, &txBlob[wrappedOffset], paramSize,
391 			       pVal1, pVal2, ulWrappedCmdParamOutSize, rgbWrappedCmdParamOut,
392 			       pWrappedCmdAuth1, pWrappedCmdAuth2);
393 
394 	offset = 0;
395 	switch (unWrappedCommandOrdinal) {
396 	case TPM_ORD_LoadKey2:
397 	{
398 		TCS_KEY_HANDLE tcs_handle = NULL_TCS_HANDLE;
399 
400 		if ((result = load_key_final(hContext, handle1, &tcs_handle, NULL, val1)))
401 			goto done;
402 
403 		*rghHandles[0] = tcs_handle;
404 		*pulHandleListSize = 1;
405 		break;
406 	}
407 	case TPM_ORD_DSAP:
408 	case TPM_ORD_OSAP:
409 	case TPM_ORD_OIAP:
410 	{
411 		UINT32 handle;
412 
413 		UnloadBlob_UINT32(&offset, &handle, *rgbWrappedCmdParamOut);
414 		result = auth_mgr_add(hContext, handle);
415 		break;
416 	}
417 	default:
418 		break;
419 	}
420 
421 done:
422 	auth_mgr_release_auth(pWrappedCmdAuth1, pWrappedCmdAuth2, hContext);
423 	return result;
424 }
425 
426 TSS_RESULT
TCSP_ReleaseTransportSigned_Internal(TCS_CONTEXT_HANDLE hContext,TCS_KEY_HANDLE hSignatureKey,TPM_NONCE * AntiReplayNonce,TPM_AUTH * pKeyAuth,TPM_AUTH * pTransAuth,TPM_MODIFIER_INDICATOR * pbLocality,UINT32 * pulCurrentTicksSize,BYTE ** prgbCurrentTicks,UINT32 * pulSignatureSize,BYTE ** prgbSignature)427 TCSP_ReleaseTransportSigned_Internal(TCS_CONTEXT_HANDLE      hContext,
428 				     TCS_KEY_HANDLE          hSignatureKey,
429 				     TPM_NONCE*              AntiReplayNonce,
430 				     TPM_AUTH*               pKeyAuth,		/* in, out */
431 				     TPM_AUTH*               pTransAuth,	/* in, out */
432 				     TPM_MODIFIER_INDICATOR* pbLocality,
433 				     UINT32*                 pulCurrentTicksSize,
434 				     BYTE**                  prgbCurrentTicks,
435 				     UINT32*                 pulSignatureSize,
436 				     BYTE**                  prgbSignature)
437 {
438 	TSS_RESULT result;
439 	UINT32 paramSize;
440 	UINT64 offset;
441 	TPM_KEY_HANDLE keySlot;
442 	BYTE txBlob[TSS_TPM_TXBLOB_SIZE];
443 
444 	if ((result = ctx_verify_context(hContext)))
445 		return result;
446 
447 	if (pKeyAuth) {
448 		if ((result = auth_mgr_check(hContext, &pKeyAuth->AuthHandle)))
449 			return result;
450 	}
451 
452 	if ((result = ensureKeyIsLoaded(hContext, hSignatureKey, &keySlot)))
453 		return result;
454 
455 	offset = TSS_TPM_TXBLOB_HDR_LEN;
456 	LoadBlob_UINT32(&offset, keySlot, txBlob);
457 	LoadBlob(&offset, sizeof(TPM_NONCE), txBlob, (BYTE *)AntiReplayNonce);
458 	if (pKeyAuth) {
459 		LoadBlob_Auth(&offset, txBlob, pKeyAuth);
460 		LoadBlob_Auth(&offset, txBlob, pTransAuth);
461 		LoadBlob_Header(TPM_TAG_RQU_AUTH2_COMMAND, offset, TPM_ORD_ReleaseTransportSigned,
462 				txBlob);
463 	} else {
464 		LoadBlob_Auth(&offset, txBlob, pTransAuth);
465 		LoadBlob_Header(TPM_TAG_RQU_AUTH1_COMMAND, offset, TPM_ORD_ReleaseTransportSigned,
466 				txBlob);
467 	}
468 
469 	if ((result = req_mgr_submit_req(txBlob)))
470 		goto done;
471 
472 	if ((result = UnloadBlob_Header(txBlob, &paramSize))) {
473 		LogDebugFn("UnloadBlob_Header failed: rc=0x%x", result);
474 		goto done;
475 	}
476 
477 	/* unconditionally disable our accounting of the session */
478 	ctx_set_transport_disabled(hContext, NULL);
479 
480 	offset = TSS_TPM_TXBLOB_HDR_LEN;
481 	UnloadBlob_UINT32(&offset, pbLocality, txBlob);
482 
483 	*pulCurrentTicksSize = sizeof(TPM_STRUCTURE_TAG)
484 			       + sizeof(UINT64)
485 			       + sizeof(UINT16)
486 			       + sizeof(TPM_NONCE);
487 
488 	*prgbCurrentTicks = malloc(*pulCurrentTicksSize);
489 	if (*prgbCurrentTicks == NULL) {
490 		result = TCSERR(TSS_E_OUTOFMEMORY);
491 		goto done;
492 	}
493 
494 	UnloadBlob(&offset, *pulCurrentTicksSize, txBlob, *prgbCurrentTicks);
495 	UnloadBlob_UINT32(&offset, pulSignatureSize, txBlob);
496 
497 	*prgbSignature = malloc(*pulSignatureSize);
498 	if (*prgbSignature == NULL) {
499 		free(*prgbCurrentTicks);
500 		result = TCSERR(TSS_E_OUTOFMEMORY);
501 		goto done;
502 	}
503 
504 	UnloadBlob(&offset, *pulSignatureSize, txBlob, *prgbSignature);
505 
506 	if (pKeyAuth)
507 		UnloadBlob_Auth(&offset, txBlob, pKeyAuth);
508 	UnloadBlob_Auth(&offset, txBlob, pTransAuth);
509 
510 done:
511 	auth_mgr_release_auth(pKeyAuth, NULL, hContext);
512 	return result;
513 }
514