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