X-Git-Url: https://git.proxmox.com/?p=mirror_edk2.git;a=blobdiff_plain;f=SecurityPkg%2FLibrary%2FSecureBootVariableLib%2FSecureBootVariableLib.c;fp=SecurityPkg%2FLibrary%2FSecureBootVariableLib%2FSecureBootVariableLib.c;h=abca249c6504d78cf81ecbaf73dbd8b80a8d1c2c;hp=f56f0322e9431b16093154e964f425ea4161abad;hb=6eb407947592e084110a124be089bef167af1383;hpb=6de7c084dbb6d02f3b8cdb68dc4716df96c6758f diff --git a/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c b/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c index f56f0322e9..abca249c65 100644 --- a/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c +++ b/SecurityPkg/Library/SecureBootVariableLib/SecureBootVariableLib.c @@ -21,6 +21,7 @@ #include #include #include +#include // This time can be used when deleting variables, as it should be greater than any variable time. EFI_TIME mMaxTimestamp = { @@ -37,6 +38,24 @@ EFI_TIME mMaxTimestamp = { 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. @@ -413,6 +432,44 @@ GetSetupMode ( 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. @@ -531,3 +588,311 @@ DeletePlatformKey ( ); 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", __FUNCTION__)); + + // + // 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", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__, TempStatus)); + if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) { + Status = EFI_ACCESS_DENIED; + } + + TempStatus = DeleteDb (); + DEBUG ((DEBUG_INFO, "%a - db Delete = %r\n", __FUNCTION__, TempStatus)); + if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) { + Status = EFI_ACCESS_DENIED; + } + + TempStatus = DeleteDbx (); + DEBUG ((DEBUG_INFO, "%a - dbx Delete = %r\n", __FUNCTION__, TempStatus)); + if (EFI_ERROR (TempStatus) && (TempStatus != EFI_NOT_FOUND)) { + Status = EFI_ACCESS_DENIED; + } + + TempStatus = DeleteDbt (); + DEBUG ((DEBUG_INFO, "%a - dbt Delete = %r\n", __FUNCTION__, 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", + __FUNCTION__, + 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", __FUNCTION__)); + + if (SecureBootPayload == NULL) { + DEBUG ((DEBUG_ERROR, "%a - Invalid SecureBoot payload is supplied!\n", __FUNCTION__)); + 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", __FUNCTION__)); + return EFI_ABORTED; + } + + DEBUG ((DEBUG_INFO, "%a - Setting up key %s!\n", __FUNCTION__, 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; + Status = EnrollFromInput ( + EFI_IMAGE_SECURITY_DATABASE1, + &gEfiImageSecurityDatabaseGuid, + DataSize, + Data + ); + + // 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", __FUNCTION__, Status)); + } + } else { + DEBUG ((DEBUG_ERROR, "%a - Failed to enroll DBX %r!\n", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__, 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", __FUNCTION__, Status)); + Status = EFI_SECURITY_VIOLATION; + } + } + + return Status; +}