]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SecurityPkg/VariableAuthenticated/SecureBootConfigDxe/SecureBootConfigImpl.c
Fix infinite loop bug in secure boot UI driver.
[mirror_edk2.git] / SecurityPkg / VariableAuthenticated / SecureBootConfigDxe / SecureBootConfigImpl.c
index 904a210338f386de8b287aededadfab36ed722b5..51da86b6fdaabe57167e8b9c455bf612808abc73 100644 (file)
@@ -1,7 +1,7 @@
 /** @file\r
   HII Config Access protocol implementation of SecureBoot configuration module.\r
 \r
-Copyright (c) 2011 - 2012, Intel Corporation. All rights reserved.<BR>\r
+Copyright (c) 2011 - 2013, Intel Corporation. All rights reserved.<BR>\r
 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
@@ -68,8 +68,9 @@ HASH_TABLE mHash[] = {
   { L"SHA512", 64, &mHashOidValue[40], 9, NULL,                NULL,       NULL,          NULL       }\r
 };\r
 \r
-\r
-// Variable Definitions                                           \r
+//\r
+// Variable Definitions \r
+//                                          \r
 UINT32            mPeCoffHeaderOffset = 0;\r
 WIN_CERTIFICATE   *mCertificate = NULL;\r
 IMAGE_TYPE        mImageType;\r
@@ -81,6 +82,39 @@ EFI_GUID          mCertType;
 EFI_IMAGE_SECURITY_DATA_DIRECTORY    *mSecDataDir = NULL;\r
 EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION  mNtHeader;\r
 \r
+//\r
+// Possible DER-encoded certificate file suffixes, end with NULL pointer.\r
+//\r
+CHAR16* mDerEncodedSuffix[] = {\r
+  L".cer",\r
+  L".der",\r
+  L".crt",\r
+  NULL\r
+};\r
+CHAR16* mSupportX509Suffix = L"*.cer/der/crt";\r
+\r
+/**\r
+  This code checks if the FileSuffix is one of the possible DER-encoded certificate suffix.\r
+\r
+  @param[in] FileSuffix            The suffix of the input certificate file\r
+\r
+  @retval    TRUE           It's a DER-encoded certificate.\r
+  @retval    FALSE          It's NOT a DER-encoded certificate.\r
+\r
+**/\r
+BOOLEAN\r
+IsDerEncodeCertificate (\r
+  IN CONST CHAR16         *FileSuffix\r
+)\r
+{\r
+  UINTN     Index; \r
+  for (Index = 0; mDerEncodedSuffix[Index] != NULL; Index++) {\r
+    if (StrCmp (FileSuffix, mDerEncodedSuffix[Index]) == 0) {\r
+      return TRUE;\r
+    }\r
+  }\r
+  return FALSE;\r
+}\r
 \r
 /**\r
   Set Secure Boot option into variable space.\r
@@ -219,6 +253,7 @@ DeleteVariable (
   if (Variable == NULL) {\r
     return EFI_SUCCESS;\r
   }\r
+  FreePool (Variable);\r
 \r
   Data     = NULL;\r
   DataSize = 0;\r
@@ -244,6 +279,31 @@ DeleteVariable (
   return Status;\r
 }\r
 \r
+/**\r
+\r
+  Set the platform secure boot mode into "Custom" or "Standard" mode.\r
+\r
+  @param[in]   SecureBootMode        New secure boot mode: STANDARD_SECURE_BOOT_MODE or\r
+                                     CUSTOM_SECURE_BOOT_MODE.\r
+  \r
+  @return EFI_SUCCESS                The platform has switched to the special mode successfully.\r
+  @return other                      Fail to operate the secure boot mode.\r
+  \r
+**/\r
+EFI_STATUS\r
+SetSecureBootMode (\r
+  IN     UINT8         SecureBootMode\r
+  )\r
+{\r
+  return gRT->SetVariable (                          \r
+                EFI_CUSTOM_MODE_NAME,\r
+                &gEfiCustomModeEnableGuid,\r
+                EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+                sizeof (UINT8),\r
+                &SecureBootMode\r
+                );\r
+}\r
+\r
 /**\r
   Generate the PK signature list from the X509 Certificate storing file (.cer)\r
 \r
@@ -346,12 +406,17 @@ EnrollPlatformKey (
 \r
   PkCert = NULL;\r
 \r
+  Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
   //\r
-  // Parse the file's postfix. Only support *.cer(X509) files.\r
+  // Parse the file's postfix. Only support DER encoded X.509 certificate files.\r
   //\r
   FilePostFix = Private->FileContext->FileName + StrLen (Private->FileContext->FileName) - 4;\r
-  if (CompareMem (FilePostFix, L".cer",4)) {\r
-    DEBUG ((EFI_D_ERROR, "Don't support the file, only *.cer is supported."));\r
+  if (!IsDerEncodeCertificate(FilePostFix)) {\r
+    DEBUG ((EFI_D_ERROR, "Unsupported file type, only DER encoded certificate (%s) is supported.", mSupportX509Suffix));\r
     return EFI_INVALID_PARAMETER;\r
   }\r
   DEBUG ((EFI_D_INFO, "FileName= %s\n", Private->FileContext->FileName));\r
@@ -423,6 +488,11 @@ DeletePlatformKey (
 {\r
   EFI_STATUS Status;\r
 \r
+  Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
   Status = DeleteVariable (\r
              EFI_PLATFORM_KEY_NAME,\r
              &gEfiGlobalVariableGuid\r
@@ -732,17 +802,23 @@ EnrollKeyExchangeKey (
   ) \r
 {\r
   UINT16*     FilePostFix;\r
+  EFI_STATUS  Status;\r
   \r
   if ((Private->FileContext->FileName == NULL) || (Private->SignatureGUID == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
   //\r
-  // Parse the file's postfix. Supports .cer and .der file as X509 certificate, \r
+  // Parse the file's postfix. Supports DER-encoded X509 certificate, \r
   // and .pbk as RSA public key file.\r
   //\r
   FilePostFix = Private->FileContext->FileName + StrLen (Private->FileContext->FileName) - 4;\r
-  if ((CompareMem (FilePostFix, L".cer",4) == 0) || (CompareMem (FilePostFix, L".der",4) == 0)) {\r
+  if (IsDerEncodeCertificate(FilePostFix)) {\r
     return EnrollX509ToKek (Private);\r
   } else if (CompareMem (FilePostFix, L".pbk",4) == 0) {\r
     return EnrollRsa2048ToKek (Private);\r
@@ -1016,7 +1092,21 @@ HashPeImage (
   // Measuring PE/COFF Image Header;\r
   // But CheckSum field and SECURITY data directory (certificate) are excluded\r
   //\r
-  Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
+  if (mNtHeader.Pe32->FileHeader.Machine == IMAGE_FILE_MACHINE_IA64 && mNtHeader.Pe32->OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {\r
+    //\r
+    // NOTE: Some versions of Linux ELILO for Itanium have an incorrect magic value \r
+    //       in the PE/COFF Header. If the MachineType is Itanium(IA64) and the \r
+    //       Magic value in the OptionalHeader is EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC\r
+    //       then override the magic value to EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC\r
+    //\r
+    Magic = EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC;\r
+  } else {\r
+    //\r
+    // Get the magic value from the PE/COFF Optional Header\r
+    //\r
+    Magic = mNtHeader.Pe32->OptionalHeader.Magic;\r
+  }\r
+  \r
   //\r
   // 3.  Calculate the distance from the base of the image header to the image checksum address.\r
   // 4.  Hash the image header from its base to beginning of the image checksum.\r
@@ -1460,18 +1550,24 @@ EnrollSignatureDatabase (
   ) \r
 {\r
   UINT16*      FilePostFix;\r
+  EFI_STATUS   Status;\r
 \r
   if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->SignatureGUID == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
+  Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+  \r
   //\r
   // Parse the file's postfix. \r
   //\r
   FilePostFix = Private->FileContext->FileName + StrLen (Private->FileContext->FileName) - 4;\r
-  if ((CompareMem (FilePostFix, L".cer",4) == 0) || (CompareMem (FilePostFix, L".der",4) == 0)) {\r
+  if (IsDerEncodeCertificate(FilePostFix)) {\r
     //\r
-    // Supports .cer and .der file as X509 certificate.\r
+    // Supports DER-encoded X509 certificate.\r
     //\r
     return EnrollX509toSigDB (Private, VariableName);\r
   }\r
@@ -1611,6 +1707,8 @@ UpdateDeletePage (
       //\r
       // The signature type is not supported in current implementation.\r
       //\r
+      ItemDataSize -= CertList->SignatureListSize;\r
+      CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
       continue;\r
     }\r
 \r
@@ -1708,6 +1806,11 @@ DeleteKeyExchangeKey (
   Cert            = NULL;\r
   Attr            = 0;   \r
   DeleteKekIndex  = QuestionId - OPTION_DEL_KEK_QUESTION_ID;\r
+\r
+  Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
   \r
   //\r
   // Get original KEK variable.\r
@@ -1896,6 +1999,11 @@ DeleteSignature (
   Cert            = NULL;\r
   Attr            = 0; \r
 \r
+  Status = SetSecureBootMode(CUSTOM_SECURE_BOOT_MODE);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
   //\r
   // Get original signature list data.\r
   //                           \r
@@ -2061,21 +2169,21 @@ SecureBootExtractConfigFromVariable (
   SetupMode        = NULL;\r
   SecureBootMode   = NULL;\r
   \r
-  //\r
-  // Get the SecureBootEnable Variable\r
-  //\r
-  GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);\r
-\r
   //\r
   // If the SecureBootEnable Variable doesn't exist, hide the SecureBoot Enable/Disable\r
   // Checkbox.\r
   //\r
+  ConfigData->AttemptSecureBoot = FALSE;\r
+  GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);\r
   if (SecureBootEnable == NULL) {\r
     ConfigData->HideSecureBoot = TRUE;\r
   } else {\r
     ConfigData->HideSecureBoot = FALSE;\r
-    ConfigData->SecureBootState = *SecureBootEnable;\r
+    if ((*SecureBootEnable) == SECURE_BOOT_ENABLE) {\r
+      ConfigData->AttemptSecureBoot = TRUE;\r
+    }\r
   }\r
+  \r
   //\r
   // If it is Physical Presence User, set the PhysicalPresent to true.\r
   //\r
@@ -2089,7 +2197,7 @@ SecureBootExtractConfigFromVariable (
   // If there is no PK then the Delete Pk button will be gray.\r
   //\r
   GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL);\r
-  if (SetupMode == NULL || (*SetupMode) == 1) {\r
+  if (SetupMode == NULL || (*SetupMode) == SETUP_MODE) {\r
     ConfigData->HasPk = FALSE;\r
   } else  {\r
     ConfigData->HasPk = TRUE;\r
@@ -2104,7 +2212,16 @@ SecureBootExtractConfigFromVariable (
   } else {\r
     ConfigData->SecureBootMode = *(SecureBootMode);\r
   }\r
-  \r
+\r
+  if (SecureBootEnable != NULL) {\r
+    FreePool (SecureBootEnable);\r
+  }\r
+  if (SetupMode != NULL) {\r
+    FreePool (SetupMode);\r
+  }\r
+  if (SecureBootMode != NULL) {\r
+    FreePool (SecureBootMode);\r
+  }\r
 }\r
 \r
 /**\r
@@ -2150,6 +2267,7 @@ SecureBootExtractConfig (
   EFI_STRING                        ConfigRequestHdr;\r
   SECUREBOOT_CONFIG_PRIVATE_DATA    *PrivateData;\r
   BOOLEAN                           AllocatedRequest;\r
+  UINT8                             *SecureBoot;\r
 \r
   if (Progress == NULL || Results == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -2159,6 +2277,7 @@ SecureBootExtractConfig (
   ConfigRequestHdr = NULL;\r
   ConfigRequest    = NULL;\r
   Size             = 0;\r
+  SecureBoot       = NULL;\r
   \r
   ZeroMem (&Configuration, sizeof (Configuration));\r
   PrivateData      = SECUREBOOT_CONFIG_PRIVATE_FROM_THIS (This);\r
@@ -2172,6 +2291,19 @@ SecureBootExtractConfig (
   // Get Configuration from Variable.\r
   //\r
   SecureBootExtractConfigFromVariable (&Configuration);\r
+\r
+  //\r
+  // Update current secure boot state.\r
+  //\r
+  GetVariable2 (EFI_SECURE_BOOT_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SecureBoot, NULL);\r
+  if (SecureBoot != NULL && *SecureBoot == SECURE_BOOT_MODE_ENABLE) {\r
+    HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Enabled", NULL);\r
+  } else {\r
+    HiiSetString (PrivateData->HiiHandle, STRING_TOKEN (STR_SECURE_BOOT_STATE_CONTENT), L"Disabled", NULL);\r
+  }\r
+  if (SecureBoot != NULL) {\r
+    FreePool (SecureBoot);\r
+  }\r
   \r
   BufferSize = sizeof (SECUREBOOT_CONFIGURATION);\r
   ConfigRequest = Request;\r
@@ -2299,14 +2431,21 @@ SecureBootCallback (
   SECUREBOOT_CONFIGURATION        *IfrNvData;\r
   UINT16                          LabelId;\r
   UINT8                           *SecureBootEnable;\r
+  UINT8                           *SecureBootMode;\r
+  UINT8                           *SetupMode;\r
+  CHAR16                          PromptString[100];\r
 \r
   SecureBootEnable = NULL;\r
+  SecureBootMode   = NULL;\r
+  SetupMode        = NULL;\r
 \r
   if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
   }\r
 \r
-  if ((Action != EFI_BROWSER_ACTION_CHANGED) && (Action != EFI_BROWSER_ACTION_CHANGING)) {\r
+  if ((Action != EFI_BROWSER_ACTION_CHANGED) &&\r
+      (Action != EFI_BROWSER_ACTION_CHANGING) &&\r
+      (Action != EFI_BROWSER_ACTION_FORM_CLOSE)) {\r
     return EFI_UNSUPPORTED;\r
   }\r
   \r
@@ -2331,6 +2470,7 @@ SecureBootCallback (
     case KEY_SECURE_BOOT_ENABLE:\r
       GetVariable2 (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid, (VOID**)&SecureBootEnable, NULL);\r
       if (NULL != SecureBootEnable) {\r
+        FreePool (SecureBootEnable);\r
         if (EFI_ERROR (SaveSecureBootVariable (Value->u8))) {\r
           CreatePopUp (\r
             EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
@@ -2339,8 +2479,14 @@ SecureBootCallback (
             NULL\r
             );\r
           Status = EFI_UNSUPPORTED;\r
+        } else {\r
+          CreatePopUp (\r
+            EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+            &Key,\r
+            L"Configuration changed, please reset the platform to take effect!",\r
+            NULL\r
+            );\r
         }\r
-        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; \r
       }\r
       break;\r
 \r
@@ -2397,10 +2543,26 @@ SecureBootCallback (
       break;\r
 \r
     case KEY_SECURE_BOOT_DELETE_PK: \r
-        if (Value->u8) {\r
+      if (Value->u8) {\r
+        CreatePopUp (\r
+          EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+          &Key,\r
+          L"Are you sure you want to delete PK? Secure boot will be disabled!",\r
+          L"Press 'Y' to delete PK and exit, 'N' to discard change and return",\r
+          NULL\r
+          );\r
+        if (Key.UnicodeChar == 'y' || Key.UnicodeChar == 'Y') {\r
           Status = DeletePlatformKey ();\r
-          *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+          if (EFI_ERROR (Status)) {\r
+            CreatePopUp (\r
+              EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
+              &Key,\r
+              L"Only Physical Presence User could delete PK in custom mode!",\r
+              NULL\r
+              );\r
+          }\r
         }\r
+      }\r
       break;\r
 \r
     case KEY_DELETE_KEK:\r
@@ -2483,19 +2645,26 @@ SecureBootCallback (
   } else if (Action == EFI_BROWSER_ACTION_CHANGED) {\r
     switch (QuestionId) {\r
     case KEY_SECURE_BOOT_ENABLE:\r
-      *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;      \r
+      *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
       break;  \r
     case KEY_VALUE_SAVE_AND_EXIT_PK:\r
       Status = EnrollPlatformKey (Private);\r
+      UnicodeSPrint (\r
+        PromptString,\r
+        sizeof (PromptString),\r
+        L"Only DER encoded certificate file (%s) is supported.",\r
+        mSupportX509Suffix\r
+        );\r
       if (EFI_ERROR (Status)) {\r
         CreatePopUp (\r
           EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE,\r
           &Key,\r
-          L"ERROR: Unsupported file type, only *.cer is supported!",\r
+          L"ERROR: Unsupported file type!",\r
+          PromptString,\r
           NULL\r
           );\r
       } else {\r
-        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT; \r
+        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_RESET; \r
       }        \r
       break;\r
 \r
@@ -2517,8 +2686,8 @@ SecureBootCallback (
       break;\r
       \r
     case KEY_SECURE_BOOT_MODE:\r
-      GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootEnable, NULL);\r
-      if (NULL != SecureBootEnable) {\r
+      GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL);\r
+      if (NULL != SecureBootMode) {\r
         Status = gRT->SetVariable (                          \r
                         EFI_CUSTOM_MODE_NAME,\r
                         &gEfiCustomModeEnableGuid,\r
@@ -2528,6 +2697,7 @@ SecureBootCallback (
                         );\r
         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
         IfrNvData->SecureBootMode = Value->u8;\r
+        FreePool (SecureBootMode);\r
       }        \r
       break;\r
 \r
@@ -2548,11 +2718,33 @@ SecureBootCallback (
       break;\r
 \r
     case KEY_SECURE_BOOT_DELETE_PK:\r
-      if (Value->u8) {\r
+      GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL);\r
+      if (SetupMode == NULL || (*SetupMode) == SETUP_MODE) {\r
+        IfrNvData->DeletePk = TRUE;\r
+        IfrNvData->HasPk    = FALSE;\r
         *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;\r
+      } else  {\r
+        IfrNvData->DeletePk = FALSE;\r
+        IfrNvData->HasPk    = TRUE;\r
+        *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY;\r
+      }\r
+      if (SetupMode != NULL) {\r
+        FreePool (SetupMode);\r
       }\r
       break;  \r
     }\r
+  } else if (Action == EFI_BROWSER_ACTION_FORM_CLOSE) {\r
+    //\r
+    // Force the platform back to Standard Mode once user leave the setup screen.\r
+    //\r
+    GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL);\r
+    if (NULL != SecureBootMode && *SecureBootMode == CUSTOM_SECURE_BOOT_MODE) {\r
+      IfrNvData->SecureBootMode = STANDARD_SECURE_BOOT_MODE;\r
+      SetSecureBootMode(STANDARD_SECURE_BOOT_MODE);\r
+    }\r
+    if (SecureBootMode != NULL) {\r
+      FreePool (SecureBootMode);\r
+    }\r
   }\r
   \r
   if (!EFI_ERROR (Status)) {\r