/* # Copyright (c) 2014-2018, Linaro Limited. All rights reserved. # # SPDX-License-Identifier: BSD-2-Clause-Patent # */ #include typedef enum KEY { PK_KEY=1, KEK_KEY, DB_KEY, DBX_KEY } eKey; /* ************************** */ STATIC EFI_STATUS OpenFileByDevicePath( IN OUT EFI_DEVICE_PATH_PROTOCOL **FilePath, OUT EFI_FILE_HANDLE *FileHandle, IN UINT64 OpenMode, IN UINT64 Attributes ) { EFI_STATUS Status; EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *EfiSimpleFileSystemProtocol; EFI_FILE_PROTOCOL *Handle1; EFI_FILE_PROTOCOL *Handle2; EFI_HANDLE DeviceHandle; if (FilePath == NULL) { return EFI_INVALID_PARAMETER; } Status = gBS->LocateDevicePath ( &gEfiSimpleFileSystemProtocolGuid, FilePath, &DeviceHandle ); if (EFI_ERROR (Status)) { return Status; } Status = gBS->OpenProtocol ( DeviceHandle, &gEfiSimpleFileSystemProtocolGuid, (VOID**)&EfiSimpleFileSystemProtocol, gImageHandle, NULL, EFI_OPEN_PROTOCOL_GET_PROTOCOL ); if (EFI_ERROR (Status)) { return Status; } Status = EfiSimpleFileSystemProtocol->OpenVolume (\ EfiSimpleFileSystemProtocol, &Handle1); if (EFI_ERROR (Status)) { FileHandle = NULL; return Status; } // // go down directories one node at a time. // while (!IsDevicePathEnd (*FilePath)) { // // For file system access each node should be a file path component // if (DevicePathType (*FilePath) != MEDIA_DEVICE_PATH || DevicePathSubType (*FilePath) != MEDIA_FILEPATH_DP ) { FileHandle = NULL; return (EFI_INVALID_PARAMETER); } // // Open this file path node // Handle2 = Handle1; Handle1 = NULL; // // Try to test opening an existing file // Status = Handle2->Open ( Handle2, &Handle1, ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, OpenMode &~EFI_FILE_MODE_CREATE, 0 ); // // see if the error was that it needs to be created // if ((EFI_ERROR (Status)) && (OpenMode != (OpenMode &~EFI_FILE_MODE_CREATE))) { Status = Handle2->Open ( Handle2, &Handle1, ((FILEPATH_DEVICE_PATH*)*FilePath)->PathName, OpenMode, Attributes ); } // // Close the last node // Handle2->Close (Handle2); if (EFI_ERROR (Status)) { return (Status); } // // Get the next node // *FilePath = NextDevicePathNode (*FilePath); } // // This is a weak spot since if the undefined // SHELL_FILE_HANDLE format changes this must change also! // *FileHandle = (VOID*)Handle1; return EFI_SUCCESS; } EFI_STATUS GetFileHandler ( OUT EFI_FILE_HANDLE *FileHandle, IN CONST CHAR16 *Path, IN UINT64 OpenMode ) { EFI_STATUS Status; EFI_DEVICE_PATH_PROTOCOL *KeyFileDevicePath; EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *DevicePathFromTextProtocol; Status = EFI_SUCCESS; KeyFileDevicePath = NULL; Status = gBS->LocateProtocol ( &gEfiDevicePathFromTextProtocolGuid, NULL, (VOID**)&DevicePathFromTextProtocol ); ASSERT_EFI_ERROR (Status); KeyFileDevicePath = DevicePathFromTextProtocol->ConvertTextToDevicePath (Path); if (KeyFileDevicePath != NULL) { Status = OpenFileByDevicePath (&KeyFileDevicePath, FileHandle, OpenMode, 0); if (Status != EFI_SUCCESS) { DEBUG ((DEBUG_ERROR, "Getting FileHandle of %s Failed\n",Path)); } } return Status; } STATIC EFI_STATUS CreateTimeBasedPayload ( IN OUT UINTN *DataSize, IN OUT UINT8 **Data ) { EFI_STATUS Status; UINT8 *NewData; UINT8 *Payload; UINTN PayloadSize; EFI_VARIABLE_AUTHENTICATION_2 *DescriptorData; UINTN DescriptorSize; EFI_TIME Time; if (Data == NULL || DataSize == NULL) { 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) { return EFI_OUT_OF_RESOURCES; } if ((Payload != NULL) && (PayloadSize != 0)) { CopyMem (NewData + DescriptorSize, Payload, PayloadSize); } DescriptorData = (EFI_VARIABLE_AUTHENTICATION_2 *) (NewData); ZeroMem (&Time, sizeof (EFI_TIME)); Status = gRT->GetTime (&Time, NULL); if (EFI_ERROR (Status)) { FreePool(NewData); return Status; } Time.Pad1 = 0; Time.Nanosecond = 0; Time.TimeZone = 0; Time.Daylight = 0; Time.Pad2 = 0; 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); } *DataSize = DescriptorSize + PayloadSize; *Data = NewData; return EFI_SUCCESS; } STATIC EFI_STATUS SetBootMode ( IN UINT8 SecureBootMode ) { return gRT->SetVariable ( EFI_CUSTOM_MODE_NAME, &gEfiCustomModeEnableGuid, EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS, sizeof (UINT8), &SecureBootMode ); } STATIC EFI_STATUS SetVariable ( IN EFI_SIGNATURE_LIST *PkCert, IN UINTN DataSize, IN eKey KeyType ) { UINT32 Attr; EFI_STATUS Status; Status = EFI_SUCCESS; Attr = EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS; if (KeyType == PK_KEY) { DEBUG ((DEBUG_INFO, "Setting PK Key\n")); Status = gRT->SetVariable ( EFI_PLATFORM_KEY_NAME, &gEfiGlobalVariableGuid, Attr, DataSize, PkCert ); } else if (KeyType == KEK_KEY) { DEBUG ((DEBUG_INFO, "Setting KEK Key\n")); Status = gRT->SetVariable ( EFI_KEY_EXCHANGE_KEY_NAME, &gEfiGlobalVariableGuid, Attr, DataSize, PkCert ); Status = gRT->SetVariable ( EFI_IMAGE_SECURITY_DATABASE, &gEfiImageSecurityDatabaseGuid, Attr, DataSize, PkCert ); } else { ASSERT(FALSE); } return Status; } STATIC VOID PopulateCert ( OUT EFI_SIGNATURE_LIST **Cert, IN UINTN DataSize, IN UINT8 *Data ) { EFI_SIGNATURE_DATA *CertData = NULL; if ((*Cert) == NULL) { (*Cert) = (EFI_SIGNATURE_LIST*) AllocateZeroPool (sizeof (EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + DataSize ); ASSERT ((*Cert) != NULL); } (*Cert)->SignatureListSize = (UINT32) (sizeof (EFI_SIGNATURE_LIST) + sizeof (EFI_SIGNATURE_DATA) - 1 + DataSize); (*Cert)->SignatureSize = (UINT32) (sizeof (EFI_SIGNATURE_DATA) - 1 + DataSize); (*Cert)->SignatureHeaderSize = 0; CopyGuid (&(*Cert)->SignatureType, &gEfiCertX509Guid); CertData = (EFI_SIGNATURE_DATA*) ((UINTN)(*Cert) + \ sizeof(EFI_SIGNATURE_LIST) + (*Cert)->SignatureHeaderSize); ASSERT (CertData != NULL); CopyGuid (&CertData->SignatureOwner, &gEfiGlobalVariableGuid); CopyMem (&CertData->SignatureData, Data, DataSize); } STATIC EFI_STATUS RegisterCert ( IN UINT8 *KeyData, IN UINTN KeySize, IN eKey KeyType ) { EFI_STATUS Status; EFI_SIGNATURE_LIST *Cert; Cert = NULL; Status = SetBootMode (CUSTOM_SECURE_BOOT_MODE); ASSERT_EFI_ERROR (Status); PopulateCert (&Cert, KeySize, KeyData); KeySize = Cert->SignatureListSize; Status = CreateTimeBasedPayload (&KeySize, (UINT8**) &Cert); ASSERT_EFI_ERROR (Status); Status = SetVariable (Cert, KeySize, KeyType); return Status; } STATIC VOID RdkSetVariable ( VOID ) { CONST CHAR16 *KeyPath; EFI_STATUS Status; UINT8 *KekKey, *PkKey, *KekCrtData; UINTN KekKeySize, PkKeySize, KekCrtSize; INT8* SetupMode; eKey KeyType; KeyPath = NULL; SetupMode = NULL; KekKey = PkKey = KekCrtData = NULL; KekKeySize = PkKeySize = KekCrtSize = 0; Status = GetRdkVariable (L"ROOTCERT", &KeyPath); //set only if the Kek Crt file mentioned in the configuration file if (KeyPath != NULL) { Status = RdkReadFile ( KeyPath, (VOID **)&KekCrtData, &KekCrtSize ); ASSERT_EFI_ERROR (Status); Status = gRT->SetVariable ( L"RdkRootCertificate", &gRdkGlobalVariableGuid, EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS, KekCrtSize, KekCrtData ); ASSERT_EFI_ERROR (Status); if (KekCrtData) FreePool (KekCrtData); } Status = GetRdkVariable (L"KEKCERT", &KeyPath); ASSERT_EFI_ERROR (Status); Status = RdkReadFile ( KeyPath, (VOID **)&KekKey, &KekKeySize ); ASSERT_EFI_ERROR (Status); Status = GetRdkVariable (L"PKCERT", &KeyPath); ASSERT_EFI_ERROR (Status); Status = RdkReadFile ( KeyPath, (VOID **)&PkKey, &PkKeySize ); ASSERT_EFI_ERROR (Status); KeyType = PK_KEY; Status = RegisterCert (PkKey, PkKeySize, KeyType); GetEfiGlobalVariable2 (L"SetupMode", (VOID**)&SetupMode, NULL); if (*SetupMode == 0) { DEBUG ((DEBUG_INFO, "PK Key Got Registered. Now System in User Mode\n")); KeyType = KEK_KEY; Status = RegisterCert (KekKey, KekKeySize, KeyType); } else if(*SetupMode == 1) { DEBUG ((DEBUG_INFO, "System in Standard System Mode ::: Secure Boot Not enabled\n")); ASSERT_EFI_ERROR (Status); } if ( PkKey ) FreePool (PkKey); if ( KekKey ) FreePool (KekKey); } EFI_STATUS RdkSecureBoot ( EFI_HANDLE ImageHandle, EFI_BOOT_SERVICES *BootServices ) { UINTN ExitDataSize; CHAR16 *ExitData; CHAR16 LoadOption[128]; CONST CHAR8 *CmdLine; CHAR16 *ImagePath; UINT8 *FdtData; CONST CHAR16 *DtbPath; EFI_STATUS Status; EFI_HANDLE Handle; EFI_DEVICE_PATH_PROTOCOL *FilePath; EFI_LOADED_IMAGE_PROTOCOL *ImageInfo; EFI_DEVICE_PATH_FROM_TEXT_PROTOCOL *DevicePathFromTextProtocol; FilePath = NULL; ExitData = NULL; CmdLine = (CONST CHAR8 *)FixedPcdGetPtr (PcdRdkCmdLineArgs); if (FixedPcdGetBool (PcdDtbAvailable)) { FdtData = NULL; DtbPath = NULL; Status = GetRdkVariable (L"DTB", &DtbPath); ASSERT_EFI_ERROR (Status); Status = RdkReadFile (DtbPath, (VOID**) &FdtData, NULL); ASSERT_EFI_ERROR (Status); Status = gBS->InstallConfigurationTable (&gFdtTableGuid,(VOID*)FdtData); ASSERT_EFI_ERROR (Status); } RdkSetVariable (); Status = GetRdkVariable (L"IMAGE", (CONST CHAR16**)&ImagePath); ASSERT_EFI_ERROR (Status); Status = gBS->LocateProtocol ( &gEfiDevicePathFromTextProtocolGuid, NULL, (VOID**)&DevicePathFromTextProtocol ); ASSERT_EFI_ERROR (Status); FilePath = DevicePathFromTextProtocol->ConvertTextToDevicePath (ImagePath); ASSERT(NULL != FilePath); Status = BootServices->LoadImage ( TRUE, ImageHandle, FilePath, NULL, 0, &Handle ); ASSERT_EFI_ERROR (Status); UnicodeSPrintAsciiFormat (LoadOption, sizeof (LoadOption), CmdLine); Status = BootServices->HandleProtocol (\ Handle, &gEfiLoadedImageProtocolGuid, (VOID **)&ImageInfo); ASSERT_EFI_ERROR (Status); ImageInfo->LoadOptionsSize = sizeof (LoadOption); ImageInfo->LoadOptions = LoadOption; Status = BootServices->StartImage (Handle, &ExitDataSize, &ExitData); ASSERT_EFI_ERROR (Status); return Status; }