Vadim Bendebury | 5679752 | 2015-05-20 10:32:25 -0700 | [diff] [blame] | 1 | // This file was extracted from the TCG Published |
| 2 | // Trusted Platform Module Library |
| 3 | // Part 4: Supporting Routines |
| 4 | // Family "2.0" |
| 5 | // Level 00 Revision 01.16 |
| 6 | // October 30, 2014 |
| 7 | |
| 8 | #define SESSION_C |
| 9 | #include "InternalRoutines.h" |
| 10 | #include "Platform.h" |
| 11 | #include "SessionProcess_fp.h" |
| 12 | // |
| 13 | // |
| 14 | // File Scope Function -- ContextIdSetOldest() |
| 15 | // |
| 16 | // This function is called when the oldest contextID is being loaded or deleted. Once a saved context |
| 17 | // becomes the oldest, it stays the oldest until it is deleted. |
| 18 | // Finding the oldest is a bit tricky. It is not just the numeric comparison of values but is dependent on the |
| 19 | // value of contextCounter. |
| 20 | // Assume we have a small contextArray with 8, 4-bit values with values 1 and 2 used to indicate the loaded |
| 21 | // context slot number. Also assume that the array contains hex values of (0 0 1 0 3 0 9 F) and that the |
| 22 | // contextCounter is an 8-bit counter with a value of 0x37. Since the low nibble is 7, that means that values |
| 23 | // above 7 are older than values below it and, in this example, 9 is the oldest value. |
| 24 | // Note if we subtract the counter value, from each slot that contains a saved contextID we get (- - - - B - 2 - |
| 25 | // 8) and the oldest entry is now easy to find. |
| 26 | // |
| 27 | static void |
| 28 | ContextIdSetOldest( |
| 29 | void |
| 30 | ) |
| 31 | { |
| 32 | CONTEXT_SLOT lowBits; |
| 33 | CONTEXT_SLOT entry; |
| 34 | CONTEXT_SLOT smallest = ((CONTEXT_SLOT) ~0); |
| 35 | UINT32 i; |
| 36 | // |
| 37 | // Set oldestSaveContext to a value indicating none assigned |
| 38 | s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1; |
| 39 | lowBits = (CONTEXT_SLOT)gr.contextCounter; |
| 40 | for(i = 0; i < MAX_ACTIVE_SESSIONS; i++) |
| 41 | { |
| 42 | entry = gr.contextArray[i]; |
| 43 | // only look at entries that are saved contexts |
| 44 | if(entry > MAX_LOADED_SESSIONS) |
| 45 | { |
| 46 | // Use a less than or equal in case the oldest |
| 47 | // is brand new (= lowBits-1) and equal to our initial |
| 48 | // value for smallest. |
| 49 | if(((CONTEXT_SLOT) (entry - lowBits)) <= smallest) |
| 50 | { |
| 51 | smallest = (entry - lowBits); |
| 52 | s_oldestSavedSession = i; |
| 53 | } |
| 54 | } |
| 55 | } |
| 56 | // When we finish, either the s_oldestSavedSession still has its initial |
| 57 | // value, or it has the index of the oldest saved context. |
| 58 | } |
| 59 | // |
| 60 | // |
| 61 | // Startup Function -- SessionStartup() |
| 62 | // |
| 63 | // This function initializes the session subsystem on TPM2_Startup(). |
| 64 | // |
| 65 | void |
| 66 | SessionStartup( |
| 67 | STARTUP_TYPE type |
| 68 | ) |
| 69 | { |
| 70 | UINT32 i; |
| 71 | // Initialize session slots. At startup, all the in-memory session slots |
| 72 | // are cleared and marked as not occupied |
| 73 | for(i = 0; i < MAX_LOADED_SESSIONS; i++) |
| 74 | s_sessions[i].occupied = FALSE; // session slot is not occupied |
| 75 | // The free session slots the number of maximum allowed loaded sessions |
| 76 | s_freeSessionSlots = MAX_LOADED_SESSIONS; |
| 77 | // Initialize context ID data. On a ST_SAVE or hibernate sequence, it will |
| 78 | // scan the saved array of session context counts, and clear any entry that |
| 79 | // references a session that was in memory during the state save since that |
| 80 | // memory was not preserved over the ST_SAVE. |
| 81 | if(type == SU_RESUME || type == SU_RESTART) |
| 82 | { |
| 83 | // On ST_SAVE we preserve the contexts that were saved but not the ones |
| 84 | // in memory |
| 85 | for (i = 0; i < MAX_ACTIVE_SESSIONS; i++) |
| 86 | { |
| 87 | // If the array value is unused or references a loaded session then |
| 88 | // that loaded session context is lost and the array entry is |
| 89 | // reclaimed. |
| 90 | if (gr.contextArray[i] <= MAX_LOADED_SESSIONS) |
| 91 | gr.contextArray[i] = 0; |
| 92 | } |
| 93 | // Find the oldest session in context ID data and set it in |
| 94 | // s_oldestSavedSession |
| 95 | ContextIdSetOldest(); |
| 96 | // |
| 97 | } |
| 98 | else |
| 99 | { |
| 100 | // For STARTUP_CLEAR, clear out the contextArray |
| 101 | for (i = 0; i < MAX_ACTIVE_SESSIONS; i++) |
| 102 | gr.contextArray[i] = 0; |
| 103 | // reset the context counter |
| 104 | gr.contextCounter = MAX_LOADED_SESSIONS + 1; |
| 105 | // Initialize oldest saved session |
| 106 | s_oldestSavedSession = MAX_ACTIVE_SESSIONS + 1; |
| 107 | } |
| 108 | return; |
| 109 | } |
| 110 | // |
| 111 | // |
| 112 | // Access Functions |
| 113 | // |
| 114 | // SessionIsLoaded() |
| 115 | // |
| 116 | // This function test a session handle references a loaded session. The handle must have previously been |
| 117 | // checked to make sure that it is a valid handle for an authorization session. |
| 118 | // |
| 119 | // NOTE: A PWAP authorization does not have a session. |
| 120 | // |
| 121 | // |
| 122 | // Return Value Meaning |
| 123 | // |
| 124 | // TRUE if session is loaded |
| 125 | // FALSE if it is not loaded |
| 126 | // |
| 127 | BOOL |
| 128 | SessionIsLoaded( |
| 129 | TPM_HANDLE handle // IN: session handle |
| 130 | ) |
| 131 | { |
| 132 | pAssert( HandleGetType(handle) == TPM_HT_POLICY_SESSION |
| 133 | || HandleGetType(handle) == TPM_HT_HMAC_SESSION); |
| 134 | handle = handle & HR_HANDLE_MASK; |
| 135 | // if out of range of possible active session, or not assigned to a loaded |
| 136 | // session return false |
| 137 | if( handle >= MAX_ACTIVE_SESSIONS |
| 138 | || gr.contextArray[handle] == 0 |
| 139 | || gr.contextArray[handle] > MAX_LOADED_SESSIONS |
| 140 | ) |
| 141 | return FALSE; |
| 142 | return TRUE; |
| 143 | } |
| 144 | // |
| 145 | // |
| 146 | // SessionIsSaved() |
| 147 | // |
| 148 | // This function test a session handle references a saved session. The handle must have previously been |
| 149 | // checked to make sure that it is a valid handle for an authorization session. |
| 150 | // |
| 151 | // NOTE: An password authorization does not have a session. |
| 152 | // |
| 153 | // This function requires that the handle be a valid session handle. |
| 154 | // |
| 155 | // |
| 156 | // Return Value Meaning |
| 157 | // |
| 158 | // TRUE if session is saved |
| 159 | // FALSE if it is not saved |
| 160 | // |
| 161 | BOOL |
| 162 | SessionIsSaved( |
| 163 | TPM_HANDLE handle // IN: session handle |
| 164 | ) |
| 165 | { |
| 166 | pAssert( HandleGetType(handle) == TPM_HT_POLICY_SESSION |
| 167 | || HandleGetType(handle) == TPM_HT_HMAC_SESSION); |
| 168 | handle = handle & HR_HANDLE_MASK; |
| 169 | // if out of range of possible active session, or not assigned, or |
| 170 | // assigned to a loaded session, return false |
| 171 | if( handle >= MAX_ACTIVE_SESSIONS |
| 172 | || gr.contextArray[handle] == 0 |
| 173 | || gr.contextArray[handle] <= MAX_LOADED_SESSIONS |
| 174 | ) |
| 175 | return FALSE; |
| 176 | return TRUE; |
| 177 | } |
| 178 | // |
| 179 | // |
| 180 | // SessionPCRValueIsCurrent() |
| 181 | // |
| 182 | // This function is used to check if PCR values have been updated since the last time they were checked in |
| 183 | // a policy session. |
| 184 | // This function requires the session is loaded. |
| 185 | // |
| 186 | // Return Value Meaning |
| 187 | // |
| 188 | // TRUE if PCR value is current |
| 189 | // FALSE if PCR value is not current |
| 190 | // |
| 191 | BOOL |
| 192 | SessionPCRValueIsCurrent( |
| 193 | TPMI_SH_POLICY handle // IN: session handle |
| 194 | ) |
| 195 | { |
| 196 | SESSION *session; |
| 197 | pAssert(SessionIsLoaded(handle)); |
| 198 | session = SessionGet(handle); |
| 199 | if( session->pcrCounter != 0 |
| 200 | && session->pcrCounter != gr.pcrCounter |
| 201 | ) |
| 202 | return FALSE; |
| 203 | else |
| 204 | return TRUE; |
| 205 | } |
| 206 | // |
| 207 | // |
| 208 | // SessionGet() |
| 209 | // |
| 210 | // This function returns a pointer to the session object associated with a session handle. |
| 211 | // The function requires that the session is loaded. |
| 212 | // |
| 213 | SESSION * |
| 214 | SessionGet( |
| 215 | TPM_HANDLE handle // IN: session handle |
| 216 | ) |
| 217 | { |
| 218 | CONTEXT_SLOT sessionIndex; |
| 219 | pAssert( HandleGetType(handle) == TPM_HT_POLICY_SESSION |
| 220 | || HandleGetType(handle) == TPM_HT_HMAC_SESSION |
| 221 | ); |
| 222 | pAssert((handle & HR_HANDLE_MASK) < MAX_ACTIVE_SESSIONS); |
| 223 | // get the contents of the session array. Because session is loaded, we |
| 224 | // should always get a valid sessionIndex |
| 225 | sessionIndex = gr.contextArray[handle & HR_HANDLE_MASK] - 1; |
| 226 | pAssert(sessionIndex < MAX_LOADED_SESSIONS); |
| 227 | return &s_sessions[sessionIndex].session; |
| 228 | } |
| 229 | // |
| 230 | // |
| 231 | // Utility Functions |
| 232 | // |
| 233 | // ContextIdSessionCreate() |
| 234 | // |
| 235 | // This function is called when a session is created. It will check to see if the current gap would prevent a |
| 236 | // context from being saved. If so it will return TPM_RC_CONTEXT_GAP. Otherwise, it will try to find an |
| 237 | // open slot in contextArray, set contextArray to the slot. |
| 238 | // This routine requires that the caller has determined the session array index for the session. |
| 239 | // |
| 240 | // return type TPM_RC |
| 241 | // |
| 242 | // TPM_RC_SUCCESS context ID was assigned |
| 243 | // TPM_RC_CONTEXT_GAP can't assign a new contextID until the oldest saved session context is |
| 244 | // recycled |
| 245 | // TPM_RC_SESSION_HANDLE there is no slot available in the context array for tracking of this |
| 246 | // session context |
| 247 | // |
| 248 | static TPM_RC |
| 249 | ContextIdSessionCreate ( |
| 250 | TPM_HANDLE *handle, // OUT: receives the assigned handle. This will |
| 251 | // be an index that must be adjusted by the |
| 252 | // caller according to the type of the |
| 253 | // session created |
| 254 | UINT32 sessionIndex // IN: The session context array entry that will |
| 255 | // be occupied by the created session |
| 256 | ) |
| 257 | { |
| 258 | pAssert(sessionIndex < MAX_LOADED_SESSIONS); |
| 259 | // check to see if creating the context is safe |
| 260 | // Is this going to be an assignment for the last session context |
| 261 | // array entry? If so, then there will be no room to recycle the |
| 262 | // oldest context if needed. If the gap is not at maximum, then |
| 263 | // it will be possible to save a context if it becomes necessary. |
| 264 | if( s_oldestSavedSession < MAX_ACTIVE_SESSIONS |
| 265 | && s_freeSessionSlots == 1) |
| 266 | { |
| 267 | // See if the gap is at maximum |
| 268 | if( (CONTEXT_SLOT)gr.contextCounter |
| 269 | == gr.contextArray[s_oldestSavedSession]) |
| 270 | // Note: if this is being used on a TPM.combined, this return |
| 271 | // code should be transformed to an appropriate 1.2 error |
| 272 | // code for this case. |
| 273 | return TPM_RC_CONTEXT_GAP; |
| 274 | } |
| 275 | // Find an unoccupied entry in the contextArray |
| 276 | for(*handle = 0; *handle < MAX_ACTIVE_SESSIONS; (*handle)++) |
| 277 | { |
| 278 | if(gr.contextArray[*handle] == 0) |
| 279 | { |
| 280 | // indicate that the session associated with this handle |
| 281 | // references a loaded session |
| 282 | gr.contextArray[*handle] = (CONTEXT_SLOT)(sessionIndex+1); |
| 283 | return TPM_RC_SUCCESS; |
| 284 | } |
| 285 | } |
| 286 | return TPM_RC_SESSION_HANDLES; |
| 287 | } |
| 288 | // |
| 289 | // |
| 290 | // SessionCreate() |
| 291 | // |
| 292 | // This function does the detailed work for starting an authorization session. This is done in a support |
| 293 | // routine rather than in the action code because the session management may differ in implementations. |
| 294 | // This implementation uses a fixed memory allocation to hold sessions and a fixed allocation to hold the |
| 295 | // contextID for the saved contexts. |
| 296 | // |
| 297 | // Error Returns Meaning |
| 298 | // |
| 299 | // TPM_RC_CONTEXT_GAP need to recycle sessions |
| 300 | // TPM_RC_SESSION_HANDLE active session space is full |
| 301 | // TPM_RC_SESSION_MEMORY loaded session space is full |
| 302 | // |
| 303 | TPM_RC |
| 304 | SessionCreate( |
| 305 | TPM_SE sessionType, // IN: the session type |
| 306 | TPMI_ALG_HASH authHash, // IN: the hash algorithm |
| 307 | TPM2B_NONCE *nonceCaller, // IN: initial nonceCaller |
| 308 | TPMT_SYM_DEF *symmetric, // IN: the symmetric algorithm |
| 309 | TPMI_DH_ENTITY bind, // IN: the bind object |
| 310 | TPM2B_DATA *seed, // IN: seed data |
| 311 | TPM_HANDLE *sessionHandle // OUT: the session handle |
| 312 | ) |
| 313 | { |
| 314 | TPM_RC result = TPM_RC_SUCCESS; |
| 315 | CONTEXT_SLOT slotIndex; |
| 316 | SESSION *session = NULL; |
| 317 | pAssert( sessionType == TPM_SE_HMAC |
| 318 | || sessionType == TPM_SE_POLICY |
| 319 | || sessionType == TPM_SE_TRIAL); |
| 320 | // If there are no open spots in the session array, then no point in searching |
| 321 | if(s_freeSessionSlots == 0) |
| 322 | return TPM_RC_SESSION_MEMORY; |
| 323 | // Find a space for loading a session |
| 324 | for(slotIndex = 0; slotIndex < MAX_LOADED_SESSIONS; slotIndex++) |
| 325 | { |
| 326 | // Is this available? |
| 327 | if(s_sessions[slotIndex].occupied == FALSE) |
| 328 | { |
| 329 | session = &s_sessions[slotIndex].session; |
| 330 | break; |
| 331 | } |
| 332 | } |
| 333 | // if no spot found, then this is an internal error |
| 334 | pAssert (slotIndex < MAX_LOADED_SESSIONS); |
| 335 | // Call context ID function to get a handle. TPM_RC_SESSION_HANDLE may be |
| 336 | // returned from ContextIdHandelAssign() |
| 337 | result = ContextIdSessionCreate(sessionHandle, slotIndex); |
| 338 | if(result != TPM_RC_SUCCESS) |
| 339 | return result; |
| 340 | //*** Only return from this point on is TPM_RC_SUCCESS |
| 341 | // Can now indicate that the session array entry is occupied. |
| 342 | s_freeSessionSlots--; |
| 343 | s_sessions[slotIndex].occupied = TRUE; |
| 344 | // Initialize the session data |
| 345 | MemorySet(session, 0, sizeof(SESSION)); |
| 346 | // Initialize internal session data |
| 347 | session->authHashAlg = authHash; |
| 348 | // Initialize session type |
| 349 | if(sessionType == TPM_SE_HMAC) |
| 350 | { |
| 351 | *sessionHandle += HMAC_SESSION_FIRST; |
| 352 | } |
| 353 | else |
| 354 | { |
| 355 | *sessionHandle += POLICY_SESSION_FIRST; |
| 356 | // For TPM_SE_POLICY or TPM_SE_TRIAL |
| 357 | session->attributes.isPolicy = SET; |
| 358 | if(sessionType == TPM_SE_TRIAL) |
| 359 | session->attributes.isTrialPolicy = SET; |
| 360 | // Initialize policy session data |
| 361 | SessionInitPolicyData(session); |
| 362 | } |
| 363 | // Create initial session nonce |
| 364 | session->nonceTPM.t.size = nonceCaller->t.size; |
| 365 | CryptGenerateRandom(session->nonceTPM.t.size, session->nonceTPM.t.buffer); |
| 366 | // Set up session parameter encryption algorithm |
| 367 | session->symmetric = *symmetric; |
| 368 | // If there is a bind object or a session secret, then need to compute |
| 369 | // a sessionKey. |
| 370 | if(bind != TPM_RH_NULL || seed->t.size != 0) |
| 371 | { |
| 372 | // sessionKey = KDFa(hash, (authValue || seed), "ATH", nonceTPM, |
| 373 | // nonceCaller, bits) |
| 374 | // The HMAC key for generating the sessionSecret can be the concatenation |
| 375 | // of an authorization value and a seed value |
| 376 | TPM2B_TYPE(KEY, (sizeof(TPMT_HA) + sizeof(seed->t.buffer))); |
| 377 | TPM2B_KEY key; |
| 378 | UINT16 hashSize; // The size of the hash used by the |
| 379 | // session crated by this command |
| 380 | TPM2B_AUTH entityAuth; // The authValue of the entity |
| 381 | // associated with HMAC session |
| 382 | // Get hash size, which is also the length of sessionKey |
| 383 | hashSize = CryptGetHashDigestSize(session->authHashAlg); |
| 384 | // Get authValue of associated entity |
| 385 | entityAuth.t.size = EntityGetAuthValue(bind, &entityAuth.t.buffer); |
| 386 | // Concatenate authValue and seed |
| 387 | pAssert(entityAuth.t.size + seed->t.size <= sizeof(key.t.buffer)); |
| 388 | MemoryCopy2B(&key.b, &entityAuth.b, sizeof(key.t.buffer)); |
| 389 | MemoryConcat2B(&key.b, &seed->b, sizeof(key.t.buffer)); |
| 390 | session->sessionKey.t.size = hashSize; |
| 391 | // Compute the session key |
| 392 | KDFa(session->authHashAlg, &key.b, "ATH", &session->nonceTPM.b, |
| 393 | &nonceCaller->b, hashSize * 8, session->sessionKey.t.buffer, NULL); |
| 394 | } |
| 395 | // Copy the name of the entity that the HMAC session is bound to |
| 396 | // Policy session is not bound to an entity |
| 397 | if(bind != TPM_RH_NULL && sessionType == TPM_SE_HMAC) |
| 398 | { |
| 399 | session->attributes.isBound = SET; |
| 400 | SessionComputeBoundEntity(bind, &session->u1.boundEntity); |
| 401 | } |
| 402 | // If there is a bind object and it is subject to DA, then use of this session |
| 403 | // is subject to DA regardless of how it is used. |
| 404 | session->attributes.isDaBound = (bind != TPM_RH_NULL) |
| 405 | && (IsDAExempted(bind) == FALSE); |
| 406 | // If the session is bound, then check to see if it is bound to lockoutAuth |
| 407 | session->attributes.isLockoutBound = (session->attributes.isDaBound == SET) |
| 408 | && (bind == TPM_RH_LOCKOUT); |
| 409 | return TPM_RC_SUCCESS; |
| 410 | } |
| 411 | // |
| 412 | // |
| 413 | // SessionContextSave() |
| 414 | // |
| 415 | // This function is called when a session context is to be saved. The contextID of the saved session is |
| 416 | // returned. If no contextID can be assigned, then the routine returns TPM_RC_CONTEXT_GAP. If the |
| 417 | // function completes normally, the session slot will be freed. |
| 418 | // This function requires that handle references a loaded session. Otherwise, it should not be called at the |
| 419 | // first place. |
| 420 | // |
| 421 | // Error Returns Meaning |
| 422 | // |
| 423 | // TPM_RC_CONTEXT_GAP a contextID could not be assigned. |
| 424 | // TPM_RC_TOO_MANY_CONTEXTS the counter maxed out |
| 425 | // |
| 426 | TPM_RC |
| 427 | SessionContextSave ( |
| 428 | TPM_HANDLE handle, // IN: session handle |
| 429 | CONTEXT_COUNTER *contextID // OUT: assigned contextID |
| 430 | ) |
| 431 | { |
| 432 | UINT32 contextIndex; |
| 433 | CONTEXT_SLOT slotIndex; |
| 434 | pAssert(SessionIsLoaded(handle)); |
| 435 | // check to see if the gap is already maxed out |
| 436 | // Need to have a saved session |
| 437 | if( s_oldestSavedSession < MAX_ACTIVE_SESSIONS |
| 438 | // if the oldest saved session has the same value as the low bits |
| 439 | // of the contextCounter, then the GAP is maxed out. |
| 440 | && gr.contextArray[s_oldestSavedSession] == (CONTEXT_SLOT)gr.contextCounter) |
| 441 | return TPM_RC_CONTEXT_GAP; |
| 442 | // if the caller wants the context counter, set it |
| 443 | if(contextID != NULL) |
| 444 | *contextID = gr.contextCounter; |
| 445 | pAssert((handle & HR_HANDLE_MASK) < MAX_ACTIVE_SESSIONS); |
| 446 | contextIndex = handle & HR_HANDLE_MASK; |
| 447 | // Extract the session slot number referenced by the contextArray |
| 448 | // because we are going to overwrite this with the low order |
| 449 | // contextID value. |
| 450 | slotIndex = gr.contextArray[contextIndex] - 1; |
| 451 | // Set the contextID for the contextArray |
| 452 | gr.contextArray[contextIndex] = (CONTEXT_SLOT)gr.contextCounter; |
| 453 | // Increment the counter |
| 454 | gr.contextCounter++; |
| 455 | // In the unlikely event that the 64-bit context counter rolls over... |
| 456 | if(gr.contextCounter == 0) |
| 457 | { |
| 458 | // back it up |
| 459 | gr.contextCounter--; |
| 460 | // return an error |
| 461 | return TPM_RC_TOO_MANY_CONTEXTS; |
| 462 | } |
| 463 | // if the low-order bits wrapped, need to advance the value to skip over |
| 464 | // the values used to indicate that a session is loaded |
| 465 | if(((CONTEXT_SLOT)gr.contextCounter) == 0) |
| 466 | gr.contextCounter += MAX_LOADED_SESSIONS + 1; |
| 467 | // If no other sessions are saved, this is now the oldest. |
| 468 | if(s_oldestSavedSession >= MAX_ACTIVE_SESSIONS) |
| 469 | s_oldestSavedSession = contextIndex; |
| 470 | // Mark the session slot as unoccupied |
| 471 | s_sessions[slotIndex].occupied = FALSE; |
| 472 | // and indicate that there is an additional open slot |
| 473 | s_freeSessionSlots++; |
| 474 | return TPM_RC_SUCCESS; |
| 475 | } |
| 476 | // |
| 477 | // |
| 478 | // SessionContextLoad() |
| 479 | // |
| 480 | // This function is used to load a session from saved context. The session handle must be for a saved |
| 481 | // context. |
| 482 | // If the gap is at a maximum, then the only session that can be loaded is the oldest session, otherwise |
| 483 | // TPM_RC_CONTEXT_GAP is returned. |
| 484 | // This function requires that handle references a valid saved session. |
| 485 | // |
| 486 | // |
| 487 | // |
| 488 | // Error Returns Meaning |
| 489 | // |
| 490 | // TPM_RC_SESSION_MEMORY no free session slots |
| 491 | // TPM_RC_CONTEXT_GAP the gap count is maximum and this is not the oldest saved context |
| 492 | // |
| 493 | TPM_RC |
| 494 | SessionContextLoad( |
| 495 | SESSION *session, // IN: session structure from saved context |
| 496 | TPM_HANDLE *handle // IN/OUT: session handle |
| 497 | ) |
| 498 | { |
| 499 | UINT32 contextIndex; |
| 500 | CONTEXT_SLOT slotIndex; |
| 501 | pAssert( HandleGetType(*handle) == TPM_HT_POLICY_SESSION |
| 502 | || HandleGetType(*handle) == TPM_HT_HMAC_SESSION); |
| 503 | // Don't bother looking if no openings |
| 504 | if(s_freeSessionSlots == 0) |
| 505 | return TPM_RC_SESSION_MEMORY; |
| 506 | // Find a free session slot to load the session |
| 507 | for(slotIndex = 0; slotIndex < MAX_LOADED_SESSIONS; slotIndex++) |
| 508 | if(s_sessions[slotIndex].occupied == FALSE) break; |
| 509 | // if no spot found, then this is an internal error |
| 510 | pAssert (slotIndex < MAX_LOADED_SESSIONS); |
| 511 | contextIndex = *handle & HR_HANDLE_MASK; // extract the index |
| 512 | // If there is only one slot left, and the gap is at maximum, the only session |
| 513 | // context that we can safely load is the oldest one. |
| 514 | if( s_oldestSavedSession < MAX_ACTIVE_SESSIONS |
| 515 | && s_freeSessionSlots == 1 |
| 516 | && (CONTEXT_SLOT)gr.contextCounter == gr.contextArray[s_oldestSavedSession] |
| 517 | && contextIndex != s_oldestSavedSession |
| 518 | ) |
| 519 | return TPM_RC_CONTEXT_GAP; |
| 520 | pAssert(contextIndex < MAX_ACTIVE_SESSIONS); |
| 521 | // set the contextArray value to point to the session slot where |
| 522 | // the context is loaded |
| 523 | gr.contextArray[contextIndex] = slotIndex + 1; |
| 524 | // if this was the oldest context, find the new oldest |
| 525 | if(contextIndex == s_oldestSavedSession) |
| 526 | ContextIdSetOldest(); |
| 527 | // Copy session data to session slot |
| 528 | s_sessions[slotIndex].session = *session; |
| 529 | // Set session slot as occupied |
| 530 | s_sessions[slotIndex].occupied = TRUE; |
| 531 | // Reduce the number of open spots |
| 532 | s_freeSessionSlots--; |
| 533 | return TPM_RC_SUCCESS; |
| 534 | } |
| 535 | // |
| 536 | // |
| 537 | // |
| 538 | // SessionFlush() |
| 539 | // |
| 540 | // This function is used to flush a session referenced by its handle. If the session associated with handle is |
| 541 | // loaded, the session array entry is marked as available. |
| 542 | // This function requires that handle be a valid active session. |
| 543 | // |
| 544 | void |
| 545 | SessionFlush( |
| 546 | TPM_HANDLE handle // IN: loaded or saved session handle |
| 547 | ) |
| 548 | { |
| 549 | CONTEXT_SLOT slotIndex; |
| 550 | UINT32 contextIndex; // Index into contextArray |
| 551 | pAssert( ( HandleGetType(handle) == TPM_HT_POLICY_SESSION |
| 552 | || HandleGetType(handle) == TPM_HT_HMAC_SESSION |
| 553 | ) |
| 554 | && (SessionIsLoaded(handle) || SessionIsSaved(handle)) |
| 555 | ); |
| 556 | // Flush context ID of this session |
| 557 | // Convert handle to an index into the contextArray |
| 558 | contextIndex = handle & HR_HANDLE_MASK; |
| 559 | pAssert(contextIndex < sizeof(gr.contextArray)/sizeof(gr.contextArray[0])); |
| 560 | // Get the current contents of the array |
| 561 | slotIndex = gr.contextArray[contextIndex]; |
| 562 | // Mark context array entry as available |
| 563 | gr.contextArray[contextIndex] = 0; |
| 564 | // Is this a saved session being flushed |
| 565 | if(slotIndex > MAX_LOADED_SESSIONS) |
| 566 | { |
| 567 | // Flushing the oldest session? |
| 568 | if(contextIndex == s_oldestSavedSession) |
| 569 | // If so, find a new value for oldest. |
| 570 | ContextIdSetOldest(); |
| 571 | } |
| 572 | else |
| 573 | { |
| 574 | // Adjust slot index to point to session array index |
| 575 | slotIndex -= 1; |
| 576 | // Free session array index |
| 577 | s_sessions[slotIndex].occupied = FALSE; |
| 578 | s_freeSessionSlots++; |
| 579 | } |
| 580 | return; |
| 581 | } |
| 582 | // |
| 583 | // |
| 584 | // SessionComputeBoundEntity() |
| 585 | // |
| 586 | // This function computes the binding value for a session. The binding value for a reserved handle is the |
| 587 | // handle itself. For all the other entities, the authValue at the time of binding is included to prevent |
| 588 | // squatting. For those values, the Name and the authValue are concatenated into the bind buffer. If they |
| 589 | // will not both fit, the will be overlapped by XORing() bytes. If XOR is required, the bind value will be full. |
| 590 | // |
| 591 | void |
| 592 | SessionComputeBoundEntity( |
| 593 | TPMI_DH_ENTITY entityHandle, // IN: handle of entity |
| 594 | TPM2B_NAME *bind // OUT: binding value |
| 595 | ) |
| 596 | { |
| 597 | TPM2B_AUTH auth; |
| 598 | INT16 overlap; |
| 599 | // Get name |
| 600 | bind->t.size = EntityGetName(entityHandle, &bind->t.name); |
| 601 | // // The bound value of a reserved handle is the handle itself |
| 602 | // if(bind->t.size == sizeof(TPM_HANDLE)) return; |
| 603 | // For all the other entities, concatenate the auth value to the name. |
| 604 | // Get a local copy of the auth value because some overlapping |
| 605 | // may be necessary. |
| 606 | auth.t.size = EntityGetAuthValue(entityHandle, &auth.t.buffer); |
| 607 | pAssert(auth.t.size <= sizeof(TPMU_HA)); |
| 608 | // Figure out if there will be any overlap |
| 609 | overlap = bind->t.size + auth.t.size - sizeof(bind->t.name); |
| 610 | // There is overlap if the combined sizes are greater than will fit |
| 611 | if(overlap > 0) |
| 612 | { |
| 613 | // The overlap area is at the end of the Name |
| 614 | BYTE *result = &bind->t.name[bind->t.size - overlap]; |
| 615 | int i; |
| 616 | // XOR the auth value into the Name for the overlap area |
| 617 | for(i = 0; i < overlap; i++) |
| 618 | result[i] ^= auth.t.buffer[i]; |
| 619 | } |
| 620 | else |
| 621 | { |
| 622 | // There is no overlap |
| 623 | overlap = 0; |
| 624 | } |
| 625 | //copy the remainder of the authData to the end of the name |
| 626 | MemoryCopy(&bind->t.name[bind->t.size], &auth.t.buffer[overlap], |
| 627 | auth.t.size - overlap, sizeof(bind->t.name) - bind->t.size); |
| 628 | // Increase the size of the bind data by the size of the auth - the overlap |
| 629 | bind->t.size += auth.t.size-overlap; |
| 630 | return; |
| 631 | } |
| 632 | // |
| 633 | // |
| 634 | // SessionInitPolicyData() |
| 635 | // |
| 636 | // This function initializes the portions of the session policy data that are not set by the allocation of a |
| 637 | // session. |
| 638 | // |
| 639 | void |
| 640 | SessionInitPolicyData( |
| 641 | SESSION *session // IN: session handle |
| 642 | ) |
| 643 | { |
| 644 | // Initialize start time |
| 645 | session->startTime = go.clock; |
| 646 | // Initialize policyDigest. policyDigest is initialized with a string of 0 of |
| 647 | // session algorithm digest size. Since the policy already contains all zeros |
| 648 | // it is only necessary to set the size |
| 649 | session->u2.policyDigest.t.size = CryptGetHashDigestSize(session->authHashAlg); |
| 650 | return; |
| 651 | } |
| 652 | // |
| 653 | // |
| 654 | // SessionResetPolicyData() |
| 655 | // |
| 656 | // This function is used to reset the policy data without changing the nonce or the start time of the session. |
| 657 | // |
| 658 | void |
| 659 | SessionResetPolicyData( |
| 660 | SESSION *session // IN: the session to reset |
| 661 | ) |
| 662 | { |
| 663 | session->commandCode = 0; // No command |
| 664 | // No locality selected |
| 665 | MemorySet(&session->commandLocality, 0, sizeof(session->commandLocality)); |
| 666 | // The cpHash size to zero |
| 667 | session->u1.cpHash.b.size = 0; |
| 668 | // No timeout |
| 669 | session->timeOut = 0; |
| 670 | // Reset the pcrCounter |
| 671 | session->pcrCounter = 0; |
| 672 | // Reset the policy hash |
| 673 | MemorySet(&session->u2.policyDigest.t.buffer, 0, |
| 674 | session->u2.policyDigest.t.size); |
| 675 | // Reset the session attributes |
| 676 | MemorySet(&session->attributes, 0, sizeof(SESSION_ATTRIBUTES)); |
| 677 | // set the policy attribute |
| 678 | session->attributes.isPolicy = SET; |
| 679 | } |
| 680 | // |
| 681 | // |
| 682 | // SessionCapGetLoaded() |
| 683 | // |
| 684 | // This function returns a list of handles of loaded session, started from input handle |
| 685 | // Handle must be in valid loaded session handle range, but does not have to point to a loaded session. |
| 686 | // |
| 687 | // Return Value Meaning |
| 688 | // |
| 689 | // YES if there are more handles available |
| 690 | // NO all the available handles has been returned |
| 691 | // |
| 692 | TPMI_YES_NO |
| 693 | SessionCapGetLoaded( |
| 694 | TPMI_SH_POLICY handle, // IN: start handle |
| 695 | UINT32 count, // IN: count of returned handle |
| 696 | TPML_HANDLE *handleList // OUT: list of handle |
| 697 | ) |
| 698 | { |
| 699 | TPMI_YES_NO more = NO; |
| 700 | UINT32 i; |
| 701 | pAssert(HandleGetType(handle) == TPM_HT_LOADED_SESSION); |
| 702 | // Initialize output handle list |
| 703 | handleList->count = 0; |
| 704 | // The maximum count of handles we may return is MAX_CAP_HANDLES |
| 705 | if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; |
| 706 | // Iterate session context ID slots to get loaded session handles |
| 707 | for(i = handle & HR_HANDLE_MASK; i < MAX_ACTIVE_SESSIONS; i++) |
| 708 | { |
| 709 | // If session is active |
| 710 | if(gr.contextArray[i] != 0) |
| 711 | { |
| 712 | // If session is loaded |
| 713 | if (gr.contextArray[i] <= MAX_LOADED_SESSIONS) |
| 714 | { |
| 715 | if(handleList->count < count) |
| 716 | { |
| 717 | SESSION *session; |
| 718 | // If we have not filled up the return list, add this |
| 719 | // session handle to it |
| 720 | // assume that this is going to be an HMAC session |
| 721 | handle = i + HMAC_SESSION_FIRST; |
| 722 | session = SessionGet(handle); |
| 723 | if(session->attributes.isPolicy) |
| 724 | handle = i + POLICY_SESSION_FIRST; |
| 725 | handleList->handle[handleList->count] = handle; |
| 726 | handleList->count++; |
| 727 | } |
| 728 | else |
| 729 | { |
| 730 | // If the return list is full but we still have loaded object |
| 731 | // available, report this and stop iterating |
| 732 | more = YES; |
| 733 | break; |
| 734 | } |
| 735 | } |
| 736 | } |
| 737 | } |
| 738 | return more; |
| 739 | } |
| 740 | // |
| 741 | // |
| 742 | // SessionCapGetSaved() |
| 743 | // |
| 744 | // This function returns a list of handles for saved session, starting at handle. |
| 745 | // Handle must be in a valid handle range, but does not have to point to a saved session |
| 746 | // |
| 747 | // Return Value Meaning |
| 748 | // |
| 749 | // YES if there are more handles available |
| 750 | // NO all the available handles has been returned |
| 751 | // |
| 752 | TPMI_YES_NO |
| 753 | SessionCapGetSaved( |
| 754 | TPMI_SH_HMAC handle, // IN: start handle |
| 755 | UINT32 count, // IN: count of returned handle |
| 756 | TPML_HANDLE *handleList // OUT: list of handle |
| 757 | ) |
| 758 | { |
| 759 | TPMI_YES_NO more = NO; |
| 760 | UINT32 i; |
| 761 | pAssert(HandleGetType(handle) == TPM_HT_ACTIVE_SESSION); |
| 762 | // Initialize output handle list |
| 763 | handleList->count = 0; |
| 764 | // The maximum count of handles we may return is MAX_CAP_HANDLES |
| 765 | if(count > MAX_CAP_HANDLES) count = MAX_CAP_HANDLES; |
| 766 | // Iterate session context ID slots to get loaded session handles |
| 767 | for(i = handle & HR_HANDLE_MASK; i < MAX_ACTIVE_SESSIONS; i++) |
| 768 | { |
| 769 | // If session is active |
| 770 | if(gr.contextArray[i] != 0) |
| 771 | { |
| 772 | // If session is saved |
| 773 | if (gr.contextArray[i] > MAX_LOADED_SESSIONS) |
| 774 | { |
| 775 | if(handleList->count < count) |
| 776 | { |
| 777 | // If we have not filled up the return list, add this |
| 778 | // session handle to it |
| 779 | handleList->handle[handleList->count] = i + HMAC_SESSION_FIRST; |
| 780 | handleList->count++; |
| 781 | } |
| 782 | else |
| 783 | { |
| 784 | // If the return list is full but we still have loaded object |
| 785 | // available, report this and stop iterating |
| 786 | more = YES; |
| 787 | break; |
| 788 | } |
| 789 | } |
| 790 | } |
| 791 | } |
| 792 | return more; |
| 793 | } |
| 794 | // |
| 795 | // |
| 796 | // SessionCapGetLoadedNumber() |
| 797 | // |
| 798 | // This function return the number of authorization sessions currently loaded into TPM RAM. |
| 799 | // |
| 800 | UINT32 |
| 801 | SessionCapGetLoadedNumber( |
| 802 | void |
| 803 | ) |
| 804 | { |
| 805 | return MAX_LOADED_SESSIONS - s_freeSessionSlots; |
| 806 | } |
| 807 | // |
| 808 | // |
| 809 | // SessionCapGetLoadedAvail() |
| 810 | // |
| 811 | // This function returns the number of additional authorization sessions, of any type, that could be loaded |
| 812 | // into TPM RAM. |
| 813 | // |
| 814 | // NOTE: In other implementations, this number may just be an estimate. The only requirement for the estimate is, if it is |
| 815 | // one or more, then at least one session must be loadable. |
| 816 | // |
| 817 | UINT32 |
| 818 | SessionCapGetLoadedAvail( |
| 819 | void |
| 820 | ) |
| 821 | { |
| 822 | return s_freeSessionSlots; |
| 823 | } |
| 824 | // |
| 825 | // |
| 826 | // SessionCapGetActiveNumber() |
| 827 | // |
| 828 | // This function returns the number of active authorization sessions currently being tracked by the TPM. |
| 829 | // |
| 830 | UINT32 |
| 831 | SessionCapGetActiveNumber( |
| 832 | void |
| 833 | ) |
| 834 | { |
| 835 | UINT32 i; |
| 836 | UINT32 num = 0; |
| 837 | // Iterate the context array to find the number of non-zero slots |
| 838 | for(i = 0; i < MAX_ACTIVE_SESSIONS; i++) |
| 839 | { |
| 840 | if(gr.contextArray[i] != 0) num++; |
| 841 | } |
| 842 | return num; |
| 843 | } |
| 844 | // |
| 845 | // |
| 846 | // SessionCapGetActiveAvail() |
| 847 | // |
| 848 | // This function returns the number of additional authorization sessions, of any type, that could be created. |
| 849 | // This not the number of slots for sessions, but the number of additional sessions that the TPM is capable |
| 850 | // of tracking. |
| 851 | // |
| 852 | UINT32 |
| 853 | SessionCapGetActiveAvail( |
| 854 | void |
| 855 | ) |
| 856 | { |
| 857 | UINT32 i; |
| 858 | UINT32 num = 0; |
| 859 | // Iterate the context array to find the number of zero slots |
| 860 | for(i = 0; i < MAX_ACTIVE_SESSIONS; i++) |
| 861 | { |
| 862 | if(gr.contextArray[i] == 0) num++; |
| 863 | } |
| 864 | return num; |
| 865 | } |