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