/** @file This library provides functions to set/clear Secure Boot keys and databases. Copyright (c) 2011 - 2018, Intel Corporation. All rights reserved.
(C) Copyright 2018 Hewlett Packard Enterprise Development LP
Copyright (c) 2021, ARM Ltd. All rights reserved.
Copyright (c) 2021, Semihalf All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include /** Create a EFI Signature List with data fetched from section specified as a argument. Found keys are verified using RsaGetPublicKeyFromX509(). @param[in] KeyFileGuid A pointer to to the FFS filename GUID @param[out] SigListsSize A pointer to size of signature list @param[out] SigListOut a pointer to a callee-allocated buffer with signature lists @retval EFI_SUCCESS Create time based payload successfully. @retval EFI_NOT_FOUND Section with key has not been found. @retval EFI_INVALID_PARAMETER Embedded key has a wrong format. @retval Others Unexpected error happens. **/ STATIC EFI_STATUS SecureBootFetchData ( IN EFI_GUID *KeyFileGuid, OUT UINTN *SigListsSize, OUT EFI_SIGNATURE_LIST **SigListOut ) { EFI_SIGNATURE_LIST *EfiSig; EFI_STATUS Status; VOID *Buffer; VOID *RsaPubKey; UINTN Size; UINTN KeyIndex; UINTN Index; SECURE_BOOT_CERTIFICATE_INFO *CertInfo; SECURE_BOOT_CERTIFICATE_INFO *NewCertInfo; KeyIndex = 0; EfiSig = NULL; *SigListOut = NULL; *SigListsSize = 0; CertInfo = AllocatePool (sizeof (SECURE_BOOT_CERTIFICATE_INFO)); NewCertInfo = CertInfo; while (1) { if (NewCertInfo == NULL) { Status = EFI_OUT_OF_RESOURCES; break; } else { CertInfo = NewCertInfo; } Status = GetSectionFromAnyFv ( KeyFileGuid, EFI_SECTION_RAW, KeyIndex, &Buffer, &Size ); if (Status == EFI_SUCCESS) { RsaPubKey = NULL; if (RsaGetPublicKeyFromX509 (Buffer, Size, &RsaPubKey) == FALSE) { DEBUG ((DEBUG_ERROR, "%a: Invalid key format: %d\n", __func__, KeyIndex)); if (EfiSig != NULL) { FreePool (EfiSig); } FreePool (Buffer); Status = EFI_INVALID_PARAMETER; break; } CertInfo[KeyIndex].Data = Buffer; CertInfo[KeyIndex].DataSize = Size; KeyIndex++; NewCertInfo = ReallocatePool ( sizeof (SECURE_BOOT_CERTIFICATE_INFO) * KeyIndex, sizeof (SECURE_BOOT_CERTIFICATE_INFO) * (KeyIndex + 1), CertInfo ); } if (Status == EFI_NOT_FOUND) { Status = EFI_SUCCESS; break; } } if (EFI_ERROR (Status)) { goto Cleanup; } if (KeyIndex == 0) { Status = EFI_NOT_FOUND; goto Cleanup; } // Now that we collected all certs from FV, convert it into sig list Status = SecureBootCreateDataFromInput (SigListsSize, SigListOut, KeyIndex, CertInfo); if (EFI_ERROR (Status)) { goto Cleanup; } Cleanup: if (CertInfo) { for (Index = 0; Index < KeyIndex; Index++) { FreePool ((VOID *)CertInfo[Index].Data); } FreePool (CertInfo); } return Status; } /** Enroll a key/certificate based on a default variable. @param[in] VariableName The name of the key/database. @param[in] DefaultName The name of the default variable. @param[in] VendorGuid The namespace (ie. vendor GUID) of the variable @retval EFI_OUT_OF_RESOURCES Out of memory while allocating AuthHeader. @retval EFI_SUCCESS Successful enrollment. @return Error codes from GetTime () and SetVariable (). **/ STATIC EFI_STATUS EnrollFromDefault ( IN CHAR16 *VariableName, IN CHAR16 *DefaultName, IN EFI_GUID *VendorGuid ) { VOID *Data; UINTN DataSize; EFI_STATUS Status; Status = EFI_SUCCESS; DataSize = 0; Status = GetVariable2 (DefaultName, &gEfiGlobalVariableGuid, &Data, &DataSize); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "error: GetVariable (\"%s): %r\n", DefaultName, Status)); return Status; } Status = EnrollFromInput (VariableName, VendorGuid, DataSize, Data); if (Data != NULL) { FreePool (Data); } return Status; } /** Initializes PKDefault variable with data from FFS section. @retval EFI_SUCCESS Variable was initialized successfully. @retval EFI_UNSUPPORTED Variable already exists. **/ EFI_STATUS SecureBootInitPKDefault ( IN VOID ) { EFI_SIGNATURE_LIST *EfiSig; UINTN SigListsSize; EFI_STATUS Status; UINT8 *Data; UINTN DataSize; // // Check if variable exists, if so do not change it // Status = GetVariable2 (EFI_PK_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, (VOID **)&Data, &DataSize); if (Status == EFI_SUCCESS) { DEBUG ((DEBUG_INFO, "Variable %s exists. Old value is preserved\n", EFI_PK_DEFAULT_VARIABLE_NAME)); FreePool (Data); return EFI_UNSUPPORTED; } if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { return Status; } // // Variable does not exist, can be initialized // DEBUG ((DEBUG_INFO, "Variable %s does not exist.\n", EFI_PK_DEFAULT_VARIABLE_NAME)); Status = SecureBootFetchData (&gDefaultPKFileGuid, &SigListsSize, &EfiSig); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "Content for %s not found\n", EFI_PK_DEFAULT_VARIABLE_NAME)); return Status; } Status = gRT->SetVariable ( EFI_PK_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, SigListsSize, (VOID *)EfiSig ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "Failed to set %s\n", EFI_PK_DEFAULT_VARIABLE_NAME)); } FreePool (EfiSig); return Status; } /** Initializes KEKDefault variable with data from FFS section. @retval EFI_SUCCESS Variable was initialized successfully. @retval EFI_UNSUPPORTED Variable already exists. **/ EFI_STATUS SecureBootInitKEKDefault ( IN VOID ) { EFI_SIGNATURE_LIST *EfiSig; UINTN SigListsSize; EFI_STATUS Status; UINT8 *Data; UINTN DataSize; // // Check if variable exists, if so do not change it // Status = GetVariable2 (EFI_KEK_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, (VOID **)&Data, &DataSize); if (Status == EFI_SUCCESS) { DEBUG ((DEBUG_INFO, "Variable %s exists. Old value is preserved\n", EFI_KEK_DEFAULT_VARIABLE_NAME)); FreePool (Data); return EFI_UNSUPPORTED; } if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { return Status; } // // Variable does not exist, can be initialized // DEBUG ((DEBUG_INFO, "Variable %s does not exist.\n", EFI_KEK_DEFAULT_VARIABLE_NAME)); Status = SecureBootFetchData (&gDefaultKEKFileGuid, &SigListsSize, &EfiSig); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "Content for %s not found\n", EFI_KEK_DEFAULT_VARIABLE_NAME)); return Status; } Status = gRT->SetVariable ( EFI_KEK_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, SigListsSize, (VOID *)EfiSig ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "Failed to set %s\n", EFI_KEK_DEFAULT_VARIABLE_NAME)); } FreePool (EfiSig); return Status; } /** Initializes dbDefault variable with data from FFS section. @retval EFI_SUCCESS Variable was initialized successfully. @retval EFI_UNSUPPORTED Variable already exists. **/ EFI_STATUS SecureBootInitDbDefault ( IN VOID ) { EFI_SIGNATURE_LIST *EfiSig; UINTN SigListsSize; EFI_STATUS Status; UINT8 *Data; UINTN DataSize; Status = GetVariable2 (EFI_DB_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, (VOID **)&Data, &DataSize); if (Status == EFI_SUCCESS) { DEBUG ((DEBUG_INFO, "Variable %s exists. Old value is preserved\n", EFI_DB_DEFAULT_VARIABLE_NAME)); FreePool (Data); return EFI_UNSUPPORTED; } if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { return Status; } DEBUG ((DEBUG_INFO, "Variable %s does not exist.\n", EFI_DB_DEFAULT_VARIABLE_NAME)); Status = SecureBootFetchData (&gDefaultdbFileGuid, &SigListsSize, &EfiSig); if (EFI_ERROR (Status)) { return Status; } Status = gRT->SetVariable ( EFI_DB_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, SigListsSize, (VOID *)EfiSig ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "Failed to set %s\n", EFI_DB_DEFAULT_VARIABLE_NAME)); } FreePool (EfiSig); return Status; } /** Initializes dbxDefault variable with data from FFS section. @retval EFI_SUCCESS Variable was initialized successfully. @retval EFI_UNSUPPORTED Variable already exists. **/ EFI_STATUS SecureBootInitDbxDefault ( IN VOID ) { EFI_SIGNATURE_LIST *EfiSig; UINTN SigListsSize; EFI_STATUS Status; UINT8 *Data; UINTN DataSize; // // Check if variable exists, if so do not change it // Status = GetVariable2 (EFI_DBX_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, (VOID **)&Data, &DataSize); if (Status == EFI_SUCCESS) { DEBUG ((DEBUG_INFO, "Variable %s exists. Old value is preserved\n", EFI_DBX_DEFAULT_VARIABLE_NAME)); FreePool (Data); return EFI_UNSUPPORTED; } if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { return Status; } // // Variable does not exist, can be initialized // DEBUG ((DEBUG_INFO, "Variable %s does not exist.\n", EFI_DBX_DEFAULT_VARIABLE_NAME)); Status = SecureBootFetchData (&gDefaultdbxFileGuid, &SigListsSize, &EfiSig); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "Content for %s not found\n", EFI_DBX_DEFAULT_VARIABLE_NAME)); return Status; } Status = gRT->SetVariable ( EFI_DBX_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, SigListsSize, (VOID *)EfiSig ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "Failed to set %s\n", EFI_DBX_DEFAULT_VARIABLE_NAME)); } FreePool (EfiSig); return Status; } /** Initializes dbtDefault variable with data from FFS section. @retval EFI_SUCCESS Variable was initialized successfully. @retval EFI_UNSUPPORTED Variable already exists. **/ EFI_STATUS SecureBootInitDbtDefault ( IN VOID ) { EFI_SIGNATURE_LIST *EfiSig; UINTN SigListsSize; EFI_STATUS Status; UINT8 *Data; UINTN DataSize; // // Check if variable exists, if so do not change it // Status = GetVariable2 (EFI_DBT_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, (VOID **)&Data, &DataSize); if (Status == EFI_SUCCESS) { DEBUG ((DEBUG_INFO, "Variable %s exists. Old value is preserved\n", EFI_DBT_DEFAULT_VARIABLE_NAME)); FreePool (Data); return EFI_UNSUPPORTED; } if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) { return Status; } // // Variable does not exist, can be initialized // DEBUG ((DEBUG_INFO, "Variable %s does not exist.\n", EFI_DBT_DEFAULT_VARIABLE_NAME)); Status = SecureBootFetchData (&gDefaultdbtFileGuid, &SigListsSize, &EfiSig); if (EFI_ERROR (Status)) { return Status; } Status = gRT->SetVariable ( EFI_DBT_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid, EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS, SigListsSize, (VOID *)EfiSig ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_INFO, "Failed to set %s\n", EFI_DBT_DEFAULT_VARIABLE_NAME)); } FreePool (EfiSig); return EFI_SUCCESS; } /** Sets the content of the 'db' variable based on 'dbDefault' variable content. @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 EnrollDbFromDefault ( VOID ) { EFI_STATUS Status; Status = EnrollFromDefault ( EFI_IMAGE_SECURITY_DATABASE, EFI_DB_DEFAULT_VARIABLE_NAME, &gEfiImageSecurityDatabaseGuid ); return Status; } /** Sets the content of the 'dbx' variable based on 'dbxDefault' variable content. @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 EnrollDbxFromDefault ( VOID ) { EFI_STATUS Status; Status = EnrollFromDefault ( EFI_IMAGE_SECURITY_DATABASE1, EFI_DBX_DEFAULT_VARIABLE_NAME, &gEfiImageSecurityDatabaseGuid ); return Status; } /** Sets the content of the 'dbt' variable based on 'dbtDefault' variable content. @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 EnrollDbtFromDefault ( VOID ) { EFI_STATUS Status; Status = EnrollFromDefault ( EFI_IMAGE_SECURITY_DATABASE2, EFI_DBT_DEFAULT_VARIABLE_NAME, &gEfiImageSecurityDatabaseGuid ); return Status; } /** Sets the content of the 'KEK' variable based on 'KEKDefault' variable content. @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 EnrollKEKFromDefault ( VOID ) { EFI_STATUS Status; Status = EnrollFromDefault ( EFI_KEY_EXCHANGE_KEY_NAME, EFI_KEK_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid ); return Status; } /** Sets the content of the 'KEK' variable based on 'KEKDefault' variable content. @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 EnrollPKFromDefault ( VOID ) { EFI_STATUS Status; Status = EnrollFromDefault ( EFI_PLATFORM_KEY_NAME, EFI_PK_DEFAULT_VARIABLE_NAME, &gEfiGlobalVariableGuid ); return Status; }