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 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, ¶mSize))) { 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 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, ¶mSize))) { 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], ¶mSize))) { 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 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, ¶mSize))) { 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