]> 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 63dffd76bcd1237307b8117d0b890bea9fd7e7d5..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
@@ -108,6 +142,90 @@ SaveSecureBootVariable (
   return Status;\r
 }\r
 \r
+/**\r
+  Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2\r
+  descriptor with the input data. NO authentication is required in this function.\r
+  \r
+  @param[in, out]   DataSize       On input, the size of Data buffer in bytes.\r
+                                   On output, the size of data returned in Data\r
+                                   buffer in bytes.\r
+  @param[in, out]   Data           On input, Pointer to data buffer to be wrapped or \r
+                                   pointer to NULL to wrap an empty payload.\r
+                                   On output, Pointer to the new payload date buffer allocated from pool,\r
+                                   it's caller's responsibility to free the memory when finish using it. \r
+\r
+  @retval EFI_SUCCESS              Create time based payload successfully.\r
+  @retval EFI_OUT_OF_RESOURCES     There are not enough memory resourses to create time based payload.\r
+  @retval EFI_INVALID_PARAMETER    The parameter is invalid.\r
+  @retval Others                   Unexpected error happens.\r
+\r
+**/\r
+EFI_STATUS\r
+CreateTimeBasedPayload (\r
+  IN OUT UINTN            *DataSize,\r
+  IN OUT UINT8            **Data\r
+  )\r
+{\r
+  EFI_STATUS                       Status;\r
+  UINT8                            *NewData;\r
+  UINT8                            *Payload;\r
+  UINTN                            PayloadSize;\r
+  EFI_VARIABLE_AUTHENTICATION_2    *DescriptorData;\r
+  UINTN                            DescriptorSize;\r
+  EFI_TIME                         Time;\r
+  \r
+  if (Data == NULL || DataSize == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  \r
+  //\r
+  // In Setup mode or Custom mode, the variable does not need to be signed but the \r
+  // parameters to the SetVariable() call still need to be prepared as authenticated\r
+  // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate\r
+  // data in it.\r
+  //\r
+  Payload     = *Data;\r
+  PayloadSize = *DataSize;\r
+  \r
+  DescriptorSize    = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);\r
+  NewData = (UINT8*) AllocateZeroPool (DescriptorSize + PayloadSize);\r
+  if (NewData == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  if ((Payload != NULL) && (PayloadSize != 0)) {\r
+    CopyMem (NewData + DescriptorSize, Payload, PayloadSize);\r
+  }\r
+\r
+  DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData);\r
+\r
+  ZeroMem (&Time, sizeof (EFI_TIME));\r
+  Status = gRT->GetTime (&Time, NULL);\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool(NewData);\r
+    return Status;\r
+  }\r
+  Time.Pad1       = 0;\r
+  Time.Nanosecond = 0;\r
+  Time.TimeZone   = 0;\r
+  Time.Daylight   = 0;\r
+  Time.Pad2       = 0;\r
+  CopyMem (&DescriptorData->TimeStamp, &Time, sizeof (EFI_TIME));\r
\r
+  DescriptorData->AuthInfo.Hdr.dwLength         = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData);\r
+  DescriptorData->AuthInfo.Hdr.wRevision        = 0x0200;\r
+  DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID;\r
+  CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid);\r
+  \r
+  if (Payload != NULL) {\r
+    FreePool(Payload);\r
+  }\r
+  \r
+  *DataSize = DescriptorSize + PayloadSize;\r
+  *Data     = NewData;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
 /**\r
   Internal helper function to delete a Variable given its name and GUID, NO authentication\r
   required.\r
@@ -127,130 +245,63 @@ DeleteVariable (
 {\r
   EFI_STATUS              Status;\r
   VOID*                   Variable;\r
+  UINT8                   *Data;\r
+  UINTN                   DataSize;\r
+  UINT32                  Attr;\r
 \r
-  Variable = GetVariable (VariableName, VendorGuid);\r
+  GetVariable2 (VariableName, VendorGuid, &Variable, NULL);\r
   if (Variable == NULL) {\r
     return EFI_SUCCESS;\r
   }\r
+  FreePool (Variable);\r
 \r
-  Status =   gRT->SetVariable (\r
-                    VariableName,\r
-                    VendorGuid,\r
-                    EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
-                    0,\r
-                    NULL\r
-                    );\r
+  Data     = NULL;\r
+  DataSize = 0;\r
+  Attr     = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS\r
+             | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
+\r
+  Status = CreateTimeBasedPayload (&DataSize, &Data);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
+    return Status;\r
+  }\r
+\r
+  Status = gRT->SetVariable (\r
+                  VariableName,\r
+                  VendorGuid,\r
+                  Attr,\r
+                  DataSize,\r
+                  Data\r
+                  );\r
+  if (Data != NULL) {\r
+    FreePool (Data);\r
+  }\r
   return Status;\r
 }\r
 \r
 /**\r
-  Generate a PK signature list from the public key storing file (*.pbk).\r
 \r
-  @param[in]   PkKeyFile             FileHandle of the public key storing file.\r
-  @param[out]  PkCert                Point to the data buffer to store the signature list.\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_UNSUPPORTED            Unsupported Key Length.\r
-  @return EFI_OUT_OF_RESOURCES       There are not enough memory resourses to form the signature list.\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
-CreatePkRsaSignatureList (\r
-  IN    EFI_FILE_HANDLE             PkKeyFile, \r
-  OUT   EFI_SIGNATURE_LIST          **PkCert \r
+SetSecureBootMode (\r
+  IN     UINT8         SecureBootMode\r
   )\r
 {\r
-  EFI_STATUS                      Status;  \r
-  UINTN                           KeyBlobSize;\r
-  VOID                            *KeyBlob;\r
-  CPL_KEY_INFO                    *KeyInfo;\r
-  EFI_SIGNATURE_DATA              *PkCertData;\r
-  VOID                            *KeyBuffer;  \r
-  UINTN                           KeyLenInBytes;\r
-\r
-  PkCertData = NULL;\r
-  KeyBlob = NULL;\r
-  KeyBuffer = NULL;\r
-  Status = EFI_SUCCESS;\r
-\r
-  //\r
-  // Get key from PK key file\r
-  //                           \r
-  Status = ReadFileContent (PkKeyFile, &KeyBlob, &KeyBlobSize, 0);\r
-  if (EFI_ERROR(Status)) {\r
-    DEBUG ((EFI_D_ERROR, "Can't Open the file for PK enrolling.\n"));\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  KeyInfo = (CPL_KEY_INFO *)KeyBlob;\r
-  if (KeyInfo->KeyLengthInBits/8 != WIN_CERT_UEFI_RSA2048_SIZE) {\r
-    Status = EFI_UNSUPPORTED;\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  //\r
-  // Convert the Public key to fix octet string format represented in RSA PKCS#1.\r
-  // \r
-  KeyLenInBytes = KeyInfo->KeyLengthInBits / 8;\r
-  KeyBuffer = AllocateZeroPool(KeyLenInBytes);\r
-  if (KeyBuffer == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto ON_EXIT;\r
-  }\r
-  Status = Int2OctStr (\r
-              (UINTN*) ((UINTN)KeyBlob + sizeof(CPL_KEY_INFO)), \r
-              KeyLenInBytes / sizeof (UINTN), \r
-              (UINT8*)KeyBuffer, \r
-              KeyLenInBytes\r
-              );\r
-  if (EFI_ERROR(Status)) {\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  // Allocate space for PK certificate list and initialize the list.\r
-  // Create PK database entry with SignatureHeaderSize equals 0.\r
-  //\r
-  *PkCert = (EFI_SIGNATURE_LIST*)AllocateZeroPool(\r
-            sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1\r
-            + WIN_CERT_UEFI_RSA2048_SIZE\r
-            );\r
-  \r
-  if (*PkCert == NULL) {\r
-    Status = EFI_OUT_OF_RESOURCES;\r
-    goto ON_EXIT;\r
-  }\r
-\r
-  (*PkCert)->SignatureListSize   = sizeof(EFI_SIGNATURE_LIST) \r
-                                  + sizeof(EFI_SIGNATURE_DATA) - 1\r
-                                  + WIN_CERT_UEFI_RSA2048_SIZE;\r
-  (*PkCert)->SignatureSize       = sizeof(EFI_SIGNATURE_DATA) - 1 + WIN_CERT_UEFI_RSA2048_SIZE;\r
-  (*PkCert)->SignatureHeaderSize = 0;\r
-  CopyGuid (&(*PkCert)->SignatureType, &gEfiCertRsa2048Guid);\r
-\r
-  PkCertData                    = (EFI_SIGNATURE_DATA*)((UINTN)(*PkCert) \r
-                                                          + sizeof(EFI_SIGNATURE_LIST)\r
-                                                          + (*PkCert)->SignatureHeaderSize);\r
-  CopyGuid (&PkCertData->SignatureOwner, &gEfiGlobalVariableGuid);\r
-  //\r
-  // Fill the PK database with PKpub data from PKKeyFile.\r
-  //               \r
-  CopyMem (&(PkCertData->SignatureData[0]), KeyBuffer, WIN_CERT_UEFI_RSA2048_SIZE);\r
-\r
-ON_EXIT:\r
-  \r
-  if (KeyBlob != NULL) {\r
-    FreePool (KeyBlob);\r
-  }\r
-  \r
-  if (EFI_ERROR(Status) && *PkCert != NULL) {\r
-    FreePool (*PkCert);\r
-    *PkCert = NULL;\r
-  }\r
-  \r
-  if (KeyBuffer != NULL) {\r
-    FreePool (KeyBuffer);\r
-  }\r
-  \r
-  return Status;\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
@@ -278,10 +329,11 @@ CreatePkX509SignatureList (
   PkCertData = NULL;\r
   X509DataSize = 0;  \r
   \r
-  Status = ReadFileContent (X509File, &X509Data, &X509DataSize, 0);\r
+  Status = ReadFileContent (X509File, (VOID**) &X509Data, &X509DataSize, 0);\r
   if (EFI_ERROR (Status)) {\r
     goto ON_EXIT;\r
   }\r
+  ASSERT (X509Data != NULL);\r
 \r
   //\r
   // Allocate space for PK certificate list and initialize it.\r
@@ -354,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 *.pbk(RSA2048) and *.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".pbk",4) && CompareMem (FilePostFix, L".cer",4)) {\r
-    DEBUG ((EFI_D_ERROR, "Don't support the file, only *.pbk or *.cer.\n 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
@@ -368,30 +425,27 @@ EnrollPlatformKey (
   //\r
   // Prase the selected PK file and generature PK certificate list.\r
   //\r
-  if (!CompareMem (FilePostFix, L".pbk",4)) {\r
-    Status = CreatePkRsaSignatureList (\r
-              Private->FileContext->FHandle, \r
-              &PkCert \r
-              );\r
-    if (EFI_ERROR (Status)) {\r
-      goto ON_EXIT;\r
-    }\r
-  } else if (!CompareMem (FilePostFix, L".cer",4)) {\r
-    Status = CreatePkX509SignatureList (\r
-              Private->FileContext->FHandle, \r
-              &PkCert \r
-              );\r
-    if (EFI_ERROR (Status)) {\r
-      goto ON_EXIT;\r
-    }\r
+  Status = CreatePkX509SignatureList (\r
+            Private->FileContext->FHandle, \r
+            &PkCert \r
+            );\r
+  if (EFI_ERROR (Status)) {\r
+    goto ON_EXIT;\r
   }\r
+  ASSERT (PkCert != NULL);\r
                          \r
   //\r
   // Set Platform Key variable.\r
   // \r
   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS \r
-          | EFI_VARIABLE_BOOTSERVICE_ACCESS;\r
+          | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
   DataSize = PkCert->SignatureListSize;\r
+  Status = CreateTimeBasedPayload (&DataSize, (UINT8**) &PkCert);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
+    goto ON_EXIT;\r
+  }\r
+  \r
   Status = gRT->SetVariable(\r
                   EFI_PLATFORM_KEY_NAME, \r
                   &gEfiGlobalVariableGuid, \r
@@ -434,8 +488,15 @@ DeletePlatformKey (
 {\r
   EFI_STATUS Status;\r
 \r
-  Status = DeleteVariable (EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid);\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
+             );\r
   return Status;\r
 }\r
 \r
@@ -483,13 +544,14 @@ EnrollRsa2048ToKek (
   //                \r
   Status = ReadFileContent (\r
              Private->FileContext->FHandle,\r
-             &KeyBlob,\r
+             (VOID**) &KeyBlob,\r
              &KeyBlobSize,\r
              0\r
              );\r
   if (EFI_ERROR (Status)) {\r
     goto ON_EXIT;\r
   }\r
+  ASSERT (KeyBlob != NULL);\r
   KeyInfo = (CPL_KEY_INFO *) KeyBlob;\r
   if (KeyInfo->KeyLengthInBits / 8 != WIN_CERT_UEFI_RSA2048_SIZE) {\r
     DEBUG ((DEBUG_ERROR, "Unsupported key length, Only RSA2048 is supported.\n"));\r
@@ -547,8 +609,14 @@ EnrollRsa2048ToKek (
   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the \r
   // new KEK to original variable.\r
   //            \r
-  Attr |= EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS;\r
-  DataSize = 0;\r
+  Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS \r
+         | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
+  Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
+    goto ON_EXIT;\r
+  }\r
+\r
   Status = gRT->GetVariable(\r
                   EFI_KEY_EXCHANGE_KEY_NAME, \r
                   &gEfiGlobalVariableGuid, \r
@@ -641,6 +709,7 @@ EnrollX509ToKek (
   if (EFI_ERROR (Status)) {\r
     goto ON_EXIT;\r
   }\r
+  ASSERT (X509Data != NULL);\r
 \r
   KekSigListSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize;\r
   KekSigList = (EFI_SIGNATURE_LIST*) AllocateZeroPool (KekSigListSize);\r
@@ -667,8 +736,13 @@ EnrollX509ToKek (
   // new kek to original variable\r
   //    \r
   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS \r
-          | EFI_VARIABLE_BOOTSERVICE_ACCESS;\r
-\r
+          | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
+  Status = CreateTimeBasedPayload (&KekSigListSize, (UINT8**) &KekSigList);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
+    goto ON_EXIT;\r
+  }\r
+  \r
   Status = gRT->GetVariable(\r
                   EFI_KEY_EXCHANGE_KEY_NAME, \r
                   &gEfiGlobalVariableGuid, \r
@@ -728,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
@@ -792,6 +872,7 @@ EnrollX509toSigDB (
   if (EFI_ERROR (Status)) {\r
     goto ON_EXIT;\r
   }\r
+  ASSERT (X509Data != NULL);\r
 \r
   SigDBSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize;\r
 \r
@@ -820,7 +901,12 @@ EnrollX509toSigDB (
   // new signature data to original variable\r
   //    \r
   Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS \r
-          | EFI_VARIABLE_BOOTSERVICE_ACCESS;\r
+          | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
+  Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
+    goto ON_EXIT;\r
+  }\r
 \r
   Status = gRT->GetVariable(\r
                   VariableName, \r
@@ -1006,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
@@ -1275,8 +1375,6 @@ EnrollImageSignatureToSigDB (
 \r
   Data = NULL;\r
   GuidCertData = NULL;\r
-  Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS \r
-          | EFI_VARIABLE_BOOTSERVICE_ACCESS;\r
 \r
   //\r
   // Form the SigDB certificate list.\r
@@ -1299,6 +1397,7 @@ EnrollImageSignatureToSigDB (
   if (EFI_ERROR (Status)) {\r
     goto ON_EXIT;\r
   }  \r
+  ASSERT (mImageBase != NULL);\r
 \r
   Status = LoadPeImage ();\r
   if (EFI_ERROR (Status)) {\r
@@ -1367,6 +1466,14 @@ EnrollImageSignatureToSigDB (
   CopyGuid (&SigDBCertData->SignatureOwner, Private->SignatureGUID);\r
   CopyMem (SigDBCertData->SignatureData, mImageDigest, mImageDigestSize);\r
 \r
+  Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS \r
+          | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS;\r
+  Status = CreateTimeBasedPayload (&SigDBSize, (UINT8**) &Data);\r
+  if (EFI_ERROR (Status)) {\r
+    DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
+    goto ON_EXIT;\r
+  }\r
+  \r
   //\r
   // Check if SigDB variable has been already existed. \r
   // If true, use EFI_VARIABLE_APPEND_WRITE attribute to append the \r
@@ -1443,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
@@ -1594,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
@@ -1691,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
@@ -1792,8 +1912,14 @@ DeleteKeyExchangeKey (
     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
   }\r
 \r
-  CertList = (EFI_SIGNATURE_LIST*) OldData;\r
   DataSize = Offset;\r
+  if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+    Status = CreateTimeBasedPayload (&DataSize, &OldData);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
 \r
   Status = gRT->SetVariable(\r
                   EFI_KEY_EXCHANGE_KEY_NAME, \r
@@ -1873,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
@@ -1979,8 +2110,14 @@ DeleteSignature (
     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);\r
   }\r
 \r
-  CertList = (EFI_SIGNATURE_LIST*) OldData;\r
   DataSize = Offset;\r
+  if ((Attr & EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS) != 0) {\r
+    Status = CreateTimeBasedPayload (&DataSize, &OldData);\r
+    if (EFI_ERROR (Status)) {\r
+      DEBUG ((EFI_D_ERROR, "Fail to create time-based data payload: %r", Status));\r
+      goto ON_EXIT;\r
+    }\r
+  }\r
 \r
   Status = gRT->SetVariable(\r
                   VariableName, \r
@@ -2032,21 +2169,21 @@ SecureBootExtractConfigFromVariable (
   SetupMode        = NULL;\r
   SecureBootMode   = NULL;\r
   \r
-  //\r
-  // Get the SecureBootEnable Variable\r
-  //\r
-  SecureBootEnable = GetVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid);\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
@@ -2059,8 +2196,8 @@ SecureBootExtractConfigFromVariable (
   //\r
   // If there is no PK then the Delete Pk button will be gray.\r
   //\r
-  SetupMode = GetVariable (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid);\r
-  if (SetupMode == NULL || (*SetupMode) == 1) {\r
+  GetVariable2 (EFI_SETUP_MODE_NAME, &gEfiGlobalVariableGuid, (VOID**)&SetupMode, NULL);\r
+  if (SetupMode == NULL || (*SetupMode) == SETUP_MODE) {\r
     ConfigData->HasPk = FALSE;\r
   } else  {\r
     ConfigData->HasPk = TRUE;\r
@@ -2069,13 +2206,22 @@ SecureBootExtractConfigFromVariable (
   //\r
   // Get the SecureBootMode from CustomMode variable.\r
   //\r
-  SecureBootMode = GetVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid);\r
+  GetVariable2 (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, (VOID**)&SecureBootMode, NULL);\r
   if (SecureBootMode == NULL) {\r
     ConfigData->SecureBootMode = STANDARD_SECURE_BOOT_MODE;\r
   } 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
@@ -2121,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
@@ -2130,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
@@ -2143,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
@@ -2269,12 +2430,22 @@ SecureBootCallback (
   UINTN                           BufferSize;\r
   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
@@ -2297,7 +2468,9 @@ SecureBootCallback (
 \r
     switch (QuestionId) {\r
     case KEY_SECURE_BOOT_ENABLE:\r
-      if (NULL != GetVariable (EFI_SECURE_BOOT_ENABLE_NAME, &gEfiSecureBootEnableDisableGuid)) {\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
@@ -2306,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
@@ -2364,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
@@ -2450,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: The File Type is neither *.cer nor *.pbk!",\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
@@ -2484,7 +2686,8 @@ SecureBootCallback (
       break;\r
       \r
     case KEY_SECURE_BOOT_MODE:\r
-      if (NULL != GetVariable (EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid)) {\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
@@ -2494,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
@@ -2514,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