Home | History | Annotate | Download | only in Tpm2CommandLib
      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