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 *
AsciiStrCaseStr(IN CONST CHAR8 * String,IN CONST CHAR8 * SearchString)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
FreeNbufList(IN VOID * Arg)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
IsHttpsUrl(IN CHAR8 * Url)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
TlsCreateChild(IN EFI_HANDLE ImageHandle,OUT EFI_TLS_PROTOCOL ** TlsProto,OUT EFI_TLS_CONFIGURATION_PROTOCOL ** TlsConfiguration)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
TlsCreateTxRxEvent(IN OUT HTTP_PROTOCOL * HttpInstance)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
TlsCloseTxRxEvent(IN HTTP_PROTOCOL * HttpInstance)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
TlsConfigCertificate(IN OUT HTTP_PROTOCOL * HttpInstance)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
TlsConfigureSession(IN OUT HTTP_PROTOCOL * HttpInstance)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
TlsCommonTransmit(IN OUT HTTP_PROTOCOL * HttpInstance,IN NET_BUF * Packet)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
TlsCommonReceive(IN OUT HTTP_PROTOCOL * HttpInstance,IN NET_BUF * Packet,IN EFI_EVENT Timeout)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
TlsReceiveOnePdu(IN OUT HTTP_PROTOCOL * HttpInstance,OUT NET_BUF ** Pdu,IN EFI_EVENT Timeout)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
TlsConnectSession(IN HTTP_PROTOCOL * HttpInstance,IN EFI_EVENT Timeout)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
TlsCloseSession(IN HTTP_PROTOCOL * HttpInstance)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
TlsProcessMessage(IN HTTP_PROTOCOL * HttpInstance,IN UINT8 * Message,IN UINTN MessageSize,IN EFI_TLS_CRYPT_MODE ProcessMode,IN OUT NET_FRAGMENT * Fragment)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
HttpsReceive(IN HTTP_PROTOCOL * HttpInstance,IN OUT NET_FRAGMENT * Fragment,IN EFI_EVENT Timeout)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