1/** @file
2  This module implements Hash2 Protocol.
3
4(C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
5Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
6This program and the accompanying materials are licensed and made available under
7the terms and conditions of the BSD License that accompanies this distribution.
8The full text of the license may be found at
9http://opensource.org/licenses/bsd-license.php.
10
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14**/
15
16#include <Uefi.h>
17#include <Protocol/Hash2.h>
18#include <Library/BaseLib.h>
19#include <Library/UefiBootServicesTableLib.h>
20#include <Library/MemoryAllocationLib.h>
21#include <Library/BaseMemoryLib.h>
22#include <Library/DebugLib.h>
23#include <Library/BaseCryptLib.h>
24
25#include "Driver.h"
26
27/**
28  Retrieves the size, in bytes, of the context buffer required for hash operations.
29
30  If this interface is not supported, then return zero.
31
32  @return  The size, in bytes, of the context buffer required for hash operations.
33  @retval  0   This interface is not supported.
34
35**/
36typedef
37UINTN
38(EFIAPI *EFI_HASH_GET_CONTEXT_SIZE) (
39  VOID
40  );
41
42/**
43  Initializes user-supplied memory pointed by Sha1Context as hash context for
44  subsequent use.
45
46  If HashContext is NULL, then return FALSE.
47  If this interface is not supported, then return FALSE.
48
49  @param[out]  HashContext  Pointer to Hashcontext being initialized.
50
51  @retval TRUE   Hash context initialization succeeded.
52  @retval FALSE  Hash context initialization failed.
53  @retval FALSE  This interface is not supported.
54
55**/
56typedef
57BOOLEAN
58(EFIAPI *EFI_HASH_INIT) (
59  OUT  VOID  *HashContext
60  );
61
62/**
63  Digests the input data and updates Hash context.
64
65  This function performs Hash digest on a data buffer of the specified size.
66  It can be called multiple times to compute the digest of long or discontinuous data streams.
67  Hash context should be already correctly initialized by HashInit(), and should not be finalized
68  by HashFinal(). Behavior with invalid context is undefined.
69
70  If HashContext is NULL, then return FALSE.
71  If this interface is not supported, then return FALSE.
72
73  @param[in, out]  HashContext  Pointer to the Hash context.
74  @param[in]       Data         Pointer to the buffer containing the data to be hashed.
75  @param[in]       DataSize     Size of Data buffer in bytes.
76
77  @retval TRUE   SHA-1 data digest succeeded.
78  @retval FALSE  SHA-1 data digest failed.
79  @retval FALSE  This interface is not supported.
80
81**/
82typedef
83BOOLEAN
84(EFIAPI *EFI_HASH_UPDATE) (
85  IN OUT  VOID        *HashContext,
86  IN      CONST VOID  *Data,
87  IN      UINTN       DataSize
88  );
89
90/**
91  Completes computation of the Hash digest value.
92
93  This function completes hash computation and retrieves the digest value into
94  the specified memory. After this function has been called, the Hash context cannot
95  be used again.
96  Hash context should be already correctly intialized by HashInit(), and should not be
97  finalized by HashFinal(). Behavior with invalid Hash context is undefined.
98
99  If HashContext is NULL, then return FALSE.
100  If HashValue is NULL, then return FALSE.
101  If this interface is not supported, then return FALSE.
102
103  @param[in, out]  HashContext  Pointer to the Hash context.
104  @param[out]      HashValue    Pointer to a buffer that receives the Hash digest
105                                value.
106
107  @retval TRUE   Hash digest computation succeeded.
108  @retval FALSE  Hash digest computation failed.
109  @retval FALSE  This interface is not supported.
110
111**/
112typedef
113BOOLEAN
114(EFIAPI *EFI_HASH_FINAL) (
115  IN OUT  VOID   *HashContext,
116  OUT     UINT8  *HashValue
117  );
118
119typedef struct {
120  EFI_GUID                   *Guid;
121  UINT32                     HashSize;
122  EFI_HASH_GET_CONTEXT_SIZE  GetContextSize;
123  EFI_HASH_INIT              Init;
124  EFI_HASH_UPDATE            Update;
125  EFI_HASH_FINAL             Final;
126} EFI_HASH_INFO;
127
128EFI_HASH_INFO  mHashInfo[] = {
129  {&gEfiHashAlgorithmMD5Guid,     sizeof(EFI_MD5_HASH2),    Md5GetContextSize,    Md5Init,    Md5Update,    Md5Final  },
130  {&gEfiHashAlgorithmSha1Guid,    sizeof(EFI_SHA1_HASH2),   Sha1GetContextSize,   Sha1Init,   Sha1Update,   Sha1Final   },
131  {&gEfiHashAlgorithmSha256Guid,  sizeof(EFI_SHA256_HASH2), Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final },
132  {&gEfiHashAlgorithmSha384Guid,  sizeof(EFI_SHA384_HASH2), Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final },
133  {&gEfiHashAlgorithmSha512Guid,  sizeof(EFI_SHA512_HASH2), Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final },
134};
135
136/**
137  Returns the size of the hash which results from a specific algorithm.
138
139  @param[in]  This                  Points to this instance of EFI_HASH2_PROTOCOL.
140  @param[in]  HashAlgorithm         Points to the EFI_GUID which identifies the algorithm to use.
141  @param[out] HashSize              Holds the returned size of the algorithm's hash.
142
143  @retval EFI_SUCCESS           Hash size returned successfully.
144  @retval EFI_INVALID_PARAMETER This or HashSize is NULL.
145  @retval EFI_UNSUPPORTED       The algorithm specified by HashAlgorithm is not supported by this driver
146                                or HashAlgorithm is null.
147
148**/
149EFI_STATUS
150EFIAPI
151BaseCrypto2GetHashSize (
152  IN  CONST EFI_HASH2_PROTOCOL     *This,
153  IN  CONST EFI_GUID               *HashAlgorithm,
154  OUT UINTN                        *HashSize
155  );
156
157/**
158  Creates a hash for the specified message text. The hash is not extendable.
159  The output is final with any algorithm-required padding added by the function.
160
161  @param[in]  This          Points to this instance of EFI_HASH2_PROTOCOL.
162  @param[in]  HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use.
163  @param[in]  Message       Points to the start of the message.
164  @param[in]  MessageSize   The size of Message, in bytes.
165  @param[in,out]  Hash      On input, points to a caller-allocated buffer of the size
166                              returned by GetHashSize() for the specified HashAlgorithm.
167                            On output, the buffer holds the resulting hash computed from the message.
168
169  @retval EFI_SUCCESS           Hash returned successfully.
170  @retval EFI_INVALID_PARAMETER This or Hash is NULL.
171  @retval EFI_UNSUPPORTED       The algorithm specified by HashAlgorithm is not supported by this driver
172                                or HashAlgorithm is Null.
173  @retval EFI_OUT_OF_RESOURCES  Some resource required by the function is not available
174                                or MessageSize is greater than platform maximum.
175
176**/
177EFI_STATUS
178EFIAPI
179BaseCrypto2Hash (
180  IN CONST EFI_HASH2_PROTOCOL      *This,
181  IN CONST EFI_GUID                *HashAlgorithm,
182  IN CONST UINT8                   *Message,
183  IN UINTN                         MessageSize,
184  IN OUT EFI_HASH2_OUTPUT          *Hash
185  );
186
187/**
188  This function must be called to initialize a digest calculation to be subsequently performed using the
189  EFI_HASH2_PROTOCOL functions HashUpdate() and HashFinal().
190
191  @param[in]  This          Points to this instance of EFI_HASH2_PROTOCOL.
192  @param[in]  HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use.
193
194  @retval EFI_SUCCESS           Initialized successfully.
195  @retval EFI_INVALID_PARAMETER This is NULL.
196  @retval EFI_UNSUPPORTED       The algorithm specified by HashAlgorithm is not supported by this driver
197                                or HashAlgorithm is Null.
198  @retval EFI_OUT_OF_RESOURCES  Process failed due to lack of required resource.
199  @retval EFI_ALREADY_STARTED   This function is called when the operation in progress is still in processing Hash(),
200                                or HashInit() is already called before and not terminated by HashFinal() yet on the same instance.
201
202**/
203EFI_STATUS
204EFIAPI
205BaseCrypto2HashInit (
206  IN CONST EFI_HASH2_PROTOCOL      *This,
207  IN CONST EFI_GUID                *HashAlgorithm
208  );
209
210/**
211  Updates the hash of a computation in progress by adding a message text.
212
213  @param[in]  This          Points to this instance of EFI_HASH2_PROTOCOL.
214  @param[in]  Message       Points to the start of the message.
215  @param[in]  MessageSize   The size of Message, in bytes.
216
217  @retval EFI_SUCCESS           Digest in progress updated successfully.
218  @retval EFI_INVALID_PARAMETER This or Hash is NULL.
219  @retval EFI_OUT_OF_RESOURCES  Some resource required by the function is not available
220                                or MessageSize is greater than platform maximum.
221  @retval EFI_NOT_READY         This call was not preceded by a valid call to HashInit(),
222                                or the operation in progress was terminated by a call to Hash() or HashFinal() on the same instance.
223
224**/
225EFI_STATUS
226EFIAPI
227BaseCrypto2HashUpdate (
228  IN CONST EFI_HASH2_PROTOCOL      *This,
229  IN CONST UINT8                   *Message,
230  IN UINTN                         MessageSize
231  );
232
233/**
234  Finalizes a hash operation in progress and returns calculation result.
235  The output is final with any necessary padding added by the function.
236  The hash may not be further updated or extended after HashFinal().
237
238  @param[in]  This          Points to this instance of EFI_HASH2_PROTOCOL.
239  @param[in,out]  Hash      On input, points to a caller-allocated buffer of the size
240                              returned by GetHashSize() for the specified HashAlgorithm specified in preceding HashInit().
241                            On output, the buffer holds the resulting hash computed from the message.
242
243  @retval EFI_SUCCESS           Hash returned successfully.
244  @retval EFI_INVALID_PARAMETER This or Hash is NULL.
245  @retval EFI_NOT_READY         This call was not preceded by a valid call to HashInit() and at least one call to HashUpdate(),
246                                or the operation in progress was canceled by a call to Hash() on the same instance.
247
248**/
249EFI_STATUS
250EFIAPI
251BaseCrypto2HashFinal (
252  IN CONST EFI_HASH2_PROTOCOL      *This,
253  IN OUT EFI_HASH2_OUTPUT          *Hash
254  );
255
256EFI_HASH2_PROTOCOL mHash2Protocol = {
257  BaseCrypto2GetHashSize,
258  BaseCrypto2Hash,
259  BaseCrypto2HashInit,
260  BaseCrypto2HashUpdate,
261  BaseCrypto2HashFinal,
262};
263
264/**
265  Returns hash information.
266
267  @param[in]  HashAlgorithm         Points to the EFI_GUID which identifies the algorithm to use.
268
269  @return Hash information.
270**/
271EFI_HASH_INFO *
272GetHashInfo (
273  IN CONST EFI_GUID              *HashAlgorithm
274  )
275{
276  UINTN      Index;
277
278  for (Index = 0; Index < sizeof(mHashInfo)/sizeof(mHashInfo[0]); Index++) {
279    if (CompareGuid (HashAlgorithm, mHashInfo[Index].Guid)) {
280      return &mHashInfo[Index];
281    }
282  }
283  return NULL;
284}
285
286/**
287  Returns the size of the hash which results from a specific algorithm.
288
289  @param[in]  This                  Points to this instance of EFI_HASH2_PROTOCOL.
290  @param[in]  HashAlgorithm         Points to the EFI_GUID which identifies the algorithm to use.
291  @param[out] HashSize              Holds the returned size of the algorithm's hash.
292
293  @retval EFI_SUCCESS           Hash size returned successfully.
294  @retval EFI_INVALID_PARAMETER This or HashSize is NULL.
295  @retval EFI_UNSUPPORTED       The algorithm specified by HashAlgorithm is not supported by this driver
296                                or HashAlgorithm is null.
297
298**/
299EFI_STATUS
300EFIAPI
301BaseCrypto2GetHashSize (
302  IN  CONST EFI_HASH2_PROTOCOL     *This,
303  IN  CONST EFI_GUID              *HashAlgorithm,
304  OUT UINTN                       *HashSize
305  )
306{
307  EFI_HASH_INFO *HashInfo;
308
309  if ((This == NULL) || (HashSize == NULL)) {
310    return EFI_INVALID_PARAMETER;
311  }
312
313  if (HashAlgorithm == NULL) {
314    return EFI_UNSUPPORTED;
315  }
316
317  HashInfo = GetHashInfo (HashAlgorithm);
318  if (HashInfo == NULL) {
319    return EFI_UNSUPPORTED;
320  }
321
322  *HashSize = HashInfo->HashSize;
323  return EFI_SUCCESS;
324}
325
326/**
327  Creates a hash for the specified message text. The hash is not extendable.
328  The output is final with any algorithm-required padding added by the function.
329
330  @param[in]  This          Points to this instance of EFI_HASH2_PROTOCOL.
331  @param[in]  HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use.
332  @param[in]  Message       Points to the start of the message.
333  @param[in]  MessageSize   The size of Message, in bytes.
334  @param[in,out]  Hash      On input, points to a caller-allocated buffer of the size
335                              returned by GetHashSize() for the specified HashAlgorithm.
336                            On output, the buffer holds the resulting hash computed from the message.
337
338  @retval EFI_SUCCESS           Hash returned successfully.
339  @retval EFI_INVALID_PARAMETER This or Hash is NULL.
340  @retval EFI_UNSUPPORTED       The algorithm specified by HashAlgorithm is not supported by this driver
341                                or HashAlgorithm is Null.
342  @retval EFI_OUT_OF_RESOURCES  Some resource required by the function is not available
343                                or MessageSize is greater than platform maximum.
344
345**/
346EFI_STATUS
347EFIAPI
348BaseCrypto2Hash (
349  IN CONST EFI_HASH2_PROTOCOL      *This,
350  IN CONST EFI_GUID                *HashAlgorithm,
351  IN CONST UINT8                   *Message,
352  IN UINTN                         MessageSize,
353  IN OUT EFI_HASH2_OUTPUT          *Hash
354  )
355{
356  EFI_HASH_INFO            *HashInfo;
357  VOID                     *HashCtx;
358  UINTN                    CtxSize;
359  BOOLEAN                  Ret;
360  EFI_STATUS               Status;
361  HASH2_INSTANCE_DATA      *Instance;
362
363  Status = EFI_SUCCESS;
364
365  if ((This == NULL) || (Hash == NULL)) {
366    return EFI_INVALID_PARAMETER;
367  }
368
369  if (HashAlgorithm == NULL) {
370    return EFI_UNSUPPORTED;
371  }
372
373  HashInfo = GetHashInfo (HashAlgorithm);
374  if (HashInfo == NULL) {
375    return EFI_UNSUPPORTED;
376  }
377
378  Instance = HASH2_INSTANCE_DATA_FROM_THIS(This);
379  if (Instance->HashContext != NULL) {
380    FreePool (Instance->HashContext);
381  }
382  Instance->HashInfoContext = NULL;
383  Instance->HashContext = NULL;
384
385  //
386  // Start hash sequence
387  //
388  CtxSize = HashInfo->GetContextSize ();
389  if (CtxSize == 0) {
390    return EFI_UNSUPPORTED;
391  }
392  HashCtx = AllocatePool (CtxSize);
393  if (HashCtx == NULL) {
394    return EFI_OUT_OF_RESOURCES;
395  }
396
397  Ret = HashInfo->Init (HashCtx);
398  if (!Ret) {
399    Status = EFI_OUT_OF_RESOURCES;
400    goto Done;
401  }
402
403  //
404  // Setup the context
405  //
406  Instance->HashContext = HashCtx;
407  Instance->HashInfoContext = HashInfo;
408
409  Ret = HashInfo->Update (HashCtx, Message, MessageSize);
410  if (!Ret) {
411    Status = EFI_OUT_OF_RESOURCES;
412    goto Done;
413  }
414
415  Ret = HashInfo->Final (HashCtx, (UINT8 *)Hash->Sha1Hash);
416  if (!Ret) {
417    Status = EFI_OUT_OF_RESOURCES;
418    goto Done;
419  }
420Done:
421  //
422  // Cleanup the context
423  //
424  FreePool (HashCtx);
425  Instance->HashInfoContext = NULL;
426  Instance->HashContext = NULL;
427  return Status;
428}
429
430/**
431  This function must be called to initialize a digest calculation to be subsequently performed using the
432  EFI_HASH2_PROTOCOL functions HashUpdate() and HashFinal().
433
434  @param[in]  This          Points to this instance of EFI_HASH2_PROTOCOL.
435  @param[in]  HashAlgorithm Points to the EFI_GUID which identifies the algorithm to use.
436
437  @retval EFI_SUCCESS           Initialized successfully.
438  @retval EFI_INVALID_PARAMETER This is NULL.
439  @retval EFI_UNSUPPORTED       The algorithm specified by HashAlgorithm is not supported by this driver
440                                or HashAlgorithm is Null.
441  @retval EFI_OUT_OF_RESOURCES  Process failed due to lack of required resource.
442  @retval EFI_ALREADY_STARTED   This function is called when the operation in progress is still in processing Hash(),
443                                or HashInit() is already called before and not terminated by HashFinal() yet on the same instance.
444
445**/
446EFI_STATUS
447EFIAPI
448BaseCrypto2HashInit (
449  IN CONST EFI_HASH2_PROTOCOL      *This,
450  IN CONST EFI_GUID                *HashAlgorithm
451  )
452{
453  EFI_HASH_INFO            *HashInfo;
454  VOID                     *HashCtx;
455  UINTN                    CtxSize;
456  BOOLEAN                  Ret;
457  HASH2_INSTANCE_DATA      *Instance;
458
459  if (This == NULL) {
460    return EFI_INVALID_PARAMETER;
461  }
462
463  if (HashAlgorithm == NULL) {
464    return EFI_UNSUPPORTED;
465  }
466
467  HashInfo = GetHashInfo (HashAlgorithm);
468  if (HashInfo == NULL) {
469    return EFI_UNSUPPORTED;
470  }
471
472  //
473  // Consistency Check
474  //
475  Instance = HASH2_INSTANCE_DATA_FROM_THIS(This);
476  if ((Instance->HashContext != NULL) || (Instance->HashInfoContext != NULL)) {
477    return EFI_ALREADY_STARTED;
478  }
479
480  //
481  // Start hash sequence
482  //
483  CtxSize = HashInfo->GetContextSize ();
484  if (CtxSize == 0) {
485    return EFI_UNSUPPORTED;
486  }
487  HashCtx = AllocatePool (CtxSize);
488  if (HashCtx == NULL) {
489    return EFI_OUT_OF_RESOURCES;
490  }
491
492  Ret = HashInfo->Init (HashCtx);
493  if (!Ret) {
494    FreePool (HashCtx);
495    return EFI_OUT_OF_RESOURCES;
496  }
497
498  //
499  // Setup the context
500  //
501  Instance->HashContext = HashCtx;
502  Instance->HashInfoContext = HashInfo;
503  Instance->Updated = FALSE;
504
505  return EFI_SUCCESS;
506}
507
508/**
509  Updates the hash of a computation in progress by adding a message text.
510
511  @param[in]  This          Points to this instance of EFI_HASH2_PROTOCOL.
512  @param[in]  Message       Points to the start of the message.
513  @param[in]  MessageSize   The size of Message, in bytes.
514
515  @retval EFI_SUCCESS           Digest in progress updated successfully.
516  @retval EFI_INVALID_PARAMETER This or Hash is NULL.
517  @retval EFI_OUT_OF_RESOURCES  Some resource required by the function is not available
518                                or MessageSize is greater than platform maximum.
519  @retval EFI_NOT_READY         This call was not preceded by a valid call to HashInit(),
520                                or the operation in progress was terminated by a call to Hash() or HashFinal() on the same instance.
521
522**/
523EFI_STATUS
524EFIAPI
525BaseCrypto2HashUpdate (
526  IN CONST EFI_HASH2_PROTOCOL      *This,
527  IN CONST UINT8                   *Message,
528  IN UINTN                         MessageSize
529  )
530{
531  EFI_HASH_INFO            *HashInfo;
532  VOID                     *HashCtx;
533  BOOLEAN                  Ret;
534  HASH2_INSTANCE_DATA      *Instance;
535
536  if (This == NULL) {
537    return EFI_INVALID_PARAMETER;
538  }
539
540  //
541  // Consistency Check
542  //
543  Instance = HASH2_INSTANCE_DATA_FROM_THIS(This);
544  if ((Instance->HashContext == NULL) || (Instance->HashInfoContext == NULL)) {
545    return EFI_NOT_READY;
546  }
547  HashInfo = Instance->HashInfoContext;
548  HashCtx  = Instance->HashContext;
549
550  Ret = HashInfo->Update (HashCtx, Message, MessageSize);
551  if (!Ret) {
552    return EFI_OUT_OF_RESOURCES;
553  }
554
555  Instance->Updated = TRUE;
556
557  return EFI_SUCCESS;
558}
559
560/**
561  Finalizes a hash operation in progress and returns calculation result.
562  The output is final with any necessary padding added by the function.
563  The hash may not be further updated or extended after HashFinal().
564
565  @param[in]  This          Points to this instance of EFI_HASH2_PROTOCOL.
566  @param[in,out]  Hash      On input, points to a caller-allocated buffer of the size
567                              returned by GetHashSize() for the specified HashAlgorithm specified in preceding HashInit().
568                            On output, the buffer holds the resulting hash computed from the message.
569
570  @retval EFI_SUCCESS           Hash returned successfully.
571  @retval EFI_INVALID_PARAMETER This or Hash is NULL.
572  @retval EFI_NOT_READY         This call was not preceded by a valid call to HashInit() and at least one call to HashUpdate(),
573                                or the operation in progress was canceled by a call to Hash() on the same instance.
574
575**/
576EFI_STATUS
577EFIAPI
578BaseCrypto2HashFinal (
579  IN CONST EFI_HASH2_PROTOCOL      *This,
580  IN OUT EFI_HASH2_OUTPUT          *Hash
581  )
582{
583  EFI_HASH_INFO            *HashInfo;
584  VOID                     *HashCtx;
585  BOOLEAN                  Ret;
586  HASH2_INSTANCE_DATA      *Instance;
587
588  if ((This == NULL) || (Hash == NULL)) {
589    return EFI_INVALID_PARAMETER;
590  }
591
592  //
593  // Consistency Check
594  //
595  Instance = HASH2_INSTANCE_DATA_FROM_THIS(This);
596  if ((Instance->HashContext == NULL) || (Instance->HashInfoContext == NULL) ||
597      (!Instance->Updated)) {
598    return EFI_NOT_READY;
599  }
600  HashInfo = Instance->HashInfoContext;
601  HashCtx  = Instance->HashContext;
602
603  Ret = HashInfo->Final (HashCtx, (UINT8 *)Hash->Sha1Hash);
604
605  //
606  // Cleanup the context
607  //
608  FreePool (HashCtx);
609  Instance->HashInfoContext = NULL;
610  Instance->HashContext = NULL;
611  Instance->Updated = FALSE;
612
613  if (!Ret) {
614    return EFI_OUT_OF_RESOURCES;
615  }
616
617  return EFI_SUCCESS;
618}
619