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