1/** @file 2 Implement TPM2 Sequences related command. 3 4Copyright (c) 2013, Intel Corporation. All rights reserved. <BR> 5This program and the accompanying materials 6are licensed and made available under the terms and conditions of the BSD License 7which accompanies this distribution. The full text of the license may be found at 8http://opensource.org/licenses/bsd-license.php 9 10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. 12 13**/ 14 15#include <IndustryStandard/UefiTcgPlatform.h> 16#include <Library/Tpm2CommandLib.h> 17#include <Library/Tpm2DeviceLib.h> 18#include <Library/BaseMemoryLib.h> 19#include <Library/BaseLib.h> 20#include <Library/DebugLib.h> 21 22#pragma pack(1) 23 24typedef struct { 25 TPM2_COMMAND_HEADER Header; 26 TPM2B_AUTH Auth; 27 TPMI_ALG_HASH HashAlg; 28} TPM2_HASH_SEQUENCE_START_COMMAND; 29 30typedef struct { 31 TPM2_RESPONSE_HEADER Header; 32 TPMI_DH_OBJECT SequenceHandle; 33} TPM2_HASH_SEQUENCE_START_RESPONSE; 34 35typedef struct { 36 TPM2_COMMAND_HEADER Header; 37 TPMI_DH_OBJECT SequenceHandle; 38 UINT32 AuthorizationSize; 39 TPMS_AUTH_COMMAND AuthSessionSeq; 40 TPM2B_MAX_BUFFER Buffer; 41} TPM2_SEQUENCE_UPDATE_COMMAND; 42 43typedef struct { 44 TPM2_RESPONSE_HEADER Header; 45 UINT32 ParameterSize; 46 TPMS_AUTH_RESPONSE AuthSessionSeq; 47} TPM2_SEQUENCE_UPDATE_RESPONSE; 48 49typedef struct { 50 TPM2_COMMAND_HEADER Header; 51 TPMI_DH_PCR PcrHandle; 52 TPMI_DH_OBJECT SequenceHandle; 53 UINT32 AuthorizationSize; 54 TPMS_AUTH_COMMAND AuthSessionPcr; 55 TPMS_AUTH_COMMAND AuthSessionSeq; 56 TPM2B_MAX_BUFFER Buffer; 57} TPM2_EVENT_SEQUENCE_COMPLETE_COMMAND; 58 59typedef struct { 60 TPM2_RESPONSE_HEADER Header; 61 UINT32 ParameterSize; 62 TPML_DIGEST_VALUES Results; 63 TPMS_AUTH_RESPONSE AuthSessionPcr; 64 TPMS_AUTH_RESPONSE AuthSessionSeq; 65} TPM2_EVENT_SEQUENCE_COMPLETE_RESPONSE; 66 67typedef struct { 68 TPM2_COMMAND_HEADER Header; 69 TPMI_DH_OBJECT SequenceHandle; 70 UINT32 AuthorizationSize; 71 TPMS_AUTH_COMMAND AuthSessionSeq; 72 TPM2B_MAX_BUFFER Buffer; 73 TPMI_RH_HIERARCHY Hierarchy; 74} TPM2_SEQUENCE_COMPLETE_COMMAND; 75 76typedef struct { 77 TPM2_RESPONSE_HEADER Header; 78 UINT32 ParameterSize; 79 TPM2B_DIGEST Digest; 80 TPMS_AUTH_RESPONSE AuthSessionSeq; 81} TPM2_SEQUENCE_COMPLETE_RESPONSE; 82 83#pragma pack() 84 85/** 86 This command starts a hash or an Event sequence. 87 If hashAlg is an implemented hash, then a hash sequence is started. 88 If hashAlg is TPM_ALG_NULL, then an Event sequence is started. 89 90 @param[in] HashAlg The hash algorithm to use for the hash sequence 91 An Event sequence starts if this is TPM_ALG_NULL. 92 @param[out] SequenceHandle A handle to reference the sequence 93 94 @retval EFI_SUCCESS Operation completed successfully. 95 @retval EFI_DEVICE_ERROR Unexpected device behavior. 96**/ 97EFI_STATUS 98EFIAPI 99Tpm2HashSequenceStart ( 100 IN TPMI_ALG_HASH HashAlg, 101 OUT TPMI_DH_OBJECT *SequenceHandle 102 ) 103{ 104 EFI_STATUS Status; 105 TPM2_HASH_SEQUENCE_START_COMMAND Cmd; 106 TPM2_HASH_SEQUENCE_START_RESPONSE Res; 107 UINT32 CmdSize; 108 UINT32 RespSize; 109 UINT8 *Buffer; 110 UINT32 ResultBufSize; 111 112 ZeroMem(&Cmd, sizeof(Cmd)); 113 114 // 115 // Construct command 116 // 117 Cmd.Header.tag = SwapBytes16(TPM_ST_NO_SESSIONS); 118 Cmd.Header.commandCode = SwapBytes32(TPM_CC_HashSequenceStart); 119 120 Buffer = (UINT8 *)&Cmd.Auth; 121 122 // auth = nullAuth 123 WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(0)); 124 Buffer += sizeof(UINT16); 125 126 // hashAlg 127 WriteUnaligned16 ((UINT16 *)Buffer, SwapBytes16(HashAlg)); 128 Buffer += sizeof(UINT16); 129 130 CmdSize = (UINT32)(Buffer - (UINT8 *)&Cmd); 131 Cmd.Header.paramSize = SwapBytes32(CmdSize); 132 133 // 134 // Call the TPM 135 // 136 ResultBufSize = sizeof(Res); 137 Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); 138 if (EFI_ERROR(Status)) { 139 return Status; 140 } 141 142 if (ResultBufSize > sizeof(Res)) { 143 DEBUG ((EFI_D_ERROR, "HashSequenceStart: Failed ExecuteCommand: Buffer Too Small\r\n")); 144 return EFI_BUFFER_TOO_SMALL; 145 } 146 147 // 148 // Validate response headers 149 // 150 RespSize = SwapBytes32(Res.Header.paramSize); 151 if (RespSize > sizeof(Res)) { 152 DEBUG ((EFI_D_ERROR, "HashSequenceStart: Response size too large! %d\r\n", RespSize)); 153 return EFI_BUFFER_TOO_SMALL; 154 } 155 156 // 157 // Fail if command failed 158 // 159 if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { 160 DEBUG ((EFI_D_ERROR, "HashSequenceStart: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); 161 return EFI_DEVICE_ERROR; 162 } 163 164 // 165 // Unmarshal the response 166 // 167 168 // sequenceHandle 169 *SequenceHandle = SwapBytes32(Res.SequenceHandle); 170 171 return EFI_SUCCESS; 172} 173 174/** 175 This command is used to add data to a hash or HMAC sequence. 176 The amount of data in buffer may be any size up to the limits of the TPM. 177 NOTE: In all TPM, a buffer size of 1,024 octets is allowed. 178 179 @param[in] SequenceHandle Handle for the sequence object 180 @param[in] Buffer Data to be added to hash 181 182 @retval EFI_SUCCESS Operation completed successfully. 183 @retval EFI_DEVICE_ERROR Unexpected device behavior. 184**/ 185EFI_STATUS 186EFIAPI 187Tpm2SequenceUpdate ( 188 IN TPMI_DH_OBJECT SequenceHandle, 189 IN TPM2B_MAX_BUFFER *Buffer 190 ) 191{ 192 EFI_STATUS Status; 193 TPM2_SEQUENCE_UPDATE_COMMAND Cmd; 194 TPM2_SEQUENCE_UPDATE_RESPONSE Res; 195 UINT32 CmdSize; 196 UINT32 RespSize; 197 UINT8 *BufferPtr; 198 UINT32 SessionInfoSize; 199 UINT32 ResultBufSize; 200 201 ZeroMem(&Cmd, sizeof(Cmd)); 202 203 // 204 // Construct command 205 // 206 Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); 207 Cmd.Header.commandCode = SwapBytes32(TPM_CC_SequenceUpdate); 208 Cmd.SequenceHandle = SwapBytes32(SequenceHandle); 209 210 // 211 // Add in Auth session 212 // 213 BufferPtr = (UINT8 *)&Cmd.AuthSessionSeq; 214 215 // sessionInfoSize 216 SessionInfoSize = CopyAuthSessionCommand (NULL, BufferPtr); 217 BufferPtr += SessionInfoSize; 218 Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize); 219 220 // buffer.size 221 WriteUnaligned16 ((UINT16 *)BufferPtr, SwapBytes16(Buffer->size)); 222 BufferPtr += sizeof(UINT16); 223 224 CopyMem(BufferPtr, &Buffer->buffer, Buffer->size); 225 BufferPtr += Buffer->size; 226 227 CmdSize = (UINT32)(BufferPtr - (UINT8 *)&Cmd); 228 Cmd.Header.paramSize = SwapBytes32(CmdSize); 229 230 // 231 // Call the TPM 232 // 233 ResultBufSize = sizeof(Res); 234 Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd,&ResultBufSize, (UINT8 *)&Res); 235 if (EFI_ERROR(Status)) { 236 return Status; 237 } 238 239 if (ResultBufSize > sizeof(Res)) { 240 DEBUG ((EFI_D_ERROR, "SequenceUpdate: Failed ExecuteCommand: Buffer Too Small\r\n")); 241 return EFI_BUFFER_TOO_SMALL; 242 } 243 244 // 245 // Validate response headers 246 // 247 RespSize = SwapBytes32(Res.Header.paramSize); 248 if (RespSize > sizeof(Res)) { 249 DEBUG ((EFI_D_ERROR, "SequenceUpdate: Response size too large! %d\r\n", RespSize)); 250 return EFI_BUFFER_TOO_SMALL; 251 } 252 253 // 254 // Fail if command failed 255 // 256 if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { 257 DEBUG ((EFI_D_ERROR, "SequenceUpdate: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); 258 return EFI_DEVICE_ERROR; 259 } 260 261 // 262 // Unmarshal the response 263 // 264 265 // None 266 267 return EFI_SUCCESS; 268} 269 270/** 271 This command adds the last part of data, if any, to an Event sequence and returns the result in a digest list. 272 If pcrHandle references a PCR and not TPM_RH_NULL, then the returned digest list is processed in 273 the same manner as the digest list input parameter to TPM2_PCR_Extend() with the pcrHandle in each 274 bank extended with the associated digest value. 275 276 @param[in] PcrHandle PCR to be extended with the Event data 277 @param[in] SequenceHandle Authorization for the sequence 278 @param[in] Buffer Data to be added to the Event 279 @param[out] Results List of digests computed for the PCR 280 281 @retval EFI_SUCCESS Operation completed successfully. 282 @retval EFI_DEVICE_ERROR Unexpected device behavior. 283**/ 284EFI_STATUS 285EFIAPI 286Tpm2EventSequenceComplete ( 287 IN TPMI_DH_PCR PcrHandle, 288 IN TPMI_DH_OBJECT SequenceHandle, 289 IN TPM2B_MAX_BUFFER *Buffer, 290 OUT TPML_DIGEST_VALUES *Results 291 ) 292{ 293 EFI_STATUS Status; 294 TPM2_EVENT_SEQUENCE_COMPLETE_COMMAND Cmd; 295 TPM2_EVENT_SEQUENCE_COMPLETE_RESPONSE Res; 296 UINT32 CmdSize; 297 UINT32 RespSize; 298 UINT8 *BufferPtr; 299 UINT32 SessionInfoSize; 300 UINT32 SessionInfoSize2; 301 UINT32 Index; 302 UINT32 ResultBufSize; 303 UINT16 DigestSize; 304 305 ZeroMem(&Cmd, sizeof(Cmd)); 306 307 // 308 // Construct command 309 // 310 Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); 311 Cmd.Header.commandCode = SwapBytes32(TPM_CC_EventSequenceComplete); 312 Cmd.PcrHandle = SwapBytes32(PcrHandle); 313 Cmd.SequenceHandle = SwapBytes32(SequenceHandle); 314 315 // 316 // Add in pcrHandle Auth session 317 // 318 BufferPtr = (UINT8 *)&Cmd.AuthSessionPcr; 319 320 // sessionInfoSize 321 SessionInfoSize = CopyAuthSessionCommand (NULL, BufferPtr); 322 BufferPtr += SessionInfoSize; 323 324 // sessionInfoSize 325 SessionInfoSize2 = CopyAuthSessionCommand (NULL, BufferPtr); 326 BufferPtr += SessionInfoSize2; 327 Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize + SessionInfoSize2); 328 329 // buffer.size 330 WriteUnaligned16 ((UINT16 *)BufferPtr, SwapBytes16(Buffer->size)); 331 BufferPtr += sizeof(UINT16); 332 333 CopyMem(BufferPtr, &Buffer->buffer[0], Buffer->size); 334 BufferPtr += Buffer->size; 335 336 CmdSize = (UINT32)(BufferPtr - (UINT8 *)&Cmd); 337 Cmd.Header.paramSize = SwapBytes32(CmdSize); 338 339 // 340 // Call the TPM 341 // 342 ResultBufSize = sizeof(Res); 343 Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); 344 if (EFI_ERROR(Status)) { 345 return Status; 346 } 347 348 if (ResultBufSize > sizeof(Res)) { 349 DEBUG ((EFI_D_ERROR, "EventSequenceComplete: Failed ExecuteCommand: Buffer Too Small\r\n")); 350 return EFI_BUFFER_TOO_SMALL; 351 } 352 353 // 354 // Validate response headers 355 // 356 RespSize = SwapBytes32(Res.Header.paramSize); 357 if (RespSize > sizeof(Res)) { 358 DEBUG ((EFI_D_ERROR, "EventSequenceComplete: Response size too large! %d\r\n", RespSize)); 359 return EFI_BUFFER_TOO_SMALL; 360 } 361 362 // 363 // Fail if command failed 364 // 365 if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { 366 DEBUG ((EFI_D_ERROR, "EventSequenceComplete: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); 367 return EFI_DEVICE_ERROR; 368 } 369 370 // 371 // Unmarshal the response 372 // 373 374 BufferPtr = (UINT8 *)&Res.Results; 375 376 // count 377 Results->count = SwapBytes32(ReadUnaligned32 ((UINT32 *)BufferPtr)); 378 BufferPtr += sizeof(UINT32); 379 380 for (Index = 0; Index < Results->count; Index++) { 381 Results->digests[Index].hashAlg = SwapBytes16(ReadUnaligned16 ((UINT16 *)BufferPtr)); 382 BufferPtr += sizeof(UINT16); 383 384 DigestSize = GetHashSizeFromAlgo (Results->digests[Index].hashAlg); 385 if (DigestSize == 0) { 386 DEBUG ((EFI_D_ERROR, "EventSequenceComplete: Unknown hash algorithm %d\r\n", Results->digests[Index].hashAlg)); 387 return EFI_DEVICE_ERROR; 388 } 389 CopyMem( 390 &Results->digests[Index].digest, 391 BufferPtr, 392 DigestSize 393 ); 394 BufferPtr += DigestSize; 395 } 396 397 return EFI_SUCCESS; 398} 399 400/** 401 This command adds the last part of data, if any, to a hash/HMAC sequence and returns the result. 402 403 @param[in] SequenceHandle Authorization for the sequence 404 @param[in] Buffer Data to be added to the hash/HMAC 405 @param[out] Result The returned HMAC or digest in a sized buffer 406 407 @retval EFI_SUCCESS Operation completed successfully. 408 @retval EFI_DEVICE_ERROR Unexpected device behavior. 409**/ 410EFI_STATUS 411EFIAPI 412Tpm2SequenceComplete ( 413 IN TPMI_DH_OBJECT SequenceHandle, 414 IN TPM2B_MAX_BUFFER *Buffer, 415 OUT TPM2B_DIGEST *Result 416 ) 417{ 418 EFI_STATUS Status; 419 TPM2_SEQUENCE_COMPLETE_COMMAND Cmd; 420 TPM2_SEQUENCE_COMPLETE_RESPONSE Res; 421 UINT32 CmdSize; 422 UINT32 RespSize; 423 UINT8 *BufferPtr; 424 UINT32 SessionInfoSize; 425 UINT32 ResultBufSize; 426 427 ZeroMem(&Cmd, sizeof(Cmd)); 428 429 // 430 // Construct command 431 // 432 Cmd.Header.tag = SwapBytes16(TPM_ST_SESSIONS); 433 Cmd.Header.commandCode = SwapBytes32(TPM_CC_SequenceComplete); 434 Cmd.SequenceHandle = SwapBytes32(SequenceHandle); 435 436 // 437 // Add in Auth session 438 // 439 BufferPtr = (UINT8 *)&Cmd.AuthSessionSeq; 440 441 // sessionInfoSize 442 SessionInfoSize = CopyAuthSessionCommand (NULL, BufferPtr); 443 BufferPtr += SessionInfoSize; 444 Cmd.AuthorizationSize = SwapBytes32(SessionInfoSize); 445 446 // buffer.size 447 WriteUnaligned16 ((UINT16 *)BufferPtr, SwapBytes16(Buffer->size)); 448 BufferPtr += sizeof(UINT16); 449 450 CopyMem(BufferPtr, &Buffer->buffer[0], Buffer->size); 451 BufferPtr += Buffer->size; 452 453 // Hierarchy 454 WriteUnaligned32 ((UINT32 *)BufferPtr, SwapBytes32 (TPM_RH_NULL)); 455 BufferPtr += sizeof (UINT32); 456 457 CmdSize = (UINT32)(BufferPtr - (UINT8 *)&Cmd); 458 Cmd.Header.paramSize = SwapBytes32(CmdSize); 459 460 // 461 // Call the TPM 462 // 463 ResultBufSize = sizeof(Res); 464 Status = Tpm2SubmitCommand (CmdSize, (UINT8 *)&Cmd, &ResultBufSize, (UINT8 *)&Res); 465 if (EFI_ERROR(Status)) { 466 return Status; 467 } 468 469 if (ResultBufSize > sizeof(Res)) { 470 DEBUG ((EFI_D_ERROR, "SequenceComplete: Failed ExecuteCommand: Buffer Too Small\r\n")); 471 return EFI_BUFFER_TOO_SMALL; 472 } 473 474 // 475 // Validate response headers 476 // 477 RespSize = SwapBytes32(Res.Header.paramSize); 478 if (RespSize > sizeof(Res)) { 479 DEBUG ((EFI_D_ERROR, "SequenceComplete: Response size too large! %d\r\n", RespSize)); 480 return EFI_BUFFER_TOO_SMALL; 481 } 482 483 // 484 // Fail if command failed 485 // 486 if (SwapBytes32(Res.Header.responseCode) != TPM_RC_SUCCESS) { 487 DEBUG ((EFI_D_ERROR, "SequenceComplete: Response Code error! 0x%08x\r\n", SwapBytes32(Res.Header.responseCode))); 488 return EFI_DEVICE_ERROR; 489 } 490 491 // 492 // Unmarshal the response 493 // 494 495 BufferPtr = (UINT8 *)&Res.Digest; 496 497 // digestSize 498 Result->size = SwapBytes16(ReadUnaligned16 ((UINT16 *)BufferPtr)); 499 BufferPtr += sizeof(UINT16); 500 501 CopyMem( 502 Result->buffer, 503 BufferPtr, 504 Result->size 505 ); 506 507 return EFI_SUCCESS; 508} 509