NetworkPkg/HttpDxe: HTTPS support over IPv4 and IPv6
authorJiaxin Wu <jiaxin.wu@intel.com>
Wed, 14 Dec 2016 02:57:41 +0000 (10:57 +0800)
committerJiaxin Wu <jiaxin.wu@intel.com>
Thu, 22 Dec 2016 12:33:40 +0000 (20:33 +0800)
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>
Reviewed-by: Fu Siyuan <siyuan.fu@intel.com>
Reviewed-by: Ye Ting <ting.ye@intel.com>
NetworkPkg/HttpDxe/HttpDriver.h
NetworkPkg/HttpDxe/HttpDxe.inf
NetworkPkg/HttpDxe/HttpImpl.c
NetworkPkg/HttpDxe/HttpProto.c
NetworkPkg/HttpDxe/HttpProto.h
NetworkPkg/HttpDxe/HttpsSupport.c [new file with mode: 0644]
NetworkPkg/HttpDxe/HttpsSupport.h [new file with mode: 0644]

index fa2372c..93a412a 100644 (file)
@@ -24,6 +24,7 @@
 // Libraries\r
 //\r
 #include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiRuntimeServicesTableLib.h>\r
 #include <Library/MemoryAllocationLib.h>\r
 #include <Library/BaseLib.h>\r
 #include <Library/UefiLib.h>\r
 #include <Protocol/Dns6.h>\r
 #include <Protocol/Ip4Config2.h>\r
 #include <Protocol/Ip6Config.h>\r
+#include <Protocol/Tls.h>\r
+#include <Protocol/TlsConfig.h>\r
 \r
-\r
+#include <Guid/ImageAuthentication.h>\r
 //\r
 // Produced Protocols\r
 //\r
 #include <Protocol/Http.h>\r
 \r
+#include <Guid/TlsAuthentication.h>\r
+\r
+#include <IndustryStandard/Tls1.h>\r
+\r
 //\r
 // Driver Version\r
 //\r
@@ -79,6 +86,7 @@ extern EFI_HTTP_UTILITIES_PROTOCOL  *mHttpUtilities;
 #include "ComponentName.h"\r
 #include "HttpImpl.h"\r
 #include "HttpProto.h"\r
+#include "HttpsSupport.h"\r
 #include "HttpDns.h"\r
 \r
 typedef struct {\r
index bf2cbee..1118181 100644 (file)
@@ -1,7 +1,7 @@
 ## @file\r
 #  Implementation of EFI HTTP protocol interfaces.\r
 #\r
-#  Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>\r
+#  Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>\r
 #\r
 #  This program and the accompanying materials\r
 #  are licensed and made available under the terms and conditions of the BSD License\r
@@ -26,6 +26,7 @@
 [Packages]\r
   MdePkg/MdePkg.dec\r
   MdeModulePkg/MdeModulePkg.dec\r
+  NetworkPkg/NetworkPkg.dec\r
 \r
 [Sources]\r
   ComponentName.h\r
   HttpImpl.c\r
   HttpProto.h\r
   HttpProto.c\r
+  HttpsSupport.h\r
+  HttpsSupport.c\r
 \r
 [LibraryClasses]\r
   UefiDriverEntryPoint\r
   UefiBootServicesTableLib\r
+  UefiRuntimeServicesTableLib\r
   MemoryAllocationLib\r
   BaseLib\r
   UefiLib\r
   gEfiDns6ProtocolGuid                             ## SOMETIMES_CONSUMES\r
   gEfiIp4Config2ProtocolGuid                       ## SOMETIMES_CONSUMES\r
   gEfiIp6ConfigProtocolGuid                        ## SOMETIMES_CONSUMES\r
+  gEfiTlsServiceBindingProtocolGuid                ## SOMETIMES_CONSUMES\r
+  gEfiTlsProtocolGuid                              ## SOMETIMES_CONSUMES\r
+  gEfiTlsConfigurationProtocolGuid                 ## SOMETIMES_CONSUMES\r
+\r
+[Guids]\r
+  gEfiTlsCaCertificateGuid                         ## CONSUMES  ## GUID\r
 \r
 [UserExtensions.TianoCore."ExtraFiles"]\r
   HttpDxeExtra.uni
\ No newline at end of file
index 6fcb0b7..77aa64a 100644 (file)
@@ -241,6 +241,7 @@ EfiHttpRequest (
   HTTP_PROTOCOL                 *HttpInstance;\r
   BOOLEAN                       Configure;\r
   BOOLEAN                       ReConfigure;\r
+  BOOLEAN                       TlsConfigure;\r
   CHAR8                         *RequestMsg;\r
   CHAR8                         *Url;\r
   UINTN                         UrlLen;\r
@@ -260,6 +261,7 @@ EfiHttpRequest (
   HostNameStr = NULL;\r
   Wrap = NULL;\r
   FileUrl = NULL;\r
+  TlsConfigure = FALSE;\r
 \r
   if ((This == NULL) || (Token == NULL)) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -345,6 +347,32 @@ EfiHttpRequest (
 \r
 \r
     UnicodeStrToAsciiStrS (Request->Url, Url, UrlLen);\r
+\r
+    //\r
+    // From the information in Url, the HTTP instance will \r
+    // be able to determine whether to use http or https.\r
+    //\r
+    HttpInstance->UseHttps = IsHttpsUrl (Url);\r
+\r
+    //\r
+    // Check whether we need to create Tls child and open the TLS protocol.\r
+    //\r
+    if (HttpInstance->UseHttps && HttpInstance->TlsChildHandle == NULL) {\r
+      //\r
+      // Use TlsSb to create Tls child and open the TLS protocol.\r
+      //\r
+      HttpInstance->TlsChildHandle = TlsCreateChild (\r
+                                       HttpInstance->Service->ImageHandle,\r
+                                       &(HttpInstance->Tls),\r
+                                       &(HttpInstance->TlsConfiguration)\r
+                                       );\r
+      if (HttpInstance->TlsChildHandle == NULL) {\r
+        return EFI_DEVICE_ERROR;\r
+      }\r
+\r
+      TlsConfigure = TRUE;\r
+    }\r
+\r
     UrlParser = NULL;\r
     Status = HttpParseUrl (Url, (UINT32) AsciiStrLen (Url), FALSE, &UrlParser);\r
     if (EFI_ERROR (Status)) {\r
@@ -359,7 +387,11 @@ EfiHttpRequest (
 \r
     Status = HttpUrlGetPort (Url, UrlParser, &RemotePort);\r
     if (EFI_ERROR (Status)) {\r
-      RemotePort = HTTP_DEFAULT_PORT;\r
+      if (HttpInstance->UseHttps) {\r
+        RemotePort = HTTPS_DEFAULT_PORT;\r
+      } else {\r
+        RemotePort = HTTP_DEFAULT_PORT;\r
+      }\r
     }\r
     //\r
     // If Configure is TRUE, it indicates the first time to call Request();\r
@@ -376,9 +408,13 @@ EfiHttpRequest (
       ReConfigure = FALSE;\r
     } else {\r
       if ((HttpInstance->RemotePort == RemotePort) &&\r
-        (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0)) {\r
+          (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0) && \r
+          (!HttpInstance->UseHttps || (HttpInstance->UseHttps && \r
+                                       !TlsConfigure && \r
+                                       HttpInstance->TlsSessionState == EfiTlsSessionDataTransferring))) {\r
         //\r
         // Host Name and port number of the request URL are the same with previous call to Request().\r
+        // If Https protocol used, the corresponding SessionState is EfiTlsSessionDataTransferring.\r
         // Check whether previous TCP packet sent out.\r
         //\r
 \r
@@ -482,6 +518,16 @@ EfiHttpRequest (
     } else {\r
       ASSERT (HttpInstance->Tcp6 != NULL);\r
     }\r
+\r
+    if (HttpInstance->UseHttps && !TlsConfigure) {\r
+      Status = TlsCloseSession (HttpInstance);\r
+      if (EFI_ERROR (Status)) {\r
+        goto Error1;\r
+      }\r
+      \r
+      TlsCloseTxRxEvent (HttpInstance);\r
+    }\r
+    \r
     HttpCloseConnection (HttpInstance);\r
     EfiHttpCancel (This, NULL);\r
   }\r
@@ -500,13 +546,18 @@ EfiHttpRequest (
   if (Request != NULL) {\r
     Wrap->TcpWrap.Method = Request->Method;\r
   }\r
-\r
-  Status = HttpInitTcp (HttpInstance, Wrap, Configure);\r
+  \r
+  Status = HttpInitSession (\r
+             HttpInstance, \r
+             Wrap, \r
+             Configure || ReConfigure, \r
+             TlsConfigure\r
+             );\r
   if (EFI_ERROR (Status)) {\r
     goto Error2;\r
-  }  \r
+  }\r
 \r
-  if (!Configure) {\r
+  if (!Configure && !ReConfigure && !TlsConfigure) {\r
     //\r
     // For the new HTTP token, create TX TCP token events.    \r
     //\r
@@ -593,9 +644,14 @@ Error4:
   }  \r
 \r
 Error3:\r
-  HttpCloseConnection (HttpInstance);\r
+  if (HttpInstance->UseHttps) {\r
+    TlsCloseSession (HttpInstance);\r
+    TlsCloseTxRxEvent (HttpInstance);\r
+  }\r
 \r
 Error2:\r
+  HttpCloseConnection (HttpInstance);\r
+  \r
   HttpCloseTcpConnCloseEvent (HttpInstance);\r
   if (NULL != Wrap->TcpWrap.Tx4Token.CompletionToken.Event) {\r
     gBS->CloseEvent (Wrap->TcpWrap.Tx4Token.CompletionToken.Event);\r
@@ -731,22 +787,30 @@ HttpCancel (
     }\r
   }\r
 \r
-  //\r
-  // Then check the tokens queued by EfiHttpResponse().\r
-  //\r
-  Status = NetMapIterate (&HttpInstance->RxTokens, HttpCancelTokens, Token);\r
-  if (EFI_ERROR (Status)) {\r
-    if (Token != NULL) {\r
-      if (Status == EFI_ABORTED) {\r
-        return EFI_SUCCESS;\r
+  if (!HttpInstance->UseHttps) {\r
+    //\r
+    // Then check the tokens queued by EfiHttpResponse(), except for Https.\r
+    //\r
+    Status = NetMapIterate (&HttpInstance->RxTokens, HttpCancelTokens, Token);\r
+    if (EFI_ERROR (Status)) {\r
+      if (Token != NULL) {\r
+        if (Status == EFI_ABORTED) {\r
+          return EFI_SUCCESS;\r
+        } else {\r
+          return EFI_NOT_FOUND;\r
+        }\r
       } else {\r
-        return EFI_NOT_FOUND;\r
+        return Status;\r
       }\r
+    }\r
+  } else {\r
+    if (!HttpInstance->LocalAddressIsIPv6) {\r
+      HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken.CompletionToken);\r
     } else {\r
-      return Status;\r
+      HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken.CompletionToken);\r
     }\r
   }\r
-\r
+  \r
   return EFI_SUCCESS;\r
 }\r
 \r
@@ -882,6 +946,7 @@ HttpResponseWorker (
   NET_MAP_ITEM                  *Item;\r
   HTTP_TOKEN_WRAP               *ValueInItem;\r
   UINTN                         HdrLen;\r
+  NET_FRAGMENT                  Fragment;\r
 \r
   if (Wrap == NULL || Wrap->HttpInstance == NULL) {\r
     return EFI_INVALID_PARAMETER;\r
@@ -899,16 +964,10 @@ HttpResponseWorker (
   BufferSize                = 0;\r
   EndofHeader               = NULL;\r
   ValueInItem               = NULL;\r
+  Fragment.Len              = 0;\r
+  Fragment.Bulk             = NULL;\r
  \r
   if (HttpMsg->Data.Response != NULL) {\r
-    //\r
-    // Need receive the HTTP headers, prepare buffer.\r
-    //\r
-    Status = HttpCreateTcpRxEventForHeader (HttpInstance);\r
-    if (EFI_ERROR (Status)) {\r
-      goto Error;\r
-    }\r
-\r
     //\r
     // Check whether we have cached header from previous call.\r
     //\r
@@ -1200,9 +1259,116 @@ HttpResponseWorker (
   //\r
   // We still need receive more data when there is no cache data and MsgParser is not NULL;\r
   //\r
-  Status = HttpTcpReceiveBody (Wrap, HttpMsg);\r
-  if (EFI_ERROR (Status)) {\r
-    goto Error2;\r
+  if (!HttpInstance->UseHttps) {\r
+    Status = HttpTcpReceiveBody (Wrap, HttpMsg);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error2;\r
+    }\r
+    \r
+  } else {\r
+    if (HttpInstance->TimeoutEvent == NULL) {\r
+      //\r
+      // Create TimeoutEvent for response\r
+      //\r
+      Status = gBS->CreateEvent (\r
+                      EVT_TIMER,\r
+                      TPL_CALLBACK,\r
+                      NULL,\r
+                      NULL,\r
+                      &HttpInstance->TimeoutEvent\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        goto Error2;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Start the timer, and wait Timeout seconds to receive the body packet.\r
+    //\r
+    Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_RESPONSE_TIMEOUT * TICKS_PER_SECOND);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error2;\r
+    }\r
+  \r
+    Status = HttpsReceive (HttpInstance, &Fragment, HttpInstance->TimeoutEvent);\r
+\r
+    gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);\r
+    \r
+    if (EFI_ERROR (Status)) {\r
+      goto Error2;\r
+    }\r
+\r
+    //\r
+    // Check whether we receive a complete HTTP message.\r
+    //\r
+    Status = HttpParseMessageBody (\r
+               HttpInstance->MsgParser,\r
+               (UINTN) Fragment.Len,\r
+               (CHAR8 *) Fragment.Bulk\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error2;\r
+    }\r
+\r
+    if (HttpIsMessageComplete (HttpInstance->MsgParser)) {\r
+      //\r
+      // Free the MsgParse since we already have a full HTTP message.\r
+      //\r
+      HttpFreeMsgParser (HttpInstance->MsgParser);\r
+      HttpInstance->MsgParser = NULL;\r
+    }\r
+\r
+    //\r
+    // We receive part of header of next HTTP msg.\r
+    //\r
+    if (HttpInstance->NextMsg != NULL) {\r
+      HttpMsg->BodyLength = MIN ((UINTN) (HttpInstance->NextMsg - (CHAR8 *) Fragment.Bulk), HttpMsg->BodyLength);\r
+      CopyMem (HttpMsg->Body, Fragment.Bulk, HttpMsg->BodyLength);\r
+      \r
+      HttpInstance->CacheLen = Fragment.Len - HttpMsg->BodyLength;\r
+      if (HttpInstance->CacheLen != 0) {\r
+        if (HttpInstance->CacheBody != NULL) {\r
+          FreePool (HttpInstance->CacheBody);\r
+        }\r
+        \r
+        HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);\r
+        if (HttpInstance->CacheBody == NULL) {\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+          goto Error2;\r
+        }\r
+        \r
+        CopyMem (HttpInstance->CacheBody, Fragment.Bulk + HttpMsg->BodyLength, HttpInstance->CacheLen);\r
+        HttpInstance->CacheOffset = 0;\r
+\r
+        HttpInstance->NextMsg = HttpInstance->CacheBody + (UINTN) (HttpInstance->NextMsg - (CHAR8 *) (Fragment.Bulk + HttpMsg->BodyLength));\r
+      }\r
+    } else {\r
+      HttpMsg->BodyLength = MIN (Fragment.Len, (UINT32) HttpMsg->BodyLength);\r
+      CopyMem (HttpMsg->Body, Fragment.Bulk, HttpMsg->BodyLength);\r
+      HttpInstance->CacheLen = Fragment.Len - HttpMsg->BodyLength;\r
+      if (HttpInstance->CacheLen != 0) {\r
+        if (HttpInstance->CacheBody != NULL) {\r
+          FreePool (HttpInstance->CacheBody);\r
+        }\r
+        \r
+        HttpInstance->CacheBody = AllocateZeroPool (HttpInstance->CacheLen);\r
+        if (HttpInstance->CacheBody == NULL) {\r
+          Status = EFI_OUT_OF_RESOURCES;\r
+          goto Error2;\r
+        }\r
+\r
+        CopyMem (HttpInstance->CacheBody, Fragment.Bulk + HttpMsg->BodyLength, HttpInstance->CacheLen);\r
+        HttpInstance->CacheOffset = 0;\r
+      }\r
+    }\r
+\r
+    if (Fragment.Bulk != NULL) {\r
+      FreePool (Fragment.Bulk);\r
+      Fragment.Bulk = NULL;\r
+    }\r
+\r
+    goto Exit;\r
   }\r
 \r
   return Status;\r
@@ -1234,15 +1400,26 @@ Error:
   if (Item != NULL) {\r
     NetMapRemoveItem (&Wrap->HttpInstance->RxTokens, Item, NULL);\r
   }\r
-  \r
-  HttpTcpTokenCleanup (Wrap);\r
+\r
+  if (!HttpInstance->UseHttps) {\r
+    HttpTcpTokenCleanup (Wrap);\r
+  } else {\r
+    FreePool (Wrap);\r
+  }\r
   \r
   if (HttpHeaders != NULL) {\r
     FreePool (HttpHeaders);\r
+    HttpHeaders = NULL;\r
+  }\r
+\r
+  if (Fragment.Bulk != NULL) {\r
+    FreePool (Fragment.Bulk);\r
+    Fragment.Bulk = NULL;\r
   }\r
 \r
   if (HttpMsg->Headers != NULL) {\r
     FreePool (HttpMsg->Headers);\r
+    HttpMsg->Headers = NULL;\r
   }\r
 \r
   if (HttpInstance->CacheBody != NULL) {\r
@@ -1353,9 +1530,16 @@ EfiHttpResponse (
   Wrap->HttpInstance = HttpInstance;\r
   Wrap->HttpToken    = Token;\r
 \r
-  Status = HttpCreateTcpRxEvent (Wrap);\r
-  if (EFI_ERROR (Status)) {\r
-    goto Error;\r
+  //\r
+  // Notes: For Https, receive token wrapped in HTTP_TOKEN_WRAP is not used to \r
+  // receive the https response. A special TlsRxToken is used for receiving TLS \r
+  // related messages. It should be a blocking response.\r
+  //\r
+  if (!HttpInstance->UseHttps) {\r
+    Status = HttpCreateTcpRxEvent (Wrap);\r
+    if (EFI_ERROR (Status)) {\r
+      goto Error;\r
+    }\r
   }\r
 \r
   Status = NetMapInsertTail (&HttpInstance->RxTokens, Token, Wrap);\r
index 6373f07..36c61e2 100644 (file)
@@ -927,7 +927,8 @@ HttpCleanProtocol (
            HttpInstance->Handle\r
            );\r
   }\r
-  \r
+\r
+  TlsCloseTxRxEvent (HttpInstance); \r
 }\r
 \r
 /**\r
@@ -1185,7 +1186,8 @@ HttpConfigureTcp6 (
 }\r
 \r
 /**\r
-  Check existing TCP connection, if in error state, recover TCP4 connection.\r
+  Check existing TCP connection, if in error state, recover TCP4 connection. Then, \r
+  connect one TLS session if required.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
 \r
@@ -1226,11 +1228,58 @@ HttpConnectTcp4 (
     HttpCloseConnection(HttpInstance);\r
   }\r
 \r
-  return HttpCreateConnection (HttpInstance);\r
+  Status = HttpCreateConnection (HttpInstance);\r
+  if (EFI_ERROR(Status)){\r
+    DEBUG ((EFI_D_ERROR, "Tcp4 Connection fail - %x\n", Status));\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Tls session connection.\r
+  //\r
+  if (HttpInstance->UseHttps) {\r
+    if (HttpInstance->TimeoutEvent == NULL) {\r
+      //\r
+      // Create TimeoutEvent for TLS connection.\r
+      //\r
+      Status = gBS->CreateEvent (\r
+                      EVT_TIMER,\r
+                      TPL_CALLBACK,\r
+                      NULL,\r
+                      NULL,\r
+                      &HttpInstance->TimeoutEvent\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        TlsCloseTxRxEvent (HttpInstance);\r
+        return Status;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Start the timer, and wait Timeout seconds for connection.\r
+    //\r
+    Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);\r
+    if (EFI_ERROR (Status)) {\r
+      TlsCloseTxRxEvent (HttpInstance);\r
+      return Status;\r
+    }\r
+    \r
+    Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);\r
+\r
+    gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);\r
+    \r
+    if (EFI_ERROR (Status)) {\r
+      TlsCloseTxRxEvent (HttpInstance);\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 /**\r
-  Check existing TCP connection, if in error state, recover TCP6 connection.\r
+  Check existing TCP connection, if in error state, recover TCP6 connection. Then, \r
+  connect one TLS session if required.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
 \r
@@ -1271,30 +1320,88 @@ HttpConnectTcp6 (
     HttpCloseConnection(HttpInstance);\r
   }\r
 \r
-  return HttpCreateConnection (HttpInstance);\r
+  Status = HttpCreateConnection (HttpInstance);\r
+  if (EFI_ERROR(Status)){\r
+    DEBUG ((EFI_D_ERROR, "Tcp6 Connection fail - %x\n", Status));\r
+    return Status;\r
+  }\r
+  \r
+  //\r
+  // Tls session connection.\r
+  //\r
+  if (HttpInstance->UseHttps) {\r
+    if (HttpInstance->TimeoutEvent == NULL) {\r
+      //\r
+      // Create TimeoutEvent for TLS connection.\r
+      //\r
+      Status = gBS->CreateEvent (\r
+                      EVT_TIMER,\r
+                      TPL_CALLBACK,\r
+                      NULL,\r
+                      NULL,\r
+                      &HttpInstance->TimeoutEvent\r
+                      );\r
+      if (EFI_ERROR (Status)) {\r
+        TlsCloseTxRxEvent (HttpInstance);\r
+        return Status;\r
+      }\r
+    }\r
+\r
+    //\r
+    // Start the timer, and wait Timeout seconds for connection.\r
+    //\r
+    Status = gBS->SetTimer (HttpInstance->TimeoutEvent, TimerRelative, HTTP_CONNECTION_TIMEOUT * TICKS_PER_SECOND);\r
+    if (EFI_ERROR (Status)) {\r
+      TlsCloseTxRxEvent (HttpInstance);\r
+      return Status;\r
+    }\r
+    \r
+    Status = TlsConnectSession (HttpInstance, HttpInstance->TimeoutEvent);\r
+\r
+    gBS->SetTimer (HttpInstance->TimeoutEvent, TimerCancel, 0);\r
+    \r
+    if (EFI_ERROR (Status)) {\r
+      TlsCloseTxRxEvent (HttpInstance);\r
+      return Status;\r
+    }\r
+  }\r
+\r
+  return Status;\r
 }\r
 \r
 /**\r
-  Initialize TCP related data.\r
+  Initialize Http session.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
   @param[in]  Wrap               The HTTP token's wrap data.\r
-  @param[in]  Configure          The Flag indicates whether the first time to initialize Tcp.\r
+  @param[in]  Configure          The Flag indicates whether need to initialize session.\r
+  @param[in]  TlsConfigure       The Flag indicates whether it's the new Tls session.\r
 \r
-  @retval EFI_SUCCESS            The initialization of TCP instance is done. \r
+  @retval EFI_SUCCESS            The initialization of session is done. \r
   @retval Others                 Other error as indicated.\r
 \r
 **/\r
 EFI_STATUS\r
-HttpInitTcp (\r
+HttpInitSession (\r
   IN  HTTP_PROTOCOL    *HttpInstance,\r
   IN  HTTP_TOKEN_WRAP  *Wrap,\r
-  IN  BOOLEAN          Configure\r
+  IN  BOOLEAN          Configure,\r
+  IN  BOOLEAN          TlsConfigure\r
   )\r
 {\r
   EFI_STATUS           Status;\r
   ASSERT (HttpInstance != NULL);\r
 \r
+  //\r
+  // Configure Tls session.\r
+  //\r
+  if (TlsConfigure) {\r
+    Status = TlsConfigureSession (HttpInstance);\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
+\r
   if (!HttpInstance->LocalAddressIsIPv6) {\r
     //\r
     // Configure TCP instance.\r
@@ -1338,7 +1445,7 @@ HttpInitTcp (
 }\r
 \r
 /**\r
-  Send the HTTP message through TCP4 or TCP6.\r
+  Send the HTTP or HTTPS message through TCP4 or TCP6.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
   @param[in]  Wrap               The HTTP token's wrap data.\r
@@ -1362,14 +1469,64 @@ HttpTransmitTcp (
   EFI_TCP4_PROTOCOL             *Tcp4;\r
   EFI_TCP6_IO_TOKEN             *Tx6Token;\r
   EFI_TCP6_PROTOCOL             *Tcp6;\r
+  UINT8                         *Buffer;  \r
+  UINTN                         BufferSize;\r
+  NET_FRAGMENT                  TempFragment;\r
+\r
+  Status                = EFI_SUCCESS;\r
+  Buffer                = NULL;\r
+\r
+  //\r
+  // Need to encrypt data.\r
+  //\r
+  if (HttpInstance->UseHttps) {\r
+    //\r
+    // Build BufferOut data\r
+    //\r
+    BufferSize = sizeof (TLS_RECORD_HEADER) + TxStringLen;\r
+    Buffer     = AllocateZeroPool (BufferSize);\r
+    if (Buffer == NULL) {\r
+      Status = EFI_OUT_OF_RESOURCES;\r
+      return Status;\r
+    }\r
+    ((TLS_RECORD_HEADER *) Buffer)->ContentType = TLS_CONTENT_TYPE_APPLICATION_DATA;\r
+    ((TLS_RECORD_HEADER *) Buffer)->Version.Major = HttpInstance->TlsConfigData.Version.Major;\r
+    ((TLS_RECORD_HEADER *) Buffer)->Version.Minor = HttpInstance->TlsConfigData.Version.Minor;\r
+    ((TLS_RECORD_HEADER *) Buffer)->Length = (UINT16) (TxStringLen);\r
+    CopyMem (Buffer + sizeof (TLS_RECORD_HEADER), TxString, TxStringLen);\r
+    \r
+    //\r
+    // Encrypt Packet.\r
+    //\r
+    Status = TlsProcessMessage (\r
+               HttpInstance, \r
+               Buffer, \r
+               BufferSize, \r
+               EfiTlsEncrypt, \r
+               &TempFragment\r
+               );\r
+    \r
+    FreePool (Buffer);\r
+\r
+    if (EFI_ERROR (Status)) {\r
+      return Status;\r
+    }\r
+  }\r
   \r
-  if (!HttpInstance->LocalAddressIsIPv6) {     \r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
     Tcp4 = HttpInstance->Tcp4;\r
     Tx4Token = &Wrap->TcpWrap.Tx4Token;\r
+\r
+    if (HttpInstance->UseHttps) {\r
+      Tx4Token->Packet.TxData->DataLength = TempFragment.Len;\r
+      Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = TempFragment.Len;\r
+      Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TempFragment.Bulk;\r
+    } else {\r
+      Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen;\r
+      Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;\r
+      Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;\r
+    }\r
     \r
-    Tx4Token->Packet.TxData->DataLength = (UINT32) TxStringLen;\r
-    Tx4Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;\r
-    Tx4Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;\r
     Tx4Token->CompletionToken.Status = EFI_NOT_READY;  \r
     \r
     Wrap->TcpWrap.IsTxDone = FALSE;\r
@@ -1382,10 +1539,17 @@ HttpTransmitTcp (
   } else {\r
     Tcp6 = HttpInstance->Tcp6;\r
     Tx6Token = &Wrap->TcpWrap.Tx6Token;\r
-\r
-    Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen;\r
-    Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;\r
-    Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;\r
+    \r
+    if (HttpInstance->UseHttps) {\r
+      Tx6Token->Packet.TxData->DataLength = TempFragment.Len;\r
+      Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = TempFragment.Len;\r
+      Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TempFragment.Bulk;\r
+    } else {\r
+      Tx6Token->Packet.TxData->DataLength = (UINT32) TxStringLen;\r
+      Tx6Token->Packet.TxData->FragmentTable[0].FragmentLength = (UINT32) TxStringLen;\r
+      Tx6Token->Packet.TxData->FragmentTable[0].FragmentBuffer = (VOID *) TxString;\r
+    }\r
+    \r
     Tx6Token->CompletionToken.Status = EFI_NOT_READY;\r
 \r
     Wrap->TcpWrap.IsTxDone = FALSE;\r
@@ -1396,7 +1560,6 @@ HttpTransmitTcp (
     }\r
   }\r
   \r
-\r
   return Status;\r
 }\r
 \r
@@ -1466,7 +1629,7 @@ HttpTcpNotReady (
 }\r
 \r
 /**\r
-  Transmit the HTTP mssage by processing the associated HTTP token.\r
+  Transmit the HTTP or HTTPS mssage by processing the associated HTTP token.\r
 \r
   @param[in]  Map                The container of Tx4Token or Tx6Token.\r
   @param[in]  Item               Current item to check against.\r
@@ -1590,6 +1753,7 @@ HttpTcpReceiveHeader (
   CHAR8                         **EndofHeader;\r
   CHAR8                         **HttpHeaders;\r
   CHAR8                         *Buffer;\r
+  NET_FRAGMENT                  Fragment;\r
 \r
   ASSERT (HttpInstance != NULL);\r
 \r
@@ -1600,6 +1764,8 @@ HttpTcpReceiveHeader (
   Buffer      = NULL;\r
   Rx4Token    = NULL;\r
   Rx6Token    = NULL;\r
+  Fragment.Len  = 0;\r
+  Fragment.Bulk = NULL;\r
   \r
   if (HttpInstance->LocalAddressIsIPv6) {\r
     ASSERT (Tcp6 != NULL);\r
@@ -1607,146 +1773,211 @@ HttpTcpReceiveHeader (
     ASSERT (Tcp4 != NULL);\r
   }\r
 \r
-  if (!HttpInstance->LocalAddressIsIPv6) {\r
-    Rx4Token = &HttpInstance->Rx4Token;\r
-    Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);\r
-    if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
+  if (!HttpInstance->UseHttps) {\r
+    Status = HttpCreateTcpRxEventForHeader (HttpInstance);\r
+    if (EFI_ERROR (Status)) {\r
       return Status;\r
     }\r
+  }\r
+\r
+  if (!HttpInstance->LocalAddressIsIPv6) {\r
+    if (!HttpInstance->UseHttps) {\r
+      Rx4Token = &HttpInstance->Rx4Token;\r
+      Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);\r
+      if (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        return Status;\r
+      }\r
+    }\r
   \r
     //\r
     // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.\r
     //\r
-    while (*EndofHeader == NULL) {   \r
-      HttpInstance->IsRxDone = FALSE;\r
-      Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;\r
-      Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;\r
-      Status = Tcp4->Receive (Tcp4, Rx4Token);\r
-      if (EFI_ERROR (Status)) {\r
-        DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));\r
-        return Status;\r
-      }\r
-      \r
-      while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
-        Tcp4->Poll (Tcp4);\r
+    while (*EndofHeader == NULL) {\r
+      if (!HttpInstance->UseHttps) {\r
+        HttpInstance->IsRxDone = FALSE;\r
+        Rx4Token->Packet.RxData->DataLength = DEF_BUF_LEN;\r
+        Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;\r
+        Status = Tcp4->Receive (Tcp4, Rx4Token);\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));\r
+          return Status;\r
+        }\r
+\r
+        while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
+          Tcp4->Poll (Tcp4);\r
+        }\r
+\r
+        if (!HttpInstance->IsRxDone) {\r
+          //\r
+          // Cancle the Token before close its Event.\r
+          //\r
+          Tcp4->Cancel (HttpInstance->Tcp4, &Rx4Token->CompletionToken);\r
+          gBS->CloseEvent (Rx4Token->CompletionToken.Event);\r
+          Rx4Token->CompletionToken.Status = EFI_TIMEOUT;\r
+        }\r
+\r
+        Status = Rx4Token->CompletionToken.Status;\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
+        }\r
+        \r
+        Fragment.Len  = Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength;\r
+        Fragment.Bulk = (UINT8 *) Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer;\r
+      } else {\r
+        if (Fragment.Bulk != NULL) {\r
+          FreePool (Fragment.Bulk);\r
+          Fragment.Bulk = NULL;\r
+        }\r
+        \r
+        Status = HttpsReceive (HttpInstance, &Fragment, Timeout);\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR, "Tcp4 receive failed: %r\n", Status));\r
+          return Status;\r
+        }\r
       }\r
 \r
-      if (!HttpInstance->IsRxDone) {\r
-        //\r
-        // Cancle the Token before close its Event.\r
-        //\r
-        Tcp4->Cancel (HttpInstance->Tcp4, &Rx4Token->CompletionToken);\r
-        gBS->CloseEvent (Rx4Token->CompletionToken.Event);\r
-        Rx4Token->CompletionToken.Status = EFI_TIMEOUT;\r
-      }\r
-  \r
-      Status = Rx4Token->CompletionToken.Status;\r
-      if (EFI_ERROR (Status)) {\r
-        return Status;\r
-      }\r
-  \r
       //\r
       // Append the response string.\r
       //\r
-      *BufferSize = (*SizeofHeaders) + Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength;\r
+      *BufferSize = *SizeofHeaders + Fragment.Len;\r
       Buffer      = AllocateZeroPool (*BufferSize);\r
       if (Buffer == NULL) {\r
         Status = EFI_OUT_OF_RESOURCES;\r
         return Status;\r
       }\r
-  \r
+\r
       if (*HttpHeaders != NULL) {\r
-        CopyMem (Buffer, *HttpHeaders, (*SizeofHeaders));\r
+        CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);\r
         FreePool (*HttpHeaders);\r
       }\r
-  \r
+\r
       CopyMem (\r
-        Buffer + (*SizeofHeaders),\r
-        Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer,\r
-        Rx4Token->Packet.RxData->FragmentTable[0].FragmentLength\r
+        Buffer + *SizeofHeaders,\r
+        Fragment.Bulk,\r
+        Fragment.Len\r
         );\r
-      *HttpHeaders    = Buffer;\r
-      *SizeofHeaders  = *BufferSize;\r
-  \r
+      *HttpHeaders   = Buffer;\r
+      *SizeofHeaders = *BufferSize;\r
+\r
       //\r
       // Check whether we received end of HTTP headers.\r
       //\r
       *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR); \r
-    }\r
-    FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
-    Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
+    };\r
     \r
+    //\r
+    // Free the buffer.\r
+    //\r
+    if (Rx4Token != NULL && Rx4Token->Packet.RxData != NULL && Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+      FreePool (Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+      Rx4Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
+      Fragment.Bulk = NULL;\r
+    }\r
+\r
+    if (Fragment.Bulk != NULL) {\r
+      FreePool (Fragment.Bulk);\r
+      Fragment.Bulk = NULL;\r
+    } \r
   } else {\r
-    Rx6Token = &HttpInstance->Rx6Token;\r
-    Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);\r
-    if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {\r
-      Status = EFI_OUT_OF_RESOURCES;\r
-      return Status;\r
+    if (!HttpInstance->UseHttps) {\r
+      Rx6Token = &HttpInstance->Rx6Token;\r
+      Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = AllocateZeroPool (DEF_BUF_LEN);\r
+      if (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer == NULL) {\r
+        Status = EFI_OUT_OF_RESOURCES;\r
+        return Status;\r
+      }\r
     }\r
   \r
     //\r
     // Receive the HTTP headers only when EFI_HTTP_RESPONSE_DATA is not NULL.\r
     //\r
-    while (*EndofHeader == NULL) {   \r
-      HttpInstance->IsRxDone = FALSE;\r
-      Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;\r
-      Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;\r
-      Status = Tcp6->Receive (Tcp6, Rx6Token);\r
-      if (EFI_ERROR (Status)) {\r
-        DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));\r
-        return Status;\r
-      }\r
-      \r
-      while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
-        Tcp6->Poll (Tcp6);\r
+    while (*EndofHeader == NULL) {\r
+      if (!HttpInstance->UseHttps) {\r
+        HttpInstance->IsRxDone = FALSE;\r
+        Rx6Token->Packet.RxData->DataLength = DEF_BUF_LEN;\r
+        Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength = DEF_BUF_LEN;\r
+        Status = Tcp6->Receive (Tcp6, Rx6Token);\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));\r
+          return Status;\r
+        }\r
+\r
+        while (!HttpInstance->IsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {\r
+          Tcp6->Poll (Tcp6);\r
+        }\r
+\r
+        if (!HttpInstance->IsRxDone) {\r
+          //\r
+          // Cancle the Token before close its Event.\r
+          //\r
+          Tcp6->Cancel (HttpInstance->Tcp6, &Rx6Token->CompletionToken);\r
+          gBS->CloseEvent (Rx6Token->CompletionToken.Event);\r
+          Rx6Token->CompletionToken.Status = EFI_TIMEOUT;\r
+        }\r
+\r
+        Status = Rx6Token->CompletionToken.Status;\r
+        if (EFI_ERROR (Status)) {\r
+          return Status;\r
+        }\r
+        \r
+        Fragment.Len  = Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength;\r
+        Fragment.Bulk = (UINT8 *) Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer;\r
+      } else {\r
+        if (Fragment.Bulk != NULL) {\r
+          FreePool (Fragment.Bulk);\r
+          Fragment.Bulk = NULL;\r
+        }\r
+        \r
+        Status = HttpsReceive (HttpInstance, &Fragment, Timeout);\r
+        if (EFI_ERROR (Status)) {\r
+          DEBUG ((EFI_D_ERROR, "Tcp6 receive failed: %r\n", Status));\r
+          return Status;\r
+        }\r
       }\r
 \r
-      if (!HttpInstance->IsRxDone) {\r
-        //\r
-        // Cancle the Token before close its Event.\r
-        //\r
-        Tcp6->Cancel (HttpInstance->Tcp6, &Rx6Token->CompletionToken);\r
-        gBS->CloseEvent (Rx6Token->CompletionToken.Event);\r
-        Rx6Token->CompletionToken.Status = EFI_TIMEOUT;\r
-      }\r
-  \r
-      Status = Rx6Token->CompletionToken.Status;\r
-      if (EFI_ERROR (Status)) {\r
-        return Status;\r
-      }\r
-  \r
       //\r
       // Append the response string.\r
       //\r
-      *BufferSize = (*SizeofHeaders) + Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength;\r
+      *BufferSize = *SizeofHeaders + Fragment.Len;\r
       Buffer      = AllocateZeroPool (*BufferSize);\r
       if (Buffer == NULL) {\r
         Status = EFI_OUT_OF_RESOURCES;\r
         return Status;\r
       }\r
-  \r
+\r
       if (*HttpHeaders != NULL) {\r
-        CopyMem (Buffer, *HttpHeaders, (*SizeofHeaders));\r
+        CopyMem (Buffer, *HttpHeaders, *SizeofHeaders);\r
         FreePool (*HttpHeaders);\r
       }\r
-  \r
+\r
       CopyMem (\r
-        Buffer + (*SizeofHeaders),\r
-        Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer,\r
-        Rx6Token->Packet.RxData->FragmentTable[0].FragmentLength\r
+        Buffer + *SizeofHeaders,\r
+        Fragment.Bulk,\r
+        Fragment.Len\r
         );\r
-      *HttpHeaders     = Buffer;\r
-      *SizeofHeaders  = *BufferSize;\r
-  \r
+      *HttpHeaders   = Buffer;\r
+      *SizeofHeaders = *BufferSize;\r
+\r
       //\r
       // Check whether we received end of HTTP headers.\r
       //\r
-      *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR);\r
-  \r
+      *EndofHeader = AsciiStrStr (*HttpHeaders, HTTP_END_OF_HDR_STR); \r
+    };\r
+\r
+    //\r
+    // Free the buffer.\r
+    //\r
+    if (Rx6Token != NULL && Rx6Token->Packet.RxData != NULL && Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer != NULL) {\r
+      FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
+      Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;\r
+      Fragment.Bulk = NULL;\r
+    }\r
+\r
+    if (Fragment.Bulk != NULL) {\r
+      FreePool (Fragment.Bulk);\r
+      Fragment.Bulk = NULL;\r
     }\r
-    FreePool (Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer);\r
-    Rx6Token->Packet.RxData->FragmentTable[0].FragmentBuffer = NULL;    \r
   }     \r
 \r
   //\r
index e1fd785..ced8aca 100644 (file)
@@ -83,6 +83,13 @@ typedef struct {
   EFI_HTTP_METHOD               Method;\r
 } HTTP_TCP_TOKEN_WRAP;\r
 \r
+typedef struct {\r
+  EFI_TLS_VERSION               Version;\r
+  EFI_TLS_CONNECTION_END        ConnectionEnd;\r
+  EFI_TLS_VERIFY                VerifyMethod;\r
+  EFI_TLS_SESSION_STATE         SessionState;\r
+} TLS_CONFIG_DATA;\r
+\r
 typedef struct _HTTP_PROTOCOL {\r
   UINT32                        Signature;\r
   EFI_HTTP_PROTOCOL             Http;\r
@@ -153,6 +160,35 @@ typedef struct _HTTP_PROTOCOL {
   NET_MAP                       RxTokens;\r
 \r
   CHAR8                         *Url;\r
+\r
+  //\r
+  // Https Support\r
+  //\r
+  BOOLEAN                          UseHttps;\r
+  \r
+  EFI_HANDLE                       TlsChildHandle; /// Tls ChildHandle\r
+  TLS_CONFIG_DATA                  TlsConfigData;\r
+  EFI_TLS_PROTOCOL                 *Tls;\r
+  EFI_TLS_CONFIGURATION_PROTOCOL   *TlsConfiguration;\r
+  EFI_TLS_SESSION_STATE            TlsSessionState;\r
+\r
+  //\r
+  // TlsTxData used for transmitting TLS related messages.\r
+  //\r
+  EFI_TCP4_IO_TOKEN                Tcp4TlsTxToken;\r
+  EFI_TCP4_TRANSMIT_DATA           Tcp4TlsTxData;\r
+  EFI_TCP6_IO_TOKEN                Tcp6TlsTxToken;\r
+  EFI_TCP6_TRANSMIT_DATA           Tcp6TlsTxData;\r
+  BOOLEAN                          TlsIsTxDone;\r
+\r
+  //\r
+  // TlsRxData used for receiving TLS related messages.\r
+  //\r
+  EFI_TCP4_IO_TOKEN                Tcp4TlsRxToken;\r
+  EFI_TCP4_RECEIVE_DATA            Tcp4TlsRxData;\r
+  EFI_TCP6_IO_TOKEN                Tcp6TlsRxToken;\r
+  EFI_TCP6_RECEIVE_DATA            Tcp6TlsRxData;\r
+  BOOLEAN                          TlsIsRxDone;\r
 } HTTP_PROTOCOL;\r
 \r
 typedef struct {\r
@@ -352,7 +388,8 @@ HttpConfigureTcp6 (
   );\r
 \r
 /**\r
-  Check existing TCP connection, if in error state, receover TCP4 connection.\r
+  Check existing TCP connection, if in error state, recover TCP4 connection. Then, \r
+  connect one TLS session if required.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
 \r
@@ -367,7 +404,8 @@ HttpConnectTcp4 (
   );\r
 \r
 /**\r
-  Check existing TCP connection, if in error state, recover TCP6 connection.\r
+  Check existing TCP connection, if in error state, recover TCP6 connection. Then, \r
+  connect one TLS session if required.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
 \r
@@ -382,7 +420,7 @@ HttpConnectTcp6 (
   );\r
 \r
 /**\r
-  Send the HTTP message through TCP4 or TCP6.\r
+  Send the HTTP or HTTPS message through TCP4 or TCP6.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
   @param[in]  Wrap               The HTTP token's wrap data.\r
@@ -443,25 +481,27 @@ HttpTcpNotReady (
   );\r
 \r
 /**\r
-  Initialize TCP related data.\r
+  Initialize Http session.\r
 \r
   @param[in]  HttpInstance       The HTTP instance private data.\r
   @param[in]  Wrap               The HTTP token's wrap data.\r
-  @param[in]  Configure          The Flag indicates whether the first time to initialize Tcp.\r
+  @param[in]  Configure          The Flag indicates whether need to initialize session.\r
+  @param[in]  TlsConfigure       The Flag indicates whether it's the new Tls session.\r
 \r
-  @retval EFI_SUCCESS            The initialization of TCP instance is done. \r
+  @retval EFI_SUCCESS            The initialization of session is done. \r
   @retval Others                 Other error as indicated.\r
 \r
 **/\r
 EFI_STATUS\r
-HttpInitTcp (\r
+HttpInitSession (\r
   IN  HTTP_PROTOCOL    *HttpInstance,\r
   IN  HTTP_TOKEN_WRAP  *Wrap,\r
-  IN  BOOLEAN          Configure\r
+  IN  BOOLEAN          Configure,\r
+  IN  BOOLEAN          TlsConfigure\r
   );\r
 \r
 /**\r
-  Transmit the HTTP mssage by processing the associated HTTP token.\r
+  Transmit the HTTP or HTTPS mssage by processing the associated HTTP token.\r
 \r
   @param[in]  Map                The container of TxToken or Tx6Token.\r
   @param[in]  Item               Current item to check against.\r
diff --git a/NetworkPkg/HttpDxe/HttpsSupport.c b/NetworkPkg/HttpDxe/HttpsSupport.c
new file mode 100644 (file)
index 0000000..478a9e0
--- /dev/null
@@ -0,0 +1,1693 @@
+/** @file
+  Miscellaneous routines specific to Https for HttpDxe driver.
+
+Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution.  The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "HttpDriver.h"
+
+/**
+  Returns the first occurrence of a Null-terminated ASCII sub-string in a Null-terminated
+  ASCII string and ignore case during the search process.
+
+  This function scans the contents of the ASCII string specified by String
+  and returns the first occurrence of SearchString and ignore case during the search process.
+  If SearchString is not found in String, then NULL is returned. If the length of SearchString
+  is zero, then String is returned.
+
+  If String is NULL, then ASSERT().
+  If SearchString is NULL, then ASSERT().
+
+  @param[in]  String          A pointer to a Null-terminated ASCII string.
+  @param[in]  SearchString    A pointer to a Null-terminated ASCII string to search for.
+
+  @retval NULL            If the SearchString does not appear in String.
+  @retval others          If there is a match return the first occurrence of SearchingString.
+                          If the length of SearchString is zero,return String.
+
+**/
+CHAR8 *
+AsciiStrCaseStr (
+  IN      CONST CHAR8               *String,
+  IN      CONST CHAR8               *SearchString
+  )
+{
+  CONST CHAR8 *FirstMatch;
+  CONST CHAR8 *SearchStringTmp;
+
+  CHAR8 Src;
+  CHAR8 Dst;
+
+  //
+  // ASSERT both strings are less long than PcdMaximumAsciiStringLength
+  //
+  ASSERT (AsciiStrSize (String) != 0);
+  ASSERT (AsciiStrSize (SearchString) != 0);
+
+  if (*SearchString == '\0') {
+    return (CHAR8 *) String;
+  }
+
+  while (*String != '\0') {
+    SearchStringTmp = SearchString;
+    FirstMatch = String;
+
+    while ((*SearchStringTmp != '\0')
+            && (*String != '\0')) {
+      Src = *String;
+      Dst = *SearchStringTmp;
+
+      if ((Src >= 'A') && (Src <= 'Z')) {
+        Src -= ('A' - 'a');
+      }
+
+      if ((Dst >= 'A') && (Dst <= 'Z')) {
+        Dst -= ('A' - 'a');
+      }
+
+      if (Src != Dst) {
+        break;
+      }
+
+      String++;
+      SearchStringTmp++;
+    }
+
+    if (*SearchStringTmp == '\0') {
+      return (CHAR8 *) FirstMatch;
+    }
+
+    String = FirstMatch + 1;
+  }
+
+  return NULL;
+}
+
+/**
+  The callback function to free the net buffer list.
+
+  @param[in]  Arg The opaque parameter.
+
+**/
+VOID
+EFIAPI
+FreeNbufList (
+  IN VOID *Arg
+  )
+{
+  ASSERT (Arg != NULL);
+
+  NetbufFreeList ((LIST_ENTRY *) Arg);
+  FreePool (Arg);
+}
+
+/**
+  Check whether the Url is from Https.
+
+  @param[in]    Url             The pointer to a HTTP or HTTPS URL string.
+
+  @retval TRUE                  The Url is from HTTPS.
+  @retval FALSE                 The Url is from HTTP.
+
+**/
+BOOLEAN
+IsHttpsUrl (
+  IN CHAR8    *Url
+  )
+{
+  CHAR8  *Tmp;
+
+  Tmp = NULL;
+
+  Tmp = AsciiStrCaseStr (Url, HTTPS_FLAG);
+  if (Tmp != NULL && Tmp == Url) {
+    return TRUE;
+  }
+
+  return FALSE;
+}
+
+/**
+  Creates a Tls child handle, open EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
+
+  @param[in]  ImageHandle           The firmware allocated handle for the UEFI image.
+  @param[out] TlsProto              Pointer to the EFI_TLS_PROTOCOL instance.
+  @param[out] TlsConfiguration      Pointer to the EFI_TLS_CONFIGURATION_PROTOCOL instance.
+
+  @return  The child handle with opened EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
+
+**/
+EFI_HANDLE
+EFIAPI
+TlsCreateChild (
+  IN  EFI_HANDLE                     ImageHandle,
+  OUT EFI_TLS_PROTOCOL               **TlsProto,
+  OUT EFI_TLS_CONFIGURATION_PROTOCOL **TlsConfiguration
+  )
+{
+  EFI_STATUS                    Status;
+  EFI_SERVICE_BINDING_PROTOCOL  *TlsSb;
+  EFI_HANDLE                    TlsChildHandle;
+
+  TlsSb          = NULL;
+  TlsChildHandle = 0;
+
+  //
+  // Locate TlsServiceBinding protocol.
+  //
+  gBS->LocateProtocol (
+     &gEfiTlsServiceBindingProtocolGuid,
+     NULL,
+     (VOID **) &TlsSb
+     );
+  if (TlsSb == NULL) {
+    return NULL;
+  }
+
+  Status = TlsSb->CreateChild (TlsSb, &TlsChildHandle);
+  if (EFI_ERROR (Status)) {
+    return NULL;
+  }
+
+  Status = gBS->OpenProtocol (
+                  TlsChildHandle,
+                  &gEfiTlsProtocolGuid,
+                  (VOID **) TlsProto,
+                  ImageHandle,
+                  TlsChildHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    TlsSb->DestroyChild (TlsSb, TlsChildHandle);
+    return NULL;
+  }
+
+  Status = gBS->OpenProtocol (
+                  TlsChildHandle,
+                  &gEfiTlsConfigurationProtocolGuid,
+                  (VOID **) TlsConfiguration,
+                  ImageHandle,
+                  TlsChildHandle,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    TlsSb->DestroyChild (TlsSb, TlsChildHandle);
+    return NULL;
+  }
+
+  return TlsChildHandle;
+}
+
+/**
+  Create event for the TLS receive and transmit tokens which are used to receive and
+  transmit TLS related messages.
+
+  @param[in, out]  HttpInstance       Pointer to HTTP_PROTOCOL structure.
+
+  @retval EFI_SUCCESS            The events are created successfully.
+  @retval others                 Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsCreateTxRxEvent (
+  IN OUT HTTP_PROTOCOL      *HttpInstance
+  )
+{
+  EFI_STATUS                Status;
+
+  if (!HttpInstance->LocalAddressIsIPv6) {
+    //
+    // For Tcp4TlsTxToken.
+    //
+    Status = gBS->CreateEvent (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_NOTIFY,
+                    HttpCommonNotify,
+                    &HttpInstance->TlsIsTxDone,
+                    &HttpInstance->Tcp4TlsTxToken.CompletionToken.Event
+                    );
+    if (EFI_ERROR (Status)) {
+      goto ERROR;
+    }
+
+    HttpInstance->Tcp4TlsTxData.Push = TRUE;
+    HttpInstance->Tcp4TlsTxData.Urgent = FALSE;
+    HttpInstance->Tcp4TlsTxData.DataLength = 0;
+    HttpInstance->Tcp4TlsTxData.FragmentCount = 1;
+    HttpInstance->Tcp4TlsTxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp4TlsTxData.DataLength;
+    HttpInstance->Tcp4TlsTxData.FragmentTable[0].FragmentBuffer = NULL;
+    HttpInstance->Tcp4TlsTxToken.Packet.TxData = &HttpInstance->Tcp4TlsTxData;
+    HttpInstance->Tcp4TlsTxToken.CompletionToken.Status = EFI_NOT_READY;
+
+    //
+    // For Tcp4TlsRxToken.
+    //
+    Status = gBS->CreateEvent (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_NOTIFY,
+                    HttpCommonNotify,
+                    &HttpInstance->TlsIsRxDone,
+                    &HttpInstance->Tcp4TlsRxToken.CompletionToken.Event
+                    );
+    if (EFI_ERROR (Status)) {
+      goto ERROR;
+    }
+
+    HttpInstance->Tcp4TlsRxData.DataLength                       = 0;
+    HttpInstance->Tcp4TlsRxData.FragmentCount                    = 1;
+    HttpInstance->Tcp4TlsRxData.FragmentTable[0].FragmentLength  = HttpInstance->Tcp4TlsRxData.DataLength ;
+    HttpInstance->Tcp4TlsRxData.FragmentTable[0].FragmentBuffer  = NULL;
+    HttpInstance->Tcp4TlsRxToken.Packet.RxData          = &HttpInstance->Tcp4TlsRxData;
+    HttpInstance->Tcp4TlsRxToken.CompletionToken.Status = EFI_NOT_READY;
+  } else {
+    //
+    // For Tcp6TlsTxToken.
+    //
+    Status = gBS->CreateEvent (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_NOTIFY,
+                    HttpCommonNotify,
+                    &HttpInstance->TlsIsTxDone,
+                    &HttpInstance->Tcp6TlsTxToken.CompletionToken.Event
+                    );
+    if (EFI_ERROR (Status)) {
+      goto ERROR;
+    }
+
+    HttpInstance->Tcp6TlsTxData.Push = TRUE;
+    HttpInstance->Tcp6TlsTxData.Urgent = FALSE;
+    HttpInstance->Tcp6TlsTxData.DataLength = 0;
+    HttpInstance->Tcp6TlsTxData.FragmentCount = 1;
+    HttpInstance->Tcp6TlsTxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp6TlsTxData.DataLength;
+    HttpInstance->Tcp6TlsTxData.FragmentTable[0].FragmentBuffer = NULL;
+    HttpInstance->Tcp6TlsTxToken.Packet.TxData = &HttpInstance->Tcp6TlsTxData;
+    HttpInstance->Tcp6TlsTxToken.CompletionToken.Status = EFI_NOT_READY;
+
+    //
+    // For Tcp6TlsRxToken.
+    //
+    Status = gBS->CreateEvent (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_NOTIFY,
+                    HttpCommonNotify,
+                    &HttpInstance->TlsIsRxDone,
+                    &HttpInstance->Tcp6TlsRxToken.CompletionToken.Event
+                    );
+    if (EFI_ERROR (Status)) {
+      goto ERROR;
+    }
+
+    HttpInstance->Tcp6TlsRxData.DataLength                       = 0;
+    HttpInstance->Tcp6TlsRxData.FragmentCount                    = 1;
+    HttpInstance->Tcp6TlsRxData.FragmentTable[0].FragmentLength  = HttpInstance->Tcp6TlsRxData.DataLength ;
+    HttpInstance->Tcp6TlsRxData.FragmentTable[0].FragmentBuffer  = NULL;
+    HttpInstance->Tcp6TlsRxToken.Packet.RxData          = &HttpInstance->Tcp6TlsRxData;
+    HttpInstance->Tcp6TlsRxToken.CompletionToken.Status = EFI_NOT_READY;
+  }
+
+  return Status;
+
+ERROR:
+  //
+  // Error handling
+  //
+  TlsCloseTxRxEvent (HttpInstance);
+
+  return Status;
+}
+
+/**
+  Close events in the TlsTxToken and TlsRxToken.
+
+  @param[in]  HttpInstance   Pointer to HTTP_PROTOCOL structure.
+
+**/
+VOID
+EFIAPI
+TlsCloseTxRxEvent (
+  IN  HTTP_PROTOCOL        *HttpInstance
+  )
+{
+  ASSERT (HttpInstance != NULL);
+  if (!HttpInstance->LocalAddressIsIPv6) {
+    if (NULL != HttpInstance->Tcp4TlsTxToken.CompletionToken.Event) {
+      gBS->CloseEvent(HttpInstance->Tcp4TlsTxToken.CompletionToken.Event);
+      HttpInstance->Tcp4TlsTxToken.CompletionToken.Event = NULL;
+    }
+
+    if (NULL != HttpInstance->Tcp4TlsRxToken.CompletionToken.Event) {
+      gBS->CloseEvent (HttpInstance->Tcp4TlsRxToken.CompletionToken.Event);
+      HttpInstance->Tcp4TlsRxToken.CompletionToken.Event = NULL;
+    }
+  } else {
+    if (NULL != HttpInstance->Tcp6TlsTxToken.CompletionToken.Event) {
+      gBS->CloseEvent(HttpInstance->Tcp6TlsTxToken.CompletionToken.Event);
+      HttpInstance->Tcp6TlsTxToken.CompletionToken.Event = NULL;
+    }
+
+    if (NULL != HttpInstance->Tcp6TlsRxToken.CompletionToken.Event) {
+      gBS->CloseEvent (HttpInstance->Tcp6TlsRxToken.CompletionToken.Event);
+      HttpInstance->Tcp6TlsRxToken.CompletionToken.Event = NULL;
+    }
+  }
+}
+
+/**
+  Read the TlsCaCertificate variable and configure it.
+
+  @param[in, out]  HttpInstance       The HTTP instance private data.
+
+  @retval EFI_SUCCESS            TlsCaCertificate is configured.
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
+  @retval EFI_NOT_FOUND          Fail to get 'TlsCaCertificate' variable.
+  @retval Others                 Other error as indicated.
+
+**/
+EFI_STATUS
+TlsConfigCertificate (
+  IN OUT HTTP_PROTOCOL      *HttpInstance
+  )
+{
+  EFI_STATUS          Status;
+  UINT8               *CACert;
+  UINTN               CACertSize;
+  UINT32              Index;
+  EFI_SIGNATURE_LIST  *CertList;
+  EFI_SIGNATURE_DATA  *Cert;
+  UINTN               CertCount;
+  UINT32              ItemDataSize;
+
+  CACert     = NULL;
+  CACertSize = 0;
+  
+  //
+  // Try to read the TlsCaCertificate variable.
+  //
+  Status  = gRT->GetVariable (
+                   EFI_TLS_CA_CERTIFICATE_VARIABLE,
+                   &gEfiTlsCaCertificateGuid,
+                   NULL,
+                   &CACertSize,
+                   NULL
+                   );
+
+  if (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)) {
+        FreePool (CACert);
+        return Status;
+      }
+
+      Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
+    }
+
+    ItemDataSize -= CertList->SignatureListSize;
+    CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
+  }
+
+  FreePool (CACert);
+  return Status;
+}
+
+/**
+  Configure TLS session data.
+
+  @param[in, out]  HttpInstance       The HTTP instance private data.
+
+  @retval EFI_SUCCESS            TLS session data is configured.
+  @retval Others                 Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsConfigureSession (
+  IN OUT HTTP_PROTOCOL      *HttpInstance
+  )
+{
+  EFI_STATUS                 Status;
+
+  //
+  // TlsConfigData initialization
+  //
+  HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient;
+  HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER;
+  HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted;
+
+  //
+  // EfiTlsConnectionEnd,
+  // EfiTlsVerifyMethod
+  // EfiTlsSessionState
+  //
+  Status = HttpInstance->Tls->SetSessionData (
+                                HttpInstance->Tls,
+                                EfiTlsConnectionEnd,
+                                &(HttpInstance->TlsConfigData.ConnectionEnd),
+                                sizeof (EFI_TLS_CONNECTION_END)
+                                );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = HttpInstance->Tls->SetSessionData (
+                                HttpInstance->Tls,
+                                EfiTlsVerifyMethod,
+                                &HttpInstance->TlsConfigData.VerifyMethod,
+                                sizeof (EFI_TLS_VERIFY)
+                                );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = HttpInstance->Tls->SetSessionData (
+                                HttpInstance->Tls,
+                                EfiTlsSessionState,
+                                &(HttpInstance->TlsConfigData.SessionState),
+                                sizeof (EFI_TLS_SESSION_STATE)
+                                );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Tls Config Certificate
+  //
+  Status = TlsConfigCertificate (HttpInstance);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((EFI_D_ERROR, "TLS Certificate Config Error!\n"));
+    return Status;
+  }
+
+  //
+  // TlsCreateTxRxEvent
+  //
+  Status = TlsCreateTxRxEvent (HttpInstance);
+  if (EFI_ERROR (Status)) {
+    goto ERROR;
+  }
+
+  return Status;
+
+ERROR:
+  TlsCloseTxRxEvent (HttpInstance);
+
+  return Status;
+}
+
+/**
+  Transmit the Packet by processing the associated HTTPS token.
+
+  @param[in, out]   HttpInstance    Pointer to HTTP_PROTOCOL structure.
+  @param[in]        Packet          The packet to transmit.
+
+  @retval EFI_SUCCESS            The packet is transmitted.
+  @retval EFI_INVALID_PARAMETER  HttpInstance is NULL or Packet is NULL.
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
+  @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
+  @retval Others                 Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsCommonTransmit (
+  IN OUT HTTP_PROTOCOL      *HttpInstance,
+  IN     NET_BUF            *Packet
+  )
+{
+  EFI_STATUS                Status;
+  VOID                      *Data;
+  UINTN                     Size;
+
+  if ((HttpInstance == NULL) || (Packet == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (!HttpInstance->LocalAddressIsIPv6) {
+    Size = sizeof (EFI_TCP4_TRANSMIT_DATA) +
+           (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA);
+  } else {
+    Size = sizeof (EFI_TCP6_TRANSMIT_DATA) +
+           (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA);
+  }
+
+  Data = AllocatePool (Size);
+  if (Data == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  if (!HttpInstance->LocalAddressIsIPv6) {
+    ((EFI_TCP4_TRANSMIT_DATA *) Data)->Push        = TRUE;
+    ((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent      = FALSE;
+    ((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength  = Packet->TotalSize;
+
+    //
+    // Build the fragment table.
+    //
+    ((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
+
+    NetbufBuildExt (
+      Packet,
+      (NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0],
+      &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount
+      );
+
+    HttpInstance->Tcp4TlsTxToken.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data;
+
+    Status = EFI_DEVICE_ERROR;
+
+    //
+    // Transmit the packet.
+    //
+    Status  = HttpInstance->Tcp4->Transmit (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsTxToken);
+    if (EFI_ERROR (Status)) {
+      goto ON_EXIT;
+    }
+
+    while (!HttpInstance->TlsIsTxDone) {
+      HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
+    }
+
+    HttpInstance->TlsIsTxDone = FALSE;
+    Status = HttpInstance->Tcp4TlsTxToken.CompletionToken.Status;
+  } else {
+    ((EFI_TCP6_TRANSMIT_DATA *) Data)->Push        = TRUE;
+    ((EFI_TCP6_TRANSMIT_DATA *) Data)->Urgent      = FALSE;
+    ((EFI_TCP6_TRANSMIT_DATA *) Data)->DataLength  = Packet->TotalSize;
+
+    //
+    // Build the fragment table.
+    //
+    ((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
+
+    NetbufBuildExt (
+      Packet,
+      (NET_FRAGMENT *) &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentTable[0],
+      &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount
+      );
+
+    HttpInstance->Tcp6TlsTxToken.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data;
+
+    Status = EFI_DEVICE_ERROR;
+
+    //
+    // Transmit the packet.
+    //
+    Status  = HttpInstance->Tcp6->Transmit (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsTxToken);
+    if (EFI_ERROR (Status)) {
+      goto ON_EXIT;
+    }
+
+    while (!HttpInstance->TlsIsTxDone) {
+      HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
+    }
+
+    HttpInstance->TlsIsTxDone = FALSE;
+    Status = HttpInstance->Tcp6TlsTxToken.CompletionToken.Status;
+  }
+
+ON_EXIT:
+  FreePool (Data);
+
+  return Status;
+}
+
+/**
+  Receive the Packet by processing the associated HTTPS token.
+
+  @param[in, out]   HttpInstance    Pointer to HTTP_PROTOCOL structure.
+  @param[in]        Packet          The packet to transmit.
+  @param[in]        Timeout         The time to wait for connection done.
+
+  @retval EFI_SUCCESS            The Packet is received.
+  @retval EFI_INVALID_PARAMETER  HttpInstance is NULL or Packet is NULL.
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
+  @retval EFI_TIMEOUT            The operation is time out.
+  @retval Others                 Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsCommonReceive (
+  IN OUT HTTP_PROTOCOL      *HttpInstance,
+  IN     NET_BUF            *Packet,
+  IN     EFI_EVENT          Timeout
+  )
+{
+  EFI_TCP4_RECEIVE_DATA     *Tcp4RxData;
+  EFI_TCP6_RECEIVE_DATA     *Tcp6RxData;
+  EFI_STATUS                Status;
+  NET_FRAGMENT              *Fragment;
+  UINT32                    FragmentCount;
+  UINT32                    CurrentFragment;
+
+  Tcp4RxData = NULL;
+  Tcp6RxData = NULL;
+
+  if ((HttpInstance == NULL) || (Packet == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  FragmentCount = Packet->BlockOpNum;
+  Fragment      = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
+  if (Fragment == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto ON_EXIT;
+  }
+
+  //
+  // Build the fragment table.
+  //
+  NetbufBuildExt (Packet, Fragment, &FragmentCount);
+
+  if (!HttpInstance->LocalAddressIsIPv6) {
+    Tcp4RxData = HttpInstance->Tcp4TlsRxToken.Packet.RxData;
+    if (Tcp4RxData == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+    Tcp4RxData->FragmentCount         = 1;
+  } else {
+    Tcp6RxData = HttpInstance->Tcp6TlsRxToken.Packet.RxData;
+    if (Tcp6RxData == NULL) {
+      return EFI_INVALID_PARAMETER;
+    }
+    Tcp6RxData->FragmentCount         = 1;
+  }
+
+  CurrentFragment               = 0;
+  Status                        = EFI_SUCCESS;
+
+  while (CurrentFragment < FragmentCount) {
+    if (!HttpInstance->LocalAddressIsIPv6) {
+      Tcp4RxData->DataLength                       = Fragment[CurrentFragment].Len;
+      Tcp4RxData->FragmentTable[0].FragmentLength  = Fragment[CurrentFragment].Len;
+      Tcp4RxData->FragmentTable[0].FragmentBuffer  = Fragment[CurrentFragment].Bulk;
+      Status = HttpInstance->Tcp4->Receive (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken);
+    } else {
+      Tcp6RxData->DataLength                       = Fragment[CurrentFragment].Len;
+      Tcp6RxData->FragmentTable[0].FragmentLength  = Fragment[CurrentFragment].Len;
+      Tcp6RxData->FragmentTable[0].FragmentBuffer  = Fragment[CurrentFragment].Bulk;
+      Status = HttpInstance->Tcp6->Receive (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken);
+    }
+    if (EFI_ERROR (Status)) {
+      goto ON_EXIT;
+    }
+
+    while (!HttpInstance->TlsIsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
+      //
+      // Poll until some data is received or an error occurs.
+      //
+      if (!HttpInstance->LocalAddressIsIPv6) {
+        HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
+      } else {
+        HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
+      }
+    }
+
+    if (!HttpInstance->TlsIsRxDone) {
+      //
+      // Timeout occurs, cancel the receive request.
+      //
+      if (!HttpInstance->LocalAddressIsIPv6) {
+        HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken.CompletionToken);
+      } else {
+        HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken.CompletionToken);
+      }
+
+      Status = EFI_TIMEOUT;
+      goto ON_EXIT;
+    } else {
+      HttpInstance->TlsIsRxDone = FALSE;
+    }
+
+    if (!HttpInstance->LocalAddressIsIPv6) {
+      Status = HttpInstance->Tcp4TlsRxToken.CompletionToken.Status;
+      if (EFI_ERROR (Status)) {
+        goto ON_EXIT;
+      }
+
+      Fragment[CurrentFragment].Len -= Tcp4RxData->FragmentTable[0].FragmentLength;
+      if (Fragment[CurrentFragment].Len == 0) {
+        CurrentFragment++;
+      } else {
+        Fragment[CurrentFragment].Bulk += Tcp4RxData->FragmentTable[0].FragmentLength;
+      }
+    } else {
+      Status = HttpInstance->Tcp6TlsRxToken.CompletionToken.Status;
+      if (EFI_ERROR (Status)) {
+        goto ON_EXIT;
+      }
+
+      Fragment[CurrentFragment].Len -= Tcp6RxData->FragmentTable[0].FragmentLength;
+      if (Fragment[CurrentFragment].Len == 0) {
+        CurrentFragment++;
+      } else {
+        Fragment[CurrentFragment].Bulk += Tcp6RxData->FragmentTable[0].FragmentLength;
+      }
+    }
+  }
+
+ON_EXIT:
+
+  if (Fragment != NULL) {
+    FreePool (Fragment);
+  }
+
+  return Status;
+}
+
+/**
+  Receive one TLS PDU. An TLS PDU contains an TLS record header and it's
+  corresponding record data. These two parts will be put into two blocks of buffers in the
+  net buffer.
+
+  @param[in, out]      HttpInstance    Pointer to HTTP_PROTOCOL structure.
+  @param[out]          Pdu             The received TLS PDU.
+  @param[in]           Timeout         The time to wait for connection done.
+
+  @retval EFI_SUCCESS          An TLS PDU is received.
+  @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+  @retval EFI_PROTOCOL_ERROR   An unexpected TLS packet was received.
+  @retval Others               Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsReceiveOnePdu (
+  IN OUT HTTP_PROTOCOL      *HttpInstance,
+     OUT NET_BUF            **Pdu,
+  IN     EFI_EVENT          Timeout
+  )
+{
+  EFI_STATUS      Status;
+
+  LIST_ENTRY      *NbufList;
+
+  UINT32          Len;
+
+  NET_BUF           *PduHdr;
+  UINT8             *Header;
+  TLS_RECORD_HEADER RecordHeader;
+
+  NET_BUF           *DataSeg;
+
+  NbufList = NULL;
+  PduHdr   = NULL;
+  Header   = NULL;
+  DataSeg  = NULL;
+
+  NbufList = AllocatePool (sizeof (LIST_ENTRY));
+  if (NbufList == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  InitializeListHead (NbufList);
+
+  //
+  // Allocate buffer to receive one TLS header.
+  //
+  Len     = sizeof (TLS_RECORD_HEADER);
+  PduHdr  = NetbufAlloc (Len);
+  if (PduHdr == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto ON_EXIT;
+  }
+
+  Header = NetbufAllocSpace (PduHdr, Len, NET_BUF_TAIL);
+  if (Header == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto ON_EXIT;
+  }
+
+  //
+  // First step, receive one TLS header.
+  //
+  Status = TlsCommonReceive (HttpInstance, PduHdr, Timeout);
+  if (EFI_ERROR (Status)) {
+    goto ON_EXIT;
+  }
+
+  RecordHeader = *(TLS_RECORD_HEADER *) Header;
+  if ((RecordHeader.ContentType == TLS_CONTENT_TYPE_HANDSHAKE ||
+    RecordHeader.ContentType == TLS_CONTENT_TYPE_ALERT ||
+    RecordHeader.ContentType == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC ||
+    RecordHeader.ContentType == TLS_CONTENT_TYPE_APPLICATION_DATA) &&
+    (RecordHeader.Version.Major == 0x03) && /// Major versions are same.
+    (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
+    RecordHeader.Version.Minor ==TLS11_PROTOCOL_VERSION_MINOR ||
+    RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
+   ) {
+    InsertTailList (NbufList, &PduHdr->List);
+  } else {
+    Status = EFI_PROTOCOL_ERROR;
+    goto ON_EXIT;
+  }
+
+  Len = SwapBytes16(RecordHeader.Length);
+  if (Len == 0) {
+    //
+    // No TLS payload.
+    //
+    goto FORM_PDU;
+  }
+
+  //
+  // Allocate buffer to receive one TLS payload.
+  //
+  DataSeg = NetbufAlloc (Len);
+  if (DataSeg == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    goto ON_EXIT;
+  }
+
+  NetbufAllocSpace (DataSeg, Len, NET_BUF_TAIL);
+
+  //
+  // Second step, receive one TLS payload.
+  //
+  Status = TlsCommonReceive (HttpInstance, DataSeg, Timeout);
+  if (EFI_ERROR (Status)) {
+    goto ON_EXIT;
+  }
+
+  InsertTailList (NbufList, &DataSeg->List);
+
+FORM_PDU:
+  //
+  // Form the PDU from a list of PDU.
+  //
+  *Pdu = NetbufFromBufList (NbufList, 0, 0, FreeNbufList, NbufList);
+  if (*Pdu == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+  }
+
+ON_EXIT:
+
+  if (EFI_ERROR (Status)) {
+    //
+    // Free the Nbufs in this NbufList and the NbufList itself.
+    //
+    FreeNbufList (NbufList);
+  }
+
+  return Status;
+}
+
+/**
+  Connect one TLS session by finishing the TLS handshake process.
+
+  @param[in]  HttpInstance       The HTTP instance private data.
+  @param[in]  Timeout            The time to wait for connection done.
+
+  @retval EFI_SUCCESS            The TLS session is established.
+  @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
+  @retval EFI_ABORTED            TLS session state is incorrect.
+  @retval Others                 Other error as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsConnectSession (
+  IN  HTTP_PROTOCOL            *HttpInstance,
+  IN  EFI_EVENT                Timeout
+  )
+{
+  EFI_STATUS              Status;
+  UINT8                   *BufferOut;
+  UINTN                   BufferOutSize;
+  NET_BUF                 *PacketOut;
+  UINT8                   *DataOut;
+  NET_BUF                 *Pdu;
+  UINT8                   *BufferIn;
+  UINTN                   BufferInSize;
+  UINT8                   *GetSessionDataBuffer;
+  UINTN                   GetSessionDataBufferSize;
+
+  BufferOut    = NULL;
+  PacketOut    = NULL;
+  DataOut      = NULL;
+  Pdu          = NULL;
+  BufferIn     = NULL;
+
+  //
+  // Initialize TLS state.
+  //
+  HttpInstance->TlsSessionState = EfiTlsSessionNotStarted;
+  Status = HttpInstance->Tls->SetSessionData (
+                                HttpInstance->Tls,
+                                EfiTlsSessionState,
+                                &(HttpInstance->TlsSessionState),
+                                sizeof (EFI_TLS_SESSION_STATE)
+                                );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Create ClientHello
+  //
+  BufferOutSize = DEF_BUF_LEN;
+  BufferOut = AllocateZeroPool (BufferOutSize);
+  if (BufferOut == NULL) {
+    Status = EFI_OUT_OF_RESOURCES;
+    return Status;
+  }
+
+  Status = HttpInstance->Tls->BuildResponsePacket (
+                                HttpInstance->Tls,
+                                NULL,
+                                0,
+                                BufferOut,
+                                &BufferOutSize
+                                );
+  if (Status == EFI_BUFFER_TOO_SMALL) {
+    FreePool (BufferOut);
+    BufferOut = AllocateZeroPool (BufferOutSize);
+    if (BufferOut == NULL) {
+      Status = EFI_OUT_OF_RESOURCES;
+      return Status;
+    }
+
+    Status = HttpInstance->Tls->BuildResponsePacket (
+                                  HttpInstance->Tls,
+                                  NULL,
+                                  0,
+                                  BufferOut,
+                                  &BufferOutSize
+                                  );
+  }
+  if (EFI_ERROR (Status)) {
+    FreePool (BufferOut);
+    return Status;
+  }
+
+  //
+  // Transmit ClientHello
+  //
+  PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
+  DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
+  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 (file)
index 0000000..fcb3aa0
--- /dev/null
@@ -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. These two parts will be put into two blocks of buffers in the
+  net buffer.
+
+  @param[in, out]      HttpInstance    Pointer to HTTP_PROTOCOL structure.
+  @param[out]          Pdu             The received TLS PDU.
+  @param[in]           Timeout         The time to wait for connection done.
+
+  @retval EFI_SUCCESS          An TLS PDU is received.
+  @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
+  @retval EFI_PROTOCOL_ERROR   An unexpected TLS packet was received.
+  @retval Others               Other errors as indicated.
+
+**/
+EFI_STATUS
+EFIAPI
+TlsReceiveOnePdu (
+  IN OUT HTTP_PROTOCOL      *HttpInstance,
+     OUT NET_BUF            **Pdu,
+  IN     EFI_EVENT          Timeout
+  );
+
+/**
+  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