]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.c
IntelFrameworkModulePkg: Fix MSFT C4255 warning
[mirror_edk2.git] / MdeModulePkg / Library / DxeSecurityManagementLib / DxeSecurityManagementLib.c
CommitLineData
cd98f305
LG
1/** @file\r
2 Provides generic security measurement functions for DXE module.\r
3\r
2b75e8cd 4Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>\r
cd5ebaa0 5This program and the accompanying materials\r
cd98f305
LG
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
12\r
13**/\r
14\r
15#include <PiDxe.h>\r
2b75e8cd 16#include <Protocol/LoadFile.h>\r
cd98f305
LG
17#include <Library/DebugLib.h>\r
18#include <Library/DxeServicesLib.h>\r
19#include <Library/MemoryAllocationLib.h>\r
20#include <Library/SecurityManagementLib.h>\r
2b75e8cd
LG
21#include <Library/DevicePathLib.h>\r
22#include <Library/UefiBootServicesTableLib.h>\r
cd98f305
LG
23\r
24#define SECURITY_HANDLER_TABLE_SIZE 0x10\r
25\r
bc2dfdbc
LG
26//\r
27// Secruity Operation on Image and none Image.\r
28//\r
29#define EFI_AUTH_IMAGE_OPERATION_MASK (EFI_AUTH_OPERATION_VERIFY_IMAGE \\r
30 | EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD \\r
31 | EFI_AUTH_OPERATION_MEASURE_IMAGE)\r
32#define EFI_AUTH_NONE_IMAGE_OPERATION_MASK (EFI_AUTH_OPERATION_CONNECT_POLICY \\r
33 | EFI_AUTH_OPERATION_AUTHENTICATION_STATE)\r
cd98f305
LG
34\r
35typedef struct {\r
36 UINT32 SecurityOperation;\r
37 SECURITY_FILE_AUTHENTICATION_STATE_HANDLER SecurityHandler;\r
38} SECURITY_INFO;\r
39\r
bc2dfdbc
LG
40typedef struct {\r
41 UINT32 Security2Operation;\r
42 SECURITY2_FILE_AUTHENTICATION_HANDLER Security2Handler;\r
43} SECURITY2_INFO;\r
44\r
cd98f305
LG
45UINT32 mCurrentAuthOperation = 0;\r
46UINT32 mNumberOfSecurityHandler = 0;\r
47UINT32 mMaxNumberOfSecurityHandler = 0;\r
48SECURITY_INFO *mSecurityTable = NULL;\r
49\r
bc2dfdbc
LG
50UINT32 mCurrentAuthOperation2 = 0;\r
51UINT32 mNumberOfSecurity2Handler = 0;\r
52UINT32 mMaxNumberOfSecurity2Handler = 0;\r
53SECURITY2_INFO *mSecurity2Table = NULL;\r
54\r
cd98f305
LG
55/**\r
56 Reallocates more global memory to store the registered Handler list.\r
57\r
58 @retval RETURN_SUCCESS Reallocate memory successfully.\r
59 @retval RETURN_OUT_OF_RESOURCES No enough memory to allocated.\r
60**/\r
61RETURN_STATUS\r
62EFIAPI\r
63ReallocateSecurityHandlerTable (\r
64 )\r
65{\r
66 //\r
67 // Reallocate memory for security info structure.\r
68 //\r
69 mSecurityTable = ReallocatePool (\r
70 mMaxNumberOfSecurityHandler * sizeof (SECURITY_INFO), \r
71 (mMaxNumberOfSecurityHandler + SECURITY_HANDLER_TABLE_SIZE) * sizeof (SECURITY_INFO), \r
72 mSecurityTable\r
73 );\r
74\r
75 //\r
76 // No enough resource is allocated.\r
77 //\r
78 if (mSecurityTable == NULL) {\r
79 return RETURN_OUT_OF_RESOURCES;\r
80 }\r
81\r
82 //\r
83 // Increase max handler number\r
84 //\r
85 mMaxNumberOfSecurityHandler = mMaxNumberOfSecurityHandler + SECURITY_HANDLER_TABLE_SIZE;\r
86 return RETURN_SUCCESS;\r
87}\r
88\r
89/**\r
90 Check whether an operation is valid according to the requirement of current operation, \r
91 which must make sure that the measure image operation is the last one.\r
92\r
93 @param CurrentAuthOperation Current operation.\r
94 @param CheckAuthOperation Operation to be checked.\r
95\r
96 @retval TRUE Operation is valid for current operation.\r
97 @retval FALSE Operation is invalid for current operation.\r
98**/\r
99BOOLEAN\r
100CheckAuthenticationOperation (\r
101 IN UINT32 CurrentAuthOperation,\r
102 IN UINT32 CheckAuthOperation\r
103 )\r
104{ \r
105 //\r
106 // Make sure new auth operation can be recognized.\r
107 //\r
c9e88815 108 ASSERT ((CheckAuthOperation & ~(EFI_AUTH_IMAGE_OPERATION_MASK | EFI_AUTH_OPERATION_AUTHENTICATION_STATE | EFI_AUTH_OPERATION_IMAGE_REQUIRED)) == 0);\r
cd98f305
LG
109 \r
110 //\r
111 // When current operation includes measure image operation, \r
112 // only another measure image operation or none operation will be allowed.\r
113 //\r
114 if ((CurrentAuthOperation & EFI_AUTH_OPERATION_MEASURE_IMAGE) == EFI_AUTH_OPERATION_MEASURE_IMAGE) {\r
115 if (((CheckAuthOperation & EFI_AUTH_OPERATION_MEASURE_IMAGE) == EFI_AUTH_OPERATION_MEASURE_IMAGE) ||\r
bc2dfdbc 116 ((CheckAuthOperation & EFI_AUTH_IMAGE_OPERATION_MASK) == EFI_AUTH_OPERATION_NONE)) {\r
cd98f305
LG
117 return TRUE;\r
118 } else {\r
119 return FALSE;\r
120 }\r
121 }\r
122 \r
123 //\r
124 // When current operation doesn't include measure image operation, \r
125 // any new operation will be allowed.\r
126 //\r
127 return TRUE;\r
128}\r
129\r
130/**\r
131 Register security measurement handler with its operation type. The different\r
132 handler with the same operation can all be registered.\r
133\r
134 If SecurityHandler is NULL, then ASSERT().\r
135 If no enough resources available to register new handler, then ASSERT().\r
136 If AuthenticationOperation is not recongnized, then ASSERT().\r
137 If the previous register handler can't be executed before the later register handler, then ASSERT().\r
138\r
139 @param[in] SecurityHandler Security measurement service handler to be registered.\r
140 @param[in] AuthenticationOperation Operation type is specified for the registered handler.\r
141\r
142 @retval EFI_SUCCESS The handlers were registered successfully.\r
143**/\r
144EFI_STATUS\r
145EFIAPI\r
146RegisterSecurityHandler (\r
147 IN SECURITY_FILE_AUTHENTICATION_STATE_HANDLER SecurityHandler,\r
148 IN UINT32 AuthenticationOperation\r
149 )\r
150{\r
151 EFI_STATUS Status;\r
152\r
153 ASSERT (SecurityHandler != NULL);\r
154\r
155 //\r
156 // Make sure AuthenticationOperation is valid in the register order.\r
157 //\r
158 ASSERT (CheckAuthenticationOperation (mCurrentAuthOperation, AuthenticationOperation));\r
159 mCurrentAuthOperation = mCurrentAuthOperation | AuthenticationOperation;\r
160\r
161 //\r
162 // Check whether the handler lists is enough to store new handler.\r
163 //\r
164 if (mNumberOfSecurityHandler == mMaxNumberOfSecurityHandler) {\r
165 //\r
166 // Allocate more resources for new handler.\r
167 //\r
168 Status = ReallocateSecurityHandlerTable();\r
169 ASSERT_EFI_ERROR (Status);\r
170 }\r
171\r
172 //\r
173 // Register new handler into the handler list.\r
174 //\r
175 mSecurityTable[mNumberOfSecurityHandler].SecurityOperation = AuthenticationOperation;\r
176 mSecurityTable[mNumberOfSecurityHandler].SecurityHandler = SecurityHandler;\r
177 mNumberOfSecurityHandler ++;\r
178\r
179 return EFI_SUCCESS;\r
180}\r
181\r
182/**\r
183 Execute registered handlers until one returns an error and that error is returned.\r
184 If none of the handlers return an error, then EFI_SUCCESS is returned.\r
185\r
186 Before exectue handler, get the image buffer by file device path if a handler \r
187 requires the image file. And return the image buffer to each handler when exectue handler.\r
188\r
189 The handlers are executed in same order to their registered order.\r
190\r
191 @param[in] AuthenticationStatus \r
192 This is the authentication type returned from the Section\r
193 Extraction protocol. See the Section Extraction Protocol\r
194 Specification for details on this type.\r
195 @param[in] FilePath This is a pointer to the device path of the file that is\r
196 being dispatched. This will optionally be used for logging.\r
197\r
198 @retval EFI_SUCCESS The file specified by File did authenticate when more\r
199 than one security handler services were registered, \r
200 or the file did not authenticate when no security \r
201 handler service was registered. And the platform policy \r
202 dictates that the DXE Core may use File.\r
203 @retval EFI_INVALID_PARAMETER File is NULL.\r
204 @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r
205 the platform policy dictates that File should be placed\r
206 in the untrusted state. A file may be promoted from\r
207 the untrusted to the trusted state at a future time\r
208 with a call to the Trust() DXE Service.\r
209 @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and\r
210 the platform policy dictates that File should not be\r
211 used for any purpose.\r
212**/\r
213EFI_STATUS\r
214EFIAPI\r
215ExecuteSecurityHandlers (\r
216 IN UINT32 AuthenticationStatus,\r
217 IN CONST EFI_DEVICE_PATH_PROTOCOL *FilePath\r
218 )\r
219{\r
220 UINT32 Index;\r
221 EFI_STATUS Status;\r
222 UINT32 HandlerAuthenticationStatus;\r
223 VOID *FileBuffer;\r
224 UINTN FileSize;\r
2b75e8cd
LG
225 EFI_HANDLE Handle;\r
226 EFI_DEVICE_PATH_PROTOCOL *Node;\r
227 EFI_DEVICE_PATH_PROTOCOL *FilePathToVerfiy;\r
cd98f305
LG
228 \r
229 if (FilePath == NULL) {\r
230 return EFI_INVALID_PARAMETER;\r
231 }\r
232\r
233 //\r
234 // Directly return successfully when no handler is registered.\r
235 //\r
236 if (mNumberOfSecurityHandler == 0) {\r
237 return EFI_SUCCESS;\r
238 }\r
239 \r
240 Status = EFI_SUCCESS;\r
241 FileBuffer = NULL;\r
242 FileSize = 0;\r
243 HandlerAuthenticationStatus = AuthenticationStatus;\r
2b75e8cd 244 FilePathToVerfiy = (EFI_DEVICE_PATH_PROTOCOL *) FilePath;\r
cd98f305
LG
245 //\r
246 // Run security handler in same order to their registered list\r
247 //\r
248 for (Index = 0; Index < mNumberOfSecurityHandler; Index ++) {\r
249 if ((mSecurityTable[Index].SecurityOperation & EFI_AUTH_OPERATION_IMAGE_REQUIRED) == EFI_AUTH_OPERATION_IMAGE_REQUIRED) {\r
250 //\r
251 // Try get file buffer when the handler requires image buffer.\r
252 //\r
253 if (FileBuffer == NULL) {\r
2b75e8cd
LG
254 Node = FilePathToVerfiy;\r
255 Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &Node, &Handle);\r
2983a79d
LG
256 //\r
257 // Try to get image by FALSE boot policy for the exact boot file path.\r
258 //\r
cd98f305 259 FileBuffer = GetFileBufferByFilePath (FALSE, FilePath, &FileSize, &AuthenticationStatus);\r
2983a79d
LG
260 if (FileBuffer == NULL) {\r
261 //\r
262 // Try to get image by TRUE boot policy for the inexact boot file path.\r
263 //\r
264 FileBuffer = GetFileBufferByFilePath (TRUE, FilePath, &FileSize, &AuthenticationStatus);\r
265 }\r
2b75e8cd
LG
266 if ((FileBuffer != NULL) && (!EFI_ERROR (Status))) {\r
267 //\r
268 // LoadFile () may cause the device path of the Handle be updated.\r
269 //\r
270 FilePathToVerfiy = AppendDevicePath (DevicePathFromHandle (Handle), Node);\r
271 }\r
cd98f305
LG
272 }\r
273 }\r
274 Status = mSecurityTable[Index].SecurityHandler (\r
275 HandlerAuthenticationStatus,\r
2b75e8cd 276 FilePathToVerfiy,\r
cd98f305
LG
277 FileBuffer,\r
278 FileSize\r
279 );\r
280 if (EFI_ERROR (Status)) {\r
281 break;\r
282 }\r
283 }\r
284\r
285 if (FileBuffer != NULL) {\r
286 FreePool (FileBuffer);\r
287 }\r
2b75e8cd
LG
288 if (FilePathToVerfiy != FilePath) {\r
289 FreePool (FilePathToVerfiy);\r
290 }\r
cd98f305
LG
291\r
292 return Status;\r
293}\r
bc2dfdbc
LG
294\r
295/**\r
296 Reallocates more global memory to store the registered Securit2Handler list.\r
297\r
298 @retval RETURN_SUCCESS Reallocate memory successfully.\r
299 @retval RETURN_OUT_OF_RESOURCES No enough memory to allocated.\r
300**/\r
301RETURN_STATUS\r
302EFIAPI\r
303ReallocateSecurity2HandlerTable (\r
304 )\r
305{\r
306 //\r
307 // Reallocate memory for security info structure.\r
308 //\r
309 mSecurity2Table = ReallocatePool (\r
310 mMaxNumberOfSecurity2Handler * sizeof (SECURITY2_INFO), \r
311 (mMaxNumberOfSecurity2Handler + SECURITY_HANDLER_TABLE_SIZE) * sizeof (SECURITY2_INFO), \r
312 mSecurity2Table\r
313 );\r
314\r
315 //\r
316 // No enough resource is allocated.\r
317 //\r
318 if (mSecurity2Table == NULL) {\r
319 return RETURN_OUT_OF_RESOURCES;\r
320 }\r
321\r
322 //\r
323 // Increase max handler number\r
324 //\r
325 mMaxNumberOfSecurity2Handler = mMaxNumberOfSecurity2Handler + SECURITY_HANDLER_TABLE_SIZE;\r
326 return RETURN_SUCCESS;\r
327}\r
328\r
329/**\r
330 Check whether an operation is valid according to the requirement of current operation, \r
331 which must make sure that the measure image operation is the last one.\r
332 \r
333 If AuthenticationOperation is not recongnized, return FALSE.\r
334 If AuthenticationOperation is EFI_AUTH_OPERATION_NONE, return FALSE.\r
335 If AuthenticationOperation includes security operation and authentication operation, return FALSE.\r
336 If the previous register handler can't be executed before the later register handler, return FALSE.\r
337 \r
338 @param CurrentAuthOperation Current operation.\r
339 @param CheckAuthOperation Operation to be checked.\r
340 \r
341 @retval TRUE Operation is valid for current operation.\r
342 @retval FALSE Operation is invalid for current operation.\r
343**/\r
344BOOLEAN\r
345CheckAuthentication2Operation (\r
346 IN UINT32 CurrentAuthOperation,\r
347 IN UINT32 CheckAuthOperation\r
348 )\r
349{ \r
350 //\r
351 // Make sure new auth operation can be recognized.\r
352 //\r
353 if (CheckAuthOperation == EFI_AUTH_OPERATION_NONE) {\r
354 return FALSE;\r
355 }\r
356 if ((CheckAuthOperation & ~(EFI_AUTH_IMAGE_OPERATION_MASK | \r
357 EFI_AUTH_NONE_IMAGE_OPERATION_MASK | \r
358 EFI_AUTH_OPERATION_IMAGE_REQUIRED)) != 0) {\r
359 return FALSE;\r
360 }\r
361\r
362 //\r
363 // When current operation includes measure image operation, \r
364 // only another measure image or none image operation will be allowed.\r
365 //\r
366 if ((CurrentAuthOperation & EFI_AUTH_OPERATION_MEASURE_IMAGE) == EFI_AUTH_OPERATION_MEASURE_IMAGE) {\r
367 if (((CheckAuthOperation & EFI_AUTH_OPERATION_MEASURE_IMAGE) == EFI_AUTH_OPERATION_MEASURE_IMAGE) ||\r
368 ((CheckAuthOperation & EFI_AUTH_IMAGE_OPERATION_MASK) == 0)) {\r
369 return TRUE;\r
370 } else {\r
371 return FALSE;\r
372 }\r
373 }\r
374 \r
375 //\r
376 // Any other operation will be allowed.\r
377 //\r
378 return TRUE;\r
379}\r
380\r
381/**\r
382 Register security measurement handler with its operation type. Different\r
383 handlers with the same operation can all be registered.\r
384\r
385 If Security2Handler is NULL, then ASSERT().\r
386 If no enough resources available to register new handler, then ASSERT().\r
387 If AuthenticationOperation is not recongnized, then ASSERT().\r
388 If AuthenticationOperation is EFI_AUTH_OPERATION_NONE, then ASSERT().\r
389 If the previous register handler can't be executed before the later register handler, then ASSERT().\r
390\r
391 @param[in] Security2Handler The security measurement service handler to be registered.\r
392 @param[in] AuthenticationOperation The operation type is specified for the registered handler.\r
393\r
394 @retval EFI_SUCCESS The handlers were registered successfully.\r
395**/\r
396EFI_STATUS\r
397EFIAPI\r
398RegisterSecurity2Handler (\r
399 IN SECURITY2_FILE_AUTHENTICATION_HANDLER Security2Handler,\r
400 IN UINT32 AuthenticationOperation\r
401 )\r
402{\r
403 EFI_STATUS Status;\r
404\r
405 ASSERT (Security2Handler != NULL);\r
406\r
407 //\r
408 // Make sure AuthenticationOperation is valid in the register order.\r
409 //\r
410 ASSERT (CheckAuthentication2Operation (mCurrentAuthOperation2, AuthenticationOperation));\r
411 mCurrentAuthOperation2 = mCurrentAuthOperation2 | AuthenticationOperation;\r
412\r
413 //\r
414 // Check whether the handler lists is enough to store new handler.\r
415 //\r
416 if (mNumberOfSecurity2Handler == mMaxNumberOfSecurity2Handler) {\r
417 //\r
418 // Allocate more resources for new handler.\r
419 //\r
420 Status = ReallocateSecurity2HandlerTable();\r
421 ASSERT_EFI_ERROR (Status);\r
422 }\r
423\r
424 //\r
425 // Register new handler into the handler list.\r
426 //\r
427 mSecurity2Table[mNumberOfSecurity2Handler].Security2Operation = AuthenticationOperation;\r
428 mSecurity2Table[mNumberOfSecurity2Handler].Security2Handler = Security2Handler;\r
429 mNumberOfSecurity2Handler ++;\r
430\r
431 return EFI_SUCCESS;\r
432}\r
433\r
434/**\r
435 Execute registered handlers based on input AuthenticationOperation until \r
436 one returns an error and that error is returned. \r
437 \r
438 If none of the handlers return an error, then EFI_SUCCESS is returned.\r
439 The handlers those satisfy AuthenticationOperation will only be executed.\r
440 The handlers are executed in same order to their registered order.\r
441\r
442 @param[in] AuthenticationOperation \r
443 The operation type specifies which handlers will be executed.\r
444 @param[in] AuthenticationStatus \r
445 The authentication status for the input file.\r
446 @param[in] File This is a pointer to the device path of the file that is\r
447 being dispatched. This will optionally be used for logging.\r
448 @param[in] FileBuffer A pointer to the buffer with the UEFI file image\r
449 @param[in] FileSize The size of File buffer.\r
450 @param[in] BootPolicy A boot policy that was used to call LoadImage() UEFI service.\r
451\r
452 @retval EFI_SUCCESS The file specified by DevicePath and non-NULL\r
453 FileBuffer did authenticate, and the platform policy dictates\r
454 that the DXE Foundation may use the file.\r
455 @retval EFI_SUCCESS The device path specified by NULL device path DevicePath\r
456 and non-NULL FileBuffer did authenticate, and the platform\r
457 policy dictates that the DXE Foundation may execute the image in\r
458 FileBuffer.\r
459 @retval EFI_SUCCESS FileBuffer is NULL and current user has permission to start\r
460 UEFI device drivers on the device path specified by DevicePath.\r
461 @retval EFI_SECURITY_VIOLATION The file specified by File or FileBuffer did not\r
462 authenticate, and the platform policy dictates that \r
463 the file should be placed in the untrusted state.\r
464 @retval EFI_SECURITY_VIOLATION FileBuffer FileBuffer is NULL and the user has no\r
465 permission to start UEFI device drivers on the device path specified\r
466 by DevicePath.\r
467 @retval EFI_SECURITY_VIOLATION FileBuffer is not NULL and the user has no permission to load\r
468 drivers from the device path specified by DevicePath. The\r
469 image has been added into the list of the deferred images.\r
470 @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and\r
471 the platform policy dictates that the DXE\r
472 Foundation may not use File.\r
473 @retval EFI_INVALID_PARAMETER File and FileBuffer are both NULL. \r
474**/\r
475EFI_STATUS\r
476EFIAPI\r
477ExecuteSecurity2Handlers (\r
478 IN UINT32 AuthenticationOperation,\r
479 IN UINT32 AuthenticationStatus,\r
480 IN CONST EFI_DEVICE_PATH_PROTOCOL *File,\r
481 IN VOID *FileBuffer,\r
482 IN UINTN FileSize,\r
483 IN BOOLEAN BootPolicy\r
484 )\r
485{\r
486 UINT32 Index;\r
487 EFI_STATUS Status;\r
488\r
489 //\r
490 // Invalid case if File and FileBuffer are both NULL.\r
491 //\r
492 if (File == NULL && FileBuffer == NULL) {\r
493 return EFI_INVALID_PARAMETER;\r
494 }\r
495\r
496 //\r
497 // Directly return successfully when no handler is registered.\r
498 //\r
499 if (mNumberOfSecurity2Handler == 0) {\r
500 return EFI_SUCCESS;\r
501 }\r
502\r
503 //\r
504 // Run security handler in same order to their registered list\r
505 //\r
506 for (Index = 0; Index < mNumberOfSecurity2Handler; Index ++) {\r
507 //\r
508 // If FileBuffer is not NULL, the input is Image, which will be handled by EFI_AUTH_IMAGE_OPERATION_MASK operation.\r
509 // If FileBuffer is NULL, the input is not Image, which will be handled by EFI_AUTH_NONE_IMAGE_OPERATION_MASK operation.\r
510 // Other cases are ignored.\r
511 //\r
512 if ((FileBuffer != NULL && (mSecurity2Table[Index].Security2Operation & EFI_AUTH_IMAGE_OPERATION_MASK) != 0) ||\r
513 (FileBuffer == NULL && (mSecurity2Table[Index].Security2Operation & EFI_AUTH_NONE_IMAGE_OPERATION_MASK) != 0)) {\r
514 //\r
515 // Execute registered handlers based on input AuthenticationOperation\r
516 //\r
517 if ((mSecurity2Table[Index].Security2Operation & AuthenticationOperation) != 0) {\r
518 Status = mSecurity2Table[Index].Security2Handler (\r
519 AuthenticationStatus,\r
520 File,\r
521 FileBuffer,\r
522 FileSize,\r
523 BootPolicy\r
524 );\r
525 if (EFI_ERROR (Status)) {\r
526 return Status;\r
527 }\r
528 }\r
529 }\r
530 }\r
531\r
532 return EFI_SUCCESS;\r
533}\r