1 /** @file 2 Implement TPM2 Sequences related command. 3 4 Copyright (c) 2013, Intel Corporation. All rights reserved. <BR> 5 This program and the accompanying materials 6 are licensed and made available under the terms and conditions of the BSD License 7 which accompanies this distribution. The full text of the license may be found at 8 http://opensource.org/licenses/bsd-license.php 9 10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, 11 WITHOUT 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 24 typedef struct { 25 TPM2_COMMAND_HEADER Header; 26 TPM2B_AUTH Auth; 27 TPMI_ALG_HASH HashAlg; 28 } TPM2_HASH_SEQUENCE_START_COMMAND; 29 30 typedef struct { 31 TPM2_RESPONSE_HEADER Header; 32 TPMI_DH_OBJECT SequenceHandle; 33 } TPM2_HASH_SEQUENCE_START_RESPONSE; 34 35 typedef 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 43 typedef struct { 44 TPM2_RESPONSE_HEADER Header; 45 UINT32 ParameterSize; 46 TPMS_AUTH_RESPONSE AuthSessionSeq; 47 } TPM2_SEQUENCE_UPDATE_RESPONSE; 48 49 typedef 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 59 typedef 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 67 typedef 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 76 typedef 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 **/ 97 EFI_STATUS 98 EFIAPI 99 Tpm2HashSequenceStart ( 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 **/ 185 EFI_STATUS 186 EFIAPI 187 Tpm2SequenceUpdate ( 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 **/ 284 EFI_STATUS 285 EFIAPI 286 Tpm2EventSequenceComplete ( 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 **/ 410 EFI_STATUS 411 EFIAPI 412 Tpm2SequenceComplete ( 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