NetworkPkg: Define one private variable for HTTPS to set Tls CipherList.
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpsSupport.c
CommitLineData
7618784b
HW
1/** @file\r
2 Miscellaneous routines specific to Https for HttpDxe driver.\r
3\r
4Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>\r
5(C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>\r
6This program and the accompanying materials\r
7are licensed and made available under the terms and conditions of the BSD License\r
8which accompanies this distribution. The full text of the license may be found at\r
9http://opensource.org/licenses/bsd-license.php\r
10\r
11THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
12WITHOUT 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
38CHAR8 *\r
39AsciiStrCaseStr (\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
1e4725e5 70 Src += ('a' - 'A');\r
7618784b
HW
71 }\r
72\r
73 if ((Dst >= 'A') && (Dst <= 'Z')) {\r
1e4725e5 74 Dst += ('a' - 'A');\r
7618784b
HW
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
101VOID\r
102EFIAPI\r
103FreeNbufList (\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
122BOOLEAN\r
123IsHttpsUrl (\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
45ea8a0c 143 @param[out] TlsSb Pointer to the TLS SERVICE_BINDING_PROTOCOL.\r
7618784b
HW
144 @param[out] TlsProto Pointer to the EFI_TLS_PROTOCOL instance.\r
145 @param[out] TlsConfiguration Pointer to the EFI_TLS_CONFIGURATION_PROTOCOL instance.\r
146\r
147 @return The child handle with opened EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.\r
148\r
149**/\r
150EFI_HANDLE\r
151EFIAPI\r
152TlsCreateChild (\r
153 IN EFI_HANDLE ImageHandle,\r
45ea8a0c 154 OUT EFI_SERVICE_BINDING_PROTOCOL **TlsSb,\r
7618784b
HW
155 OUT EFI_TLS_PROTOCOL **TlsProto,\r
156 OUT EFI_TLS_CONFIGURATION_PROTOCOL **TlsConfiguration\r
157 )\r
158{\r
159 EFI_STATUS Status;\r
7618784b
HW
160 EFI_HANDLE TlsChildHandle;\r
161\r
7618784b
HW
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
45ea8a0c 170 (VOID **) TlsSb\r
7618784b 171 );\r
45ea8a0c 172 if (*TlsSb == NULL) {\r
7618784b
HW
173 return NULL;\r
174 }\r
175\r
45ea8a0c 176 Status = (*TlsSb)->CreateChild (*TlsSb, &TlsChildHandle);\r
7618784b
HW
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
45ea8a0c 190 (*TlsSb)->DestroyChild (*TlsSb, TlsChildHandle);\r
7618784b
HW
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
45ea8a0c 203 (*TlsSb)->DestroyChild (*TlsSb, TlsChildHandle);\r
7618784b
HW
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
220EFI_STATUS\r
221EFIAPI\r
222TlsCreateTxRxEvent (\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
320ERROR:\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
335VOID\r
336EFIAPI\r
337TlsCloseTxRxEvent (\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
376EFI_STATUS\r
377TlsConfigCertificate (\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
478EFI_STATUS\r
479EFIAPI\r
480TlsConfigureSession (\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
547ERROR:\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
566EFI_STATUS\r
567EFIAPI\r
568TlsCommonTransmit (\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
664ON_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
684EFI_STATUS\r
685EFIAPI\r
686TlsCommonReceive (\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
805ON_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
829EFI_STATUS\r
830EFIAPI\r
831TlsReceiveOnePdu (\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
930FORM_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
939ON_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
963EFI_STATUS\r
964EFIAPI\r
965TlsConnectSession (\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
1212EFI_STATUS\r
1213EFIAPI\r
1214TlsCloseSession (\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
1315EFI_STATUS\r
1316EFIAPI\r
1317TlsProcessMessage (\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
1408ON_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
1439EFI_STATUS\r
1440EFIAPI\r
1441HttpsReceive (\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