/** @file | |
The Driver Binding and Service Binding Protocol for TlsDxe driver. | |
Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> | |
SPDX-License-Identifier: BSD-2-Clause-Patent | |
**/ | |
#include "TlsImpl.h" | |
EFI_SERVICE_BINDING_PROTOCOL mTlsServiceBinding = { | |
TlsServiceBindingCreateChild, | |
TlsServiceBindingDestroyChild | |
}; | |
/** | |
Release all the resources used by the TLS instance. | |
@param[in] Instance The TLS instance data. | |
**/ | |
VOID | |
TlsCleanInstance ( | |
IN TLS_INSTANCE *Instance | |
) | |
{ | |
if (Instance != NULL) { | |
if (Instance->TlsConn != NULL) { | |
TlsFree (Instance->TlsConn); | |
} | |
FreePool (Instance); | |
} | |
} | |
/** | |
Create the TLS instance and initialize it. | |
@param[in] Service The pointer to the TLS service. | |
@param[out] Instance The pointer to the TLS instance. | |
@retval EFI_OUT_OF_RESOURCES Failed to allocate resources. | |
@retval EFI_SUCCESS The TLS instance is created. | |
**/ | |
EFI_STATUS | |
TlsCreateInstance ( | |
IN TLS_SERVICE *Service, | |
OUT TLS_INSTANCE **Instance | |
) | |
{ | |
TLS_INSTANCE *TlsInstance; | |
*Instance = NULL; | |
TlsInstance = AllocateZeroPool (sizeof (TLS_INSTANCE)); | |
if (TlsInstance == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
TlsInstance->Signature = TLS_INSTANCE_SIGNATURE; | |
InitializeListHead (&TlsInstance->Link); | |
TlsInstance->InDestroy = FALSE; | |
TlsInstance->Service = Service; | |
CopyMem (&TlsInstance->Tls, &mTlsProtocol, sizeof (TlsInstance->Tls)); | |
CopyMem (&TlsInstance->TlsConfig, &mTlsConfigurationProtocol, sizeof (TlsInstance->TlsConfig)); | |
TlsInstance->TlsSessionState = EfiTlsSessionNotStarted; | |
*Instance = TlsInstance; | |
return EFI_SUCCESS; | |
} | |
/** | |
Release all the resources used by the TLS service binding instance. | |
@param[in] Service The TLS service data. | |
**/ | |
VOID | |
TlsCleanService ( | |
IN TLS_SERVICE *Service | |
) | |
{ | |
if (Service != NULL) { | |
if (Service->TlsCtx != NULL) { | |
TlsCtxFree (Service->TlsCtx); | |
} | |
FreePool (Service); | |
} | |
} | |
/** | |
Create then initialize a TLS service. | |
@param[in] Image ImageHandle of the TLS driver | |
@param[out] Service The service for TLS driver | |
@retval EFI_OUT_OF_RESOURCES Failed to allocate resource to create the service. | |
@retval EFI_SUCCESS The service is created for the driver. | |
**/ | |
EFI_STATUS | |
TlsCreateService ( | |
IN EFI_HANDLE Image, | |
OUT TLS_SERVICE **Service | |
) | |
{ | |
TLS_SERVICE *TlsService; | |
ASSERT (Service != NULL); | |
*Service = NULL; | |
// | |
// Allocate a TLS Service Data | |
// | |
TlsService = AllocateZeroPool (sizeof (TLS_SERVICE)); | |
if (TlsService == NULL) { | |
return EFI_OUT_OF_RESOURCES; | |
} | |
// | |
// Initialize TLS Service Data | |
// | |
TlsService->Signature = TLS_SERVICE_SIGNATURE; | |
CopyMem (&TlsService->ServiceBinding, &mTlsServiceBinding, sizeof (TlsService->ServiceBinding)); | |
TlsService->TlsChildrenNum = 0; | |
InitializeListHead (&TlsService->TlsChildrenList); | |
TlsService->ImageHandle = Image; | |
*Service = TlsService; | |
return EFI_SUCCESS; | |
} | |
/** | |
Unloads an image. | |
@param[in] ImageHandle Handle that identifies the image to be unloaded. | |
@retval EFI_SUCCESS The image has been unloaded. | |
@retval EFI_INVALID_PARAMETER ImageHandle is not a valid image handle. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
TlsUnload ( | |
IN EFI_HANDLE ImageHandle | |
) | |
{ | |
EFI_STATUS Status; | |
UINTN HandleNum; | |
EFI_HANDLE *HandleBuffer; | |
UINT32 Index; | |
EFI_SERVICE_BINDING_PROTOCOL *ServiceBinding; | |
TLS_SERVICE *TlsService; | |
HandleBuffer = NULL; | |
ServiceBinding = NULL; | |
TlsService = NULL; | |
// | |
// Locate all the handles with Tls service binding protocol. | |
// | |
Status = gBS->LocateHandleBuffer ( | |
ByProtocol, | |
&gEfiTlsServiceBindingProtocolGuid, | |
NULL, | |
&HandleNum, | |
&HandleBuffer | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
for (Index = 0; Index < HandleNum; Index++) { | |
// | |
// Firstly, find ServiceBinding interface | |
// | |
Status = gBS->OpenProtocol ( | |
HandleBuffer[Index], | |
&gEfiTlsServiceBindingProtocolGuid, | |
(VOID **)&ServiceBinding, | |
ImageHandle, | |
NULL, | |
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
TlsService = TLS_SERVICE_FROM_THIS (ServiceBinding); | |
// | |
// Then, uninstall ServiceBinding interface | |
// | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
HandleBuffer[Index], | |
&gEfiTlsServiceBindingProtocolGuid, | |
ServiceBinding, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
TlsCleanService (TlsService); | |
} | |
if (HandleBuffer != NULL) { | |
FreePool (HandleBuffer); | |
} | |
return EFI_SUCCESS; | |
} | |
/** | |
This is the declaration of an EFI image entry point. This entry point is | |
the same for UEFI Applications, UEFI OS Loaders, and UEFI Drivers including | |
both device drivers and bus drivers. | |
@param ImageHandle The firmware allocated handle for the UEFI image. | |
@param SystemTable A pointer to the EFI System Table. | |
@retval EFI_SUCCESS The operation completed successfully. | |
@retval Others An unexpected error occurred. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
TlsDriverEntryPoint ( | |
IN EFI_HANDLE ImageHandle, | |
IN EFI_SYSTEM_TABLE *SystemTable | |
) | |
{ | |
EFI_STATUS Status; | |
TLS_SERVICE *TlsService; | |
// | |
// Create TLS Service | |
// | |
Status = TlsCreateService (ImageHandle, &TlsService); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
ASSERT (TlsService != NULL); | |
// | |
// Initializes the OpenSSL library. | |
// | |
TlsInitialize (); | |
// | |
// Create a new SSL_CTX object as framework to establish TLS/SSL enabled | |
// connections. TLS 1.0 is used as the default version. | |
// | |
TlsService->TlsCtx = TlsCtxNew (TLS10_PROTOCOL_VERSION_MAJOR, TLS10_PROTOCOL_VERSION_MINOR); | |
if (TlsService->TlsCtx == NULL) { | |
FreePool (TlsService); | |
return EFI_ABORTED; | |
} | |
// | |
// Install the TlsServiceBinding Protocol onto Handle | |
// | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
&TlsService->Handle, | |
&gEfiTlsServiceBindingProtocolGuid, | |
&TlsService->ServiceBinding, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
goto ON_CLEAN_SERVICE; | |
} | |
return Status; | |
ON_CLEAN_SERVICE: | |
TlsCleanService (TlsService); | |
return Status; | |
} | |
/** | |
Creates a child handle and installs a protocol. | |
The CreateChild() function installs a protocol on ChildHandle. | |
If ChildHandle is a pointer to NULL, then a new handle is created and returned in ChildHandle. | |
If ChildHandle is not a pointer to NULL, then the protocol installs on the existing ChildHandle. | |
@param[in] This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. | |
@param[in] ChildHandle Pointer to the handle of the child to create. If it is NULL, | |
then a new handle is created. If it is a pointer to an existing UEFI handle, | |
then the protocol is added to the existing UEFI handle. | |
@retval EFI_SUCCESS The protocol was added to ChildHandle. | |
@retval EFI_INVALID_PARAMETER ChildHandle is NULL. | |
@retval EFI_OUT_OF_RESOURCES There are not enough resources available to create | |
the child. | |
@retval other The child handle was not created. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
TlsServiceBindingCreateChild ( | |
IN EFI_SERVICE_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE *ChildHandle | |
) | |
{ | |
TLS_SERVICE *TlsService; | |
TLS_INSTANCE *TlsInstance; | |
EFI_STATUS Status; | |
EFI_TPL OldTpl; | |
if ((This == NULL) || (ChildHandle == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
TlsService = TLS_SERVICE_FROM_THIS (This); | |
Status = TlsCreateInstance (TlsService, &TlsInstance); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
ASSERT (TlsInstance != NULL); | |
// | |
// Create a new TLS connection object. | |
// | |
TlsInstance->TlsConn = TlsNew (TlsService->TlsCtx); | |
if (TlsInstance->TlsConn == NULL) { | |
Status = EFI_ABORTED; | |
goto ON_ERROR; | |
} | |
// | |
// Set default ConnectionEnd to EfiTlsClient | |
// | |
Status = TlsSetConnectionEnd (TlsInstance->TlsConn, EfiTlsClient); | |
if (EFI_ERROR (Status)) { | |
goto ON_ERROR; | |
} | |
// | |
// Install TLS protocol and configuration protocol onto ChildHandle | |
// | |
Status = gBS->InstallMultipleProtocolInterfaces ( | |
ChildHandle, | |
&gEfiTlsProtocolGuid, | |
&TlsInstance->Tls, | |
&gEfiTlsConfigurationProtocolGuid, | |
&TlsInstance->TlsConfig, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
goto ON_ERROR; | |
} | |
TlsInstance->ChildHandle = *ChildHandle; | |
// | |
// Add it to the TLS service's child list. | |
// | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
InsertTailList (&TlsService->TlsChildrenList, &TlsInstance->Link); | |
TlsService->TlsChildrenNum++; | |
gBS->RestoreTPL (OldTpl); | |
return EFI_SUCCESS; | |
ON_ERROR: | |
TlsCleanInstance (TlsInstance); | |
return Status; | |
} | |
/** | |
Destroys a child handle with a protocol installed on it. | |
The DestroyChild() function does the opposite of CreateChild(). It removes a protocol | |
that was installed by CreateChild() from ChildHandle. If the removed protocol is the | |
last protocol on ChildHandle, then ChildHandle is destroyed. | |
@param This Pointer to the EFI_SERVICE_BINDING_PROTOCOL instance. | |
@param ChildHandle Handle of the child to destroy. | |
@retval EFI_SUCCESS The protocol was removed from ChildHandle. | |
@retval EFI_UNSUPPORTED ChildHandle does not support the protocol that is being removed. | |
@retval EFI_INVALID_PARAMETER Child handle is NULL. | |
@retval EFI_ACCESS_DENIED The protocol could not be removed from the ChildHandle | |
because its services are being used. | |
@retval other The child handle was not destroyed. | |
**/ | |
EFI_STATUS | |
EFIAPI | |
TlsServiceBindingDestroyChild ( | |
IN EFI_SERVICE_BINDING_PROTOCOL *This, | |
IN EFI_HANDLE ChildHandle | |
) | |
{ | |
TLS_SERVICE *TlsService; | |
TLS_INSTANCE *TlsInstance; | |
EFI_TLS_PROTOCOL *Tls; | |
EFI_TLS_CONFIGURATION_PROTOCOL *TlsConfig; | |
EFI_STATUS Status; | |
EFI_TPL OldTpl; | |
if ((This == NULL) || (ChildHandle == NULL)) { | |
return EFI_INVALID_PARAMETER; | |
} | |
TlsService = TLS_SERVICE_FROM_THIS (This); | |
// | |
// Find TLS protocol interface installed in ChildHandle | |
// | |
Status = gBS->OpenProtocol ( | |
ChildHandle, | |
&gEfiTlsProtocolGuid, | |
(VOID **)&Tls, | |
TlsService->ImageHandle, | |
NULL, | |
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
// | |
// Find TLS configuration protocol interface installed in ChildHandle | |
// | |
Status = gBS->OpenProtocol ( | |
ChildHandle, | |
&gEfiTlsConfigurationProtocolGuid, | |
(VOID **)&TlsConfig, | |
TlsService->ImageHandle, | |
NULL, | |
EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
TlsInstance = TLS_INSTANCE_FROM_PROTOCOL (Tls); | |
if (TlsInstance->Service != TlsService) { | |
return EFI_INVALID_PARAMETER; | |
} | |
if (TlsInstance->InDestroy) { | |
return EFI_SUCCESS; | |
} | |
OldTpl = gBS->RaiseTPL (TPL_CALLBACK); | |
TlsInstance->InDestroy = TRUE; | |
// | |
// Uninstall the TLS protocol and TLS Configuration Protocol interface installed in ChildHandle. | |
// | |
Status = gBS->UninstallMultipleProtocolInterfaces ( | |
ChildHandle, | |
&gEfiTlsProtocolGuid, | |
Tls, | |
&gEfiTlsConfigurationProtocolGuid, | |
TlsConfig, | |
NULL | |
); | |
if (EFI_ERROR (Status)) { | |
return Status; | |
} | |
RemoveEntryList (&TlsInstance->Link); | |
TlsService->TlsChildrenNum--; | |
gBS->RestoreTPL (OldTpl); | |
TlsCleanInstance (TlsInstance); | |
return EFI_SUCCESS; | |
} |