--- /dev/null
+/** @file\r
+ Provides generic security measurement functions for DXE module.\r
+\r
+Copyright (c) 2009 Intel Corporation\r
+All rights reserved. This program and the accompanying materials\r
+are licensed and made available under the terms and conditions of the BSD License\r
+which accompanies this distribution. The full text of the license may be found at\r
+http://opensource.org/licenses/bsd-license.php\r
+\r
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/DxeServicesLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/SecurityManagementLib.h>\r
+\r
+#define SECURITY_HANDLER_TABLE_SIZE 0x10\r
+\r
+#define EFI_AUTH_OPERATION_MASK EFI_AUTH_OPERATION_VERIFY_IMAGE \\r
+ | EFI_AUTH_OPERATION_DEFER_IMAGE_LOAD \\r
+ | EFI_AUTH_OPERATION_MEASURE_IMAGE\r
+\r
+typedef struct {\r
+ UINT32 SecurityOperation;\r
+ SECURITY_FILE_AUTHENTICATION_STATE_HANDLER SecurityHandler;\r
+} SECURITY_INFO;\r
+\r
+UINT32 mCurrentAuthOperation = 0;\r
+UINT32 mNumberOfSecurityHandler = 0;\r
+UINT32 mMaxNumberOfSecurityHandler = 0;\r
+SECURITY_INFO *mSecurityTable = NULL;\r
+\r
+/**\r
+ Reallocates more global memory to store the registered Handler list.\r
+\r
+ @retval RETURN_SUCCESS Reallocate memory successfully.\r
+ @retval RETURN_OUT_OF_RESOURCES No enough memory to allocated.\r
+**/\r
+RETURN_STATUS\r
+EFIAPI\r
+ReallocateSecurityHandlerTable (\r
+ )\r
+{\r
+ //\r
+ // Reallocate memory for security info structure.\r
+ //\r
+ mSecurityTable = ReallocatePool (\r
+ mMaxNumberOfSecurityHandler * sizeof (SECURITY_INFO), \r
+ (mMaxNumberOfSecurityHandler + SECURITY_HANDLER_TABLE_SIZE) * sizeof (SECURITY_INFO), \r
+ mSecurityTable\r
+ );\r
+\r
+ //\r
+ // No enough resource is allocated.\r
+ //\r
+ if (mSecurityTable == NULL) {\r
+ return RETURN_OUT_OF_RESOURCES;\r
+ }\r
+\r
+ //\r
+ // Increase max handler number\r
+ //\r
+ mMaxNumberOfSecurityHandler = mMaxNumberOfSecurityHandler + SECURITY_HANDLER_TABLE_SIZE;\r
+ return RETURN_SUCCESS;\r
+}\r
+\r
+/**\r
+ Check whether an operation is valid according to the requirement of current operation, \r
+ which must make sure that the measure image operation is the last one.\r
+\r
+ @param CurrentAuthOperation Current operation.\r
+ @param CheckAuthOperation Operation to be checked.\r
+\r
+ @retval TRUE Operation is valid for current operation.\r
+ @retval FALSE Operation is invalid for current operation.\r
+**/\r
+BOOLEAN\r
+CheckAuthenticationOperation (\r
+ IN UINT32 CurrentAuthOperation,\r
+ IN UINT32 CheckAuthOperation\r
+ )\r
+{ \r
+ //\r
+ // Make sure new auth operation can be recognized.\r
+ //\r
+ ASSERT ((CheckAuthOperation & ~(EFI_AUTH_OPERATION_MASK | EFI_AUTH_OPERATION_IMAGE_REQUIRED)) == 0);\r
+ \r
+ //\r
+ // When current operation includes measure image operation, \r
+ // only another measure image operation or none operation will be allowed.\r
+ //\r
+ if ((CurrentAuthOperation & EFI_AUTH_OPERATION_MEASURE_IMAGE) == EFI_AUTH_OPERATION_MEASURE_IMAGE) {\r
+ if (((CheckAuthOperation & EFI_AUTH_OPERATION_MEASURE_IMAGE) == EFI_AUTH_OPERATION_MEASURE_IMAGE) ||\r
+ ((CheckAuthOperation & EFI_AUTH_OPERATION_MASK) == EFI_AUTH_OPERATION_NONE)) {\r
+ return TRUE;\r
+ } else {\r
+ return FALSE;\r
+ }\r
+ }\r
+ \r
+ //\r
+ // When current operation doesn't include measure image operation, \r
+ // any new operation will be allowed.\r
+ //\r
+ return TRUE;\r
+}\r
+\r
+/**\r
+ Register security measurement handler with its operation type. The different\r
+ handler with the same operation can all be registered.\r
+\r
+ If SecurityHandler is NULL, then ASSERT().\r
+ If no enough resources available to register new handler, then ASSERT().\r
+ If AuthenticationOperation is not recongnized, then ASSERT().\r
+ If the previous register handler can't be executed before the later register handler, then ASSERT().\r
+\r
+ @param[in] SecurityHandler Security measurement service handler to be registered.\r
+ @param[in] AuthenticationOperation Operation type is specified for the registered handler.\r
+\r
+ @retval EFI_SUCCESS The handlers were registered successfully.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+RegisterSecurityHandler (\r
+ IN SECURITY_FILE_AUTHENTICATION_STATE_HANDLER SecurityHandler,\r
+ IN UINT32 AuthenticationOperation\r
+ )\r
+{\r
+ EFI_STATUS Status;\r
+\r
+ ASSERT (SecurityHandler != NULL);\r
+\r
+ //\r
+ // Make sure AuthenticationOperation is valid in the register order.\r
+ //\r
+ ASSERT (CheckAuthenticationOperation (mCurrentAuthOperation, AuthenticationOperation));\r
+ mCurrentAuthOperation = mCurrentAuthOperation | AuthenticationOperation;\r
+\r
+ //\r
+ // Check whether the handler lists is enough to store new handler.\r
+ //\r
+ if (mNumberOfSecurityHandler == mMaxNumberOfSecurityHandler) {\r
+ //\r
+ // Allocate more resources for new handler.\r
+ //\r
+ Status = ReallocateSecurityHandlerTable();\r
+ ASSERT_EFI_ERROR (Status);\r
+ }\r
+\r
+ //\r
+ // Register new handler into the handler list.\r
+ //\r
+ mSecurityTable[mNumberOfSecurityHandler].SecurityOperation = AuthenticationOperation;\r
+ mSecurityTable[mNumberOfSecurityHandler].SecurityHandler = SecurityHandler;\r
+ mNumberOfSecurityHandler ++;\r
+\r
+ return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+ Execute registered handlers until one returns an error and that error is returned.\r
+ If none of the handlers return an error, then EFI_SUCCESS is returned.\r
+\r
+ Before exectue handler, get the image buffer by file device path if a handler \r
+ requires the image file. And return the image buffer to each handler when exectue handler.\r
+\r
+ The handlers are executed in same order to their registered order.\r
+\r
+ @param[in] AuthenticationStatus \r
+ This is the authentication type returned from the Section\r
+ Extraction protocol. See the Section Extraction Protocol\r
+ Specification for details on this type.\r
+ @param[in] FilePath This is a pointer to the device path of the file that is\r
+ being dispatched. This will optionally be used for logging.\r
+\r
+ @retval EFI_SUCCESS The file specified by File did authenticate when more\r
+ than one security handler services were registered, \r
+ or the file did not authenticate when no security \r
+ handler service was registered. And the platform policy \r
+ dictates that the DXE Core may use File.\r
+ @retval EFI_INVALID_PARAMETER File is NULL.\r
+ @retval EFI_SECURITY_VIOLATION The file specified by File did not authenticate, and\r
+ the platform policy dictates that File should be placed\r
+ in the untrusted state. A file may be promoted from\r
+ the untrusted to the trusted state at a future time\r
+ with a call to the Trust() DXE Service.\r
+ @retval EFI_ACCESS_DENIED The file specified by File did not authenticate, and\r
+ the platform policy dictates that File should not be\r
+ used for any purpose.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+ExecuteSecurityHandlers (\r
+ IN UINT32 AuthenticationStatus,\r
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *FilePath\r
+ )\r
+{\r
+ UINT32 Index;\r
+ EFI_STATUS Status;\r
+ UINT32 HandlerAuthenticationStatus;\r
+ VOID *FileBuffer;\r
+ UINTN FileSize;\r
+ \r
+ if (FilePath == NULL) {\r
+ return EFI_INVALID_PARAMETER;\r
+ }\r
+\r
+ //\r
+ // Directly return successfully when no handler is registered.\r
+ //\r
+ if (mNumberOfSecurityHandler == 0) {\r
+ return EFI_SUCCESS;\r
+ }\r
+ \r
+ Status = EFI_SUCCESS;\r
+ FileBuffer = NULL;\r
+ FileSize = 0;\r
+ HandlerAuthenticationStatus = AuthenticationStatus;\r
+ //\r
+ // Run security handler in same order to their registered list\r
+ //\r
+ for (Index = 0; Index < mNumberOfSecurityHandler; Index ++) {\r
+ if ((mSecurityTable[Index].SecurityOperation & EFI_AUTH_OPERATION_IMAGE_REQUIRED) == EFI_AUTH_OPERATION_IMAGE_REQUIRED) {\r
+ //\r
+ // Try get file buffer when the handler requires image buffer.\r
+ //\r
+ if (FileBuffer == NULL) {\r
+ FileBuffer = GetFileBufferByFilePath (FALSE, FilePath, &FileSize, &AuthenticationStatus);\r
+ }\r
+ }\r
+ Status = mSecurityTable[Index].SecurityHandler (\r
+ HandlerAuthenticationStatus,\r
+ FilePath,\r
+ FileBuffer,\r
+ FileSize\r
+ );\r
+ if (EFI_ERROR (Status)) {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (FileBuffer != NULL) {\r
+ FreePool (FileBuffer);\r
+ }\r
+\r
+ return Status;\r
+}\r