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