]> git.proxmox.com Git - mirror_edk2.git/blame - SecurityPkg/Pkcs7Verify/Pkcs7VerifyDxe/Pkcs7VerifyDxe.c
SecurityPkg: Fix few typos
[mirror_edk2.git] / SecurityPkg / Pkcs7Verify / Pkcs7VerifyDxe / Pkcs7VerifyDxe.c
CommitLineData
2d093499
QL
1/** @file\r
2 Pkcs7Verify Driver to produce the UEFI PKCS7 Verification Protocol.\r
3\r
4 The driver will produce the UEFI PKCS7 Verification Protocol which is used to\r
5 verify data signed using PKCS7 structure. The PKCS7 data to be verified must\r
6 be ASN.1 (DER) encoded.\r
7\r
76b35710 8Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>\r
289b714b 9SPDX-License-Identifier: BSD-2-Clause-Patent\r
2d093499
QL
10\r
11**/\r
12\r
13#include <Library/BaseLib.h>\r
14#include <Library/BaseMemoryLib.h>\r
15#include <Library/MemoryAllocationLib.h>\r
16#include <Library/UefiBootServicesTableLib.h>\r
17#include <Library/BaseCryptLib.h>\r
18#include <Protocol/Pkcs7Verify.h>\r
19\r
20#define MAX_DIGEST_SIZE SHA512_DIGEST_SIZE\r
21\r
22/**\r
23 Calculates the hash of the given data based on the specified hash GUID.\r
24\r
25 @param[in] Data Pointer to the data buffer to be hashed.\r
26 @param[in] DataSize The size of data buffer in bytes.\r
27 @param[in] CertGuid The GUID to identify the hash algorithm to be used.\r
28 @param[out] HashValue Pointer to a buffer that receives the hash result.\r
29\r
30 @retval TRUE Data hash calculation succeeded.\r
31 @retval FALSE Data hash calculation failed.\r
32\r
33**/\r
34BOOLEAN\r
35CalculateDataHash (\r
36 IN VOID *Data,\r
37 IN UINTN DataSize,\r
38 IN EFI_GUID *CertGuid,\r
39 OUT UINT8 *HashValue\r
40 )\r
41{\r
42 BOOLEAN Status;\r
43 VOID *HashCtx;\r
44 UINTN CtxSize;\r
45\r
46 Status = FALSE;\r
47 HashCtx = NULL;\r
48\r
49 if (CompareGuid (CertGuid, &gEfiCertSha1Guid)) {\r
50 //\r
51 // SHA-1 Hash\r
52 //\r
53 CtxSize = Sha1GetContextSize ();\r
54 HashCtx = AllocatePool (CtxSize);\r
55 if (HashCtx == NULL) {\r
56 goto _Exit;\r
57 }\r
58 Status = Sha1Init (HashCtx);\r
59 Status = Sha1Update (HashCtx, Data, DataSize);\r
60 Status = Sha1Final (HashCtx, HashValue);\r
61\r
62 } else if (CompareGuid (CertGuid, &gEfiCertSha256Guid)) {\r
63 //\r
64 // SHA256 Hash\r
65 //\r
66 CtxSize = Sha256GetContextSize ();\r
67 HashCtx = AllocatePool (CtxSize);\r
68 if (HashCtx == NULL) {\r
69 goto _Exit;\r
70 }\r
71 Status = Sha256Init (HashCtx);\r
72 Status = Sha256Update (HashCtx, Data, DataSize);\r
73 Status = Sha256Final (HashCtx, HashValue);\r
74\r
75 } else if (CompareGuid (CertGuid, &gEfiCertSha384Guid)) {\r
76 //\r
77 // SHA384 Hash\r
78 //\r
79 CtxSize = Sha384GetContextSize ();\r
80 HashCtx = AllocatePool (CtxSize);\r
81 if (HashCtx == NULL) {\r
82 goto _Exit;\r
83 }\r
84 Status = Sha384Init (HashCtx);\r
85 Status = Sha384Update (HashCtx, Data, DataSize);\r
86 Status = Sha384Final (HashCtx, HashValue);\r
87\r
88 } else if (CompareGuid (CertGuid, &gEfiCertSha512Guid)) {\r
89 //\r
90 // SHA512 Hash\r
91 //\r
92 CtxSize = Sha512GetContextSize ();\r
93 HashCtx = AllocatePool (CtxSize);\r
94 if (HashCtx == NULL) {\r
95 goto _Exit;\r
96 }\r
97 Status = Sha512Init (HashCtx);\r
98 Status = Sha512Update (HashCtx, Data, DataSize);\r
99 Status = Sha512Final (HashCtx, HashValue);\r
100 }\r
101\r
102_Exit:\r
103 if (HashCtx != NULL) {\r
104 FreePool (HashCtx);\r
105 }\r
106\r
107 return Status;\r
108}\r
109\r
a2481f81
LQ
110/**\r
111 Check whether the hash of data content is revoked by the revocation database.\r
112\r
113 @param[in] Hash Pointer to the hash that is searched for.\r
114 @param[in] HashSize The size of the hash in bytes.\r
115 @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
116 structure which contains list of X.509 certificates\r
117 of revoked signers and revoked content hashes.\r
118\r
119 @return TRUE The matched content hash is found in the revocation database.\r
120 @return FALSE The matched content hash is not found in the revocation database.\r
121\r
122**/\r
123BOOLEAN\r
124IsContentHashRevokedByHash (\r
125 IN UINT8 *Hash,\r
126 IN UINTN HashSize,\r
127 IN EFI_SIGNATURE_LIST **RevokedDb\r
128 )\r
129{\r
130 EFI_SIGNATURE_LIST *SigList;\r
131 EFI_SIGNATURE_DATA *SigData;\r
132 UINTN Index;\r
133 UINTN EntryIndex;\r
134 UINTN EntryCount;\r
135 BOOLEAN Status;\r
136\r
137 if (RevokedDb == NULL) {\r
138 return FALSE;\r
139 }\r
140\r
141 Status = FALSE;\r
142 //\r
143 // Check if any hash matching content hash can be found in RevokedDB\r
144 //\r
145 for (Index = 0; ; Index++) {\r
146 SigList = (EFI_SIGNATURE_LIST *)(RevokedDb[Index]);\r
147\r
148 //\r
149 // The list is terminated by a NULL pointer.\r
150 //\r
151 if (SigList == NULL) {\r
152 break;\r
153 }\r
154\r
155 //\r
156 // Search the signature database to search the revoked content hash\r
157 //\r
158 SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +\r
159 SigList->SignatureHeaderSize);\r
160 EntryCount = (SigList->SignatureListSize - SigList->SignatureHeaderSize -\r
161 sizeof (EFI_SIGNATURE_LIST)) / SigList->SignatureSize;\r
162 for (EntryIndex = 0; EntryIndex < EntryCount; EntryIndex++) {\r
163 //\r
164 // The problem case. There's a revocation hash but the sizes\r
165 // don't match, meaning it's a different hash algorithm and we\r
166 // can't tell if it's revoking our binary or not. Assume not.\r
167 //\r
168 if (SigList->SignatureSize - sizeof(EFI_GUID) == HashSize) {\r
169 //\r
170 // Compare Data Hash with Signature Data\r
171 //\r
172 if (CompareMem (SigData->SignatureData, Hash, HashSize) == 0) {\r
173 Status = TRUE;\r
174 goto _Exit;\r
175 }\r
176 }\r
177\r
178 SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigData + SigList->SignatureSize);\r
179 }\r
180 }\r
181\r
182_Exit:\r
183 return Status;\r
184}\r
185\r
2d093499
QL
186/**\r
187 Check whether the hash of data content is revoked by the revocation database.\r
188\r
189 @param[in] Content Pointer to the content buffer that is searched for.\r
190 @param[in] ContentSize The size of data content in bytes.\r
191 @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
192 structure which contains list of X.509 certificates\r
193 of revoked signers and revoked content hashes.\r
194\r
195 @return TRUE The matched content hash is found in the revocation database.\r
196 @return FALSE The matched content hash is not found in the revocation database.\r
197\r
198**/\r
199BOOLEAN\r
200IsContentHashRevoked (\r
201 IN UINT8 *Content,\r
202 IN UINTN ContentSize,\r
203 IN EFI_SIGNATURE_LIST **RevokedDb\r
204 )\r
205{\r
206 EFI_SIGNATURE_LIST *SigList;\r
207 EFI_SIGNATURE_DATA *SigData;\r
208 UINTN Index;\r
209 UINT8 HashVal[MAX_DIGEST_SIZE];\r
210 UINTN EntryIndex;\r
211 UINTN EntryCount;\r
212 BOOLEAN Status;\r
213\r
214 if (RevokedDb == NULL) {\r
215 return FALSE;\r
216 }\r
217\r
218 Status = FALSE;\r
219 //\r
220 // Check if any hash matching content hash can be found in RevokedDB\r
221 //\r
222 for (Index = 0; ; Index++) {\r
223 SigList = (EFI_SIGNATURE_LIST *)(RevokedDb[Index]);\r
224\r
225 //\r
226 // The list is terminated by a NULL pointer.\r
227 //\r
228 if (SigList == NULL) {\r
229 break;\r
230 }\r
231\r
232 //\r
233 // Calculate the digest of supplied data based on the signature hash type.\r
234 //\r
235 if (!CalculateDataHash (Content, ContentSize, &SigList->SignatureType, HashVal)) {\r
236 //\r
237 // Un-matched Hash GUID or other failure.\r
238 //\r
239 continue;\r
240 }\r
241\r
242 //\r
243 // Search the signature database to search the revoked content hash\r
244 //\r
245 SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +\r
246 SigList->SignatureHeaderSize);\r
247 EntryCount = (SigList->SignatureListSize - SigList->SignatureHeaderSize -\r
248 sizeof (EFI_SIGNATURE_LIST)) / SigList->SignatureSize;\r
249 for (EntryIndex = 0; EntryIndex < EntryCount; EntryIndex++) {\r
250 //\r
251 // Compare Data Hash with Signature Data\r
252 //\r
253 if (CompareMem (SigData->SignatureData, HashVal, (SigList->SignatureSize - sizeof (EFI_GUID))) == 0) {\r
254 Status = TRUE;\r
255 goto _Exit;\r
256 }\r
257\r
258 SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigData + SigList->SignatureSize);\r
259 }\r
260 }\r
261\r
262_Exit:\r
263 return Status;\r
264}\r
265\r
266/**\r
267 Check whether the hash of an given certificate is revoked by the revocation database.\r
268\r
269 @param[in] Certificate Pointer to the certificate that is searched for.\r
270 @param[in] CertSize Size of certificate in bytes.\r
271 @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
272 structures which contains list of X.509 certificate\r
273 of revoked signers and revoked content hashes.\r
274 @param[out] RevocationTime Return the time that the certificate was revoked.\r
275\r
276 @return TRUE The certificate hash is found in the revocation database.\r
277 @return FALSE The certificate hash is not found in the revocation database.\r
278\r
279**/\r
280BOOLEAN\r
281IsCertHashRevoked (\r
282 IN UINT8 *Certificate,\r
283 IN UINTN CertSize,\r
284 IN EFI_SIGNATURE_LIST **RevokedDb,\r
285 OUT EFI_TIME *RevocationTime\r
286 )\r
287{\r
288 BOOLEAN Status;\r
289 EFI_SIGNATURE_LIST *SigList;\r
290 EFI_SIGNATURE_DATA *SigData;\r
291 UINT8 *TBSCert;\r
292 UINTN TBSCertSize;\r
293 UINTN Index;\r
294 UINTN EntryIndex;\r
295 UINTN EntryCount;\r
296 UINT8 CertHashVal[MAX_DIGEST_SIZE];\r
297\r
298 if ((RevocationTime == NULL) || (RevokedDb == NULL)) {\r
299 return FALSE;\r
300 }\r
301\r
302 //\r
303 // Retrieve the TBSCertificate from the X.509 Certificate for hash calculation\r
304 //\r
305 if (!X509GetTBSCert (Certificate, CertSize, &TBSCert, &TBSCertSize)) {\r
306 return FALSE;\r
307 }\r
308\r
309 Status = FALSE;\r
310 for (Index = 0; ; Index++) {\r
311\r
312 SigList = (EFI_SIGNATURE_LIST *)(RevokedDb[Index]);\r
313 //\r
314 // The list is terminated by a NULL pointer.\r
315 //\r
316 if (SigList == NULL) {\r
317 break;\r
318 }\r
319\r
320 //\r
321 // Determine Hash Algorithm based on the entry type in revocation database, and\r
322 // calculate the certificate hash.\r
323 //\r
324 if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Sha256Guid)) {\r
325 Status = CalculateDataHash (TBSCert, TBSCertSize, &gEfiCertSha256Guid, CertHashVal);\r
326\r
327 } else if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Sha384Guid)) {\r
328 Status = CalculateDataHash (TBSCert, TBSCertSize, &gEfiCertSha384Guid, CertHashVal);\r
329\r
330 } else if (CompareGuid (&SigList->SignatureType, &gEfiCertX509Sha512Guid)) {\r
331 Status = CalculateDataHash (TBSCert, TBSCertSize, &gEfiCertSha512Guid, CertHashVal);\r
332\r
333 } else {\r
334 //\r
335 // Un-matched Cert Hash GUID\r
336 //\r
337 continue;\r
338 }\r
339\r
340 if (!Status) {\r
341 continue;\r
342 }\r
343\r
344 SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +\r
345 SigList->SignatureHeaderSize);\r
346 EntryCount = (SigList->SignatureListSize - SigList->SignatureHeaderSize -\r
347 sizeof (EFI_SIGNATURE_LIST)) / SigList->SignatureSize;\r
348 for (EntryIndex = 0; EntryIndex < EntryCount; Index++) {\r
349 //\r
350 // Check if the Certificate Hash is revoked.\r
351 //\r
352 if (CompareMem (SigData->SignatureData, CertHashVal,\r
353 SigList->SignatureSize - sizeof (EFI_GUID) - sizeof (EFI_TIME)) == 0) {\r
354 Status = TRUE;\r
355 //\r
356 // Return the revocation time of this revoked certificate.\r
357 //\r
358 CopyMem (\r
359 RevocationTime,\r
360 (EFI_TIME *)((UINT8 *)SigData + SigList->SignatureSize - sizeof (EFI_TIME)),\r
361 sizeof (EFI_TIME)\r
362 );\r
363 goto _Exit;\r
364 }\r
365\r
366 SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigData + SigList->SignatureSize);\r
367 }\r
368 }\r
369\r
370_Exit:\r
371 return Status;\r
372}\r
373\r
374/**\r
375 Check if the given time value is zero.\r
376\r
377 @param[in] Time Pointer of a time value.\r
378\r
379 @retval TRUE The Time is Zero.\r
380 @retval FALSE The Time is not Zero.\r
381\r
382**/\r
383BOOLEAN\r
384IsTimeZero (\r
385 IN EFI_TIME *Time\r
386 )\r
387{\r
388 if ((Time->Year == 0) && (Time->Month == 0) && (Time->Day == 0) &&\r
389 (Time->Hour == 0) && (Time->Minute == 0) && (Time->Second == 0)) {\r
390 return TRUE;\r
391 }\r
392\r
393 return FALSE;\r
394}\r
395\r
396/**\r
397 Check whether the timestamp is valid by comparing the signing time and the revocation time.\r
398\r
399 @param SigningTime Pointer to the signing time.\r
400 @param RevocationTime Pointer to the revocation time.\r
401\r
402 @retval TRUE The SigningTime is not later than the RevocationTime.\r
403 @retval FALSE The SigningTime is later than the RevocationTime.\r
404\r
405**/\r
406BOOLEAN\r
407CompareTimestamp (\r
408 IN EFI_TIME *SigningTime,\r
409 IN EFI_TIME *RevocationTime\r
410 )\r
411{\r
412 if (SigningTime->Year != RevocationTime->Year) {\r
413 return (BOOLEAN) (SigningTime->Year < RevocationTime->Year);\r
414 } else if (SigningTime->Month != RevocationTime->Month) {\r
415 return (BOOLEAN) (SigningTime->Month < RevocationTime->Month);\r
416 } else if (SigningTime->Day != RevocationTime->Day) {\r
417 return (BOOLEAN) (SigningTime->Day < RevocationTime->Day);\r
418 } else if (SigningTime->Hour != RevocationTime->Hour) {\r
419 return (BOOLEAN) (SigningTime->Hour < RevocationTime->Hour);\r
420 } else if (SigningTime->Minute != RevocationTime->Minute) {\r
421 return (BOOLEAN) (SigningTime->Minute < RevocationTime->Minute);\r
422 }\r
423\r
424 return (BOOLEAN) (SigningTime->Second <= RevocationTime->Second);\r
425}\r
426\r
427/**\r
428 Check whether the timestamp signature embedded in PKCS7 signedData is valid and\r
429 the signing time is also earlier than the revocation time.\r
430\r
431 @param[in] SignedData Pointer to the PKCS#7 signedData.\r
432 @param[in] SignedDataSize Size of SignedData in bytes.\r
433 @param[in] TimeStampDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
434 structures which is used to pass a list of X.509\r
435 certificates of trusted timestamp signers.\r
436 @param[in] RevocationTime The time that the certificate was revoked.\r
437\r
438 @retval TRUE Timestamp signature is valid and the signing time is no later\r
439 than the revocation time.\r
440 @retval FALSE Timestamp signature is not valid or the signing time is later\r
441 than the revocation time.\r
442\r
443**/\r
444BOOLEAN\r
445IsValidTimestamp (\r
446 IN UINT8 *SignedData,\r
447 IN UINTN SignedDataSize,\r
448 IN EFI_SIGNATURE_LIST **TimeStampDb,\r
449 IN EFI_TIME *RevocationTime\r
450 )\r
451{\r
452 BOOLEAN Status;\r
453 EFI_SIGNATURE_LIST *SigList;\r
454 EFI_SIGNATURE_DATA *SigData;\r
455 UINT8 *TsaCert;\r
456 UINTN TsaCertSize;\r
457 UINTN Index;\r
458 EFI_TIME SigningTime;\r
459\r
460 //\r
461 // If no supplied database for verification or RevocationTime is zero,\r
462 // the certificate shall be considered to always be revoked.\r
463 //\r
464 if ((TimeStampDb == NULL) || (IsTimeZero (RevocationTime))) {\r
465 return FALSE;\r
466 }\r
467\r
468 Status = FALSE;\r
469 //\r
470 // RevocationTime is non-zero, the certificate should be considered to be revoked\r
471 // from that time and onwards.\r
472 //\r
473 for (Index = 0; ; Index++) {\r
474 SigList = (EFI_SIGNATURE_LIST *) (TimeStampDb[Index]);\r
475\r
476 //\r
477 // The list is terminated by a NULL pointer.\r
478 //\r
479 if (SigList == NULL) {\r
480 break;\r
481 }\r
482\r
483 //\r
484 // Ignore any non-X509-format entry in the list\r
485 //\r
486 if (!CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {\r
487 continue;\r
488 }\r
489\r
490\r
491 SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +\r
492 SigList->SignatureHeaderSize);\r
493 TsaCert = SigData->SignatureData;\r
494 TsaCertSize = SigList->SignatureSize - sizeof (EFI_GUID);\r
495\r
496 //\r
d6b926e7 497 // Each TSA Certificate will normally be in a separate EFI_SIGNATURE_LIST\r
2d093499
QL
498 // Leverage ImageTimestampVerify interface for Timestamp counterSignature Verification\r
499 //\r
500 if (ImageTimestampVerify (SignedData, SignedDataSize, TsaCert, TsaCertSize, &SigningTime)) {\r
501 //\r
502 // The signer signature is valid only when the signing time is earlier than revocation time.\r
503 //\r
504 if (CompareTimestamp (&SigningTime, RevocationTime)) {\r
505 Status = TRUE;\r
506 break;\r
507 }\r
508 }\r
509 }\r
510\r
511 return Status;\r
512}\r
513\r
a2481f81
LQ
514/**\r
515 Check whether the PKCS7 signedData is revoked by verifying with the revoked\r
516 certificates database, and if the signedData is timestamped, the embedded timestamp\r
d6b926e7 517 counterSignature will be checked with the supplied timestamp database.\r
a2481f81
LQ
518\r
519 @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7\r
520 signature.\r
521 @param[in] SignedDataSize The size of SignedData buffer in bytes.\r
fc70522f 522 @param[in] InHash Pointer to the buffer containing the hash of the message data\r
a2481f81
LQ
523 previously signed and to be verified.\r
524 @param[in] InHashSize The size of InHash buffer in bytes.\r
525 @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
526 structure which contains list of X.509 certificates\r
527 of revoked signers and revoked content hashes.\r
528 @param[in] TimeStampDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
529 structures which is used to pass a list of X.509\r
530 certificates of trusted timestamp signers.\r
531\r
532 @retval EFI_SUCCESS The PKCS7 signedData is revoked.\r
533 @retval EFI_SECURITY_VIOLATION Fail to verify the signature in PKCS7 signedData.\r
534 @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.\r
535 AllowedDb is NULL.\r
536 Content is not NULL and ContentSize is NULL.\r
537 @retval EFI_NOT_FOUND Content not found because InData is NULL and no\r
538 content embedded in PKCS7 signedData.\r
539 @retval EFI_UNSUPPORTED The PKCS7 signedData was not correctly formatted.\r
540\r
541**/\r
542EFI_STATUS\r
543P7CheckRevocationByHash (\r
544 IN UINT8 *SignedData,\r
545 IN UINTN SignedDataSize,\r
546 IN UINT8 *InHash,\r
547 IN UINTN InHashSize,\r
548 IN EFI_SIGNATURE_LIST **RevokedDb,\r
549 IN EFI_SIGNATURE_LIST **TimeStampDb\r
550 )\r
551{\r
552 EFI_STATUS Status;\r
553 EFI_SIGNATURE_LIST *SigList;\r
554 EFI_SIGNATURE_DATA *SigData;\r
555 UINT8 *RevokedCert;\r
556 UINTN RevokedCertSize;\r
557 UINTN Index;\r
558 UINT8 *CertBuffer;\r
559 UINTN BufferLength;\r
560 UINT8 *TrustedCert;\r
561 UINTN TrustedCertLength;\r
562 UINT8 CertNumber;\r
563 UINT8 *CertPtr;\r
564 UINT8 *Cert;\r
565 UINTN CertSize;\r
566 EFI_TIME RevocationTime;\r
567\r
568 Status = EFI_SECURITY_VIOLATION;\r
569 SigData = NULL;\r
570 RevokedCert = NULL;\r
571 RevokedCertSize = 0;\r
572 CertBuffer = NULL;\r
573 TrustedCert = NULL;\r
574\r
575 //\r
576 // The signedData is revoked if the hash of content existed in RevokedDb\r
577 //\r
578 if (IsContentHashRevokedByHash (InHash, InHashSize, RevokedDb)) {\r
579 Status = EFI_SUCCESS;\r
580 goto _Exit;\r
581 }\r
582\r
583 //\r
584 // Check if the signer's certificate can be found in Revoked database\r
585 //\r
586 for (Index = 0; ; Index++) {\r
587 SigList = (EFI_SIGNATURE_LIST *)(RevokedDb[Index]);\r
588\r
589 //\r
590 // The list is terminated by a NULL pointer.\r
591 //\r
592 if (SigList == NULL) {\r
593 break;\r
594 }\r
595\r
596 //\r
597 // Ignore any non-X509-format entry in the list.\r
598 //\r
599 if (!CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {\r
600 continue;\r
601 }\r
602\r
603 SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +\r
604 SigList->SignatureHeaderSize);\r
605\r
606 RevokedCert = SigData->SignatureData;\r
607 RevokedCertSize = SigList->SignatureSize - sizeof (EFI_GUID);\r
608\r
609 //\r
610 // Verifying the PKCS#7 SignedData with the revoked certificate in RevokedDb\r
611 //\r
612 if (AuthenticodeVerify (SignedData, SignedDataSize, RevokedCert, RevokedCertSize, InHash, InHashSize)) {\r
613 //\r
614 // The signedData was verified by one entry in Revoked Database\r
615 //\r
616 Status = EFI_SUCCESS;\r
617 break;\r
618 }\r
619 }\r
620\r
621 if (!EFI_ERROR (Status)) {\r
622 //\r
623 // The signedData was revoked, since it was hit by RevokedDb\r
624 //\r
625 goto _Exit;\r
626 }\r
627\r
628 //\r
629 // Now we will continue to check the X.509 Certificate Hash & Possible Timestamp\r
630 //\r
631 if ((TimeStampDb == NULL) || (*TimeStampDb == NULL)) {\r
632 goto _Exit;\r
633 }\r
634\r
635 Pkcs7GetSigners (SignedData, SignedDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength);\r
636 if ((BufferLength == 0) || (CertBuffer == NULL)) {\r
637 Status = EFI_SUCCESS;\r
638 goto _Exit;\r
639 }\r
640\r
641 //\r
642 // Check if any hash of certificates embedded in P7 data is in the revoked database.\r
643 //\r
644 CertNumber = (UINT8) (*CertBuffer);\r
645 CertPtr = CertBuffer + 1;\r
646 for (Index = 0; Index < CertNumber; Index++) {\r
647 //\r
648 // Retrieve the Certificate data\r
649 //\r
650 CertSize = (UINTN) ReadUnaligned32 ((UINT32 *) CertPtr);\r
651 Cert = (UINT8 *)CertPtr + sizeof (UINT32);\r
652\r
653 if (IsCertHashRevoked (Cert, CertSize, RevokedDb, &RevocationTime)) {\r
654 //\r
655 // Check the timestamp signature and signing time to determine if p7 data can be trusted.\r
656 //\r
657 Status = EFI_SUCCESS;\r
658 if (IsValidTimestamp (SignedData, SignedDataSize, TimeStampDb, &RevocationTime)) {\r
659 //\r
d6b926e7
SB
660 // Use EFI_NOT_READY to identify the P7Data is not revoked, because the timestamping\r
661 // occurred prior to the time of certificate revocation.\r
a2481f81
LQ
662 //\r
663 Status = EFI_NOT_READY;\r
664 }\r
665\r
666 goto _Exit;\r
667 }\r
668\r
669 CertPtr = CertPtr + sizeof (UINT32) + CertSize;\r
670 }\r
671\r
672_Exit:\r
673 Pkcs7FreeSigners (CertBuffer);\r
674 Pkcs7FreeSigners (TrustedCert);\r
675\r
676 return Status;\r
677}\r
678\r
2d093499
QL
679/**\r
680 Check whether the PKCS7 signedData is revoked by verifying with the revoked\r
681 certificates database, and if the signedData is timestamped, the embedded timestamp\r
d6b926e7 682 counterSignature will be checked with the supplied timestamp database.\r
2d093499
QL
683\r
684 @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7\r
685 signature.\r
686 @param[in] SignedDataSize The size of SignedData buffer in bytes.\r
687 @param[in] InData Pointer to the buffer containing the raw message data\r
688 previously signed and to be verified.\r
689 @param[in] InDataSize The size of InData buffer in bytes.\r
690 @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
691 structure which contains list of X.509 certificates\r
692 of revoked signers and revoked content hashes.\r
693 @param[in] TimeStampDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
694 structures which is used to pass a list of X.509\r
695 certificates of trusted timestamp signers.\r
696\r
697 @retval EFI_SUCCESS The PKCS7 signedData is revoked.\r
698 @retval EFI_SECURITY_VIOLATION Fail to verify the signature in PKCS7 signedData.\r
699 @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.\r
700 AllowedDb is NULL.\r
701 Content is not NULL and ContentSize is NULL.\r
702 @retval EFI_NOT_FOUND Content not found because InData is NULL and no\r
703 content embedded in PKCS7 signedData.\r
704 @retval EFI_UNSUPPORTED The PKCS7 signedData was not correctly formatted.\r
705\r
706**/\r
707EFI_STATUS\r
708P7CheckRevocation (\r
709 IN UINT8 *SignedData,\r
710 IN UINTN SignedDataSize,\r
711 IN UINT8 *InData,\r
712 IN UINTN InDataSize,\r
713 IN EFI_SIGNATURE_LIST **RevokedDb,\r
714 IN EFI_SIGNATURE_LIST **TimeStampDb\r
715 )\r
716{\r
717 EFI_STATUS Status;\r
718 EFI_SIGNATURE_LIST *SigList;\r
719 EFI_SIGNATURE_DATA *SigData;\r
720 UINT8 *RevokedCert;\r
721 UINTN RevokedCertSize;\r
722 UINTN Index;\r
723 UINT8 *CertBuffer;\r
724 UINTN BufferLength;\r
725 UINT8 *TrustedCert;\r
726 UINTN TrustedCertLength;\r
727 UINT8 CertNumber;\r
728 UINT8 *CertPtr;\r
729 UINT8 *Cert;\r
730 UINTN CertSize;\r
731 EFI_TIME RevocationTime;\r
732\r
733 Status = EFI_UNSUPPORTED;\r
734 SigData = NULL;\r
735 RevokedCert = NULL;\r
736 RevokedCertSize = 0;\r
737 CertBuffer = NULL;\r
738 TrustedCert = NULL;\r
739\r
740 //\r
741 // The signedData is revoked if the hash of content existed in RevokedDb\r
742 //\r
743 if (IsContentHashRevoked (InData, InDataSize, RevokedDb)) {\r
744 Status = EFI_SUCCESS;\r
745 goto _Exit;\r
746 }\r
747\r
748 //\r
749 // Check if the signer's certificate can be found in Revoked database\r
750 //\r
751 for (Index = 0; ; Index++) {\r
752 SigList = (EFI_SIGNATURE_LIST *)(RevokedDb[Index]);\r
753\r
754 //\r
755 // The list is terminated by a NULL pointer.\r
756 //\r
757 if (SigList == NULL) {\r
758 break;\r
759 }\r
760\r
761 //\r
762 // Ignore any non-X509-format entry in the list.\r
763 //\r
764 if (!CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {\r
765 continue;\r
766 }\r
767\r
768 SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +\r
769 SigList->SignatureHeaderSize);\r
770\r
771 RevokedCert = SigData->SignatureData;\r
772 RevokedCertSize = SigList->SignatureSize - sizeof (EFI_GUID);\r
773\r
774 //\r
775 // Verifying the PKCS#7 SignedData with the revoked certificate in RevokedDb\r
776 //\r
777 if (Pkcs7Verify (SignedData, SignedDataSize, RevokedCert, RevokedCertSize, InData, InDataSize)) {\r
778 //\r
779 // The signedData was verified by one entry in Revoked Database\r
780 //\r
781 Status = EFI_SUCCESS;\r
782 break;\r
783 }\r
784 }\r
785\r
786 if (!EFI_ERROR (Status)) {\r
787 //\r
788 // The signedData was revoked, since it was hit by RevokedDb\r
789 //\r
790 goto _Exit;\r
791 }\r
792\r
793 //\r
794 // Now we will continue to check the X.509 Certificate Hash & Possible Timestamp\r
795 //\r
796 if ((TimeStampDb == NULL) || (*TimeStampDb == NULL)) {\r
797 goto _Exit;\r
798 }\r
799\r
800 Pkcs7GetSigners (SignedData, SignedDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength);\r
801 if ((BufferLength == 0) || (CertBuffer == NULL)) {\r
802 Status = EFI_SUCCESS;\r
803 goto _Exit;\r
804 }\r
805\r
806 //\r
807 // Check if any hash of certificates embedded in P7 data is in the revoked database.\r
808 //\r
809 CertNumber = (UINT8) (*CertBuffer);\r
810 CertPtr = CertBuffer + 1;\r
811 for (Index = 0; Index < CertNumber; Index++) {\r
812 //\r
813 // Retrieve the Certificate data\r
814 //\r
815 CertSize = (UINTN) ReadUnaligned32 ((UINT32 *) CertPtr);\r
816 Cert = (UINT8 *)CertPtr + sizeof (UINT32);\r
817\r
818 if (IsCertHashRevoked (Cert, CertSize, RevokedDb, &RevocationTime)) {\r
819 //\r
820 // Check the timestamp signature and signing time to determine if p7 data can be trusted.\r
821 //\r
822 Status = EFI_SUCCESS;\r
823 if (IsValidTimestamp (SignedData, SignedDataSize, TimeStampDb, &RevocationTime)) {\r
824 //\r
d6b926e7
SB
825 // Use EFI_NOT_READY to identify the P7Data is not revoked, because the timestamping\r
826 // occurred prior to the time of certificate revocation.\r
2d093499
QL
827 //\r
828 Status = EFI_NOT_READY;\r
829 }\r
830\r
831 goto _Exit;\r
832 }\r
833\r
834 CertPtr = CertPtr + sizeof (UINT32) + CertSize;\r
835 }\r
836\r
837_Exit:\r
838 Pkcs7FreeSigners (CertBuffer);\r
839 Pkcs7FreeSigners (TrustedCert);\r
840\r
841 return Status;\r
842}\r
843\r
a2481f81
LQ
844/**\r
845 Check whether the PKCS7 signedData can be verified by the trusted certificates\r
846 database, and return the content of the signedData if requested.\r
847\r
848 @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7\r
849 signature.\r
850 @param[in] SignedDataSize The size of SignedData buffer in bytes.\r
851 @param[in] InHash Pointer to the buffer containing the hash of the message data\r
852 previously signed and to be verified.\r
853 @param[in] InHashSize The size of InHash buffer in bytes.\r
854 @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
855 structures which contains lists of X.509 certificates\r
856 of approved signers.\r
857\r
858 @retval EFI_SUCCESS The PKCS7 signedData is trusted.\r
859 @retval EFI_SECURITY_VIOLATION Fail to verify the signature in PKCS7 signedData.\r
860 @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.\r
861 AllowedDb is NULL.\r
862 Content is not NULL and ContentSize is NULL.\r
863 @retval EFI_NOT_FOUND Content not found because InData is NULL and no\r
864 content embedded in PKCS7 signedData.\r
865 @retval EFI_UNSUPPORTED The PKCS7 signedData was not correctly formatted.\r
866 @retval EFI_BUFFER_TOO_SMALL The size of buffer indicated by ContentSize is too\r
867 small to hold the content. ContentSize updated to\r
868 the required size.\r
869\r
870**/\r
871EFI_STATUS\r
872P7CheckTrustByHash (\r
873 IN UINT8 *SignedData,\r
874 IN UINTN SignedDataSize,\r
875 IN UINT8 *InHash,\r
876 IN UINTN InHashSize,\r
877 IN EFI_SIGNATURE_LIST **AllowedDb\r
878 )\r
879{\r
880 EFI_STATUS Status;\r
881 EFI_SIGNATURE_LIST *SigList;\r
882 EFI_SIGNATURE_DATA *SigData;\r
883 UINT8 *TrustCert;\r
884 UINTN TrustCertSize;\r
885 UINTN Index;\r
886\r
887 Status = EFI_SECURITY_VIOLATION;\r
888 SigData = NULL;\r
889 TrustCert = NULL;\r
890 TrustCertSize = 0;\r
891\r
892 if (AllowedDb == NULL) {\r
893 return EFI_INVALID_PARAMETER;\r
894 }\r
895\r
896 //\r
897 // Build Certificate Stack with all valid X509 certificates in the supplied\r
898 // Signature List for PKCS7 Verification.\r
899 //\r
900 for (Index = 0; ; Index++) {\r
901 SigList = (EFI_SIGNATURE_LIST *)(AllowedDb[Index]);\r
902\r
903 //\r
904 // The list is terminated by a NULL pointer.\r
905 //\r
906 if (SigList == NULL) {\r
907 break;\r
908 }\r
909\r
910 //\r
911 // Ignore any non-X509-format entry in the list.\r
912 //\r
913 if (!CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {\r
914 continue;\r
915 }\r
916\r
917 SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +\r
918 SigList->SignatureHeaderSize);\r
919\r
920 TrustCert = SigData->SignatureData;\r
921 TrustCertSize = SigList->SignatureSize - sizeof (EFI_GUID);\r
922\r
923 //\r
924 // Verifying the PKCS#7 SignedData with the trusted certificate from AllowedDb\r
925 //\r
926 if (AuthenticodeVerify (SignedData, SignedDataSize, TrustCert, TrustCertSize, InHash, InHashSize)) {\r
927 //\r
928 // The SignedData was verified successfully by one entry in Trusted Database\r
929 //\r
930 Status = EFI_SUCCESS;\r
931 break;\r
932 }\r
933 }\r
934\r
935 return Status;\r
936}\r
937\r
2d093499
QL
938/**\r
939 Check whether the PKCS7 signedData can be verified by the trusted certificates\r
940 database, and return the content of the signedData if requested.\r
941\r
942 @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7\r
943 signature.\r
944 @param[in] SignedDataSize The size of SignedData buffer in bytes.\r
945 @param[in] InData Pointer to the buffer containing the raw message data\r
946 previously signed and to be verified.\r
947 @param[in] InDataSize The size of InData buffer in bytes.\r
948 @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
949 structures which contains lists of X.509 certificates\r
950 of approved signers.\r
2d093499
QL
951\r
952 @retval EFI_SUCCESS The PKCS7 signedData is trusted.\r
953 @retval EFI_SECURITY_VIOLATION Fail to verify the signature in PKCS7 signedData.\r
954 @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.\r
955 AllowedDb is NULL.\r
956 Content is not NULL and ContentSize is NULL.\r
957 @retval EFI_NOT_FOUND Content not found because InData is NULL and no\r
958 content embedded in PKCS7 signedData.\r
959 @retval EFI_UNSUPPORTED The PKCS7 signedData was not correctly formatted.\r
960 @retval EFI_BUFFER_TOO_SMALL The size of buffer indicated by ContentSize is too\r
961 small to hold the content. ContentSize updated to\r
962 the required size.\r
963\r
964**/\r
965EFI_STATUS\r
966P7CheckTrust (\r
967 IN UINT8 *SignedData,\r
968 IN UINTN SignedDataSize,\r
969 IN UINT8 *InData,\r
970 IN UINTN InDataSize,\r
971 IN EFI_SIGNATURE_LIST **AllowedDb\r
972 )\r
973{\r
974 EFI_STATUS Status;\r
975 EFI_SIGNATURE_LIST *SigList;\r
976 EFI_SIGNATURE_DATA *SigData;\r
977 UINT8 *TrustCert;\r
978 UINTN TrustCertSize;\r
979 UINTN Index;\r
980\r
981 Status = EFI_SECURITY_VIOLATION;\r
982 SigData = NULL;\r
983 TrustCert = NULL;\r
984 TrustCertSize = 0;\r
985\r
986 if (AllowedDb == NULL) {\r
987 return EFI_INVALID_PARAMETER;\r
988 }\r
989\r
990 //\r
991 // Build Certificate Stack with all valid X509 certificates in the supplied\r
992 // Signature List for PKCS7 Verification.\r
993 //\r
994 for (Index = 0; ; Index++) {\r
995 SigList = (EFI_SIGNATURE_LIST *)(AllowedDb[Index]);\r
996\r
997 //\r
998 // The list is terminated by a NULL pointer.\r
999 //\r
1000 if (SigList == NULL) {\r
1001 break;\r
1002 }\r
1003\r
1004 //\r
1005 // Ignore any non-X509-format entry in the list.\r
1006 //\r
1007 if (!CompareGuid (&SigList->SignatureType, &gEfiCertX509Guid)) {\r
1008 continue;\r
1009 }\r
1010\r
1011 SigData = (EFI_SIGNATURE_DATA *) ((UINT8 *) SigList + sizeof (EFI_SIGNATURE_LIST) +\r
1012 SigList->SignatureHeaderSize);\r
1013\r
1014 TrustCert = SigData->SignatureData;\r
1015 TrustCertSize = SigList->SignatureSize - sizeof (EFI_GUID);\r
1016\r
1017 //\r
1018 // Verifying the PKCS#7 SignedData with the trusted certificate from AllowedDb\r
1019 //\r
1020 if (Pkcs7Verify (SignedData, SignedDataSize, TrustCert, TrustCertSize, InData, InDataSize)) {\r
1021 //\r
1022 // The SignedData was verified successfully by one entry in Trusted Database\r
1023 //\r
1024 Status = EFI_SUCCESS;\r
1025 break;\r
1026 }\r
1027 }\r
1028\r
1029 return Status;\r
1030}\r
1031\r
1032/**\r
1033 Processes a buffer containing binary DER-encoded PKCS7 signature.\r
1034 The signed data content may be embedded within the buffer or separated. Function\r
1035 verifies the signature of the content is valid and signing certificate was not\r
1036 revoked and is contained within a list of trusted signers.\r
1037\r
1038 @param[in] This Pointer to EFI_PKCS7_VERIFY_PROTOCOL instance.\r
1039 @param[in] SignedData Points to buffer containing ASN.1 DER-encoded PKCS7\r
1040 signature.\r
1041 @param[in] SignedDataSize The size of SignedData buffer in bytes.\r
1042 @param[in] InData In case of detached signature, InData points to\r
1043 buffer containing the raw message data previously\r
1044 signed and to be verified by function. In case of\r
1045 SignedData containing embedded data, InData must be\r
1046 NULL.\r
1047 @param[in] InDataSize When InData is used, the size of InData buffer in\r
1048 bytes. When InData is NULL. This parameter must be\r
1049 0.\r
1050 @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
1051 structures. The list is terminated by a null\r
1052 pointer. The EFI_SIGNATURE_LIST structures contain\r
1053 lists of X.509 certificates of approved signers.\r
1054 Function recognizes signer certificates of type\r
1055 EFI_CERT_X509_GUID. Any hash certificate in AllowedDb\r
1056 list is ignored by this function. Function returns\r
1057 success if signer of the buffer is within this list\r
1058 (and not within RevokedDb). This parameter is\r
1059 required.\r
1060 @param[in] RevokedDb Optional pointer to a list of pointers to\r
1061 EFI_SIGNATURE_LIST structures. The list is terminated\r
1062 by a null pointer. List of X.509 certificates of\r
1063 revoked signers and revoked file hashes. Except as\r
1064 noted in description of TimeStampDb signature\r
1065 verification will always fail if the signer of the\r
1066 file or the hash of the data component of the buffer\r
1067 is in RevokedDb list. This list is optional and\r
1068 caller may pass Null or pointer to NULL if not\r
1069 required.\r
1070 @param[in] TimeStampDb Optional pointer to a list of pointers to\r
1071 EFI_SIGNATURE_LIST structures. The list is terminated\r
1072 by a null pointer. This parameter can be used to pass\r
1073 a list of X.509 certificates of trusted time stamp\r
1074 signers. This list is optional and caller must pass\r
1075 Null or pointer to NULL if not required.\r
1076 @param[out] Content On input, points to an optional caller-allocated\r
1077 buffer into which the function will copy the content\r
1078 portion of the file after verification succeeds.\r
1079 This parameter is optional and if NULL, no copy of\r
1080 content from file is performed.\r
1081 @param[in,out] ContentSize On input, points to the size in bytes of the optional\r
1082 buffer Content previously allocated by caller. On\r
1083 output, if the verification succeeds, the value\r
1084 referenced by ContentSize will contain the actual\r
1085 size of the content from signed file. If ContentSize\r
1086 indicates the caller-allocated buffer is too small\r
1087 to contain content, an error is returned, and\r
1088 ContentSize will be updated with the required size.\r
1089 This parameter must be 0 if Content is Null.\r
1090\r
1091 @retval EFI_SUCCESS Content signature was verified against hash of\r
1092 content, the signer's certificate was not found in\r
1093 RevokedDb, and was found in AllowedDb or if in signer\r
1094 is found in both AllowedDb and RevokedDb, the\r
1095 signing was allowed by reference to TimeStampDb as\r
1096 described above, and no hash matching content hash\r
1097 was found in RevokedDb.\r
1098 @retval EFI_SECURITY_VIOLATION The SignedData buffer was correctly formatted but\r
1099 signer was in RevokedDb or not in AllowedDb. Also\r
1100 returned if matching content hash found in RevokedDb.\r
1101 @retval EFI_COMPROMISED_DATA Calculated hash differs from signed hash.\r
1102 @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.\r
1103 AllowedDb is NULL.\r
1104 @retval EFI_INVALID_PARAMETER Content is not NULL and ContentSize is NULL.\r
1105 @retval EFI_ABORTED Unsupported or invalid format in TimeStampDb,\r
1106 RevokedDb or AllowedDb list contents was detected.\r
1107 @retval EFI_NOT_FOUND Content not found because InData is NULL and no\r
1108 content embedded in SignedData.\r
1109 @retval EFI_UNSUPPORTED The SignedData buffer was not correctly formatted\r
1110 for processing by the function.\r
1111 @retval EFI_UNSUPPORTED Signed data embedded in SignedData but InData is not\r
1112 NULL.\r
1113 @retval EFI_BUFFER_TOO_SMALL The size of buffer indicated by ContentSize is too\r
1114 small to hold the content. ContentSize updated to\r
1115 required size.\r
1116\r
1117**/\r
1118EFI_STATUS\r
1119EFIAPI\r
1120VerifyBuffer (\r
1121 IN EFI_PKCS7_VERIFY_PROTOCOL *This,\r
1122 IN VOID *SignedData,\r
1123 IN UINTN SignedDataSize,\r
1124 IN VOID *InData OPTIONAL,\r
1125 IN UINTN InDataSize,\r
1126 IN EFI_SIGNATURE_LIST **AllowedDb,\r
1127 IN EFI_SIGNATURE_LIST **RevokedDb OPTIONAL,\r
1128 IN EFI_SIGNATURE_LIST **TimeStampDb OPTIONAL,\r
1129 OUT VOID *Content OPTIONAL,\r
1130 IN OUT UINTN *ContentSize\r
1131 )\r
1132{\r
76b35710
LQ
1133 EFI_STATUS Status;\r
1134 EFI_SIGNATURE_LIST *SigList;\r
1135 UINTN Index;\r
1136 UINT8 *AttachedData;\r
1137 UINTN AttachedDataSize;\r
1138 UINT8 *DataPtr;\r
1139 UINTN DataSize;\r
2d093499
QL
1140\r
1141 //\r
1142 // Parameters Checking\r
1143 //\r
1144 if ((SignedData == NULL) || (SignedDataSize == 0) || (AllowedDb == NULL)) {\r
1145 return EFI_INVALID_PARAMETER;\r
1146 }\r
1147 if ((Content != NULL) && (ContentSize == NULL)) {\r
1148 return EFI_INVALID_PARAMETER;\r
1149 }\r
1150\r
76b35710
LQ
1151 //\r
1152 // Check if any invalid entry format in AllowedDb list contents\r
1153 //\r
1154 for (Index = 0; ; Index++) {\r
1155 SigList = (EFI_SIGNATURE_LIST *)(AllowedDb[Index]);\r
1156\r
1157 if (SigList == NULL) {\r
1158 break;\r
1159 }\r
1160 if (SigList->SignatureListSize < sizeof (EFI_SIGNATURE_LIST) +\r
1161 SigList->SignatureHeaderSize +\r
1162 SigList->SignatureSize) {\r
1163 return EFI_ABORTED;\r
1164 }\r
1165 }\r
1166\r
1167 //\r
1168 // Check if any invalid entry format in RevokedDb list contents\r
1169 //\r
1170 if (RevokedDb != NULL) {\r
1171 for (Index = 0; ; Index++) {\r
1172 SigList = (EFI_SIGNATURE_LIST *)(RevokedDb[Index]);\r
1173\r
1174 if (SigList == NULL) {\r
1175 break;\r
1176 }\r
1177 if (SigList->SignatureListSize < sizeof (EFI_SIGNATURE_LIST) +\r
1178 SigList->SignatureHeaderSize +\r
1179 SigList->SignatureSize) {\r
1180 return EFI_ABORTED;\r
1181 }\r
1182 }\r
1183 }\r
1184\r
1185 //\r
1186 // Check if any invalid entry format in TimeStampDb list contents\r
1187 //\r
1188 if (TimeStampDb != NULL) {\r
1189 for (Index = 0; ; Index++) {\r
1190 SigList = (EFI_SIGNATURE_LIST *)(TimeStampDb[Index]);\r
1191\r
1192 if (SigList == NULL) {\r
1193 break;\r
1194 }\r
1195 if (SigList->SignatureListSize < sizeof (EFI_SIGNATURE_LIST) +\r
1196 SigList->SignatureHeaderSize +\r
1197 SigList->SignatureSize) {\r
1198 return EFI_ABORTED;\r
1199 }\r
1200 }\r
1201 }\r
1202\r
2d093499
QL
1203 //\r
1204 // Try to retrieve the attached content from PKCS7 signedData\r
1205 //\r
1206 AttachedData = NULL;\r
1207 AttachedDataSize = 0;\r
1208 if (!Pkcs7GetAttachedContent (\r
1209 SignedData,\r
1210 SignedDataSize,\r
1211 (VOID **)&AttachedData,\r
1212 &AttachedDataSize)) {\r
1213 //\r
1214 // The SignedData buffer was not correctly formatted for processing\r
1215 //\r
1216 return EFI_UNSUPPORTED;\r
1217 }\r
1218 if (AttachedData != NULL) {\r
173a1e68
QL
1219 if (InData != NULL) {\r
1220 //\r
1221 // The embedded content is found in SignedData but InData is not NULL\r
1222 //\r
1223 Status = EFI_UNSUPPORTED;\r
1224 goto _Exit;\r
1225 }\r
2d093499
QL
1226 //\r
1227 // PKCS7-formatted signedData with attached content; Use the embedded\r
1228 // content for verification\r
1229 //\r
1230 DataPtr = AttachedData;\r
1231 DataSize = AttachedDataSize;\r
1232\r
1233 } else if (InData != NULL) {\r
1234 //\r
1235 // PKCS7-formatted signedData with detached content; Use the user-supplied\r
1236 // input data for verification\r
1237 //\r
1238 DataPtr = (UINT8 *)InData;\r
1239 DataSize = InDataSize;\r
1240 } else {\r
1241 //\r
1242 // Content not found because InData is NULL and no content attached in SignedData\r
1243 //\r
1244 Status = EFI_NOT_FOUND;\r
1245 goto _Exit;\r
1246 }\r
1247\r
1248 Status = EFI_UNSUPPORTED;\r
1249\r
1250 //\r
1251 // Verify PKCS7 SignedData with Revoked database\r
1252 //\r
1253 if (RevokedDb != NULL) {\r
1254 Status = P7CheckRevocation (\r
1255 SignedData,\r
1256 SignedDataSize,\r
1257 DataPtr,\r
1258 DataSize,\r
1259 RevokedDb,\r
1260 TimeStampDb\r
1261 );\r
1262 if (!EFI_ERROR (Status)) {\r
1263 //\r
d6b926e7 1264 // The PKCS7 SignedData is revoked\r
2d093499
QL
1265 //\r
1266 Status = EFI_SECURITY_VIOLATION;\r
1267 goto _Exit;\r
1268 }\r
1269 }\r
1270\r
1271 //\r
1272 // Verify PKCS7 SignedData with AllowedDB\r
1273 //\r
1274 Status = P7CheckTrust (\r
1275 SignedData,\r
1276 SignedDataSize,\r
1277 DataPtr,\r
1278 DataSize,\r
1279 AllowedDb\r
1280 );\r
1281 if (EFI_ERROR (Status)) {\r
1282 //\r
1283 // Verification failed with AllowedDb\r
1284 //\r
1285 goto _Exit;\r
1286 }\r
1287\r
1288 //\r
1289 // Copy the content portion after verification succeeds\r
1290 //\r
1291 if (Content != NULL) {\r
1292 if (*ContentSize < DataSize) {\r
1293 //\r
1294 // Caller-allocated buffer is too small to contain content\r
1295 //\r
1296 *ContentSize = DataSize;\r
1297 Status = EFI_BUFFER_TOO_SMALL;\r
1298 } else {\r
1299 *ContentSize = DataSize;\r
1300 CopyMem (Content, DataPtr, DataSize);\r
1301 }\r
1302 }\r
1303\r
1304_Exit:\r
1305 if (AttachedData != NULL) {\r
1306 FreePool (AttachedData);\r
1307 }\r
1308\r
1309 return Status;\r
1310}\r
1311\r
1312/**\r
1313 Processes a buffer containing binary DER-encoded detached PKCS7 signature.\r
1314 The hash of the signed data content is calculated and passed by the caller. Function\r
1315 verifies the signature of the content is valid and signing certificate was not revoked\r
1316 and is contained within a list of trusted signers.\r
1317\r
6ded1955
LQ
1318 Note: because this function uses hashes and the specification contains a variety of\r
1319 hash choices, you should be aware that the check against the RevokedDb list\r
1320 will improperly succeed if the signature is revoked using a different hash\r
1321 algorithm. For this reason, you should either cycle through all UEFI supported\r
1322 hashes to see if one is forbidden, or rely on a single hash choice only if the\r
1323 UEFI signature authority only signs and revokes with a single hash (at time\r
1324 of writing, this hash choice is SHA256).\r
1325\r
2d093499
QL
1326 @param[in] This Pointer to EFI_PKCS7_VERIFY_PROTOCOL instance.\r
1327 @param[in] Signature Points to buffer containing ASN.1 DER-encoded PKCS\r
1328 detached signature.\r
1329 @param[in] SignatureSize The size of Signature buffer in bytes.\r
1330 @param[in] InHash InHash points to buffer containing the caller\r
1331 calculated hash of the data. The parameter may not\r
1332 be NULL.\r
1333 @param[in] InHashSize The size in bytes of InHash buffer.\r
1334 @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST\r
1335 structures. The list is terminated by a null\r
1336 pointer. The EFI_SIGNATURE_LIST structures contain\r
1337 lists of X.509 certificates of approved signers.\r
1338 Function recognizes signer certificates of type\r
1339 EFI_CERT_X509_GUID. Any hash certificate in AllowedDb\r
1340 list is ignored by this function. Function returns\r
1341 success if signer of the buffer is within this list\r
1342 (and not within RevokedDb). This parameter is\r
1343 required.\r
1344 @param[in] RevokedDb Optional pointer to a list of pointers to\r
1345 EFI_SIGNATURE_LIST structures. The list is terminated\r
1346 by a null pointer. List of X.509 certificates of\r
1347 revoked signers and revoked file hashes. Signature\r
1348 verification will always fail if the signer of the\r
1349 file or the hash of the data component of the buffer\r
1350 is in RevokedDb list. This parameter is optional\r
1351 and caller may pass Null if not required.\r
1352 @param[in] TimeStampDb Optional pointer to a list of pointers to\r
1353 EFI_SIGNATURE_LIST structures. The list is terminated\r
1354 by a null pointer. This parameter can be used to pass\r
1355 a list of X.509 certificates of trusted time stamp\r
1356 counter-signers.\r
1357\r
1358 @retval EFI_SUCCESS Signed hash was verified against caller-provided\r
1359 hash of content, the signer's certificate was not\r
1360 found in RevokedDb, and was found in AllowedDb or\r
1361 if in signer is found in both AllowedDb and\r
1362 RevokedDb, the signing was allowed by reference to\r
1363 TimeStampDb as described above, and no hash matching\r
1364 content hash was found in RevokedDb.\r
1365 @retval EFI_SECURITY_VIOLATION The SignedData buffer was correctly formatted but\r
1366 signer was in RevokedDb or not in AllowedDb. Also\r
1367 returned if matching content hash found in RevokedDb.\r
1368 @retval EFI_COMPROMISED_DATA Caller provided hash differs from signed hash. Or,\r
1369 caller and encrypted hash are different sizes.\r
1370 @retval EFI_INVALID_PARAMETER Signature is NULL or SignatureSize is zero. InHash\r
1371 is NULL or InHashSize is zero. AllowedDb is NULL.\r
1372 @retval EFI_ABORTED Unsupported or invalid format in TimeStampDb,\r
1373 RevokedDb or AllowedDb list contents was detected.\r
1374 @retval EFI_UNSUPPORTED The Signature buffer was not correctly formatted\r
1375 for processing by the function.\r
1376\r
1377**/\r
1378EFI_STATUS\r
1379EFIAPI\r
1380VerifySignature (\r
1381 IN EFI_PKCS7_VERIFY_PROTOCOL *This,\r
1382 IN VOID *Signature,\r
1383 IN UINTN SignatureSize,\r
1384 IN VOID *InHash,\r
1385 IN UINTN InHashSize,\r
1386 IN EFI_SIGNATURE_LIST **AllowedDb,\r
1387 IN EFI_SIGNATURE_LIST **RevokedDb OPTIONAL,\r
1388 IN EFI_SIGNATURE_LIST **TimeStampDb OPTIONAL\r
1389 )\r
1390{\r
a2481f81
LQ
1391 EFI_STATUS Status;\r
1392\r
1393 //\r
1394 // Parameters Checking\r
2d093499 1395 //\r
a2481f81
LQ
1396 if ((Signature == NULL) || (SignatureSize == 0) || (AllowedDb == NULL)\r
1397 || (InHash == NULL) || (InHashSize == 0)) {\r
1398 return EFI_INVALID_PARAMETER;\r
1399 }\r
1400\r
2d093499 1401 //\r
a2481f81
LQ
1402 // Verify PKCS7 SignedData with Revoked database\r
1403 //\r
1404 if (RevokedDb != NULL) {\r
1405 Status = P7CheckRevocationByHash (\r
1406 Signature,\r
1407 SignatureSize,\r
1408 InHash,\r
1409 InHashSize,\r
1410 RevokedDb,\r
1411 TimeStampDb\r
1412 );\r
1413\r
1414 if (!EFI_ERROR (Status)) {\r
1415 //\r
d6b926e7 1416 // The PKCS7 SignedData is revoked\r
a2481f81
LQ
1417 //\r
1418 return EFI_SECURITY_VIOLATION;\r
1419 }\r
1420 }\r
1421\r
1422 //\r
1423 // Verify PKCS7 SignedData with AllowedDB\r
1424 //\r
1425 Status = P7CheckTrustByHash (\r
1426 Signature,\r
1427 SignatureSize,\r
1428 InHash,\r
1429 InHashSize,\r
1430 AllowedDb\r
1431 );\r
1432\r
1433 return Status;\r
2d093499
QL
1434}\r
1435\r
1436//\r
1437// The PKCS7 Verification Protocol\r
1438//\r
1439EFI_PKCS7_VERIFY_PROTOCOL mPkcs7Verify = {\r
1440 VerifyBuffer,\r
1441 VerifySignature\r
1442};\r
1443\r
1444/**\r
1445 The user Entry Point for the PKCS7 Verification driver.\r
1446\r
1447 @param[in] ImageHandle The firmware allocated handle for the EFI image.\r
1448 @param[in] SystemTable A pointer to the EFI System Table.\r
1449\r
1450 @retval EFI_SUCCESS The entry point is executed successfully.\r
1451 @retval EFI_NOT_SUPPORTED Platform does not support PKCS7 Verification.\r
1452 @retval Other Some error occurs when executing this entry point.\r
1453\r
1454**/\r
1455EFI_STATUS\r
1456EFIAPI\r
1457Pkcs7VerifyDriverEntry (\r
1458 IN EFI_HANDLE ImageHandle,\r
1459 IN EFI_SYSTEM_TABLE *SystemTable\r
1460 )\r
1461{\r
56e88e9e
PJ
1462 EFI_STATUS Status;\r
1463 EFI_HANDLE Handle;\r
1464 EFI_PKCS7_VERIFY_PROTOCOL Useless;\r
1465\r
1466 //\r
1467 // Avoid loading a second copy if this is built as an external module\r
1468 //\r
1469 Status = gBS->LocateProtocol (&gEfiPkcs7VerifyProtocolGuid, NULL, (VOID **)&Useless);\r
1470 if (!EFI_ERROR (Status)) {\r
1471 return EFI_ABORTED;\r
1472 }\r
2d093499
QL
1473\r
1474 //\r
1475 // Install UEFI Pkcs7 Verification Protocol\r
1476 //\r
1477 Handle = NULL;\r
1478 Status = gBS->InstallMultipleProtocolInterfaces (\r
1479 &Handle,\r
1480 &gEfiPkcs7VerifyProtocolGuid,\r
1481 &mPkcs7Verify,\r
1482 NULL\r
1483 );\r
1484\r
1485 return Status;\r
1486}\r