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