Home | History | Annotate | Download | only in HttpDxe
      1 /** @file
      2   Miscellaneous routines specific to Https for HttpDxe driver.
      3 
      4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
      5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
      6 This program and the accompanying materials
      7 are licensed and made available under the terms and conditions of the BSD License
      8 which accompanies this distribution.  The full text of the license may be found at
      9 http://opensource.org/licenses/bsd-license.php
     10 
     11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
     12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
     13 
     14 **/
     15 
     16 #include "HttpDriver.h"
     17 
     18 /**
     19   Returns the first occurrence of a Null-terminated ASCII sub-string in a Null-terminated
     20   ASCII string and ignore case during the search process.
     21 
     22   This function scans the contents of the ASCII string specified by String
     23   and returns the first occurrence of SearchString and ignore case during the search process.
     24   If SearchString is not found in String, then NULL is returned. If the length of SearchString
     25   is zero, then String is returned.
     26 
     27   If String is NULL, then ASSERT().
     28   If SearchString is NULL, then ASSERT().
     29 
     30   @param[in]  String          A pointer to a Null-terminated ASCII string.
     31   @param[in]  SearchString    A pointer to a Null-terminated ASCII string to search for.
     32 
     33   @retval NULL            If the SearchString does not appear in String.
     34   @retval others          If there is a match return the first occurrence of SearchingString.
     35                           If the length of SearchString is zero,return String.
     36 
     37 **/
     38 CHAR8 *
     39 AsciiStrCaseStr (
     40   IN      CONST CHAR8               *String,
     41   IN      CONST CHAR8               *SearchString
     42   )
     43 {
     44   CONST CHAR8 *FirstMatch;
     45   CONST CHAR8 *SearchStringTmp;
     46 
     47   CHAR8 Src;
     48   CHAR8 Dst;
     49 
     50   //
     51   // ASSERT both strings are less long than PcdMaximumAsciiStringLength
     52   //
     53   ASSERT (AsciiStrSize (String) != 0);
     54   ASSERT (AsciiStrSize (SearchString) != 0);
     55 
     56   if (*SearchString == '\0') {
     57     return (CHAR8 *) String;
     58   }
     59 
     60   while (*String != '\0') {
     61     SearchStringTmp = SearchString;
     62     FirstMatch = String;
     63 
     64     while ((*SearchStringTmp != '\0')
     65             && (*String != '\0')) {
     66       Src = *String;
     67       Dst = *SearchStringTmp;
     68 
     69       if ((Src >= 'A') && (Src <= 'Z')) {
     70         Src -= ('A' - 'a');
     71       }
     72 
     73       if ((Dst >= 'A') && (Dst <= 'Z')) {
     74         Dst -= ('A' - 'a');
     75       }
     76 
     77       if (Src != Dst) {
     78         break;
     79       }
     80 
     81       String++;
     82       SearchStringTmp++;
     83     }
     84 
     85     if (*SearchStringTmp == '\0') {
     86       return (CHAR8 *) FirstMatch;
     87     }
     88 
     89     String = FirstMatch + 1;
     90   }
     91 
     92   return NULL;
     93 }
     94 
     95 /**
     96   The callback function to free the net buffer list.
     97 
     98   @param[in]  Arg The opaque parameter.
     99 
    100 **/
    101 VOID
    102 EFIAPI
    103 FreeNbufList (
    104   IN VOID *Arg
    105   )
    106 {
    107   ASSERT (Arg != NULL);
    108 
    109   NetbufFreeList ((LIST_ENTRY *) Arg);
    110   FreePool (Arg);
    111 }
    112 
    113 /**
    114   Check whether the Url is from Https.
    115 
    116   @param[in]    Url             The pointer to a HTTP or HTTPS URL string.
    117 
    118   @retval TRUE                  The Url is from HTTPS.
    119   @retval FALSE                 The Url is from HTTP.
    120 
    121 **/
    122 BOOLEAN
    123 IsHttpsUrl (
    124   IN CHAR8    *Url
    125   )
    126 {
    127   CHAR8  *Tmp;
    128 
    129   Tmp = NULL;
    130 
    131   Tmp = AsciiStrCaseStr (Url, HTTPS_FLAG);
    132   if (Tmp != NULL && Tmp == Url) {
    133     return TRUE;
    134   }
    135 
    136   return FALSE;
    137 }
    138 
    139 /**
    140   Creates a Tls child handle, open EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
    141 
    142   @param[in]  ImageHandle           The firmware allocated handle for the UEFI image.
    143   @param[out] TlsProto              Pointer to the EFI_TLS_PROTOCOL instance.
    144   @param[out] TlsConfiguration      Pointer to the EFI_TLS_CONFIGURATION_PROTOCOL instance.
    145 
    146   @return  The child handle with opened EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
    147 
    148 **/
    149 EFI_HANDLE
    150 EFIAPI
    151 TlsCreateChild (
    152   IN  EFI_HANDLE                     ImageHandle,
    153   OUT EFI_TLS_PROTOCOL               **TlsProto,
    154   OUT EFI_TLS_CONFIGURATION_PROTOCOL **TlsConfiguration
    155   )
    156 {
    157   EFI_STATUS                    Status;
    158   EFI_SERVICE_BINDING_PROTOCOL  *TlsSb;
    159   EFI_HANDLE                    TlsChildHandle;
    160 
    161   TlsSb          = NULL;
    162   TlsChildHandle = 0;
    163 
    164   //
    165   // Locate TlsServiceBinding protocol.
    166   //
    167   gBS->LocateProtocol (
    168      &gEfiTlsServiceBindingProtocolGuid,
    169      NULL,
    170      (VOID **) &TlsSb
    171      );
    172   if (TlsSb == NULL) {
    173     return NULL;
    174   }
    175 
    176   Status = TlsSb->CreateChild (TlsSb, &TlsChildHandle);
    177   if (EFI_ERROR (Status)) {
    178     return NULL;
    179   }
    180 
    181   Status = gBS->OpenProtocol (
    182                   TlsChildHandle,
    183                   &gEfiTlsProtocolGuid,
    184                   (VOID **) TlsProto,
    185                   ImageHandle,
    186                   TlsChildHandle,
    187                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    188                   );
    189   if (EFI_ERROR (Status)) {
    190     TlsSb->DestroyChild (TlsSb, TlsChildHandle);
    191     return NULL;
    192   }
    193 
    194   Status = gBS->OpenProtocol (
    195                   TlsChildHandle,
    196                   &gEfiTlsConfigurationProtocolGuid,
    197                   (VOID **) TlsConfiguration,
    198                   ImageHandle,
    199                   TlsChildHandle,
    200                   EFI_OPEN_PROTOCOL_GET_PROTOCOL
    201                   );
    202   if (EFI_ERROR (Status)) {
    203     TlsSb->DestroyChild (TlsSb, TlsChildHandle);
    204     return NULL;
    205   }
    206 
    207   return TlsChildHandle;
    208 }
    209 
    210 /**
    211   Create event for the TLS receive and transmit tokens which are used to receive and
    212   transmit TLS related messages.
    213 
    214   @param[in, out]  HttpInstance       Pointer to HTTP_PROTOCOL structure.
    215 
    216   @retval EFI_SUCCESS            The events are created successfully.
    217   @retval others                 Other error as indicated.
    218 
    219 **/
    220 EFI_STATUS
    221 EFIAPI
    222 TlsCreateTxRxEvent (
    223   IN OUT HTTP_PROTOCOL      *HttpInstance
    224   )
    225 {
    226   EFI_STATUS                Status;
    227 
    228   if (!HttpInstance->LocalAddressIsIPv6) {
    229     //
    230     // For Tcp4TlsTxToken.
    231     //
    232     Status = gBS->CreateEvent (
    233                     EVT_NOTIFY_SIGNAL,
    234                     TPL_NOTIFY,
    235                     HttpCommonNotify,
    236                     &HttpInstance->TlsIsTxDone,
    237                     &HttpInstance->Tcp4TlsTxToken.CompletionToken.Event
    238                     );
    239     if (EFI_ERROR (Status)) {
    240       goto ERROR;
    241     }
    242 
    243     HttpInstance->Tcp4TlsTxData.Push = TRUE;
    244     HttpInstance->Tcp4TlsTxData.Urgent = FALSE;
    245     HttpInstance->Tcp4TlsTxData.DataLength = 0;
    246     HttpInstance->Tcp4TlsTxData.FragmentCount = 1;
    247     HttpInstance->Tcp4TlsTxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp4TlsTxData.DataLength;
    248     HttpInstance->Tcp4TlsTxData.FragmentTable[0].FragmentBuffer = NULL;
    249     HttpInstance->Tcp4TlsTxToken.Packet.TxData = &HttpInstance->Tcp4TlsTxData;
    250     HttpInstance->Tcp4TlsTxToken.CompletionToken.Status = EFI_NOT_READY;
    251 
    252     //
    253     // For Tcp4TlsRxToken.
    254     //
    255     Status = gBS->CreateEvent (
    256                     EVT_NOTIFY_SIGNAL,
    257                     TPL_NOTIFY,
    258                     HttpCommonNotify,
    259                     &HttpInstance->TlsIsRxDone,
    260                     &HttpInstance->Tcp4TlsRxToken.CompletionToken.Event
    261                     );
    262     if (EFI_ERROR (Status)) {
    263       goto ERROR;
    264     }
    265 
    266     HttpInstance->Tcp4TlsRxData.DataLength                       = 0;
    267     HttpInstance->Tcp4TlsRxData.FragmentCount                    = 1;
    268     HttpInstance->Tcp4TlsRxData.FragmentTable[0].FragmentLength  = HttpInstance->Tcp4TlsRxData.DataLength ;
    269     HttpInstance->Tcp4TlsRxData.FragmentTable[0].FragmentBuffer  = NULL;
    270     HttpInstance->Tcp4TlsRxToken.Packet.RxData          = &HttpInstance->Tcp4TlsRxData;
    271     HttpInstance->Tcp4TlsRxToken.CompletionToken.Status = EFI_NOT_READY;
    272   } else {
    273     //
    274     // For Tcp6TlsTxToken.
    275     //
    276     Status = gBS->CreateEvent (
    277                     EVT_NOTIFY_SIGNAL,
    278                     TPL_NOTIFY,
    279                     HttpCommonNotify,
    280                     &HttpInstance->TlsIsTxDone,
    281                     &HttpInstance->Tcp6TlsTxToken.CompletionToken.Event
    282                     );
    283     if (EFI_ERROR (Status)) {
    284       goto ERROR;
    285     }
    286 
    287     HttpInstance->Tcp6TlsTxData.Push = TRUE;
    288     HttpInstance->Tcp6TlsTxData.Urgent = FALSE;
    289     HttpInstance->Tcp6TlsTxData.DataLength = 0;
    290     HttpInstance->Tcp6TlsTxData.FragmentCount = 1;
    291     HttpInstance->Tcp6TlsTxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp6TlsTxData.DataLength;
    292     HttpInstance->Tcp6TlsTxData.FragmentTable[0].FragmentBuffer = NULL;
    293     HttpInstance->Tcp6TlsTxToken.Packet.TxData = &HttpInstance->Tcp6TlsTxData;
    294     HttpInstance->Tcp6TlsTxToken.CompletionToken.Status = EFI_NOT_READY;
    295 
    296     //
    297     // For Tcp6TlsRxToken.
    298     //
    299     Status = gBS->CreateEvent (
    300                     EVT_NOTIFY_SIGNAL,
    301                     TPL_NOTIFY,
    302                     HttpCommonNotify,
    303                     &HttpInstance->TlsIsRxDone,
    304                     &HttpInstance->Tcp6TlsRxToken.CompletionToken.Event
    305                     );
    306     if (EFI_ERROR (Status)) {
    307       goto ERROR;
    308     }
    309 
    310     HttpInstance->Tcp6TlsRxData.DataLength                       = 0;
    311     HttpInstance->Tcp6TlsRxData.FragmentCount                    = 1;
    312     HttpInstance->Tcp6TlsRxData.FragmentTable[0].FragmentLength  = HttpInstance->Tcp6TlsRxData.DataLength ;
    313     HttpInstance->Tcp6TlsRxData.FragmentTable[0].FragmentBuffer  = NULL;
    314     HttpInstance->Tcp6TlsRxToken.Packet.RxData          = &HttpInstance->Tcp6TlsRxData;
    315     HttpInstance->Tcp6TlsRxToken.CompletionToken.Status = EFI_NOT_READY;
    316   }
    317 
    318   return Status;
    319 
    320 ERROR:
    321   //
    322   // Error handling
    323   //
    324   TlsCloseTxRxEvent (HttpInstance);
    325 
    326   return Status;
    327 }
    328 
    329 /**
    330   Close events in the TlsTxToken and TlsRxToken.
    331 
    332   @param[in]  HttpInstance   Pointer to HTTP_PROTOCOL structure.
    333 
    334 **/
    335 VOID
    336 EFIAPI
    337 TlsCloseTxRxEvent (
    338   IN  HTTP_PROTOCOL        *HttpInstance
    339   )
    340 {
    341   ASSERT (HttpInstance != NULL);
    342   if (!HttpInstance->LocalAddressIsIPv6) {
    343     if (NULL != HttpInstance->Tcp4TlsTxToken.CompletionToken.Event) {
    344       gBS->CloseEvent(HttpInstance->Tcp4TlsTxToken.CompletionToken.Event);
    345       HttpInstance->Tcp4TlsTxToken.CompletionToken.Event = NULL;
    346     }
    347 
    348     if (NULL != HttpInstance->Tcp4TlsRxToken.CompletionToken.Event) {
    349       gBS->CloseEvent (HttpInstance->Tcp4TlsRxToken.CompletionToken.Event);
    350       HttpInstance->Tcp4TlsRxToken.CompletionToken.Event = NULL;
    351     }
    352   } else {
    353     if (NULL != HttpInstance->Tcp6TlsTxToken.CompletionToken.Event) {
    354       gBS->CloseEvent(HttpInstance->Tcp6TlsTxToken.CompletionToken.Event);
    355       HttpInstance->Tcp6TlsTxToken.CompletionToken.Event = NULL;
    356     }
    357 
    358     if (NULL != HttpInstance->Tcp6TlsRxToken.CompletionToken.Event) {
    359       gBS->CloseEvent (HttpInstance->Tcp6TlsRxToken.CompletionToken.Event);
    360       HttpInstance->Tcp6TlsRxToken.CompletionToken.Event = NULL;
    361     }
    362   }
    363 }
    364 
    365 /**
    366   Read the TlsCaCertificate variable and configure it.
    367 
    368   @param[in, out]  HttpInstance       The HTTP instance private data.
    369 
    370   @retval EFI_SUCCESS            TlsCaCertificate is configured.
    371   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
    372   @retval EFI_NOT_FOUND          Fail to get 'TlsCaCertificate' variable.
    373   @retval Others                 Other error as indicated.
    374 
    375 **/
    376 EFI_STATUS
    377 TlsConfigCertificate (
    378   IN OUT HTTP_PROTOCOL      *HttpInstance
    379   )
    380 {
    381   EFI_STATUS          Status;
    382   UINT8               *CACert;
    383   UINTN               CACertSize;
    384   UINT32              Index;
    385   EFI_SIGNATURE_LIST  *CertList;
    386   EFI_SIGNATURE_DATA  *Cert;
    387   UINTN               CertCount;
    388   UINT32              ItemDataSize;
    389 
    390   CACert     = NULL;
    391   CACertSize = 0;
    392 
    393   //
    394   // Try to read the TlsCaCertificate variable.
    395   //
    396   Status  = gRT->GetVariable (
    397                    EFI_TLS_CA_CERTIFICATE_VARIABLE,
    398                    &gEfiTlsCaCertificateGuid,
    399                    NULL,
    400                    &CACertSize,
    401                    NULL
    402                    );
    403 
    404   if (EFI_ERROR (Status) && Status != EFI_BUFFER_TOO_SMALL) {
    405     return Status;
    406   }
    407 
    408   //
    409   // Allocate buffer and read the config variable.
    410   //
    411   CACert = AllocatePool (CACertSize);
    412   if (CACert == NULL) {
    413     return EFI_OUT_OF_RESOURCES;
    414   }
    415 
    416   Status = gRT->GetVariable (
    417                   EFI_TLS_CA_CERTIFICATE_VARIABLE,
    418                   &gEfiTlsCaCertificateGuid,
    419                   NULL,
    420                   &CACertSize,
    421                   CACert
    422                   );
    423   if (EFI_ERROR (Status)) {
    424     //
    425     // GetVariable still error or the variable is corrupted.
    426     // Fall back to the default value.
    427     //
    428     FreePool (CACert);
    429 
    430     return EFI_NOT_FOUND;
    431   }
    432 
    433   ASSERT (CACert != NULL);
    434 
    435   //
    436   // Enumerate all data and erasing the target item.
    437   //
    438   ItemDataSize = (UINT32) CACertSize;
    439   CertList = (EFI_SIGNATURE_LIST *) CACert;
    440   while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
    441     Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
    442     CertCount  = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
    443     for (Index = 0; Index < CertCount; Index++) {
    444       //
    445       // EfiTlsConfigDataTypeCACertificate
    446       //
    447       Status = HttpInstance->TlsConfiguration->SetData (
    448                                                  HttpInstance->TlsConfiguration,
    449                                                  EfiTlsConfigDataTypeCACertificate,
    450                                                  Cert->SignatureData,
    451                                                  CertList->SignatureSize - sizeof (Cert->SignatureOwner)
    452                                                  );
    453       if (EFI_ERROR (Status)) {
    454         FreePool (CACert);
    455         return Status;
    456       }
    457 
    458       Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
    459     }
    460 
    461     ItemDataSize -= CertList->SignatureListSize;
    462     CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
    463   }
    464 
    465   FreePool (CACert);
    466   return Status;
    467 }
    468 
    469 /**
    470   Configure TLS session data.
    471 
    472   @param[in, out]  HttpInstance       The HTTP instance private data.
    473 
    474   @retval EFI_SUCCESS            TLS session data is configured.
    475   @retval Others                 Other error as indicated.
    476 
    477 **/
    478 EFI_STATUS
    479 EFIAPI
    480 TlsConfigureSession (
    481   IN OUT HTTP_PROTOCOL      *HttpInstance
    482   )
    483 {
    484   EFI_STATUS                 Status;
    485 
    486   //
    487   // TlsConfigData initialization
    488   //
    489   HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient;
    490   HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER;
    491   HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted;
    492 
    493   //
    494   // EfiTlsConnectionEnd,
    495   // EfiTlsVerifyMethod
    496   // EfiTlsSessionState
    497   //
    498   Status = HttpInstance->Tls->SetSessionData (
    499                                 HttpInstance->Tls,
    500                                 EfiTlsConnectionEnd,
    501                                 &(HttpInstance->TlsConfigData.ConnectionEnd),
    502                                 sizeof (EFI_TLS_CONNECTION_END)
    503                                 );
    504   if (EFI_ERROR (Status)) {
    505     return Status;
    506   }
    507 
    508   Status = HttpInstance->Tls->SetSessionData (
    509                                 HttpInstance->Tls,
    510                                 EfiTlsVerifyMethod,
    511                                 &HttpInstance->TlsConfigData.VerifyMethod,
    512                                 sizeof (EFI_TLS_VERIFY)
    513                                 );
    514   if (EFI_ERROR (Status)) {
    515     return Status;
    516   }
    517 
    518   Status = HttpInstance->Tls->SetSessionData (
    519                                 HttpInstance->Tls,
    520                                 EfiTlsSessionState,
    521                                 &(HttpInstance->TlsConfigData.SessionState),
    522                                 sizeof (EFI_TLS_SESSION_STATE)
    523                                 );
    524   if (EFI_ERROR (Status)) {
    525     return Status;
    526   }
    527 
    528   //
    529   // Tls Config Certificate
    530   //
    531   Status = TlsConfigCertificate (HttpInstance);
    532   if (EFI_ERROR (Status)) {
    533     DEBUG ((EFI_D_ERROR, "TLS Certificate Config Error!\n"));
    534     return Status;
    535   }
    536 
    537   //
    538   // TlsCreateTxRxEvent
    539   //
    540   Status = TlsCreateTxRxEvent (HttpInstance);
    541   if (EFI_ERROR (Status)) {
    542     goto ERROR;
    543   }
    544 
    545   return Status;
    546 
    547 ERROR:
    548   TlsCloseTxRxEvent (HttpInstance);
    549 
    550   return Status;
    551 }
    552 
    553 /**
    554   Transmit the Packet by processing the associated HTTPS token.
    555 
    556   @param[in, out]   HttpInstance    Pointer to HTTP_PROTOCOL structure.
    557   @param[in]        Packet          The packet to transmit.
    558 
    559   @retval EFI_SUCCESS            The packet is transmitted.
    560   @retval EFI_INVALID_PARAMETER  HttpInstance is NULL or Packet is NULL.
    561   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
    562   @retval EFI_DEVICE_ERROR       An unexpected system or network error occurred.
    563   @retval Others                 Other errors as indicated.
    564 
    565 **/
    566 EFI_STATUS
    567 EFIAPI
    568 TlsCommonTransmit (
    569   IN OUT HTTP_PROTOCOL      *HttpInstance,
    570   IN     NET_BUF            *Packet
    571   )
    572 {
    573   EFI_STATUS                Status;
    574   VOID                      *Data;
    575   UINTN                     Size;
    576 
    577   if ((HttpInstance == NULL) || (Packet == NULL)) {
    578     return EFI_INVALID_PARAMETER;
    579   }
    580 
    581   if (!HttpInstance->LocalAddressIsIPv6) {
    582     Size = sizeof (EFI_TCP4_TRANSMIT_DATA) +
    583            (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA);
    584   } else {
    585     Size = sizeof (EFI_TCP6_TRANSMIT_DATA) +
    586            (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA);
    587   }
    588 
    589   Data = AllocatePool (Size);
    590   if (Data == NULL) {
    591     return EFI_OUT_OF_RESOURCES;
    592   }
    593 
    594   if (!HttpInstance->LocalAddressIsIPv6) {
    595     ((EFI_TCP4_TRANSMIT_DATA *) Data)->Push        = TRUE;
    596     ((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent      = FALSE;
    597     ((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength  = Packet->TotalSize;
    598 
    599     //
    600     // Build the fragment table.
    601     //
    602     ((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
    603 
    604     NetbufBuildExt (
    605       Packet,
    606       (NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0],
    607       &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount
    608       );
    609 
    610     HttpInstance->Tcp4TlsTxToken.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data;
    611 
    612     Status = EFI_DEVICE_ERROR;
    613 
    614     //
    615     // Transmit the packet.
    616     //
    617     Status  = HttpInstance->Tcp4->Transmit (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsTxToken);
    618     if (EFI_ERROR (Status)) {
    619       goto ON_EXIT;
    620     }
    621 
    622     while (!HttpInstance->TlsIsTxDone) {
    623       HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
    624     }
    625 
    626     HttpInstance->TlsIsTxDone = FALSE;
    627     Status = HttpInstance->Tcp4TlsTxToken.CompletionToken.Status;
    628   } else {
    629     ((EFI_TCP6_TRANSMIT_DATA *) Data)->Push        = TRUE;
    630     ((EFI_TCP6_TRANSMIT_DATA *) Data)->Urgent      = FALSE;
    631     ((EFI_TCP6_TRANSMIT_DATA *) Data)->DataLength  = Packet->TotalSize;
    632 
    633     //
    634     // Build the fragment table.
    635     //
    636     ((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
    637 
    638     NetbufBuildExt (
    639       Packet,
    640       (NET_FRAGMENT *) &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentTable[0],
    641       &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount
    642       );
    643 
    644     HttpInstance->Tcp6TlsTxToken.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data;
    645 
    646     Status = EFI_DEVICE_ERROR;
    647 
    648     //
    649     // Transmit the packet.
    650     //
    651     Status  = HttpInstance->Tcp6->Transmit (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsTxToken);
    652     if (EFI_ERROR (Status)) {
    653       goto ON_EXIT;
    654     }
    655 
    656     while (!HttpInstance->TlsIsTxDone) {
    657       HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
    658     }
    659 
    660     HttpInstance->TlsIsTxDone = FALSE;
    661     Status = HttpInstance->Tcp6TlsTxToken.CompletionToken.Status;
    662   }
    663 
    664 ON_EXIT:
    665   FreePool (Data);
    666 
    667   return Status;
    668 }
    669 
    670 /**
    671   Receive the Packet by processing the associated HTTPS token.
    672 
    673   @param[in, out]   HttpInstance    Pointer to HTTP_PROTOCOL structure.
    674   @param[in]        Packet          The packet to transmit.
    675   @param[in]        Timeout         The time to wait for connection done.
    676 
    677   @retval EFI_SUCCESS            The Packet is received.
    678   @retval EFI_INVALID_PARAMETER  HttpInstance is NULL or Packet is NULL.
    679   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
    680   @retval EFI_TIMEOUT            The operation is time out.
    681   @retval Others                 Other error as indicated.
    682 
    683 **/
    684 EFI_STATUS
    685 EFIAPI
    686 TlsCommonReceive (
    687   IN OUT HTTP_PROTOCOL      *HttpInstance,
    688   IN     NET_BUF            *Packet,
    689   IN     EFI_EVENT          Timeout
    690   )
    691 {
    692   EFI_TCP4_RECEIVE_DATA     *Tcp4RxData;
    693   EFI_TCP6_RECEIVE_DATA     *Tcp6RxData;
    694   EFI_STATUS                Status;
    695   NET_FRAGMENT              *Fragment;
    696   UINT32                    FragmentCount;
    697   UINT32                    CurrentFragment;
    698 
    699   Tcp4RxData = NULL;
    700   Tcp6RxData = NULL;
    701 
    702   if ((HttpInstance == NULL) || (Packet == NULL)) {
    703     return EFI_INVALID_PARAMETER;
    704   }
    705 
    706   FragmentCount = Packet->BlockOpNum;
    707   Fragment      = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
    708   if (Fragment == NULL) {
    709     Status = EFI_OUT_OF_RESOURCES;
    710     goto ON_EXIT;
    711   }
    712 
    713   //
    714   // Build the fragment table.
    715   //
    716   NetbufBuildExt (Packet, Fragment, &FragmentCount);
    717 
    718   if (!HttpInstance->LocalAddressIsIPv6) {
    719     Tcp4RxData = HttpInstance->Tcp4TlsRxToken.Packet.RxData;
    720     if (Tcp4RxData == NULL) {
    721       return EFI_INVALID_PARAMETER;
    722     }
    723     Tcp4RxData->FragmentCount         = 1;
    724   } else {
    725     Tcp6RxData = HttpInstance->Tcp6TlsRxToken.Packet.RxData;
    726     if (Tcp6RxData == NULL) {
    727       return EFI_INVALID_PARAMETER;
    728     }
    729     Tcp6RxData->FragmentCount         = 1;
    730   }
    731 
    732   CurrentFragment               = 0;
    733   Status                        = EFI_SUCCESS;
    734 
    735   while (CurrentFragment < FragmentCount) {
    736     if (!HttpInstance->LocalAddressIsIPv6) {
    737       Tcp4RxData->DataLength                       = Fragment[CurrentFragment].Len;
    738       Tcp4RxData->FragmentTable[0].FragmentLength  = Fragment[CurrentFragment].Len;
    739       Tcp4RxData->FragmentTable[0].FragmentBuffer  = Fragment[CurrentFragment].Bulk;
    740       Status = HttpInstance->Tcp4->Receive (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken);
    741     } else {
    742       Tcp6RxData->DataLength                       = Fragment[CurrentFragment].Len;
    743       Tcp6RxData->FragmentTable[0].FragmentLength  = Fragment[CurrentFragment].Len;
    744       Tcp6RxData->FragmentTable[0].FragmentBuffer  = Fragment[CurrentFragment].Bulk;
    745       Status = HttpInstance->Tcp6->Receive (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken);
    746     }
    747     if (EFI_ERROR (Status)) {
    748       goto ON_EXIT;
    749     }
    750 
    751     while (!HttpInstance->TlsIsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
    752       //
    753       // Poll until some data is received or an error occurs.
    754       //
    755       if (!HttpInstance->LocalAddressIsIPv6) {
    756         HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
    757       } else {
    758         HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
    759       }
    760     }
    761 
    762     if (!HttpInstance->TlsIsRxDone) {
    763       //
    764       // Timeout occurs, cancel the receive request.
    765       //
    766       if (!HttpInstance->LocalAddressIsIPv6) {
    767         HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken.CompletionToken);
    768       } else {
    769         HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken.CompletionToken);
    770       }
    771 
    772       Status = EFI_TIMEOUT;
    773       goto ON_EXIT;
    774     } else {
    775       HttpInstance->TlsIsRxDone = FALSE;
    776     }
    777 
    778     if (!HttpInstance->LocalAddressIsIPv6) {
    779       Status = HttpInstance->Tcp4TlsRxToken.CompletionToken.Status;
    780       if (EFI_ERROR (Status)) {
    781         goto ON_EXIT;
    782       }
    783 
    784       Fragment[CurrentFragment].Len -= Tcp4RxData->FragmentTable[0].FragmentLength;
    785       if (Fragment[CurrentFragment].Len == 0) {
    786         CurrentFragment++;
    787       } else {
    788         Fragment[CurrentFragment].Bulk += Tcp4RxData->FragmentTable[0].FragmentLength;
    789       }
    790     } else {
    791       Status = HttpInstance->Tcp6TlsRxToken.CompletionToken.Status;
    792       if (EFI_ERROR (Status)) {
    793         goto ON_EXIT;
    794       }
    795 
    796       Fragment[CurrentFragment].Len -= Tcp6RxData->FragmentTable[0].FragmentLength;
    797       if (Fragment[CurrentFragment].Len == 0) {
    798         CurrentFragment++;
    799       } else {
    800         Fragment[CurrentFragment].Bulk += Tcp6RxData->FragmentTable[0].FragmentLength;
    801       }
    802     }
    803   }
    804 
    805 ON_EXIT:
    806 
    807   if (Fragment != NULL) {
    808     FreePool (Fragment);
    809   }
    810 
    811   return Status;
    812 }
    813 
    814 /**
    815   Receive one TLS PDU. An TLS PDU contains an TLS record header and it's
    816   corresponding record data. These two parts will be put into two blocks of buffers in the
    817   net buffer.
    818 
    819   @param[in, out]      HttpInstance    Pointer to HTTP_PROTOCOL structure.
    820   @param[out]          Pdu             The received TLS PDU.
    821   @param[in]           Timeout         The time to wait for connection done.
    822 
    823   @retval EFI_SUCCESS          An TLS PDU is received.
    824   @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
    825   @retval EFI_PROTOCOL_ERROR   An unexpected TLS packet was received.
    826   @retval Others               Other errors as indicated.
    827 
    828 **/
    829 EFI_STATUS
    830 EFIAPI
    831 TlsReceiveOnePdu (
    832   IN OUT HTTP_PROTOCOL      *HttpInstance,
    833      OUT NET_BUF            **Pdu,
    834   IN     EFI_EVENT          Timeout
    835   )
    836 {
    837   EFI_STATUS      Status;
    838 
    839   LIST_ENTRY      *NbufList;
    840 
    841   UINT32          Len;
    842 
    843   NET_BUF           *PduHdr;
    844   UINT8             *Header;
    845   TLS_RECORD_HEADER RecordHeader;
    846 
    847   NET_BUF           *DataSeg;
    848 
    849   NbufList = NULL;
    850   PduHdr   = NULL;
    851   Header   = NULL;
    852   DataSeg  = NULL;
    853 
    854   NbufList = AllocatePool (sizeof (LIST_ENTRY));
    855   if (NbufList == NULL) {
    856     return EFI_OUT_OF_RESOURCES;
    857   }
    858 
    859   InitializeListHead (NbufList);
    860 
    861   //
    862   // Allocate buffer to receive one TLS header.
    863   //
    864   Len     = sizeof (TLS_RECORD_HEADER);
    865   PduHdr  = NetbufAlloc (Len);
    866   if (PduHdr == NULL) {
    867     Status = EFI_OUT_OF_RESOURCES;
    868     goto ON_EXIT;
    869   }
    870 
    871   Header = NetbufAllocSpace (PduHdr, Len, NET_BUF_TAIL);
    872   if (Header == NULL) {
    873     Status = EFI_OUT_OF_RESOURCES;
    874     goto ON_EXIT;
    875   }
    876 
    877   //
    878   // First step, receive one TLS header.
    879   //
    880   Status = TlsCommonReceive (HttpInstance, PduHdr, Timeout);
    881   if (EFI_ERROR (Status)) {
    882     goto ON_EXIT;
    883   }
    884 
    885   RecordHeader = *(TLS_RECORD_HEADER *) Header;
    886   if ((RecordHeader.ContentType == TLS_CONTENT_TYPE_HANDSHAKE ||
    887     RecordHeader.ContentType == TLS_CONTENT_TYPE_ALERT ||
    888     RecordHeader.ContentType == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC ||
    889     RecordHeader.ContentType == TLS_CONTENT_TYPE_APPLICATION_DATA) &&
    890     (RecordHeader.Version.Major == 0x03) && /// Major versions are same.
    891     (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
    892     RecordHeader.Version.Minor ==TLS11_PROTOCOL_VERSION_MINOR ||
    893     RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
    894    ) {
    895     InsertTailList (NbufList, &PduHdr->List);
    896   } else {
    897     Status = EFI_PROTOCOL_ERROR;
    898     goto ON_EXIT;
    899   }
    900 
    901   Len = SwapBytes16(RecordHeader.Length);
    902   if (Len == 0) {
    903     //
    904     // No TLS payload.
    905     //
    906     goto FORM_PDU;
    907   }
    908 
    909   //
    910   // Allocate buffer to receive one TLS payload.
    911   //
    912   DataSeg = NetbufAlloc (Len);
    913   if (DataSeg == NULL) {
    914     Status = EFI_OUT_OF_RESOURCES;
    915     goto ON_EXIT;
    916   }
    917 
    918   NetbufAllocSpace (DataSeg, Len, NET_BUF_TAIL);
    919 
    920   //
    921   // Second step, receive one TLS payload.
    922   //
    923   Status = TlsCommonReceive (HttpInstance, DataSeg, Timeout);
    924   if (EFI_ERROR (Status)) {
    925     goto ON_EXIT;
    926   }
    927 
    928   InsertTailList (NbufList, &DataSeg->List);
    929 
    930 FORM_PDU:
    931   //
    932   // Form the PDU from a list of PDU.
    933   //
    934   *Pdu = NetbufFromBufList (NbufList, 0, 0, FreeNbufList, NbufList);
    935   if (*Pdu == NULL) {
    936     Status = EFI_OUT_OF_RESOURCES;
    937   }
    938 
    939 ON_EXIT:
    940 
    941   if (EFI_ERROR (Status)) {
    942     //
    943     // Free the Nbufs in this NbufList and the NbufList itself.
    944     //
    945     FreeNbufList (NbufList);
    946   }
    947 
    948   return Status;
    949 }
    950 
    951 /**
    952   Connect one TLS session by finishing the TLS handshake process.
    953 
    954   @param[in]  HttpInstance       The HTTP instance private data.
    955   @param[in]  Timeout            The time to wait for connection done.
    956 
    957   @retval EFI_SUCCESS            The TLS session is established.
    958   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
    959   @retval EFI_ABORTED            TLS session state is incorrect.
    960   @retval Others                 Other error as indicated.
    961 
    962 **/
    963 EFI_STATUS
    964 EFIAPI
    965 TlsConnectSession (
    966   IN  HTTP_PROTOCOL            *HttpInstance,
    967   IN  EFI_EVENT                Timeout
    968   )
    969 {
    970   EFI_STATUS              Status;
    971   UINT8                   *BufferOut;
    972   UINTN                   BufferOutSize;
    973   NET_BUF                 *PacketOut;
    974   UINT8                   *DataOut;
    975   NET_BUF                 *Pdu;
    976   UINT8                   *BufferIn;
    977   UINTN                   BufferInSize;
    978   UINT8                   *GetSessionDataBuffer;
    979   UINTN                   GetSessionDataBufferSize;
    980 
    981   BufferOut    = NULL;
    982   PacketOut    = NULL;
    983   DataOut      = NULL;
    984   Pdu          = NULL;
    985   BufferIn     = NULL;
    986 
    987   //
    988   // Initialize TLS state.
    989   //
    990   HttpInstance->TlsSessionState = EfiTlsSessionNotStarted;
    991   Status = HttpInstance->Tls->SetSessionData (
    992                                 HttpInstance->Tls,
    993                                 EfiTlsSessionState,
    994                                 &(HttpInstance->TlsSessionState),
    995                                 sizeof (EFI_TLS_SESSION_STATE)
    996                                 );
    997   if (EFI_ERROR (Status)) {
    998     return Status;
    999   }
   1000 
   1001   //
   1002   // Create ClientHello
   1003   //
   1004   BufferOutSize = DEF_BUF_LEN;
   1005   BufferOut = AllocateZeroPool (BufferOutSize);
   1006   if (BufferOut == NULL) {
   1007     Status = EFI_OUT_OF_RESOURCES;
   1008     return Status;
   1009   }
   1010 
   1011   Status = HttpInstance->Tls->BuildResponsePacket (
   1012                                 HttpInstance->Tls,
   1013                                 NULL,
   1014                                 0,
   1015                                 BufferOut,
   1016                                 &BufferOutSize
   1017                                 );
   1018   if (Status == EFI_BUFFER_TOO_SMALL) {
   1019     FreePool (BufferOut);
   1020     BufferOut = AllocateZeroPool (BufferOutSize);
   1021     if (BufferOut == NULL) {
   1022       Status = EFI_OUT_OF_RESOURCES;
   1023       return Status;
   1024     }
   1025 
   1026     Status = HttpInstance->Tls->BuildResponsePacket (
   1027                                   HttpInstance->Tls,
   1028                                   NULL,
   1029                                   0,
   1030                                   BufferOut,
   1031                                   &BufferOutSize
   1032                                   );
   1033   }
   1034   if (EFI_ERROR (Status)) {
   1035     FreePool (BufferOut);
   1036     return Status;
   1037   }
   1038 
   1039   //
   1040   // Transmit ClientHello
   1041   //
   1042   PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
   1043   DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
   1044   if (DataOut == NULL) {
   1045     FreePool (BufferOut);
   1046     return EFI_OUT_OF_RESOURCES;
   1047   }
   1048 
   1049   CopyMem (DataOut, BufferOut, BufferOutSize);
   1050   Status = TlsCommonTransmit (HttpInstance, PacketOut);
   1051 
   1052   FreePool (BufferOut);
   1053   NetbufFree (PacketOut);
   1054 
   1055   if (EFI_ERROR (Status)) {
   1056     return Status;
   1057   }
   1058 
   1059   while(HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring && \
   1060     ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
   1061     //
   1062     // Receive one TLS record.
   1063     //
   1064     Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
   1065     if (EFI_ERROR (Status)) {
   1066       return Status;
   1067     }
   1068 
   1069     BufferInSize = Pdu->TotalSize;
   1070     BufferIn = AllocateZeroPool (BufferInSize);
   1071     if (BufferIn == NULL) {
   1072       NetbufFree (Pdu);
   1073       Status = EFI_OUT_OF_RESOURCES;
   1074       return Status;
   1075     }
   1076 
   1077     NetbufCopy (Pdu, 0, (UINT32)BufferInSize, BufferIn);
   1078 
   1079     NetbufFree (Pdu);
   1080 
   1081     //
   1082     // Handle Receive data.
   1083     //
   1084     BufferOutSize = DEF_BUF_LEN;
   1085     BufferOut = AllocateZeroPool (BufferOutSize);
   1086     if (BufferOut == NULL) {
   1087       Status = EFI_OUT_OF_RESOURCES;
   1088       return Status;
   1089     }
   1090 
   1091     Status = HttpInstance->Tls->BuildResponsePacket (
   1092                                   HttpInstance->Tls,
   1093                                   BufferIn,
   1094                                   BufferInSize,
   1095                                   BufferOut,
   1096                                   &BufferOutSize
   1097                                   );
   1098     if (Status == EFI_BUFFER_TOO_SMALL) {
   1099        FreePool (BufferOut);
   1100        BufferOut = AllocateZeroPool (BufferOutSize);
   1101        if (BufferOut == NULL) {
   1102          FreePool (BufferIn);
   1103          Status = EFI_OUT_OF_RESOURCES;
   1104          return Status;
   1105        }
   1106 
   1107        Status = HttpInstance->Tls->BuildResponsePacket (
   1108                                      HttpInstance->Tls,
   1109                                      BufferIn,
   1110                                      BufferInSize,
   1111                                      BufferOut,
   1112                                      &BufferOutSize
   1113                                      );
   1114     }
   1115 
   1116     FreePool (BufferIn);
   1117 
   1118     if (EFI_ERROR (Status)) {
   1119       FreePool (BufferOut);
   1120       return Status;
   1121     }
   1122 
   1123     if (BufferOutSize != 0) {
   1124       //
   1125       // Transmit the response packet.
   1126       //
   1127       PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
   1128       DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
   1129       if (DataOut == NULL) {
   1130         FreePool (BufferOut);
   1131         return EFI_OUT_OF_RESOURCES;
   1132       }
   1133 
   1134       CopyMem (DataOut, BufferOut, BufferOutSize);
   1135 
   1136       Status = TlsCommonTransmit (HttpInstance, PacketOut);
   1137 
   1138       NetbufFree (PacketOut);
   1139 
   1140       if (EFI_ERROR (Status)) {
   1141         FreePool (BufferOut);
   1142         return Status;
   1143       }
   1144     }
   1145 
   1146     FreePool (BufferOut);
   1147 
   1148     //
   1149     // Get the session state, then decide whether need to continue handle received packet.
   1150     //
   1151     GetSessionDataBufferSize = DEF_BUF_LEN;
   1152     GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
   1153     if (GetSessionDataBuffer == NULL) {
   1154       Status = EFI_OUT_OF_RESOURCES;
   1155       return Status;
   1156     }
   1157 
   1158     Status = HttpInstance->Tls->GetSessionData (
   1159                                   HttpInstance->Tls,
   1160                                   EfiTlsSessionState,
   1161                                   GetSessionDataBuffer,
   1162                                   &GetSessionDataBufferSize
   1163                                   );
   1164     if (Status == EFI_BUFFER_TOO_SMALL) {
   1165        FreePool (GetSessionDataBuffer);
   1166        GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
   1167        if (GetSessionDataBuffer == NULL) {
   1168          Status = EFI_OUT_OF_RESOURCES;
   1169          return Status;
   1170        }
   1171 
   1172        Status = HttpInstance->Tls->GetSessionData (
   1173                                      HttpInstance->Tls,
   1174                                      EfiTlsSessionState,
   1175                                      GetSessionDataBuffer,
   1176                                      &GetSessionDataBufferSize
   1177                                      );
   1178     }
   1179     if (EFI_ERROR (Status)) {
   1180       FreePool(GetSessionDataBuffer);
   1181       return Status;
   1182     }
   1183 
   1184     ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
   1185     HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;
   1186 
   1187     FreePool (GetSessionDataBuffer);
   1188 
   1189     if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
   1190       return EFI_ABORTED;
   1191     }
   1192   }
   1193 
   1194   if (HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring) {
   1195     Status = EFI_ABORTED;
   1196   }
   1197 
   1198   return Status;
   1199 }
   1200 
   1201 /**
   1202   Close the TLS session and send out the close notification message.
   1203 
   1204   @param[in]  HttpInstance       The HTTP instance private data.
   1205 
   1206   @retval EFI_SUCCESS            The TLS session is closed.
   1207   @retval EFI_INVALID_PARAMETER  HttpInstance is NULL.
   1208   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
   1209   @retval Others                 Other error as indicated.
   1210 
   1211 **/
   1212 EFI_STATUS
   1213 EFIAPI
   1214 TlsCloseSession (
   1215   IN  HTTP_PROTOCOL            *HttpInstance
   1216   )
   1217 {
   1218   EFI_STATUS      Status;
   1219 
   1220   UINT8           *BufferOut;
   1221   UINTN           BufferOutSize;
   1222 
   1223   NET_BUF         *PacketOut;
   1224   UINT8           *DataOut;
   1225 
   1226   Status    = EFI_SUCCESS;
   1227   BufferOut = NULL;
   1228   PacketOut = NULL;
   1229   DataOut   = NULL;
   1230 
   1231   if (HttpInstance == NULL) {
   1232     return EFI_INVALID_PARAMETER;
   1233   }
   1234 
   1235   HttpInstance->TlsSessionState = EfiTlsSessionClosing;
   1236 
   1237   Status = HttpInstance->Tls->SetSessionData (
   1238                                 HttpInstance->Tls,
   1239                                 EfiTlsSessionState,
   1240                                 &(HttpInstance->TlsSessionState),
   1241                                 sizeof (EFI_TLS_SESSION_STATE)
   1242                                 );
   1243   if (EFI_ERROR (Status)) {
   1244     return Status;
   1245   }
   1246 
   1247   BufferOutSize = DEF_BUF_LEN;
   1248   BufferOut = AllocateZeroPool (BufferOutSize);
   1249   if (BufferOut == NULL) {
   1250     Status = EFI_OUT_OF_RESOURCES;
   1251     return Status;
   1252   }
   1253 
   1254   Status = HttpInstance->Tls->BuildResponsePacket (
   1255                                 HttpInstance->Tls,
   1256                                 NULL,
   1257                                 0,
   1258                                 BufferOut,
   1259                                 &BufferOutSize
   1260                                 );
   1261   if (Status == EFI_BUFFER_TOO_SMALL) {
   1262     FreePool (BufferOut);
   1263     BufferOut = AllocateZeroPool (BufferOutSize);
   1264     if (BufferOut == NULL) {
   1265       Status = EFI_OUT_OF_RESOURCES;
   1266       return Status;
   1267     }
   1268 
   1269     Status = HttpInstance->Tls->BuildResponsePacket (
   1270                                   HttpInstance->Tls,
   1271                                   NULL,
   1272                                   0,
   1273                                   BufferOut,
   1274                                   &BufferOutSize
   1275                                   );
   1276   }
   1277 
   1278   if (EFI_ERROR (Status)) {
   1279     FreePool (BufferOut);
   1280     return Status;
   1281   }
   1282 
   1283   PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
   1284   DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
   1285   if (DataOut == NULL) {
   1286     FreePool (BufferOut);
   1287     return EFI_OUT_OF_RESOURCES;
   1288   }
   1289 
   1290   CopyMem (DataOut, BufferOut, BufferOutSize);
   1291 
   1292   Status = TlsCommonTransmit (HttpInstance, PacketOut);
   1293 
   1294   FreePool (BufferOut);
   1295   NetbufFree (PacketOut);
   1296 
   1297   if (EFI_ERROR (Status)) {
   1298     return Status;
   1299   }
   1300 
   1301   return Status;
   1302 }
   1303 
   1304 /**
   1305   Process one message according to the CryptMode.
   1306 
   1307   @param[in]           HttpInstance    Pointer to HTTP_PROTOCOL structure.
   1308   @param[in]           Message         Pointer to the message buffer needed to processed.
   1309   @param[in]           MessageSize     Pointer to the message buffer size.
   1310   @param[in]           ProcessMode     Process mode.
   1311   @param[in, out]      Fragment        Only one Fragment returned after the Message is
   1312                                        processed successfully.
   1313 
   1314   @retval EFI_SUCCESS          Message is processed successfully.
   1315   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
   1316   @retval Others               Other errors as indicated.
   1317 
   1318 **/
   1319 EFI_STATUS
   1320 EFIAPI
   1321 TlsProcessMessage (
   1322   IN     HTTP_PROTOCOL            *HttpInstance,
   1323   IN     UINT8                    *Message,
   1324   IN     UINTN                    MessageSize,
   1325   IN     EFI_TLS_CRYPT_MODE       ProcessMode,
   1326   IN OUT NET_FRAGMENT             *Fragment
   1327   )
   1328 {
   1329   EFI_STATUS                      Status;
   1330   UINT8                           *Buffer;
   1331   UINT32                          BufferSize;
   1332   UINT32                          BytesCopied;
   1333   EFI_TLS_FRAGMENT_DATA           *FragmentTable;
   1334   UINT32                          FragmentCount;
   1335   EFI_TLS_FRAGMENT_DATA           *OriginalFragmentTable;
   1336   UINTN                           Index;
   1337 
   1338   Status                   = EFI_SUCCESS;
   1339   Buffer                   = NULL;
   1340   BufferSize               = 0;
   1341   BytesCopied              = 0;
   1342   FragmentTable            = NULL;
   1343   OriginalFragmentTable    = NULL;
   1344 
   1345   //
   1346   // Rebuild fragment table from BufferIn.
   1347   //
   1348   FragmentCount = 1;
   1349   FragmentTable = AllocateZeroPool (FragmentCount * sizeof (EFI_TLS_FRAGMENT_DATA));
   1350   if (FragmentTable == NULL) {
   1351     Status = EFI_OUT_OF_RESOURCES;
   1352     goto ON_EXIT;
   1353   }
   1354 
   1355   FragmentTable->FragmentLength = (UINT32) MessageSize;
   1356   FragmentTable->FragmentBuffer = Message;
   1357 
   1358   //
   1359   // Record the original FragmentTable.
   1360   //
   1361   OriginalFragmentTable = FragmentTable;
   1362 
   1363   //
   1364   // Process the Message.
   1365   //
   1366   Status = HttpInstance->Tls->ProcessPacket (
   1367                                 HttpInstance->Tls,
   1368                                 &FragmentTable,
   1369                                 &FragmentCount,
   1370                                 ProcessMode
   1371                                 );
   1372   if (EFI_ERROR (Status)) {
   1373     goto ON_EXIT;
   1374   }
   1375 
   1376   //
   1377   // Calculate the size according to FragmentTable.
   1378   //
   1379   for (Index = 0; Index < FragmentCount; Index++) {
   1380     BufferSize += FragmentTable[Index].FragmentLength;
   1381   }
   1382 
   1383   //
   1384   // Allocate buffer for processed data.
   1385   //
   1386   Buffer = AllocateZeroPool (BufferSize);
   1387   if (Buffer == NULL) {
   1388     Status = EFI_OUT_OF_RESOURCES;
   1389     goto ON_EXIT;
   1390   }
   1391 
   1392   //
   1393   // Copy the new FragmentTable buffer into Buffer.
   1394   //
   1395   for (Index = 0; Index < FragmentCount; Index++) {
   1396     CopyMem (
   1397       (Buffer + BytesCopied),
   1398       FragmentTable[Index].FragmentBuffer,
   1399       FragmentTable[Index].FragmentLength
   1400       );
   1401     BytesCopied += FragmentTable[Index].FragmentLength;
   1402 
   1403     //
   1404     // Free the FragmentBuffer since it has been copied.
   1405     //
   1406     FreePool (FragmentTable[Index].FragmentBuffer);
   1407   }
   1408 
   1409   Fragment->Len  = BufferSize;
   1410   Fragment->Bulk = Buffer;
   1411 
   1412 ON_EXIT:
   1413 
   1414   if (OriginalFragmentTable != NULL) {
   1415     FreePool (OriginalFragmentTable);
   1416     OriginalFragmentTable = NULL;
   1417   }
   1418 
   1419   //
   1420   // Caller has the responsibility to free the FragmentTable.
   1421   //
   1422   if (FragmentTable != NULL) {
   1423     FreePool (FragmentTable);
   1424     FragmentTable = NULL;
   1425   }
   1426 
   1427   return Status;
   1428 }
   1429 
   1430 /**
   1431   Receive one fragment decrypted from one TLS record.
   1432 
   1433   @param[in]           HttpInstance    Pointer to HTTP_PROTOCOL structure.
   1434   @param[in, out]      Fragment        The received Fragment.
   1435   @param[in]           Timeout         The time to wait for connection done.
   1436 
   1437   @retval EFI_SUCCESS          One fragment is received.
   1438   @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
   1439   @retval EFI_ABORTED          Something wrong decryption the message.
   1440   @retval Others               Other errors as indicated.
   1441 
   1442 **/
   1443 EFI_STATUS
   1444 EFIAPI
   1445 HttpsReceive (
   1446   IN     HTTP_PROTOCOL         *HttpInstance,
   1447   IN OUT NET_FRAGMENT          *Fragment,
   1448   IN     EFI_EVENT             Timeout
   1449   )
   1450 {
   1451   EFI_STATUS                      Status;
   1452   NET_BUF                         *Pdu;
   1453   TLS_RECORD_HEADER               RecordHeader;
   1454   UINT8                           *BufferIn;
   1455   UINTN                           BufferInSize;
   1456   NET_FRAGMENT                    TempFragment;
   1457   UINT8                           *BufferOut;
   1458   UINTN                           BufferOutSize;
   1459   NET_BUF                         *PacketOut;
   1460   UINT8                           *DataOut;
   1461   UINT8                           *GetSessionDataBuffer;
   1462   UINTN                           GetSessionDataBufferSize;
   1463 
   1464   Status                   = EFI_SUCCESS;
   1465   Pdu                      = NULL;
   1466   BufferIn                 = NULL;
   1467   BufferInSize             = 0;
   1468   BufferOut                = NULL;
   1469   BufferOutSize            = 0;
   1470   PacketOut                = NULL;
   1471   DataOut                  = NULL;
   1472   GetSessionDataBuffer     = NULL;
   1473   GetSessionDataBufferSize = 0;
   1474 
   1475   //
   1476   // Receive only one TLS record
   1477   //
   1478   Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
   1479   if (EFI_ERROR (Status)) {
   1480     return Status;
   1481   }
   1482 
   1483   BufferInSize = Pdu->TotalSize;
   1484   BufferIn = AllocateZeroPool (BufferInSize);
   1485   if (BufferIn == NULL) {
   1486     Status = EFI_OUT_OF_RESOURCES;
   1487     NetbufFree (Pdu);
   1488     return Status;
   1489   }
   1490 
   1491   NetbufCopy (Pdu, 0, (UINT32) BufferInSize, BufferIn);
   1492 
   1493   NetbufFree (Pdu);
   1494 
   1495   //
   1496   // Handle Receive data.
   1497   //
   1498   RecordHeader = *(TLS_RECORD_HEADER *) BufferIn;
   1499 
   1500   if ((RecordHeader.ContentType == TLS_CONTENT_TYPE_APPLICATION_DATA) &&
   1501     (RecordHeader.Version.Major == 0x03) &&
   1502     (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
   1503     RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
   1504     RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
   1505   ) {
   1506     //
   1507     // Decrypt Packet.
   1508     //
   1509     Status = TlsProcessMessage (
   1510                HttpInstance,
   1511                BufferIn,
   1512                BufferInSize,
   1513                EfiTlsDecrypt,
   1514                &TempFragment
   1515                );
   1516 
   1517     FreePool (BufferIn);
   1518 
   1519     if (EFI_ERROR (Status)) {
   1520       if (Status == EFI_ABORTED) {
   1521         //
   1522         // Something wrong decryption the message.
   1523         // BuildResponsePacket() will be called to generate Error Alert message and send it out.
   1524         //
   1525         BufferOutSize = DEF_BUF_LEN;
   1526         BufferOut = AllocateZeroPool (BufferOutSize);
   1527         if (BufferOut == NULL) {
   1528           Status = EFI_OUT_OF_RESOURCES;
   1529           return Status;
   1530         }
   1531 
   1532         Status = HttpInstance->Tls->BuildResponsePacket (
   1533                                       HttpInstance->Tls,
   1534                                       NULL,
   1535                                       0,
   1536                                       BufferOut,
   1537                                       &BufferOutSize
   1538                                       );
   1539         if (Status == EFI_BUFFER_TOO_SMALL) {
   1540           FreePool (BufferOut);
   1541           BufferOut = AllocateZeroPool (BufferOutSize);
   1542           if (BufferOut == NULL) {
   1543             Status = EFI_OUT_OF_RESOURCES;
   1544             return Status;
   1545           }
   1546 
   1547           Status = HttpInstance->Tls->BuildResponsePacket (
   1548                                         HttpInstance->Tls,
   1549                                         NULL,
   1550                                         0,
   1551                                         BufferOut,
   1552                                         &BufferOutSize
   1553                                         );
   1554         }
   1555         if (EFI_ERROR (Status)) {
   1556           FreePool(BufferOut);
   1557           return Status;
   1558         }
   1559 
   1560         if (BufferOutSize != 0) {
   1561           PacketOut = NetbufAlloc ((UINT32)BufferOutSize);
   1562           DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
   1563           if (DataOut == NULL) {
   1564             FreePool (BufferOut);
   1565             return EFI_OUT_OF_RESOURCES;
   1566           }
   1567 
   1568           CopyMem (DataOut, BufferOut, BufferOutSize);
   1569 
   1570           Status = TlsCommonTransmit (HttpInstance, PacketOut);
   1571 
   1572           NetbufFree (PacketOut);
   1573         }
   1574 
   1575         FreePool(BufferOut);
   1576 
   1577         if (EFI_ERROR (Status)) {
   1578           return Status;
   1579         }
   1580 
   1581         return EFI_ABORTED;
   1582       }
   1583 
   1584       return Status;
   1585     }
   1586 
   1587     //
   1588     // Parsing buffer.
   1589     //
   1590     ASSERT (((TLS_RECORD_HEADER *) (TempFragment.Bulk))->ContentType == TLS_CONTENT_TYPE_APPLICATION_DATA);
   1591 
   1592     BufferInSize = ((TLS_RECORD_HEADER *) (TempFragment.Bulk))->Length;
   1593     BufferIn = AllocateZeroPool (BufferInSize);
   1594     if (BufferIn == NULL) {
   1595       Status = EFI_OUT_OF_RESOURCES;
   1596       return Status;
   1597     }
   1598 
   1599     CopyMem (BufferIn, TempFragment.Bulk + sizeof (TLS_RECORD_HEADER), BufferInSize);
   1600 
   1601     //
   1602     // Free the buffer in TempFragment.
   1603     //
   1604     FreePool (TempFragment.Bulk);
   1605 
   1606   } else if ((RecordHeader.ContentType == TLS_CONTENT_TYPE_ALERT) &&
   1607     (RecordHeader.Version.Major == 0x03) &&
   1608     (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
   1609     RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
   1610     RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
   1611     ) {
   1612     BufferOutSize = DEF_BUF_LEN;
   1613     BufferOut = AllocateZeroPool (BufferOutSize);
   1614     if (BufferOut == NULL) {
   1615       FreePool (BufferIn);
   1616       Status = EFI_OUT_OF_RESOURCES;
   1617       return Status;
   1618     }
   1619 
   1620     Status = HttpInstance->Tls->BuildResponsePacket (
   1621                                   HttpInstance->Tls,
   1622                                   BufferIn,
   1623                                   BufferInSize,
   1624                                   BufferOut,
   1625                                   &BufferOutSize
   1626                                   );
   1627     if (Status == EFI_BUFFER_TOO_SMALL) {
   1628       FreePool (BufferOut);
   1629       BufferOut = AllocateZeroPool (BufferOutSize);
   1630       if (BufferOut == NULL) {
   1631         FreePool (BufferIn);
   1632         Status = EFI_OUT_OF_RESOURCES;
   1633         return Status;
   1634       }
   1635 
   1636       Status = HttpInstance->Tls->BuildResponsePacket (
   1637                                     HttpInstance->Tls,
   1638                                     BufferIn,
   1639                                     BufferInSize,
   1640                                     BufferOut,
   1641                                     &BufferOutSize
   1642                                     );
   1643     }
   1644 
   1645     FreePool (BufferIn);
   1646 
   1647     if (EFI_ERROR (Status)) {
   1648       FreePool (BufferOut);
   1649       return Status;
   1650     }
   1651 
   1652     if (BufferOutSize != 0) {
   1653       PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
   1654       DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
   1655       if (DataOut == NULL) {
   1656         FreePool (BufferOut);
   1657         return EFI_OUT_OF_RESOURCES;
   1658       }
   1659 
   1660       CopyMem (DataOut, BufferOut, BufferOutSize);
   1661 
   1662       Status = TlsCommonTransmit (HttpInstance, PacketOut);
   1663 
   1664       NetbufFree (PacketOut);
   1665     }
   1666 
   1667     FreePool (BufferOut);
   1668 
   1669     //
   1670     // Get the session state.
   1671     //
   1672     GetSessionDataBufferSize = DEF_BUF_LEN;
   1673     GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
   1674     if (GetSessionDataBuffer == NULL) {
   1675       Status = EFI_OUT_OF_RESOURCES;
   1676       return Status;
   1677     }
   1678 
   1679     Status = HttpInstance->Tls->GetSessionData (
   1680                                   HttpInstance->Tls,
   1681                                   EfiTlsSessionState,
   1682                                   GetSessionDataBuffer,
   1683                                   &GetSessionDataBufferSize
   1684                                   );
   1685     if (Status == EFI_BUFFER_TOO_SMALL) {
   1686        FreePool (GetSessionDataBuffer);
   1687        GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
   1688        if (GetSessionDataBuffer == NULL) {
   1689          Status = EFI_OUT_OF_RESOURCES;
   1690          return Status;
   1691        }
   1692 
   1693        Status = HttpInstance->Tls->GetSessionData (
   1694                                      HttpInstance->Tls,
   1695                                      EfiTlsSessionState,
   1696                                      GetSessionDataBuffer,
   1697                                      &GetSessionDataBufferSize
   1698                                      );
   1699     }
   1700     if (EFI_ERROR (Status)) {
   1701       FreePool (GetSessionDataBuffer);
   1702       return Status;
   1703     }
   1704 
   1705     ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
   1706     HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;
   1707 
   1708     FreePool (GetSessionDataBuffer);
   1709 
   1710     if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
   1711       DEBUG ((EFI_D_ERROR, "TLS Session State Error!\n"));
   1712       return EFI_ABORTED;
   1713     }
   1714 
   1715     BufferIn = NULL;
   1716     BufferInSize = 0;
   1717   }
   1718 
   1719   Fragment->Bulk = BufferIn;
   1720   Fragment->Len = (UINT32) BufferInSize;
   1721 
   1722   return Status;
   1723 }
   1724