/** @file The Miscellaneous Routines for TlsAuthConfigDxe driver. Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.
SPDX-License-Identifier: BSD-2-Clause-Patent **/ #include "TlsAuthConfigImpl.h" VOID *mStartOpCodeHandle = NULL; VOID *mEndOpCodeHandle = NULL; EFI_IFR_GUID_LABEL *mStartLabel = NULL; EFI_IFR_GUID_LABEL *mEndLabel = NULL; CHAR16 mTlsAuthConfigStorageName[] = L"TLS_AUTH_CONFIG_IFR_NVDATA"; TLS_AUTH_CONFIG_PRIVATE_DATA *mTlsAuthPrivateData = NULL; HII_VENDOR_DEVICE_PATH mTlsAuthConfigHiiVendorDevicePath = { { { HARDWARE_DEVICE_PATH, HW_VENDOR_DP, { (UINT8) (sizeof (VENDOR_DEVICE_PATH)), (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8) } }, TLS_AUTH_CONFIG_GUID }, { END_DEVICE_PATH_TYPE, END_ENTIRE_DEVICE_PATH_SUBTYPE, { (UINT8) (END_DEVICE_PATH_LENGTH), (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8) } } }; // // Possible DER-encoded certificate file suffixes, end with NULL pointer. // CHAR16* mDerPemEncodedSuffix[] = { L".cer", L".der", L".crt", L".pem", NULL }; /** This code checks if the FileSuffix is one of the possible DER/PEM-encoded certificate suffix. @param[in] FileSuffix The suffix of the input certificate file @retval TRUE It's a DER/PEM-encoded certificate. @retval FALSE It's NOT a DER/PEM-encoded certificate. **/ BOOLEAN IsDerPemEncodeCertificate ( IN CONST CHAR16 *FileSuffix ) { UINTN Index; for (Index = 0; mDerPemEncodedSuffix[Index] != NULL; Index++) { if (StrCmp (FileSuffix, mDerPemEncodedSuffix[Index]) == 0) { return TRUE; } } return FALSE; } /** Worker function that prints an EFI_GUID into specified Buffer. @param[in] Guid Pointer to GUID to print. @param[in] Buffer Buffer to print Guid into. @param[in] BufferSize Size of Buffer. @retval Number of characters printed. **/ UINTN GuidToString ( IN EFI_GUID *Guid, IN CHAR16 *Buffer, IN UINTN BufferSize ) { return UnicodeSPrint ( Buffer, BufferSize, L"%g", Guid ); } /** List all cert in specified database by GUID in the page for user to select and delete as needed. @param[in] PrivateData Module's private data. @param[in] VariableName The variable name of the vendor's signature database. @param[in] VendorGuid A unique identifier for the vendor. @param[in] LabelNumber Label number to insert opcodes. @param[in] FormId Form ID of current page. @param[in] QuestionIdBase Base question id of the signature list. @retval EFI_SUCCESS Success to update the signature list page @retval EFI_OUT_OF_RESOURCES Unable to allocate required resources. **/ EFI_STATUS UpdateDeletePage ( IN TLS_AUTH_CONFIG_PRIVATE_DATA *Private, IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN UINT16 LabelNumber, IN EFI_FORM_ID FormId, IN EFI_QUESTION_ID QuestionIdBase ) { EFI_STATUS Status; UINT32 Index; UINTN CertCount; UINTN GuidIndex; VOID *StartOpCodeHandle; VOID *EndOpCodeHandle; EFI_IFR_GUID_LABEL *StartLabel; EFI_IFR_GUID_LABEL *EndLabel; UINTN DataSize; UINT8 *Data; EFI_SIGNATURE_LIST *CertList; EFI_SIGNATURE_DATA *Cert; UINT32 ItemDataSize; CHAR16 *GuidStr; EFI_STRING_ID GuidID; EFI_STRING_ID Help; Data = NULL; CertList = NULL; Cert = NULL; GuidStr = NULL; StartOpCodeHandle = NULL; EndOpCodeHandle = NULL; // // Initialize the container for dynamic opcodes. // StartOpCodeHandle = HiiAllocateOpCodeHandle (); if (StartOpCodeHandle == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; } EndOpCodeHandle = HiiAllocateOpCodeHandle (); if (EndOpCodeHandle == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; } // // Create Hii Extend Label OpCode. // StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL) ); StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; StartLabel->Number = LabelNumber; EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL) ); EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; EndLabel->Number = LABEL_END; // // Read Variable. // DataSize = 0; Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data); if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) { goto ON_EXIT; } Data = (UINT8 *) AllocateZeroPool (DataSize); if (Data == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; } Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, Data); if (EFI_ERROR (Status)) { goto ON_EXIT; } GuidStr = AllocateZeroPool (100); if (GuidStr == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; } // // Enumerate all data. // ItemDataSize = (UINT32) DataSize; CertList = (EFI_SIGNATURE_LIST *) Data; GuidIndex = 0; while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) { if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { Help = STRING_TOKEN (STR_CERT_TYPE_PCKS_GUID); } else { // // The signature type is not supported in current implementation. // ItemDataSize -= CertList->SignatureListSize; CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); continue; } CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; for (Index = 0; Index < CertCount; Index++) { Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize + Index * CertList->SignatureSize); // // Display GUID and help // GuidToString (&Cert->SignatureOwner, GuidStr, 100); GuidID = HiiSetString (Private->RegisteredHandle, 0, GuidStr, NULL); HiiCreateCheckBoxOpCode ( StartOpCodeHandle, (EFI_QUESTION_ID) (QuestionIdBase + GuidIndex++), 0, 0, GuidID, Help, EFI_IFR_FLAG_CALLBACK, 0, NULL ); } ItemDataSize -= CertList->SignatureListSize; CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); } ON_EXIT: HiiUpdateForm ( Private->RegisteredHandle, &gTlsAuthConfigGuid, FormId, StartOpCodeHandle, EndOpCodeHandle ); if (StartOpCodeHandle != NULL) { HiiFreeOpCodeHandle (StartOpCodeHandle); } if (EndOpCodeHandle != NULL) { HiiFreeOpCodeHandle (EndOpCodeHandle); } if (Data != NULL) { FreePool (Data); } if (GuidStr != NULL) { FreePool (GuidStr); } return EFI_SUCCESS; } /** Delete one entry from cert database. @param[in] Private Module's private data. @param[in] VariableName The variable name of the database. @param[in] VendorGuid A unique identifier for the vendor. @param[in] LabelNumber Label number to insert opcodes. @param[in] FormId Form ID of current page. @param[in] QuestionIdBase Base question id of the cert list. @param[in] DeleteIndex Cert index to delete. @retval EFI_SUCCESS Delete signature successfully. @retval EFI_NOT_FOUND Can't find the signature item, @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources. **/ EFI_STATUS DeleteCert ( IN TLS_AUTH_CONFIG_PRIVATE_DATA *Private, IN CHAR16 *VariableName, IN EFI_GUID *VendorGuid, IN UINT16 LabelNumber, IN EFI_FORM_ID FormId, IN EFI_QUESTION_ID QuestionIdBase, IN UINTN DeleteIndex ) { EFI_STATUS Status; UINTN DataSize; UINT8 *Data; UINT8 *OldData; UINT32 Attr; UINT32 Index; EFI_SIGNATURE_LIST *CertList; EFI_SIGNATURE_LIST *NewCertList; EFI_SIGNATURE_DATA *Cert; UINTN CertCount; UINT32 Offset; BOOLEAN IsItemFound; UINT32 ItemDataSize; UINTN GuidIndex; Data = NULL; OldData = NULL; CertList = NULL; Cert = NULL; Attr = 0; // // Get original signature list data. // DataSize = 0; Status = gRT->GetVariable (VariableName, VendorGuid, NULL, &DataSize, NULL); if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) { goto ON_EXIT; } OldData = (UINT8 *) AllocateZeroPool (DataSize); if (OldData == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; } Status = gRT->GetVariable (VariableName, VendorGuid, &Attr, &DataSize, OldData); if (EFI_ERROR(Status)) { goto ON_EXIT; } // // Allocate space for new variable. // Data = (UINT8*) AllocateZeroPool (DataSize); if (Data == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; } // // Enumerate all data and erasing the target item. // IsItemFound = FALSE; ItemDataSize = (UINT32) DataSize; CertList = (EFI_SIGNATURE_LIST *) OldData; Offset = 0; GuidIndex = 0; while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) { if (CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) { // // Copy EFI_SIGNATURE_LIST header then calculate the signature count in this list. // CopyMem (Data + Offset, CertList, (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize)); NewCertList = (EFI_SIGNATURE_LIST*) (Data + Offset); Offset += (sizeof(EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize); CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; for (Index = 0; Index < CertCount; Index++) { if (GuidIndex == DeleteIndex) { // // Find it! Skip it! // NewCertList->SignatureListSize -= CertList->SignatureSize; IsItemFound = TRUE; } else { // // This item doesn't match. Copy it to the Data buffer. // CopyMem (Data + Offset, (UINT8*)(Cert), CertList->SignatureSize); Offset += CertList->SignatureSize; } GuidIndex++; Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize); } } else { // // This List doesn't match. Just copy it to the Data buffer. // CopyMem (Data + Offset, (UINT8*)(CertList), CertList->SignatureListSize); Offset += CertList->SignatureListSize; } ItemDataSize -= CertList->SignatureListSize; CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); } if (!IsItemFound) { // // Doesn't find the signature Item! // Status = EFI_NOT_FOUND; goto ON_EXIT; } // // Delete the EFI_SIGNATURE_LIST header if there is no signature in the list. // ItemDataSize = Offset; CertList = (EFI_SIGNATURE_LIST *) Data; Offset = 0; ZeroMem (OldData, ItemDataSize); while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) { CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize; DEBUG ((DEBUG_INFO, " CertCount = %x\n", CertCount)); if (CertCount != 0) { CopyMem (OldData + Offset, (UINT8*)(CertList), CertList->SignatureListSize); Offset += CertList->SignatureListSize; } ItemDataSize -= CertList->SignatureListSize; CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); } DataSize = Offset; Status = gRT->SetVariable( VariableName, VendorGuid, Attr, DataSize, OldData ); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Failed to set variable, Status = %r\n", Status)); goto ON_EXIT; } ON_EXIT: if (Data != NULL) { FreePool(Data); } if (OldData != NULL) { FreePool(OldData); } return UpdateDeletePage ( Private, VariableName, VendorGuid, LabelNumber, FormId, QuestionIdBase ); } /** Clean the file related resource. @param[in] Private Module's private data. **/ VOID CleanFileContext ( IN TLS_AUTH_CONFIG_PRIVATE_DATA *Private ) { if (Private->FileContext->FHandle != NULL) { Private->FileContext->FHandle->Close (Private->FileContext->FHandle); Private->FileContext->FHandle = NULL; if (Private->FileContext->FileName!= NULL){ FreePool(Private->FileContext->FileName); Private->FileContext->FileName = NULL; } } } /** Read file content into BufferPtr, the size of the allocate buffer is *FileSize plus AddtionAllocateSize. @param[in] FileHandle The file to be read. @param[in, out] BufferPtr Pointers to the pointer of allocated buffer. @param[out] FileSize Size of input file @param[in] AddtionAllocateSize Addtion size the buffer need to be allocated. In case the buffer need to contain others besides the file content. @retval EFI_SUCCESS The file was read into the buffer. @retval EFI_INVALID_PARAMETER A parameter was invalid. @retval EFI_OUT_OF_RESOURCES A memory allocation failed. @retval others Unexpected error. **/ EFI_STATUS ReadFileContent ( IN EFI_FILE_HANDLE FileHandle, IN OUT VOID **BufferPtr, OUT UINTN *FileSize, IN UINTN AddtionAllocateSize ) { UINTN BufferSize; UINT64 SourceFileSize; VOID *Buffer; EFI_STATUS Status; if ((FileHandle == NULL) || (FileSize == NULL)) { return EFI_INVALID_PARAMETER; } Buffer = NULL; // // Get the file size // Status = FileHandle->SetPosition (FileHandle, (UINT64) -1); if (EFI_ERROR (Status)) { goto ON_EXIT; } Status = FileHandle->GetPosition (FileHandle, &SourceFileSize); if (EFI_ERROR (Status)) { goto ON_EXIT; } Status = FileHandle->SetPosition (FileHandle, 0); if (EFI_ERROR (Status)) { goto ON_EXIT; } BufferSize = (UINTN) SourceFileSize + AddtionAllocateSize; Buffer = AllocateZeroPool(BufferSize); if (Buffer == NULL) { return EFI_OUT_OF_RESOURCES; } BufferSize = (UINTN) SourceFileSize; *FileSize = BufferSize; Status = FileHandle->Read (FileHandle, &BufferSize, Buffer); if (EFI_ERROR (Status) || BufferSize != *FileSize) { FreePool (Buffer); Buffer = NULL; Status = EFI_BAD_BUFFER_SIZE; goto ON_EXIT; } ON_EXIT: *BufferPtr = Buffer; return Status; } /** This function converts an input device structure to a Unicode string. @param[in] DevPath A pointer to the device path structure. @return A new allocated Unicode string that represents the device path. **/ CHAR16 * EFIAPI DevicePathToStr ( IN EFI_DEVICE_PATH_PROTOCOL *DevPath ) { return ConvertDevicePathToText ( DevPath, FALSE, TRUE ); } /** Extract filename from device path. The returned buffer is allocated using AllocateCopyPool. The caller is responsible for freeing the allocated buffer using FreePool(). If return NULL means not enough memory resource. @param DevicePath Device path. @retval NULL Not enough memory resource for AllocateCopyPool. @retval Other A new allocated string that represents the file name. **/ CHAR16 * ExtractFileNameFromDevicePath ( IN EFI_DEVICE_PATH_PROTOCOL *DevicePath ) { CHAR16 *String; CHAR16 *MatchString; CHAR16 *LastMatch; CHAR16 *FileName; UINTN Length; ASSERT(DevicePath != NULL); String = DevicePathToStr(DevicePath); MatchString = String; LastMatch = String; FileName = NULL; while(MatchString != NULL){ LastMatch = MatchString + 1; MatchString = StrStr(LastMatch,L"\\"); } Length = StrLen(LastMatch); FileName = AllocateCopyPool ((Length + 1) * sizeof(CHAR16), LastMatch); if (FileName != NULL) { *(FileName + Length) = 0; } FreePool(String); return FileName; } /** Enroll a new X509 certificate into Variable. @param[in] PrivateData The module's private data. @param[in] VariableName Variable name of CA database. @retval EFI_SUCCESS New X509 is enrolled successfully. @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources. **/ EFI_STATUS EnrollX509toVariable ( IN TLS_AUTH_CONFIG_PRIVATE_DATA *Private, IN CHAR16 *VariableName ) { EFI_STATUS Status; UINTN X509DataSize; VOID *X509Data; EFI_SIGNATURE_LIST *CACert; EFI_SIGNATURE_DATA *CACertData; VOID *Data; UINTN DataSize; UINTN SigDataSize; UINT32 Attr; X509DataSize = 0; SigDataSize = 0; DataSize = 0; X509Data = NULL; CACert = NULL; CACertData = NULL; Data = NULL; Attr = 0; Status = ReadFileContent ( Private->FileContext->FHandle, &X509Data, &X509DataSize, 0 ); if (EFI_ERROR (Status)) { goto ON_EXIT; } ASSERT (X509Data != NULL); SigDataSize = sizeof(EFI_SIGNATURE_LIST) + sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize; Data = AllocateZeroPool (SigDataSize); if (Data == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; } // // Fill Certificate Database parameters. // CACert = (EFI_SIGNATURE_LIST*) Data; CACert->SignatureListSize = (UINT32) SigDataSize; CACert->SignatureHeaderSize = 0; CACert->SignatureSize = (UINT32) (sizeof(EFI_SIGNATURE_DATA) - 1 + X509DataSize); CopyGuid (&CACert->SignatureType, &gEfiCertX509Guid); CACertData = (EFI_SIGNATURE_DATA*) ((UINT8* ) CACert + sizeof (EFI_SIGNATURE_LIST)); CopyGuid (&CACertData->SignatureOwner, Private->CertGuid); CopyMem ((UINT8* ) (CACertData->SignatureData), X509Data, X509DataSize); // // Check if the signature database entry already exists. If it does, use the // EFI_VARIABLE_APPEND_WRITE attribute to append the new signature data to // the original variable, plus preserve the original variable attributes. // Status = gRT->GetVariable( VariableName, &gEfiTlsCaCertificateGuid, &Attr, &DataSize, NULL ); if (Status == EFI_BUFFER_TOO_SMALL) { Attr |= EFI_VARIABLE_APPEND_WRITE; } else if (Status == EFI_NOT_FOUND) { Attr = TLS_AUTH_CONFIG_VAR_BASE_ATTR; } else { goto ON_EXIT; } Status = gRT->SetVariable( VariableName, &gEfiTlsCaCertificateGuid, Attr, SigDataSize, Data ); if (EFI_ERROR (Status)) { goto ON_EXIT; } ON_EXIT: CleanFileContext (Private); if (Private->CertGuid != NULL) { FreePool (Private->CertGuid); Private->CertGuid = NULL; } if (Data != NULL) { FreePool (Data); } if (X509Data != NULL) { FreePool (X509Data); } return Status; } /** Enroll Cert into TlsCaCertificate. The GUID will be Private->CertGuid. @param[in] PrivateData The module's private data. @param[in] VariableName Variable name of signature database. @retval EFI_SUCCESS New Cert enrolled successfully. @retval EFI_INVALID_PARAMETER The parameter is invalid. @retval EFI_UNSUPPORTED The Cert file is unsupported type. @retval others Fail to enroll Cert data. **/ EFI_STATUS EnrollCertDatabase ( IN TLS_AUTH_CONFIG_PRIVATE_DATA *Private, IN CHAR16 *VariableName ) { UINT16* FilePostFix; UINTN NameLength; if ((Private->FileContext->FileName == NULL) || (Private->FileContext->FHandle == NULL) || (Private->CertGuid == NULL)) { return EFI_INVALID_PARAMETER; } // // Parse the file's postfix. // NameLength = StrLen (Private->FileContext->FileName); if (NameLength <= 4) { return EFI_INVALID_PARAMETER; } FilePostFix = Private->FileContext->FileName + NameLength - 4; if (IsDerPemEncodeCertificate (FilePostFix)) { // // Supports DER-encoded X509 certificate. // return EnrollX509toVariable (Private, VariableName); } return EFI_UNSUPPORTED; } /** Refresh the global UpdateData structure. **/ VOID RefreshUpdateData ( VOID ) { // // Free current updated date // if (mStartOpCodeHandle != NULL) { HiiFreeOpCodeHandle (mStartOpCodeHandle); } // // Create new OpCode Handle // mStartOpCodeHandle = HiiAllocateOpCodeHandle (); // // Create Hii Extend Label OpCode as the start opcode // mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( mStartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL) ); mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; } /** Clean up the dynamic opcode at label and form specified by both LabelId. @param[in] LabelId It is both the Form ID and Label ID for opcode deletion. @param[in] PrivateData Module private data. **/ VOID CleanUpPage ( IN UINT16 LabelId, IN TLS_AUTH_CONFIG_PRIVATE_DATA *PrivateData ) { RefreshUpdateData (); // // Remove all op-codes from dynamic page // mStartLabel->Number = LabelId; HiiUpdateForm ( PrivateData->RegisteredHandle, &gTlsAuthConfigGuid, LabelId, mStartOpCodeHandle, // Label LabelId mEndOpCodeHandle // LABEL_END ); } /** Update the form base on the selected file. @param FilePath Point to the file path. @param FormId The form need to display. @retval TRUE Exit caller function. @retval FALSE Not exit caller function. **/ BOOLEAN UpdatePage( IN EFI_DEVICE_PATH_PROTOCOL *FilePath, IN EFI_FORM_ID FormId ) { CHAR16 *FileName; EFI_STRING_ID StringToken; FileName = NULL; if (FilePath != NULL) { FileName = ExtractFileNameFromDevicePath(FilePath); } if (FileName == NULL) { // // FileName = NULL has two case: // 1. FilePath == NULL, not select file. // 2. FilePath != NULL, but ExtractFileNameFromDevicePath return NULL not enough memory resource. // In these two case, no need to update the form, and exit the caller function. // return TRUE; } StringToken = HiiSetString (mTlsAuthPrivateData->RegisteredHandle, 0, FileName, NULL); mTlsAuthPrivateData->FileContext->FileName = FileName; EfiOpenFileByDevicePath ( &FilePath, &mTlsAuthPrivateData->FileContext->FHandle, EFI_FILE_MODE_READ, 0 ); // // Create Subtitle op-code for the display string of the option. // RefreshUpdateData (); mStartLabel->Number = FormId; HiiCreateSubTitleOpCode ( mStartOpCodeHandle, StringToken, 0, 0, 0 ); HiiUpdateForm ( mTlsAuthPrivateData->RegisteredHandle, &gTlsAuthConfigGuid, FormId, mStartOpCodeHandle, /// Label FormId mEndOpCodeHandle /// LABEL_END ); return TRUE; } /** Update the form base on the input file path info. @param FilePath Point to the file path. @retval TRUE Exit caller function. @retval FALSE Not exit caller function. **/ BOOLEAN EFIAPI UpdateCAFromFile ( IN EFI_DEVICE_PATH_PROTOCOL *FilePath ) { return UpdatePage(FilePath, TLS_AUTH_CONFIG_FORMID4_FORM); } /** Unload the configuration form, this includes: delete all the configuration entries, uninstall the form callback protocol, and free the resources used. @param[in] Private Pointer to the driver private data. @retval EFI_SUCCESS The configuration form is unloaded. @retval Others Failed to unload the form. **/ EFI_STATUS TlsAuthConfigFormUnload ( IN TLS_AUTH_CONFIG_PRIVATE_DATA *Private ) { if (Private->DriverHandle != NULL) { // // Uninstall EFI_HII_CONFIG_ACCESS_PROTOCOL // gBS->UninstallMultipleProtocolInterfaces ( Private->DriverHandle, &gEfiDevicePathProtocolGuid, &mTlsAuthConfigHiiVendorDevicePath, &gEfiHiiConfigAccessProtocolGuid, &Private->ConfigAccess, NULL ); Private->DriverHandle = NULL; } if (Private->RegisteredHandle != NULL) { // // Remove HII package list // HiiRemovePackages (Private->RegisteredHandle); Private->RegisteredHandle = NULL; } if (Private->CertGuid != NULL) { FreePool (Private->CertGuid); } if (Private->FileContext != NULL) { FreePool (Private->FileContext); } FreePool (Private); if (mStartOpCodeHandle != NULL) { HiiFreeOpCodeHandle (mStartOpCodeHandle); } if (mEndOpCodeHandle != NULL) { HiiFreeOpCodeHandle (mEndOpCodeHandle); } return EFI_SUCCESS; } /** Initialize the configuration form. @param[in] Private Pointer to the driver private data. @retval EFI_SUCCESS The configuration form is initialized. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. **/ EFI_STATUS TlsAuthConfigFormInit ( IN TLS_AUTH_CONFIG_PRIVATE_DATA *Private ) { EFI_STATUS Status; Private->Signature = TLS_AUTH_CONFIG_PRIVATE_DATA_SIGNATURE; Private->ConfigAccess.ExtractConfig = TlsAuthConfigAccessExtractConfig; Private->ConfigAccess.RouteConfig = TlsAuthConfigAccessRouteConfig; Private->ConfigAccess.Callback = TlsAuthConfigAccessCallback; // // Install Device Path Protocol and Config Access protocol to driver handle. // Status = gBS->InstallMultipleProtocolInterfaces ( &Private->DriverHandle, &gEfiDevicePathProtocolGuid, &mTlsAuthConfigHiiVendorDevicePath, &gEfiHiiConfigAccessProtocolGuid, &Private->ConfigAccess, NULL ); if (EFI_ERROR (Status)) { return Status; } // // Publish our HII data. // Private->RegisteredHandle = HiiAddPackages ( &gTlsAuthConfigGuid, Private->DriverHandle, TlsAuthConfigDxeStrings, TlsAuthConfigVfrBin, NULL ); if (Private->RegisteredHandle == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } Private->FileContext = AllocateZeroPool (sizeof (TLS_AUTH_CONFIG_FILE_CONTEXT)); if (Private->FileContext == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } // // Init OpCode Handle and Allocate space for creation of Buffer // mStartOpCodeHandle = HiiAllocateOpCodeHandle (); if (mStartOpCodeHandle == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } mEndOpCodeHandle = HiiAllocateOpCodeHandle (); if (mEndOpCodeHandle == NULL) { Status = EFI_OUT_OF_RESOURCES; goto Error; } // // Create Hii Extend Label OpCode as the start opcode // mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( mStartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL) ); mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; // // Create Hii Extend Label OpCode as the end opcode // mEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode ( mEndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL) ); mEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL; mEndLabel->Number = LABEL_END; return EFI_SUCCESS; Error: TlsAuthConfigFormUnload (Private); return Status; } /** This function allows the caller to request the current configuration for one or more named elements. The resulting string is in format. Any and all alternative configuration strings shall also be appended to the end of the current configuration string. If they are, they must appear after the current configuration. They must contain the same routing (GUID, NAME, PATH) as the current configuration string. They must have an additional description indicating the type of alternative configuration the string represents, "ALTCFG=". That (when converted from Hex UNICODE to binary) is a reference to a string in the associated string pack. @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param Request A null-terminated Unicode string in format. Note that this includes the routing information as well as the configurable name / value pairs. It is invalid for this string to be in format. If a NULL is passed in for the Request field, all of the settings being abstracted by this function will be returned in the Results field. In addition, if a ConfigHdr is passed in with no request elements, all of the settings being abstracted for that particular ConfigHdr reference will be returned in the Results Field. @param Progress On return, points to a character in the Request string. Points to the string's null terminator if request was successful. Points to the most recent "&" before the first failing name / value pair (or the beginning of the string if the failure is in the first name / value pair) if the request was not successful. @param Results A null-terminated Unicode string in format which has all values filled in for the names in the Request string. String to be allocated by the called function. @retval EFI_SUCCESS The Results string is filled with the values corresponding to all requested names. @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the results that must be stored awaiting possible future protocols. @retval EFI_NOT_FOUND Routing data doesn't match any known driver. Progress set to the first character in the routing header. Note: There is no requirement that the driver validate the routing data. It must skip the in order to process the names. @retval EFI_INVALID_PARAMETER Illegal syntax. Progress set to most recent "&" before the error or the beginning of the string. @retval EFI_INVALID_PARAMETER Unknown name. Progress points to the & before the name in question. **/ EFI_STATUS EFIAPI TlsAuthConfigAccessExtractConfig ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN CONST EFI_STRING Request, OUT EFI_STRING *Progress, OUT EFI_STRING *Results ) { EFI_STATUS Status; UINTN BufferSize; UINTN Size; EFI_STRING ConfigRequest; EFI_STRING ConfigRequestHdr; TLS_AUTH_CONFIG_PRIVATE_DATA *Private; BOOLEAN AllocatedRequest; if (Progress == NULL || Results == NULL) { return EFI_INVALID_PARAMETER; } AllocatedRequest = FALSE; ConfigRequestHdr = NULL; ConfigRequest = NULL; Size = 0; Private = TLS_AUTH_CONFIG_PRIVATE_FROM_THIS (This); BufferSize = sizeof (TLS_AUTH_CONFIG_IFR_NVDATA); ZeroMem (&Private->TlsAuthConfigNvData, BufferSize); *Progress = Request; if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gTlsAuthConfigGuid, mTlsAuthConfigStorageName)) { return EFI_NOT_FOUND; } ConfigRequest = Request; if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) { // // Request is set to NULL or OFFSET is NULL, construct full request string. // // Allocate and fill a buffer large enough to hold the template // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator // ConfigRequestHdr = HiiConstructConfigHdr (&gTlsAuthConfigGuid, mTlsAuthConfigStorageName, Private->DriverHandle); Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16); ConfigRequest = AllocateZeroPool (Size); ASSERT (ConfigRequest != NULL); AllocatedRequest = TRUE; UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize); FreePool (ConfigRequestHdr); ConfigRequestHdr = NULL; } Status = gHiiConfigRouting->BlockToConfig ( gHiiConfigRouting, ConfigRequest, (UINT8 *) &Private->TlsAuthConfigNvData, BufferSize, Results, Progress ); // // Free the allocated config request string. // if (AllocatedRequest) { FreePool (ConfigRequest); } // // Set Progress string to the original request string. // if (Request == NULL) { *Progress = NULL; } else if (StrStr (Request, L"OFFSET") == NULL) { *Progress = Request + StrLen (Request); } return Status; } /** This function applies changes in a driver's configuration. Input is a Configuration, which has the routing data for this driver followed by name / value configuration pairs. The driver must apply those pairs to its configurable storage. If the driver's configuration is stored in a linear block of data and the driver's name / value pairs are in format, it may use the ConfigToBlock helper function (above) to simplify the job. @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param Configuration A null-terminated Unicode string in format. @param Progress A pointer to a string filled in with the offset of the most recent '&' before the first failing name / value pair (or the beginning of the string if the failure is in the first name / value pair) or the terminating NULL if all was successful. @retval EFI_SUCCESS The results have been distributed or are awaiting distribution. @retval EFI_OUT_OF_RESOURCES Not enough memory to store the parts of the results that must be stored awaiting possible future protocols. @retval EFI_INVALID_PARAMETERS Passing in a NULL for the Results parameter would result in this type of error. @retval EFI_NOT_FOUND Target for the specified routing data was not found **/ EFI_STATUS EFIAPI TlsAuthConfigAccessRouteConfig ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN CONST EFI_STRING Configuration, OUT EFI_STRING *Progress ) { EFI_STATUS Status; UINTN BufferSize; TLS_AUTH_CONFIG_PRIVATE_DATA *Private; if (Progress == NULL) { return EFI_INVALID_PARAMETER; } *Progress = Configuration; if (Configuration == NULL) { return EFI_INVALID_PARAMETER; } // // Check routing data in . // Note: there is no name for Name/Value storage, only GUID will be checked // if (!HiiIsConfigHdrMatch (Configuration, &gTlsAuthConfigGuid, mTlsAuthConfigStorageName)) { return EFI_NOT_FOUND; } Private = TLS_AUTH_CONFIG_PRIVATE_FROM_THIS (This); BufferSize = sizeof (TLS_AUTH_CONFIG_IFR_NVDATA); ZeroMem (&Private->TlsAuthConfigNvData, BufferSize); Status = gHiiConfigRouting->ConfigToBlock ( gHiiConfigRouting, Configuration, (UINT8 *) &Private->TlsAuthConfigNvData, &BufferSize, Progress ); if (EFI_ERROR (Status)) { return Status; } return Status; } /** This function is called to provide results data to the driver. This data consists of a unique key that is used to identify which data is either being passed back or being asked for. @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL. @param Action Specifies the type of action taken by the browser. @param QuestionId A unique value which is sent to the original exporting driver so that it can identify the type of data to expect. The format of the data tends to vary based on the opcode that generated the callback. @param Type The type of value for the question. @param Value A pointer to the data being sent to the original exporting driver. @param ActionRequest On return, points to the action requested by the callback function. @retval EFI_SUCCESS The callback successfully handled the action. @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data. @retval EFI_DEVICE_ERROR The variable could not be saved. @retval EFI_UNSUPPORTED The specified Action is not supported by the callback. **/ EFI_STATUS EFIAPI TlsAuthConfigAccessCallback ( IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This, IN EFI_BROWSER_ACTION Action, IN EFI_QUESTION_ID QuestionId, IN UINT8 Type, IN OUT EFI_IFR_TYPE_VALUE *Value, OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest ) { EFI_STATUS Status; RETURN_STATUS RStatus; TLS_AUTH_CONFIG_PRIVATE_DATA *Private; UINTN BufferSize; TLS_AUTH_CONFIG_IFR_NVDATA *IfrNvData; UINT16 LabelId; EFI_DEVICE_PATH_PROTOCOL *File; EFI_HII_POPUP_PROTOCOL *HiiPopUp; EFI_HII_POPUP_SELECTION PopUpSelect; Status = EFI_SUCCESS; File = NULL; if ((This == NULL) || (Value == NULL) || (ActionRequest == NULL)) { return EFI_INVALID_PARAMETER; } Private = TLS_AUTH_CONFIG_PRIVATE_FROM_THIS (This); mTlsAuthPrivateData = Private; Status = gBS->LocateProtocol (&gEfiHiiPopupProtocolGuid, NULL, (VOID**) &HiiPopUp); if (EFI_ERROR (Status)) { DEBUG ((DEBUG_ERROR, "Can't find Form PopUp protocol. Exit (%r)\n", Status)); return Status; } // // Retrieve uncommitted data from Browser // BufferSize = sizeof (TLS_AUTH_CONFIG_IFR_NVDATA); IfrNvData = AllocateZeroPool (BufferSize); if (IfrNvData == NULL) { return EFI_OUT_OF_RESOURCES; } HiiGetBrowserData (&gTlsAuthConfigGuid, mTlsAuthConfigStorageName, BufferSize, (UINT8 *) IfrNvData); if ((Action != EFI_BROWSER_ACTION_CHANGED) && (Action != EFI_BROWSER_ACTION_CHANGING) && (Action != EFI_BROWSER_ACTION_FORM_CLOSE)) { Status = EFI_UNSUPPORTED; goto EXIT; } if (Action == EFI_BROWSER_ACTION_CHANGING) { switch (QuestionId) { case KEY_TLS_AUTH_CONFIG_CLIENT_CERT: case KEY_TLS_AUTH_CONFIG_SERVER_CA: // // Clear Cert GUID. // ZeroMem (IfrNvData->CertGuid, sizeof (IfrNvData->CertGuid)); if (Private->CertGuid == NULL) { Private->CertGuid = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID)); if (Private->CertGuid == NULL) { return EFI_OUT_OF_RESOURCES; } } if (QuestionId == KEY_TLS_AUTH_CONFIG_CLIENT_CERT) { LabelId = TLS_AUTH_CONFIG_FORMID3_FORM; } else { LabelId = TLS_AUTH_CONFIG_FORMID4_FORM; } // // Refresh selected file. // CleanUpPage (LabelId, Private); break; case KEY_TLS_AUTH_CONFIG_ENROLL_CERT_FROM_FILE: // // If the file is already opened, clean the file related resource first. // CleanFileContext (Private); ChooseFile( NULL, NULL, UpdateCAFromFile, &File); break; case KEY_TLS_AUTH_CONFIG_VALUE_SAVE_AND_EXIT: Status = EnrollCertDatabase (Private, EFI_TLS_CA_CERTIFICATE_VARIABLE); if (EFI_ERROR (Status)) { CleanFileContext (Private); HiiPopUp->CreatePopup ( HiiPopUp, EfiHiiPopupStyleError, EfiHiiPopupTypeOk, Private->RegisteredHandle, STRING_TOKEN (STR_TLS_AUTH_ENROLL_CERT_FAILURE), &PopUpSelect ); } break; case KEY_TLS_AUTH_CONFIG_VALUE_NO_SAVE_AND_EXIT: CleanFileContext (Private); if (Private->CertGuid!= NULL) { FreePool (Private->CertGuid); Private->CertGuid = NULL; } break; case KEY_TLS_AUTH_CONFIG_DELETE_CERT: UpdateDeletePage ( Private, EFI_TLS_CA_CERTIFICATE_VARIABLE, &gEfiTlsCaCertificateGuid, LABEL_CA_DELETE, TLS_AUTH_CONFIG_FORMID5_FORM, OPTION_DEL_CA_ESTION_ID ); break; default: if ((QuestionId >= OPTION_DEL_CA_ESTION_ID) && (QuestionId < (OPTION_DEL_CA_ESTION_ID + OPTION_CONFIG_RANGE))) { DeleteCert ( Private, EFI_TLS_CA_CERTIFICATE_VARIABLE, &gEfiTlsCaCertificateGuid, LABEL_CA_DELETE, TLS_AUTH_CONFIG_FORMID5_FORM, OPTION_DEL_CA_ESTION_ID, QuestionId - OPTION_DEL_CA_ESTION_ID ); } break; } } else if (Action == EFI_BROWSER_ACTION_CHANGED) { switch (QuestionId) { case KEY_TLS_AUTH_CONFIG_CERT_GUID: ASSERT (Private->CertGuid != NULL); RStatus = StrToGuid ( IfrNvData->CertGuid, Private->CertGuid ); if (RETURN_ERROR (RStatus) || (IfrNvData->CertGuid[GUID_STRING_LENGTH] != L'\0')) { Status = EFI_INVALID_PARAMETER; break; } *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_APPLY; break; default: break; } } else if (Action == EFI_BROWSER_ACTION_FORM_CLOSE) { CleanFileContext (Private); } EXIT: if (!EFI_ERROR (Status)) { BufferSize = sizeof (TLS_AUTH_CONFIG_IFR_NVDATA); HiiSetBrowserData (&gTlsAuthConfigGuid, mTlsAuthConfigStorageName, BufferSize, (UINT8*) IfrNvData, NULL); } FreePool (IfrNvData); if (File != NULL){ FreePool(File); File = NULL; } return EFI_SUCCESS; }