f0077dd4b8cbef6675ca475f63ac3491b28f4207
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpsSupport.c
1 /** @file
2   Miscellaneous routines specific to Https for HttpDxe driver.
3
4 Copyright (c) 2016 - 2017, 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 == TlsContentTypeHandshake ||
887     RecordHeader.ContentType == TlsContentTypeAlert ||
888     RecordHeader.ContentType == TlsContentTypeChangeCipherSpec ||
889     RecordHeader.ContentType == TlsContentTypeApplicationData) &&
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   return Status;
1298 }
1299
1300 /**
1301   Process one message according to the CryptMode.
1302
1303   @param[in]           HttpInstance    Pointer to HTTP_PROTOCOL structure.
1304   @param[in]           Message         Pointer to the message buffer needed to processed.
1305   @param[in]           MessageSize     Pointer to the message buffer size.
1306   @param[in]           ProcessMode     Process mode.
1307   @param[in, out]      Fragment        Only one Fragment returned after the Message is
1308                                        processed successfully.
1309
1310   @retval EFI_SUCCESS          Message is processed successfully.
1311   @retval EFI_OUT_OF_RESOURCES   Can't allocate memory resources.
1312   @retval Others               Other errors as indicated.
1313
1314 **/
1315 EFI_STATUS
1316 EFIAPI
1317 TlsProcessMessage (
1318   IN     HTTP_PROTOCOL            *HttpInstance,
1319   IN     UINT8                    *Message,
1320   IN     UINTN                    MessageSize,
1321   IN     EFI_TLS_CRYPT_MODE       ProcessMode,
1322   IN OUT NET_FRAGMENT             *Fragment
1323   )
1324 {
1325   EFI_STATUS                      Status;
1326   UINT8                           *Buffer;
1327   UINT32                          BufferSize;
1328   UINT32                          BytesCopied;
1329   EFI_TLS_FRAGMENT_DATA           *FragmentTable;
1330   UINT32                          FragmentCount;
1331   EFI_TLS_FRAGMENT_DATA           *OriginalFragmentTable;
1332   UINTN                           Index;
1333
1334   Status                   = EFI_SUCCESS;
1335   Buffer                   = NULL;
1336   BufferSize               = 0;
1337   BytesCopied              = 0;
1338   FragmentTable            = NULL;
1339   OriginalFragmentTable    = NULL;
1340
1341   //
1342   // Rebuild fragment table from BufferIn.
1343   //
1344   FragmentCount = 1;
1345   FragmentTable = AllocateZeroPool (FragmentCount * sizeof (EFI_TLS_FRAGMENT_DATA));
1346   if (FragmentTable == NULL) {
1347     Status = EFI_OUT_OF_RESOURCES;
1348     goto ON_EXIT;
1349   }
1350
1351   FragmentTable->FragmentLength = (UINT32) MessageSize;
1352   FragmentTable->FragmentBuffer = Message;
1353
1354   //
1355   // Record the original FragmentTable.
1356   //
1357   OriginalFragmentTable = FragmentTable;
1358
1359   //
1360   // Process the Message.
1361   //
1362   Status = HttpInstance->Tls->ProcessPacket (
1363                                 HttpInstance->Tls,
1364                                 &FragmentTable,
1365                                 &FragmentCount,
1366                                 ProcessMode
1367                                 );
1368   if (EFI_ERROR (Status)) {
1369     goto ON_EXIT;
1370   }
1371
1372   //
1373   // Calculate the size according to FragmentTable.
1374   //
1375   for (Index = 0; Index < FragmentCount; Index++) {
1376     BufferSize += FragmentTable[Index].FragmentLength;
1377   }
1378
1379   //
1380   // Allocate buffer for processed data.
1381   //
1382   Buffer = AllocateZeroPool (BufferSize);
1383   if (Buffer == NULL) {
1384     Status = EFI_OUT_OF_RESOURCES;
1385     goto ON_EXIT;
1386   }
1387
1388   //
1389   // Copy the new FragmentTable buffer into Buffer.
1390   //
1391   for (Index = 0; Index < FragmentCount; Index++) {
1392     CopyMem (
1393       (Buffer + BytesCopied),
1394       FragmentTable[Index].FragmentBuffer,
1395       FragmentTable[Index].FragmentLength
1396       );
1397     BytesCopied += FragmentTable[Index].FragmentLength;
1398
1399     //
1400     // Free the FragmentBuffer since it has been copied.
1401     //
1402     FreePool (FragmentTable[Index].FragmentBuffer);
1403   }
1404
1405   Fragment->Len  = BufferSize;
1406   Fragment->Bulk = Buffer;
1407
1408 ON_EXIT:
1409
1410   if (OriginalFragmentTable != NULL) {
1411     FreePool (OriginalFragmentTable);
1412     OriginalFragmentTable = NULL;
1413   }
1414
1415   //
1416   // Caller has the responsibility to free the FragmentTable.
1417   //
1418   if (FragmentTable != NULL) {
1419     FreePool (FragmentTable);
1420     FragmentTable = NULL;
1421   }
1422
1423   return Status;
1424 }
1425
1426 /**
1427   Receive one fragment decrypted from one TLS record.
1428
1429   @param[in]           HttpInstance    Pointer to HTTP_PROTOCOL structure.
1430   @param[in, out]      Fragment        The received Fragment.
1431   @param[in]           Timeout         The time to wait for connection done.
1432
1433   @retval EFI_SUCCESS          One fragment is received.
1434   @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1435   @retval EFI_ABORTED          Something wrong decryption the message.
1436   @retval Others               Other errors as indicated.
1437
1438 **/
1439 EFI_STATUS
1440 EFIAPI
1441 HttpsReceive (
1442   IN     HTTP_PROTOCOL         *HttpInstance,
1443   IN OUT NET_FRAGMENT          *Fragment,
1444   IN     EFI_EVENT             Timeout
1445   )
1446 {
1447   EFI_STATUS                      Status;
1448   NET_BUF                         *Pdu;
1449   TLS_RECORD_HEADER               RecordHeader;
1450   UINT8                           *BufferIn;
1451   UINTN                           BufferInSize;
1452   NET_FRAGMENT                    TempFragment;
1453   UINT8                           *BufferOut;
1454   UINTN                           BufferOutSize;
1455   NET_BUF                         *PacketOut;
1456   UINT8                           *DataOut;
1457   UINT8                           *GetSessionDataBuffer;
1458   UINTN                           GetSessionDataBufferSize;
1459
1460   Status                   = EFI_SUCCESS;
1461   Pdu                      = NULL;
1462   BufferIn                 = NULL;
1463   BufferInSize             = 0;
1464   BufferOut                = NULL;
1465   BufferOutSize            = 0;
1466   PacketOut                = NULL;
1467   DataOut                  = NULL;
1468   GetSessionDataBuffer     = NULL;
1469   GetSessionDataBufferSize = 0;
1470
1471   //
1472   // Receive only one TLS record
1473   //
1474   Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
1475   if (EFI_ERROR (Status)) {
1476     return Status;
1477   }
1478
1479   BufferInSize = Pdu->TotalSize;
1480   BufferIn = AllocateZeroPool (BufferInSize);
1481   if (BufferIn == NULL) {
1482     Status = EFI_OUT_OF_RESOURCES;
1483     NetbufFree (Pdu);
1484     return Status;
1485   }
1486
1487   NetbufCopy (Pdu, 0, (UINT32) BufferInSize, BufferIn);
1488
1489   NetbufFree (Pdu);
1490
1491   //
1492   // Handle Receive data.
1493   //
1494   RecordHeader = *(TLS_RECORD_HEADER *) BufferIn;
1495
1496   if ((RecordHeader.ContentType == TlsContentTypeApplicationData) &&
1497     (RecordHeader.Version.Major == 0x03) &&
1498     (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
1499     RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
1500     RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
1501   ) {
1502     //
1503     // Decrypt Packet.
1504     //
1505     Status = TlsProcessMessage (
1506                HttpInstance,
1507                BufferIn,
1508                BufferInSize,
1509                EfiTlsDecrypt,
1510                &TempFragment
1511                );
1512
1513     FreePool (BufferIn);
1514
1515     if (EFI_ERROR (Status)) {
1516       if (Status == EFI_ABORTED) {
1517         //
1518         // Something wrong decryption the message.
1519         // BuildResponsePacket() will be called to generate Error Alert message and send it out.
1520         //
1521         BufferOutSize = DEF_BUF_LEN;
1522         BufferOut = AllocateZeroPool (BufferOutSize);
1523         if (BufferOut == NULL) {
1524           Status = EFI_OUT_OF_RESOURCES;
1525           return Status;
1526         }
1527
1528         Status = HttpInstance->Tls->BuildResponsePacket (
1529                                       HttpInstance->Tls,
1530                                       NULL,
1531                                       0,
1532                                       BufferOut,
1533                                       &BufferOutSize
1534                                       );
1535         if (Status == EFI_BUFFER_TOO_SMALL) {
1536           FreePool (BufferOut);
1537           BufferOut = AllocateZeroPool (BufferOutSize);
1538           if (BufferOut == NULL) {
1539             Status = EFI_OUT_OF_RESOURCES;
1540             return Status;
1541           }
1542
1543           Status = HttpInstance->Tls->BuildResponsePacket (
1544                                         HttpInstance->Tls,
1545                                         NULL,
1546                                         0,
1547                                         BufferOut,
1548                                         &BufferOutSize
1549                                         );
1550         }
1551         if (EFI_ERROR (Status)) {
1552           FreePool(BufferOut);
1553           return Status;
1554         }
1555
1556         if (BufferOutSize != 0) {
1557           PacketOut = NetbufAlloc ((UINT32)BufferOutSize);
1558           DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
1559           if (DataOut == NULL) {
1560             FreePool (BufferOut);
1561             return EFI_OUT_OF_RESOURCES;
1562           }
1563           
1564           CopyMem (DataOut, BufferOut, BufferOutSize);
1565
1566           Status = TlsCommonTransmit (HttpInstance, PacketOut);
1567
1568           NetbufFree (PacketOut);
1569         }
1570
1571         FreePool(BufferOut);
1572
1573         if (EFI_ERROR (Status)) {
1574           return Status;
1575         }
1576
1577         return EFI_ABORTED;
1578       }
1579
1580       return Status;
1581     }
1582
1583     //
1584     // Parsing buffer.
1585     //
1586     ASSERT (((TLS_RECORD_HEADER *) (TempFragment.Bulk))->ContentType == TlsContentTypeApplicationData);
1587
1588     BufferInSize = ((TLS_RECORD_HEADER *) (TempFragment.Bulk))->Length;
1589     BufferIn = AllocateZeroPool (BufferInSize);
1590     if (BufferIn == NULL) {
1591       Status = EFI_OUT_OF_RESOURCES;
1592       return Status;
1593     }
1594
1595     CopyMem (BufferIn, TempFragment.Bulk + sizeof (TLS_RECORD_HEADER), BufferInSize);
1596
1597     //
1598     // Free the buffer in TempFragment.
1599     //
1600     FreePool (TempFragment.Bulk);
1601
1602   } else if ((RecordHeader.ContentType == TlsContentTypeAlert) &&
1603     (RecordHeader.Version.Major == 0x03) &&
1604     (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
1605     RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
1606     RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
1607     ) {
1608     BufferOutSize = DEF_BUF_LEN;
1609     BufferOut = AllocateZeroPool (BufferOutSize);
1610     if (BufferOut == NULL) {
1611       FreePool (BufferIn);
1612       Status = EFI_OUT_OF_RESOURCES;
1613       return Status;
1614     }
1615
1616     Status = HttpInstance->Tls->BuildResponsePacket (
1617                                   HttpInstance->Tls,
1618                                   BufferIn,
1619                                   BufferInSize,
1620                                   BufferOut,
1621                                   &BufferOutSize
1622                                   );
1623     if (Status == EFI_BUFFER_TOO_SMALL) {
1624       FreePool (BufferOut);
1625       BufferOut = AllocateZeroPool (BufferOutSize);
1626       if (BufferOut == NULL) {
1627         FreePool (BufferIn);
1628         Status = EFI_OUT_OF_RESOURCES;
1629         return Status;
1630       }
1631
1632       Status = HttpInstance->Tls->BuildResponsePacket (
1633                                     HttpInstance->Tls,
1634                                     BufferIn,
1635                                     BufferInSize,
1636                                     BufferOut,
1637                                     &BufferOutSize
1638                                     );
1639     }
1640
1641     FreePool (BufferIn);
1642
1643     if (EFI_ERROR (Status)) {
1644       FreePool (BufferOut);
1645       return Status;
1646     }
1647
1648     if (BufferOutSize != 0) {
1649       PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
1650       DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
1651       if (DataOut == NULL) {
1652         FreePool (BufferOut);
1653         return EFI_OUT_OF_RESOURCES;
1654       }
1655       
1656       CopyMem (DataOut, BufferOut, BufferOutSize);
1657
1658       Status = TlsCommonTransmit (HttpInstance, PacketOut);
1659
1660       NetbufFree (PacketOut);
1661     }
1662
1663     FreePool (BufferOut);
1664
1665     //
1666     // Get the session state.
1667     //
1668     GetSessionDataBufferSize = DEF_BUF_LEN;
1669     GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1670     if (GetSessionDataBuffer == NULL) {
1671       Status = EFI_OUT_OF_RESOURCES;
1672       return Status;
1673     }
1674
1675     Status = HttpInstance->Tls->GetSessionData (
1676                                   HttpInstance->Tls,
1677                                   EfiTlsSessionState,
1678                                   GetSessionDataBuffer,
1679                                   &GetSessionDataBufferSize
1680                                   );
1681     if (Status == EFI_BUFFER_TOO_SMALL) {
1682        FreePool (GetSessionDataBuffer);
1683        GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1684        if (GetSessionDataBuffer == NULL) {
1685          Status = EFI_OUT_OF_RESOURCES;
1686          return Status;
1687        }
1688
1689        Status = HttpInstance->Tls->GetSessionData (
1690                                      HttpInstance->Tls,
1691                                      EfiTlsSessionState,
1692                                      GetSessionDataBuffer,
1693                                      &GetSessionDataBufferSize
1694                                      );
1695     }
1696     if (EFI_ERROR (Status)) {
1697       FreePool (GetSessionDataBuffer);
1698       return Status;
1699     }
1700
1701     ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
1702     HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;
1703
1704     FreePool (GetSessionDataBuffer);
1705
1706     if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
1707       DEBUG ((EFI_D_ERROR, "TLS Session State Error!\n"));
1708       return EFI_ABORTED;
1709     }
1710
1711     BufferIn = NULL;
1712     BufferInSize = 0;
1713   }
1714
1715   Fragment->Bulk = BufferIn;
1716   Fragment->Len = (UINT32) BufferInSize;
1717
1718   return Status;
1719 }