]>
Commit | Line | Data |
---|---|---|
0c18794e | 1 | /** @file\r |
3cd2484e | 2 | Implement image verification services for secure boot service\r |
0c18794e | 3 | \r |
dc204d5a JY |
4 | Caution: This file requires additional review when modified.\r |
5 | This library will have external input - PE/COFF image.\r | |
6 | This external input must be validated carefully to avoid security issue like\r | |
7 | buffer overflow, integer overflow.\r | |
8 | \r | |
9 | DxeImageVerificationLibImageRead() function will make sure the PE/COFF image content\r | |
10 | read is within the image buffer.\r | |
11 | \r | |
12 | DxeImageVerificationHandler(), HashPeImageByType(), HashPeImage() function will accept\r | |
13 | untrusted PE/COFF image and validate its data structure within this image buffer before use.\r | |
14 | \r | |
b3548d32 | 15 | Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>\r |
531c89a1 | 16 | (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r |
289b714b | 17 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
0c18794e | 18 | \r |
19 | **/\r | |
20 | \r | |
21 | #include "DxeImageVerificationLib.h"\r | |
22 | \r | |
dc204d5a JY |
23 | //\r |
24 | // Caution: This is used by a function which may receive untrusted input.\r | |
25 | // These global variables hold PE/COFF image data, and they should be validated before use.\r | |
26 | //\r | |
c411b485 MK |
27 | EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION mNtHeader;\r |
28 | UINT32 mPeCoffHeaderOffset;\r | |
29 | EFI_GUID mCertType;\r | |
0c18794e | 30 | \r |
dc204d5a JY |
31 | //\r |
32 | // Information on current PE/COFF image\r | |
33 | //\r | |
c411b485 MK |
34 | UINTN mImageSize;\r |
35 | UINT8 *mImageBase = NULL;\r | |
36 | UINT8 mImageDigest[MAX_DIGEST_SIZE];\r | |
37 | UINTN mImageDigestSize;\r | |
dc204d5a | 38 | \r |
0c18794e | 39 | //\r |
40 | // Notify string for authorization UI.\r | |
41 | //\r | |
42 | CHAR16 mNotifyString1[MAX_NOTIFY_STRING_LEN] = L"Image verification pass but not found in authorized database!";\r | |
43 | CHAR16 mNotifyString2[MAX_NOTIFY_STRING_LEN] = L"Launch this image anyway? (Yes/Defer/No)";\r | |
44 | //\r | |
45 | // Public Exponent of RSA Key.\r | |
46 | //\r | |
c411b485 | 47 | CONST UINT8 mRsaE[] = { 0x01, 0x00, 0x01 };\r |
0c18794e | 48 | \r |
49 | //\r | |
50 | // OID ASN.1 Value for Hash Algorithms\r | |
51 | //\r | |
c411b485 MK |
52 | UINT8 mHashOidValue[] = {\r |
53 | 0x2B, 0x0E, 0x03, 0x02, 0x1A, // OBJ_sha1\r | |
54 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, // OBJ_sha224\r | |
55 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, // OBJ_sha256\r | |
56 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, // OBJ_sha384\r | |
57 | 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, // OBJ_sha512\r | |
58 | };\r | |
59 | \r | |
60 | HASH_TABLE mHash[] = {\r | |
61 | #ifndef DISABLE_SHA1_DEPRECATED_INTERFACES\r | |
62 | { L"SHA1", 20, &mHashOidValue[0], 5, Sha1GetContextSize, Sha1Init, Sha1Update, Sha1Final },\r | |
63 | #else\r | |
64 | { L"SHA1", 20, &mHashOidValue[0], 5, NULL, NULL, NULL, NULL },\r | |
65 | #endif\r | |
66 | { L"SHA224", 28, &mHashOidValue[5], 9, NULL, NULL, NULL, NULL },\r | |
67 | { L"SHA256", 32, &mHashOidValue[14], 9, Sha256GetContextSize, Sha256Init, Sha256Update, Sha256Final },\r | |
68 | { L"SHA384", 48, &mHashOidValue[23], 9, Sha384GetContextSize, Sha384Init, Sha384Update, Sha384Final },\r | |
69 | { L"SHA512", 64, &mHashOidValue[32], 9, Sha512GetContextSize, Sha512Init, Sha512Update, Sha512Final }\r | |
0c18794e | 70 | };\r |
71 | \r | |
c411b485 | 72 | EFI_STRING mHashTypeStr;\r |
531c89a1 | 73 | \r |
c1d93242 JY |
74 | /**\r |
75 | SecureBoot Hook for processing image verification.\r | |
76 | \r | |
77 | @param[in] VariableName Name of Variable to be found.\r | |
78 | @param[in] VendorGuid Variable vendor GUID.\r | |
79 | @param[in] DataSize Size of Data found. If size is less than the\r | |
80 | data, this value contains the required size.\r | |
81 | @param[in] Data Data pointer.\r | |
82 | \r | |
83 | **/\r | |
84 | VOID\r | |
85 | EFIAPI\r | |
86 | SecureBootHook (\r | |
c411b485 MK |
87 | IN CHAR16 *VariableName,\r |
88 | IN EFI_GUID *VendorGuid,\r | |
89 | IN UINTN DataSize,\r | |
90 | IN VOID *Data\r | |
c1d93242 JY |
91 | );\r |
92 | \r | |
28186d45 ED |
93 | /**\r |
94 | Reads contents of a PE/COFF image in memory buffer.\r | |
95 | \r | |
dc204d5a JY |
96 | Caution: This function may receive untrusted input.\r |
97 | PE/COFF image is external input, so this function will make sure the PE/COFF image content\r | |
98 | read is within the image buffer.\r | |
99 | \r | |
28186d45 ED |
100 | @param FileHandle Pointer to the file handle to read the PE/COFF image.\r |
101 | @param FileOffset Offset into the PE/COFF image to begin the read operation.\r | |
20333c6d | 102 | @param ReadSize On input, the size in bytes of the requested read operation.\r |
28186d45 ED |
103 | On output, the number of bytes actually read.\r |
104 | @param Buffer Output buffer that contains the data read from the PE/COFF image.\r | |
20333c6d QL |
105 | \r |
106 | @retval EFI_SUCCESS The specified portion of the PE/COFF image was read and the size\r | |
28186d45 ED |
107 | **/\r |
108 | EFI_STATUS\r | |
109 | EFIAPI\r | |
e0192326 | 110 | DxeImageVerificationLibImageRead (\r |
c411b485 MK |
111 | IN VOID *FileHandle,\r |
112 | IN UINTN FileOffset,\r | |
113 | IN OUT UINTN *ReadSize,\r | |
114 | OUT VOID *Buffer\r | |
28186d45 ED |
115 | )\r |
116 | {\r | |
c411b485 | 117 | UINTN EndPosition;\r |
28186d45 | 118 | \r |
c411b485 | 119 | if ((FileHandle == NULL) || (ReadSize == NULL) || (Buffer == NULL)) {\r |
20333c6d | 120 | return EFI_INVALID_PARAMETER;\r |
28186d45 ED |
121 | }\r |
122 | \r | |
123 | if (MAX_ADDRESS - FileOffset < *ReadSize) {\r | |
124 | return EFI_INVALID_PARAMETER;\r | |
125 | }\r | |
126 | \r | |
127 | EndPosition = FileOffset + *ReadSize;\r | |
128 | if (EndPosition > mImageSize) {\r | |
129 | *ReadSize = (UINT32)(mImageSize - FileOffset);\r | |
130 | }\r | |
131 | \r | |
132 | if (FileOffset >= mImageSize) {\r | |
133 | *ReadSize = 0;\r | |
134 | }\r | |
135 | \r | |
c411b485 | 136 | CopyMem (Buffer, (UINT8 *)((UINTN)FileHandle + FileOffset), *ReadSize);\r |
28186d45 ED |
137 | \r |
138 | return EFI_SUCCESS;\r | |
139 | }\r | |
140 | \r | |
0c18794e | 141 | /**\r |
142 | Get the image type.\r | |
143 | \r | |
144 | @param[in] File This is a pointer to the device path of the file that is\r | |
45bf2c47 | 145 | being dispatched.\r |
0c18794e | 146 | \r |
45bf2c47 | 147 | @return UINT32 Image Type\r |
0c18794e | 148 | \r |
149 | **/\r | |
150 | UINT32\r | |
151 | GetImageType (\r | |
c411b485 | 152 | IN CONST EFI_DEVICE_PATH_PROTOCOL *File\r |
0c18794e | 153 | )\r |
154 | {\r | |
c411b485 MK |
155 | EFI_STATUS Status;\r |
156 | EFI_HANDLE DeviceHandle;\r | |
157 | EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;\r | |
158 | EFI_BLOCK_IO_PROTOCOL *BlockIo;\r | |
0c18794e | 159 | \r |
5db28a67 LG |
160 | if (File == NULL) {\r |
161 | return IMAGE_UNKNOWN;\r | |
162 | }\r | |
163 | \r | |
0c18794e | 164 | //\r |
165 | // First check to see if File is from a Firmware Volume\r | |
166 | //\r | |
c411b485 MK |
167 | DeviceHandle = NULL;\r |
168 | TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r | |
169 | Status = gBS->LocateDevicePath (\r | |
170 | &gEfiFirmwareVolume2ProtocolGuid,\r | |
171 | &TempDevicePath,\r | |
172 | &DeviceHandle\r | |
173 | );\r | |
0c18794e | 174 | if (!EFI_ERROR (Status)) {\r |
175 | Status = gBS->OpenProtocol (\r | |
176 | DeviceHandle,\r | |
177 | &gEfiFirmwareVolume2ProtocolGuid,\r | |
178 | NULL,\r | |
179 | NULL,\r | |
180 | NULL,\r | |
181 | EFI_OPEN_PROTOCOL_TEST_PROTOCOL\r | |
182 | );\r | |
183 | if (!EFI_ERROR (Status)) {\r | |
184 | return IMAGE_FROM_FV;\r | |
185 | }\r | |
186 | }\r | |
187 | \r | |
188 | //\r | |
189 | // Next check to see if File is from a Block I/O device\r | |
190 | //\r | |
191 | DeviceHandle = NULL;\r | |
c411b485 MK |
192 | TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r |
193 | Status = gBS->LocateDevicePath (\r | |
194 | &gEfiBlockIoProtocolGuid,\r | |
195 | &TempDevicePath,\r | |
196 | &DeviceHandle\r | |
197 | );\r | |
0c18794e | 198 | if (!EFI_ERROR (Status)) {\r |
199 | BlockIo = NULL;\r | |
c411b485 MK |
200 | Status = gBS->OpenProtocol (\r |
201 | DeviceHandle,\r | |
202 | &gEfiBlockIoProtocolGuid,\r | |
203 | (VOID **)&BlockIo,\r | |
204 | NULL,\r | |
205 | NULL,\r | |
206 | EFI_OPEN_PROTOCOL_GET_PROTOCOL\r | |
207 | );\r | |
208 | if (!EFI_ERROR (Status) && (BlockIo != NULL)) {\r | |
0c18794e | 209 | if (BlockIo->Media != NULL) {\r |
210 | if (BlockIo->Media->RemovableMedia) {\r | |
211 | //\r | |
212 | // Block I/O is present and specifies the media is removable\r | |
213 | //\r | |
214 | return IMAGE_FROM_REMOVABLE_MEDIA;\r | |
215 | } else {\r | |
216 | //\r | |
217 | // Block I/O is present and specifies the media is not removable\r | |
218 | //\r | |
219 | return IMAGE_FROM_FIXED_MEDIA;\r | |
220 | }\r | |
221 | }\r | |
222 | }\r | |
223 | }\r | |
224 | \r | |
225 | //\r | |
45bf2c47 | 226 | // File is not in a Firmware Volume or on a Block I/O device, so check to see if\r |
0c18794e | 227 | // the device path supports the Simple File System Protocol.\r |
228 | //\r | |
229 | DeviceHandle = NULL;\r | |
c411b485 MK |
230 | TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r |
231 | Status = gBS->LocateDevicePath (\r | |
232 | &gEfiSimpleFileSystemProtocolGuid,\r | |
233 | &TempDevicePath,\r | |
234 | &DeviceHandle\r | |
235 | );\r | |
0c18794e | 236 | if (!EFI_ERROR (Status)) {\r |
237 | //\r | |
238 | // Simple File System is present without Block I/O, so assume media is fixed.\r | |
239 | //\r | |
240 | return IMAGE_FROM_FIXED_MEDIA;\r | |
241 | }\r | |
242 | \r | |
243 | //\r | |
244 | // File is not from an FV, Block I/O or Simple File System, so the only options\r | |
45bf2c47 | 245 | // left are a PCI Option ROM and a Load File Protocol such as a PXE Boot from a NIC.\r |
0c18794e | 246 | //\r |
c411b485 | 247 | TempDevicePath = (EFI_DEVICE_PATH_PROTOCOL *)File;\r |
0c18794e | 248 | while (!IsDevicePathEndType (TempDevicePath)) {\r |
249 | switch (DevicePathType (TempDevicePath)) {\r | |
c411b485 MK |
250 | case MEDIA_DEVICE_PATH:\r |
251 | if (DevicePathSubType (TempDevicePath) == MEDIA_RELATIVE_OFFSET_RANGE_DP) {\r | |
252 | return IMAGE_FROM_OPTION_ROM;\r | |
253 | }\r | |
45bf2c47 | 254 | \r |
c411b485 | 255 | break;\r |
0c18794e | 256 | \r |
c411b485 MK |
257 | case MESSAGING_DEVICE_PATH:\r |
258 | if (DevicePathSubType (TempDevicePath) == MSG_MAC_ADDR_DP) {\r | |
259 | return IMAGE_FROM_REMOVABLE_MEDIA;\r | |
260 | }\r | |
0c18794e | 261 | \r |
c411b485 MK |
262 | break;\r |
263 | \r | |
264 | default:\r | |
265 | break;\r | |
0c18794e | 266 | }\r |
c411b485 | 267 | \r |
0c18794e | 268 | TempDevicePath = NextDevicePathNode (TempDevicePath);\r |
269 | }\r | |
c411b485 | 270 | \r |
45bf2c47 | 271 | return IMAGE_UNKNOWN;\r |
0c18794e | 272 | }\r |
273 | \r | |
274 | /**\r | |
69f8bb52 | 275 | Calculate hash of Pe/Coff image based on the authenticode image hashing in\r |
0c18794e | 276 | PE/COFF Specification 8.0 Appendix A\r |
b3548d32 | 277 | \r |
dc204d5a JY |
278 | Caution: This function may receive untrusted input.\r |
279 | PE/COFF image is external input, so this function will validate its data structure\r | |
280 | within this image buffer before use.\r | |
281 | \r | |
b3548d32 | 282 | Notes: PE/COFF image has been checked by BasePeCoffLib PeCoffLoaderGetImageInfo() in\r |
89fb5aef LG |
283 | its caller function DxeImageVerificationHandler().\r |
284 | \r | |
0c18794e | 285 | @param[in] HashAlg Hash algorithm type.\r |
45bf2c47 | 286 | \r |
0c18794e | 287 | @retval TRUE Successfully hash image.\r |
288 | @retval FALSE Fail in hash image.\r | |
289 | \r | |
290 | **/\r | |
45bf2c47 | 291 | BOOLEAN\r |
0c18794e | 292 | HashPeImage (\r |
c411b485 | 293 | IN UINT32 HashAlg\r |
0c18794e | 294 | )\r |
295 | {\r | |
296 | BOOLEAN Status;\r | |
0c18794e | 297 | EFI_IMAGE_SECTION_HEADER *Section;\r |
298 | VOID *HashCtx;\r | |
299 | UINTN CtxSize;\r | |
300 | UINT8 *HashBase;\r | |
301 | UINTN HashSize;\r | |
302 | UINTN SumOfBytesHashed;\r | |
303 | EFI_IMAGE_SECTION_HEADER *SectionHeader;\r | |
304 | UINTN Index;\r | |
305 | UINTN Pos;\r | |
551d8081 | 306 | UINT32 CertSize;\r |
307 | UINT32 NumberOfRvaAndSizes;\r | |
45bf2c47 | 308 | \r |
0c18794e | 309 | HashCtx = NULL;\r |
310 | SectionHeader = NULL;\r | |
311 | Status = FALSE;\r | |
312 | \r | |
20333c6d | 313 | if ((HashAlg >= HASHALG_MAX)) {\r |
0c18794e | 314 | return FALSE;\r |
315 | }\r | |
45bf2c47 | 316 | \r |
0c18794e | 317 | //\r |
318 | // Initialize context of hash.\r | |
319 | //\r | |
320 | ZeroMem (mImageDigest, MAX_DIGEST_SIZE);\r | |
321 | \r | |
20333c6d | 322 | switch (HashAlg) {\r |
c411b485 MK |
323 | #ifndef DISABLE_SHA1_DEPRECATED_INTERFACES\r |
324 | case HASHALG_SHA1:\r | |
325 | mImageDigestSize = SHA1_DIGEST_SIZE;\r | |
326 | mCertType = gEfiCertSha1Guid;\r | |
327 | break;\r | |
328 | #endif\r | |
329 | \r | |
330 | case HASHALG_SHA256:\r | |
331 | mImageDigestSize = SHA256_DIGEST_SIZE;\r | |
332 | mCertType = gEfiCertSha256Guid;\r | |
333 | break;\r | |
334 | \r | |
335 | case HASHALG_SHA384:\r | |
336 | mImageDigestSize = SHA384_DIGEST_SIZE;\r | |
337 | mCertType = gEfiCertSha384Guid;\r | |
338 | break;\r | |
339 | \r | |
340 | case HASHALG_SHA512:\r | |
341 | mImageDigestSize = SHA512_DIGEST_SIZE;\r | |
342 | mCertType = gEfiCertSha512Guid;\r | |
343 | break;\r | |
344 | \r | |
345 | default:\r | |
346 | return FALSE;\r | |
0c18794e | 347 | }\r |
348 | \r | |
531c89a1 | 349 | mHashTypeStr = mHash[HashAlg].Name;\r |
c411b485 | 350 | CtxSize = mHash[HashAlg].GetContextSize ();\r |
45bf2c47 | 351 | \r |
0c18794e | 352 | HashCtx = AllocatePool (CtxSize);\r |
570b3d1a | 353 | if (HashCtx == NULL) {\r |
354 | return FALSE;\r | |
355 | }\r | |
0c18794e | 356 | \r |
357 | // 1. Load the image header into memory.\r | |
358 | \r | |
359 | // 2. Initialize a SHA hash context.\r | |
c411b485 | 360 | Status = mHash[HashAlg].HashInit (HashCtx);\r |
45bf2c47 | 361 | \r |
0c18794e | 362 | if (!Status) {\r |
363 | goto Done;\r | |
364 | }\r | |
551d8081 | 365 | \r |
0c18794e | 366 | //\r |
367 | // Measuring PE/COFF Image Header;\r | |
368 | // But CheckSum field and SECURITY data directory (certificate) are excluded\r | |
369 | //\r | |
20333c6d | 370 | \r |
0c18794e | 371 | //\r |
372 | // 3. Calculate the distance from the base of the image header to the image checksum address.\r | |
373 | // 4. Hash the image header from its base to beginning of the image checksum.\r | |
374 | //\r | |
375 | HashBase = mImageBase;\r | |
f199664c | 376 | if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r |
0c18794e | 377 | //\r |
378 | // Use PE32 offset.\r | |
379 | //\r | |
c411b485 | 380 | HashSize = (UINTN)(&mNtHeader.Pe32->OptionalHeader.CheckSum) - (UINTN)HashBase;\r |
551d8081 | 381 | NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r |
f199664c | 382 | } else if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {\r |
0c18794e | 383 | //\r |
384 | // Use PE32+ offset.\r | |
385 | //\r | |
c411b485 | 386 | HashSize = (UINTN)(&mNtHeader.Pe32Plus->OptionalHeader.CheckSum) - (UINTN)HashBase;\r |
551d8081 | 387 | NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r |
570b3d1a | 388 | } else {\r |
389 | //\r | |
390 | // Invalid header magic number.\r | |
391 | //\r | |
392 | Status = FALSE;\r | |
393 | goto Done;\r | |
0c18794e | 394 | }\r |
395 | \r | |
c411b485 | 396 | Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize);\r |
0c18794e | 397 | if (!Status) {\r |
398 | goto Done;\r | |
399 | }\r | |
551d8081 | 400 | \r |
0c18794e | 401 | //\r |
402 | // 5. Skip over the image checksum (it occupies a single ULONG).\r | |
0c18794e | 403 | //\r |
551d8081 | 404 | if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r |
0c18794e | 405 | //\r |
551d8081 | 406 | // 6. Since there is no Cert Directory in optional header, hash everything\r |
407 | // from the end of the checksum to the end of image header.\r | |
0c18794e | 408 | //\r |
f199664c | 409 | if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r |
551d8081 | 410 | //\r |
411 | // Use PE32 offset.\r | |
412 | //\r | |
c411b485 MK |
413 | HashBase = (UINT8 *)&mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r |
414 | HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN)HashBase - (UINTN)mImageBase);\r | |
551d8081 | 415 | } else {\r |
416 | //\r | |
417 | // Use PE32+ offset.\r | |
418 | //\r | |
c411b485 MK |
419 | HashBase = (UINT8 *)&mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r |
420 | HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN)HashBase - (UINTN)mImageBase);\r | |
551d8081 | 421 | }\r |
422 | \r | |
423 | if (HashSize != 0) {\r | |
c411b485 | 424 | Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize);\r |
551d8081 | 425 | if (!Status) {\r |
426 | goto Done;\r | |
427 | }\r | |
428 | }\r | |
0c18794e | 429 | } else {\r |
430 | //\r | |
551d8081 | 431 | // 7. Hash everything from the end of the checksum to the start of the Cert Directory.\r |
45bf2c47 | 432 | //\r |
f199664c | 433 | if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r |
551d8081 | 434 | //\r |
435 | // Use PE32 offset.\r | |
436 | //\r | |
c411b485 MK |
437 | HashBase = (UINT8 *)&mNtHeader.Pe32->OptionalHeader.CheckSum + sizeof (UINT32);\r |
438 | HashSize = (UINTN)(&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase;\r | |
551d8081 | 439 | } else {\r |
440 | //\r | |
441 | // Use PE32+ offset.\r | |
442 | //\r | |
c411b485 MK |
443 | HashBase = (UINT8 *)&mNtHeader.Pe32Plus->OptionalHeader.CheckSum + sizeof (UINT32);\r |
444 | HashSize = (UINTN)(&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY]) - (UINTN)HashBase;\r | |
551d8081 | 445 | }\r |
446 | \r | |
447 | if (HashSize != 0) {\r | |
c411b485 | 448 | Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize);\r |
551d8081 | 449 | if (!Status) {\r |
450 | goto Done;\r | |
451 | }\r | |
452 | }\r | |
0c18794e | 453 | \r |
0c18794e | 454 | //\r |
551d8081 | 455 | // 8. Skip over the Cert Directory. (It is sizeof(IMAGE_DATA_DIRECTORY) bytes.)\r |
456 | // 9. Hash everything from the end of the Cert Directory to the end of image header.\r | |
0c18794e | 457 | //\r |
f199664c | 458 | if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r |
551d8081 | 459 | //\r |
460 | // Use PE32 offset\r | |
461 | //\r | |
c411b485 MK |
462 | HashBase = (UINT8 *)&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r |
463 | HashSize = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders - ((UINTN)HashBase - (UINTN)mImageBase);\r | |
551d8081 | 464 | } else {\r |
465 | //\r | |
466 | // Use PE32+ offset.\r | |
467 | //\r | |
c411b485 MK |
468 | HashBase = (UINT8 *)&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY + 1];\r |
469 | HashSize = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders - ((UINTN)HashBase - (UINTN)mImageBase);\r | |
551d8081 | 470 | }\r |
0c18794e | 471 | \r |
551d8081 | 472 | if (HashSize != 0) {\r |
c411b485 | 473 | Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize);\r |
551d8081 | 474 | if (!Status) {\r |
475 | goto Done;\r | |
476 | }\r | |
20333c6d | 477 | }\r |
0c18794e | 478 | }\r |
551d8081 | 479 | \r |
0c18794e | 480 | //\r |
481 | // 10. Set the SUM_OF_BYTES_HASHED to the size of the header.\r | |
482 | //\r | |
f199664c | 483 | if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r |
0c18794e | 484 | //\r |
485 | // Use PE32 offset.\r | |
486 | //\r | |
487 | SumOfBytesHashed = mNtHeader.Pe32->OptionalHeader.SizeOfHeaders;\r | |
488 | } else {\r | |
489 | //\r | |
490 | // Use PE32+ offset\r | |
491 | //\r | |
492 | SumOfBytesHashed = mNtHeader.Pe32Plus->OptionalHeader.SizeOfHeaders;\r | |
493 | }\r | |
494 | \r | |
c411b485 MK |
495 | Section = (EFI_IMAGE_SECTION_HEADER *)(\r |
496 | mImageBase +\r | |
497 | mPeCoffHeaderOffset +\r | |
498 | sizeof (UINT32) +\r | |
499 | sizeof (EFI_IMAGE_FILE_HEADER) +\r | |
500 | mNtHeader.Pe32->FileHeader.SizeOfOptionalHeader\r | |
501 | );\r | |
570b3d1a | 502 | \r |
0c18794e | 503 | //\r |
504 | // 11. Build a temporary table of pointers to all the IMAGE_SECTION_HEADER\r | |
505 | // structures in the image. The 'NumberOfSections' field of the image\r | |
506 | // header indicates how big the table should be. Do not include any\r | |
507 | // IMAGE_SECTION_HEADERs in the table whose 'SizeOfRawData' field is zero.\r | |
508 | //\r | |
c411b485 | 509 | SectionHeader = (EFI_IMAGE_SECTION_HEADER *)AllocateZeroPool (sizeof (EFI_IMAGE_SECTION_HEADER) * mNtHeader.Pe32->FileHeader.NumberOfSections);\r |
570b3d1a | 510 | if (SectionHeader == NULL) {\r |
511 | Status = FALSE;\r | |
512 | goto Done;\r | |
513 | }\r | |
c411b485 | 514 | \r |
0c18794e | 515 | //\r |
516 | // 12. Using the 'PointerToRawData' in the referenced section headers as\r | |
517 | // a key, arrange the elements in the table in ascending order. In other\r | |
518 | // words, sort the section headers according to the disk-file offset of\r | |
519 | // the section.\r | |
520 | //\r | |
0c18794e | 521 | for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {\r |
522 | Pos = Index;\r | |
523 | while ((Pos > 0) && (Section->PointerToRawData < SectionHeader[Pos - 1].PointerToRawData)) {\r | |
524 | CopyMem (&SectionHeader[Pos], &SectionHeader[Pos - 1], sizeof (EFI_IMAGE_SECTION_HEADER));\r | |
525 | Pos--;\r | |
526 | }\r | |
c411b485 | 527 | \r |
0c18794e | 528 | CopyMem (&SectionHeader[Pos], Section, sizeof (EFI_IMAGE_SECTION_HEADER));\r |
529 | Section += 1;\r | |
530 | }\r | |
531 | \r | |
532 | //\r | |
533 | // 13. Walk through the sorted table, bring the corresponding section\r | |
534 | // into memory, and hash the entire section (using the 'SizeOfRawData'\r | |
535 | // field in the section header to determine the amount of data to hash).\r | |
536 | // 14. Add the section's 'SizeOfRawData' to SUM_OF_BYTES_HASHED .\r | |
537 | // 15. Repeat steps 13 and 14 for all the sections in the sorted table.\r | |
538 | //\r | |
539 | for (Index = 0; Index < mNtHeader.Pe32->FileHeader.NumberOfSections; Index++) {\r | |
540 | Section = &SectionHeader[Index];\r | |
541 | if (Section->SizeOfRawData == 0) {\r | |
542 | continue;\r | |
543 | }\r | |
0c18794e | 544 | \r |
c411b485 MK |
545 | HashBase = mImageBase + Section->PointerToRawData;\r |
546 | HashSize = (UINTN)Section->SizeOfRawData;\r | |
547 | \r | |
548 | Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize);\r | |
0c18794e | 549 | if (!Status) {\r |
550 | goto Done;\r | |
551 | }\r | |
552 | \r | |
553 | SumOfBytesHashed += HashSize;\r | |
554 | }\r | |
555 | \r | |
556 | //\r | |
557 | // 16. If the file size is greater than SUM_OF_BYTES_HASHED, there is extra\r | |
558 | // data in the file that needs to be added to the hash. This data begins\r | |
559 | // at file offset SUM_OF_BYTES_HASHED and its length is:\r | |
560 | // FileSize - (CertDirectory->Size)\r | |
561 | //\r | |
562 | if (mImageSize > SumOfBytesHashed) {\r | |
563 | HashBase = mImageBase + SumOfBytesHashed;\r | |
551d8081 | 564 | \r |
565 | if (NumberOfRvaAndSizes <= EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r | |
566 | CertSize = 0;\r | |
0c18794e | 567 | } else {\r |
f199664c | 568 | if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r |
551d8081 | 569 | //\r |
570 | // Use PE32 offset.\r | |
571 | //\r | |
572 | CertSize = mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r | |
573 | } else {\r | |
574 | //\r | |
575 | // Use PE32+ offset.\r | |
576 | //\r | |
577 | CertSize = mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY].Size;\r | |
28186d45 | 578 | }\r |
0c18794e | 579 | }\r |
580 | \r | |
551d8081 | 581 | if (mImageSize > CertSize + SumOfBytesHashed) {\r |
c411b485 | 582 | HashSize = (UINTN)(mImageSize - CertSize - SumOfBytesHashed);\r |
551d8081 | 583 | \r |
c411b485 | 584 | Status = mHash[HashAlg].HashUpdate (HashCtx, HashBase, HashSize);\r |
551d8081 | 585 | if (!Status) {\r |
586 | goto Done;\r | |
587 | }\r | |
588 | } else if (mImageSize < CertSize + SumOfBytesHashed) {\r | |
589 | Status = FALSE;\r | |
0c18794e | 590 | goto Done;\r |
591 | }\r | |
592 | }\r | |
551d8081 | 593 | \r |
c411b485 | 594 | Status = mHash[HashAlg].HashFinal (HashCtx, mImageDigest);\r |
0c18794e | 595 | \r |
596 | Done:\r | |
597 | if (HashCtx != NULL) {\r | |
598 | FreePool (HashCtx);\r | |
599 | }\r | |
c411b485 | 600 | \r |
0c18794e | 601 | if (SectionHeader != NULL) {\r |
602 | FreePool (SectionHeader);\r | |
603 | }\r | |
c411b485 | 604 | \r |
0c18794e | 605 | return Status;\r |
606 | }\r | |
607 | \r | |
608 | /**\r | |
69f8bb52 | 609 | Recognize the Hash algorithm in PE/COFF Authenticode and calculate hash of\r |
45bf2c47 | 610 | Pe/Coff image based on the authenticode image hashing in PE/COFF Specification\r |
0c18794e | 611 | 8.0 Appendix A\r |
612 | \r | |
dc204d5a JY |
613 | Caution: This function may receive untrusted input.\r |
614 | PE/COFF image is external input, so this function will validate its data structure\r | |
615 | within this image buffer before use.\r | |
616 | \r | |
f6f9031f | 617 | @param[in] AuthData Pointer to the Authenticode Signature retrieved from signed image.\r |
618 | @param[in] AuthDataSize Size of the Authenticode Signature in bytes.\r | |
20333c6d | 619 | \r |
0c18794e | 620 | @retval EFI_UNSUPPORTED Hash algorithm is not supported.\r |
621 | @retval EFI_SUCCESS Hash successfully.\r | |
622 | \r | |
623 | **/\r | |
45bf2c47 | 624 | EFI_STATUS\r |
0c18794e | 625 | HashPeImageByType (\r |
c411b485 MK |
626 | IN UINT8 *AuthData,\r |
627 | IN UINTN AuthDataSize\r | |
0c18794e | 628 | )\r |
629 | {\r | |
c411b485 | 630 | UINT8 Index;\r |
badd40f9 | 631 | \r |
45bf2c47 | 632 | for (Index = 0; Index < HASHALG_MAX; Index++) {\r |
0c18794e | 633 | //\r |
634 | // Check the Hash algorithm in PE/COFF Authenticode.\r | |
45bf2c47 | 635 | // According to PKCS#7 Definition:\r |
0c18794e | 636 | // SignedData ::= SEQUENCE {\r |
637 | // version Version,\r | |
638 | // digestAlgorithms DigestAlgorithmIdentifiers,\r | |
639 | // contentInfo ContentInfo,\r | |
640 | // .... }\r | |
641 | // The DigestAlgorithmIdentifiers can be used to determine the hash algorithm in PE/COFF hashing\r | |
642 | // This field has the fixed offset (+32) in final Authenticode ASN.1 data.\r | |
bd0de396 | 643 | // Fixed offset (+32) is calculated based on two bytes of length encoding.\r |
45bf2c47 | 644 | //\r |
f6f9031f | 645 | if ((*(AuthData + 1) & TWO_BYTE_ENCODE) != TWO_BYTE_ENCODE) {\r |
bd0de396 | 646 | //\r |
647 | // Only support two bytes of Long Form of Length Encoding.\r | |
648 | //\r | |
649 | continue;\r | |
650 | }\r | |
651 | \r | |
f6f9031f | 652 | if (AuthDataSize < 32 + mHash[Index].OidLength) {\r |
badd40f9 | 653 | return EFI_UNSUPPORTED;\r |
654 | }\r | |
655 | \r | |
f6f9031f | 656 | if (CompareMem (AuthData + 32, mHash[Index].OidValue, mHash[Index].OidLength) == 0) {\r |
0c18794e | 657 | break;\r |
658 | }\r | |
659 | }\r | |
660 | \r | |
661 | if (Index == HASHALG_MAX) {\r | |
662 | return EFI_UNSUPPORTED;\r | |
663 | }\r | |
664 | \r | |
665 | //\r | |
666 | // HASH PE Image based on Hash algorithm in PE/COFF Authenticode.\r | |
667 | //\r | |
c411b485 | 668 | if (!HashPeImage (Index)) {\r |
0c18794e | 669 | return EFI_UNSUPPORTED;\r |
670 | }\r | |
671 | \r | |
672 | return EFI_SUCCESS;\r | |
673 | }\r | |
674 | \r | |
0c18794e | 675 | /**\r |
676 | Returns the size of a given image execution info table in bytes.\r | |
677 | \r | |
678 | This function returns the size, in bytes, of the image execution info table specified by\r | |
679 | ImageExeInfoTable. If ImageExeInfoTable is NULL, then 0 is returned.\r | |
680 | \r | |
681 | @param ImageExeInfoTable A pointer to a image execution info table structure.\r | |
45bf2c47 | 682 | \r |
0c18794e | 683 | @retval 0 If ImageExeInfoTable is NULL.\r |
684 | @retval Others The size of a image execution info table in bytes.\r | |
685 | \r | |
686 | **/\r | |
687 | UINTN\r | |
688 | GetImageExeInfoTableSize (\r | |
c411b485 | 689 | EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable\r |
0c18794e | 690 | )\r |
691 | {\r | |
692 | UINTN Index;\r | |
693 | EFI_IMAGE_EXECUTION_INFO *ImageExeInfoItem;\r | |
694 | UINTN TotalSize;\r | |
695 | \r | |
696 | if (ImageExeInfoTable == NULL) {\r | |
697 | return 0;\r | |
698 | }\r | |
699 | \r | |
c411b485 MK |
700 | ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *)((UINT8 *)ImageExeInfoTable + sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE));\r |
701 | TotalSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);\r | |
0c18794e | 702 | for (Index = 0; Index < ImageExeInfoTable->NumberOfImages; Index++) {\r |
c411b485 MK |
703 | TotalSize += ReadUnaligned32 ((UINT32 *)&ImageExeInfoItem->InfoSize);\r |
704 | ImageExeInfoItem = (EFI_IMAGE_EXECUTION_INFO *)((UINT8 *)ImageExeInfoItem + ReadUnaligned32 ((UINT32 *)&ImageExeInfoItem->InfoSize));\r | |
0c18794e | 705 | }\r |
706 | \r | |
707 | return TotalSize;\r | |
708 | }\r | |
709 | \r | |
710 | /**\r | |
711 | Create an Image Execution Information Table entry and add it to system configuration table.\r | |
712 | \r | |
713 | @param[in] Action Describes the action taken by the firmware regarding this image.\r | |
714 | @param[in] Name Input a null-terminated, user-friendly name.\r | |
715 | @param[in] DevicePath Input device path pointer.\r | |
716 | @param[in] Signature Input signature info in EFI_SIGNATURE_LIST data structure.\r | |
6aa31db5 | 717 | @param[in] SignatureSize Size of signature. Must be zero if Signature is NULL.\r |
45bf2c47 | 718 | \r |
0c18794e | 719 | **/\r |
720 | VOID\r | |
721 | AddImageExeInfo (\r | |
c411b485 MK |
722 | IN EFI_IMAGE_EXECUTION_ACTION Action,\r |
723 | IN CHAR16 *Name OPTIONAL,\r | |
724 | IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,\r | |
725 | IN EFI_SIGNATURE_LIST *Signature OPTIONAL,\r | |
726 | IN UINTN SignatureSize\r | |
0c18794e | 727 | )\r |
728 | {\r | |
0c18794e | 729 | EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable;\r |
730 | EFI_IMAGE_EXECUTION_INFO_TABLE *NewImageExeInfoTable;\r | |
731 | EFI_IMAGE_EXECUTION_INFO *ImageExeInfoEntry;\r | |
732 | UINTN ImageExeInfoTableSize;\r | |
733 | UINTN NewImageExeInfoEntrySize;\r | |
734 | UINTN NameStringLen;\r | |
735 | UINTN DevicePathSize;\r | |
4fc08e8d | 736 | CHAR16 *NameStr;\r |
0c18794e | 737 | \r |
c411b485 MK |
738 | ImageExeInfoTable = NULL;\r |
739 | NewImageExeInfoTable = NULL;\r | |
740 | ImageExeInfoEntry = NULL;\r | |
741 | NameStringLen = 0;\r | |
742 | NameStr = NULL;\r | |
0c18794e | 743 | \r |
570b3d1a | 744 | if (DevicePath == NULL) {\r |
c411b485 | 745 | return;\r |
570b3d1a | 746 | }\r |
45bf2c47 | 747 | \r |
0c18794e | 748 | if (Name != NULL) {\r |
749 | NameStringLen = StrSize (Name);\r | |
b3d42170 | 750 | } else {\r |
751 | NameStringLen = sizeof (CHAR16);\r | |
0c18794e | 752 | }\r |
753 | \r | |
c411b485 | 754 | EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **)&ImageExeInfoTable);\r |
0c18794e | 755 | if (ImageExeInfoTable != NULL) {\r |
756 | //\r | |
757 | // The table has been found!\r | |
d6b926e7 | 758 | // We must enlarge the table to accommodate the new exe info entry.\r |
0c18794e | 759 | //\r |
760 | ImageExeInfoTableSize = GetImageExeInfoTableSize (ImageExeInfoTable);\r | |
761 | } else {\r | |
762 | //\r | |
763 | // Not Found!\r | |
764 | // We should create a new table to append to the configuration table.\r | |
765 | //\r | |
766 | ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);\r | |
767 | }\r | |
768 | \r | |
c411b485 | 769 | DevicePathSize = GetDevicePathSize (DevicePath);\r |
4fc08e8d CZ |
770 | \r |
771 | //\r | |
772 | // Signature size can be odd. Pad after signature to ensure next EXECUTION_INFO entry align\r | |
773 | //\r | |
6aa31db5 | 774 | ASSERT (Signature != NULL || SignatureSize == 0);\r |
4fc08e8d CZ |
775 | NewImageExeInfoEntrySize = sizeof (EFI_IMAGE_EXECUTION_INFO) + NameStringLen + DevicePathSize + SignatureSize;\r |
776 | \r | |
c411b485 | 777 | NewImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *)AllocateRuntimePool (ImageExeInfoTableSize + NewImageExeInfoEntrySize);\r |
570b3d1a | 778 | if (NewImageExeInfoTable == NULL) {\r |
c411b485 | 779 | return;\r |
570b3d1a | 780 | }\r |
0c18794e | 781 | \r |
782 | if (ImageExeInfoTable != NULL) {\r | |
783 | CopyMem (NewImageExeInfoTable, ImageExeInfoTable, ImageExeInfoTableSize);\r | |
784 | } else {\r | |
785 | NewImageExeInfoTable->NumberOfImages = 0;\r | |
786 | }\r | |
c411b485 | 787 | \r |
0c18794e | 788 | NewImageExeInfoTable->NumberOfImages++;\r |
c411b485 | 789 | ImageExeInfoEntry = (EFI_IMAGE_EXECUTION_INFO *)((UINT8 *)NewImageExeInfoTable + ImageExeInfoTableSize);\r |
0c18794e | 790 | //\r |
ffccb935 | 791 | // Update new item's information.\r |
0c18794e | 792 | //\r |
c411b485 MK |
793 | WriteUnaligned32 ((UINT32 *)ImageExeInfoEntry, Action);\r |
794 | WriteUnaligned32 ((UINT32 *)((UINT8 *)ImageExeInfoEntry + sizeof (EFI_IMAGE_EXECUTION_ACTION)), (UINT32)NewImageExeInfoEntrySize);\r | |
0c18794e | 795 | \r |
4fc08e8d | 796 | NameStr = (CHAR16 *)(ImageExeInfoEntry + 1);\r |
0c18794e | 797 | if (Name != NULL) {\r |
c411b485 | 798 | CopyMem ((UINT8 *)NameStr, Name, NameStringLen);\r |
b3d42170 | 799 | } else {\r |
c411b485 | 800 | ZeroMem ((UINT8 *)NameStr, sizeof (CHAR16));\r |
0c18794e | 801 | }\r |
4fc08e8d | 802 | \r |
0c18794e | 803 | CopyMem (\r |
c411b485 | 804 | (UINT8 *)NameStr + NameStringLen,\r |
0c18794e | 805 | DevicePath,\r |
806 | DevicePathSize\r | |
807 | );\r | |
808 | if (Signature != NULL) {\r | |
809 | CopyMem (\r | |
c411b485 | 810 | (UINT8 *)NameStr + NameStringLen + DevicePathSize,\r |
0c18794e | 811 | Signature,\r |
812 | SignatureSize\r | |
813 | );\r | |
814 | }\r | |
c411b485 | 815 | \r |
0c18794e | 816 | //\r |
817 | // Update/replace the image execution table.\r | |
818 | //\r | |
c411b485 | 819 | gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *)NewImageExeInfoTable);\r |
45bf2c47 | 820 | \r |
0c18794e | 821 | //\r |
822 | // Free Old table data!\r | |
823 | //\r | |
824 | if (ImageExeInfoTable != NULL) {\r | |
825 | FreePool (ImageExeInfoTable);\r | |
826 | }\r | |
827 | }\r | |
828 | \r | |
20333c6d QL |
829 | /**\r |
830 | Check whether the hash of an given X.509 certificate is in forbidden database (DBX).\r | |
831 | \r | |
832 | @param[in] Certificate Pointer to X.509 Certificate that is searched for.\r | |
833 | @param[in] CertSize Size of X.509 Certificate.\r | |
834 | @param[in] SignatureList Pointer to the Signature List in forbidden database.\r | |
835 | @param[in] SignatureListSize Size of Signature List.\r | |
836 | @param[out] RevocationTime Return the time that the certificate was revoked.\r | |
a83dbf00 | 837 | @param[out] IsFound Search result. Only valid if EFI_SUCCESS returned.\r |
20333c6d | 838 | \r |
a83dbf00 JW |
839 | @retval EFI_SUCCESS Finished the search without any error.\r |
840 | @retval Others Error occurred in the search of database.\r | |
20333c6d QL |
841 | \r |
842 | **/\r | |
a83dbf00 | 843 | EFI_STATUS\r |
c230c002 | 844 | IsCertHashFoundInDbx (\r |
20333c6d QL |
845 | IN UINT8 *Certificate,\r |
846 | IN UINTN CertSize,\r | |
847 | IN EFI_SIGNATURE_LIST *SignatureList,\r | |
848 | IN UINTN SignatureListSize,\r | |
a83dbf00 JW |
849 | OUT EFI_TIME *RevocationTime,\r |
850 | OUT BOOLEAN *IsFound\r | |
20333c6d QL |
851 | )\r |
852 | {\r | |
a83dbf00 | 853 | EFI_STATUS Status;\r |
20333c6d QL |
854 | EFI_SIGNATURE_LIST *DbxList;\r |
855 | UINTN DbxSize;\r | |
856 | EFI_SIGNATURE_DATA *CertHash;\r | |
857 | UINTN CertHashCount;\r | |
858 | UINTN Index;\r | |
859 | UINT32 HashAlg;\r | |
860 | VOID *HashCtx;\r | |
861 | UINT8 CertDigest[MAX_DIGEST_SIZE];\r | |
862 | UINT8 *DbxCertHash;\r | |
863 | UINTN SiglistHeaderSize;\r | |
12d95665 LQ |
864 | UINT8 *TBSCert;\r |
865 | UINTN TBSCertSize;\r | |
20333c6d | 866 | \r |
a83dbf00 JW |
867 | Status = EFI_ABORTED;\r |
868 | *IsFound = FALSE;\r | |
20333c6d QL |
869 | DbxList = SignatureList;\r |
870 | DbxSize = SignatureListSize;\r | |
871 | HashCtx = NULL;\r | |
872 | HashAlg = HASHALG_MAX;\r | |
873 | \r | |
12d95665 | 874 | if ((RevocationTime == NULL) || (DbxList == NULL)) {\r |
a83dbf00 | 875 | return EFI_INVALID_PARAMETER;\r |
12d95665 LQ |
876 | }\r |
877 | \r | |
878 | //\r | |
879 | // Retrieve the TBSCertificate from the X.509 Certificate.\r | |
880 | //\r | |
881 | if (!X509GetTBSCert (Certificate, CertSize, &TBSCert, &TBSCertSize)) {\r | |
a83dbf00 | 882 | return Status;\r |
12d95665 | 883 | }\r |
20333c6d QL |
884 | \r |
885 | while ((DbxSize > 0) && (SignatureListSize >= DbxList->SignatureListSize)) {\r | |
886 | //\r | |
887 | // Determine Hash Algorithm of Certificate in the forbidden database.\r | |
888 | //\r | |
889 | if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha256Guid)) {\r | |
890 | HashAlg = HASHALG_SHA256;\r | |
891 | } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha384Guid)) {\r | |
892 | HashAlg = HASHALG_SHA384;\r | |
893 | } else if (CompareGuid (&DbxList->SignatureType, &gEfiCertX509Sha512Guid)) {\r | |
894 | HashAlg = HASHALG_SHA512;\r | |
895 | } else {\r | |
896 | DbxSize -= DbxList->SignatureListSize;\r | |
c411b485 | 897 | DbxList = (EFI_SIGNATURE_LIST *)((UINT8 *)DbxList + DbxList->SignatureListSize);\r |
20333c6d QL |
898 | continue;\r |
899 | }\r | |
900 | \r | |
901 | //\r | |
12d95665 | 902 | // Calculate the hash value of current TBSCertificate for comparision.\r |
20333c6d QL |
903 | //\r |
904 | if (mHash[HashAlg].GetContextSize == NULL) {\r | |
905 | goto Done;\r | |
906 | }\r | |
c411b485 | 907 | \r |
20333c6d QL |
908 | ZeroMem (CertDigest, MAX_DIGEST_SIZE);\r |
909 | HashCtx = AllocatePool (mHash[HashAlg].GetContextSize ());\r | |
910 | if (HashCtx == NULL) {\r | |
911 | goto Done;\r | |
912 | }\r | |
c411b485 | 913 | \r |
a83dbf00 | 914 | if (!mHash[HashAlg].HashInit (HashCtx)) {\r |
20333c6d QL |
915 | goto Done;\r |
916 | }\r | |
c411b485 | 917 | \r |
a83dbf00 | 918 | if (!mHash[HashAlg].HashUpdate (HashCtx, TBSCert, TBSCertSize)) {\r |
20333c6d QL |
919 | goto Done;\r |
920 | }\r | |
c411b485 | 921 | \r |
a83dbf00 | 922 | if (!mHash[HashAlg].HashFinal (HashCtx, CertDigest)) {\r |
20333c6d QL |
923 | goto Done;\r |
924 | }\r | |
925 | \r | |
fbb96072 JW |
926 | FreePool (HashCtx);\r |
927 | HashCtx = NULL;\r | |
928 | \r | |
20333c6d | 929 | SiglistHeaderSize = sizeof (EFI_SIGNATURE_LIST) + DbxList->SignatureHeaderSize;\r |
c411b485 | 930 | CertHash = (EFI_SIGNATURE_DATA *)((UINT8 *)DbxList + SiglistHeaderSize);\r |
20333c6d QL |
931 | CertHashCount = (DbxList->SignatureListSize - SiglistHeaderSize) / DbxList->SignatureSize;\r |
932 | for (Index = 0; Index < CertHashCount; Index++) {\r | |
933 | //\r | |
934 | // Iterate each Signature Data Node within this CertList for verify.\r | |
935 | //\r | |
936 | DbxCertHash = CertHash->SignatureData;\r | |
937 | if (CompareMem (DbxCertHash, CertDigest, mHash[HashAlg].DigestLength) == 0) {\r | |
938 | //\r | |
939 | // Hash of Certificate is found in forbidden database.\r | |
940 | //\r | |
a83dbf00 JW |
941 | Status = EFI_SUCCESS;\r |
942 | *IsFound = TRUE;\r | |
20333c6d QL |
943 | \r |
944 | //\r | |
945 | // Return the revocation time.\r | |
946 | //\r | |
947 | CopyMem (RevocationTime, (EFI_TIME *)(DbxCertHash + mHash[HashAlg].DigestLength), sizeof (EFI_TIME));\r | |
948 | goto Done;\r | |
949 | }\r | |
c411b485 MK |
950 | \r |
951 | CertHash = (EFI_SIGNATURE_DATA *)((UINT8 *)CertHash + DbxList->SignatureSize);\r | |
20333c6d QL |
952 | }\r |
953 | \r | |
954 | DbxSize -= DbxList->SignatureListSize;\r | |
c411b485 | 955 | DbxList = (EFI_SIGNATURE_LIST *)((UINT8 *)DbxList + DbxList->SignatureListSize);\r |
20333c6d QL |
956 | }\r |
957 | \r | |
a83dbf00 JW |
958 | Status = EFI_SUCCESS;\r |
959 | \r | |
20333c6d QL |
960 | Done:\r |
961 | if (HashCtx != NULL) {\r | |
962 | FreePool (HashCtx);\r | |
963 | }\r | |
964 | \r | |
a83dbf00 | 965 | return Status;\r |
20333c6d QL |
966 | }\r |
967 | \r | |
0c18794e | 968 | /**\r |
969 | Check whether signature is in specified database.\r | |
970 | \r | |
971 | @param[in] VariableName Name of database variable that is searched in.\r | |
972 | @param[in] Signature Pointer to signature that is searched for.\r | |
d6b926e7 | 973 | @param[in] CertType Pointer to hash algorithm.\r |
0c18794e | 974 | @param[in] SignatureSize Size of Signature.\r |
b1c11470 | 975 | @param[out] IsFound Search result. Only valid if EFI_SUCCESS returned\r |
0c18794e | 976 | \r |
b1c11470 JW |
977 | @retval EFI_SUCCESS Finished the search without any error.\r |
978 | @retval Others Error occurred in the search of database.\r | |
0c18794e | 979 | \r |
980 | **/\r | |
b1c11470 | 981 | EFI_STATUS\r |
0c18794e | 982 | IsSignatureFoundInDatabase (\r |
c411b485 MK |
983 | IN CHAR16 *VariableName,\r |
984 | IN UINT8 *Signature,\r | |
985 | IN EFI_GUID *CertType,\r | |
986 | IN UINTN SignatureSize,\r | |
987 | OUT BOOLEAN *IsFound\r | |
0c18794e | 988 | )\r |
989 | {\r | |
990 | EFI_STATUS Status;\r | |
991 | EFI_SIGNATURE_LIST *CertList;\r | |
992 | EFI_SIGNATURE_DATA *Cert;\r | |
993 | UINTN DataSize;\r | |
994 | UINT8 *Data;\r | |
995 | UINTN Index;\r | |
996 | UINTN CertCount;\r | |
20333c6d | 997 | \r |
0c18794e | 998 | //\r |
999 | // Read signature database variable.\r | |
1000 | //\r | |
c411b485 MK |
1001 | *IsFound = FALSE;\r |
1002 | Data = NULL;\r | |
1003 | DataSize = 0;\r | |
1004 | Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r | |
0c18794e | 1005 | if (Status != EFI_BUFFER_TOO_SMALL) {\r |
b1c11470 JW |
1006 | if (Status == EFI_NOT_FOUND) {\r |
1007 | //\r | |
1008 | // No database, no need to search.\r | |
1009 | //\r | |
1010 | Status = EFI_SUCCESS;\r | |
1011 | }\r | |
1012 | \r | |
1013 | return Status;\r | |
0c18794e | 1014 | }\r |
1015 | \r | |
c411b485 | 1016 | Data = (UINT8 *)AllocateZeroPool (DataSize);\r |
570b3d1a | 1017 | if (Data == NULL) {\r |
b1c11470 | 1018 | return EFI_OUT_OF_RESOURCES;\r |
570b3d1a | 1019 | }\r |
0c18794e | 1020 | \r |
1021 | Status = gRT->GetVariable (VariableName, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, Data);\r | |
1022 | if (EFI_ERROR (Status)) {\r | |
1023 | goto Done;\r | |
1024 | }\r | |
c411b485 | 1025 | \r |
0c18794e | 1026 | //\r |
d6b926e7 | 1027 | // Enumerate all signature data in SigDB to check if signature exists for executable.\r |
0c18794e | 1028 | //\r |
c411b485 | 1029 | CertList = (EFI_SIGNATURE_LIST *)Data;\r |
0c18794e | 1030 | while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r |
7403ff5b | 1031 | CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r |
c411b485 MK |
1032 | Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r |
1033 | if ((CertList->SignatureSize == sizeof (EFI_SIGNATURE_DATA) - 1 + SignatureSize) && (CompareGuid (&CertList->SignatureType, CertType))) {\r | |
0c18794e | 1034 | for (Index = 0; Index < CertCount; Index++) {\r |
1035 | if (CompareMem (Cert->SignatureData, Signature, SignatureSize) == 0) {\r | |
1036 | //\r | |
1037 | // Find the signature in database.\r | |
1038 | //\r | |
b1c11470 | 1039 | *IsFound = TRUE;\r |
5b196b06 ZC |
1040 | //\r |
1041 | // Entries in UEFI_IMAGE_SECURITY_DATABASE that are used to validate image should be measured\r | |
1042 | //\r | |
c411b485 | 1043 | if (StrCmp (VariableName, EFI_IMAGE_SECURITY_DATABASE) == 0) {\r |
5b196b06 ZC |
1044 | SecureBootHook (VariableName, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, Cert);\r |
1045 | }\r | |
c411b485 | 1046 | \r |
0c18794e | 1047 | break;\r |
1048 | }\r | |
1049 | \r | |
c411b485 | 1050 | Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)Cert + CertList->SignatureSize);\r |
0c18794e | 1051 | }\r |
1052 | \r | |
b1c11470 | 1053 | if (*IsFound) {\r |
0c18794e | 1054 | break;\r |
1055 | }\r | |
1056 | }\r | |
1057 | \r | |
1058 | DataSize -= CertList->SignatureListSize;\r | |
c411b485 | 1059 | CertList = (EFI_SIGNATURE_LIST *)((UINT8 *)CertList + CertList->SignatureListSize);\r |
0c18794e | 1060 | }\r |
1061 | \r | |
1062 | Done:\r | |
1063 | if (Data != NULL) {\r | |
1064 | FreePool (Data);\r | |
1065 | }\r | |
1066 | \r | |
b1c11470 | 1067 | return Status;\r |
0c18794e | 1068 | }\r |
1069 | \r | |
1070 | /**\r | |
20333c6d | 1071 | Check whether the timestamp is valid by comparing the signing time and the revocation time.\r |
0c18794e | 1072 | \r |
20333c6d QL |
1073 | @param SigningTime A pointer to the signing time.\r |
1074 | @param RevocationTime A pointer to the revocation time.\r | |
45bf2c47 | 1075 | \r |
20333c6d QL |
1076 | @retval TRUE The SigningTime is not later than the RevocationTime.\r |
1077 | @retval FALSE The SigningTime is later than the RevocationTime.\r | |
0c18794e | 1078 | \r |
1079 | **/\r | |
45bf2c47 | 1080 | BOOLEAN\r |
20333c6d | 1081 | IsValidSignatureByTimestamp (\r |
c411b485 MK |
1082 | IN EFI_TIME *SigningTime,\r |
1083 | IN EFI_TIME *RevocationTime\r | |
20333c6d QL |
1084 | )\r |
1085 | {\r | |
1086 | if (SigningTime->Year != RevocationTime->Year) {\r | |
c411b485 | 1087 | return (BOOLEAN)(SigningTime->Year < RevocationTime->Year);\r |
20333c6d | 1088 | } else if (SigningTime->Month != RevocationTime->Month) {\r |
c411b485 | 1089 | return (BOOLEAN)(SigningTime->Month < RevocationTime->Month);\r |
20333c6d | 1090 | } else if (SigningTime->Day != RevocationTime->Day) {\r |
c411b485 | 1091 | return (BOOLEAN)(SigningTime->Day < RevocationTime->Day);\r |
20333c6d | 1092 | } else if (SigningTime->Hour != RevocationTime->Hour) {\r |
c411b485 | 1093 | return (BOOLEAN)(SigningTime->Hour < RevocationTime->Hour);\r |
20333c6d | 1094 | } else if (SigningTime->Minute != RevocationTime->Minute) {\r |
c411b485 | 1095 | return (BOOLEAN)(SigningTime->Minute < RevocationTime->Minute);\r |
20333c6d QL |
1096 | }\r |
1097 | \r | |
c411b485 | 1098 | return (BOOLEAN)(SigningTime->Second <= RevocationTime->Second);\r |
20333c6d QL |
1099 | }\r |
1100 | \r | |
1101 | /**\r | |
1102 | Check if the given time value is zero.\r | |
1103 | \r | |
1104 | @param[in] Time Pointer of a time value.\r | |
1105 | \r | |
1106 | @retval TRUE The Time is Zero.\r | |
1107 | @retval FALSE The Time is not Zero.\r | |
1108 | \r | |
1109 | **/\r | |
1110 | BOOLEAN\r | |
1111 | IsTimeZero (\r | |
c411b485 | 1112 | IN EFI_TIME *Time\r |
20333c6d QL |
1113 | )\r |
1114 | {\r | |
1115 | if ((Time->Year == 0) && (Time->Month == 0) && (Time->Day == 0) &&\r | |
c411b485 MK |
1116 | (Time->Hour == 0) && (Time->Minute == 0) && (Time->Second == 0))\r |
1117 | {\r | |
20333c6d QL |
1118 | return TRUE;\r |
1119 | }\r | |
1120 | \r | |
1121 | return FALSE;\r | |
1122 | }\r | |
1123 | \r | |
1124 | /**\r | |
b3548d32 | 1125 | Check whether the timestamp signature is valid and the signing time is also earlier than\r |
20333c6d QL |
1126 | the revocation time.\r |
1127 | \r | |
1128 | @param[in] AuthData Pointer to the Authenticode signature retrieved from signed image.\r | |
1129 | @param[in] AuthDataSize Size of the Authenticode signature in bytes.\r | |
1130 | @param[in] RevocationTime The time that the certificate was revoked.\r | |
1131 | \r | |
b3548d32 | 1132 | @retval TRUE Timestamp signature is valid and signing time is no later than the\r |
20333c6d QL |
1133 | revocation time.\r |
1134 | @retval FALSE Timestamp signature is not valid or the signing time is later than the\r | |
1135 | revocation time.\r | |
1136 | \r | |
1137 | **/\r | |
1138 | BOOLEAN\r | |
1139 | PassTimestampCheck (\r | |
c411b485 MK |
1140 | IN UINT8 *AuthData,\r |
1141 | IN UINTN AuthDataSize,\r | |
1142 | IN EFI_TIME *RevocationTime\r | |
20333c6d QL |
1143 | )\r |
1144 | {\r | |
c411b485 MK |
1145 | EFI_STATUS Status;\r |
1146 | BOOLEAN VerifyStatus;\r | |
1147 | EFI_SIGNATURE_LIST *CertList;\r | |
1148 | EFI_SIGNATURE_DATA *Cert;\r | |
1149 | UINT8 *DbtData;\r | |
1150 | UINTN DbtDataSize;\r | |
1151 | UINT8 *RootCert;\r | |
1152 | UINTN RootCertSize;\r | |
1153 | UINTN Index;\r | |
1154 | UINTN CertCount;\r | |
1155 | EFI_TIME SigningTime;\r | |
20333c6d QL |
1156 | \r |
1157 | //\r | |
1158 | // Variable Initialization\r | |
1159 | //\r | |
c411b485 MK |
1160 | VerifyStatus = FALSE;\r |
1161 | DbtData = NULL;\r | |
1162 | CertList = NULL;\r | |
1163 | Cert = NULL;\r | |
1164 | RootCert = NULL;\r | |
1165 | RootCertSize = 0;\r | |
20333c6d QL |
1166 | \r |
1167 | //\r | |
1168 | // If RevocationTime is zero, the certificate shall be considered to always be revoked.\r | |
1169 | //\r | |
1170 | if (IsTimeZero (RevocationTime)) {\r | |
1171 | return FALSE;\r | |
1172 | }\r | |
1173 | \r | |
1174 | //\r | |
1175 | // RevocationTime is non-zero, the certificate should be considered to be revoked from that time and onwards.\r | |
1176 | // Using the dbt to get the trusted TSA certificates.\r | |
1177 | //\r | |
1178 | DbtDataSize = 0;\r | |
c411b485 | 1179 | Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, NULL);\r |
7e0699c0 QL |
1180 | if (Status != EFI_BUFFER_TOO_SMALL) {\r |
1181 | goto Done;\r | |
1182 | }\r | |
c411b485 MK |
1183 | \r |
1184 | DbtData = (UINT8 *)AllocateZeroPool (DbtDataSize);\r | |
7e0699c0 QL |
1185 | if (DbtData == NULL) {\r |
1186 | goto Done;\r | |
1187 | }\r | |
c411b485 MK |
1188 | \r |
1189 | Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE2, &gEfiImageSecurityDatabaseGuid, NULL, &DbtDataSize, (VOID *)DbtData);\r | |
7e0699c0 QL |
1190 | if (EFI_ERROR (Status)) {\r |
1191 | goto Done;\r | |
20333c6d QL |
1192 | }\r |
1193 | \r | |
c411b485 | 1194 | CertList = (EFI_SIGNATURE_LIST *)DbtData;\r |
20333c6d QL |
1195 | while ((DbtDataSize > 0) && (DbtDataSize >= CertList->SignatureListSize)) {\r |
1196 | if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r | |
c411b485 | 1197 | Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r |
20333c6d QL |
1198 | CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r |
1199 | for (Index = 0; Index < CertCount; Index++) {\r | |
1200 | //\r | |
1201 | // Iterate each Signature Data Node within this CertList for verify.\r | |
1202 | //\r | |
1203 | RootCert = Cert->SignatureData;\r | |
1204 | RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r | |
1205 | //\r | |
1206 | // Get the signing time if the timestamp signature is valid.\r | |
1207 | //\r | |
1208 | if (ImageTimestampVerify (AuthData, AuthDataSize, RootCert, RootCertSize, &SigningTime)) {\r | |
1209 | //\r | |
1210 | // The signer signature is valid only when the signing time is earlier than revocation time.\r | |
1211 | //\r | |
1212 | if (IsValidSignatureByTimestamp (&SigningTime, RevocationTime)) {\r | |
1213 | VerifyStatus = TRUE;\r | |
1214 | goto Done;\r | |
1215 | }\r | |
1216 | }\r | |
c411b485 MK |
1217 | \r |
1218 | Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)Cert + CertList->SignatureSize);\r | |
20333c6d QL |
1219 | }\r |
1220 | }\r | |
c411b485 | 1221 | \r |
20333c6d | 1222 | DbtDataSize -= CertList->SignatureListSize;\r |
c411b485 | 1223 | CertList = (EFI_SIGNATURE_LIST *)((UINT8 *)CertList + CertList->SignatureListSize);\r |
20333c6d QL |
1224 | }\r |
1225 | \r | |
1226 | Done:\r | |
1227 | if (DbtData != NULL) {\r | |
1228 | FreePool (DbtData);\r | |
1229 | }\r | |
1230 | \r | |
1231 | return VerifyStatus;\r | |
1232 | }\r | |
1233 | \r | |
1234 | /**\r | |
1235 | Check whether the image signature is forbidden by the forbidden database (dbx).\r | |
1236 | The image is forbidden to load if any certificates for signing are revoked before signing time.\r | |
1237 | \r | |
560ac77e ZC |
1238 | @param[in] AuthData Pointer to the Authenticode signature retrieved from the signed image.\r |
1239 | @param[in] AuthDataSize Size of the Authenticode signature in bytes.\r | |
20333c6d QL |
1240 | \r |
1241 | @retval TRUE Image is forbidden by dbx.\r | |
1242 | @retval FALSE Image is not forbidden by dbx.\r | |
1243 | \r | |
1244 | **/\r | |
1245 | BOOLEAN\r | |
b3548d32 | 1246 | IsForbiddenByDbx (\r |
c411b485 MK |
1247 | IN UINT8 *AuthData,\r |
1248 | IN UINTN AuthDataSize\r | |
20333c6d QL |
1249 | )\r |
1250 | {\r | |
c411b485 MK |
1251 | EFI_STATUS Status;\r |
1252 | BOOLEAN IsForbidden;\r | |
1253 | BOOLEAN IsFound;\r | |
1254 | UINT8 *Data;\r | |
1255 | UINTN DataSize;\r | |
1256 | EFI_SIGNATURE_LIST *CertList;\r | |
1257 | UINTN CertListSize;\r | |
1258 | EFI_SIGNATURE_DATA *CertData;\r | |
1259 | UINT8 *RootCert;\r | |
1260 | UINTN RootCertSize;\r | |
1261 | UINTN CertCount;\r | |
1262 | UINTN Index;\r | |
1263 | UINT8 *CertBuffer;\r | |
1264 | UINTN BufferLength;\r | |
1265 | UINT8 *TrustedCert;\r | |
1266 | UINTN TrustedCertLength;\r | |
1267 | UINT8 CertNumber;\r | |
1268 | UINT8 *CertPtr;\r | |
1269 | UINT8 *Cert;\r | |
1270 | UINTN CertSize;\r | |
1271 | EFI_TIME RevocationTime;\r | |
1272 | \r | |
20333c6d QL |
1273 | //\r |
1274 | // Variable Initialization\r | |
1275 | //\r | |
5cd8be60 | 1276 | IsForbidden = TRUE;\r |
20333c6d | 1277 | Data = NULL;\r |
27c93c06 LQ |
1278 | CertList = NULL;\r |
1279 | CertData = NULL;\r | |
1280 | RootCert = NULL;\r | |
1281 | RootCertSize = 0;\r | |
20333c6d QL |
1282 | Cert = NULL;\r |
1283 | CertBuffer = NULL;\r | |
1284 | BufferLength = 0;\r | |
1285 | TrustedCert = NULL;\r | |
1286 | TrustedCertLength = 0;\r | |
1287 | \r | |
1288 | //\r | |
1289 | // The image will not be forbidden if dbx can't be got.\r | |
1290 | //\r | |
1291 | DataSize = 0;\r | |
1292 | Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r | |
5cd8be60 | 1293 | ASSERT (EFI_ERROR (Status));\r |
7e0699c0 | 1294 | if (Status != EFI_BUFFER_TOO_SMALL) {\r |
5cd8be60 JW |
1295 | if (Status == EFI_NOT_FOUND) {\r |
1296 | //\r | |
1297 | // Evidently not in dbx if the database doesn't exist.\r | |
1298 | //\r | |
1299 | IsForbidden = FALSE;\r | |
1300 | }\r | |
c411b485 | 1301 | \r |
7e0699c0 | 1302 | return IsForbidden;\r |
20333c6d | 1303 | }\r |
c411b485 MK |
1304 | \r |
1305 | Data = (UINT8 *)AllocateZeroPool (DataSize);\r | |
7e0699c0 QL |
1306 | if (Data == NULL) {\r |
1307 | return IsForbidden;\r | |
1308 | }\r | |
1309 | \r | |
c411b485 | 1310 | Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *)Data);\r |
20333c6d | 1311 | if (EFI_ERROR (Status)) {\r |
cb30c8f2 | 1312 | goto Done;\r |
20333c6d QL |
1313 | }\r |
1314 | \r | |
27c93c06 LQ |
1315 | //\r |
1316 | // Verify image signature with RAW X509 certificates in DBX database.\r | |
1317 | // If passed, the image will be forbidden.\r | |
1318 | //\r | |
c411b485 | 1319 | CertList = (EFI_SIGNATURE_LIST *)Data;\r |
27c93c06 LQ |
1320 | CertListSize = DataSize;\r |
1321 | while ((CertListSize > 0) && (CertListSize >= CertList->SignatureListSize)) {\r | |
1322 | if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r | |
c411b485 | 1323 | CertData = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r |
27c93c06 LQ |
1324 | CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r |
1325 | \r | |
1326 | for (Index = 0; Index < CertCount; Index++) {\r | |
1327 | //\r | |
1328 | // Iterate each Signature Data Node within this CertList for verify.\r | |
1329 | //\r | |
1330 | RootCert = CertData->SignatureData;\r | |
1331 | RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r | |
1332 | \r | |
1333 | //\r | |
1334 | // Call AuthenticodeVerify library to Verify Authenticode struct.\r | |
1335 | //\r | |
1336 | IsForbidden = AuthenticodeVerify (\r | |
1337 | AuthData,\r | |
1338 | AuthDataSize,\r | |
1339 | RootCert,\r | |
1340 | RootCertSize,\r | |
1341 | mImageDigest,\r | |
1342 | mImageDigestSize\r | |
1343 | );\r | |
1344 | if (IsForbidden) {\r | |
531c89a1 | 1345 | DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is forbidden by DBX.\n"));\r |
27c93c06 LQ |
1346 | goto Done;\r |
1347 | }\r | |
1348 | \r | |
c411b485 | 1349 | CertData = (EFI_SIGNATURE_DATA *)((UINT8 *)CertData + CertList->SignatureSize);\r |
27c93c06 LQ |
1350 | }\r |
1351 | }\r | |
1352 | \r | |
1353 | CertListSize -= CertList->SignatureListSize;\r | |
c411b485 | 1354 | CertList = (EFI_SIGNATURE_LIST *)((UINT8 *)CertList + CertList->SignatureListSize);\r |
27c93c06 LQ |
1355 | }\r |
1356 | \r | |
1357 | //\r | |
1358 | // Check X.509 Certificate Hash & Possible Timestamp.\r | |
1359 | //\r | |
1360 | \r | |
20333c6d QL |
1361 | //\r |
1362 | // Retrieve the certificate stack from AuthData\r | |
1363 | // The output CertStack format will be:\r | |
1364 | // UINT8 CertNumber;\r | |
1365 | // UINT32 Cert1Length;\r | |
1366 | // UINT8 Cert1[];\r | |
1367 | // UINT32 Cert2Length;\r | |
1368 | // UINT8 Cert2[];\r | |
1369 | // ...\r | |
1370 | // UINT32 CertnLength;\r | |
1371 | // UINT8 Certn[];\r | |
1372 | //\r | |
1373 | Pkcs7GetSigners (AuthData, AuthDataSize, &CertBuffer, &BufferLength, &TrustedCert, &TrustedCertLength);\r | |
c411b485 | 1374 | if ((BufferLength == 0) || (CertBuffer == NULL) || ((*CertBuffer) == 0)) {\r |
20333c6d QL |
1375 | IsForbidden = TRUE;\r |
1376 | goto Done;\r | |
1377 | }\r | |
1378 | \r | |
1379 | //\r | |
27c93c06 | 1380 | // Check if any hash of certificates embedded in AuthData is in the forbidden database.\r |
20333c6d | 1381 | //\r |
c411b485 | 1382 | CertNumber = (UINT8)(*CertBuffer);\r |
20333c6d QL |
1383 | CertPtr = CertBuffer + 1;\r |
1384 | for (Index = 0; Index < CertNumber; Index++) {\r | |
c411b485 | 1385 | CertSize = (UINTN)ReadUnaligned32 ((UINT32 *)CertPtr);\r |
20333c6d | 1386 | Cert = (UINT8 *)CertPtr + sizeof (UINT32);\r |
91422384 ZC |
1387 | //\r |
1388 | // Advance CertPtr to the next cert in image signer's cert list\r | |
1389 | //\r | |
1390 | CertPtr = CertPtr + sizeof (UINT32) + CertSize;\r | |
20333c6d | 1391 | \r |
c230c002 | 1392 | Status = IsCertHashFoundInDbx (Cert, CertSize, (EFI_SIGNATURE_LIST *)Data, DataSize, &RevocationTime, &IsFound);\r |
a83dbf00 | 1393 | if (EFI_ERROR (Status)) {\r |
20333c6d | 1394 | //\r |
a83dbf00 JW |
1395 | // Error in searching dbx. Consider it as 'found'. RevocationTime might\r |
1396 | // not be valid in such situation.\r | |
20333c6d QL |
1397 | //\r |
1398 | IsForbidden = TRUE;\r | |
a83dbf00 JW |
1399 | } else if (IsFound) {\r |
1400 | //\r | |
1401 | // Found Cert in dbx successfully. Check the timestamp signature and\r | |
1402 | // signing time to determine if the image can be trusted.\r | |
1403 | //\r | |
20333c6d QL |
1404 | if (PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime)) {\r |
1405 | IsForbidden = FALSE;\r | |
91422384 ZC |
1406 | //\r |
1407 | // Pass DBT check. Continue to check other certs in image signer's cert list against DBX, DBT\r | |
1408 | //\r | |
1409 | continue;\r | |
a83dbf00 JW |
1410 | } else {\r |
1411 | IsForbidden = TRUE;\r | |
1412 | DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature failed the timestamp check.\n"));\r | |
1413 | goto Done;\r | |
20333c6d | 1414 | }\r |
20333c6d | 1415 | }\r |
20333c6d QL |
1416 | }\r |
1417 | \r | |
5cd8be60 JW |
1418 | IsForbidden = FALSE;\r |
1419 | \r | |
20333c6d QL |
1420 | Done:\r |
1421 | if (Data != NULL) {\r | |
1422 | FreePool (Data);\r | |
1423 | }\r | |
1424 | \r | |
1425 | Pkcs7FreeSigners (CertBuffer);\r | |
1426 | Pkcs7FreeSigners (TrustedCert);\r | |
1427 | \r | |
1428 | return IsForbidden;\r | |
1429 | }\r | |
1430 | \r | |
1431 | /**\r | |
1432 | Check whether the image signature can be verified by the trusted certificates in DB database.\r | |
1433 | \r | |
560ac77e ZC |
1434 | @param[in] AuthData Pointer to the Authenticode signature retrieved from signed image.\r |
1435 | @param[in] AuthDataSize Size of the Authenticode signature in bytes.\r | |
20333c6d QL |
1436 | \r |
1437 | @retval TRUE Image passed verification using certificate in db.\r | |
1438 | @retval FALSE Image didn't pass verification using certificate in db.\r | |
1439 | \r | |
1440 | **/\r | |
1441 | BOOLEAN\r | |
1442 | IsAllowedByDb (\r | |
c411b485 MK |
1443 | IN UINT8 *AuthData,\r |
1444 | IN UINTN AuthDataSize\r | |
0c18794e | 1445 | )\r |
1446 | {\r | |
c411b485 MK |
1447 | EFI_STATUS Status;\r |
1448 | BOOLEAN VerifyStatus;\r | |
1449 | BOOLEAN IsFound;\r | |
1450 | EFI_SIGNATURE_LIST *CertList;\r | |
1451 | EFI_SIGNATURE_DATA *CertData;\r | |
1452 | UINTN DataSize;\r | |
1453 | UINT8 *Data;\r | |
1454 | UINT8 *RootCert;\r | |
1455 | UINTN RootCertSize;\r | |
1456 | UINTN Index;\r | |
1457 | UINTN CertCount;\r | |
1458 | UINTN DbxDataSize;\r | |
1459 | UINT8 *DbxData;\r | |
1460 | EFI_TIME RevocationTime;\r | |
0c18794e | 1461 | \r |
c411b485 MK |
1462 | Data = NULL;\r |
1463 | CertList = NULL;\r | |
1464 | CertData = NULL;\r | |
1465 | RootCert = NULL;\r | |
1466 | DbxData = NULL;\r | |
1467 | RootCertSize = 0;\r | |
1468 | VerifyStatus = FALSE;\r | |
0c18794e | 1469 | \r |
adc68983 JW |
1470 | //\r |
1471 | // Fetch 'db' content. If 'db' doesn't exist or encounters problem to get the\r | |
1472 | // data, return not-allowed-by-db (FALSE).\r | |
1473 | //\r | |
0c18794e | 1474 | DataSize = 0;\r |
20333c6d | 1475 | Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, NULL);\r |
adc68983 JW |
1476 | ASSERT (EFI_ERROR (Status));\r |
1477 | if (Status != EFI_BUFFER_TOO_SMALL) {\r | |
1478 | return VerifyStatus;\r | |
1479 | }\r | |
1480 | \r | |
c411b485 | 1481 | Data = (UINT8 *)AllocateZeroPool (DataSize);\r |
adc68983 JW |
1482 | if (Data == NULL) {\r |
1483 | return VerifyStatus;\r | |
1484 | }\r | |
1485 | \r | |
c411b485 | 1486 | Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, NULL, &DataSize, (VOID *)Data);\r |
adc68983 JW |
1487 | if (EFI_ERROR (Status)) {\r |
1488 | goto Done;\r | |
1489 | }\r | |
1490 | \r | |
1491 | //\r | |
1492 | // Fetch 'dbx' content. If 'dbx' doesn't exist, continue to check 'db'.\r | |
53b40c9c | 1493 | // If any other errors occurred, no need to check 'db' but just return\r |
adc68983 JW |
1494 | // not-allowed-by-db (FALSE) to avoid bypass.\r |
1495 | //\r | |
1496 | DbxDataSize = 0;\r | |
1497 | Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, NULL);\r | |
1498 | ASSERT (EFI_ERROR (Status));\r | |
1499 | if (Status != EFI_BUFFER_TOO_SMALL) {\r | |
1500 | if (Status != EFI_NOT_FOUND) {\r | |
1501 | goto Done;\r | |
1502 | }\r | |
c411b485 | 1503 | \r |
adc68983 JW |
1504 | //\r |
1505 | // 'dbx' does not exist. Continue to check 'db'.\r | |
1506 | //\r | |
1507 | } else {\r | |
1508 | //\r | |
1509 | // 'dbx' exists. Get its content.\r | |
1510 | //\r | |
c411b485 | 1511 | DbxData = (UINT8 *)AllocateZeroPool (DbxDataSize);\r |
adc68983 JW |
1512 | if (DbxData == NULL) {\r |
1513 | goto Done;\r | |
570b3d1a | 1514 | }\r |
0c18794e | 1515 | \r |
c411b485 | 1516 | Status = gRT->GetVariable (EFI_IMAGE_SECURITY_DATABASE1, &gEfiImageSecurityDatabaseGuid, NULL, &DbxDataSize, (VOID *)DbxData);\r |
0c18794e | 1517 | if (EFI_ERROR (Status)) {\r |
1518 | goto Done;\r | |
1519 | }\r | |
adc68983 | 1520 | }\r |
45bf2c47 | 1521 | \r |
adc68983 JW |
1522 | //\r |
1523 | // Find X509 certificate in Signature List to verify the signature in pkcs7 signed data.\r | |
1524 | //\r | |
c411b485 | 1525 | CertList = (EFI_SIGNATURE_LIST *)Data;\r |
adc68983 JW |
1526 | while ((DataSize > 0) && (DataSize >= CertList->SignatureListSize)) {\r |
1527 | if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {\r | |
c411b485 | 1528 | CertData = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);\r |
adc68983 | 1529 | CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;\r |
20333c6d | 1530 | \r |
adc68983 JW |
1531 | for (Index = 0; Index < CertCount; Index++) {\r |
1532 | //\r | |
1533 | // Iterate each Signature Data Node within this CertList for verify.\r | |
1534 | //\r | |
1535 | RootCert = CertData->SignatureData;\r | |
1536 | RootCertSize = CertList->SignatureSize - sizeof (EFI_GUID);\r | |
45bf2c47 | 1537 | \r |
adc68983 JW |
1538 | //\r |
1539 | // Call AuthenticodeVerify library to Verify Authenticode struct.\r | |
1540 | //\r | |
1541 | VerifyStatus = AuthenticodeVerify (\r | |
1542 | AuthData,\r | |
1543 | AuthDataSize,\r | |
1544 | RootCert,\r | |
1545 | RootCertSize,\r | |
1546 | mImageDigest,\r | |
1547 | mImageDigestSize\r | |
1548 | );\r | |
1549 | if (VerifyStatus) {\r | |
0c18794e | 1550 | //\r |
adc68983 | 1551 | // The image is signed and its signature is found in 'db'.\r |
0c18794e | 1552 | //\r |
adc68983 | 1553 | if (DbxData != NULL) {\r |
27c93c06 LQ |
1554 | //\r |
1555 | // Here We still need to check if this RootCert's Hash is revoked\r | |
1556 | //\r | |
c230c002 | 1557 | Status = IsCertHashFoundInDbx (RootCert, RootCertSize, (EFI_SIGNATURE_LIST *)DbxData, DbxDataSize, &RevocationTime, &IsFound);\r |
a83dbf00 JW |
1558 | if (EFI_ERROR (Status)) {\r |
1559 | //\r | |
1560 | // Error in searching dbx. Consider it as 'found'. RevocationTime might\r | |
1561 | // not be valid in such situation.\r | |
1562 | //\r | |
1563 | VerifyStatus = FALSE;\r | |
1564 | } else if (IsFound) {\r | |
27c93c06 | 1565 | //\r |
531c89a1 | 1566 | // Check the timestamp signature and signing time to determine if the RootCert can be trusted.\r |
27c93c06 LQ |
1567 | //\r |
1568 | VerifyStatus = PassTimestampCheck (AuthData, AuthDataSize, &RevocationTime);\r | |
531c89a1 CS |
1569 | if (!VerifyStatus) {\r |
1570 | DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed and signature is accepted by DB, but its root cert failed the timestamp check.\n"));\r | |
1571 | }\r | |
27c93c06 | 1572 | }\r |
0c18794e | 1573 | }\r |
20333c6d | 1574 | \r |
adc68983 JW |
1575 | //\r |
1576 | // There's no 'dbx' to check revocation time against (must-be pass),\r | |
1577 | // or, there's revocation time found in 'dbx' and checked againt 'dbt'\r | |
1578 | // (maybe pass or fail, depending on timestamp compare result). Either\r | |
1579 | // way the verification job has been completed at this point.\r | |
1580 | //\r | |
1581 | goto Done;\r | |
45bf2c47 | 1582 | }\r |
20333c6d | 1583 | \r |
c411b485 | 1584 | CertData = (EFI_SIGNATURE_DATA *)((UINT8 *)CertData + CertList->SignatureSize);\r |
adc68983 | 1585 | }\r |
0c18794e | 1586 | }\r |
adc68983 JW |
1587 | \r |
1588 | DataSize -= CertList->SignatureListSize;\r | |
c411b485 | 1589 | CertList = (EFI_SIGNATURE_LIST *)((UINT8 *)CertList + CertList->SignatureListSize);\r |
0c18794e | 1590 | }\r |
1591 | \r | |
45bf2c47 | 1592 | Done:\r |
4fc08e8d | 1593 | \r |
27c93c06 | 1594 | if (VerifyStatus) {\r |
4fc08e8d | 1595 | SecureBootHook (EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, CertList->SignatureSize, CertData);\r |
27c93c06 LQ |
1596 | }\r |
1597 | \r | |
45bf2c47 | 1598 | if (Data != NULL) {\r |
1599 | FreePool (Data);\r | |
1600 | }\r | |
c411b485 | 1601 | \r |
27c93c06 LQ |
1602 | if (DbxData != NULL) {\r |
1603 | FreePool (DbxData);\r | |
1604 | }\r | |
0c18794e | 1605 | \r |
45bf2c47 | 1606 | return VerifyStatus;\r |
1607 | }\r | |
0c18794e | 1608 | \r |
0c18794e | 1609 | /**\r |
1610 | Provide verification service for signed images, which include both signature validation\r | |
45bf2c47 | 1611 | and platform policy control. For signature types, both UEFI WIN_CERTIFICATE_UEFI_GUID and\r |
0c18794e | 1612 | MSFT Authenticode type signatures are supported.\r |
0c18794e | 1613 | \r |
45bf2c47 | 1614 | In this implementation, only verify external executables when in USER MODE.\r |
1615 | Executables from FV is bypass, so pass in AuthenticationStatus is ignored.\r | |
1616 | \r | |
6de4c35f | 1617 | The image verification policy is:\r |
50fe73a1 | 1618 | If the image is signed,\r |
6de4c35f | 1619 | At least one valid signature or at least one hash value of the image must match a record\r |
1620 | in the security database "db", and no valid signature nor any hash value of the image may\r | |
1621 | be reflected in the security database "dbx".\r | |
50fe73a1 | 1622 | Otherwise, the image is not signed,\r |
6de4c35f | 1623 | The SHA256 hash value of the image must match a record in the security database "db", and\r |
1624 | not be reflected in the security data base "dbx".\r | |
45bf2c47 | 1625 | \r |
dc204d5a JY |
1626 | Caution: This function may receive untrusted input.\r |
1627 | PE/COFF image is external input, so this function will validate its data structure\r | |
1628 | within this image buffer before use.\r | |
1629 | \r | |
45bf2c47 | 1630 | @param[in] AuthenticationStatus\r |
0c18794e | 1631 | This is the authentication status returned from the security\r |
1632 | measurement services for the input file.\r | |
1633 | @param[in] File This is a pointer to the device path of the file that is\r | |
1634 | being dispatched. This will optionally be used for logging.\r | |
1635 | @param[in] FileBuffer File buffer matches the input file device path.\r | |
1636 | @param[in] FileSize Size of File buffer matches the input file device path.\r | |
5db28a67 LG |
1637 | @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r |
1638 | \r | |
1639 | @retval EFI_SUCCESS The file specified by DevicePath and non-NULL\r | |
1640 | FileBuffer did authenticate, and the platform policy dictates\r | |
1641 | that the DXE Foundation may use the file.\r | |
1642 | @retval EFI_SUCCESS The device path specified by NULL device path DevicePath\r | |
1643 | and non-NULL FileBuffer did authenticate, and the platform\r | |
1644 | policy dictates that the DXE Foundation may execute the image in\r | |
1645 | FileBuffer.\r | |
0c18794e | 1646 | @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r |
1647 | the platform policy dictates that File should be placed\r | |
5db28a67 LG |
1648 | in the untrusted state. The image has been added to the file\r |
1649 | execution table.\r | |
1650 | @retval EFI_ACCESS_DENIED The file specified by File and FileBuffer did not\r | |
1651 | authenticate, and the platform policy dictates that the DXE\r | |
8b0932c1 LE |
1652 | Foundation may not use File. The image has\r |
1653 | been added to the file execution table.\r | |
0c18794e | 1654 | \r |
1655 | **/\r | |
1656 | EFI_STATUS\r | |
1657 | EFIAPI\r | |
1658 | DxeImageVerificationHandler (\r | |
c411b485 MK |
1659 | IN UINT32 AuthenticationStatus,\r |
1660 | IN CONST EFI_DEVICE_PATH_PROTOCOL *File OPTIONAL,\r | |
1661 | IN VOID *FileBuffer,\r | |
1662 | IN UINTN FileSize,\r | |
1663 | IN BOOLEAN BootPolicy\r | |
0c18794e | 1664 | )\r |
0c18794e | 1665 | {\r |
c411b485 MK |
1666 | EFI_IMAGE_DOS_HEADER *DosHdr;\r |
1667 | BOOLEAN IsVerified;\r | |
1668 | EFI_SIGNATURE_LIST *SignatureList;\r | |
1669 | UINTN SignatureListSize;\r | |
1670 | EFI_SIGNATURE_DATA *Signature;\r | |
1671 | EFI_IMAGE_EXECUTION_ACTION Action;\r | |
1672 | WIN_CERTIFICATE *WinCertificate;\r | |
1673 | UINT32 Policy;\r | |
1674 | UINT8 *SecureBoot;\r | |
1675 | PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;\r | |
1676 | UINT32 NumberOfRvaAndSizes;\r | |
1677 | WIN_CERTIFICATE_EFI_PKCS *PkcsCertData;\r | |
1678 | WIN_CERTIFICATE_UEFI_GUID *WinCertUefiGuid;\r | |
1679 | UINT8 *AuthData;\r | |
1680 | UINTN AuthDataSize;\r | |
1681 | EFI_IMAGE_DATA_DIRECTORY *SecDataDir;\r | |
1682 | UINT32 SecDataDirEnd;\r | |
1683 | UINT32 SecDataDirLeft;\r | |
1684 | UINT32 OffSet;\r | |
1685 | CHAR16 *NameStr;\r | |
1686 | RETURN_STATUS PeCoffStatus;\r | |
1687 | EFI_STATUS HashStatus;\r | |
1688 | EFI_STATUS DbStatus;\r | |
1689 | BOOLEAN IsFound;\r | |
0c18794e | 1690 | \r |
0c18794e | 1691 | SignatureList = NULL;\r |
1692 | SignatureListSize = 0;\r | |
1693 | WinCertificate = NULL;\r | |
f6f9031f | 1694 | SecDataDir = NULL;\r |
1695 | PkcsCertData = NULL;\r | |
0c18794e | 1696 | Action = EFI_IMAGE_EXECUTION_AUTH_UNTESTED;\r |
1e0f973b | 1697 | IsVerified = FALSE;\r |
b1c11470 | 1698 | IsFound = FALSE;\r |
4fc08e8d | 1699 | \r |
0c18794e | 1700 | //\r |
1701 | // Check the image type and get policy setting.\r | |
1702 | //\r | |
1703 | switch (GetImageType (File)) {\r | |
c411b485 MK |
1704 | case IMAGE_FROM_FV:\r |
1705 | Policy = ALWAYS_EXECUTE;\r | |
1706 | break;\r | |
45bf2c47 | 1707 | \r |
c411b485 MK |
1708 | case IMAGE_FROM_OPTION_ROM:\r |
1709 | Policy = PcdGet32 (PcdOptionRomImageVerificationPolicy);\r | |
1710 | break;\r | |
0c18794e | 1711 | \r |
c411b485 MK |
1712 | case IMAGE_FROM_REMOVABLE_MEDIA:\r |
1713 | Policy = PcdGet32 (PcdRemovableMediaImageVerificationPolicy);\r | |
1714 | break;\r | |
0c18794e | 1715 | \r |
c411b485 MK |
1716 | case IMAGE_FROM_FIXED_MEDIA:\r |
1717 | Policy = PcdGet32 (PcdFixedMediaImageVerificationPolicy);\r | |
1718 | break;\r | |
0c18794e | 1719 | \r |
c411b485 MK |
1720 | default:\r |
1721 | Policy = DENY_EXECUTE_ON_SECURITY_VIOLATION;\r | |
1722 | break;\r | |
0c18794e | 1723 | }\r |
c411b485 | 1724 | \r |
0c18794e | 1725 | //\r |
1726 | // If policy is always/never execute, return directly.\r | |
1727 | //\r | |
1728 | if (Policy == ALWAYS_EXECUTE) {\r | |
1729 | return EFI_SUCCESS;\r | |
eccb856f | 1730 | }\r |
c411b485 | 1731 | \r |
eccb856f | 1732 | if (Policy == NEVER_EXECUTE) {\r |
0c18794e | 1733 | return EFI_ACCESS_DENIED;\r |
1734 | }\r | |
beda2356 | 1735 | \r |
db44ea6c | 1736 | //\r |
20333c6d | 1737 | // The policy QUERY_USER_ON_SECURITY_VIOLATION and ALLOW_EXECUTE_ON_SECURITY_VIOLATION\r |
68fc0c73 | 1738 | // violates the UEFI spec and has been removed.\r |
db44ea6c | 1739 | //\r |
68fc0c73 | 1740 | ASSERT (Policy != QUERY_USER_ON_SECURITY_VIOLATION && Policy != ALLOW_EXECUTE_ON_SECURITY_VIOLATION);\r |
c411b485 | 1741 | if ((Policy == QUERY_USER_ON_SECURITY_VIOLATION) || (Policy == ALLOW_EXECUTE_ON_SECURITY_VIOLATION)) {\r |
db44ea6c FS |
1742 | CpuDeadLoop ();\r |
1743 | }\r | |
1744 | \r | |
c411b485 | 1745 | GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID **)&SecureBoot, NULL);\r |
beda2356 | 1746 | //\r |
8f8ca22e | 1747 | // Skip verification if SecureBoot variable doesn't exist.\r |
beda2356 | 1748 | //\r |
560ac77e | 1749 | if (SecureBoot == NULL) {\r |
beda2356 | 1750 | return EFI_SUCCESS;\r |
1751 | }\r | |
1752 | \r | |
1753 | //\r | |
4fc08e8d | 1754 | // Skip verification if SecureBoot is disabled but not AuditMode\r |
beda2356 | 1755 | //\r |
560ac77e ZC |
1756 | if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) {\r |
1757 | FreePool (SecureBoot);\r | |
beda2356 | 1758 | return EFI_SUCCESS;\r |
45bf2c47 | 1759 | }\r |
c411b485 | 1760 | \r |
560ac77e | 1761 | FreePool (SecureBoot);\r |
551d8081 | 1762 | \r |
0c18794e | 1763 | //\r |
1764 | // Read the Dos header.\r | |
1765 | //\r | |
570b3d1a | 1766 | if (FileBuffer == NULL) {\r |
6d575927 | 1767 | return EFI_ACCESS_DENIED;\r |
570b3d1a | 1768 | }\r |
551d8081 | 1769 | \r |
c411b485 MK |
1770 | mImageBase = (UINT8 *)FileBuffer;\r |
1771 | mImageSize = FileSize;\r | |
28186d45 ED |
1772 | \r |
1773 | ZeroMem (&ImageContext, sizeof (ImageContext));\r | |
c411b485 MK |
1774 | ImageContext.Handle = (VOID *)FileBuffer;\r |
1775 | ImageContext.ImageRead = (PE_COFF_LOADER_READ_FILE)DxeImageVerificationLibImageRead;\r | |
28186d45 ED |
1776 | \r |
1777 | //\r | |
1778 | // Get information about the image being loaded\r | |
1779 | //\r | |
61a9fa58 LE |
1780 | PeCoffStatus = PeCoffLoaderGetImageInfo (&ImageContext);\r |
1781 | if (RETURN_ERROR (PeCoffStatus)) {\r | |
28186d45 ED |
1782 | //\r |
1783 | // The information can't be got from the invalid PeImage\r | |
1784 | //\r | |
531c89a1 | 1785 | DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: PeImage invalid. Cannot retrieve image information.\n"));\r |
c602e974 | 1786 | goto Failed;\r |
28186d45 ED |
1787 | }\r |
1788 | \r | |
c411b485 | 1789 | DosHdr = (EFI_IMAGE_DOS_HEADER *)mImageBase;\r |
0c18794e | 1790 | if (DosHdr->e_magic == EFI_IMAGE_DOS_SIGNATURE) {\r |
1791 | //\r | |
45bf2c47 | 1792 | // DOS image header is present,\r |
0c18794e | 1793 | // so read the PE header after the DOS image header.\r |
1794 | //\r | |
1795 | mPeCoffHeaderOffset = DosHdr->e_lfanew;\r | |
1796 | } else {\r | |
1797 | mPeCoffHeaderOffset = 0;\r | |
1798 | }\r | |
c411b485 | 1799 | \r |
0c18794e | 1800 | //\r |
1801 | // Check PE/COFF image.\r | |
1802 | //\r | |
c411b485 | 1803 | mNtHeader.Pe32 = (EFI_IMAGE_NT_HEADERS32 *)(mImageBase + mPeCoffHeaderOffset);\r |
0c18794e | 1804 | if (mNtHeader.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {\r |
1805 | //\r | |
1806 | // It is not a valid Pe/Coff file.\r | |
1807 | //\r | |
531c89a1 | 1808 | DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Not a valid PE/COFF image.\n"));\r |
c602e974 | 1809 | goto Failed;\r |
0c18794e | 1810 | }\r |
1811 | \r | |
f199664c | 1812 | if (mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r |
0c18794e | 1813 | //\r |
1814 | // Use PE32 offset.\r | |
1815 | //\r | |
551d8081 | 1816 | NumberOfRvaAndSizes = mNtHeader.Pe32->OptionalHeader.NumberOfRvaAndSizes;\r |
1817 | if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r | |
c411b485 | 1818 | SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r |
20333c6d | 1819 | }\r |
570b3d1a | 1820 | } else {\r |
1821 | //\r | |
551d8081 | 1822 | // Use PE32+ offset.\r |
570b3d1a | 1823 | //\r |
551d8081 | 1824 | NumberOfRvaAndSizes = mNtHeader.Pe32Plus->OptionalHeader.NumberOfRvaAndSizes;\r |
1825 | if (NumberOfRvaAndSizes > EFI_IMAGE_DIRECTORY_ENTRY_SECURITY) {\r | |
c411b485 | 1826 | SecDataDir = (EFI_IMAGE_DATA_DIRECTORY *)&mNtHeader.Pe32Plus->OptionalHeader.DataDirectory[EFI_IMAGE_DIRECTORY_ENTRY_SECURITY];\r |
551d8081 | 1827 | }\r |
0c18794e | 1828 | }\r |
1829 | \r | |
6de4c35f | 1830 | //\r |
1831 | // Start Image Validation.\r | |
1832 | //\r | |
c411b485 | 1833 | if ((SecDataDir == NULL) || (SecDataDir->Size == 0)) {\r |
0c18794e | 1834 | //\r |
20333c6d | 1835 | // This image is not signed. The SHA256 hash value of the image must match a record in the security database "db",\r |
6de4c35f | 1836 | // and not be reflected in the security data base "dbx".\r |
0c18794e | 1837 | //\r |
45bf2c47 | 1838 | if (!HashPeImage (HASHALG_SHA256)) {\r |
531c89a1 | 1839 | DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Failed to hash this image using %s.\n", mHashTypeStr));\r |
c602e974 | 1840 | goto Failed;\r |
45bf2c47 | 1841 | }\r |
1842 | \r | |
b1c11470 JW |
1843 | DbStatus = IsSignatureFoundInDatabase (\r |
1844 | EFI_IMAGE_SECURITY_DATABASE1,\r | |
1845 | mImageDigest,\r | |
1846 | &mCertType,\r | |
1847 | mImageDigestSize,\r | |
1848 | &IsFound\r | |
1849 | );\r | |
1850 | if (EFI_ERROR (DbStatus) || IsFound) {\r | |
45bf2c47 | 1851 | //\r |
1852 | // Image Hash is in forbidden database (DBX).\r | |
1853 | //\r | |
531c89a1 | 1854 | DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is forbidden by DBX.\n", mHashTypeStr));\r |
c602e974 | 1855 | goto Failed;\r |
45bf2c47 | 1856 | }\r |
1857 | \r | |
b1c11470 JW |
1858 | DbStatus = IsSignatureFoundInDatabase (\r |
1859 | EFI_IMAGE_SECURITY_DATABASE,\r | |
1860 | mImageDigest,\r | |
1861 | &mCertType,\r | |
1862 | mImageDigestSize,\r | |
1863 | &IsFound\r | |
1864 | );\r | |
1865 | if (!EFI_ERROR (DbStatus) && IsFound) {\r | |
45bf2c47 | 1866 | //\r |
1867 | // Image Hash is in allowed database (DB).\r | |
1868 | //\r | |
1869 | return EFI_SUCCESS;\r | |
1870 | }\r | |
1871 | \r | |
1872 | //\r | |
1873 | // Image Hash is not found in both forbidden and allowed database.\r | |
1874 | //\r | |
531c89a1 | 1875 | DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is not signed and %s hash of image is not found in DB/DBX.\n", mHashTypeStr));\r |
c602e974 | 1876 | goto Failed;\r |
0c18794e | 1877 | }\r |
45bf2c47 | 1878 | \r |
0c18794e | 1879 | //\r |
20333c6d | 1880 | // Verify the signature of the image, multiple signatures are allowed as per PE/COFF Section 4.7\r |
6de4c35f | 1881 | // "Attribute Certificate Table".\r |
1882 | // The first certificate starts at offset (SecDataDir->VirtualAddress) from the start of the file.\r | |
0c18794e | 1883 | //\r |
503248cc | 1884 | SecDataDirEnd = SecDataDir->VirtualAddress + SecDataDir->Size;\r |
6de4c35f | 1885 | for (OffSet = SecDataDir->VirtualAddress;\r |
503248cc | 1886 | OffSet < SecDataDirEnd;\r |
c411b485 MK |
1887 | OffSet += (WinCertificate->dwLength + ALIGN_SIZE (WinCertificate->dwLength)))\r |
1888 | {\r | |
503248cc | 1889 | SecDataDirLeft = SecDataDirEnd - OffSet;\r |
a7632e91 LE |
1890 | if (SecDataDirLeft <= sizeof (WIN_CERTIFICATE)) {\r |
1891 | break;\r | |
1892 | }\r | |
c411b485 MK |
1893 | \r |
1894 | WinCertificate = (WIN_CERTIFICATE *)(mImageBase + OffSet);\r | |
1895 | if ((SecDataDirLeft < WinCertificate->dwLength) ||\r | |
0b143fa4 | 1896 | (SecDataDirLeft - WinCertificate->dwLength <\r |
c411b485 MK |
1897 | ALIGN_SIZE (WinCertificate->dwLength)))\r |
1898 | {\r | |
6de4c35f | 1899 | break;\r |
1900 | }\r | |
20333c6d | 1901 | \r |
0c18794e | 1902 | //\r |
6de4c35f | 1903 | // Verify the image's Authenticode signature, only DER-encoded PKCS#7 signed data is supported.\r |
0c18794e | 1904 | //\r |
6de4c35f | 1905 | if (WinCertificate->wCertificateType == WIN_CERT_TYPE_PKCS_SIGNED_DATA) {\r |
1906 | //\r | |
20333c6d | 1907 | // The certificate is formatted as WIN_CERTIFICATE_EFI_PKCS which is described in the\r |
6de4c35f | 1908 | // Authenticode specification.\r |
1909 | //\r | |
c411b485 | 1910 | PkcsCertData = (WIN_CERTIFICATE_EFI_PKCS *)WinCertificate;\r |
6de4c35f | 1911 | if (PkcsCertData->Hdr.dwLength <= sizeof (PkcsCertData->Hdr)) {\r |
1912 | break;\r | |
1913 | }\r | |
c411b485 MK |
1914 | \r |
1915 | AuthData = PkcsCertData->CertData;\r | |
1916 | AuthDataSize = PkcsCertData->Hdr.dwLength - sizeof (PkcsCertData->Hdr);\r | |
6de4c35f | 1917 | } else if (WinCertificate->wCertificateType == WIN_CERT_TYPE_EFI_GUID) {\r |
1918 | //\r | |
1919 | // The certificate is formatted as WIN_CERTIFICATE_UEFI_GUID which is described in UEFI Spec.\r | |
1920 | //\r | |
c411b485 MK |
1921 | WinCertUefiGuid = (WIN_CERTIFICATE_UEFI_GUID *)WinCertificate;\r |
1922 | if (WinCertUefiGuid->Hdr.dwLength <= OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData)) {\r | |
6de4c35f | 1923 | break;\r |
1924 | }\r | |
c411b485 | 1925 | \r |
6de4c35f | 1926 | if (!CompareGuid (&WinCertUefiGuid->CertType, &gEfiCertPkcs7Guid)) {\r |
1927 | continue;\r | |
1928 | }\r | |
c411b485 MK |
1929 | \r |
1930 | AuthData = WinCertUefiGuid->CertData;\r | |
1931 | AuthDataSize = WinCertUefiGuid->Hdr.dwLength - OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);\r | |
6de4c35f | 1932 | } else {\r |
1933 | if (WinCertificate->dwLength < sizeof (WIN_CERTIFICATE)) {\r | |
1934 | break;\r | |
1935 | }\r | |
c411b485 | 1936 | \r |
6de4c35f | 1937 | continue;\r |
84bce75b | 1938 | }\r |
6de4c35f | 1939 | \r |
47650a5c LE |
1940 | HashStatus = HashPeImageByType (AuthData, AuthDataSize);\r |
1941 | if (EFI_ERROR (HashStatus)) {\r | |
6de4c35f | 1942 | continue;\r |
0c18794e | 1943 | }\r |
20333c6d | 1944 | \r |
f6f9031f | 1945 | //\r |
6de4c35f | 1946 | // Check the digital signature against the revoked certificate in forbidden database (dbx).\r |
f6f9031f | 1947 | //\r |
560ac77e | 1948 | if (IsForbiddenByDbx (AuthData, AuthDataSize)) {\r |
c411b485 | 1949 | Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED;\r |
1e0f973b | 1950 | IsVerified = FALSE;\r |
6de4c35f | 1951 | break;\r |
f6f9031f | 1952 | }\r |
0c18794e | 1953 | \r |
1954 | //\r | |
6de4c35f | 1955 | // Check the digital signature against the valid certificate in allowed database (db).\r |
0c18794e | 1956 | //\r |
1e0f973b | 1957 | if (!IsVerified) {\r |
560ac77e | 1958 | if (IsAllowedByDb (AuthData, AuthDataSize)) {\r |
1e0f973b | 1959 | IsVerified = TRUE;\r |
6de4c35f | 1960 | }\r |
0c18794e | 1961 | }\r |
6de4c35f | 1962 | \r |
0c18794e | 1963 | //\r |
6de4c35f | 1964 | // Check the image's hash value.\r |
0c18794e | 1965 | //\r |
b1c11470 JW |
1966 | DbStatus = IsSignatureFoundInDatabase (\r |
1967 | EFI_IMAGE_SECURITY_DATABASE1,\r | |
1968 | mImageDigest,\r | |
1969 | &mCertType,\r | |
1970 | mImageDigestSize,\r | |
1971 | &IsFound\r | |
1972 | );\r | |
1973 | if (EFI_ERROR (DbStatus) || IsFound) {\r | |
6de4c35f | 1974 | Action = EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND;\r |
531c89a1 | 1975 | DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but %s hash of image is found in DBX.\n", mHashTypeStr));\r |
1e0f973b | 1976 | IsVerified = FALSE;\r |
6de4c35f | 1977 | break;\r |
eccb856f | 1978 | }\r |
b1c11470 | 1979 | \r |
eccb856f | 1980 | if (!IsVerified) {\r |
b1c11470 JW |
1981 | DbStatus = IsSignatureFoundInDatabase (\r |
1982 | EFI_IMAGE_SECURITY_DATABASE,\r | |
1983 | mImageDigest,\r | |
1984 | &mCertType,\r | |
1985 | mImageDigestSize,\r | |
1986 | &IsFound\r | |
1987 | );\r | |
1988 | if (!EFI_ERROR (DbStatus) && IsFound) {\r | |
1e0f973b | 1989 | IsVerified = TRUE;\r |
531c89a1 CS |
1990 | } else {\r |
1991 | DEBUG ((DEBUG_INFO, "DxeImageVerificationLib: Image is signed but signature is not allowed by DB and %s hash of image is not found in DB/DBX.\n", mHashTypeStr));\r | |
6de4c35f | 1992 | }\r |
45bf2c47 | 1993 | }\r |
50fe73a1 | 1994 | }\r |
1995 | \r | |
503248cc | 1996 | if (OffSet != SecDataDirEnd) {\r |
0c18794e | 1997 | //\r |
d6b926e7 | 1998 | // The Size in Certificate Table or the attribute certificate table is corrupted.\r |
0c18794e | 1999 | //\r |
1e0f973b | 2000 | IsVerified = FALSE;\r |
6de4c35f | 2001 | }\r |
20333c6d | 2002 | \r |
1e0f973b | 2003 | if (IsVerified) {\r |
6de4c35f | 2004 | return EFI_SUCCESS;\r |
eccb856f | 2005 | }\r |
c411b485 MK |
2006 | \r |
2007 | if ((Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FAILED) || (Action == EFI_IMAGE_EXECUTION_AUTH_SIG_FOUND)) {\r | |
eccb856f LE |
2008 | //\r |
2009 | // Get image hash value as signature of executable.\r | |
2010 | //\r | |
2011 | SignatureListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize;\r | |
c411b485 | 2012 | SignatureList = (EFI_SIGNATURE_LIST *)AllocateZeroPool (SignatureListSize);\r |
eccb856f | 2013 | if (SignatureList == NULL) {\r |
6aa31db5 | 2014 | SignatureListSize = 0;\r |
c602e974 | 2015 | goto Failed;\r |
50fe73a1 | 2016 | }\r |
c411b485 MK |
2017 | \r |
2018 | SignatureList->SignatureHeaderSize = 0;\r | |
2019 | SignatureList->SignatureListSize = (UINT32)SignatureListSize;\r | |
2020 | SignatureList->SignatureSize = (UINT32)(sizeof (EFI_SIGNATURE_DATA) - 1 + mImageDigestSize);\r | |
eccb856f | 2021 | CopyMem (&SignatureList->SignatureType, &mCertType, sizeof (EFI_GUID));\r |
c411b485 | 2022 | Signature = (EFI_SIGNATURE_DATA *)((UINT8 *)SignatureList + sizeof (EFI_SIGNATURE_LIST));\r |
eccb856f | 2023 | CopyMem (Signature->SignatureData, mImageDigest, mImageDigestSize);\r |
0c18794e | 2024 | }\r |
2025 | \r | |
c602e974 LE |
2026 | Failed:\r |
2027 | //\r | |
8b0932c1 LE |
2028 | // Policy decides to defer or reject the image; add its information in image\r |
2029 | // executable information table in either case.\r | |
c602e974 LE |
2030 | //\r |
2031 | NameStr = ConvertDevicePathToText (File, FALSE, TRUE);\r | |
2032 | AddImageExeInfo (Action, NameStr, File, SignatureList, SignatureListSize);\r | |
2033 | if (NameStr != NULL) {\r | |
2034 | DEBUG ((DEBUG_INFO, "The image doesn't pass verification: %s\n", NameStr));\r | |
c411b485 | 2035 | FreePool (NameStr);\r |
0c18794e | 2036 | }\r |
2037 | \r | |
2038 | if (SignatureList != NULL) {\r | |
2039 | FreePool (SignatureList);\r | |
2040 | }\r | |
2041 | \r | |
8b0932c1 LE |
2042 | if (Policy == DEFER_EXECUTE_ON_SECURITY_VIOLATION) {\r |
2043 | return EFI_SECURITY_VIOLATION;\r | |
2044 | }\r | |
c411b485 | 2045 | \r |
8b0932c1 | 2046 | return EFI_ACCESS_DENIED;\r |
0c18794e | 2047 | }\r |
2048 | \r | |
ffccb935 DG |
2049 | /**\r |
2050 | On Ready To Boot Services Event notification handler.\r | |
2051 | \r | |
2052 | Add the image execution information table if it is not in system configuration table.\r | |
2053 | \r | |
2054 | @param[in] Event Event whose notification function is being invoked\r | |
2055 | @param[in] Context Pointer to the notification function's context\r | |
2056 | \r | |
2057 | **/\r | |
2058 | VOID\r | |
2059 | EFIAPI\r | |
2060 | OnReadyToBoot (\r | |
c411b485 MK |
2061 | IN EFI_EVENT Event,\r |
2062 | IN VOID *Context\r | |
ffccb935 DG |
2063 | )\r |
2064 | {\r | |
2065 | EFI_IMAGE_EXECUTION_INFO_TABLE *ImageExeInfoTable;\r | |
2066 | UINTN ImageExeInfoTableSize;\r | |
2067 | \r | |
c411b485 | 2068 | EfiGetSystemConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID **)&ImageExeInfoTable);\r |
ffccb935 DG |
2069 | if (ImageExeInfoTable != NULL) {\r |
2070 | return;\r | |
2071 | }\r | |
2072 | \r | |
2073 | ImageExeInfoTableSize = sizeof (EFI_IMAGE_EXECUTION_INFO_TABLE);\r | |
c411b485 | 2074 | ImageExeInfoTable = (EFI_IMAGE_EXECUTION_INFO_TABLE *)AllocateRuntimePool (ImageExeInfoTableSize);\r |
ffccb935 | 2075 | if (ImageExeInfoTable == NULL) {\r |
c411b485 | 2076 | return;\r |
ffccb935 DG |
2077 | }\r |
2078 | \r | |
20333c6d | 2079 | ImageExeInfoTable->NumberOfImages = 0;\r |
c411b485 | 2080 | gBS->InstallConfigurationTable (&gEfiImageSecurityDatabaseGuid, (VOID *)ImageExeInfoTable);\r |
ffccb935 DG |
2081 | }\r |
2082 | \r | |
0c18794e | 2083 | /**\r |
2084 | Register security measurement handler.\r | |
2085 | \r | |
2086 | @param ImageHandle ImageHandle of the loaded driver.\r | |
2087 | @param SystemTable Pointer to the EFI System Table.\r | |
2088 | \r | |
2089 | @retval EFI_SUCCESS The handlers were registered successfully.\r | |
2090 | **/\r | |
2091 | EFI_STATUS\r | |
2092 | EFIAPI\r | |
2093 | DxeImageVerificationLibConstructor (\r | |
2094 | IN EFI_HANDLE ImageHandle,\r | |
2095 | IN EFI_SYSTEM_TABLE *SystemTable\r | |
2096 | )\r | |
2097 | {\r | |
c411b485 | 2098 | EFI_EVENT Event;\r |
ffccb935 DG |
2099 | \r |
2100 | //\r | |
2101 | // Register the event to publish the image execution table.\r | |
2102 | //\r | |
2103 | EfiCreateEventReadyToBootEx (\r | |
2104 | TPL_CALLBACK,\r | |
20333c6d QL |
2105 | OnReadyToBoot,\r |
2106 | NULL,\r | |
ffccb935 | 2107 | &Event\r |
20333c6d | 2108 | );\r |
ffccb935 | 2109 | \r |
5db28a67 | 2110 | return RegisterSecurity2Handler (\r |
c411b485 MK |
2111 | DxeImageVerificationHandler,\r |
2112 | EFI_AUTH_OPERATION_VERIFY_IMAGE | EFI_AUTH_OPERATION_IMAGE_REQUIRED\r | |
2113 | );\r | |
0c18794e | 2114 | }\r |