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