mirror of
https://github.com/CloverHackyColor/CloverBootloader.git
synced 2024-12-26 16:47:40 +01:00
1878 lines
55 KiB
C
1878 lines
55 KiB
C
|
/** @file
|
||
|
Miscellaneous routines specific to Https for HttpDxe driver.
|
||
|
|
||
|
Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
|
||
|
(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
|
||
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
||
|
|
||
|
**/
|
||
|
|
||
|
#include "HttpDriver.h"
|
||
|
|
||
|
/**
|
||
|
Returns the first occurrence of a Null-terminated ASCII sub-string in a Null-terminated
|
||
|
ASCII string and ignore case during the search process.
|
||
|
|
||
|
This function scans the contents of the ASCII string specified by String
|
||
|
and returns the first occurrence of SearchString and ignore case during the search process.
|
||
|
If SearchString is not found in String, then NULL is returned. If the length of SearchString
|
||
|
is zero, then String is returned.
|
||
|
|
||
|
If String is NULL, then ASSERT().
|
||
|
If SearchString is NULL, then ASSERT().
|
||
|
|
||
|
@param[in] String A pointer to a Null-terminated ASCII string.
|
||
|
@param[in] SearchString A pointer to a Null-terminated ASCII string to search for.
|
||
|
|
||
|
@retval NULL If the SearchString does not appear in String.
|
||
|
@retval others If there is a match return the first occurrence of SearchingString.
|
||
|
If the length of SearchString is zero,return String.
|
||
|
|
||
|
**/
|
||
|
CHAR8 *
|
||
|
AsciiStrCaseStr (
|
||
|
IN CONST CHAR8 *String,
|
||
|
IN CONST CHAR8 *SearchString
|
||
|
)
|
||
|
{
|
||
|
CONST CHAR8 *FirstMatch;
|
||
|
CONST CHAR8 *SearchStringTmp;
|
||
|
|
||
|
CHAR8 Src;
|
||
|
CHAR8 Dst;
|
||
|
|
||
|
//
|
||
|
// ASSERT both strings are less long than PcdMaximumAsciiStringLength
|
||
|
//
|
||
|
ASSERT (AsciiStrSize (String) != 0);
|
||
|
ASSERT (AsciiStrSize (SearchString) != 0);
|
||
|
|
||
|
if (*SearchString == '\0') {
|
||
|
return (CHAR8 *) String;
|
||
|
}
|
||
|
|
||
|
while (*String != '\0') {
|
||
|
SearchStringTmp = SearchString;
|
||
|
FirstMatch = String;
|
||
|
|
||
|
while ((*SearchStringTmp != '\0')
|
||
|
&& (*String != '\0')) {
|
||
|
Src = *String;
|
||
|
Dst = *SearchStringTmp;
|
||
|
|
||
|
if ((Src >= 'A') && (Src <= 'Z')) {
|
||
|
Src += ('a' - 'A');
|
||
|
}
|
||
|
|
||
|
if ((Dst >= 'A') && (Dst <= 'Z')) {
|
||
|
Dst += ('a' - 'A');
|
||
|
}
|
||
|
|
||
|
if (Src != Dst) {
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
String++;
|
||
|
SearchStringTmp++;
|
||
|
}
|
||
|
|
||
|
if (*SearchStringTmp == '\0') {
|
||
|
return (CHAR8 *) FirstMatch;
|
||
|
}
|
||
|
|
||
|
String = FirstMatch + 1;
|
||
|
}
|
||
|
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
The callback function to free the net buffer list.
|
||
|
|
||
|
@param[in] Arg The opaque parameter.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
EFIAPI
|
||
|
FreeNbufList (
|
||
|
IN VOID *Arg
|
||
|
)
|
||
|
{
|
||
|
ASSERT (Arg != NULL);
|
||
|
|
||
|
NetbufFreeList ((LIST_ENTRY *) Arg);
|
||
|
FreePool (Arg);
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Check whether the Url is from Https.
|
||
|
|
||
|
@param[in] Url The pointer to a HTTP or HTTPS URL string.
|
||
|
|
||
|
@retval TRUE The Url is from HTTPS.
|
||
|
@retval FALSE The Url is from HTTP.
|
||
|
|
||
|
**/
|
||
|
BOOLEAN
|
||
|
IsHttpsUrl (
|
||
|
IN CHAR8 *Url
|
||
|
)
|
||
|
{
|
||
|
CHAR8 *Tmp;
|
||
|
|
||
|
Tmp = NULL;
|
||
|
|
||
|
Tmp = AsciiStrCaseStr (Url, HTTPS_FLAG);
|
||
|
if (Tmp != NULL && Tmp == Url) {
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Creates a Tls child handle, open EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
|
||
|
|
||
|
@param[in] ImageHandle The firmware allocated handle for the UEFI image.
|
||
|
@param[out] TlsSb Pointer to the TLS SERVICE_BINDING_PROTOCOL.
|
||
|
@param[out] TlsProto Pointer to the EFI_TLS_PROTOCOL instance.
|
||
|
@param[out] TlsConfiguration Pointer to the EFI_TLS_CONFIGURATION_PROTOCOL instance.
|
||
|
|
||
|
@return The child handle with opened EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
|
||
|
|
||
|
**/
|
||
|
EFI_HANDLE
|
||
|
EFIAPI
|
||
|
TlsCreateChild (
|
||
|
IN EFI_HANDLE ImageHandle,
|
||
|
OUT EFI_SERVICE_BINDING_PROTOCOL **TlsSb,
|
||
|
OUT EFI_TLS_PROTOCOL **TlsProto,
|
||
|
OUT EFI_TLS_CONFIGURATION_PROTOCOL **TlsConfiguration
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
EFI_HANDLE TlsChildHandle;
|
||
|
|
||
|
TlsChildHandle = 0;
|
||
|
|
||
|
//
|
||
|
// Locate TlsServiceBinding protocol.
|
||
|
//
|
||
|
gBS->LocateProtocol (
|
||
|
&gEfiTlsServiceBindingProtocolGuid,
|
||
|
NULL,
|
||
|
(VOID **) TlsSb
|
||
|
);
|
||
|
if (*TlsSb == NULL) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
Status = (*TlsSb)->CreateChild (*TlsSb, &TlsChildHandle);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
Status = gBS->OpenProtocol (
|
||
|
TlsChildHandle,
|
||
|
&gEfiTlsProtocolGuid,
|
||
|
(VOID **) TlsProto,
|
||
|
ImageHandle,
|
||
|
TlsChildHandle,
|
||
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
(*TlsSb)->DestroyChild (*TlsSb, TlsChildHandle);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
Status = gBS->OpenProtocol (
|
||
|
TlsChildHandle,
|
||
|
&gEfiTlsConfigurationProtocolGuid,
|
||
|
(VOID **) TlsConfiguration,
|
||
|
ImageHandle,
|
||
|
TlsChildHandle,
|
||
|
EFI_OPEN_PROTOCOL_GET_PROTOCOL
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
(*TlsSb)->DestroyChild (*TlsSb, TlsChildHandle);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
return TlsChildHandle;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Create event for the TLS receive and transmit tokens which are used to receive and
|
||
|
transmit TLS related messages.
|
||
|
|
||
|
@param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
|
||
|
|
||
|
@retval EFI_SUCCESS The events are created successfully.
|
||
|
@retval others Other error as indicated.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
TlsCreateTxRxEvent (
|
||
|
IN OUT HTTP_PROTOCOL *HttpInstance
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
if (!HttpInstance->LocalAddressIsIPv6) {
|
||
|
//
|
||
|
// For Tcp4TlsTxToken.
|
||
|
//
|
||
|
Status = gBS->CreateEvent (
|
||
|
EVT_NOTIFY_SIGNAL,
|
||
|
TPL_NOTIFY,
|
||
|
HttpCommonNotify,
|
||
|
&HttpInstance->TlsIsTxDone,
|
||
|
&HttpInstance->Tcp4TlsTxToken.CompletionToken.Event
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ERROR;
|
||
|
}
|
||
|
|
||
|
HttpInstance->Tcp4TlsTxData.Push = TRUE;
|
||
|
HttpInstance->Tcp4TlsTxData.Urgent = FALSE;
|
||
|
HttpInstance->Tcp4TlsTxData.DataLength = 0;
|
||
|
HttpInstance->Tcp4TlsTxData.FragmentCount = 1;
|
||
|
HttpInstance->Tcp4TlsTxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp4TlsTxData.DataLength;
|
||
|
HttpInstance->Tcp4TlsTxData.FragmentTable[0].FragmentBuffer = NULL;
|
||
|
HttpInstance->Tcp4TlsTxToken.Packet.TxData = &HttpInstance->Tcp4TlsTxData;
|
||
|
HttpInstance->Tcp4TlsTxToken.CompletionToken.Status = EFI_NOT_READY;
|
||
|
|
||
|
//
|
||
|
// For Tcp4TlsRxToken.
|
||
|
//
|
||
|
Status = gBS->CreateEvent (
|
||
|
EVT_NOTIFY_SIGNAL,
|
||
|
TPL_NOTIFY,
|
||
|
HttpCommonNotify,
|
||
|
&HttpInstance->TlsIsRxDone,
|
||
|
&HttpInstance->Tcp4TlsRxToken.CompletionToken.Event
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ERROR;
|
||
|
}
|
||
|
|
||
|
HttpInstance->Tcp4TlsRxData.DataLength = 0;
|
||
|
HttpInstance->Tcp4TlsRxData.FragmentCount = 1;
|
||
|
HttpInstance->Tcp4TlsRxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp4TlsRxData.DataLength ;
|
||
|
HttpInstance->Tcp4TlsRxData.FragmentTable[0].FragmentBuffer = NULL;
|
||
|
HttpInstance->Tcp4TlsRxToken.Packet.RxData = &HttpInstance->Tcp4TlsRxData;
|
||
|
HttpInstance->Tcp4TlsRxToken.CompletionToken.Status = EFI_NOT_READY;
|
||
|
} else {
|
||
|
//
|
||
|
// For Tcp6TlsTxToken.
|
||
|
//
|
||
|
Status = gBS->CreateEvent (
|
||
|
EVT_NOTIFY_SIGNAL,
|
||
|
TPL_NOTIFY,
|
||
|
HttpCommonNotify,
|
||
|
&HttpInstance->TlsIsTxDone,
|
||
|
&HttpInstance->Tcp6TlsTxToken.CompletionToken.Event
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ERROR;
|
||
|
}
|
||
|
|
||
|
HttpInstance->Tcp6TlsTxData.Push = TRUE;
|
||
|
HttpInstance->Tcp6TlsTxData.Urgent = FALSE;
|
||
|
HttpInstance->Tcp6TlsTxData.DataLength = 0;
|
||
|
HttpInstance->Tcp6TlsTxData.FragmentCount = 1;
|
||
|
HttpInstance->Tcp6TlsTxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp6TlsTxData.DataLength;
|
||
|
HttpInstance->Tcp6TlsTxData.FragmentTable[0].FragmentBuffer = NULL;
|
||
|
HttpInstance->Tcp6TlsTxToken.Packet.TxData = &HttpInstance->Tcp6TlsTxData;
|
||
|
HttpInstance->Tcp6TlsTxToken.CompletionToken.Status = EFI_NOT_READY;
|
||
|
|
||
|
//
|
||
|
// For Tcp6TlsRxToken.
|
||
|
//
|
||
|
Status = gBS->CreateEvent (
|
||
|
EVT_NOTIFY_SIGNAL,
|
||
|
TPL_NOTIFY,
|
||
|
HttpCommonNotify,
|
||
|
&HttpInstance->TlsIsRxDone,
|
||
|
&HttpInstance->Tcp6TlsRxToken.CompletionToken.Event
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ERROR;
|
||
|
}
|
||
|
|
||
|
HttpInstance->Tcp6TlsRxData.DataLength = 0;
|
||
|
HttpInstance->Tcp6TlsRxData.FragmentCount = 1;
|
||
|
HttpInstance->Tcp6TlsRxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp6TlsRxData.DataLength ;
|
||
|
HttpInstance->Tcp6TlsRxData.FragmentTable[0].FragmentBuffer = NULL;
|
||
|
HttpInstance->Tcp6TlsRxToken.Packet.RxData = &HttpInstance->Tcp6TlsRxData;
|
||
|
HttpInstance->Tcp6TlsRxToken.CompletionToken.Status = EFI_NOT_READY;
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
|
||
|
ERROR:
|
||
|
//
|
||
|
// Error handling
|
||
|
//
|
||
|
TlsCloseTxRxEvent (HttpInstance);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Close events in the TlsTxToken and TlsRxToken.
|
||
|
|
||
|
@param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
|
||
|
|
||
|
**/
|
||
|
VOID
|
||
|
EFIAPI
|
||
|
TlsCloseTxRxEvent (
|
||
|
IN HTTP_PROTOCOL *HttpInstance
|
||
|
)
|
||
|
{
|
||
|
ASSERT (HttpInstance != NULL);
|
||
|
if (!HttpInstance->LocalAddressIsIPv6) {
|
||
|
if (NULL != HttpInstance->Tcp4TlsTxToken.CompletionToken.Event) {
|
||
|
gBS->CloseEvent(HttpInstance->Tcp4TlsTxToken.CompletionToken.Event);
|
||
|
HttpInstance->Tcp4TlsTxToken.CompletionToken.Event = NULL;
|
||
|
}
|
||
|
|
||
|
if (NULL != HttpInstance->Tcp4TlsRxToken.CompletionToken.Event) {
|
||
|
gBS->CloseEvent (HttpInstance->Tcp4TlsRxToken.CompletionToken.Event);
|
||
|
HttpInstance->Tcp4TlsRxToken.CompletionToken.Event = NULL;
|
||
|
}
|
||
|
} else {
|
||
|
if (NULL != HttpInstance->Tcp6TlsTxToken.CompletionToken.Event) {
|
||
|
gBS->CloseEvent(HttpInstance->Tcp6TlsTxToken.CompletionToken.Event);
|
||
|
HttpInstance->Tcp6TlsTxToken.CompletionToken.Event = NULL;
|
||
|
}
|
||
|
|
||
|
if (NULL != HttpInstance->Tcp6TlsRxToken.CompletionToken.Event) {
|
||
|
gBS->CloseEvent (HttpInstance->Tcp6TlsRxToken.CompletionToken.Event);
|
||
|
HttpInstance->Tcp6TlsRxToken.CompletionToken.Event = NULL;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Read the TlsCaCertificate variable and configure it.
|
||
|
|
||
|
@param[in, out] HttpInstance The HTTP instance private data.
|
||
|
|
||
|
@retval EFI_SUCCESS TlsCaCertificate is configured.
|
||
|
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
|
||
|
@retval EFI_NOT_FOUND Fail to get 'TlsCaCertificate' variable.
|
||
|
@retval Others Other error as indicated.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
TlsConfigCertificate (
|
||
|
IN OUT HTTP_PROTOCOL *HttpInstance
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINT8 *CACert;
|
||
|
UINTN CACertSize;
|
||
|
UINT32 Index;
|
||
|
EFI_SIGNATURE_LIST *CertList;
|
||
|
EFI_SIGNATURE_DATA *Cert;
|
||
|
UINTN CertArraySizeInBytes;
|
||
|
UINTN CertCount;
|
||
|
UINT32 ItemDataSize;
|
||
|
|
||
|
CACert = NULL;
|
||
|
CACertSize = 0;
|
||
|
|
||
|
//
|
||
|
// Try to read the TlsCaCertificate variable.
|
||
|
//
|
||
|
Status = gRT->GetVariable (
|
||
|
EFI_TLS_CA_CERTIFICATE_VARIABLE,
|
||
|
&gEfiTlsCaCertificateGuid,
|
||
|
NULL,
|
||
|
&CACertSize,
|
||
|
NULL
|
||
|
);
|
||
|
|
||
|
if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate buffer and read the config variable.
|
||
|
//
|
||
|
CACert = AllocatePool (CACertSize);
|
||
|
if (CACert == NULL) {
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
Status = gRT->GetVariable (
|
||
|
EFI_TLS_CA_CERTIFICATE_VARIABLE,
|
||
|
&gEfiTlsCaCertificateGuid,
|
||
|
NULL,
|
||
|
&CACertSize,
|
||
|
CACert
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
//
|
||
|
// GetVariable still error or the variable is corrupted.
|
||
|
//
|
||
|
goto FreeCACert;
|
||
|
}
|
||
|
|
||
|
ASSERT (CACert != NULL);
|
||
|
|
||
|
//
|
||
|
// Sanity check
|
||
|
//
|
||
|
Status = EFI_INVALID_PARAMETER;
|
||
|
CertCount = 0;
|
||
|
ItemDataSize = (UINT32) CACertSize;
|
||
|
while (ItemDataSize > 0) {
|
||
|
if (ItemDataSize < sizeof (EFI_SIGNATURE_LIST)) {
|
||
|
DEBUG ((DEBUG_ERROR, "%a: truncated EFI_SIGNATURE_LIST header\n",
|
||
|
__FUNCTION__));
|
||
|
goto FreeCACert;
|
||
|
}
|
||
|
|
||
|
CertList = (EFI_SIGNATURE_LIST *) (CACert + (CACertSize - ItemDataSize));
|
||
|
|
||
|
if (CertList->SignatureListSize < sizeof (EFI_SIGNATURE_LIST)) {
|
||
|
DEBUG ((DEBUG_ERROR,
|
||
|
"%a: SignatureListSize too small for EFI_SIGNATURE_LIST\n",
|
||
|
__FUNCTION__));
|
||
|
goto FreeCACert;
|
||
|
}
|
||
|
|
||
|
if (CertList->SignatureListSize > ItemDataSize) {
|
||
|
DEBUG ((DEBUG_ERROR, "%a: truncated EFI_SIGNATURE_LIST body\n",
|
||
|
__FUNCTION__));
|
||
|
goto FreeCACert;
|
||
|
}
|
||
|
|
||
|
if (!CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
|
||
|
DEBUG ((DEBUG_ERROR, "%a: only X509 certificates are supported\n",
|
||
|
__FUNCTION__));
|
||
|
Status = EFI_UNSUPPORTED;
|
||
|
goto FreeCACert;
|
||
|
}
|
||
|
|
||
|
if (CertList->SignatureHeaderSize != 0) {
|
||
|
DEBUG ((DEBUG_ERROR, "%a: SignatureHeaderSize must be 0 for X509\n",
|
||
|
__FUNCTION__));
|
||
|
goto FreeCACert;
|
||
|
}
|
||
|
|
||
|
if (CertList->SignatureSize < sizeof (EFI_SIGNATURE_DATA)) {
|
||
|
DEBUG ((DEBUG_ERROR,
|
||
|
"%a: SignatureSize too small for EFI_SIGNATURE_DATA\n", __FUNCTION__));
|
||
|
goto FreeCACert;
|
||
|
}
|
||
|
|
||
|
CertArraySizeInBytes = (CertList->SignatureListSize -
|
||
|
sizeof (EFI_SIGNATURE_LIST));
|
||
|
if (CertArraySizeInBytes % CertList->SignatureSize != 0) {
|
||
|
DEBUG ((DEBUG_ERROR,
|
||
|
"%a: EFI_SIGNATURE_DATA array not a multiple of SignatureSize\n",
|
||
|
__FUNCTION__));
|
||
|
goto FreeCACert;
|
||
|
}
|
||
|
|
||
|
CertCount += CertArraySizeInBytes / CertList->SignatureSize;
|
||
|
ItemDataSize -= CertList->SignatureListSize;
|
||
|
}
|
||
|
if (CertCount == 0) {
|
||
|
DEBUG ((DEBUG_ERROR, "%a: no X509 certificates provided\n", __FUNCTION__));
|
||
|
goto FreeCACert;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Enumerate all data and erasing the target item.
|
||
|
//
|
||
|
ItemDataSize = (UINT32) CACertSize;
|
||
|
CertList = (EFI_SIGNATURE_LIST *) CACert;
|
||
|
while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
|
||
|
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++) {
|
||
|
//
|
||
|
// EfiTlsConfigDataTypeCACertificate
|
||
|
//
|
||
|
Status = HttpInstance->TlsConfiguration->SetData (
|
||
|
HttpInstance->TlsConfiguration,
|
||
|
EfiTlsConfigDataTypeCACertificate,
|
||
|
Cert->SignatureData,
|
||
|
CertList->SignatureSize - sizeof (Cert->SignatureOwner)
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto FreeCACert;
|
||
|
}
|
||
|
|
||
|
Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
|
||
|
}
|
||
|
|
||
|
ItemDataSize -= CertList->SignatureListSize;
|
||
|
CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
|
||
|
}
|
||
|
|
||
|
FreeCACert:
|
||
|
FreePool (CACert);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Read the HttpTlsCipherList variable and configure it for HTTPS session.
|
||
|
|
||
|
@param[in, out] HttpInstance The HTTP instance private data.
|
||
|
|
||
|
@retval EFI_SUCCESS The prefered HTTP TLS CipherList is configured.
|
||
|
@retval EFI_NOT_FOUND Fail to get 'HttpTlsCipherList' variable.
|
||
|
@retval EFI_INVALID_PARAMETER The contents of variable are invalid.
|
||
|
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
|
||
|
|
||
|
@retval Others Other error as indicated.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
TlsConfigCipherList (
|
||
|
IN OUT HTTP_PROTOCOL *HttpInstance
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINT8 *CipherList;
|
||
|
UINTN CipherListSize;
|
||
|
|
||
|
CipherList = NULL;
|
||
|
CipherListSize = 0;
|
||
|
|
||
|
//
|
||
|
// Try to read the HttpTlsCipherList variable.
|
||
|
//
|
||
|
Status = gRT->GetVariable (
|
||
|
EDKII_HTTP_TLS_CIPHER_LIST_VARIABLE,
|
||
|
&gEdkiiHttpTlsCipherListGuid,
|
||
|
NULL,
|
||
|
&CipherListSize,
|
||
|
NULL
|
||
|
);
|
||
|
ASSERT (EFI_ERROR (Status));
|
||
|
if (Status != EFI_BUFFER_TOO_SMALL) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
if (CipherListSize % sizeof (EFI_TLS_CIPHER) != 0) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate buffer and read the config variable.
|
||
|
//
|
||
|
CipherList = AllocatePool (CipherListSize);
|
||
|
if (CipherList == NULL) {
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
Status = gRT->GetVariable (
|
||
|
EDKII_HTTP_TLS_CIPHER_LIST_VARIABLE,
|
||
|
&gEdkiiHttpTlsCipherListGuid,
|
||
|
NULL,
|
||
|
&CipherListSize,
|
||
|
CipherList
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
//
|
||
|
// GetVariable still error or the variable is corrupted.
|
||
|
//
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
ASSERT (CipherList != NULL);
|
||
|
|
||
|
Status = HttpInstance->Tls->SetSessionData (
|
||
|
HttpInstance->Tls,
|
||
|
EfiTlsCipherList,
|
||
|
CipherList,
|
||
|
CipherListSize
|
||
|
);
|
||
|
|
||
|
ON_EXIT:
|
||
|
FreePool (CipherList);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Configure TLS session data.
|
||
|
|
||
|
@param[in, out] HttpInstance The HTTP instance private data.
|
||
|
|
||
|
@retval EFI_SUCCESS TLS session data is configured.
|
||
|
@retval Others Other error as indicated.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
TlsConfigureSession (
|
||
|
IN OUT HTTP_PROTOCOL *HttpInstance
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
//
|
||
|
// TlsConfigData initialization
|
||
|
//
|
||
|
HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient;
|
||
|
HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER;
|
||
|
HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted;
|
||
|
|
||
|
//
|
||
|
// EfiTlsConnectionEnd,
|
||
|
// EfiTlsVerifyMethod
|
||
|
// EfiTlsSessionState
|
||
|
//
|
||
|
Status = HttpInstance->Tls->SetSessionData (
|
||
|
HttpInstance->Tls,
|
||
|
EfiTlsConnectionEnd,
|
||
|
&(HttpInstance->TlsConfigData.ConnectionEnd),
|
||
|
sizeof (EFI_TLS_CONNECTION_END)
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->SetSessionData (
|
||
|
HttpInstance->Tls,
|
||
|
EfiTlsVerifyMethod,
|
||
|
&HttpInstance->TlsConfigData.VerifyMethod,
|
||
|
sizeof (EFI_TLS_VERIFY)
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->SetSessionData (
|
||
|
HttpInstance->Tls,
|
||
|
EfiTlsSessionState,
|
||
|
&(HttpInstance->TlsConfigData.SessionState),
|
||
|
sizeof (EFI_TLS_SESSION_STATE)
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Tls Cipher List
|
||
|
//
|
||
|
Status = TlsConfigCipherList (HttpInstance);
|
||
|
if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {
|
||
|
DEBUG ((EFI_D_ERROR, "TlsConfigCipherList: return %r error.\n", Status));
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Tls Config Certificate
|
||
|
//
|
||
|
Status = TlsConfigCertificate (HttpInstance);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
DEBUG ((EFI_D_ERROR, "TLS Certificate Config Error!\n"));
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// TlsCreateTxRxEvent
|
||
|
//
|
||
|
Status = TlsCreateTxRxEvent (HttpInstance);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ERROR;
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
|
||
|
ERROR:
|
||
|
TlsCloseTxRxEvent (HttpInstance);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Transmit the Packet by processing the associated HTTPS token.
|
||
|
|
||
|
@param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
|
||
|
@param[in] Packet The packet to transmit.
|
||
|
|
||
|
@retval EFI_SUCCESS The packet is transmitted.
|
||
|
@retval EFI_INVALID_PARAMETER HttpInstance is NULL or Packet is NULL.
|
||
|
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
|
||
|
@retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
|
||
|
@retval Others Other errors as indicated.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
TlsCommonTransmit (
|
||
|
IN OUT HTTP_PROTOCOL *HttpInstance,
|
||
|
IN NET_BUF *Packet
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
VOID *Data;
|
||
|
UINTN Size;
|
||
|
|
||
|
if ((HttpInstance == NULL) || (Packet == NULL)) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
if (!HttpInstance->LocalAddressIsIPv6) {
|
||
|
Size = sizeof (EFI_TCP4_TRANSMIT_DATA) +
|
||
|
(Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA);
|
||
|
} else {
|
||
|
Size = sizeof (EFI_TCP6_TRANSMIT_DATA) +
|
||
|
(Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA);
|
||
|
}
|
||
|
|
||
|
Data = AllocatePool (Size);
|
||
|
if (Data == NULL) {
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
if (!HttpInstance->LocalAddressIsIPv6) {
|
||
|
((EFI_TCP4_TRANSMIT_DATA *) Data)->Push = TRUE;
|
||
|
((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent = FALSE;
|
||
|
((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
|
||
|
|
||
|
//
|
||
|
// Build the fragment table.
|
||
|
//
|
||
|
((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
|
||
|
|
||
|
NetbufBuildExt (
|
||
|
Packet,
|
||
|
(NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0],
|
||
|
&((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount
|
||
|
);
|
||
|
|
||
|
HttpInstance->Tcp4TlsTxToken.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data;
|
||
|
|
||
|
Status = EFI_DEVICE_ERROR;
|
||
|
|
||
|
//
|
||
|
// Transmit the packet.
|
||
|
//
|
||
|
Status = HttpInstance->Tcp4->Transmit (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsTxToken);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
while (!HttpInstance->TlsIsTxDone) {
|
||
|
HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
|
||
|
}
|
||
|
|
||
|
HttpInstance->TlsIsTxDone = FALSE;
|
||
|
Status = HttpInstance->Tcp4TlsTxToken.CompletionToken.Status;
|
||
|
} else {
|
||
|
((EFI_TCP6_TRANSMIT_DATA *) Data)->Push = TRUE;
|
||
|
((EFI_TCP6_TRANSMIT_DATA *) Data)->Urgent = FALSE;
|
||
|
((EFI_TCP6_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
|
||
|
|
||
|
//
|
||
|
// Build the fragment table.
|
||
|
//
|
||
|
((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
|
||
|
|
||
|
NetbufBuildExt (
|
||
|
Packet,
|
||
|
(NET_FRAGMENT *) &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentTable[0],
|
||
|
&((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount
|
||
|
);
|
||
|
|
||
|
HttpInstance->Tcp6TlsTxToken.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data;
|
||
|
|
||
|
Status = EFI_DEVICE_ERROR;
|
||
|
|
||
|
//
|
||
|
// Transmit the packet.
|
||
|
//
|
||
|
Status = HttpInstance->Tcp6->Transmit (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsTxToken);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
while (!HttpInstance->TlsIsTxDone) {
|
||
|
HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
|
||
|
}
|
||
|
|
||
|
HttpInstance->TlsIsTxDone = FALSE;
|
||
|
Status = HttpInstance->Tcp6TlsTxToken.CompletionToken.Status;
|
||
|
}
|
||
|
|
||
|
ON_EXIT:
|
||
|
FreePool (Data);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Receive the Packet by processing the associated HTTPS token.
|
||
|
|
||
|
@param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
|
||
|
@param[in] Packet The packet to transmit.
|
||
|
@param[in] Timeout The time to wait for connection done.
|
||
|
|
||
|
@retval EFI_SUCCESS The Packet is received.
|
||
|
@retval EFI_INVALID_PARAMETER HttpInstance is NULL or Packet is NULL.
|
||
|
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
|
||
|
@retval EFI_TIMEOUT The operation is time out.
|
||
|
@retval Others Other error as indicated.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
TlsCommonReceive (
|
||
|
IN OUT HTTP_PROTOCOL *HttpInstance,
|
||
|
IN NET_BUF *Packet,
|
||
|
IN EFI_EVENT Timeout
|
||
|
)
|
||
|
{
|
||
|
EFI_TCP4_RECEIVE_DATA *Tcp4RxData;
|
||
|
EFI_TCP6_RECEIVE_DATA *Tcp6RxData;
|
||
|
EFI_STATUS Status;
|
||
|
NET_FRAGMENT *Fragment;
|
||
|
UINT32 FragmentCount;
|
||
|
UINT32 CurrentFragment;
|
||
|
|
||
|
Tcp4RxData = NULL;
|
||
|
Tcp6RxData = NULL;
|
||
|
|
||
|
if ((HttpInstance == NULL) || (Packet == NULL)) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
FragmentCount = Packet->BlockOpNum;
|
||
|
Fragment = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
|
||
|
if (Fragment == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Build the fragment table.
|
||
|
//
|
||
|
NetbufBuildExt (Packet, Fragment, &FragmentCount);
|
||
|
|
||
|
if (!HttpInstance->LocalAddressIsIPv6) {
|
||
|
Tcp4RxData = HttpInstance->Tcp4TlsRxToken.Packet.RxData;
|
||
|
if (Tcp4RxData == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
Tcp4RxData->FragmentCount = 1;
|
||
|
} else {
|
||
|
Tcp6RxData = HttpInstance->Tcp6TlsRxToken.Packet.RxData;
|
||
|
if (Tcp6RxData == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
Tcp6RxData->FragmentCount = 1;
|
||
|
}
|
||
|
|
||
|
CurrentFragment = 0;
|
||
|
Status = EFI_SUCCESS;
|
||
|
|
||
|
while (CurrentFragment < FragmentCount) {
|
||
|
if (!HttpInstance->LocalAddressIsIPv6) {
|
||
|
Tcp4RxData->DataLength = Fragment[CurrentFragment].Len;
|
||
|
Tcp4RxData->FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len;
|
||
|
Tcp4RxData->FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk;
|
||
|
Status = HttpInstance->Tcp4->Receive (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken);
|
||
|
} else {
|
||
|
Tcp6RxData->DataLength = Fragment[CurrentFragment].Len;
|
||
|
Tcp6RxData->FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len;
|
||
|
Tcp6RxData->FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk;
|
||
|
Status = HttpInstance->Tcp6->Receive (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken);
|
||
|
}
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
while (!HttpInstance->TlsIsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
|
||
|
//
|
||
|
// Poll until some data is received or an error occurs.
|
||
|
//
|
||
|
if (!HttpInstance->LocalAddressIsIPv6) {
|
||
|
HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
|
||
|
} else {
|
||
|
HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (!HttpInstance->TlsIsRxDone) {
|
||
|
//
|
||
|
// Timeout occurs, cancel the receive request.
|
||
|
//
|
||
|
if (!HttpInstance->LocalAddressIsIPv6) {
|
||
|
HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken.CompletionToken);
|
||
|
} else {
|
||
|
HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken.CompletionToken);
|
||
|
}
|
||
|
|
||
|
Status = EFI_TIMEOUT;
|
||
|
goto ON_EXIT;
|
||
|
} else {
|
||
|
HttpInstance->TlsIsRxDone = FALSE;
|
||
|
}
|
||
|
|
||
|
if (!HttpInstance->LocalAddressIsIPv6) {
|
||
|
Status = HttpInstance->Tcp4TlsRxToken.CompletionToken.Status;
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
Fragment[CurrentFragment].Len -= Tcp4RxData->FragmentTable[0].FragmentLength;
|
||
|
if (Fragment[CurrentFragment].Len == 0) {
|
||
|
CurrentFragment++;
|
||
|
} else {
|
||
|
Fragment[CurrentFragment].Bulk += Tcp4RxData->FragmentTable[0].FragmentLength;
|
||
|
}
|
||
|
} else {
|
||
|
Status = HttpInstance->Tcp6TlsRxToken.CompletionToken.Status;
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
Fragment[CurrentFragment].Len -= Tcp6RxData->FragmentTable[0].FragmentLength;
|
||
|
if (Fragment[CurrentFragment].Len == 0) {
|
||
|
CurrentFragment++;
|
||
|
} else {
|
||
|
Fragment[CurrentFragment].Bulk += Tcp6RxData->FragmentTable[0].FragmentLength;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
ON_EXIT:
|
||
|
|
||
|
if (Fragment != NULL) {
|
||
|
FreePool (Fragment);
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Receive one TLS PDU. An TLS PDU contains an TLS record header and it's
|
||
|
corresponding record data. These two parts will be put into two blocks of buffers in the
|
||
|
net buffer.
|
||
|
|
||
|
@param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
|
||
|
@param[out] Pdu The received TLS PDU.
|
||
|
@param[in] Timeout The time to wait for connection done.
|
||
|
|
||
|
@retval EFI_SUCCESS An TLS PDU is received.
|
||
|
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
|
||
|
@retval EFI_PROTOCOL_ERROR An unexpected TLS packet was received.
|
||
|
@retval Others Other errors as indicated.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
TlsReceiveOnePdu (
|
||
|
IN OUT HTTP_PROTOCOL *HttpInstance,
|
||
|
OUT NET_BUF **Pdu,
|
||
|
IN EFI_EVENT Timeout
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
LIST_ENTRY *NbufList;
|
||
|
|
||
|
UINT32 Len;
|
||
|
|
||
|
NET_BUF *PduHdr;
|
||
|
UINT8 *Header;
|
||
|
TLS_RECORD_HEADER RecordHeader;
|
||
|
|
||
|
NET_BUF *DataSeg;
|
||
|
|
||
|
NbufList = NULL;
|
||
|
PduHdr = NULL;
|
||
|
Header = NULL;
|
||
|
DataSeg = NULL;
|
||
|
|
||
|
NbufList = AllocatePool (sizeof (LIST_ENTRY));
|
||
|
if (NbufList == NULL) {
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
InitializeListHead (NbufList);
|
||
|
|
||
|
//
|
||
|
// Allocate buffer to receive one TLS header.
|
||
|
//
|
||
|
Len = TLS_RECORD_HEADER_LENGTH;
|
||
|
PduHdr = NetbufAlloc (Len);
|
||
|
if (PduHdr == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
Header = NetbufAllocSpace (PduHdr, Len, NET_BUF_TAIL);
|
||
|
if (Header == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// First step, receive one TLS header.
|
||
|
//
|
||
|
Status = TlsCommonReceive (HttpInstance, PduHdr, Timeout);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
RecordHeader = *(TLS_RECORD_HEADER *) Header;
|
||
|
if ((RecordHeader.ContentType == TlsContentTypeHandshake ||
|
||
|
RecordHeader.ContentType == TlsContentTypeAlert ||
|
||
|
RecordHeader.ContentType == TlsContentTypeChangeCipherSpec ||
|
||
|
RecordHeader.ContentType == TlsContentTypeApplicationData) &&
|
||
|
(RecordHeader.Version.Major == 0x03) && /// Major versions are same.
|
||
|
(RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
|
||
|
RecordHeader.Version.Minor ==TLS11_PROTOCOL_VERSION_MINOR ||
|
||
|
RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
|
||
|
) {
|
||
|
InsertTailList (NbufList, &PduHdr->List);
|
||
|
} else {
|
||
|
Status = EFI_PROTOCOL_ERROR;
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
Len = SwapBytes16(RecordHeader.Length);
|
||
|
if (Len == 0) {
|
||
|
//
|
||
|
// No TLS payload.
|
||
|
//
|
||
|
goto FORM_PDU;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate buffer to receive one TLS payload.
|
||
|
//
|
||
|
DataSeg = NetbufAlloc (Len);
|
||
|
if (DataSeg == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
NetbufAllocSpace (DataSeg, Len, NET_BUF_TAIL);
|
||
|
|
||
|
//
|
||
|
// Second step, receive one TLS payload.
|
||
|
//
|
||
|
Status = TlsCommonReceive (HttpInstance, DataSeg, Timeout);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
InsertTailList (NbufList, &DataSeg->List);
|
||
|
|
||
|
FORM_PDU:
|
||
|
//
|
||
|
// Form the PDU from a list of PDU.
|
||
|
//
|
||
|
*Pdu = NetbufFromBufList (NbufList, 0, 0, FreeNbufList, NbufList);
|
||
|
if (*Pdu == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
ON_EXIT:
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
//
|
||
|
// Free the Nbufs in this NbufList and the NbufList itself.
|
||
|
//
|
||
|
FreeNbufList (NbufList);
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Connect one TLS session by finishing the TLS handshake process.
|
||
|
|
||
|
@param[in] HttpInstance The HTTP instance private data.
|
||
|
@param[in] Timeout The time to wait for connection done.
|
||
|
|
||
|
@retval EFI_SUCCESS The TLS session is established.
|
||
|
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
|
||
|
@retval EFI_ABORTED TLS session state is incorrect.
|
||
|
@retval Others Other error as indicated.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
TlsConnectSession (
|
||
|
IN HTTP_PROTOCOL *HttpInstance,
|
||
|
IN EFI_EVENT Timeout
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINT8 *BufferOut;
|
||
|
UINTN BufferOutSize;
|
||
|
NET_BUF *PacketOut;
|
||
|
UINT8 *DataOut;
|
||
|
NET_BUF *Pdu;
|
||
|
UINT8 *BufferIn;
|
||
|
UINTN BufferInSize;
|
||
|
UINT8 *GetSessionDataBuffer;
|
||
|
UINTN GetSessionDataBufferSize;
|
||
|
|
||
|
BufferOut = NULL;
|
||
|
PacketOut = NULL;
|
||
|
DataOut = NULL;
|
||
|
Pdu = NULL;
|
||
|
BufferIn = NULL;
|
||
|
|
||
|
//
|
||
|
// Initialize TLS state.
|
||
|
//
|
||
|
HttpInstance->TlsSessionState = EfiTlsSessionNotStarted;
|
||
|
Status = HttpInstance->Tls->SetSessionData (
|
||
|
HttpInstance->Tls,
|
||
|
EfiTlsSessionState,
|
||
|
&(HttpInstance->TlsSessionState),
|
||
|
sizeof (EFI_TLS_SESSION_STATE)
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Create ClientHello
|
||
|
//
|
||
|
BufferOutSize = DEF_BUF_LEN;
|
||
|
BufferOut = AllocateZeroPool (BufferOutSize);
|
||
|
if (BufferOut == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->BuildResponsePacket (
|
||
|
HttpInstance->Tls,
|
||
|
NULL,
|
||
|
0,
|
||
|
BufferOut,
|
||
|
&BufferOutSize
|
||
|
);
|
||
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
||
|
FreePool (BufferOut);
|
||
|
BufferOut = AllocateZeroPool (BufferOutSize);
|
||
|
if (BufferOut == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->BuildResponsePacket (
|
||
|
HttpInstance->Tls,
|
||
|
NULL,
|
||
|
0,
|
||
|
BufferOut,
|
||
|
&BufferOutSize
|
||
|
);
|
||
|
}
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreePool (BufferOut);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Transmit ClientHello
|
||
|
//
|
||
|
PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
|
||
|
DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
|
||
|
if (DataOut == NULL) {
|
||
|
FreePool (BufferOut);
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
CopyMem (DataOut, BufferOut, BufferOutSize);
|
||
|
Status = TlsCommonTransmit (HttpInstance, PacketOut);
|
||
|
|
||
|
FreePool (BufferOut);
|
||
|
NetbufFree (PacketOut);
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
while(HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring && \
|
||
|
((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
|
||
|
//
|
||
|
// Receive one TLS record.
|
||
|
//
|
||
|
Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
BufferInSize = Pdu->TotalSize;
|
||
|
BufferIn = AllocateZeroPool (BufferInSize);
|
||
|
if (BufferIn == NULL) {
|
||
|
NetbufFree (Pdu);
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NetbufCopy (Pdu, 0, (UINT32)BufferInSize, BufferIn);
|
||
|
|
||
|
NetbufFree (Pdu);
|
||
|
|
||
|
//
|
||
|
// Handle Receive data.
|
||
|
//
|
||
|
BufferOutSize = DEF_BUF_LEN;
|
||
|
BufferOut = AllocateZeroPool (BufferOutSize);
|
||
|
if (BufferOut == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->BuildResponsePacket (
|
||
|
HttpInstance->Tls,
|
||
|
BufferIn,
|
||
|
BufferInSize,
|
||
|
BufferOut,
|
||
|
&BufferOutSize
|
||
|
);
|
||
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
||
|
FreePool (BufferOut);
|
||
|
BufferOut = AllocateZeroPool (BufferOutSize);
|
||
|
if (BufferOut == NULL) {
|
||
|
FreePool (BufferIn);
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->BuildResponsePacket (
|
||
|
HttpInstance->Tls,
|
||
|
BufferIn,
|
||
|
BufferInSize,
|
||
|
BufferOut,
|
||
|
&BufferOutSize
|
||
|
);
|
||
|
}
|
||
|
|
||
|
FreePool (BufferIn);
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreePool (BufferOut);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
if (BufferOutSize != 0) {
|
||
|
//
|
||
|
// Transmit the response packet.
|
||
|
//
|
||
|
PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
|
||
|
DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
|
||
|
if (DataOut == NULL) {
|
||
|
FreePool (BufferOut);
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
CopyMem (DataOut, BufferOut, BufferOutSize);
|
||
|
|
||
|
Status = TlsCommonTransmit (HttpInstance, PacketOut);
|
||
|
|
||
|
NetbufFree (PacketOut);
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreePool (BufferOut);
|
||
|
return Status;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
FreePool (BufferOut);
|
||
|
|
||
|
//
|
||
|
// Get the session state, then decide whether need to continue handle received packet.
|
||
|
//
|
||
|
GetSessionDataBufferSize = DEF_BUF_LEN;
|
||
|
GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
|
||
|
if (GetSessionDataBuffer == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->GetSessionData (
|
||
|
HttpInstance->Tls,
|
||
|
EfiTlsSessionState,
|
||
|
GetSessionDataBuffer,
|
||
|
&GetSessionDataBufferSize
|
||
|
);
|
||
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
||
|
FreePool (GetSessionDataBuffer);
|
||
|
GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
|
||
|
if (GetSessionDataBuffer == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->GetSessionData (
|
||
|
HttpInstance->Tls,
|
||
|
EfiTlsSessionState,
|
||
|
GetSessionDataBuffer,
|
||
|
&GetSessionDataBufferSize
|
||
|
);
|
||
|
}
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreePool(GetSessionDataBuffer);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
|
||
|
HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;
|
||
|
|
||
|
FreePool (GetSessionDataBuffer);
|
||
|
|
||
|
if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring) {
|
||
|
Status = EFI_ABORTED;
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Close the TLS session and send out the close notification message.
|
||
|
|
||
|
@param[in] HttpInstance The HTTP instance private data.
|
||
|
|
||
|
@retval EFI_SUCCESS The TLS session is closed.
|
||
|
@retval EFI_INVALID_PARAMETER HttpInstance is NULL.
|
||
|
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
|
||
|
@retval Others Other error as indicated.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
TlsCloseSession (
|
||
|
IN HTTP_PROTOCOL *HttpInstance
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
|
||
|
UINT8 *BufferOut;
|
||
|
UINTN BufferOutSize;
|
||
|
|
||
|
NET_BUF *PacketOut;
|
||
|
UINT8 *DataOut;
|
||
|
|
||
|
Status = EFI_SUCCESS;
|
||
|
BufferOut = NULL;
|
||
|
PacketOut = NULL;
|
||
|
DataOut = NULL;
|
||
|
|
||
|
if (HttpInstance == NULL) {
|
||
|
return EFI_INVALID_PARAMETER;
|
||
|
}
|
||
|
|
||
|
HttpInstance->TlsSessionState = EfiTlsSessionClosing;
|
||
|
|
||
|
Status = HttpInstance->Tls->SetSessionData (
|
||
|
HttpInstance->Tls,
|
||
|
EfiTlsSessionState,
|
||
|
&(HttpInstance->TlsSessionState),
|
||
|
sizeof (EFI_TLS_SESSION_STATE)
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
BufferOutSize = DEF_BUF_LEN;
|
||
|
BufferOut = AllocateZeroPool (BufferOutSize);
|
||
|
if (BufferOut == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->BuildResponsePacket (
|
||
|
HttpInstance->Tls,
|
||
|
NULL,
|
||
|
0,
|
||
|
BufferOut,
|
||
|
&BufferOutSize
|
||
|
);
|
||
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
||
|
FreePool (BufferOut);
|
||
|
BufferOut = AllocateZeroPool (BufferOutSize);
|
||
|
if (BufferOut == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->BuildResponsePacket (
|
||
|
HttpInstance->Tls,
|
||
|
NULL,
|
||
|
0,
|
||
|
BufferOut,
|
||
|
&BufferOutSize
|
||
|
);
|
||
|
}
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreePool (BufferOut);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
|
||
|
DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
|
||
|
if (DataOut == NULL) {
|
||
|
FreePool (BufferOut);
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
CopyMem (DataOut, BufferOut, BufferOutSize);
|
||
|
|
||
|
Status = TlsCommonTransmit (HttpInstance, PacketOut);
|
||
|
|
||
|
FreePool (BufferOut);
|
||
|
NetbufFree (PacketOut);
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Process one message according to the CryptMode.
|
||
|
|
||
|
@param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
|
||
|
@param[in] Message Pointer to the message buffer needed to processed.
|
||
|
If ProcessMode is EfiTlsEncrypt, the message contain the TLS
|
||
|
header and plain text TLS APP payload.
|
||
|
If ProcessMode is EfiTlsDecrypt, the message contain the TLS
|
||
|
header and cipher text TLS APP payload.
|
||
|
@param[in] MessageSize Pointer to the message buffer size.
|
||
|
@param[in] ProcessMode Process mode.
|
||
|
@param[in, out] Fragment Only one Fragment returned after the Message is
|
||
|
processed successfully.
|
||
|
If ProcessMode is EfiTlsEncrypt, the fragment contain the TLS
|
||
|
header and cipher text TLS APP payload.
|
||
|
If ProcessMode is EfiTlsDecrypt, the fragment contain the TLS
|
||
|
header and plain text TLS APP payload.
|
||
|
|
||
|
@retval EFI_SUCCESS Message is processed successfully.
|
||
|
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
|
||
|
@retval Others Other errors as indicated.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
TlsProcessMessage (
|
||
|
IN HTTP_PROTOCOL *HttpInstance,
|
||
|
IN UINT8 *Message,
|
||
|
IN UINTN MessageSize,
|
||
|
IN EFI_TLS_CRYPT_MODE ProcessMode,
|
||
|
IN OUT NET_FRAGMENT *Fragment
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
UINT8 *Buffer;
|
||
|
UINT32 BufferSize;
|
||
|
UINT32 BytesCopied;
|
||
|
EFI_TLS_FRAGMENT_DATA *FragmentTable;
|
||
|
UINT32 FragmentCount;
|
||
|
EFI_TLS_FRAGMENT_DATA *OriginalFragmentTable;
|
||
|
UINTN Index;
|
||
|
|
||
|
Status = EFI_SUCCESS;
|
||
|
Buffer = NULL;
|
||
|
BufferSize = 0;
|
||
|
BytesCopied = 0;
|
||
|
FragmentTable = NULL;
|
||
|
OriginalFragmentTable = NULL;
|
||
|
|
||
|
//
|
||
|
// Rebuild fragment table from BufferIn.
|
||
|
//
|
||
|
FragmentCount = 1;
|
||
|
FragmentTable = AllocateZeroPool (FragmentCount * sizeof (EFI_TLS_FRAGMENT_DATA));
|
||
|
if (FragmentTable == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
FragmentTable->FragmentLength = (UINT32) MessageSize;
|
||
|
FragmentTable->FragmentBuffer = Message;
|
||
|
|
||
|
//
|
||
|
// Record the original FragmentTable.
|
||
|
//
|
||
|
OriginalFragmentTable = FragmentTable;
|
||
|
|
||
|
//
|
||
|
// Process the Message.
|
||
|
//
|
||
|
Status = HttpInstance->Tls->ProcessPacket (
|
||
|
HttpInstance->Tls,
|
||
|
&FragmentTable,
|
||
|
&FragmentCount,
|
||
|
ProcessMode
|
||
|
);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Calculate the size according to FragmentTable.
|
||
|
//
|
||
|
for (Index = 0; Index < FragmentCount; Index++) {
|
||
|
BufferSize += FragmentTable[Index].FragmentLength;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Allocate buffer for processed data.
|
||
|
//
|
||
|
Buffer = AllocateZeroPool (BufferSize);
|
||
|
if (Buffer == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
goto ON_EXIT;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Copy the new FragmentTable buffer into Buffer.
|
||
|
//
|
||
|
for (Index = 0; Index < FragmentCount; Index++) {
|
||
|
CopyMem (
|
||
|
(Buffer + BytesCopied),
|
||
|
FragmentTable[Index].FragmentBuffer,
|
||
|
FragmentTable[Index].FragmentLength
|
||
|
);
|
||
|
BytesCopied += FragmentTable[Index].FragmentLength;
|
||
|
|
||
|
//
|
||
|
// Free the FragmentBuffer since it has been copied.
|
||
|
//
|
||
|
FreePool (FragmentTable[Index].FragmentBuffer);
|
||
|
}
|
||
|
|
||
|
Fragment->Len = BufferSize;
|
||
|
Fragment->Bulk = Buffer;
|
||
|
|
||
|
ON_EXIT:
|
||
|
|
||
|
if (OriginalFragmentTable != NULL) {
|
||
|
if( FragmentTable == OriginalFragmentTable) {
|
||
|
FragmentTable = NULL;
|
||
|
}
|
||
|
FreePool (OriginalFragmentTable);
|
||
|
OriginalFragmentTable = NULL;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Caller has the responsibility to free the FragmentTable.
|
||
|
//
|
||
|
if (FragmentTable != NULL) {
|
||
|
FreePool (FragmentTable);
|
||
|
FragmentTable = NULL;
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
Receive one fragment decrypted from one TLS record.
|
||
|
|
||
|
@param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
|
||
|
@param[in, out] Fragment The received Fragment.
|
||
|
@param[in] Timeout The time to wait for connection done.
|
||
|
|
||
|
@retval EFI_SUCCESS One fragment is received.
|
||
|
@retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
|
||
|
@retval EFI_ABORTED Something wrong decryption the message.
|
||
|
@retval Others Other errors as indicated.
|
||
|
|
||
|
**/
|
||
|
EFI_STATUS
|
||
|
EFIAPI
|
||
|
HttpsReceive (
|
||
|
IN HTTP_PROTOCOL *HttpInstance,
|
||
|
IN OUT NET_FRAGMENT *Fragment,
|
||
|
IN EFI_EVENT Timeout
|
||
|
)
|
||
|
{
|
||
|
EFI_STATUS Status;
|
||
|
NET_BUF *Pdu;
|
||
|
TLS_RECORD_HEADER RecordHeader;
|
||
|
UINT8 *BufferIn;
|
||
|
UINTN BufferInSize;
|
||
|
NET_FRAGMENT TempFragment;
|
||
|
UINT8 *BufferOut;
|
||
|
UINTN BufferOutSize;
|
||
|
NET_BUF *PacketOut;
|
||
|
UINT8 *DataOut;
|
||
|
UINT8 *GetSessionDataBuffer;
|
||
|
UINTN GetSessionDataBufferSize;
|
||
|
|
||
|
Status = EFI_SUCCESS;
|
||
|
Pdu = NULL;
|
||
|
BufferIn = NULL;
|
||
|
BufferInSize = 0;
|
||
|
BufferOut = NULL;
|
||
|
BufferOutSize = 0;
|
||
|
PacketOut = NULL;
|
||
|
DataOut = NULL;
|
||
|
GetSessionDataBuffer = NULL;
|
||
|
GetSessionDataBufferSize = 0;
|
||
|
|
||
|
//
|
||
|
// Receive only one TLS record
|
||
|
//
|
||
|
Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
BufferInSize = Pdu->TotalSize;
|
||
|
BufferIn = AllocateZeroPool (BufferInSize);
|
||
|
if (BufferIn == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
NetbufFree (Pdu);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
NetbufCopy (Pdu, 0, (UINT32) BufferInSize, BufferIn);
|
||
|
|
||
|
NetbufFree (Pdu);
|
||
|
|
||
|
//
|
||
|
// Handle Receive data.
|
||
|
//
|
||
|
RecordHeader = *(TLS_RECORD_HEADER *) BufferIn;
|
||
|
|
||
|
if ((RecordHeader.ContentType == TlsContentTypeApplicationData) &&
|
||
|
(RecordHeader.Version.Major == 0x03) &&
|
||
|
(RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
|
||
|
RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
|
||
|
RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
|
||
|
) {
|
||
|
//
|
||
|
// Decrypt Packet.
|
||
|
//
|
||
|
Status = TlsProcessMessage (
|
||
|
HttpInstance,
|
||
|
BufferIn,
|
||
|
BufferInSize,
|
||
|
EfiTlsDecrypt,
|
||
|
&TempFragment
|
||
|
);
|
||
|
|
||
|
FreePool (BufferIn);
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
if (Status == EFI_ABORTED) {
|
||
|
//
|
||
|
// Something wrong decryption the message.
|
||
|
// BuildResponsePacket() will be called to generate Error Alert message and send it out.
|
||
|
//
|
||
|
BufferOutSize = DEF_BUF_LEN;
|
||
|
BufferOut = AllocateZeroPool (BufferOutSize);
|
||
|
if (BufferOut == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->BuildResponsePacket (
|
||
|
HttpInstance->Tls,
|
||
|
NULL,
|
||
|
0,
|
||
|
BufferOut,
|
||
|
&BufferOutSize
|
||
|
);
|
||
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
||
|
FreePool (BufferOut);
|
||
|
BufferOut = AllocateZeroPool (BufferOutSize);
|
||
|
if (BufferOut == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->BuildResponsePacket (
|
||
|
HttpInstance->Tls,
|
||
|
NULL,
|
||
|
0,
|
||
|
BufferOut,
|
||
|
&BufferOutSize
|
||
|
);
|
||
|
}
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreePool(BufferOut);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
if (BufferOutSize != 0) {
|
||
|
PacketOut = NetbufAlloc ((UINT32)BufferOutSize);
|
||
|
DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
|
||
|
if (DataOut == NULL) {
|
||
|
FreePool (BufferOut);
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
CopyMem (DataOut, BufferOut, BufferOutSize);
|
||
|
|
||
|
Status = TlsCommonTransmit (HttpInstance, PacketOut);
|
||
|
|
||
|
NetbufFree (PacketOut);
|
||
|
}
|
||
|
|
||
|
FreePool(BufferOut);
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
//
|
||
|
// Parsing buffer.
|
||
|
//
|
||
|
ASSERT (((TLS_RECORD_HEADER *) (TempFragment.Bulk))->ContentType == TlsContentTypeApplicationData);
|
||
|
|
||
|
BufferInSize = ((TLS_RECORD_HEADER *) (TempFragment.Bulk))->Length;
|
||
|
BufferIn = AllocateZeroPool (BufferInSize);
|
||
|
if (BufferIn == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
CopyMem (BufferIn, TempFragment.Bulk + TLS_RECORD_HEADER_LENGTH, BufferInSize);
|
||
|
|
||
|
//
|
||
|
// Free the buffer in TempFragment.
|
||
|
//
|
||
|
FreePool (TempFragment.Bulk);
|
||
|
|
||
|
} else if ((RecordHeader.ContentType == TlsContentTypeAlert) &&
|
||
|
(RecordHeader.Version.Major == 0x03) &&
|
||
|
(RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
|
||
|
RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
|
||
|
RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
|
||
|
) {
|
||
|
BufferOutSize = DEF_BUF_LEN;
|
||
|
BufferOut = AllocateZeroPool (BufferOutSize);
|
||
|
if (BufferOut == NULL) {
|
||
|
FreePool (BufferIn);
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->BuildResponsePacket (
|
||
|
HttpInstance->Tls,
|
||
|
BufferIn,
|
||
|
BufferInSize,
|
||
|
BufferOut,
|
||
|
&BufferOutSize
|
||
|
);
|
||
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
||
|
FreePool (BufferOut);
|
||
|
BufferOut = AllocateZeroPool (BufferOutSize);
|
||
|
if (BufferOut == NULL) {
|
||
|
FreePool (BufferIn);
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->BuildResponsePacket (
|
||
|
HttpInstance->Tls,
|
||
|
BufferIn,
|
||
|
BufferInSize,
|
||
|
BufferOut,
|
||
|
&BufferOutSize
|
||
|
);
|
||
|
}
|
||
|
|
||
|
FreePool (BufferIn);
|
||
|
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreePool (BufferOut);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
if (BufferOutSize != 0) {
|
||
|
PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
|
||
|
DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
|
||
|
if (DataOut == NULL) {
|
||
|
FreePool (BufferOut);
|
||
|
return EFI_OUT_OF_RESOURCES;
|
||
|
}
|
||
|
|
||
|
CopyMem (DataOut, BufferOut, BufferOutSize);
|
||
|
|
||
|
Status = TlsCommonTransmit (HttpInstance, PacketOut);
|
||
|
|
||
|
NetbufFree (PacketOut);
|
||
|
}
|
||
|
|
||
|
FreePool (BufferOut);
|
||
|
|
||
|
//
|
||
|
// Get the session state.
|
||
|
//
|
||
|
GetSessionDataBufferSize = DEF_BUF_LEN;
|
||
|
GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
|
||
|
if (GetSessionDataBuffer == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->GetSessionData (
|
||
|
HttpInstance->Tls,
|
||
|
EfiTlsSessionState,
|
||
|
GetSessionDataBuffer,
|
||
|
&GetSessionDataBufferSize
|
||
|
);
|
||
|
if (Status == EFI_BUFFER_TOO_SMALL) {
|
||
|
FreePool (GetSessionDataBuffer);
|
||
|
GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
|
||
|
if (GetSessionDataBuffer == NULL) {
|
||
|
Status = EFI_OUT_OF_RESOURCES;
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
Status = HttpInstance->Tls->GetSessionData (
|
||
|
HttpInstance->Tls,
|
||
|
EfiTlsSessionState,
|
||
|
GetSessionDataBuffer,
|
||
|
&GetSessionDataBufferSize
|
||
|
);
|
||
|
}
|
||
|
if (EFI_ERROR (Status)) {
|
||
|
FreePool (GetSessionDataBuffer);
|
||
|
return Status;
|
||
|
}
|
||
|
|
||
|
ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
|
||
|
HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;
|
||
|
|
||
|
FreePool (GetSessionDataBuffer);
|
||
|
|
||
|
if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
|
||
|
DEBUG ((EFI_D_ERROR, "TLS Session State Error!\n"));
|
||
|
return EFI_ABORTED;
|
||
|
}
|
||
|
|
||
|
BufferIn = NULL;
|
||
|
BufferInSize = 0;
|
||
|
}
|
||
|
|
||
|
Fragment->Bulk = BufferIn;
|
||
|
Fragment->Len = (UINT32) BufferInSize;
|
||
|
|
||
|
return Status;
|
||
|
}
|
||
|
|