public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Wu, Jiaxin" <jiaxin.wu@intel.com>
To: "Fu, Siyuan" <siyuan.fu@intel.com>,
	"edk2-devel@lists.01.org" <edk2-devel@lists.01.org>
Cc: "Ye, Ting" <ting.ye@intel.com>,
	"Zhang, Lubo" <lubo.zhang@intel.com>,
	"Long, Qin" <qin.long@intel.com>,
	Thomas Palmer <thomas.palmer@hpe.com>
Subject: Re: [Patch 07/10] NetworkPkg/HttpDxe: HTTPS support over IPv4 and IPv6
Date: Thu, 15 Dec 2016 07:14:53 +0000	[thread overview]
Message-ID: <895558F6EA4E3B41AC93A00D163B72741627F514@SHSMSX103.ccr.corp.intel.com> (raw)
In-Reply-To: <B1FF2E9001CE9041BD10B825821D5BC58A88641B@SHSMSX151.ccr.corp.intel.com>

Good suggestion, I will change the flag to "https://" before commit the patch.

Even we have a library to get the URI scheme, we still need check whether it's http or https.

Thanks,
Jiaxin


> -----Original Message-----
> From: Fu, Siyuan
> Sent: Thursday, December 15, 2016 10:39 AM
> To: Wu, Jiaxin <jiaxin.wu@intel.com>; edk2-devel@lists.01.org
> Cc: Ye, Ting <ting.ye@intel.com>; Zhang, Lubo <lubo.zhang@intel.com>;
> Long, Qin <qin.long@intel.com>; Thomas Palmer <thomas.palmer@hpe.com>
> Subject: RE: [Patch 07/10] NetworkPkg/HttpDxe: HTTPS support over IPv4
> and IPv6
> 
> Hi, Jiaxin
> 
> In function IsHttpsUrl(), I suggest to search string "https://" instead of only
> "https", in case of some incorrect scheme like "httpsabc://".
> However, since there is already code to parse the URL by using
> HttpParseUrl(), the scheme should already been known by the Http url
> parser, I think it better to add a new function to the HttpLib like
> HttpUrlGetScheme().
> 
> Reviewed-by: Fu Siyuan <siyuan.fu@intel.com>
> 
> 
> -----Original Message-----
> From: Wu, Jiaxin
> Sent: 2016年12月14日 15:34
> To: edk2-devel@lists.01.org
> Cc: Ye, Ting <ting.ye@intel.com>; Fu, Siyuan <siyuan.fu@intel.com>; Zhang,
> Lubo <lubo.zhang@intel.com>; Long, Qin <qin.long@intel.com>; Thomas
> Palmer <thomas.palmer@hpe.com>; Wu, Jiaxin <jiaxin.wu@intel.com>
> Subject: [Patch 07/10] NetworkPkg/HttpDxe: HTTPS support over IPv4 and
> IPv6
> 
> This patch is used to enable HTTPS feature. HttpDxe driver
> will consume TlsDxe driver. It can both support http and https
> feature, that’s depended on the information of URL, the HTTP
> instance can be able to determine whether to use http or https.
> 
> Cc: Ye Ting <ting.ye@intel.com>
> Cc: Fu Siyuan <siyuan.fu@intel.com>
> Cc: Zhang Lubo <lubo.zhang@intel.com>
> Cc: Long Qin <qin.long@intel.com>
> Cc: Thomas Palmer <thomas.palmer@hpe.com>
> Contributed-under: TianoCore Contribution Agreement 1.0
> Signed-off-by: Wu Jiaxin <jiaxin.wu@intel.com>
> ---
>  NetworkPkg/HttpDxe/HttpDriver.h   |   10 +-
>  NetworkPkg/HttpDxe/HttpDxe.inf    |   12 +-
>  NetworkPkg/HttpDxe/HttpImpl.c     |  252 +++++-
>  NetworkPkg/HttpDxe/HttpProto.c    |  464 +++++++---
>  NetworkPkg/HttpDxe/HttpProto.h    |   65 +-
>  NetworkPkg/HttpDxe/HttpsSupport.c | 1692
> +++++++++++++++++++++++++++++++++++++
>  NetworkPkg/HttpDxe/HttpsSupport.h |  260 ++++++
>  7 files changed, 2601 insertions(+), 154 deletions(-)
>  create mode 100644 NetworkPkg/HttpDxe/HttpsSupport.c
>  create mode 100644 NetworkPkg/HttpDxe/HttpsSupport.h
> 
> diff --git a/NetworkPkg/HttpDxe/HttpDriver.h
> b/NetworkPkg/HttpDxe/HttpDriver.h
> index fa2372c..93a412a 100644
> --- a/NetworkPkg/HttpDxe/HttpDriver.h
> +++ b/NetworkPkg/HttpDxe/HttpDriver.h
> @@ -22,10 +22,11 @@
> 
>  //
>  // Libraries
>  //
>  #include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
>  #include <Library/MemoryAllocationLib.h>
>  #include <Library/BaseLib.h>
>  #include <Library/UefiLib.h>
>  #include <Library/DebugLib.h>
>  #include <Library/NetLib.h>
> @@ -48,17 +49,23 @@
>  #include <Protocol/Tcp6.h>
>  #include <Protocol/Dns4.h>
>  #include <Protocol/Dns6.h>
>  #include <Protocol/Ip4Config2.h>
>  #include <Protocol/Ip6Config.h>
> +#include <Protocol/Tls.h>
> +#include <Protocol/TlsConfig.h>
> 
> -
> +#include <Guid/ImageAuthentication.h>
>  //
>  // Produced Protocols
>  //
>  #include <Protocol/Http.h>
> 
> +#include <Guid/TlsAuthentication.h>
> +
> +#include <IndustryStandard/Tls1.h>
> +
>  //
>  // Driver Version
>  //
>  #define HTTP_DRIVER_VERSION 0xa
> 
> @@ -77,10 +84,11 @@ extern EFI_HTTP_UTILITIES_PROTOCOL
> *mHttpUtilities;
>  // Include files with function prototypes
>  //
>  #include "ComponentName.h"
>  #include "HttpImpl.h"
>  #include "HttpProto.h"
> +#include "HttpsSupport.h"
>  #include "HttpDns.h"
> 
>  typedef struct {
>    EFI_SERVICE_BINDING_PROTOCOL  *ServiceBinding;
>    UINTN                         NumberOfChildren;
> diff --git a/NetworkPkg/HttpDxe/HttpDxe.inf
> b/NetworkPkg/HttpDxe/HttpDxe.inf
> index bf2cbee..1118181 100644
> --- a/NetworkPkg/HttpDxe/HttpDxe.inf
> +++ b/NetworkPkg/HttpDxe/HttpDxe.inf
> @@ -1,9 +1,9 @@
>  ## @file
>  #  Implementation of EFI HTTP protocol interfaces.
>  #
> -#  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
> +#  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<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.
> @@ -24,10 +24,11 @@
>    MODULE_UNI_FILE           = HttpDxe.uni
> 
>  [Packages]
>    MdePkg/MdePkg.dec
>    MdeModulePkg/MdeModulePkg.dec
> +  NetworkPkg/NetworkPkg.dec
> 
>  [Sources]
>    ComponentName.h
>    ComponentName.c
>    HttpDns.h
> @@ -36,14 +37,17 @@
>    HttpDriver.c
>    HttpImpl.h
>    HttpImpl.c
>    HttpProto.h
>    HttpProto.c
> +  HttpsSupport.h
> +  HttpsSupport.c
> 
>  [LibraryClasses]
>    UefiDriverEntryPoint
>    UefiBootServicesTableLib
> +  UefiRuntimeServicesTableLib
>    MemoryAllocationLib
>    BaseLib
>    UefiLib
>    DebugLib
>    NetLib
> @@ -62,8 +66,14 @@
>    gEfiDns4ProtocolGuid                             ## SOMETIMES_CONSUMES
>    gEfiDns6ServiceBindingProtocolGuid               ## SOMETIMES_CONSUMES
>    gEfiDns6ProtocolGuid                             ## SOMETIMES_CONSUMES
>    gEfiIp4Config2ProtocolGuid                       ## SOMETIMES_CONSUMES
>    gEfiIp6ConfigProtocolGuid                        ## SOMETIMES_CONSUMES
> +  gEfiTlsServiceBindingProtocolGuid                ## SOMETIMES_CONSUMES
> +  gEfiTlsProtocolGuid                              ## SOMETIMES_CONSUMES
> +  gEfiTlsConfigurationProtocolGuid                 ## SOMETIMES_CONSUMES
> +
> +[Guids]
> +  gEfiTlsCaCertificateGuid                         ## CONSUMES  ## GUID
> 
>  [UserExtensions.TianoCore."ExtraFiles"]
>    HttpDxeExtra.uni
> \ No newline at end of file
> diff --git a/NetworkPkg/HttpDxe/HttpImpl.c
> b/NetworkPkg/HttpDxe/HttpImpl.c
> index 6fcb0b7..77aa64a 100644
> --- a/NetworkPkg/HttpDxe/HttpImpl.c
> +++ b/NetworkPkg/HttpDxe/HttpImpl.c
> @@ -239,10 +239,11 @@ EfiHttpRequest (
>    UINTN                         HostNameSize;
>    UINT16                        RemotePort;
>    HTTP_PROTOCOL                 *HttpInstance;
>    BOOLEAN                       Configure;
>    BOOLEAN                       ReConfigure;
> +  BOOLEAN                       TlsConfigure;
>    CHAR8                         *RequestMsg;
>    CHAR8                         *Url;
>    UINTN                         UrlLen;
>    CHAR16                        *HostNameStr;
>    HTTP_TOKEN_WRAP               *Wrap;
> @@ -258,10 +259,11 @@ EfiHttpRequest (
>    HostName = NULL;
>    RequestMsg = NULL;
>    HostNameStr = NULL;
>    Wrap = NULL;
>    FileUrl = NULL;
> +  TlsConfigure = FALSE;
> 
>    if ((This == NULL) || (Token == NULL)) {
>      return EFI_INVALID_PARAMETER;
>    }
> 
> @@ -343,10 +345,36 @@ EfiHttpRequest (
>        HttpInstance->Url = Url;
>      }
> 
> 
>      UnicodeStrToAsciiStrS (Request->Url, Url, UrlLen);
> +
> +    //
> +    // From the information in Url, the HTTP instance will
> +    // be able to determine whether to use http or https.
> +    //
> +    HttpInstance->UseHttps = IsHttpsUrl (Url);
> +
> +    //
> +    // Check whether we need to create Tls child and open the TLS protocol.
> +    //
> +    if (HttpInstance->UseHttps && HttpInstance->TlsChildHandle == NULL) {
> +      //
> +      // Use TlsSb to create Tls child and open the TLS protocol.
> +      //
> +      HttpInstance->TlsChildHandle = TlsCreateChild (
> +                                       HttpInstance->Service->ImageHandle,
> +                                       &(HttpInstance->Tls),
> +                                       &(HttpInstance->TlsConfiguration)
> +                                       );
> +      if (HttpInstance->TlsChildHandle == NULL) {
> +        return EFI_DEVICE_ERROR;
> +      }
> +
> +      TlsConfigure = TRUE;
> +    }
> +
>      UrlParser = NULL;
>      Status = HttpParseUrl (Url, (UINT32) AsciiStrLen (Url), FALSE, &UrlParser);
>      if (EFI_ERROR (Status)) {
>        goto Error1;
>      }
> @@ -357,11 +385,15 @@ EfiHttpRequest (
>       goto Error1;
>      }
> 
>      Status = HttpUrlGetPort (Url, UrlParser, &RemotePort);
>      if (EFI_ERROR (Status)) {
> -      RemotePort = HTTP_DEFAULT_PORT;
> +      if (HttpInstance->UseHttps) {
> +        RemotePort = HTTPS_DEFAULT_PORT;
> +      } else {
> +        RemotePort = HTTP_DEFAULT_PORT;
> +      }
>      }
>      //
>      // If Configure is TRUE, it indicates the first time to call Request();
>      // If ReConfigure is TRUE, it indicates the request URL is not same
>      // with the previous call to Request();
> @@ -374,13 +406,17 @@ EfiHttpRequest (
>        // Request() is called the first time.
>        //
>        ReConfigure = FALSE;
>      } else {
>        if ((HttpInstance->RemotePort == RemotePort) &&
> -        (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0)) {
> +          (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0) &&
> +          (!HttpInstance->UseHttps || (HttpInstance->UseHttps &&
> +                                       !TlsConfigure &&
> +                                       HttpInstance->TlsSessionState ==
> EfiTlsSessionDataTransferring))) {
>          //
>          // Host Name and port number of the request URL are the same with
> previous call to Request().
> +        // If Https protocol used, the corresponding SessionState is
> EfiTlsSessionDataTransferring.
>          // Check whether previous TCP packet sent out.
>          //
> 
>          if (EFI_ERROR (NetMapIterate (&HttpInstance->TxTokens,
> HttpTcpNotReady, NULL))) {
>            //
> @@ -480,10 +516,20 @@ EfiHttpRequest (
>      if (!HttpInstance->LocalAddressIsIPv6) {
>        ASSERT (HttpInstance->Tcp4 != NULL);
>      } else {
>        ASSERT (HttpInstance->Tcp6 != NULL);
>      }
> +
> +    if (HttpInstance->UseHttps && !TlsConfigure) {
> +      Status = TlsCloseSession (HttpInstance);
> +      if (EFI_ERROR (Status)) {
> +        goto Error1;
> +      }
> +
> +      TlsCloseTxRxEvent (HttpInstance);
> +    }
> +
>      HttpCloseConnection (HttpInstance);
>      EfiHttpCancel (This, NULL);
>    }
> 
>    //
> @@ -498,17 +544,22 @@ EfiHttpRequest (
>    Wrap->HttpToken      = Token;
>    Wrap->HttpInstance   = HttpInstance;
>    if (Request != NULL) {
>      Wrap->TcpWrap.Method = Request->Method;
>    }
> -
> -  Status = HttpInitTcp (HttpInstance, Wrap, Configure);
> +
> +  Status = HttpInitSession (
> +             HttpInstance,
> +             Wrap,
> +             Configure || ReConfigure,
> +             TlsConfigure
> +             );
>    if (EFI_ERROR (Status)) {
>      goto Error2;
> -  }
> +  }
> 
> -  if (!Configure) {
> +  if (!Configure && !ReConfigure && !TlsConfigure) {
>      //
>      // For the new HTTP token, create TX TCP token events.
>      //
>      Status = HttpCreateTcpTxEvent (Wrap);
>      if (EFI_ERROR (Status)) {
> @@ -591,13 +642,18 @@ Error4:
>    if (RequestMsg != NULL) {
>      FreePool (RequestMsg);
>    }
> 
>  Error3:
> -  HttpCloseConnection (HttpInstance);
> +  if (HttpInstance->UseHttps) {
> +    TlsCloseSession (HttpInstance);
> +    TlsCloseTxRxEvent (HttpInstance);
> +  }
> 
>  Error2:
> +  HttpCloseConnection (HttpInstance);
> +
>    HttpCloseTcpConnCloseEvent (HttpInstance);
>    if (NULL != Wrap->TcpWrap.Tx4Token.CompletionToken.Event) {
>      gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);
>      Wrap->TcpWrap.Tx4Token.CompletionToken.Event = NULL;
>    }
> @@ -729,26 +785,34 @@ HttpCancel (
>      } else {
>        return Status;
>      }
>    }
> 
> -  //
> -  // Then check the tokens queued by EfiHttpResponse().
> -  //
> -  Status = NetMapIterate (&HttpInstance->RxTokens, HttpCancelTokens,
> Token);
> -  if (EFI_ERROR (Status)) {
> -    if (Token != NULL) {
> -      if (Status == EFI_ABORTED) {
> -        return EFI_SUCCESS;
> +  if (!HttpInstance->UseHttps) {
> +    //
> +    // Then check the tokens queued by EfiHttpResponse(), except for Https.
> +    //
> +    Status = NetMapIterate (&HttpInstance->RxTokens, HttpCancelTokens,
> Token);
> +    if (EFI_ERROR (Status)) {
> +      if (Token != NULL) {
> +        if (Status == EFI_ABORTED) {
> +          return EFI_SUCCESS;
> +        } else {
> +          return EFI_NOT_FOUND;
> +        }
>        } else {
> -        return EFI_NOT_FOUND;
> +        return Status;
>        }
> +    }
> +  } else {
> +    if (!HttpInstance->LocalAddressIsIPv6) {
> +      HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &HttpInstance-
> >Tcp4TlsRxToken.CompletionToken);
>      } else {
> -      return Status;
> +      HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &HttpInstance-
> >Tcp6TlsRxToken.CompletionToken);
>      }
>    }
> -
> +
>    return EFI_SUCCESS;
>  }
> 
> 
>  /**
> @@ -880,10 +944,11 @@ HttpResponseWorker (
>    HTTP_PROTOCOL                 *HttpInstance;
>    EFI_HTTP_TOKEN                *Token;
>    NET_MAP_ITEM                  *Item;
>    HTTP_TOKEN_WRAP               *ValueInItem;
>    UINTN                         HdrLen;
> +  NET_FRAGMENT                  Fragment;
> 
>    if (Wrap == NULL || Wrap->HttpInstance == NULL) {
>      return EFI_INVALID_PARAMETER;
>    }
> 
> @@ -897,21 +962,15 @@ HttpResponseWorker (
>    HttpHeaders               = NULL;
>    SizeofHeaders             = 0;
>    BufferSize                = 0;
>    EndofHeader               = NULL;
>    ValueInItem               = NULL;
> +  Fragment.Len              = 0;
> +  Fragment.Bulk             = NULL;
> 
>    if (HttpMsg->Data.Response != NULL) {
>      //
> -    // Need receive the HTTP headers, prepare buffer.
> -    //
> -    Status = HttpCreateTcpRxEventForHeader (HttpInstance);
> -    if (EFI_ERROR (Status)) {
> -      goto Error;
> -    }
> -
> -    //
>      // Check whether we have cached header from previous call.
>      //
>      if ((HttpInstance->CacheBody != NULL) && (HttpInstance->NextMsg !=
> NULL)) {
>        //
>        // The data is stored at [NextMsg, CacheBody + CacheLen].
> @@ -1198,13 +1257,120 @@ HttpResponseWorker (
>    ASSERT (HttpInstance->MsgParser != NULL);
> 
>    //
>    // We still need receive more data when there is no cache data and
> MsgParser is not NULL;
>    //
> -  Status = HttpTcpReceiveBody (Wrap, HttpMsg);
> -  if (EFI_ERROR (Status)) {
> -    goto Error2;
> +  if (!HttpInstance->UseHttps) {
> +    Status = HttpTcpReceiveBody (Wrap, HttpMsg);
> +
> +    if (EFI_ERROR (Status)) {
> +      goto Error2;
> +    }
> +
> +  } else {
> +    if (HttpInstance->TimeoutEvent == NULL) {
> +      //
> +      // Create TimeoutEvent for response
> +      //
> +      Status = gBS->CreateEvent (
> +                      EVT_TIMER,
> +                      TPL_CALLBACK,
> +                      NULL,
> +                      NULL,
> +                      &HttpInstance->TimeoutEvent
> +                      );
> +      if (EFI_ERROR (Status)) {
> +        goto Error2;
> +      }
> +    }
> +
> +    //
> +    // Start the timer, and wait Timeout seconds to receive the body packet.
> +    //
> +    Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative,
> HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);
> +    if (EFI_ERROR (Status)) {
> +      goto Error2;
> +    }
> +
> +    Status = HttpsReceive (HttpInstance, &Fragment, HttpInstance-
> >TimeoutEvent);
> +
> +    gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
> +
> +    if (EFI_ERROR (Status)) {
> +      goto Error2;
> +    }
> +
> +    //
> +    // Check whether we receive a complete HTTP message.
> +    //
> +    Status = HttpParseMessageBody (
> +               HttpInstance->MsgParser,
> +               (UINTN) Fragment.Len,
> +               (CHAR8 *) Fragment.Bulk
> +               );
> +    if (EFI_ERROR (Status)) {
> +      goto Error2;
> +    }
> +
> +    if (HttpIsMessageComplete (HttpInstance->MsgParser)) {
> +      //
> +      // Free the MsgParse since we already have a full HTTP message.
> +      //
> +      HttpFreeMsgParser (HttpInstance->MsgParser);
> +      HttpInstance->MsgParser = NULL;
> +    }
> +
> +    //
> +    // We receive part of header of next HTTP msg.
> +    //
> +    if (HttpInstance->NextMsg != NULL) {
> +      HttpMsg->BodyLength = MIN ((UINTN) (HttpInstance->NextMsg -
> (CHAR8 *) Fragment.Bulk), HttpMsg->BodyLength);
> +      CopyMem (HttpMsg->Body, Fragment.Bulk, HttpMsg->BodyLength);
> +
> +      HttpInstance->CacheLen = Fragment.Len - HttpMsg->BodyLength;
> +      if (HttpInstance->CacheLen != 0) {
> +        if (HttpInstance->CacheBody != NULL) {
> +          FreePool (HttpInstance->CacheBody);
> +        }
> +
> +        HttpInstance->CacheBody = AllocateZeroPool (HttpInstance-
> >CacheLen);
> +        if (HttpInstance->CacheBody == NULL) {
> +          Status = EFI_OUT_OF_RESOURCES;
> +          goto Error2;
> +        }
> +
> +        CopyMem (HttpInstance->CacheBody, Fragment.Bulk + HttpMsg-
> >BodyLength, HttpInstance->CacheLen);
> +        HttpInstance->CacheOffset = 0;
> +
> +        HttpInstance->NextMsg = HttpInstance->CacheBody + (UINTN)
> (HttpInstance->NextMsg - (CHAR8 *) (Fragment.Bulk + HttpMsg-
> >BodyLength));
> +      }
> +    } else {
> +      HttpMsg->BodyLength = MIN (Fragment.Len, (UINT32) HttpMsg-
> >BodyLength);
> +      CopyMem (HttpMsg->Body, Fragment.Bulk, HttpMsg->BodyLength);
> +      HttpInstance->CacheLen = Fragment.Len - HttpMsg->BodyLength;
> +      if (HttpInstance->CacheLen != 0) {
> +        if (HttpInstance->CacheBody != NULL) {
> +          FreePool (HttpInstance->CacheBody);
> +        }
> +
> +        HttpInstance->CacheBody = AllocateZeroPool (HttpInstance-
> >CacheLen);
> +        if (HttpInstance->CacheBody == NULL) {
> +          Status = EFI_OUT_OF_RESOURCES;
> +          goto Error2;
> +        }
> +
> +        CopyMem (HttpInstance->CacheBody, Fragment.Bulk + HttpMsg-
> >BodyLength, HttpInstance->CacheLen);
> +        HttpInstance->CacheOffset = 0;
> +      }
> +    }
> +
> +    if (Fragment.Bulk != NULL) {
> +      FreePool (Fragment.Bulk);
> +      Fragment.Bulk = NULL;
> +    }
> +
> +    goto Exit;
>    }
> 
>    return Status;
> 
>  Exit:
> @@ -1232,19 +1398,30 @@ Error2:
>  Error:
>    Item = NetMapFindKey (&Wrap->HttpInstance->RxTokens, Wrap-
> >HttpToken);
>    if (Item != NULL) {
>      NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);
>    }
> -
> -  HttpTcpTokenCleanup (Wrap);
> +
> +  if (!HttpInstance->UseHttps) {
> +    HttpTcpTokenCleanup (Wrap);
> +  } else {
> +    FreePool (Wrap);
> +  }
> 
>    if (HttpHeaders != NULL) {
>      FreePool (HttpHeaders);
> +    HttpHeaders = NULL;
> +  }
> +
> +  if (Fragment.Bulk != NULL) {
> +    FreePool (Fragment.Bulk);
> +    Fragment.Bulk = NULL;
>    }
> 
>    if (HttpMsg->Headers != NULL) {
>      FreePool (HttpMsg->Headers);
> +    HttpMsg->Headers = NULL;
>    }
> 
>    if (HttpInstance->CacheBody != NULL) {
>      FreePool (HttpInstance->CacheBody);
>      HttpInstance->CacheBody = NULL;
> @@ -1351,13 +1528,20 @@ EfiHttpResponse (
>    }
> 
>    Wrap->HttpInstance = HttpInstance;
>    Wrap->HttpToken    = Token;
> 
> -  Status = HttpCreateTcpRxEvent (Wrap);
> -  if (EFI_ERROR (Status)) {
> -    goto Error;
> +  //
> +  // Notes: For Https, receive token wrapped in HTTP_TOKEN_WRAP is not
> used to
> +  // receive the https response. A special TlsRxToken is used for receiving
> TLS
> +  // related messages. It should be a blocking response.
> +  //
> +  if (!HttpInstance->UseHttps) {
> +    Status = HttpCreateTcpRxEvent (Wrap);
> +    if (EFI_ERROR (Status)) {
> +      goto Error;
> +    }
>    }
> 
>    Status = NetMapInsertTail (&HttpInstance->RxTokens, Token, Wrap);
>    if (EFI_ERROR (Status)) {
>      goto Error;
> diff --git a/NetworkPkg/HttpDxe/HttpProto.c
> b/NetworkPkg/HttpDxe/HttpProto.c
> index 6373f07..77a3ee3 100644
> --- a/NetworkPkg/HttpDxe/HttpProto.c
> +++ b/NetworkPkg/HttpDxe/HttpProto.c
> @@ -926,10 +926,26 @@ HttpCleanProtocol (
>             HttpInstance->Service->ImageHandle,
>             HttpInstance->Handle
>             );
>    }
> 
> +  if (HttpInstance->TlsConfigData.CACert != NULL) {
> +    FreePool (HttpInstance->TlsConfigData.CACert);
> +    HttpInstance->TlsConfigData.CACert = NULL;
> +  }
> +
> +  if (HttpInstance->TlsConfigData.ClientCert != NULL) {
> +    FreePool (HttpInstance->TlsConfigData.ClientCert);
> +    HttpInstance->TlsConfigData.ClientCert = NULL;
> +  }
> +
> +  if (HttpInstance->TlsConfigData.ClientPrivateKey != NULL) {
> +    FreePool (HttpInstance->TlsConfigData.ClientPrivateKey);
> +    HttpInstance->TlsConfigData.ClientPrivateKey = NULL;
> +  }
> +
> +  TlsCloseTxRxEvent (HttpInstance);
>  }
> 
>  /**
>    Establish TCP connection with HTTP server.
> 
> @@ -1183,11 +1199,12 @@ HttpConfigureTcp6 (
>    return EFI_SUCCESS;
> 
>  }
> 
>  /**
> -  Check existing TCP connection, if in error state, recover TCP4 connection.
> +  Check existing TCP connection, if in error state, recover TCP4 connection.
> Then,
> +  connect one TLS session if required.
> 
>    @param[in]  HttpInstance       The HTTP instance private data.
> 
>    @retval EFI_SUCCESS            The TCP connection is established.
>    @retval EFI_NOT_READY          TCP4 protocol child is not created or
> configured.
> @@ -1224,15 +1241,62 @@ HttpConnectTcp4 (
>      return EFI_SUCCESS;
>    } else if (Tcp4State > Tcp4StateEstablished ) {
>      HttpCloseConnection(HttpInstance);
>    }
> 
> -  return HttpCreateConnection (HttpInstance);
> +  Status = HttpCreateConnection (HttpInstance);
> +  if (EFI_ERROR(Status)){
> +    DEBUG ((EFI_D_ERROR, "Tcp4 Connection fail - %x\n", Status));
> +    return Status;
> +  }
> +
> +  //
> +  // Tls session connection.
> +  //
> +  if (HttpInstance->UseHttps) {
> +    if (HttpInstance->TimeoutEvent == NULL) {
> +      //
> +      // Create TimeoutEvent for TLS connection.
> +      //
> +      Status = gBS->CreateEvent (
> +                      EVT_TIMER,
> +                      TPL_CALLBACK,
> +                      NULL,
> +                      NULL,
> +                      &HttpInstance->TimeoutEvent
> +                      );
> +      if (EFI_ERROR (Status)) {
> +        TlsCloseTxRxEvent (HttpInstance);
> +        return Status;
> +      }
> +    }
> +
> +    //
> +    // Start the timer, and wait Timeout seconds for connection.
> +    //
> +    Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative,
> HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
> +    if (EFI_ERROR (Status)) {
> +      TlsCloseTxRxEvent (HttpInstance);
> +      return Status;
> +    }
> +
> +    Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
> +
> +    gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
> +
> +    if (EFI_ERROR (Status)) {
> +      TlsCloseTxRxEvent (HttpInstance);
> +      return Status;
> +    }
> +  }
> +
> +  return Status;
>  }
> 
>  /**
> -  Check existing TCP connection, if in error state, recover TCP6 connection.
> +  Check existing TCP connection, if in error state, recover TCP6 connection.
> Then,
> +  connect one TLS session if required.
> 
>    @param[in]  HttpInstance       The HTTP instance private data.
> 
>    @retval EFI_SUCCESS            The TCP connection is established.
>    @retval EFI_NOT_READY          TCP6 protocol child is not created or
> configured.
> @@ -1269,34 +1333,92 @@ HttpConnectTcp6 (
>      return EFI_SUCCESS;
>    } else if (Tcp6State > Tcp6StateEstablished ) {
>      HttpCloseConnection(HttpInstance);
>    }
> 
> -  return HttpCreateConnection (HttpInstance);
> +  Status = HttpCreateConnection (HttpInstance);
> +  if (EFI_ERROR(Status)){
> +    DEBUG ((EFI_D_ERROR, "Tcp6 Connection fail - %x\n", Status));
> +    return Status;
> +  }
> +
> +  //
> +  // Tls session connection.
> +  //
> +  if (HttpInstance->UseHttps) {
> +    if (HttpInstance->TimeoutEvent == NULL) {
> +      //
> +      // Create TimeoutEvent for TLS connection.
> +      //
> +      Status = gBS->CreateEvent (
> +                      EVT_TIMER,
> +                      TPL_CALLBACK,
> +                      NULL,
> +                      NULL,
> +                      &HttpInstance->TimeoutEvent
> +                      );
> +      if (EFI_ERROR (Status)) {
> +        TlsCloseTxRxEvent (HttpInstance);
> +        return Status;
> +      }
> +    }
> +
> +    //
> +    // Start the timer, and wait Timeout seconds for connection.
> +    //
> +    Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative,
> HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);
> +    if (EFI_ERROR (Status)) {
> +      TlsCloseTxRxEvent (HttpInstance);
> +      return Status;
> +    }
> +
> +    Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);
> +
> +    gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);
> +
> +    if (EFI_ERROR (Status)) {
> +      TlsCloseTxRxEvent (HttpInstance);
> +      return Status;
> +    }
> +  }
> +
> +  return Status;
>  }
> 
>  /**
> -  Initialize TCP related data.
> +  Initialize Http session.
> 
>    @param[in]  HttpInstance       The HTTP instance private data.
>    @param[in]  Wrap               The HTTP token's wrap data.
> -  @param[in]  Configure          The Flag indicates whether the first time to
> initialize Tcp.
> +  @param[in]  Configure          The Flag indicates whether need to initialize
> session.
> +  @param[in]  TlsConfigure       The Flag indicates whether it's the new Tls
> session.
> 
> -  @retval EFI_SUCCESS            The initialization of TCP instance is done.
> +  @retval EFI_SUCCESS            The initialization of session is done.
>    @retval Others                 Other error as indicated.
> 
>  **/
>  EFI_STATUS
> -HttpInitTcp (
> +HttpInitSession (
>    IN  HTTP_PROTOCOL    *HttpInstance,
>    IN  HTTP_TOKEN_WRAP  *Wrap,
> -  IN  BOOLEAN          Configure
> +  IN  BOOLEAN          Configure,
> +  IN  BOOLEAN          TlsConfigure
>    )
>  {
>    EFI_STATUS           Status;
>    ASSERT (HttpInstance != NULL);
> 
> +  //
> +  // Configure Tls session.
> +  //
> +  if (TlsConfigure) {
> +    Status = TlsConfigureSession (HttpInstance);
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +  }
> +
>    if (!HttpInstance->LocalAddressIsIPv6) {
>      //
>      // Configure TCP instance.
>      //
>      if (Configure) {
> @@ -1336,11 +1458,11 @@ HttpInitTcp (
>    return EFI_SUCCESS;
> 
>  }
> 
>  /**
> -  Send the HTTP message through TCP4 or TCP6.
> +  Send the HTTP or HTTPS message through TCP4 or TCP6.
> 
>    @param[in]  HttpInstance       The HTTP instance private data.
>    @param[in]  Wrap               The HTTP token's wrap data.
>    @param[in]  TxString           Buffer containing the HTTP message string.
>    @param[in]  TxStringLen        Length of the HTTP message string in bytes.
> @@ -1360,18 +1482,68 @@ HttpTransmitTcp (
>    EFI_STATUS                    Status;
>    EFI_TCP4_IO_TOKEN             *Tx4Token;
>    EFI_TCP4_PROTOCOL             *Tcp4;
>    EFI_TCP6_IO_TOKEN             *Tx6Token;
>    EFI_TCP6_PROTOCOL             *Tcp6;
> +  UINT8                         *Buffer;
> +  UINTN                         BufferSize;
> +  NET_FRAGMENT                  TempFragment;
> +
> +  Status                = EFI_SUCCESS;
> +  Buffer                = NULL;
> +
> +  //
> +  // Need to encrypt data.
> +  //
> +  if (HttpInstance->UseHttps) {
> +    //
> +    // Build BufferOut data
> +    //
> +    BufferSize = sizeof (TLS_RECORD_HEADER) + TxStringLen;
> +    Buffer     = AllocateZeroPool (BufferSize);
> +    if (Buffer == NULL) {
> +      Status = EFI_OUT_OF_RESOURCES;
> +      return Status;
> +    }
> +    ((TLS_RECORD_HEADER *) Buffer)->ContentType =
> TLS_CONTENT_TYPE_APPLICATION_DATA;
> +    ((TLS_RECORD_HEADER *) Buffer)->Version.Major = HttpInstance-
> >TlsConfigData.Version.Major;
> +    ((TLS_RECORD_HEADER *) Buffer)->Version.Minor = HttpInstance-
> >TlsConfigData.Version.Minor;
> +    ((TLS_RECORD_HEADER *) Buffer)->Length = (UINT16) (TxStringLen);
> +    CopyMem (Buffer + sizeof (TLS_RECORD_HEADER), TxString, TxStringLen);
> +
> +    //
> +    // Encrypt Packet.
> +    //
> +    Status = TlsProcessMessage (
> +               HttpInstance,
> +               Buffer,
> +               BufferSize,
> +               EfiTlsEncrypt,
> +               &TempFragment
> +               );
> +
> +    FreePool (Buffer);
> +
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +  }
> 
> -  if (!HttpInstance->LocalAddressIsIPv6) {
> +  if (!HttpInstance->LocalAddressIsIPv6) {
>      Tcp4 = HttpInstance->Tcp4;
>      Tx4Token = &Wrap->TcpWrap.Tx4Token;
> +
> +    if (HttpInstance->UseHttps) {
> +      Tx4Token->Packet.TxData->DataLength = TempFragment.Len;
> +      Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength =
> TempFragment.Len;
> +      Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID
> *) TempFragment.Bulk;
> +    } else {
> +      Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
> +      Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength =
> (UINT32) TxStringLen;
> +      Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID
> *) TxString;
> +    }
> 
> -    Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
> -    Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32)
> TxStringLen;
> -    Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *)
> TxString;
>      Tx4Token->CompletionToken.Status = EFI_NOT_READY;
> 
>      Wrap->TcpWrap.IsTxDone = FALSE;
>      Status  = Tcp4->Transmit (Tcp4, Tx4Token);
>      if (EFI_ERROR (Status)) {
> @@ -1380,25 +1552,31 @@ HttpTransmitTcp (
>      }
> 
>    } else {
>      Tcp6 = HttpInstance->Tcp6;
>      Tx6Token = &Wrap->TcpWrap.Tx6Token;
> -
> -    Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
> -    Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32)
> TxStringLen;
> -    Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *)
> TxString;
> +
> +    if (HttpInstance->UseHttps) {
> +      Tx6Token->Packet.TxData->DataLength = TempFragment.Len;
> +      Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength =
> TempFragment.Len;
> +      Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID
> *) TempFragment.Bulk;
> +    } else {
> +      Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen;
> +      Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength =
> (UINT32) TxStringLen;
> +      Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID
> *) TxString;
> +    }
> +
>      Tx6Token->CompletionToken.Status = EFI_NOT_READY;
> 
>      Wrap->TcpWrap.IsTxDone = FALSE;
>      Status = Tcp6->Transmit (Tcp6, Tx6Token);
>      if (EFI_ERROR (Status)) {
>        DEBUG ((EFI_D_ERROR, "Transmit failed: %r\n", Status));
>        return Status;
>      }
>    }
> 
> -
>    return Status;
>  }
> 
>  /**
>    Check whether the user's token or event has already
> @@ -1464,11 +1642,11 @@ HttpTcpNotReady (
> 
>    return EFI_SUCCESS;
>  }
> 
>  /**
> -  Transmit the HTTP mssage by processing the associated HTTP token.
> +  Transmit the HTTP or HTTPS mssage by processing the associated HTTP
> token.
> 
>    @param[in]  Map                The container of Tx4Token or Tx6Token.
>    @param[in]  Item               Current item to check against.
>    @param[in]  Context            The Token to check againist.
> 
> @@ -1588,167 +1766,235 @@ HttpTcpReceiveHeader (
>    EFI_TCP6_IO_TOKEN             *Rx6Token;
>    EFI_TCP6_PROTOCOL             *Tcp6;
>    CHAR8                         **EndofHeader;
>    CHAR8                         **HttpHeaders;
>    CHAR8                         *Buffer;
> +  NET_FRAGMENT                  Fragment;
> 
>    ASSERT (HttpInstance != NULL);
> 
>    EndofHeader = HttpInstance->EndofHeader;
>    HttpHeaders = HttpInstance->HttpHeaders;
>    Tcp4 = HttpInstance->Tcp4;
>    Tcp6 = HttpInstance->Tcp6;
>    Buffer      = NULL;
>    Rx4Token    = NULL;
>    Rx6Token    = NULL;
> +  Fragment.Len  = 0;
> +  Fragment.Bulk = NULL;
> 
>    if (HttpInstance->LocalAddressIsIPv6) {
>      ASSERT (Tcp6 != NULL);
>    } else {
>      ASSERT (Tcp4 != NULL);
>    }
> 
> -  if (!HttpInstance->LocalAddressIsIPv6) {
> -    Rx4Token = &HttpInstance->Rx4Token;
> -    Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer =
> AllocateZeroPool (DEF_BUF_LEN);
> -    if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer ==
> NULL) {
> -      Status = EFI_OUT_OF_RESOURCES;
> +  if (!HttpInstance->UseHttps) {
> +    Status = HttpCreateTcpRxEventForHeader (HttpInstance);
> +    if (EFI_ERROR (Status)) {
>        return Status;
>      }
> +  }
> +
> +  if (!HttpInstance->LocalAddressIsIPv6) {
> +    if (!HttpInstance->UseHttps) {
> +      Rx4Token = &HttpInstance->Rx4Token;
> +      Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer =
> AllocateZeroPool (DEF_BUF_LEN);
> +      if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer ==
> NULL) {
> +        Status = EFI_OUT_OF_RESOURCES;
> +        return Status;
> +      }
> +    }
> 
>      //
>      // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not
> NULL.
>      //
> -    while (*EndofHeader == NULL) {
> -      HttpInstance->IsRxDone = FALSE;
> -      Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;
> -      Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength =
> DEF_BUF_LEN;
> -      Status = Tcp4->Receive (Tcp4, Rx4Token);
> -      if (EFI_ERROR (Status)) {
> -        DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
> -        return Status;
> -      }
> -
> -      while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR
> (gBS->CheckEvent (Timeout)))) {
> -        Tcp4->Poll (Tcp4);
> +    while (*EndofHeader == NULL) {
> +      if (!HttpInstance->UseHttps) {
> +        HttpInstance->IsRxDone = FALSE;
> +        Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;
> +        Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength =
> DEF_BUF_LEN;
> +        Status = Tcp4->Receive (Tcp4, Rx4Token);
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
> +          return Status;
> +        }
> +
> +        while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR
> (gBS->CheckEvent (Timeout)))) {
> +          Tcp4->Poll (Tcp4);
> +        }
> +
> +        if (!HttpInstance->IsRxDone) {
> +          //
> +          // Cancle the Token before close its Event.
> +          //
> +          Tcp4->Cancel (HttpInstance->Tcp4, &Rx4Token->CompletionToken);
> +          gBS->CloseEvent (Rx4Token->CompletionToken.Event);
> +          Rx4Token->CompletionToken.Status = EFI_TIMEOUT;
> +        }
> +
> +        Status = Rx4Token->CompletionToken.Status;
> +        if (EFI_ERROR (Status)) {
> +          return Status;
> +        }
> +
> +        Fragment.Len  = Rx4Token->Packet.RxData-
> >FragmentTable[0].FragmentLength;
> +        Fragment.Bulk = (UINT8 *) Rx4Token->Packet.RxData-
> >FragmentTable[0].FragmentBuffer;
> +      } else {
> +        if (Fragment.Bulk != NULL) {
> +          FreePool (Fragment.Bulk);
> +          Fragment.Bulk = NULL;
> +        }
> +
> +        Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));
> +          return Status;
> +        }
>        }
> 
> -      if (!HttpInstance->IsRxDone) {
> -        //
> -        // Cancle the Token before close its Event.
> -        //
> -        Tcp4->Cancel (HttpInstance->Tcp4, &Rx4Token->CompletionToken);
> -        gBS->CloseEvent (Rx4Token->CompletionToken.Event);
> -        Rx4Token->CompletionToken.Status = EFI_TIMEOUT;
> -      }
> -
> -      Status = Rx4Token->CompletionToken.Status;
> -      if (EFI_ERROR (Status)) {
> -        return Status;
> -      }
> -
>        //
>        // Append the response string.
>        //
> -      *BufferSize = (*SizeofHeaders) + Rx4Token->Packet.RxData-
> >FragmentTable[0].FragmentLength;
> +      *BufferSize = *SizeofHeaders + Fragment.Len;
>        Buffer      = AllocateZeroPool (*BufferSize);
>        if (Buffer == NULL) {
>          Status = EFI_OUT_OF_RESOURCES;
>          return Status;
>        }
> -
> +
>        if (*HttpHeaders != NULL) {
> -        CopyMem (Buffer, *HttpHeaders, (*SizeofHeaders));
> +        CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
>          FreePool (*HttpHeaders);
>        }
> -
> +
>        CopyMem (
> -        Buffer + (*SizeofHeaders),
> -        Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer,
> -        Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength
> +        Buffer + *SizeofHeaders,
> +        Fragment.Bulk,
> +        Fragment.Len
>          );
> -      *HttpHeaders    = Buffer;
> -      *SizeofHeaders  = *BufferSize;
> -
> +      *HttpHeaders   = Buffer;
> +      *SizeofHeaders = *BufferSize;
> +
>        //
>        // Check whether we received end of HTTP headers.
>        //
>        *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
> -    }
> -    FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
> -    Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
> +    };
> 
> +    //
> +    // Free the buffer.
> +    //
> +    if (Rx4Token != NULL && Rx4Token->Packet.RxData != NULL &&
> Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
> +      FreePool (Rx4Token->Packet.RxData-
> >FragmentTable[0].FragmentBuffer);
> +      Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
> +      Fragment.Bulk = NULL;
> +    }
> +
> +    if (Fragment.Bulk != NULL) {
> +      FreePool (Fragment.Bulk);
> +      Fragment.Bulk = NULL;
> +    }
>    } else {
> -    Rx6Token = &HttpInstance->Rx6Token;
> -    Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer =
> AllocateZeroPool (DEF_BUF_LEN);
> -    if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer ==
> NULL) {
> -      Status = EFI_OUT_OF_RESOURCES;
> -      return Status;
> +    if (!HttpInstance->UseHttps) {
> +      Rx6Token = &HttpInstance->Rx6Token;
> +      Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer =
> AllocateZeroPool (DEF_BUF_LEN);
> +      if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer ==
> NULL) {
> +        Status = EFI_OUT_OF_RESOURCES;
> +        return Status;
> +      }
>      }
> 
>      //
>      // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not
> NULL.
>      //
> -    while (*EndofHeader == NULL) {
> -      HttpInstance->IsRxDone = FALSE;
> -      Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;
> -      Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength =
> DEF_BUF_LEN;
> -      Status = Tcp6->Receive (Tcp6, Rx6Token);
> -      if (EFI_ERROR (Status)) {
> -        DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
> -        return Status;
> -      }
> -
> -      while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR
> (gBS->CheckEvent (Timeout)))) {
> -        Tcp6->Poll (Tcp6);
> +    while (*EndofHeader == NULL) {
> +      if (!HttpInstance->UseHttps) {
> +        HttpInstance->IsRxDone = FALSE;
> +        Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;
> +        Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength =
> DEF_BUF_LEN;
> +        Status = Tcp6->Receive (Tcp6, Rx6Token);
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
> +          return Status;
> +        }
> +
> +        while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR
> (gBS->CheckEvent (Timeout)))) {
> +          Tcp6->Poll (Tcp6);
> +        }
> +
> +        if (!HttpInstance->IsRxDone) {
> +          //
> +          // Cancle the Token before close its Event.
> +          //
> +          Tcp6->Cancel (HttpInstance->Tcp6, &Rx6Token->CompletionToken);
> +          gBS->CloseEvent (Rx6Token->CompletionToken.Event);
> +          Rx6Token->CompletionToken.Status = EFI_TIMEOUT;
> +        }
> +
> +        Status = Rx6Token->CompletionToken.Status;
> +        if (EFI_ERROR (Status)) {
> +          return Status;
> +        }
> +
> +        Fragment.Len  = Rx6Token->Packet.RxData-
> >FragmentTable[0].FragmentLength;
> +        Fragment.Bulk = (UINT8 *) Rx6Token->Packet.RxData-
> >FragmentTable[0].FragmentBuffer;
> +      } else {
> +        if (Fragment.Bulk != NULL) {
> +          FreePool (Fragment.Bulk);
> +          Fragment.Bulk = NULL;
> +        }
> +
> +        Status = HttpsReceive (HttpInstance, &Fragment, Timeout);
> +        if (EFI_ERROR (Status)) {
> +          DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));
> +          return Status;
> +        }
>        }
> 
> -      if (!HttpInstance->IsRxDone) {
> -        //
> -        // Cancle the Token before close its Event.
> -        //
> -        Tcp6->Cancel (HttpInstance->Tcp6, &Rx6Token->CompletionToken);
> -        gBS->CloseEvent (Rx6Token->CompletionToken.Event);
> -        Rx6Token->CompletionToken.Status = EFI_TIMEOUT;
> -      }
> -
> -      Status = Rx6Token->CompletionToken.Status;
> -      if (EFI_ERROR (Status)) {
> -        return Status;
> -      }
> -
>        //
>        // Append the response string.
>        //
> -      *BufferSize = (*SizeofHeaders) + Rx6Token->Packet.RxData-
> >FragmentTable[0].FragmentLength;
> +      *BufferSize = *SizeofHeaders + Fragment.Len;
>        Buffer      = AllocateZeroPool (*BufferSize);
>        if (Buffer == NULL) {
>          Status = EFI_OUT_OF_RESOURCES;
>          return Status;
>        }
> -
> +
>        if (*HttpHeaders != NULL) {
> -        CopyMem (Buffer, *HttpHeaders, (*SizeofHeaders));
> +        CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);
>          FreePool (*HttpHeaders);
>        }
> -
> +
>        CopyMem (
> -        Buffer + (*SizeofHeaders),
> -        Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer,
> -        Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength
> +        Buffer + *SizeofHeaders,
> +        Fragment.Bulk,
> +        Fragment.Len
>          );
> -      *HttpHeaders     = Buffer;
> -      *SizeofHeaders  = *BufferSize;
> -
> +      *HttpHeaders   = Buffer;
> +      *SizeofHeaders = *BufferSize;
> +
>        //
>        // Check whether we received end of HTTP headers.
>        //
> -      *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
> -
> +      *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);
> +    };
> +
> +    //
> +    // Free the buffer.
> +    //
> +    if (Rx6Token != NULL && Rx6Token->Packet.RxData != NULL &&
> Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {
> +      FreePool (Rx6Token->Packet.RxData-
> >FragmentTable[0].FragmentBuffer);
> +      Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
> +      Fragment.Bulk = NULL;
> +    }
> +
> +    if (Fragment.Bulk != NULL) {
> +      FreePool (Fragment.Bulk);
> +      Fragment.Bulk = NULL;
>      }
> -    FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);
> -    Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;
>    }
> 
>    //
>    // Skip the CRLF after the HTTP headers.
>    //
> diff --git a/NetworkPkg/HttpDxe/HttpProto.h
> b/NetworkPkg/HttpDxe/HttpProto.h
> index e1fd785..e3b3275 100644
> --- a/NetworkPkg/HttpDxe/HttpProto.h
> +++ b/NetworkPkg/HttpDxe/HttpProto.h
> @@ -81,10 +81,24 @@ typedef struct {
>    BOOLEAN                       IsRxDone;
>    UINTN                         BodyLen;
>    EFI_HTTP_METHOD               Method;
>  } HTTP_TCP_TOKEN_WRAP;
> 
> +typedef struct {
> +  EFI_TLS_VERSION               Version;
> +  EFI_TLS_CONNECTION_END        ConnectionEnd;
> +  EFI_TLS_VERIFY                VerifyMethod;
> +  EFI_TLS_SESSION_STATE         SessionState;
> +
> +  VOID                          *CACert;
> +  UINTN                         CACertSize;
> +  VOID                          *ClientCert;
> +  UINTN                         ClientCertSize;
> +  VOID                          *ClientPrivateKey;
> +  UINTN                         ClientPrivateKeySize;
> +} TLS_CONFIG_DATA;
> +
>  typedef struct _HTTP_PROTOCOL {
>    UINT32                        Signature;
>    EFI_HTTP_PROTOCOL             Http;
>    EFI_HANDLE                    Handle;
>    HTTP_SERVICE                  *Service;
> @@ -151,10 +165,39 @@ typedef struct _HTTP_PROTOCOL {
> 
>    NET_MAP                       TxTokens;
>    NET_MAP                       RxTokens;
> 
>    CHAR8                         *Url;
> +
> +  //
> +  // Https Support
> +  //
> +  BOOLEAN                          UseHttps;
> +
> +  EFI_HANDLE                       TlsChildHandle; /// Tls ChildHandle
> +  TLS_CONFIG_DATA                  TlsConfigData;
> +  EFI_TLS_PROTOCOL                 *Tls;
> +  EFI_TLS_CONFIGURATION_PROTOCOL   *TlsConfiguration;
> +  EFI_TLS_SESSION_STATE            TlsSessionState;
> +
> +  //
> +  // TlsTxData used for transmitting TLS related messages.
> +  //
> +  EFI_TCP4_IO_TOKEN                Tcp4TlsTxToken;
> +  EFI_TCP4_TRANSMIT_DATA           Tcp4TlsTxData;
> +  EFI_TCP6_IO_TOKEN                Tcp6TlsTxToken;
> +  EFI_TCP6_TRANSMIT_DATA           Tcp6TlsTxData;
> +  BOOLEAN                          TlsIsTxDone;
> +
> +  //
> +  // TlsRxData used for receiving TLS related messages.
> +  //
> +  EFI_TCP4_IO_TOKEN                Tcp4TlsRxToken;
> +  EFI_TCP4_RECEIVE_DATA            Tcp4TlsRxData;
> +  EFI_TCP6_IO_TOKEN                Tcp6TlsRxToken;
> +  EFI_TCP6_RECEIVE_DATA            Tcp6TlsRxData;
> +  BOOLEAN                          TlsIsRxDone;
>  } HTTP_PROTOCOL;
> 
>  typedef struct {
>    EFI_HTTP_TOKEN                *HttpToken;
>    HTTP_PROTOCOL                 *HttpInstance;
> @@ -350,11 +393,12 @@ HttpConfigureTcp6 (
>    IN  HTTP_PROTOCOL        *HttpInstance,
>    IN  HTTP_TOKEN_WRAP      *Wrap
>    );
> 
>  /**
> -  Check existing TCP connection, if in error state, receover TCP4 connection.
> +  Check existing TCP connection, if in error state, recover TCP4 connection.
> Then,
> +  connect one TLS session if required.
> 
>    @param[in]  HttpInstance       The HTTP instance private data.
> 
>    @retval EFI_SUCCESS            The TCP connection is established.
>    @retval EFI_NOT_READY          TCP4 protocol child is not created or
> configured.
> @@ -365,11 +409,12 @@ EFI_STATUS
>  HttpConnectTcp4 (
>    IN  HTTP_PROTOCOL        *HttpInstance
>    );
> 
>  /**
> -  Check existing TCP connection, if in error state, recover TCP6 connection.
> +  Check existing TCP connection, if in error state, recover TCP6 connection.
> Then,
> +  connect one TLS session if required.
> 
>    @param[in]  HttpInstance       The HTTP instance private data.
> 
>    @retval EFI_SUCCESS            The TCP connection is established.
>    @retval EFI_NOT_READY          TCP6 protocol child is not created or
> configured.
> @@ -380,11 +425,11 @@ EFI_STATUS
>  HttpConnectTcp6 (
>    IN  HTTP_PROTOCOL        *HttpInstance
>    );
> 
>  /**
> -  Send the HTTP message through TCP4 or TCP6.
> +  Send the HTTP or HTTPS message through TCP4 or TCP6.
> 
>    @param[in]  HttpInstance       The HTTP instance private data.
>    @param[in]  Wrap               The HTTP token's wrap data.
>    @param[in]  TxString           Buffer containing the HTTP message string.
>    @param[in]  TxStringLen        Length of the HTTP message string in bytes.
> @@ -441,29 +486,31 @@ HttpTcpNotReady (
>    IN NET_MAP_ITEM           *Item,
>    IN VOID                   *Context
>    );
> 
>  /**
> -  Initialize TCP related data.
> +  Initialize Http session.
> 
>    @param[in]  HttpInstance       The HTTP instance private data.
>    @param[in]  Wrap               The HTTP token's wrap data.
> -  @param[in]  Configure          The Flag indicates whether the first time to
> initialize Tcp.
> +  @param[in]  Configure          The Flag indicates whether need to initialize
> session.
> +  @param[in]  TlsConfigure       The Flag indicates whether it's the new Tls
> session.
> 
> -  @retval EFI_SUCCESS            The initialization of TCP instance is done.
> +  @retval EFI_SUCCESS            The initialization of session is done.
>    @retval Others                 Other error as indicated.
> 
>  **/
>  EFI_STATUS
> -HttpInitTcp (
> +HttpInitSession (
>    IN  HTTP_PROTOCOL    *HttpInstance,
>    IN  HTTP_TOKEN_WRAP  *Wrap,
> -  IN  BOOLEAN          Configure
> +  IN  BOOLEAN          Configure,
> +  IN  BOOLEAN          TlsConfigure
>    );
> 
>  /**
> -  Transmit the HTTP mssage by processing the associated HTTP token.
> +  Transmit the HTTP or HTTPS mssage by processing the associated HTTP
> token.
> 
>    @param[in]  Map                The container of TxToken or Tx6Token.
>    @param[in]  Item               Current item to check against.
>    @param[in]  Context            The Token to check againist.
> 
> diff --git a/NetworkPkg/HttpDxe/HttpsSupport.c
> b/NetworkPkg/HttpDxe/HttpsSupport.c
> new file mode 100644
> index 0000000..177b9a8
> --- /dev/null
> +++ b/NetworkPkg/HttpDxe/HttpsSupport.c
> @@ -0,0 +1,1692 @@
> +/** @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 = (UINT8 *) HttpInstance->TlsConfigData.CACert;
> +  CACertSize = HttpInstance->TlsConfigData.CACertSize;
> +
> +  //
> +  // Try to read the TlsCaCertificate variable.
> +  //
> +  CACertSize = 0;
> +  Status  = gRT->GetVariable (
> +                   EFI_TLS_CA_CERTIFICATE_VARIABLE,
> +                   &gEfiTlsCaCertificateGuid,
> +                   NULL,
> +                   &CACertSize,
> +                   NULL
> +                   );
> +
> +  if (Status == EFI_BUFFER_TOO_SMALL) {
> +    //
> +    // 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;
> +    }
> +  }
> +
> +  //
> +  // 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)) {
> +        return Status;
> +      }
> +
> +      Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList-
> >SignatureSize);
> +    }
> +
> +    ItemDataSize -= CertList->SignatureListSize;
> +    CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList-
> >SignatureListSize);
> +  }
> +
> +  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)) {
> +    goto ERROR;
> +  }
> +
> +  Status = HttpInstance->Tls->SetSessionData (
> +                                HttpInstance->Tls,
> +                                EfiTlsVerifyMethod,
> +                                &HttpInstance->TlsConfigData.VerifyMethod,
> +                                sizeof (EFI_TLS_VERIFY)
> +                                );
> +  if (EFI_ERROR (Status)) {
> +    goto ERROR;
> +  }
> +
> +  Status = HttpInstance->Tls->SetSessionData (
> +                                HttpInstance->Tls,
> +                                EfiTlsSessionState,
> +                                &(HttpInstance->TlsConfigData.SessionState),
> +                                sizeof (EFI_TLS_SESSION_STATE)
> +                                );
> +  if (EFI_ERROR (Status)) {
> +    goto ERROR;
> +  }
> +
> +  //
> +  // Tls Config Certificate
> +  //
> +  Status = TlsConfigCertificate (HttpInstance);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((EFI_D_ERROR, "TLS Certificate Config Error!\n"));
> +    goto ERROR;
> +  }
> +
> +  //
> +  // 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. This 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);
> +  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)) {
> +      return Status;
> +    }
> +
> +    if (BufferOutSize != 0) {
> +      //
> +      // Transmit the response packet.
> +      //
> +      PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
> +      DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize,
> NET_BUF_TAIL);
> +      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);
> +  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);
> +          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);
> +      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;
> +}
> diff --git a/NetworkPkg/HttpDxe/HttpsSupport.h
> b/NetworkPkg/HttpDxe/HttpsSupport.h
> new file mode 100644
> index 0000000..d846b76
> --- /dev/null
> +++ b/NetworkPkg/HttpDxe/HttpsSupport.h
> @@ -0,0 +1,260 @@
> +/** @file
> +  The header files of miscellaneous routines specific to Https for HttpDxe
> driver.
> +
> +Copyright (c) 2016, Intel Corporation. All rights reserved.<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.
> +
> +**/
> +
> +#ifndef __EFI_HTTPS_SUPPORT_H__
> +#define __EFI_HTTPS_SUPPORT_H__
> +
> +#define HTTPS_DEFAULT_PORT       443
> +
> +#define HTTPS_FLAG               "https"
> +
> +/**
> +  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
> +  );
> +
> +/**
> +  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
> +  );
> +
> +/**
> +  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
> +  );
> +
> +/**
> +  Close events in the TlsTxToken and TlsRxToken.
> +
> +  @param[in]  HttpInstance   Pointer to HTTP_PROTOCOL structure.
> +
> +**/
> +VOID
> +EFIAPI
> +TlsCloseTxRxEvent (
> +  IN  HTTP_PROTOCOL        *HttpInstance
> +  );
> +
> +/**
> +  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
> +  );
> +
> +/**
> +  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
> +  );
> +
> +/**
> +  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
> +  );
> +
> +/**
> +  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
> +  );
> +
> +/**
> +  Receive one TLS PDU. An TLS PDU contains an TLS record header and it's
> +  corresponding record data. The 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
> +  );
> +
> +/**
> +  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
> +  );
> +
> +/**
> +  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 or Packet 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
> +  );
> +
> +/**
> +  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
> +  );
> +
> +/**
> +  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
> +  );
> +
> +#endif
> --
> 1.9.5.msysgit.1


  reply	other threads:[~2016-12-15  7:15 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-12-14  7:34 [Patch 00/10] Sync staging/HTTPS-TLS feature into edk2 master Jiaxin Wu
2016-12-14  7:34 ` [Patch 01/10] MdePkg: Add TLS related protocol definition Jiaxin Wu
2016-12-14  8:36   ` Long, Qin
2016-12-14  8:39     ` Wu, Jiaxin
2016-12-15  8:34       ` Ye, Ting
2016-12-14  8:43   ` Fu, Siyuan
2016-12-14  7:34 ` [Patch 02/10] MdePkg: Add a header to standardize TLS definitions Jiaxin Wu
2016-12-14  8:42   ` Long, Qin
2016-12-14  8:43   ` Fu, Siyuan
2016-12-15  8:35   ` Ye, Ting
2016-12-14  7:34 ` [Patch 03/10] CryptoPkg: Enable ssl build in OpensslLib directly Jiaxin Wu
2016-12-15  8:37   ` Ye, Ting
2016-12-14  7:34 ` [Patch 04/10] CryptoPkg: Add new TlsLib library Jiaxin Wu
2016-12-16  2:10   ` Ye, Ting
2016-12-16  2:51     ` Wu, Jiaxin
2016-12-14  7:34 ` [Patch 05/10] NetworkPkg/TlsDxe: TlsDxe driver implementation over OpenSSL Jiaxin Wu
2016-12-14  8:41   ` Fu, Siyuan
2016-12-15  7:24     ` Wu, Jiaxin
2016-12-14  7:34 ` [Patch 06/10] NetworkPkg/TlsAuthConfigDxe: Provide the UI to support TLS auth configuration Jiaxin Wu
2016-12-15  2:22   ` Fu, Siyuan
2016-12-22  2:52     ` Ye, Ting
2016-12-22  3:13       ` Wu, Jiaxin
2016-12-14  7:34 ` [Patch 07/10] NetworkPkg/HttpDxe: HTTPS support over IPv4 and IPv6 Jiaxin Wu
2016-12-15  2:39   ` Fu, Siyuan
2016-12-15  7:14     ` Wu, Jiaxin [this message]
2016-12-22  7:33   ` Ye, Ting
2016-12-22  8:30     ` Wu, Jiaxin
2016-12-14  7:34 ` [Patch 08/10] NetworkPkg/NetworkPkg.dsc: Enable TlsDxe and TlsAuthConfigDxe module Jiaxin Wu
2016-12-15  2:39   ` Fu, Siyuan
2016-12-22  7:37   ` Ye, Ting
2016-12-14  7:34 ` [Patch 09/10] Nt32Pkg/Nt32Pkg.dsc: Remove the flag for OpensslLib and BaseCryptLib Jiaxin Wu
2016-12-14  7:56   ` Ni, Ruiyu
2016-12-15  8:25   ` Long, Qin
2016-12-22  7:39   ` Ye, Ting
2016-12-14  7:34 ` [Patch 10/10] Nt32Pkg: Enable HTTPS boot feature for Nt32 platform Jiaxin Wu
2016-12-14  7:44   ` Yao, Jiewen
2016-12-14  7:46     ` Wu, Jiaxin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=895558F6EA4E3B41AC93A00D163B72741627F514@SHSMSX103.ccr.corp.intel.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox