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 SPDX-License-Identifier: BSD-2-Clause-Patent
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>
20 #define MAX_DIGEST_SIZE SHA512_DIGEST_SIZE
23 Calculates the hash of the given data based on the specified hash GUID.
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.
30 @retval TRUE Data hash calculation succeeded.
31 @retval FALSE Data hash calculation failed.
38 IN EFI_GUID
*CertGuid
,
49 if (CompareGuid (CertGuid
, &gEfiCertSha1Guid
)) {
53 CtxSize
= Sha1GetContextSize ();
54 HashCtx
= AllocatePool (CtxSize
);
55 if (HashCtx
== NULL
) {
58 Status
= Sha1Init (HashCtx
);
59 Status
= Sha1Update (HashCtx
, Data
, DataSize
);
60 Status
= Sha1Final (HashCtx
, HashValue
);
62 } else if (CompareGuid (CertGuid
, &gEfiCertSha256Guid
)) {
66 CtxSize
= Sha256GetContextSize ();
67 HashCtx
= AllocatePool (CtxSize
);
68 if (HashCtx
== NULL
) {
71 Status
= Sha256Init (HashCtx
);
72 Status
= Sha256Update (HashCtx
, Data
, DataSize
);
73 Status
= Sha256Final (HashCtx
, HashValue
);
75 } else if (CompareGuid (CertGuid
, &gEfiCertSha384Guid
)) {
79 CtxSize
= Sha384GetContextSize ();
80 HashCtx
= AllocatePool (CtxSize
);
81 if (HashCtx
== NULL
) {
84 Status
= Sha384Init (HashCtx
);
85 Status
= Sha384Update (HashCtx
, Data
, DataSize
);
86 Status
= Sha384Final (HashCtx
, HashValue
);
88 } else if (CompareGuid (CertGuid
, &gEfiCertSha512Guid
)) {
92 CtxSize
= Sha512GetContextSize ();
93 HashCtx
= AllocatePool (CtxSize
);
94 if (HashCtx
== NULL
) {
97 Status
= Sha512Init (HashCtx
);
98 Status
= Sha512Update (HashCtx
, Data
, DataSize
);
99 Status
= Sha512Final (HashCtx
, HashValue
);
103 if (HashCtx
!= NULL
) {
111 Check whether the hash of data content is revoked by the revocation database.
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.
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.
124 IsContentHashRevokedByHash (
127 IN EFI_SIGNATURE_LIST
**RevokedDb
130 EFI_SIGNATURE_LIST
*SigList
;
131 EFI_SIGNATURE_DATA
*SigData
;
137 if (RevokedDb
== NULL
) {
143 // Check if any hash matching content hash can be found in RevokedDB
145 for (Index
= 0; ; Index
++) {
146 SigList
= (EFI_SIGNATURE_LIST
*)(RevokedDb
[Index
]);
149 // The list is terminated by a NULL pointer.
151 if (SigList
== NULL
) {
156 // Search the signature database to search the revoked content hash
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
++) {
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.
168 if (SigList
->SignatureSize
- sizeof(EFI_GUID
) == HashSize
) {
170 // Compare Data Hash with Signature Data
172 if (CompareMem (SigData
->SignatureData
, Hash
, HashSize
) == 0) {
178 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigData
+ SigList
->SignatureSize
);
187 Check whether the hash of data content is revoked by the revocation database.
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.
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.
200 IsContentHashRevoked (
202 IN UINTN ContentSize
,
203 IN EFI_SIGNATURE_LIST
**RevokedDb
206 EFI_SIGNATURE_LIST
*SigList
;
207 EFI_SIGNATURE_DATA
*SigData
;
209 UINT8 HashVal
[MAX_DIGEST_SIZE
];
214 if (RevokedDb
== NULL
) {
220 // Check if any hash matching content hash can be found in RevokedDB
222 for (Index
= 0; ; Index
++) {
223 SigList
= (EFI_SIGNATURE_LIST
*)(RevokedDb
[Index
]);
226 // The list is terminated by a NULL pointer.
228 if (SigList
== NULL
) {
233 // Calculate the digest of supplied data based on the signature hash type.
235 if (!CalculateDataHash (Content
, ContentSize
, &SigList
->SignatureType
, HashVal
)) {
237 // Un-matched Hash GUID or other failure.
243 // Search the signature database to search the revoked content hash
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
++) {
251 // Compare Data Hash with Signature Data
253 if (CompareMem (SigData
->SignatureData
, HashVal
, (SigList
->SignatureSize
- sizeof (EFI_GUID
))) == 0) {
258 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigData
+ SigList
->SignatureSize
);
267 Check whether the hash of an given certificate is revoked by the revocation database.
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.
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.
282 IN UINT8
*Certificate
,
284 IN EFI_SIGNATURE_LIST
**RevokedDb
,
285 OUT EFI_TIME
*RevocationTime
289 EFI_SIGNATURE_LIST
*SigList
;
290 EFI_SIGNATURE_DATA
*SigData
;
296 UINT8 CertHashVal
[MAX_DIGEST_SIZE
];
298 if ((RevocationTime
== NULL
) || (RevokedDb
== NULL
)) {
303 // Retrieve the TBSCertificate from the X.509 Certificate for hash calculation
305 if (!X509GetTBSCert (Certificate
, CertSize
, &TBSCert
, &TBSCertSize
)) {
310 for (Index
= 0; ; Index
++) {
312 SigList
= (EFI_SIGNATURE_LIST
*)(RevokedDb
[Index
]);
314 // The list is terminated by a NULL pointer.
316 if (SigList
== NULL
) {
321 // Determine Hash Algorithm based on the entry type in revocation database, and
322 // calculate the certificate hash.
324 if (CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Sha256Guid
)) {
325 Status
= CalculateDataHash (TBSCert
, TBSCertSize
, &gEfiCertSha256Guid
, CertHashVal
);
327 } else if (CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Sha384Guid
)) {
328 Status
= CalculateDataHash (TBSCert
, TBSCertSize
, &gEfiCertSha384Guid
, CertHashVal
);
330 } else if (CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Sha512Guid
)) {
331 Status
= CalculateDataHash (TBSCert
, TBSCertSize
, &gEfiCertSha512Guid
, CertHashVal
);
335 // Un-matched Cert Hash GUID
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
++) {
350 // Check if the Certificate Hash is revoked.
352 if (CompareMem (SigData
->SignatureData
, CertHashVal
,
353 SigList
->SignatureSize
- sizeof (EFI_GUID
) - sizeof (EFI_TIME
)) == 0) {
356 // Return the revocation time of this revoked certificate.
360 (EFI_TIME
*)((UINT8
*)SigData
+ SigList
->SignatureSize
- sizeof (EFI_TIME
)),
366 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigData
+ SigList
->SignatureSize
);
375 Check if the given time value is zero.
377 @param[in] Time Pointer of a time value.
379 @retval TRUE The Time is Zero.
380 @retval FALSE The Time is not Zero.
388 if ((Time
->Year
== 0) && (Time
->Month
== 0) && (Time
->Day
== 0) &&
389 (Time
->Hour
== 0) && (Time
->Minute
== 0) && (Time
->Second
== 0)) {
397 Check whether the timestamp is valid by comparing the signing time and the revocation time.
399 @param SigningTime Pointer to the signing time.
400 @param RevocationTime Pointer to the revocation time.
402 @retval TRUE The SigningTime is not later than the RevocationTime.
403 @retval FALSE The SigningTime is later than the RevocationTime.
408 IN EFI_TIME
*SigningTime
,
409 IN EFI_TIME
*RevocationTime
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
);
424 return (BOOLEAN
) (SigningTime
->Second
<= RevocationTime
->Second
);
428 Check whether the timestamp signature embedded in PKCS7 signedData is valid and
429 the signing time is also earlier than the revocation time.
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.
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.
446 IN UINT8
*SignedData
,
447 IN UINTN SignedDataSize
,
448 IN EFI_SIGNATURE_LIST
**TimeStampDb
,
449 IN EFI_TIME
*RevocationTime
453 EFI_SIGNATURE_LIST
*SigList
;
454 EFI_SIGNATURE_DATA
*SigData
;
458 EFI_TIME SigningTime
;
461 // If no supplied database for verification or RevocationTime is zero,
462 // the certificate shall be considered to always be revoked.
464 if ((TimeStampDb
== NULL
) || (IsTimeZero (RevocationTime
))) {
470 // RevocationTime is non-zero, the certificate should be considered to be revoked
471 // from that time and onwards.
473 for (Index
= 0; ; Index
++) {
474 SigList
= (EFI_SIGNATURE_LIST
*) (TimeStampDb
[Index
]);
477 // The list is terminated by a NULL pointer.
479 if (SigList
== NULL
) {
484 // Ignore any non-X509-format entry in the list
486 if (!CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Guid
)) {
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
);
497 // Each TSA Certificate will normally be in a seperate EFI_SIGNATURE_LIST
498 // Leverage ImageTimestampVerify interface for Timestamp counterSignature Verification
500 if (ImageTimestampVerify (SignedData
, SignedDataSize
, TsaCert
, TsaCertSize
, &SigningTime
)) {
502 // The signer signature is valid only when the signing time is earlier than revocation time.
504 if (CompareTimestamp (&SigningTime
, RevocationTime
)) {
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.
519 @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7
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.
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.
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.
543 P7CheckRevocationByHash (
544 IN UINT8
*SignedData
,
545 IN UINTN SignedDataSize
,
548 IN EFI_SIGNATURE_LIST
**RevokedDb
,
549 IN EFI_SIGNATURE_LIST
**TimeStampDb
553 EFI_SIGNATURE_LIST
*SigList
;
554 EFI_SIGNATURE_DATA
*SigData
;
556 UINTN RevokedCertSize
;
561 UINTN TrustedCertLength
;
566 EFI_TIME RevocationTime
;
568 Status
= EFI_SECURITY_VIOLATION
;
576 // The signedData is revoked if the hash of content existed in RevokedDb
578 if (IsContentHashRevokedByHash (InHash
, InHashSize
, RevokedDb
)) {
579 Status
= EFI_SUCCESS
;
584 // Check if the signer's certificate can be found in Revoked database
586 for (Index
= 0; ; Index
++) {
587 SigList
= (EFI_SIGNATURE_LIST
*)(RevokedDb
[Index
]);
590 // The list is terminated by a NULL pointer.
592 if (SigList
== NULL
) {
597 // Ignore any non-X509-format entry in the list.
599 if (!CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Guid
)) {
603 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigList
+ sizeof (EFI_SIGNATURE_LIST
) +
604 SigList
->SignatureHeaderSize
);
606 RevokedCert
= SigData
->SignatureData
;
607 RevokedCertSize
= SigList
->SignatureSize
- sizeof (EFI_GUID
);
610 // Verifying the PKCS#7 SignedData with the revoked certificate in RevokedDb
612 if (AuthenticodeVerify (SignedData
, SignedDataSize
, RevokedCert
, RevokedCertSize
, InHash
, InHashSize
)) {
614 // The signedData was verified by one entry in Revoked Database
616 Status
= EFI_SUCCESS
;
621 if (!EFI_ERROR (Status
)) {
623 // The signedData was revoked, since it was hit by RevokedDb
629 // Now we will continue to check the X.509 Certificate Hash & Possible Timestamp
631 if ((TimeStampDb
== NULL
) || (*TimeStampDb
== NULL
)) {
635 Pkcs7GetSigners (SignedData
, SignedDataSize
, &CertBuffer
, &BufferLength
, &TrustedCert
, &TrustedCertLength
);
636 if ((BufferLength
== 0) || (CertBuffer
== NULL
)) {
637 Status
= EFI_SUCCESS
;
642 // Check if any hash of certificates embedded in P7 data is in the revoked database.
644 CertNumber
= (UINT8
) (*CertBuffer
);
645 CertPtr
= CertBuffer
+ 1;
646 for (Index
= 0; Index
< CertNumber
; Index
++) {
648 // Retrieve the Certificate data
650 CertSize
= (UINTN
) ReadUnaligned32 ((UINT32
*) CertPtr
);
651 Cert
= (UINT8
*)CertPtr
+ sizeof (UINT32
);
653 if (IsCertHashRevoked (Cert
, CertSize
, RevokedDb
, &RevocationTime
)) {
655 // Check the timestamp signature and signing time to determine if p7 data can be trusted.
657 Status
= EFI_SUCCESS
;
658 if (IsValidTimestamp (SignedData
, SignedDataSize
, TimeStampDb
, &RevocationTime
)) {
660 // Use EFI_NOT_READY to identify the P7Data is not reovked, because the timestamping
661 // occured prior to the time of certificate revocation.
663 Status
= EFI_NOT_READY
;
669 CertPtr
= CertPtr
+ sizeof (UINT32
) + CertSize
;
673 Pkcs7FreeSigners (CertBuffer
);
674 Pkcs7FreeSigners (TrustedCert
);
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.
684 @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7
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.
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.
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.
709 IN UINT8
*SignedData
,
710 IN UINTN SignedDataSize
,
713 IN EFI_SIGNATURE_LIST
**RevokedDb
,
714 IN EFI_SIGNATURE_LIST
**TimeStampDb
718 EFI_SIGNATURE_LIST
*SigList
;
719 EFI_SIGNATURE_DATA
*SigData
;
721 UINTN RevokedCertSize
;
726 UINTN TrustedCertLength
;
731 EFI_TIME RevocationTime
;
733 Status
= EFI_UNSUPPORTED
;
741 // The signedData is revoked if the hash of content existed in RevokedDb
743 if (IsContentHashRevoked (InData
, InDataSize
, RevokedDb
)) {
744 Status
= EFI_SUCCESS
;
749 // Check if the signer's certificate can be found in Revoked database
751 for (Index
= 0; ; Index
++) {
752 SigList
= (EFI_SIGNATURE_LIST
*)(RevokedDb
[Index
]);
755 // The list is terminated by a NULL pointer.
757 if (SigList
== NULL
) {
762 // Ignore any non-X509-format entry in the list.
764 if (!CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Guid
)) {
768 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigList
+ sizeof (EFI_SIGNATURE_LIST
) +
769 SigList
->SignatureHeaderSize
);
771 RevokedCert
= SigData
->SignatureData
;
772 RevokedCertSize
= SigList
->SignatureSize
- sizeof (EFI_GUID
);
775 // Verifying the PKCS#7 SignedData with the revoked certificate in RevokedDb
777 if (Pkcs7Verify (SignedData
, SignedDataSize
, RevokedCert
, RevokedCertSize
, InData
, InDataSize
)) {
779 // The signedData was verified by one entry in Revoked Database
781 Status
= EFI_SUCCESS
;
786 if (!EFI_ERROR (Status
)) {
788 // The signedData was revoked, since it was hit by RevokedDb
794 // Now we will continue to check the X.509 Certificate Hash & Possible Timestamp
796 if ((TimeStampDb
== NULL
) || (*TimeStampDb
== NULL
)) {
800 Pkcs7GetSigners (SignedData
, SignedDataSize
, &CertBuffer
, &BufferLength
, &TrustedCert
, &TrustedCertLength
);
801 if ((BufferLength
== 0) || (CertBuffer
== NULL
)) {
802 Status
= EFI_SUCCESS
;
807 // Check if any hash of certificates embedded in P7 data is in the revoked database.
809 CertNumber
= (UINT8
) (*CertBuffer
);
810 CertPtr
= CertBuffer
+ 1;
811 for (Index
= 0; Index
< CertNumber
; Index
++) {
813 // Retrieve the Certificate data
815 CertSize
= (UINTN
) ReadUnaligned32 ((UINT32
*) CertPtr
);
816 Cert
= (UINT8
*)CertPtr
+ sizeof (UINT32
);
818 if (IsCertHashRevoked (Cert
, CertSize
, RevokedDb
, &RevocationTime
)) {
820 // Check the timestamp signature and signing time to determine if p7 data can be trusted.
822 Status
= EFI_SUCCESS
;
823 if (IsValidTimestamp (SignedData
, SignedDataSize
, TimeStampDb
, &RevocationTime
)) {
825 // Use EFI_NOT_READY to identify the P7Data is not reovked, because the timestamping
826 // occured prior to the time of certificate revocation.
828 Status
= EFI_NOT_READY
;
834 CertPtr
= CertPtr
+ sizeof (UINT32
) + CertSize
;
838 Pkcs7FreeSigners (CertBuffer
);
839 Pkcs7FreeSigners (TrustedCert
);
845 Check whether the PKCS7 signedData can be verified by the trusted certificates
846 database, and return the content of the signedData if requested.
848 @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7
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
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.
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
873 IN UINT8
*SignedData
,
874 IN UINTN SignedDataSize
,
877 IN EFI_SIGNATURE_LIST
**AllowedDb
881 EFI_SIGNATURE_LIST
*SigList
;
882 EFI_SIGNATURE_DATA
*SigData
;
887 Status
= EFI_SECURITY_VIOLATION
;
892 if (AllowedDb
== NULL
) {
893 return EFI_INVALID_PARAMETER
;
897 // Build Certificate Stack with all valid X509 certificates in the supplied
898 // Signature List for PKCS7 Verification.
900 for (Index
= 0; ; Index
++) {
901 SigList
= (EFI_SIGNATURE_LIST
*)(AllowedDb
[Index
]);
904 // The list is terminated by a NULL pointer.
906 if (SigList
== NULL
) {
911 // Ignore any non-X509-format entry in the list.
913 if (!CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Guid
)) {
917 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigList
+ sizeof (EFI_SIGNATURE_LIST
) +
918 SigList
->SignatureHeaderSize
);
920 TrustCert
= SigData
->SignatureData
;
921 TrustCertSize
= SigList
->SignatureSize
- sizeof (EFI_GUID
);
924 // Verifying the PKCS#7 SignedData with the trusted certificate from AllowedDb
926 if (AuthenticodeVerify (SignedData
, SignedDataSize
, TrustCert
, TrustCertSize
, InHash
, InHashSize
)) {
928 // The SignedData was verified successfully by one entry in Trusted Database
930 Status
= EFI_SUCCESS
;
939 Check whether the PKCS7 signedData can be verified by the trusted certificates
940 database, and return the content of the signedData if requested.
942 @param[in] SignedData Pointer to buffer containing ASN.1 DER-encoded PKCS7
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
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.
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
967 IN UINT8
*SignedData
,
968 IN UINTN SignedDataSize
,
971 IN EFI_SIGNATURE_LIST
**AllowedDb
975 EFI_SIGNATURE_LIST
*SigList
;
976 EFI_SIGNATURE_DATA
*SigData
;
981 Status
= EFI_SECURITY_VIOLATION
;
986 if (AllowedDb
== NULL
) {
987 return EFI_INVALID_PARAMETER
;
991 // Build Certificate Stack with all valid X509 certificates in the supplied
992 // Signature List for PKCS7 Verification.
994 for (Index
= 0; ; Index
++) {
995 SigList
= (EFI_SIGNATURE_LIST
*)(AllowedDb
[Index
]);
998 // The list is terminated by a NULL pointer.
1000 if (SigList
== NULL
) {
1005 // Ignore any non-X509-format entry in the list.
1007 if (!CompareGuid (&SigList
->SignatureType
, &gEfiCertX509Guid
)) {
1011 SigData
= (EFI_SIGNATURE_DATA
*) ((UINT8
*) SigList
+ sizeof (EFI_SIGNATURE_LIST
) +
1012 SigList
->SignatureHeaderSize
);
1014 TrustCert
= SigData
->SignatureData
;
1015 TrustCertSize
= SigList
->SignatureSize
- sizeof (EFI_GUID
);
1018 // Verifying the PKCS#7 SignedData with the trusted certificate from AllowedDb
1020 if (Pkcs7Verify (SignedData
, SignedDataSize
, TrustCert
, TrustCertSize
, InData
, InDataSize
)) {
1022 // The SignedData was verified successfully by one entry in Trusted Database
1024 Status
= EFI_SUCCESS
;
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.
1038 @param[in] This Pointer to EFI_PKCS7_VERIFY_PROTOCOL instance.
1039 @param[in] SignedData Points to buffer containing ASN.1 DER-encoded PKCS7
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
1047 @param[in] InDataSize When InData is used, the size of InData buffer in
1048 bytes. When InData is NULL. This parameter must be
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
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
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.
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.
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
1113 @retval EFI_BUFFER_TOO_SMALL The size of buffer indicated by ContentSize is too
1114 small to hold the content. ContentSize updated to
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
1134 EFI_SIGNATURE_LIST
*SigList
;
1136 UINT8
*AttachedData
;
1137 UINTN AttachedDataSize
;
1142 // Parameters Checking
1144 if ((SignedData
== NULL
) || (SignedDataSize
== 0) || (AllowedDb
== NULL
)) {
1145 return EFI_INVALID_PARAMETER
;
1147 if ((Content
!= NULL
) && (ContentSize
== NULL
)) {
1148 return EFI_INVALID_PARAMETER
;
1152 // Check if any invalid entry format in AllowedDb list contents
1154 for (Index
= 0; ; Index
++) {
1155 SigList
= (EFI_SIGNATURE_LIST
*)(AllowedDb
[Index
]);
1157 if (SigList
== NULL
) {
1160 if (SigList
->SignatureListSize
< sizeof (EFI_SIGNATURE_LIST
) +
1161 SigList
->SignatureHeaderSize
+
1162 SigList
->SignatureSize
) {
1168 // Check if any invalid entry format in RevokedDb list contents
1170 if (RevokedDb
!= NULL
) {
1171 for (Index
= 0; ; Index
++) {
1172 SigList
= (EFI_SIGNATURE_LIST
*)(RevokedDb
[Index
]);
1174 if (SigList
== NULL
) {
1177 if (SigList
->SignatureListSize
< sizeof (EFI_SIGNATURE_LIST
) +
1178 SigList
->SignatureHeaderSize
+
1179 SigList
->SignatureSize
) {
1186 // Check if any invalid entry format in TimeStampDb list contents
1188 if (TimeStampDb
!= NULL
) {
1189 for (Index
= 0; ; Index
++) {
1190 SigList
= (EFI_SIGNATURE_LIST
*)(TimeStampDb
[Index
]);
1192 if (SigList
== NULL
) {
1195 if (SigList
->SignatureListSize
< sizeof (EFI_SIGNATURE_LIST
) +
1196 SigList
->SignatureHeaderSize
+
1197 SigList
->SignatureSize
) {
1204 // Try to retrieve the attached content from PKCS7 signedData
1206 AttachedData
= NULL
;
1207 AttachedDataSize
= 0;
1208 if (!Pkcs7GetAttachedContent (
1211 (VOID
**)&AttachedData
,
1212 &AttachedDataSize
)) {
1214 // The SignedData buffer was not correctly formatted for processing
1216 return EFI_UNSUPPORTED
;
1218 if (AttachedData
!= NULL
) {
1219 if (InData
!= NULL
) {
1221 // The embedded content is found in SignedData but InData is not NULL
1223 Status
= EFI_UNSUPPORTED
;
1227 // PKCS7-formatted signedData with attached content; Use the embedded
1228 // content for verification
1230 DataPtr
= AttachedData
;
1231 DataSize
= AttachedDataSize
;
1233 } else if (InData
!= NULL
) {
1235 // PKCS7-formatted signedData with detached content; Use the user-supplied
1236 // input data for verification
1238 DataPtr
= (UINT8
*)InData
;
1239 DataSize
= InDataSize
;
1242 // Content not found because InData is NULL and no content attached in SignedData
1244 Status
= EFI_NOT_FOUND
;
1248 Status
= EFI_UNSUPPORTED
;
1251 // Verify PKCS7 SignedData with Revoked database
1253 if (RevokedDb
!= NULL
) {
1254 Status
= P7CheckRevocation (
1262 if (!EFI_ERROR (Status
)) {
1264 // The PKCS7 SignedData is reovked
1266 Status
= EFI_SECURITY_VIOLATION
;
1272 // Verify PKCS7 SignedData with AllowedDB
1274 Status
= P7CheckTrust (
1281 if (EFI_ERROR (Status
)) {
1283 // Verification failed with AllowedDb
1289 // Copy the content portion after verification succeeds
1291 if (Content
!= NULL
) {
1292 if (*ContentSize
< DataSize
) {
1294 // Caller-allocated buffer is too small to contain content
1296 *ContentSize
= DataSize
;
1297 Status
= EFI_BUFFER_TOO_SMALL
;
1299 *ContentSize
= DataSize
;
1300 CopyMem (Content
, DataPtr
, DataSize
);
1305 if (AttachedData
!= NULL
) {
1306 FreePool (AttachedData
);
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.
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).
1326 @param[in] This Pointer to EFI_PKCS7_VERIFY_PROTOCOL instance.
1327 @param[in] Signature Points to buffer containing ASN.1 DER-encoded PKCS
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
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
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
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.
1381 IN EFI_PKCS7_VERIFY_PROTOCOL
*This
,
1383 IN UINTN SignatureSize
,
1385 IN UINTN InHashSize
,
1386 IN EFI_SIGNATURE_LIST
**AllowedDb
,
1387 IN EFI_SIGNATURE_LIST
**RevokedDb OPTIONAL
,
1388 IN EFI_SIGNATURE_LIST
**TimeStampDb OPTIONAL
1394 // Parameters Checking
1396 if ((Signature
== NULL
) || (SignatureSize
== 0) || (AllowedDb
== NULL
)
1397 || (InHash
== NULL
) || (InHashSize
== 0)) {
1398 return EFI_INVALID_PARAMETER
;
1402 // Verify PKCS7 SignedData with Revoked database
1404 if (RevokedDb
!= NULL
) {
1405 Status
= P7CheckRevocationByHash (
1414 if (!EFI_ERROR (Status
)) {
1416 // The PKCS7 SignedData is reovked
1418 return EFI_SECURITY_VIOLATION
;
1423 // Verify PKCS7 SignedData with AllowedDB
1425 Status
= P7CheckTrustByHash (
1437 // The PKCS7 Verification Protocol
1439 EFI_PKCS7_VERIFY_PROTOCOL mPkcs7Verify
= {
1445 The user Entry Point for the PKCS7 Verification driver.
1447 @param[in] ImageHandle The firmware allocated handle for the EFI image.
1448 @param[in] SystemTable A pointer to the EFI System Table.
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.
1457 Pkcs7VerifyDriverEntry (
1458 IN EFI_HANDLE ImageHandle
,
1459 IN EFI_SYSTEM_TABLE
*SystemTable
1464 EFI_PKCS7_VERIFY_PROTOCOL Useless
;
1467 // Avoid loading a second copy if this is built as an external module
1469 Status
= gBS
->LocateProtocol (&gEfiPkcs7VerifyProtocolGuid
, NULL
, (VOID
**)&Useless
);
1470 if (!EFI_ERROR (Status
)) {
1475 // Install UEFI Pkcs7 Verification Protocol
1478 Status
= gBS
->InstallMultipleProtocolInterfaces (
1480 &gEfiPkcs7VerifyProtocolGuid
,