2 Pkcs7Verify Driver to produce the UEFI PKCS7 Verification Protocol.
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.
8 Copyright (c) 2015 - 2017, Intel Corporation. All rights reserved.<BR>
9 This program and the accompanying materials
10 are licensed and made available under the terms and conditions of the BSD License
11 which accompanies this distribution. The full text of the license may be found at
12 http://opensource.org/licenses/bsd-license.php
14 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
15 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
19 #include <Library/BaseLib.h>
20 #include <Library/BaseMemoryLib.h>
21 #include <Library/MemoryAllocationLib.h>
22 #include <Library/UefiBootServicesTableLib.h>
23 #include <Library/BaseCryptLib.h>
24 #include <Protocol/Pkcs7Verify.h>
26 #define MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
29 Calculates the hash of the given data based on the specified hash GUID.
31 @param[in] Data Pointer to the data buffer to be hashed.
32 @param[in] DataSize The size of data buffer in bytes.
33 @param[in] CertGuid The GUID to identify the hash algorithm to be used.
34 @param[out] HashValue Pointer to a buffer that receives the hash result.
36 @retval TRUE Data hash calculation succeeded.
37 @retval FALSE Data hash calculation failed.
44 IN EFI_GUID
*CertGuid
,
55 if (CompareGuid (CertGuid
, &gEfiCertSha1Guid
)) {
59 CtxSize
= Sha1GetContextSize ();
60 HashCtx
= AllocatePool (CtxSize
);
61 if (HashCtx
== NULL
) {
64 Status
= Sha1Init (HashCtx
);
65 Status
= Sha1Update (HashCtx
, Data
, DataSize
);
66 Status
= Sha1Final (HashCtx
, HashValue
);
68 } else if (CompareGuid (CertGuid
, &gEfiCertSha256Guid
)) {
72 CtxSize
= Sha256GetContextSize ();
73 HashCtx
= AllocatePool (CtxSize
);
74 if (HashCtx
== NULL
) {
77 Status
= Sha256Init (HashCtx
);
78 Status
= Sha256Update (HashCtx
, Data
, DataSize
);
79 Status
= Sha256Final (HashCtx
, HashValue
);
81 } else if (CompareGuid (CertGuid
, &gEfiCertSha384Guid
)) {
85 CtxSize
= Sha384GetContextSize ();
86 HashCtx
= AllocatePool (CtxSize
);
87 if (HashCtx
== NULL
) {
90 Status
= Sha384Init (HashCtx
);
91 Status
= Sha384Update (HashCtx
, Data
, DataSize
);
92 Status
= Sha384Final (HashCtx
, HashValue
);
94 } else if (CompareGuid (CertGuid
, &gEfiCertSha512Guid
)) {
98 CtxSize
= Sha512GetContextSize ();
99 HashCtx
= AllocatePool (CtxSize
);
100 if (HashCtx
== NULL
) {
103 Status
= Sha512Init (HashCtx
);
104 Status
= Sha512Update (HashCtx
, Data
, DataSize
);
105 Status
= Sha512Final (HashCtx
, HashValue
);
109 if (HashCtx
!= NULL
) {
117 Check whether the hash of data content is revoked by the revocation database.
119 @param[in] Hash Pointer to the hash that is searched for.
120 @param[in] HashSize The size of the hash in bytes.
121 @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
122 structure which contains list of X.509 certificates
123 of revoked signers and revoked content hashes.
125 @return TRUE The matched content hash is found in the revocation database.
126 @return FALSE The matched content hash is not found in the revocation database.
130 IsContentHashRevokedByHash (
133 IN EFI_SIGNATURE_LIST
**RevokedDb
136 EFI_SIGNATURE_LIST
*SigList
;
137 EFI_SIGNATURE_DATA
*SigData
;
143 if (RevokedDb
== NULL
) {
149 // Check if any hash matching content hash can be found in RevokedDB
151 for (Index
= 0; ; Index
++) {
152 SigList
= (EFI_SIGNATURE_LIST
*)(RevokedDb
[Index
]);
155 // The list is terminated by a NULL pointer.
157 if (SigList
== NULL
) {
162 // Search the signature database to search the revoked content hash
164 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigList
+ sizeof (EFI_SIGNATURE_LIST
) +
165 SigList
->SignatureHeaderSize
);
166 EntryCount
= (SigList
->SignatureListSize
- SigList
->SignatureHeaderSize
-
167 sizeof (EFI_SIGNATURE_LIST
)) / SigList
->SignatureSize
;
168 for (EntryIndex
= 0; EntryIndex
< EntryCount
; EntryIndex
++) {
170 // The problem case. There's a revocation hash but the sizes
171 // don't match, meaning it's a different hash algorithm and we
172 // can't tell if it's revoking our binary or not. Assume not.
174 if (SigList
->SignatureSize
- sizeof(EFI_GUID
) == HashSize
) {
176 // Compare Data Hash with Signature Data
178 if (CompareMem (SigData
->SignatureData
, Hash
, HashSize
) == 0) {
184 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigData
+ SigList
->SignatureSize
);
193 Check whether the hash of data content is revoked by the revocation database.
195 @param[in] Content Pointer to the content buffer that is searched for.
196 @param[in] ContentSize The size of data content in bytes.
197 @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
198 structure which contains list of X.509 certificates
199 of revoked signers and revoked content hashes.
201 @return TRUE The matched content hash is found in the revocation database.
202 @return FALSE The matched content hash is not found in the revocation database.
206 IsContentHashRevoked (
208 IN UINTN ContentSize
,
209 IN EFI_SIGNATURE_LIST
**RevokedDb
212 EFI_SIGNATURE_LIST
*SigList
;
213 EFI_SIGNATURE_DATA
*SigData
;
215 UINT8 HashVal
[MAX_DIGEST_SIZE
];
220 if (RevokedDb
== NULL
) {
226 // Check if any hash matching content hash can be found in RevokedDB
228 for (Index
= 0; ; Index
++) {
229 SigList
= (EFI_SIGNATURE_LIST
*)(RevokedDb
[Index
]);
232 // The list is terminated by a NULL pointer.
234 if (SigList
== NULL
) {
239 // Calculate the digest of supplied data based on the signature hash type.
241 if (!CalculateDataHash (Content
, ContentSize
, &SigList
->SignatureType
, HashVal
)) {
243 // Un-matched Hash GUID or other failure.
249 // Search the signature database to search the revoked content hash
251 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigList
+ sizeof (EFI_SIGNATURE_LIST
) +
252 SigList
->SignatureHeaderSize
);
253 EntryCount
= (SigList
->SignatureListSize
- SigList
->SignatureHeaderSize
-
254 sizeof (EFI_SIGNATURE_LIST
)) / SigList
->SignatureSize
;
255 for (EntryIndex
= 0; EntryIndex
< EntryCount
; EntryIndex
++) {
257 // Compare Data Hash with Signature Data
259 if (CompareMem (SigData
->SignatureData
, HashVal
, (SigList
->SignatureSize
- sizeof (EFI_GUID
))) == 0) {
264 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigData
+ SigList
->SignatureSize
);
273 Check whether the hash of an given certificate is revoked by the revocation database.
275 @param[in] Certificate Pointer to the certificate that is searched for.
276 @param[in] CertSize Size of certificate in bytes.
277 @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
278 structures which contains list of X.509 certificate
279 of revoked signers and revoked content hashes.
280 @param[out] RevocationTime Return the time that the certificate was revoked.
282 @return TRUE The certificate hash is found in the revocation database.
283 @return FALSE The certificate hash is not found in the revocation database.
288 IN UINT8
*Certificate
,
290 IN EFI_SIGNATURE_LIST
**RevokedDb
,
291 OUT EFI_TIME
*RevocationTime
295 EFI_SIGNATURE_LIST
*SigList
;
296 EFI_SIGNATURE_DATA
*SigData
;
302 UINT8 CertHashVal
[MAX_DIGEST_SIZE
];
304 if ((RevocationTime
== NULL
) || (RevokedDb
== NULL
)) {
309 // Retrieve the TBSCertificate from the X.509 Certificate for hash calculation
311 if (!X509GetTBSCert (Certificate
, CertSize
, &TBSCert
, &TBSCertSize
)) {
316 for (Index
= 0; ; Index
++) {
318 SigList
= (EFI_SIGNATURE_LIST
*)(RevokedDb
[Index
]);
320 // The list is terminated by a NULL pointer.
322 if (SigList
== NULL
) {
327 // Determine Hash Algorithm based on the entry type in revocation database, and
328 // calculate the certificate hash.
330 if (CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Sha256Guid
)) {
331 Status
= CalculateDataHash (TBSCert
, TBSCertSize
, &gEfiCertSha256Guid
, CertHashVal
);
333 } else if (CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Sha384Guid
)) {
334 Status
= CalculateDataHash (TBSCert
, TBSCertSize
, &gEfiCertSha384Guid
, CertHashVal
);
336 } else if (CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Sha512Guid
)) {
337 Status
= CalculateDataHash (TBSCert
, TBSCertSize
, &gEfiCertSha512Guid
, CertHashVal
);
341 // Un-matched Cert Hash GUID
350 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigList
+ sizeof (EFI_SIGNATURE_LIST
) +
351 SigList
->SignatureHeaderSize
);
352 EntryCount
= (SigList
->SignatureListSize
- SigList
->SignatureHeaderSize
-
353 sizeof (EFI_SIGNATURE_LIST
)) / SigList
->SignatureSize
;
354 for (EntryIndex
= 0; EntryIndex
< EntryCount
; Index
++) {
356 // Check if the Certificate Hash is revoked.
358 if (CompareMem (SigData
->SignatureData
, CertHashVal
,
359 SigList
->SignatureSize
- sizeof (EFI_GUID
) - sizeof (EFI_TIME
)) == 0) {
362 // Return the revocation time of this revoked certificate.
366 (EFI_TIME
*)((UINT8
*)SigData
+ SigList
->SignatureSize
- sizeof (EFI_TIME
)),
372 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigData
+ SigList
->SignatureSize
);
381 Check if the given time value is zero.
383 @param[in] Time Pointer of a time value.
385 @retval TRUE The Time is Zero.
386 @retval FALSE The Time is not Zero.
394 if ((Time
->Year
== 0) && (Time
->Month
== 0) && (Time
->Day
== 0) &&
395 (Time
->Hour
== 0) && (Time
->Minute
== 0) && (Time
->Second
== 0)) {
403 Check whether the timestamp is valid by comparing the signing time and the revocation time.
405 @param SigningTime Pointer to the signing time.
406 @param RevocationTime Pointer to the revocation time.
408 @retval TRUE The SigningTime is not later than the RevocationTime.
409 @retval FALSE The SigningTime is later than the RevocationTime.
414 IN EFI_TIME
*SigningTime
,
415 IN EFI_TIME
*RevocationTime
418 if (SigningTime
->Year
!= RevocationTime
->Year
) {
419 return (BOOLEAN
) (SigningTime
->Year
< RevocationTime
->Year
);
420 } else if (SigningTime
->Month
!= RevocationTime
->Month
) {
421 return (BOOLEAN
) (SigningTime
->Month
< RevocationTime
->Month
);
422 } else if (SigningTime
->Day
!= RevocationTime
->Day
) {
423 return (BOOLEAN
) (SigningTime
->Day
< RevocationTime
->Day
);
424 } else if (SigningTime
->Hour
!= RevocationTime
->Hour
) {
425 return (BOOLEAN
) (SigningTime
->Hour
< RevocationTime
->Hour
);
426 } else if (SigningTime
->Minute
!= RevocationTime
->Minute
) {
427 return (BOOLEAN
) (SigningTime
->Minute
< RevocationTime
->Minute
);
430 return (BOOLEAN
) (SigningTime
->Second
<= RevocationTime
->Second
);
434 Check whether the timestamp signature embedded in PKCS7 signedData is valid and
435 the signing time is also earlier than the revocation time.
437 @param[in] SignedData Pointer to the PKCS#7 signedData.
438 @param[in] SignedDataSize Size of SignedData in bytes.
439 @param[in] TimeStampDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
440 structures which is used to pass a list of X.509
441 certificates of trusted timestamp signers.
442 @param[in] RevocationTime The time that the certificate was revoked.
444 @retval TRUE Timestamp signature is valid and the signing time is no later
445 than the revocation time.
446 @retval FALSE Timestamp signature is not valid or the signing time is later
447 than the revocation time.
452 IN UINT8
*SignedData
,
453 IN UINTN SignedDataSize
,
454 IN EFI_SIGNATURE_LIST
**TimeStampDb
,
455 IN EFI_TIME
*RevocationTime
459 EFI_SIGNATURE_LIST
*SigList
;
460 EFI_SIGNATURE_DATA
*SigData
;
464 EFI_TIME SigningTime
;
467 // If no supplied database for verification or RevocationTime is zero,
468 // the certificate shall be considered to always be revoked.
470 if ((TimeStampDb
== NULL
) || (IsTimeZero (RevocationTime
))) {
476 // RevocationTime is non-zero, the certificate should be considered to be revoked
477 // from that time and onwards.
479 for (Index
= 0; ; Index
++) {
480 SigList
= (EFI_SIGNATURE_LIST
*) (TimeStampDb
[Index
]);
483 // The list is terminated by a NULL pointer.
485 if (SigList
== NULL
) {
490 // Ignore any non-X509-format entry in the list
492 if (!CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Guid
)) {
497 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigList
+ sizeof (EFI_SIGNATURE_LIST
) +
498 SigList
->SignatureHeaderSize
);
499 TsaCert
= SigData
->SignatureData
;
500 TsaCertSize
= SigList
->SignatureSize
- sizeof (EFI_GUID
);
503 // Each TSA Certificate will normally be in a seperate EFI_SIGNATURE_LIST
504 // Leverage ImageTimestampVerify interface for Timestamp counterSignature Verification
506 if (ImageTimestampVerify (SignedData
, SignedDataSize
, TsaCert
, TsaCertSize
, &SigningTime
)) {
508 // The signer signature is valid only when the signing time is earlier than revocation time.
510 if (CompareTimestamp (&SigningTime
, RevocationTime
)) {
521 Check whether the PKCS7 signedData is revoked by verifying with the revoked
522 certificates database, and if the signedData is timestamped, the embedded timestamp
523 couterSignature will be checked with the supplied timestamp database.
525 @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7
527 @param[in] SignedDataSize The size of SignedData buffer in bytes.
528 @param[in] InHash Pointer to the buffer containing the hash of the mesage data
529 previously signed and to be verified.
530 @param[in] InHashSize The size of InHash buffer in bytes.
531 @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
532 structure which contains list of X.509 certificates
533 of revoked signers and revoked content hashes.
534 @param[in] TimeStampDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
535 structures which is used to pass a list of X.509
536 certificates of trusted timestamp signers.
538 @retval EFI_SUCCESS The PKCS7 signedData is revoked.
539 @retval EFI_SECURITY_VIOLATION Fail to verify the signature in PKCS7 signedData.
540 @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.
542 Content is not NULL and ContentSize is NULL.
543 @retval EFI_NOT_FOUND Content not found because InData is NULL and no
544 content embedded in PKCS7 signedData.
545 @retval EFI_UNSUPPORTED The PKCS7 signedData was not correctly formatted.
549 P7CheckRevocationByHash (
550 IN UINT8
*SignedData
,
551 IN UINTN SignedDataSize
,
554 IN EFI_SIGNATURE_LIST
**RevokedDb
,
555 IN EFI_SIGNATURE_LIST
**TimeStampDb
559 EFI_SIGNATURE_LIST
*SigList
;
560 EFI_SIGNATURE_DATA
*SigData
;
562 UINTN RevokedCertSize
;
567 UINTN TrustedCertLength
;
572 EFI_TIME RevocationTime
;
574 Status
= EFI_SECURITY_VIOLATION
;
582 // The signedData is revoked if the hash of content existed in RevokedDb
584 if (IsContentHashRevokedByHash (InHash
, InHashSize
, RevokedDb
)) {
585 Status
= EFI_SUCCESS
;
590 // Check if the signer's certificate can be found in Revoked database
592 for (Index
= 0; ; Index
++) {
593 SigList
= (EFI_SIGNATURE_LIST
*)(RevokedDb
[Index
]);
596 // The list is terminated by a NULL pointer.
598 if (SigList
== NULL
) {
603 // Ignore any non-X509-format entry in the list.
605 if (!CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Guid
)) {
609 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigList
+ sizeof (EFI_SIGNATURE_LIST
) +
610 SigList
->SignatureHeaderSize
);
612 RevokedCert
= SigData
->SignatureData
;
613 RevokedCertSize
= SigList
->SignatureSize
- sizeof (EFI_GUID
);
616 // Verifying the PKCS#7 SignedData with the revoked certificate in RevokedDb
618 if (AuthenticodeVerify (SignedData
, SignedDataSize
, RevokedCert
, RevokedCertSize
, InHash
, InHashSize
)) {
620 // The signedData was verified by one entry in Revoked Database
622 Status
= EFI_SUCCESS
;
627 if (!EFI_ERROR (Status
)) {
629 // The signedData was revoked, since it was hit by RevokedDb
635 // Now we will continue to check the X.509 Certificate Hash & Possible Timestamp
637 if ((TimeStampDb
== NULL
) || (*TimeStampDb
== NULL
)) {
641 Pkcs7GetSigners (SignedData
, SignedDataSize
, &CertBuffer
, &BufferLength
, &TrustedCert
, &TrustedCertLength
);
642 if ((BufferLength
== 0) || (CertBuffer
== NULL
)) {
643 Status
= EFI_SUCCESS
;
648 // Check if any hash of certificates embedded in P7 data is in the revoked database.
650 CertNumber
= (UINT8
) (*CertBuffer
);
651 CertPtr
= CertBuffer
+ 1;
652 for (Index
= 0; Index
< CertNumber
; Index
++) {
654 // Retrieve the Certificate data
656 CertSize
= (UINTN
) ReadUnaligned32 ((UINT32
*) CertPtr
);
657 Cert
= (UINT8
*)CertPtr
+ sizeof (UINT32
);
659 if (IsCertHashRevoked (Cert
, CertSize
, RevokedDb
, &RevocationTime
)) {
661 // Check the timestamp signature and signing time to determine if p7 data can be trusted.
663 Status
= EFI_SUCCESS
;
664 if (IsValidTimestamp (SignedData
, SignedDataSize
, TimeStampDb
, &RevocationTime
)) {
666 // Use EFI_NOT_READY to identify the P7Data is not reovked, because the timestamping
667 // occured prior to the time of certificate revocation.
669 Status
= EFI_NOT_READY
;
675 CertPtr
= CertPtr
+ sizeof (UINT32
) + CertSize
;
679 Pkcs7FreeSigners (CertBuffer
);
680 Pkcs7FreeSigners (TrustedCert
);
686 Check whether the PKCS7 signedData is revoked by verifying with the revoked
687 certificates database, and if the signedData is timestamped, the embedded timestamp
688 couterSignature will be checked with the supplied timestamp database.
690 @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7
692 @param[in] SignedDataSize The size of SignedData buffer in bytes.
693 @param[in] InData Pointer to the buffer containing the raw message data
694 previously signed and to be verified.
695 @param[in] InDataSize The size of InData buffer in bytes.
696 @param[in] RevokedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
697 structure which contains list of X.509 certificates
698 of revoked signers and revoked content hashes.
699 @param[in] TimeStampDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
700 structures which is used to pass a list of X.509
701 certificates of trusted timestamp signers.
703 @retval EFI_SUCCESS The PKCS7 signedData is revoked.
704 @retval EFI_SECURITY_VIOLATION Fail to verify the signature in PKCS7 signedData.
705 @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.
707 Content is not NULL and ContentSize is NULL.
708 @retval EFI_NOT_FOUND Content not found because InData is NULL and no
709 content embedded in PKCS7 signedData.
710 @retval EFI_UNSUPPORTED The PKCS7 signedData was not correctly formatted.
715 IN UINT8
*SignedData
,
716 IN UINTN SignedDataSize
,
719 IN EFI_SIGNATURE_LIST
**RevokedDb
,
720 IN EFI_SIGNATURE_LIST
**TimeStampDb
724 EFI_SIGNATURE_LIST
*SigList
;
725 EFI_SIGNATURE_DATA
*SigData
;
727 UINTN RevokedCertSize
;
732 UINTN TrustedCertLength
;
737 EFI_TIME RevocationTime
;
739 Status
= EFI_UNSUPPORTED
;
747 // The signedData is revoked if the hash of content existed in RevokedDb
749 if (IsContentHashRevoked (InData
, InDataSize
, RevokedDb
)) {
750 Status
= EFI_SUCCESS
;
755 // Check if the signer's certificate can be found in Revoked database
757 for (Index
= 0; ; Index
++) {
758 SigList
= (EFI_SIGNATURE_LIST
*)(RevokedDb
[Index
]);
761 // The list is terminated by a NULL pointer.
763 if (SigList
== NULL
) {
768 // Ignore any non-X509-format entry in the list.
770 if (!CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Guid
)) {
774 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigList
+ sizeof (EFI_SIGNATURE_LIST
) +
775 SigList
->SignatureHeaderSize
);
777 RevokedCert
= SigData
->SignatureData
;
778 RevokedCertSize
= SigList
->SignatureSize
- sizeof (EFI_GUID
);
781 // Verifying the PKCS#7 SignedData with the revoked certificate in RevokedDb
783 if (Pkcs7Verify (SignedData
, SignedDataSize
, RevokedCert
, RevokedCertSize
, InData
, InDataSize
)) {
785 // The signedData was verified by one entry in Revoked Database
787 Status
= EFI_SUCCESS
;
792 if (!EFI_ERROR (Status
)) {
794 // The signedData was revoked, since it was hit by RevokedDb
800 // Now we will continue to check the X.509 Certificate Hash & Possible Timestamp
802 if ((TimeStampDb
== NULL
) || (*TimeStampDb
== NULL
)) {
806 Pkcs7GetSigners (SignedData
, SignedDataSize
, &CertBuffer
, &BufferLength
, &TrustedCert
, &TrustedCertLength
);
807 if ((BufferLength
== 0) || (CertBuffer
== NULL
)) {
808 Status
= EFI_SUCCESS
;
813 // Check if any hash of certificates embedded in P7 data is in the revoked database.
815 CertNumber
= (UINT8
) (*CertBuffer
);
816 CertPtr
= CertBuffer
+ 1;
817 for (Index
= 0; Index
< CertNumber
; Index
++) {
819 // Retrieve the Certificate data
821 CertSize
= (UINTN
) ReadUnaligned32 ((UINT32
*) CertPtr
);
822 Cert
= (UINT8
*)CertPtr
+ sizeof (UINT32
);
824 if (IsCertHashRevoked (Cert
, CertSize
, RevokedDb
, &RevocationTime
)) {
826 // Check the timestamp signature and signing time to determine if p7 data can be trusted.
828 Status
= EFI_SUCCESS
;
829 if (IsValidTimestamp (SignedData
, SignedDataSize
, TimeStampDb
, &RevocationTime
)) {
831 // Use EFI_NOT_READY to identify the P7Data is not reovked, because the timestamping
832 // occured prior to the time of certificate revocation.
834 Status
= EFI_NOT_READY
;
840 CertPtr
= CertPtr
+ sizeof (UINT32
) + CertSize
;
844 Pkcs7FreeSigners (CertBuffer
);
845 Pkcs7FreeSigners (TrustedCert
);
851 Check whether the PKCS7 signedData can be verified by the trusted certificates
852 database, and return the content of the signedData if requested.
854 @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7
856 @param[in] SignedDataSize The size of SignedData buffer in bytes.
857 @param[in] InHash Pointer to the buffer containing the hash of the message data
858 previously signed and to be verified.
859 @param[in] InHashSize The size of InHash buffer in bytes.
860 @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
861 structures which contains lists of X.509 certificates
864 @retval EFI_SUCCESS The PKCS7 signedData is trusted.
865 @retval EFI_SECURITY_VIOLATION Fail to verify the signature in PKCS7 signedData.
866 @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.
868 Content is not NULL and ContentSize is NULL.
869 @retval EFI_NOT_FOUND Content not found because InData is NULL and no
870 content embedded in PKCS7 signedData.
871 @retval EFI_UNSUPPORTED The PKCS7 signedData was not correctly formatted.
872 @retval EFI_BUFFER_TOO_SMALL The size of buffer indicated by ContentSize is too
873 small to hold the content. ContentSize updated to
879 IN UINT8
*SignedData
,
880 IN UINTN SignedDataSize
,
883 IN EFI_SIGNATURE_LIST
**AllowedDb
887 EFI_SIGNATURE_LIST
*SigList
;
888 EFI_SIGNATURE_DATA
*SigData
;
893 Status
= EFI_SECURITY_VIOLATION
;
898 if (AllowedDb
== NULL
) {
899 return EFI_INVALID_PARAMETER
;
903 // Build Certificate Stack with all valid X509 certificates in the supplied
904 // Signature List for PKCS7 Verification.
906 for (Index
= 0; ; Index
++) {
907 SigList
= (EFI_SIGNATURE_LIST
*)(AllowedDb
[Index
]);
910 // The list is terminated by a NULL pointer.
912 if (SigList
== NULL
) {
917 // Ignore any non-X509-format entry in the list.
919 if (!CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Guid
)) {
923 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigList
+ sizeof (EFI_SIGNATURE_LIST
) +
924 SigList
->SignatureHeaderSize
);
926 TrustCert
= SigData
->SignatureData
;
927 TrustCertSize
= SigList
->SignatureSize
- sizeof (EFI_GUID
);
930 // Verifying the PKCS#7 SignedData with the trusted certificate from AllowedDb
932 if (AuthenticodeVerify (SignedData
, SignedDataSize
, TrustCert
, TrustCertSize
, InHash
, InHashSize
)) {
934 // The SignedData was verified successfully by one entry in Trusted Database
936 Status
= EFI_SUCCESS
;
945 Check whether the PKCS7 signedData can be verified by the trusted certificates
946 database, and return the content of the signedData if requested.
948 @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7
950 @param[in] SignedDataSize The size of SignedData buffer in bytes.
951 @param[in] InData Pointer to the buffer containing the raw message data
952 previously signed and to be verified.
953 @param[in] InDataSize The size of InData buffer in bytes.
954 @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
955 structures which contains lists of X.509 certificates
958 @retval EFI_SUCCESS The PKCS7 signedData is trusted.
959 @retval EFI_SECURITY_VIOLATION Fail to verify the signature in PKCS7 signedData.
960 @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.
962 Content is not NULL and ContentSize is NULL.
963 @retval EFI_NOT_FOUND Content not found because InData is NULL and no
964 content embedded in PKCS7 signedData.
965 @retval EFI_UNSUPPORTED The PKCS7 signedData was not correctly formatted.
966 @retval EFI_BUFFER_TOO_SMALL The size of buffer indicated by ContentSize is too
967 small to hold the content. ContentSize updated to
973 IN UINT8
*SignedData
,
974 IN UINTN SignedDataSize
,
977 IN EFI_SIGNATURE_LIST
**AllowedDb
981 EFI_SIGNATURE_LIST
*SigList
;
982 EFI_SIGNATURE_DATA
*SigData
;
987 Status
= EFI_SECURITY_VIOLATION
;
992 if (AllowedDb
== NULL
) {
993 return EFI_INVALID_PARAMETER
;
997 // Build Certificate Stack with all valid X509 certificates in the supplied
998 // Signature List for PKCS7 Verification.
1000 for (Index
= 0; ; Index
++) {
1001 SigList
= (EFI_SIGNATURE_LIST
*)(AllowedDb
[Index
]);
1004 // The list is terminated by a NULL pointer.
1006 if (SigList
== NULL
) {
1011 // Ignore any non-X509-format entry in the list.
1013 if (!CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Guid
)) {
1017 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigList
+ sizeof (EFI_SIGNATURE_LIST
) +
1018 SigList
->SignatureHeaderSize
);
1020 TrustCert
= SigData
->SignatureData
;
1021 TrustCertSize
= SigList
->SignatureSize
- sizeof (EFI_GUID
);
1024 // Verifying the PKCS#7 SignedData with the trusted certificate from AllowedDb
1026 if (Pkcs7Verify (SignedData
, SignedDataSize
, TrustCert
, TrustCertSize
, InData
, InDataSize
)) {
1028 // The SignedData was verified successfully by one entry in Trusted Database
1030 Status
= EFI_SUCCESS
;
1039 Processes a buffer containing binary DER-encoded PKCS7 signature.
1040 The signed data content may be embedded within the buffer or separated. Function
1041 verifies the signature of the content is valid and signing certificate was not
1042 revoked and is contained within a list of trusted signers.
1044 @param[in] This Pointer to EFI_PKCS7_VERIFY_PROTOCOL instance.
1045 @param[in] SignedData Points to buffer containing ASN.1 DER-encoded PKCS7
1047 @param[in] SignedDataSize The size of SignedData buffer in bytes.
1048 @param[in] InData In case of detached signature, InData points to
1049 buffer containing the raw message data previously
1050 signed and to be verified by function. In case of
1051 SignedData containing embedded data, InData must be
1053 @param[in] InDataSize When InData is used, the size of InData buffer in
1054 bytes. When InData is NULL. This parameter must be
1056 @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
1057 structures. The list is terminated by a null
1058 pointer. The EFI_SIGNATURE_LIST structures contain
1059 lists of X.509 certificates of approved signers.
1060 Function recognizes signer certificates of type
1061 EFI_CERT_X509_GUID. Any hash certificate in AllowedDb
1062 list is ignored by this function. Function returns
1063 success if signer of the buffer is within this list
1064 (and not within RevokedDb). This parameter is
1066 @param[in] RevokedDb Optional pointer to a list of pointers to
1067 EFI_SIGNATURE_LIST structures. The list is terminated
1068 by a null pointer. List of X.509 certificates of
1069 revoked signers and revoked file hashes. Except as
1070 noted in description of TimeStampDb signature
1071 verification will always fail if the signer of the
1072 file or the hash of the data component of the buffer
1073 is in RevokedDb list. This list is optional and
1074 caller may pass Null or pointer to NULL if not
1076 @param[in] TimeStampDb Optional pointer to a list of pointers to
1077 EFI_SIGNATURE_LIST structures. The list is terminated
1078 by a null pointer. This parameter can be used to pass
1079 a list of X.509 certificates of trusted time stamp
1080 signers. This list is optional and caller must pass
1081 Null or pointer to NULL if not required.
1082 @param[out] Content On input, points to an optional caller-allocated
1083 buffer into which the function will copy the content
1084 portion of the file after verification succeeds.
1085 This parameter is optional and if NULL, no copy of
1086 content from file is performed.
1087 @param[in,out] ContentSize On input, points to the size in bytes of the optional
1088 buffer Content previously allocated by caller. On
1089 output, if the verification succeeds, the value
1090 referenced by ContentSize will contain the actual
1091 size of the content from signed file. If ContentSize
1092 indicates the caller-allocated buffer is too small
1093 to contain content, an error is returned, and
1094 ContentSize will be updated with the required size.
1095 This parameter must be 0 if Content is Null.
1097 @retval EFI_SUCCESS Content signature was verified against hash of
1098 content, the signer's certificate was not found in
1099 RevokedDb, and was found in AllowedDb or if in signer
1100 is found in both AllowedDb and RevokedDb, the
1101 signing was allowed by reference to TimeStampDb as
1102 described above, and no hash matching content hash
1103 was found in RevokedDb.
1104 @retval EFI_SECURITY_VIOLATION The SignedData buffer was correctly formatted but
1105 signer was in RevokedDb or not in AllowedDb. Also
1106 returned if matching content hash found in RevokedDb.
1107 @retval EFI_COMPROMISED_DATA Calculated hash differs from signed hash.
1108 @retval EFI_INVALID_PARAMETER SignedData is NULL or SignedDataSize is zero.
1110 @retval EFI_INVALID_PARAMETER Content is not NULL and ContentSize is NULL.
1111 @retval EFI_ABORTED Unsupported or invalid format in TimeStampDb,
1112 RevokedDb or AllowedDb list contents was detected.
1113 @retval EFI_NOT_FOUND Content not found because InData is NULL and no
1114 content embedded in SignedData.
1115 @retval EFI_UNSUPPORTED The SignedData buffer was not correctly formatted
1116 for processing by the function.
1117 @retval EFI_UNSUPPORTED Signed data embedded in SignedData but InData is not
1119 @retval EFI_BUFFER_TOO_SMALL The size of buffer indicated by ContentSize is too
1120 small to hold the content. ContentSize updated to
1127 IN EFI_PKCS7_VERIFY_PROTOCOL
*This
,
1128 IN VOID
*SignedData
,
1129 IN UINTN SignedDataSize
,
1130 IN VOID
*InData OPTIONAL
,
1131 IN UINTN InDataSize
,
1132 IN EFI_SIGNATURE_LIST
**AllowedDb
,
1133 IN EFI_SIGNATURE_LIST
**RevokedDb OPTIONAL
,
1134 IN EFI_SIGNATURE_LIST
**TimeStampDb OPTIONAL
,
1135 OUT VOID
*Content OPTIONAL
,
1136 IN OUT UINTN
*ContentSize
1140 EFI_SIGNATURE_LIST
*SigList
;
1142 UINT8
*AttachedData
;
1143 UINTN AttachedDataSize
;
1148 // Parameters Checking
1150 if ((SignedData
== NULL
) || (SignedDataSize
== 0) || (AllowedDb
== NULL
)) {
1151 return EFI_INVALID_PARAMETER
;
1153 if ((Content
!= NULL
) && (ContentSize
== NULL
)) {
1154 return EFI_INVALID_PARAMETER
;
1158 // Check if any invalid entry format in AllowedDb list contents
1160 for (Index
= 0; ; Index
++) {
1161 SigList
= (EFI_SIGNATURE_LIST
*)(AllowedDb
[Index
]);
1163 if (SigList
== NULL
) {
1166 if (SigList
->SignatureListSize
< sizeof (EFI_SIGNATURE_LIST
) +
1167 SigList
->SignatureHeaderSize
+
1168 SigList
->SignatureSize
) {
1174 // Check if any invalid entry format in RevokedDb list contents
1176 if (RevokedDb
!= NULL
) {
1177 for (Index
= 0; ; Index
++) {
1178 SigList
= (EFI_SIGNATURE_LIST
*)(RevokedDb
[Index
]);
1180 if (SigList
== NULL
) {
1183 if (SigList
->SignatureListSize
< sizeof (EFI_SIGNATURE_LIST
) +
1184 SigList
->SignatureHeaderSize
+
1185 SigList
->SignatureSize
) {
1192 // Check if any invalid entry format in TimeStampDb list contents
1194 if (TimeStampDb
!= NULL
) {
1195 for (Index
= 0; ; Index
++) {
1196 SigList
= (EFI_SIGNATURE_LIST
*)(TimeStampDb
[Index
]);
1198 if (SigList
== NULL
) {
1201 if (SigList
->SignatureListSize
< sizeof (EFI_SIGNATURE_LIST
) +
1202 SigList
->SignatureHeaderSize
+
1203 SigList
->SignatureSize
) {
1210 // Try to retrieve the attached content from PKCS7 signedData
1212 AttachedData
= NULL
;
1213 AttachedDataSize
= 0;
1214 if (!Pkcs7GetAttachedContent (
1217 (VOID
**)&AttachedData
,
1218 &AttachedDataSize
)) {
1220 // The SignedData buffer was not correctly formatted for processing
1222 return EFI_UNSUPPORTED
;
1224 if (AttachedData
!= NULL
) {
1225 if (InData
!= NULL
) {
1227 // The embedded content is found in SignedData but InData is not NULL
1229 Status
= EFI_UNSUPPORTED
;
1233 // PKCS7-formatted signedData with attached content; Use the embedded
1234 // content for verification
1236 DataPtr
= AttachedData
;
1237 DataSize
= AttachedDataSize
;
1239 } else if (InData
!= NULL
) {
1241 // PKCS7-formatted signedData with detached content; Use the user-supplied
1242 // input data for verification
1244 DataPtr
= (UINT8
*)InData
;
1245 DataSize
= InDataSize
;
1248 // Content not found because InData is NULL and no content attached in SignedData
1250 Status
= EFI_NOT_FOUND
;
1254 Status
= EFI_UNSUPPORTED
;
1257 // Verify PKCS7 SignedData with Revoked database
1259 if (RevokedDb
!= NULL
) {
1260 Status
= P7CheckRevocation (
1268 if (!EFI_ERROR (Status
)) {
1270 // The PKCS7 SignedData is reovked
1272 Status
= EFI_SECURITY_VIOLATION
;
1278 // Verify PKCS7 SignedData with AllowedDB
1280 Status
= P7CheckTrust (
1287 if (EFI_ERROR (Status
)) {
1289 // Verification failed with AllowedDb
1295 // Copy the content portion after verification succeeds
1297 if (Content
!= NULL
) {
1298 if (*ContentSize
< DataSize
) {
1300 // Caller-allocated buffer is too small to contain content
1302 *ContentSize
= DataSize
;
1303 Status
= EFI_BUFFER_TOO_SMALL
;
1305 *ContentSize
= DataSize
;
1306 CopyMem (Content
, DataPtr
, DataSize
);
1311 if (AttachedData
!= NULL
) {
1312 FreePool (AttachedData
);
1319 Processes a buffer containing binary DER-encoded detached PKCS7 signature.
1320 The hash of the signed data content is calculated and passed by the caller. Function
1321 verifies the signature of the content is valid and signing certificate was not revoked
1322 and is contained within a list of trusted signers.
1324 Note: because this function uses hashes and the specification contains a variety of
1325 hash choices, you should be aware that the check against the RevokedDb list
1326 will improperly succeed if the signature is revoked using a different hash
1327 algorithm. For this reason, you should either cycle through all UEFI supported
1328 hashes to see if one is forbidden, or rely on a single hash choice only if the
1329 UEFI signature authority only signs and revokes with a single hash (at time
1330 of writing, this hash choice is SHA256).
1332 @param[in] This Pointer to EFI_PKCS7_VERIFY_PROTOCOL instance.
1333 @param[in] Signature Points to buffer containing ASN.1 DER-encoded PKCS
1335 @param[in] SignatureSize The size of Signature buffer in bytes.
1336 @param[in] InHash InHash points to buffer containing the caller
1337 calculated hash of the data. The parameter may not
1339 @param[in] InHashSize The size in bytes of InHash buffer.
1340 @param[in] AllowedDb Pointer to a list of pointers to EFI_SIGNATURE_LIST
1341 structures. The list is terminated by a null
1342 pointer. The EFI_SIGNATURE_LIST structures contain
1343 lists of X.509 certificates of approved signers.
1344 Function recognizes signer certificates of type
1345 EFI_CERT_X509_GUID. Any hash certificate in AllowedDb
1346 list is ignored by this function. Function returns
1347 success if signer of the buffer is within this list
1348 (and not within RevokedDb). This parameter is
1350 @param[in] RevokedDb Optional pointer to a list of pointers to
1351 EFI_SIGNATURE_LIST structures. The list is terminated
1352 by a null pointer. List of X.509 certificates of
1353 revoked signers and revoked file hashes. Signature
1354 verification will always fail if the signer of the
1355 file or the hash of the data component of the buffer
1356 is in RevokedDb list. This parameter is optional
1357 and caller may pass Null if not required.
1358 @param[in] TimeStampDb Optional pointer to a list of pointers to
1359 EFI_SIGNATURE_LIST structures. The list is terminated
1360 by a null pointer. This parameter can be used to pass
1361 a list of X.509 certificates of trusted time stamp
1364 @retval EFI_SUCCESS Signed hash was verified against caller-provided
1365 hash of content, the signer's certificate was not
1366 found in RevokedDb, and was found in AllowedDb or
1367 if in signer is found in both AllowedDb and
1368 RevokedDb, the signing was allowed by reference to
1369 TimeStampDb as described above, and no hash matching
1370 content hash was found in RevokedDb.
1371 @retval EFI_SECURITY_VIOLATION The SignedData buffer was correctly formatted but
1372 signer was in RevokedDb or not in AllowedDb. Also
1373 returned if matching content hash found in RevokedDb.
1374 @retval EFI_COMPROMISED_DATA Caller provided hash differs from signed hash. Or,
1375 caller and encrypted hash are different sizes.
1376 @retval EFI_INVALID_PARAMETER Signature is NULL or SignatureSize is zero. InHash
1377 is NULL or InHashSize is zero. AllowedDb is NULL.
1378 @retval EFI_ABORTED Unsupported or invalid format in TimeStampDb,
1379 RevokedDb or AllowedDb list contents was detected.
1380 @retval EFI_UNSUPPORTED The Signature buffer was not correctly formatted
1381 for processing by the function.
1387 IN EFI_PKCS7_VERIFY_PROTOCOL
*This
,
1389 IN UINTN SignatureSize
,
1391 IN UINTN InHashSize
,
1392 IN EFI_SIGNATURE_LIST
**AllowedDb
,
1393 IN EFI_SIGNATURE_LIST
**RevokedDb OPTIONAL
,
1394 IN EFI_SIGNATURE_LIST
**TimeStampDb OPTIONAL
1400 // Parameters Checking
1402 if ((Signature
== NULL
) || (SignatureSize
== 0) || (AllowedDb
== NULL
)
1403 || (InHash
== NULL
) || (InHashSize
== 0)) {
1404 return EFI_INVALID_PARAMETER
;
1408 // Verify PKCS7 SignedData with Revoked database
1410 if (RevokedDb
!= NULL
) {
1411 Status
= P7CheckRevocationByHash (
1420 if (!EFI_ERROR (Status
)) {
1422 // The PKCS7 SignedData is reovked
1424 return EFI_SECURITY_VIOLATION
;
1429 // Verify PKCS7 SignedData with AllowedDB
1431 Status
= P7CheckTrustByHash (
1443 // The PKCS7 Verification Protocol
1445 EFI_PKCS7_VERIFY_PROTOCOL mPkcs7Verify
= {
1451 The user Entry Point for the PKCS7 Verification driver.
1453 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1454 @param[in] SystemTable A pointer to the EFI System Table.
1456 @retval EFI_SUCCESS The entry point is executed successfully.
1457 @retval EFI_NOT_SUPPORTED Platform does not support PKCS7 Verification.
1458 @retval Other Some error occurs when executing this entry point.
1463 Pkcs7VerifyDriverEntry (
1464 IN EFI_HANDLE ImageHandle
,
1465 IN EFI_SYSTEM_TABLE
*SystemTable
1470 EFI_PKCS7_VERIFY_PROTOCOL Useless
;
1473 // Avoid loading a second copy if this is built as an external module
1475 Status
= gBS
->LocateProtocol (&gEfiPkcs7VerifyProtocolGuid
, NULL
, (VOID
**)&Useless
);
1476 if (!EFI_ERROR (Status
)) {
1481 // Install UEFI Pkcs7 Verification Protocol
1484 Status
= gBS
->InstallMultipleProtocolInterfaces (
1486 &gEfiPkcs7VerifyProtocolGuid
,