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