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
Tpm2HashSequenceStart(IN TPMI_ALG_HASH HashAlg,OUT TPMI_DH_OBJECT * SequenceHandle)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
Tpm2SequenceUpdate(IN TPMI_DH_OBJECT SequenceHandle,IN TPM2B_MAX_BUFFER * Buffer)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
Tpm2EventSequenceComplete(IN TPMI_DH_PCR PcrHandle,IN TPMI_DH_OBJECT SequenceHandle,IN TPM2B_MAX_BUFFER * Buffer,OUT TPML_DIGEST_VALUES * Results)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
Tpm2SequenceComplete(IN TPMI_DH_OBJECT SequenceHandle,IN TPM2B_MAX_BUFFER * Buffer,OUT TPM2B_DIGEST * Result)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