|  | /** @file | 
|  | Miscellaneous routines specific to Https for HttpDxe driver. | 
|  |  | 
|  | Copyright (c) 2016, Intel Corporation. All rights reserved.<BR> | 
|  | (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR> | 
|  | This program and the accompanying materials | 
|  | are licensed and made available under the terms and conditions of the BSD License | 
|  | which accompanies this distribution.  The full text of the license may be found at | 
|  | http://opensource.org/licenses/bsd-license.php | 
|  |  | 
|  | THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS, | 
|  | WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED. | 
|  |  | 
|  | **/ | 
|  |  | 
|  | #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] 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_TLS_PROTOCOL               **TlsProto, | 
|  | OUT EFI_TLS_CONFIGURATION_PROTOCOL **TlsConfiguration | 
|  | ) | 
|  | { | 
|  | EFI_STATUS                    Status; | 
|  | EFI_SERVICE_BINDING_PROTOCOL  *TlsSb; | 
|  | EFI_HANDLE                    TlsChildHandle; | 
|  |  | 
|  | TlsSb          = NULL; | 
|  | 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               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. | 
|  | // Fall back to the default value. | 
|  | // | 
|  | FreePool (CACert); | 
|  |  | 
|  | return EFI_NOT_FOUND; | 
|  | } | 
|  |  | 
|  | ASSERT (CACert != NULL); | 
|  |  | 
|  | // | 
|  | // 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)) { | 
|  | FreePool (CACert); | 
|  | return Status; | 
|  | } | 
|  |  | 
|  | Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize); | 
|  | } | 
|  |  | 
|  | ItemDataSize -= CertList->SignatureListSize; | 
|  | CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize); | 
|  | } | 
|  |  | 
|  | FreePool (CACert); | 
|  | 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 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     = sizeof (TLS_RECORD_HEADER); | 
|  | 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 == TLS_CONTENT_TYPE_HANDSHAKE || | 
|  | RecordHeader.ContentType == TLS_CONTENT_TYPE_ALERT || | 
|  | RecordHeader.ContentType == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC || | 
|  | RecordHeader.ContentType == TLS_CONTENT_TYPE_APPLICATION_DATA) && | 
|  | (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); | 
|  |  | 
|  | if (EFI_ERROR (Status)) { | 
|  | return Status; | 
|  | } | 
|  |  | 
|  | 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. | 
|  | @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. | 
|  |  | 
|  | @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) { | 
|  | 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 == TLS_CONTENT_TYPE_APPLICATION_DATA) && | 
|  | (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 == TLS_CONTENT_TYPE_APPLICATION_DATA); | 
|  |  | 
|  | BufferInSize = ((TLS_RECORD_HEADER *) (TempFragment.Bulk))->Length; | 
|  | BufferIn = AllocateZeroPool (BufferInSize); | 
|  | if (BufferIn == NULL) { | 
|  | Status = EFI_OUT_OF_RESOURCES; | 
|  | return Status; | 
|  | } | 
|  |  | 
|  | CopyMem (BufferIn, TempFragment.Bulk + sizeof (TLS_RECORD_HEADER), BufferInSize); | 
|  |  | 
|  | // | 
|  | // Free the buffer in TempFragment. | 
|  | // | 
|  | FreePool (TempFragment.Bulk); | 
|  |  | 
|  | } else if ((RecordHeader.ContentType == TLS_CONTENT_TYPE_ALERT) && | 
|  | (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; | 
|  | } |