| /** @file | |
| This library provides helper functions to set/clear Secure Boot | |
| keys and databases. | |
| Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.<BR> | |
| (C) Copyright 2018 Hewlett Packard Enterprise Development LP<BR> | |
| Copyright (c) 2021, ARM Ltd. All rights reserved.<BR> | |
| Copyright (c) 2021, Semihalf All rights reserved.<BR> | |
| Copyright (c) Microsoft Corporation. | |
| SPDX-License-Identifier: BSD-2-Clause-Patent | |
| **/ | |
| #include <Uefi.h> | |
| #include <UefiSecureBoot.h> | |
| #include <Guid/GlobalVariable.h> | |
| #include <Guid/AuthenticatedVariableFormat.h> | |
| #include <Guid/ImageAuthentication.h> | |
| #include <Library/BaseLib.h> | |
| #include <Library/BaseMemoryLib.h> | |
| #include <Library/DebugLib.h> | |
| #include <Library/UefiLib.h> | |
| #include <Library/MemoryAllocationLib.h> | |
| #include <Library/UefiRuntimeServicesTableLib.h> | |
| #include <Library/SecureBootVariableLib.h> | |
| #include <Library/PlatformPKProtectionLib.h> | |
| // | |
| // This is the minimum size of a EFI_SIGNATURE_LIST and data and still be valid. | |
| // | |
| // The UEFI specification defines this as: | |
| // Each signature list is a list of signatures of one type, identified by SignatureType. | |
| // The signature list contains a header and then an array of zero or more signatures in | |
| // the format specified by the header. The size of each signature in the signature list | |
| // is specified by SignatureSize. | |
| // | |
| // This is the size of a signature list with some data in it. Effectively 44 bytes are | |
| // required to set the DBX. However in reality, the size of a real payload will be larger | |
| // since this miniumum size does not consider the SIGNATURE_LIST | |
| // | |
| #define MINIMUM_VALID_SIGNATURE_LIST (sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1) | |
| // This time can be used when deleting variables, as it should be greater than any variable time. | |
| EFI_TIME mMaxTimestamp = { | |
| 0xFFFF, // Year | |
| 0xFF, // Month | |
| 0xFF, // Day | |
| 0xFF, // Hour | |
| 0xFF, // Minute | |
| 0xFF, // Second | |
| 0x00, | |
| 0x00000000, // Nanosecond | |
| 0, | |
| 0, | |
| 0x00 | |
| }; | |
| // | |
| // This epoch time is the date that is used when creating SecureBoot default variables. | |
| // NOTE: This is a placeholder date that doesn't correspond to anything else. | |
| // | |
| EFI_TIME mDefaultPayloadTimestamp = { | |
| 1970, // Year (1970) | |
| 1, // Month (Jan) | |
| 1, // Day (1) | |
| 0, // Hour | |
| 0, // Minute | |
| 0, // Second | |
| 0, // Pad1 | |
| 0, // Nanosecond | |
| 0, // Timezone (Dummy value) | |
| 0, // Daylight (Dummy value) | |
| 0 // Pad2 | |
| }; | |
| /** Creates EFI Signature List structure. | |
| @param[in] Data A pointer to signature data. | |
| @param[in] Size Size of signature data. | |
| @param[out] SigList Created Signature List. | |
| @retval EFI_SUCCESS Signature List was created successfully. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| CreateSigList ( | |
| IN VOID *Data, | |
| IN UINTN Size, | |
| OUT EFI_SIGNATURE_LIST **SigList | |
| ) | |
| { | |
| UINTN SigListSize; | |
| EFI_SIGNATURE_LIST *TmpSigList; | |
| EFI_SIGNATURE_DATA *SigData; | |
| // | |
| // Allocate data for Signature Database | |
| // | |
| SigListSize = sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + Size; | |
| TmpSigList = (EFI_SIGNATURE_LIST *)AllocateZeroPool (SigListSize); | |
| if (TmpSigList == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| // | |
| // Only gEfiCertX509Guid type is supported | |
| // | |
| TmpSigList->SignatureListSize = (UINT32)SigListSize; | |
| TmpSigList->SignatureSize = (UINT32)(sizeof (EFI_SIGNATURE_DATA) - 1 + Size); | |
| TmpSigList->SignatureHeaderSize = 0; | |
| CopyGuid (&TmpSigList->SignatureType, &gEfiCertX509Guid); | |
| // | |
| // Copy key data | |
| // | |
| SigData = (EFI_SIGNATURE_DATA *)(TmpSigList + 1); | |
| CopyGuid (&SigData->SignatureOwner, &gEfiGlobalVariableGuid); | |
| CopyMem (&SigData->SignatureData[0], Data, Size); | |
| *SigList = TmpSigList; | |
| return EFI_SUCCESS; | |
| } | |
| /** Adds new signature list to signature database. | |
| @param[in] SigLists A pointer to signature database. | |
| @param[in] SigListAppend A signature list to be added. | |
| @param[out] *SigListOut Created signature database. | |
| @param[in, out] SigListsSize A size of created signature database. | |
| @retval EFI_SUCCESS Signature List was added successfully. | |
| @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. | |
| **/ | |
| STATIC | |
| EFI_STATUS | |
| ConcatenateSigList ( | |
| IN EFI_SIGNATURE_LIST *SigLists, | |
| IN EFI_SIGNATURE_LIST *SigListAppend, | |
| OUT EFI_SIGNATURE_LIST **SigListOut, | |
| IN OUT UINTN *SigListsSize | |
| ) | |
| { | |
| EFI_SIGNATURE_LIST *TmpSigList; | |
| UINT8 *Offset; | |
| UINTN NewSigListsSize; | |
| NewSigListsSize = *SigListsSize + SigListAppend->SignatureListSize; | |
| TmpSigList = (EFI_SIGNATURE_LIST *)AllocateZeroPool (NewSigListsSize); | |
| if (TmpSigList == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| CopyMem (TmpSigList, SigLists, *SigListsSize); | |
| Offset = (UINT8 *)TmpSigList; | |
| Offset += *SigListsSize; | |
| CopyMem ((VOID *)Offset, SigListAppend, SigListAppend->SignatureListSize); | |
| *SigListsSize = NewSigListsSize; | |
| *SigListOut = TmpSigList; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Create a EFI Signature List with data supplied from input argument. | |
| The input certificates from KeyInfo parameter should be DER-encoded | |
| format. | |
| @param[out] SigListsSize A pointer to size of signature list | |
| @param[out] SigListOut A pointer to a callee-allocated buffer with signature lists | |
| @param[in] KeyInfoCount The number of certificate pointer and size pairs inside KeyInfo. | |
| @param[in] KeyInfo A pointer to all certificates, in the format of DER-encoded, | |
| to be concatenated into signature lists. | |
| @retval EFI_SUCCESS Created signature list from payload successfully. | |
| @retval EFI_NOT_FOUND Section with key has not been found. | |
| @retval EFI_INVALID_PARAMETER Embedded key has a wrong format or input pointers are NULL. | |
| @retval Others Unexpected error happens. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SecureBootCreateDataFromInput ( | |
| OUT UINTN *SigListsSize, | |
| OUT EFI_SIGNATURE_LIST **SigListOut, | |
| IN UINTN KeyInfoCount, | |
| IN CONST SECURE_BOOT_CERTIFICATE_INFO *KeyInfo | |
| ) | |
| { | |
| EFI_SIGNATURE_LIST *EfiSig; | |
| EFI_SIGNATURE_LIST *TmpEfiSig; | |
| EFI_SIGNATURE_LIST *TmpEfiSig2; | |
| EFI_STATUS Status; | |
| VOID *Buffer; | |
| UINTN Size; | |
| UINTN InputIndex; | |
| UINTN KeyIndex; | |
| if ((SigListOut == NULL) || (SigListsSize == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| if ((KeyInfoCount == 0) || (KeyInfo == NULL)) { | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| InputIndex = 0; | |
| KeyIndex = 0; | |
| EfiSig = NULL; | |
| *SigListsSize = 0; | |
| while (InputIndex < KeyInfoCount) { | |
| if (KeyInfo[InputIndex].Data != NULL) { | |
| Size = KeyInfo[InputIndex].DataSize; | |
| Buffer = AllocateCopyPool (Size, KeyInfo[InputIndex].Data); | |
| if (Buffer == NULL) { | |
| if (EfiSig != NULL) { | |
| FreePool (EfiSig); | |
| } | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| Status = CreateSigList (Buffer, Size, &TmpEfiSig); | |
| if (EFI_ERROR (Status)) { | |
| FreePool (Buffer); | |
| break; | |
| } | |
| // | |
| // Concatenate lists if more than one section found | |
| // | |
| if (KeyIndex == 0) { | |
| EfiSig = TmpEfiSig; | |
| *SigListsSize = TmpEfiSig->SignatureListSize; | |
| } else { | |
| ConcatenateSigList (EfiSig, TmpEfiSig, &TmpEfiSig2, SigListsSize); | |
| FreePool (EfiSig); | |
| FreePool (TmpEfiSig); | |
| EfiSig = TmpEfiSig2; | |
| } | |
| KeyIndex++; | |
| FreePool (Buffer); | |
| } | |
| InputIndex++; | |
| } | |
| if (KeyIndex == 0) { | |
| return EFI_NOT_FOUND; | |
| } | |
| *SigListOut = EfiSig; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Create a time based data payload by concatenating the EFI_VARIABLE_AUTHENTICATION_2 | |
| descriptor with the input data. NO authentication is required in this function. | |
| @param[in, out] DataSize On input, the size of Data buffer in bytes. | |
| On output, the size of data returned in Data | |
| buffer in bytes. | |
| @param[in, out] Data On input, Pointer to data buffer to be wrapped or | |
| pointer to NULL to wrap an empty payload. | |
| On output, Pointer to the new payload date buffer allocated from pool, | |
| it's caller's responsibility to free the memory when finish using it. | |
| @param[in] Time Pointer to time information to created time based payload. | |
| @retval EFI_SUCCESS Create time based payload successfully. | |
| @retval EFI_OUT_OF_RESOURCES There are not enough memory resources to create time based payload. | |
| @retval EFI_INVALID_PARAMETER The parameter is invalid. | |
| @retval Others Unexpected error happens. | |
| --*/ | |
| EFI_STATUS | |
| EFIAPI | |
| CreateTimeBasedPayload ( | |
| IN OUT UINTN *DataSize, | |
| IN OUT UINT8 **Data, | |
| IN EFI_TIME *Time | |
| ) | |
| { | |
| UINT8 *NewData; | |
| UINT8 *Payload; | |
| UINTN PayloadSize; | |
| EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData; | |
| UINTN DescriptorSize; | |
| if ((Data == NULL) || (DataSize == NULL) || (Time == NULL)) { | |
| DEBUG ((DEBUG_ERROR, "%a(), invalid arg\n", __func__)); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // In Setup mode or Custom mode, the variable does not need to be signed but the | |
| // parameters to the SetVariable() call still need to be prepared as authenticated | |
| // variable. So we create EFI_VARIABLE_AUTHENTICATED_2 descriptor without certificate | |
| // data in it. | |
| // | |
| Payload = *Data; | |
| PayloadSize = *DataSize; | |
| DescriptorSize = OFFSET_OF (EFI_VARIABLE_AUTHENTICATION_2, AuthInfo) + OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData); | |
| NewData = (UINT8 *)AllocateZeroPool (DescriptorSize + PayloadSize); | |
| if (NewData == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a() Out of resources.\n", __func__)); | |
| return EFI_OUT_OF_RESOURCES; | |
| } | |
| if ((Payload != NULL) && (PayloadSize != 0)) { | |
| CopyMem (NewData + DescriptorSize, Payload, PayloadSize); | |
| } | |
| DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *)(NewData); | |
| CopyMem (&DescriptorData->TimeStamp, Time, sizeof (EFI_TIME)); | |
| DescriptorData->AuthInfo.Hdr.dwLength = OFFSET_OF (WIN_CERTIFICATE_UEFI_GUID, CertData); | |
| DescriptorData->AuthInfo.Hdr.wRevision = 0x0200; | |
| DescriptorData->AuthInfo.Hdr.wCertificateType = WIN_CERT_TYPE_EFI_GUID; | |
| CopyGuid (&DescriptorData->AuthInfo.CertType, &gEfiCertPkcs7Guid); | |
| if (Payload != NULL) { | |
| FreePool (Payload); | |
| Payload = NULL; | |
| } | |
| *DataSize = DescriptorSize + PayloadSize; | |
| *Data = NewData; | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Internal helper function to delete a Variable given its name and GUID, NO authentication | |
| required. | |
| @param[in] VariableName Name of the Variable. | |
| @param[in] VendorGuid GUID of the Variable. | |
| @retval EFI_SUCCESS Variable deleted successfully. | |
| @retval Others The driver failed to start the device. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| DeleteVariable ( | |
| IN CHAR16 *VariableName, | |
| IN EFI_GUID *VendorGuid | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| VOID *Variable; | |
| UINT8 *Data; | |
| UINTN DataSize; | |
| UINT32 Attr; | |
| GetVariable2 (VariableName, VendorGuid, &Variable, NULL); | |
| if (Variable == NULL) { | |
| return EFI_SUCCESS; | |
| } | |
| FreePool (Variable); | |
| Data = NULL; | |
| DataSize = 0; | |
| Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | |
| | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; | |
| Status = CreateTimeBasedPayload (&DataSize, &Data, &mMaxTimestamp); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "Fail to create time-based data payload: %r", Status)); | |
| return Status; | |
| } | |
| Status = gRT->SetVariable ( | |
| VariableName, | |
| VendorGuid, | |
| Attr, | |
| DataSize, | |
| Data | |
| ); | |
| if (Data != NULL) { | |
| FreePool (Data); | |
| } | |
| return Status; | |
| } | |
| /** | |
| Set the platform secure boot mode into "Custom" or "Standard" mode. | |
| @param[in] SecureBootMode New secure boot mode: STANDARD_SECURE_BOOT_MODE or | |
| CUSTOM_SECURE_BOOT_MODE. | |
| @return EFI_SUCCESS The platform has switched to the special mode successfully. | |
| @return other Fail to operate the secure boot mode. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SetSecureBootMode ( | |
| IN UINT8 SecureBootMode | |
| ) | |
| { | |
| return gRT->SetVariable ( | |
| EFI_CUSTOM_MODE_NAME, | |
| &gEfiCustomModeEnableGuid, | |
| EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, | |
| sizeof (UINT8), | |
| &SecureBootMode | |
| ); | |
| } | |
| /** | |
| Fetches the value of SetupMode variable. | |
| @param[out] SetupMode Pointer to UINT8 for SetupMode output | |
| @retval other Retval from GetVariable. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| GetSetupMode ( | |
| OUT UINT8 *SetupMode | |
| ) | |
| { | |
| UINTN Size; | |
| EFI_STATUS Status; | |
| Size = sizeof (*SetupMode); | |
| Status = gRT->GetVariable ( | |
| EFI_SETUP_MODE_NAME, | |
| &gEfiGlobalVariableGuid, | |
| NULL, | |
| &Size, | |
| SetupMode | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| return EFI_SUCCESS; | |
| } | |
| /** | |
| Helper function to quickly determine whether SecureBoot is enabled. | |
| @retval TRUE SecureBoot is verifiably enabled. | |
| @retval FALSE SecureBoot is either disabled or an error prevented checking. | |
| **/ | |
| BOOLEAN | |
| EFIAPI | |
| IsSecureBootEnabled ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT8 *SecureBoot; | |
| SecureBoot = NULL; | |
| Status = GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID **)&SecureBoot, NULL); | |
| // | |
| // Skip verification if SecureBoot variable doesn't exist. | |
| // | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "Cannot check SecureBoot variable %r \n ", Status)); | |
| return FALSE; | |
| } | |
| // | |
| // Skip verification if SecureBoot is disabled but not AuditMode | |
| // | |
| if (*SecureBoot == SECURE_BOOT_MODE_DISABLE) { | |
| FreePool (SecureBoot); | |
| return FALSE; | |
| } else { | |
| return TRUE; | |
| } | |
| } | |
| /** | |
| Clears the content of the 'db' variable. | |
| @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails | |
| while VendorGuid is NULL. | |
| @retval other Errors from GetVariable2 (), GetTime () and SetVariable () | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| DeleteDb ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = DeleteVariable ( | |
| EFI_IMAGE_SECURITY_DATABASE, | |
| &gEfiImageSecurityDatabaseGuid | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Clears the content of the 'dbx' variable. | |
| @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails | |
| while VendorGuid is NULL. | |
| @retval other Errors from GetVariable2 (), GetTime () and SetVariable () | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| DeleteDbx ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = DeleteVariable ( | |
| EFI_IMAGE_SECURITY_DATABASE1, | |
| &gEfiImageSecurityDatabaseGuid | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Clears the content of the 'dbt' variable. | |
| @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails | |
| while VendorGuid is NULL. | |
| @retval other Errors from GetVariable2 (), GetTime () and SetVariable () | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| DeleteDbt ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = DeleteVariable ( | |
| EFI_IMAGE_SECURITY_DATABASE2, | |
| &gEfiImageSecurityDatabaseGuid | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Clears the content of the 'KEK' variable. | |
| @retval EFI_OUT_OF_RESOURCES If memory allocation for EFI_VARIABLE_AUTHENTICATION_2 fails | |
| while VendorGuid is NULL. | |
| @retval other Errors from GetVariable2 (), GetTime () and SetVariable () | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| DeleteKEK ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = DeleteVariable ( | |
| EFI_KEY_EXCHANGE_KEY_NAME, | |
| &gEfiGlobalVariableGuid | |
| ); | |
| return Status; | |
| } | |
| /** | |
| Remove the PK variable. | |
| @retval EFI_SUCCESS Delete PK successfully. | |
| @retval Others Could not allow to delete PK. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| DeletePlatformKey ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| Status = SetSecureBootMode (CUSTOM_SECURE_BOOT_MODE); | |
| if (EFI_ERROR (Status)) { | |
| return Status; | |
| } | |
| Status = DeleteVariable ( | |
| EFI_PLATFORM_KEY_NAME, | |
| &gEfiGlobalVariableGuid | |
| ); | |
| return Status; | |
| } | |
| /** | |
| This function will delete the secure boot keys, thus | |
| disabling secure boot. | |
| @return EFI_SUCCESS or underlying failure code. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| DeleteSecureBootVariables ( | |
| VOID | |
| ) | |
| { | |
| EFI_STATUS Status, TempStatus; | |
| DEBUG ((DEBUG_INFO, "%a - Attempting to delete the Secure Boot variables.\n", __func__)); | |
| // | |
| // Step 1: Notify that a PK update is coming shortly... | |
| Status = DisablePKProtection (); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a - Failed to signal PK update start! %r\n", __func__, Status)); | |
| // Classify this as a PK deletion error. | |
| Status = EFI_ABORTED; | |
| } | |
| // | |
| // Step 2: Attempt to delete the PK. | |
| // Let's try to nuke the PK, why not... | |
| if (!EFI_ERROR (Status)) { | |
| Status = DeletePlatformKey (); | |
| DEBUG ((DEBUG_INFO, "%a - PK Delete = %r\n", __func__, Status)); | |
| // If the PK is not found, then our work here is done. | |
| if (Status == EFI_NOT_FOUND) { | |
| Status = EFI_SUCCESS; | |
| } | |
| // If any other error occurred, let's inform the caller that the PK delete in particular failed. | |
| else if (EFI_ERROR (Status)) { | |
| Status = EFI_ABORTED; | |
| } | |
| } | |
| // | |
| // Step 3: Attempt to delete remaining keys/databases... | |
| // Now that the PK is deleted (assuming Status == EFI_SUCCESS) the system is in SETUP_MODE. | |
| // Arguably we could leave these variables in place and let them be deleted by whoever wants to | |
| // update all the SecureBoot variables. However, for cleanliness sake, let's try to | |
| // get rid of them here. | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // If any of THESE steps have an error, report the error but attempt to delete all keys. | |
| // Using TempStatus will prevent an error from being trampled by an EFI_SUCCESS. | |
| // Overwrite Status ONLY if TempStatus is an error. | |
| // | |
| // If the error is EFI_NOT_FOUND, we can safely ignore it since we were trying to delete | |
| // the variables anyway. | |
| // | |
| TempStatus = DeleteKEK (); | |
| DEBUG ((DEBUG_INFO, "%a - KEK Delete = %r\n", __func__, TempStatus)); | |
| if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) { | |
| Status = EFI_ACCESS_DENIED; | |
| } | |
| TempStatus = DeleteDb (); | |
| DEBUG ((DEBUG_INFO, "%a - db Delete = %r\n", __func__, TempStatus)); | |
| if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) { | |
| Status = EFI_ACCESS_DENIED; | |
| } | |
| TempStatus = DeleteDbx (); | |
| DEBUG ((DEBUG_INFO, "%a - dbx Delete = %r\n", __func__, TempStatus)); | |
| if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) { | |
| Status = EFI_ACCESS_DENIED; | |
| } | |
| TempStatus = DeleteDbt (); | |
| DEBUG ((DEBUG_INFO, "%a - dbt Delete = %r\n", __func__, TempStatus)); | |
| if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) { | |
| Status = EFI_ACCESS_DENIED; | |
| } | |
| } | |
| return Status; | |
| }// DeleteSecureBootVariables() | |
| /** | |
| A helper function to take in a variable payload, wrap it in the | |
| proper authenticated variable structure, and install it in the | |
| EFI variable space. | |
| @param[in] VariableName The name of the key/database. | |
| @param[in] VendorGuid The namespace (ie. vendor GUID) of the variable | |
| @param[in] DataSize Size parameter for target secure boot variable. | |
| @param[in] Data Pointer to signature list formatted secure boot variable content. | |
| @retval EFI_SUCCESS The enrollment for authenticated variable was successful. | |
| @retval EFI_OUT_OF_RESOURCES There are not enough memory resources to create time based payload. | |
| @retval EFI_INVALID_PARAMETER The parameter is invalid. | |
| @retval Others Unexpected error happens. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| EnrollFromInput ( | |
| IN CHAR16 *VariableName, | |
| IN EFI_GUID *VendorGuid, | |
| IN UINTN DataSize, | |
| IN VOID *Data | |
| ) | |
| { | |
| VOID *Payload; | |
| UINTN PayloadSize; | |
| EFI_STATUS Status; | |
| Payload = NULL; | |
| if ((VariableName == NULL) || (VendorGuid == 0)) { | |
| DEBUG ((DEBUG_ERROR, "Input vendor variable invalid: %p and %p\n", VariableName, VendorGuid)); | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| if ((Data == NULL) || (DataSize == 0)) { | |
| // You might as well just use DeleteVariable... | |
| DEBUG ((DEBUG_ERROR, "Input argument invalid: %p: %x\n", Data, DataSize)); | |
| Status = EFI_INVALID_PARAMETER; | |
| goto Exit; | |
| } | |
| // Bring in the noise... | |
| PayloadSize = DataSize; | |
| Payload = AllocateZeroPool (DataSize); | |
| // Bring in the funk... | |
| if (Payload == NULL) { | |
| return EFI_OUT_OF_RESOURCES; | |
| } else { | |
| CopyMem (Payload, Data, DataSize); | |
| } | |
| Status = CreateTimeBasedPayload (&PayloadSize, (UINT8 **)&Payload, &mDefaultPayloadTimestamp); | |
| if (EFI_ERROR (Status) || (Payload == NULL)) { | |
| DEBUG ((DEBUG_ERROR, "Fail to create time-based data payload: %r\n", Status)); | |
| Payload = NULL; | |
| Status = EFI_OUT_OF_RESOURCES; | |
| goto Exit; | |
| } | |
| // | |
| // Allocate memory for auth variable | |
| // | |
| Status = gRT->SetVariable ( | |
| VariableName, | |
| VendorGuid, | |
| (EFI_VARIABLE_NON_VOLATILE | | |
| EFI_VARIABLE_BOOTSERVICE_ACCESS | | |
| EFI_VARIABLE_RUNTIME_ACCESS | | |
| EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS), | |
| PayloadSize, | |
| Payload | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG (( | |
| DEBUG_ERROR, | |
| "error: %a (\"%s\", %g): %r\n", | |
| __func__, | |
| VariableName, | |
| VendorGuid, | |
| Status | |
| )); | |
| } | |
| Exit: | |
| // | |
| // Always Put Away Your Toys | |
| // Payload will be reassigned by CreateTimeBasedPayload()... | |
| if (Payload != NULL) { | |
| FreePool (Payload); | |
| Payload = NULL; | |
| } | |
| return Status; | |
| } | |
| /** | |
| Similar to DeleteSecureBootVariables, this function is used to unilaterally | |
| force the state of related SB variables (db, dbx, dbt, KEK, PK, etc.) to be | |
| the built-in, hardcoded default vars. | |
| @param[in] SecureBootPayload Payload information for secure boot related keys. | |
| @retval EFI_SUCCESS SecureBoot keys are now set to defaults. | |
| @retval EFI_ABORTED SecureBoot keys are not empty. Please delete keys first | |
| or follow standard methods of altering keys (ie. use the signing system). | |
| @retval EFI_SECURITY_VIOLATION Failed to create the PK. | |
| @retval Others Something failed in one of the subfunctions. | |
| **/ | |
| EFI_STATUS | |
| EFIAPI | |
| SetSecureBootVariablesToDefault ( | |
| IN CONST SECURE_BOOT_PAYLOAD_INFO *SecureBootPayload | |
| ) | |
| { | |
| EFI_STATUS Status; | |
| UINT8 *Data; | |
| UINTN DataSize; | |
| DEBUG ((DEBUG_INFO, "%a() Entry\n", __func__)); | |
| if (SecureBootPayload == NULL) { | |
| DEBUG ((DEBUG_ERROR, "%a - Invalid SecureBoot payload is supplied!\n", __func__)); | |
| return EFI_INVALID_PARAMETER; | |
| } | |
| // | |
| // Right off the bat, if SecureBoot is currently enabled, bail. | |
| if (IsSecureBootEnabled ()) { | |
| DEBUG ((DEBUG_ERROR, "%a - Cannot set default keys while SecureBoot is enabled!\n", __func__)); | |
| return EFI_ABORTED; | |
| } | |
| DEBUG ((DEBUG_INFO, "%a - Setting up key %s!\n", __func__, SecureBootPayload->SecureBootKeyName)); | |
| // | |
| // Start running down the list, creating variables in our wake. | |
| // dbx is a good place to start. | |
| Data = (UINT8 *)SecureBootPayload->DbxPtr; | |
| DataSize = SecureBootPayload->DbxSize; | |
| if (DataSize > MINIMUM_VALID_SIGNATURE_LIST) { | |
| // | |
| // Ensure that that the DataSize meets a minimum allowed size before being set. | |
| // | |
| DEBUG ((DEBUG_INFO, "%a - Setting Dbx\n", __func__)); | |
| Status = EnrollFromInput ( | |
| EFI_IMAGE_SECURITY_DATABASE1, | |
| &gEfiImageSecurityDatabaseGuid, | |
| DataSize, | |
| Data | |
| ); | |
| } else if ((DataSize == 0) || (DataSize == sizeof (EFI_SIGNATURE_LIST))) { | |
| // | |
| // The DBX is allowed to be empty by default | |
| // | |
| DEBUG ((DEBUG_INFO, "%a - Skipping Dbx - DataSize(%u)\n", __func__, DataSize)); | |
| Status = EFI_SUCCESS; | |
| } else { | |
| DEBUG ((DEBUG_ERROR, "%a - Invalid Dbx size %u\n", __func__, DataSize)); | |
| Status = EFI_INVALID_PARAMETER; | |
| } | |
| // If that went well, try the db (make sure to pick the right one!). | |
| if (!EFI_ERROR (Status)) { | |
| Data = (UINT8 *)SecureBootPayload->DbPtr; | |
| DataSize = SecureBootPayload->DbSize; | |
| Status = EnrollFromInput ( | |
| EFI_IMAGE_SECURITY_DATABASE, | |
| &gEfiImageSecurityDatabaseGuid, | |
| DataSize, | |
| Data | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a - Failed to enroll DB %r!\n", __func__, Status)); | |
| } | |
| } else { | |
| DEBUG ((DEBUG_ERROR, "%a - Failed to enroll DBX %r!\n", __func__, Status)); | |
| } | |
| // Keep it going. Keep it going. dbt if supplied... | |
| if (!EFI_ERROR (Status) && (SecureBootPayload->DbtPtr != NULL)) { | |
| Data = (UINT8 *)SecureBootPayload->DbtPtr; | |
| DataSize = SecureBootPayload->DbtSize; | |
| Status = EnrollFromInput ( | |
| EFI_IMAGE_SECURITY_DATABASE2, | |
| &gEfiImageSecurityDatabaseGuid, | |
| DataSize, | |
| Data | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a - Failed to enroll DBT %r!\n", __func__, Status)); | |
| } | |
| } | |
| // Keep it going. Keep it going. KEK... | |
| if (!EFI_ERROR (Status)) { | |
| Data = (UINT8 *)SecureBootPayload->KekPtr; | |
| DataSize = SecureBootPayload->KekSize; | |
| Status = EnrollFromInput ( | |
| EFI_KEY_EXCHANGE_KEY_NAME, | |
| &gEfiGlobalVariableGuid, | |
| DataSize, | |
| Data | |
| ); | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a - Failed to enroll KEK %r!\n", __func__, Status)); | |
| } | |
| } | |
| // | |
| // Finally! The Big Daddy of them all. | |
| // The PK! | |
| // | |
| if (!EFI_ERROR (Status)) { | |
| // | |
| // Finally, install the key. | |
| Data = (UINT8 *)SecureBootPayload->PkPtr; | |
| DataSize = SecureBootPayload->PkSize; | |
| Status = EnrollFromInput ( | |
| EFI_PLATFORM_KEY_NAME, | |
| &gEfiGlobalVariableGuid, | |
| DataSize, | |
| Data | |
| ); | |
| // | |
| // Report PK creation errors. | |
| if (EFI_ERROR (Status)) { | |
| DEBUG ((DEBUG_ERROR, "%a - Failed to update the PK! - %r\n", __func__, Status)); | |
| Status = EFI_SECURITY_VIOLATION; | |
| } | |
| } | |
| return Status; | |
| } |