NetworkPkg/HttpDxe: HTTPS support over IPv4 and IPv6
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpsSupport.c
1 /** @file
2 Miscellaneous routines specific to Https for HttpDxe driver.
3
4 Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
5 (C) Copyright 2016 Hewlett Packard Enterprise Development LP<BR>
6 This program and the accompanying materials
7 are licensed and made available under the terms and conditions of the BSD License
8 which accompanies this distribution. The full text of the license may be found at
9 http://opensource.org/licenses/bsd-license.php
10
11 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
12 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
13
14 **/
15
16 #include "HttpDriver.h"
17
18 /**
19 Returns the first occurrence of a Null-terminated ASCII sub-string in a Null-terminated
20 ASCII string and ignore case during the search process.
21
22 This function scans the contents of the ASCII string specified by String
23 and returns the first occurrence of SearchString and ignore case during the search process.
24 If SearchString is not found in String, then NULL is returned. If the length of SearchString
25 is zero, then String is returned.
26
27 If String is NULL, then ASSERT().
28 If SearchString is NULL, then ASSERT().
29
30 @param[in] String A pointer to a Null-terminated ASCII string.
31 @param[in] SearchString A pointer to a Null-terminated ASCII string to search for.
32
33 @retval NULL If the SearchString does not appear in String.
34 @retval others If there is a match return the first occurrence of SearchingString.
35 If the length of SearchString is zero,return String.
36
37 **/
38 CHAR8 *
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 (Status == EFI_BUFFER_TOO_SMALL) {
405 //
406 // Allocate buffer and read the config variable.
407 //
408 CACert = AllocatePool (CACertSize);
409 if (CACert == NULL) {
410 return EFI_OUT_OF_RESOURCES;
411 }
412
413 Status = gRT->GetVariable (
414 EFI_TLS_CA_CERTIFICATE_VARIABLE,
415 &gEfiTlsCaCertificateGuid,
416 NULL,
417 &CACertSize,
418 CACert
419 );
420 if (EFI_ERROR (Status)) {
421 //
422 // GetVariable still error or the variable is corrupted.
423 // Fall back to the default value.
424 //
425 FreePool (CACert);
426
427 return EFI_NOT_FOUND;
428 }
429 }
430
431 //
432 // Enumerate all data and erasing the target item.
433 //
434 ItemDataSize = (UINT32) CACertSize;
435 CertList = (EFI_SIGNATURE_LIST *) CACert;
436 while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
437 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
438 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
439 for (Index = 0; Index < CertCount; Index++) {
440 //
441 // EfiTlsConfigDataTypeCACertificate
442 //
443 Status = HttpInstance->TlsConfiguration->SetData (
444 HttpInstance->TlsConfiguration,
445 EfiTlsConfigDataTypeCACertificate,
446 Cert->SignatureData,
447 CertList->SignatureSize - sizeof (Cert->SignatureOwner)
448 );
449 if (EFI_ERROR (Status)) {
450 FreePool (CACert);
451 return Status;
452 }
453
454 Cert = (EFI_SIGNATURE_DATA *) ((UINT8 *) Cert + CertList->SignatureSize);
455 }
456
457 ItemDataSize -= CertList->SignatureListSize;
458 CertList = (EFI_SIGNATURE_LIST *) ((UINT8 *) CertList + CertList->SignatureListSize);
459 }
460
461 FreePool (CACert);
462 return Status;
463 }
464
465 /**
466 Configure TLS session data.
467
468 @param[in, out] HttpInstance The HTTP instance private data.
469
470 @retval EFI_SUCCESS TLS session data is configured.
471 @retval Others Other error as indicated.
472
473 **/
474 EFI_STATUS
475 EFIAPI
476 TlsConfigureSession (
477 IN OUT HTTP_PROTOCOL *HttpInstance
478 )
479 {
480 EFI_STATUS Status;
481
482 //
483 // TlsConfigData initialization
484 //
485 HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient;
486 HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER;
487 HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted;
488
489 //
490 // EfiTlsConnectionEnd,
491 // EfiTlsVerifyMethod
492 // EfiTlsSessionState
493 //
494 Status = HttpInstance->Tls->SetSessionData (
495 HttpInstance->Tls,
496 EfiTlsConnectionEnd,
497 &(HttpInstance->TlsConfigData.ConnectionEnd),
498 sizeof (EFI_TLS_CONNECTION_END)
499 );
500 if (EFI_ERROR (Status)) {
501 return Status;
502 }
503
504 Status = HttpInstance->Tls->SetSessionData (
505 HttpInstance->Tls,
506 EfiTlsVerifyMethod,
507 &HttpInstance->TlsConfigData.VerifyMethod,
508 sizeof (EFI_TLS_VERIFY)
509 );
510 if (EFI_ERROR (Status)) {
511 return Status;
512 }
513
514 Status = HttpInstance->Tls->SetSessionData (
515 HttpInstance->Tls,
516 EfiTlsSessionState,
517 &(HttpInstance->TlsConfigData.SessionState),
518 sizeof (EFI_TLS_SESSION_STATE)
519 );
520 if (EFI_ERROR (Status)) {
521 return Status;
522 }
523
524 //
525 // Tls Config Certificate
526 //
527 Status = TlsConfigCertificate (HttpInstance);
528 if (EFI_ERROR (Status)) {
529 DEBUG ((EFI_D_ERROR, "TLS Certificate Config Error!\n"));
530 return Status;
531 }
532
533 //
534 // TlsCreateTxRxEvent
535 //
536 Status = TlsCreateTxRxEvent (HttpInstance);
537 if (EFI_ERROR (Status)) {
538 goto ERROR;
539 }
540
541 return Status;
542
543 ERROR:
544 TlsCloseTxRxEvent (HttpInstance);
545
546 return Status;
547 }
548
549 /**
550 Transmit the Packet by processing the associated HTTPS token.
551
552 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
553 @param[in] Packet The packet to transmit.
554
555 @retval EFI_SUCCESS The packet is transmitted.
556 @retval EFI_INVALID_PARAMETER HttpInstance is NULL or Packet is NULL.
557 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
558 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
559 @retval Others Other errors as indicated.
560
561 **/
562 EFI_STATUS
563 EFIAPI
564 TlsCommonTransmit (
565 IN OUT HTTP_PROTOCOL *HttpInstance,
566 IN NET_BUF *Packet
567 )
568 {
569 EFI_STATUS Status;
570 VOID *Data;
571 UINTN Size;
572
573 if ((HttpInstance == NULL) || (Packet == NULL)) {
574 return EFI_INVALID_PARAMETER;
575 }
576
577 if (!HttpInstance->LocalAddressIsIPv6) {
578 Size = sizeof (EFI_TCP4_TRANSMIT_DATA) +
579 (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA);
580 } else {
581 Size = sizeof (EFI_TCP6_TRANSMIT_DATA) +
582 (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA);
583 }
584
585 Data = AllocatePool (Size);
586 if (Data == NULL) {
587 return EFI_OUT_OF_RESOURCES;
588 }
589
590 if (!HttpInstance->LocalAddressIsIPv6) {
591 ((EFI_TCP4_TRANSMIT_DATA *) Data)->Push = TRUE;
592 ((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent = FALSE;
593 ((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
594
595 //
596 // Build the fragment table.
597 //
598 ((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
599
600 NetbufBuildExt (
601 Packet,
602 (NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0],
603 &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount
604 );
605
606 HttpInstance->Tcp4TlsTxToken.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data;
607
608 Status = EFI_DEVICE_ERROR;
609
610 //
611 // Transmit the packet.
612 //
613 Status = HttpInstance->Tcp4->Transmit (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsTxToken);
614 if (EFI_ERROR (Status)) {
615 goto ON_EXIT;
616 }
617
618 while (!HttpInstance->TlsIsTxDone) {
619 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
620 }
621
622 HttpInstance->TlsIsTxDone = FALSE;
623 Status = HttpInstance->Tcp4TlsTxToken.CompletionToken.Status;
624 } else {
625 ((EFI_TCP6_TRANSMIT_DATA *) Data)->Push = TRUE;
626 ((EFI_TCP6_TRANSMIT_DATA *) Data)->Urgent = FALSE;
627 ((EFI_TCP6_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
628
629 //
630 // Build the fragment table.
631 //
632 ((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
633
634 NetbufBuildExt (
635 Packet,
636 (NET_FRAGMENT *) &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentTable[0],
637 &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount
638 );
639
640 HttpInstance->Tcp6TlsTxToken.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data;
641
642 Status = EFI_DEVICE_ERROR;
643
644 //
645 // Transmit the packet.
646 //
647 Status = HttpInstance->Tcp6->Transmit (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsTxToken);
648 if (EFI_ERROR (Status)) {
649 goto ON_EXIT;
650 }
651
652 while (!HttpInstance->TlsIsTxDone) {
653 HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
654 }
655
656 HttpInstance->TlsIsTxDone = FALSE;
657 Status = HttpInstance->Tcp6TlsTxToken.CompletionToken.Status;
658 }
659
660 ON_EXIT:
661 FreePool (Data);
662
663 return Status;
664 }
665
666 /**
667 Receive the Packet by processing the associated HTTPS token.
668
669 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
670 @param[in] Packet The packet to transmit.
671 @param[in] Timeout The time to wait for connection done.
672
673 @retval EFI_SUCCESS The Packet is received.
674 @retval EFI_INVALID_PARAMETER HttpInstance is NULL or Packet is NULL.
675 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
676 @retval EFI_TIMEOUT The operation is time out.
677 @retval Others Other error as indicated.
678
679 **/
680 EFI_STATUS
681 EFIAPI
682 TlsCommonReceive (
683 IN OUT HTTP_PROTOCOL *HttpInstance,
684 IN NET_BUF *Packet,
685 IN EFI_EVENT Timeout
686 )
687 {
688 EFI_TCP4_RECEIVE_DATA *Tcp4RxData;
689 EFI_TCP6_RECEIVE_DATA *Tcp6RxData;
690 EFI_STATUS Status;
691 NET_FRAGMENT *Fragment;
692 UINT32 FragmentCount;
693 UINT32 CurrentFragment;
694
695 Tcp4RxData = NULL;
696 Tcp6RxData = NULL;
697
698 if ((HttpInstance == NULL) || (Packet == NULL)) {
699 return EFI_INVALID_PARAMETER;
700 }
701
702 FragmentCount = Packet->BlockOpNum;
703 Fragment = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
704 if (Fragment == NULL) {
705 Status = EFI_OUT_OF_RESOURCES;
706 goto ON_EXIT;
707 }
708
709 //
710 // Build the fragment table.
711 //
712 NetbufBuildExt (Packet, Fragment, &FragmentCount);
713
714 if (!HttpInstance->LocalAddressIsIPv6) {
715 Tcp4RxData = HttpInstance->Tcp4TlsRxToken.Packet.RxData;
716 if (Tcp4RxData == NULL) {
717 return EFI_INVALID_PARAMETER;
718 }
719 Tcp4RxData->FragmentCount = 1;
720 } else {
721 Tcp6RxData = HttpInstance->Tcp6TlsRxToken.Packet.RxData;
722 if (Tcp6RxData == NULL) {
723 return EFI_INVALID_PARAMETER;
724 }
725 Tcp6RxData->FragmentCount = 1;
726 }
727
728 CurrentFragment = 0;
729 Status = EFI_SUCCESS;
730
731 while (CurrentFragment < FragmentCount) {
732 if (!HttpInstance->LocalAddressIsIPv6) {
733 Tcp4RxData->DataLength = Fragment[CurrentFragment].Len;
734 Tcp4RxData->FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len;
735 Tcp4RxData->FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk;
736 Status = HttpInstance->Tcp4->Receive (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken);
737 } else {
738 Tcp6RxData->DataLength = Fragment[CurrentFragment].Len;
739 Tcp6RxData->FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len;
740 Tcp6RxData->FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk;
741 Status = HttpInstance->Tcp6->Receive (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken);
742 }
743 if (EFI_ERROR (Status)) {
744 goto ON_EXIT;
745 }
746
747 while (!HttpInstance->TlsIsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
748 //
749 // Poll until some data is received or an error occurs.
750 //
751 if (!HttpInstance->LocalAddressIsIPv6) {
752 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
753 } else {
754 HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
755 }
756 }
757
758 if (!HttpInstance->TlsIsRxDone) {
759 //
760 // Timeout occurs, cancel the receive request.
761 //
762 if (!HttpInstance->LocalAddressIsIPv6) {
763 HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken.CompletionToken);
764 } else {
765 HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken.CompletionToken);
766 }
767
768 Status = EFI_TIMEOUT;
769 goto ON_EXIT;
770 } else {
771 HttpInstance->TlsIsRxDone = FALSE;
772 }
773
774 if (!HttpInstance->LocalAddressIsIPv6) {
775 Status = HttpInstance->Tcp4TlsRxToken.CompletionToken.Status;
776 if (EFI_ERROR (Status)) {
777 goto ON_EXIT;
778 }
779
780 Fragment[CurrentFragment].Len -= Tcp4RxData->FragmentTable[0].FragmentLength;
781 if (Fragment[CurrentFragment].Len == 0) {
782 CurrentFragment++;
783 } else {
784 Fragment[CurrentFragment].Bulk += Tcp4RxData->FragmentTable[0].FragmentLength;
785 }
786 } else {
787 Status = HttpInstance->Tcp6TlsRxToken.CompletionToken.Status;
788 if (EFI_ERROR (Status)) {
789 goto ON_EXIT;
790 }
791
792 Fragment[CurrentFragment].Len -= Tcp6RxData->FragmentTable[0].FragmentLength;
793 if (Fragment[CurrentFragment].Len == 0) {
794 CurrentFragment++;
795 } else {
796 Fragment[CurrentFragment].Bulk += Tcp6RxData->FragmentTable[0].FragmentLength;
797 }
798 }
799 }
800
801 ON_EXIT:
802
803 if (Fragment != NULL) {
804 FreePool (Fragment);
805 }
806
807 return Status;
808 }
809
810 /**
811 Receive one TLS PDU. An TLS PDU contains an TLS record header and it's
812 corresponding record data. These two parts will be put into two blocks of buffers in the
813 net buffer.
814
815 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
816 @param[out] Pdu The received TLS PDU.
817 @param[in] Timeout The time to wait for connection done.
818
819 @retval EFI_SUCCESS An TLS PDU is received.
820 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
821 @retval EFI_PROTOCOL_ERROR An unexpected TLS packet was received.
822 @retval Others Other errors as indicated.
823
824 **/
825 EFI_STATUS
826 EFIAPI
827 TlsReceiveOnePdu (
828 IN OUT HTTP_PROTOCOL *HttpInstance,
829 OUT NET_BUF **Pdu,
830 IN EFI_EVENT Timeout
831 )
832 {
833 EFI_STATUS Status;
834
835 LIST_ENTRY *NbufList;
836
837 UINT32 Len;
838
839 NET_BUF *PduHdr;
840 UINT8 *Header;
841 TLS_RECORD_HEADER RecordHeader;
842
843 NET_BUF *DataSeg;
844
845 NbufList = NULL;
846 PduHdr = NULL;
847 Header = NULL;
848 DataSeg = NULL;
849
850 NbufList = AllocatePool (sizeof (LIST_ENTRY));
851 if (NbufList == NULL) {
852 return EFI_OUT_OF_RESOURCES;
853 }
854
855 InitializeListHead (NbufList);
856
857 //
858 // Allocate buffer to receive one TLS header.
859 //
860 Len = sizeof (TLS_RECORD_HEADER);
861 PduHdr = NetbufAlloc (Len);
862 if (PduHdr == NULL) {
863 Status = EFI_OUT_OF_RESOURCES;
864 goto ON_EXIT;
865 }
866
867 Header = NetbufAllocSpace (PduHdr, Len, NET_BUF_TAIL);
868 if (Header == NULL) {
869 Status = EFI_OUT_OF_RESOURCES;
870 goto ON_EXIT;
871 }
872
873 //
874 // First step, receive one TLS header.
875 //
876 Status = TlsCommonReceive (HttpInstance, PduHdr, Timeout);
877 if (EFI_ERROR (Status)) {
878 goto ON_EXIT;
879 }
880
881 RecordHeader = *(TLS_RECORD_HEADER *) Header;
882 if ((RecordHeader.ContentType == TLS_CONTENT_TYPE_HANDSHAKE ||
883 RecordHeader.ContentType == TLS_CONTENT_TYPE_ALERT ||
884 RecordHeader.ContentType == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC ||
885 RecordHeader.ContentType == TLS_CONTENT_TYPE_APPLICATION_DATA) &&
886 (RecordHeader.Version.Major == 0x03) && /// Major versions are same.
887 (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
888 RecordHeader.Version.Minor ==TLS11_PROTOCOL_VERSION_MINOR ||
889 RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
890 ) {
891 InsertTailList (NbufList, &PduHdr->List);
892 } else {
893 Status = EFI_PROTOCOL_ERROR;
894 goto ON_EXIT;
895 }
896
897 Len = SwapBytes16(RecordHeader.Length);
898 if (Len == 0) {
899 //
900 // No TLS payload.
901 //
902 goto FORM_PDU;
903 }
904
905 //
906 // Allocate buffer to receive one TLS payload.
907 //
908 DataSeg = NetbufAlloc (Len);
909 if (DataSeg == NULL) {
910 Status = EFI_OUT_OF_RESOURCES;
911 goto ON_EXIT;
912 }
913
914 NetbufAllocSpace (DataSeg, Len, NET_BUF_TAIL);
915
916 //
917 // Second step, receive one TLS payload.
918 //
919 Status = TlsCommonReceive (HttpInstance, DataSeg, Timeout);
920 if (EFI_ERROR (Status)) {
921 goto ON_EXIT;
922 }
923
924 InsertTailList (NbufList, &DataSeg->List);
925
926 FORM_PDU:
927 //
928 // Form the PDU from a list of PDU.
929 //
930 *Pdu = NetbufFromBufList (NbufList, 0, 0, FreeNbufList, NbufList);
931 if (*Pdu == NULL) {
932 Status = EFI_OUT_OF_RESOURCES;
933 }
934
935 ON_EXIT:
936
937 if (EFI_ERROR (Status)) {
938 //
939 // Free the Nbufs in this NbufList and the NbufList itself.
940 //
941 FreeNbufList (NbufList);
942 }
943
944 return Status;
945 }
946
947 /**
948 Connect one TLS session by finishing the TLS handshake process.
949
950 @param[in] HttpInstance The HTTP instance private data.
951 @param[in] Timeout The time to wait for connection done.
952
953 @retval EFI_SUCCESS The TLS session is established.
954 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
955 @retval EFI_ABORTED TLS session state is incorrect.
956 @retval Others Other error as indicated.
957
958 **/
959 EFI_STATUS
960 EFIAPI
961 TlsConnectSession (
962 IN HTTP_PROTOCOL *HttpInstance,
963 IN EFI_EVENT Timeout
964 )
965 {
966 EFI_STATUS Status;
967 UINT8 *BufferOut;
968 UINTN BufferOutSize;
969 NET_BUF *PacketOut;
970 UINT8 *DataOut;
971 NET_BUF *Pdu;
972 UINT8 *BufferIn;
973 UINTN BufferInSize;
974 UINT8 *GetSessionDataBuffer;
975 UINTN GetSessionDataBufferSize;
976
977 BufferOut = NULL;
978 PacketOut = NULL;
979 DataOut = NULL;
980 Pdu = NULL;
981 BufferIn = NULL;
982
983 //
984 // Initialize TLS state.
985 //
986 HttpInstance->TlsSessionState = EfiTlsSessionNotStarted;
987 Status = HttpInstance->Tls->SetSessionData (
988 HttpInstance->Tls,
989 EfiTlsSessionState,
990 &(HttpInstance->TlsSessionState),
991 sizeof (EFI_TLS_SESSION_STATE)
992 );
993 if (EFI_ERROR (Status)) {
994 return Status;
995 }
996
997 //
998 // Create ClientHello
999 //
1000 BufferOutSize = DEF_BUF_LEN;
1001 BufferOut = AllocateZeroPool (BufferOutSize);
1002 if (BufferOut == NULL) {
1003 Status = EFI_OUT_OF_RESOURCES;
1004 return Status;
1005 }
1006
1007 Status = HttpInstance->Tls->BuildResponsePacket (
1008 HttpInstance->Tls,
1009 NULL,
1010 0,
1011 BufferOut,
1012 &BufferOutSize
1013 );
1014 if (Status == EFI_BUFFER_TOO_SMALL) {
1015 FreePool (BufferOut);
1016 BufferOut = AllocateZeroPool (BufferOutSize);
1017 if (BufferOut == NULL) {
1018 Status = EFI_OUT_OF_RESOURCES;
1019 return Status;
1020 }
1021
1022 Status = HttpInstance->Tls->BuildResponsePacket (
1023 HttpInstance->Tls,
1024 NULL,
1025 0,
1026 BufferOut,
1027 &BufferOutSize
1028 );
1029 }
1030 if (EFI_ERROR (Status)) {
1031 FreePool (BufferOut);
1032 return Status;
1033 }
1034
1035 //
1036 // Transmit ClientHello
1037 //
1038 PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
1039 DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
1040 CopyMem (DataOut, BufferOut, BufferOutSize);
1041 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1042
1043 FreePool (BufferOut);
1044 NetbufFree (PacketOut);
1045
1046 if (EFI_ERROR (Status)) {
1047 return Status;
1048 }
1049
1050 while(HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring && \
1051 ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1052 //
1053 // Receive one TLS record.
1054 //
1055 Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
1056 if (EFI_ERROR (Status)) {
1057 return Status;
1058 }
1059
1060 BufferInSize = Pdu->TotalSize;
1061 BufferIn = AllocateZeroPool (BufferInSize);
1062 if (BufferIn == NULL) {
1063 NetbufFree (Pdu);
1064 Status = EFI_OUT_OF_RESOURCES;
1065 return Status;
1066 }
1067
1068 NetbufCopy (Pdu, 0, (UINT32)BufferInSize, BufferIn);
1069
1070 NetbufFree (Pdu);
1071
1072 //
1073 // Handle Receive data.
1074 //
1075 BufferOutSize = DEF_BUF_LEN;
1076 BufferOut = AllocateZeroPool (BufferOutSize);
1077 if (BufferOut == NULL) {
1078 Status = EFI_OUT_OF_RESOURCES;
1079 return Status;
1080 }
1081
1082 Status = HttpInstance->Tls->BuildResponsePacket (
1083 HttpInstance->Tls,
1084 BufferIn,
1085 BufferInSize,
1086 BufferOut,
1087 &BufferOutSize
1088 );
1089 if (Status == EFI_BUFFER_TOO_SMALL) {
1090 FreePool (BufferOut);
1091 BufferOut = AllocateZeroPool (BufferOutSize);
1092 if (BufferOut == NULL) {
1093 FreePool (BufferIn);
1094 Status = EFI_OUT_OF_RESOURCES;
1095 return Status;
1096 }
1097
1098 Status = HttpInstance->Tls->BuildResponsePacket (
1099 HttpInstance->Tls,
1100 BufferIn,
1101 BufferInSize,
1102 BufferOut,
1103 &BufferOutSize
1104 );
1105 }
1106
1107 FreePool (BufferIn);
1108
1109 if (EFI_ERROR (Status)) {
1110 return Status;
1111 }
1112
1113 if (BufferOutSize != 0) {
1114 //
1115 // Transmit the response packet.
1116 //
1117 PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
1118 DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
1119 CopyMem (DataOut, BufferOut, BufferOutSize);
1120
1121 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1122
1123 NetbufFree (PacketOut);
1124
1125 if (EFI_ERROR (Status)) {
1126 FreePool (BufferOut);
1127 return Status;
1128 }
1129 }
1130
1131 FreePool (BufferOut);
1132
1133 //
1134 // Get the session state, then decide whether need to continue handle received packet.
1135 //
1136 GetSessionDataBufferSize = DEF_BUF_LEN;
1137 GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1138 if (GetSessionDataBuffer == NULL) {
1139 Status = EFI_OUT_OF_RESOURCES;
1140 return Status;
1141 }
1142
1143 Status = HttpInstance->Tls->GetSessionData (
1144 HttpInstance->Tls,
1145 EfiTlsSessionState,
1146 GetSessionDataBuffer,
1147 &GetSessionDataBufferSize
1148 );
1149 if (Status == EFI_BUFFER_TOO_SMALL) {
1150 FreePool (GetSessionDataBuffer);
1151 GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1152 if (GetSessionDataBuffer == NULL) {
1153 Status = EFI_OUT_OF_RESOURCES;
1154 return Status;
1155 }
1156
1157 Status = HttpInstance->Tls->GetSessionData (
1158 HttpInstance->Tls,
1159 EfiTlsSessionState,
1160 GetSessionDataBuffer,
1161 &GetSessionDataBufferSize
1162 );
1163 }
1164 if (EFI_ERROR (Status)) {
1165 FreePool(GetSessionDataBuffer);
1166 return Status;
1167 }
1168
1169 ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
1170 HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;
1171
1172 FreePool (GetSessionDataBuffer);
1173
1174 if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
1175 return EFI_ABORTED;
1176 }
1177 }
1178
1179 if (HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring) {
1180 Status = EFI_ABORTED;
1181 }
1182
1183 return Status;
1184 }
1185
1186 /**
1187 Close the TLS session and send out the close notification message.
1188
1189 @param[in] HttpInstance The HTTP instance private data.
1190
1191 @retval EFI_SUCCESS The TLS session is closed.
1192 @retval EFI_INVALID_PARAMETER HttpInstance is NULL.
1193 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1194 @retval Others Other error as indicated.
1195
1196 **/
1197 EFI_STATUS
1198 EFIAPI
1199 TlsCloseSession (
1200 IN HTTP_PROTOCOL *HttpInstance
1201 )
1202 {
1203 EFI_STATUS Status;
1204
1205 UINT8 *BufferOut;
1206 UINTN BufferOutSize;
1207
1208 NET_BUF *PacketOut;
1209 UINT8 *DataOut;
1210
1211 Status = EFI_SUCCESS;
1212 BufferOut = NULL;
1213 PacketOut = NULL;
1214 DataOut = NULL;
1215
1216 if (HttpInstance == NULL) {
1217 return EFI_INVALID_PARAMETER;
1218 }
1219
1220 HttpInstance->TlsSessionState = EfiTlsSessionClosing;
1221
1222 Status = HttpInstance->Tls->SetSessionData (
1223 HttpInstance->Tls,
1224 EfiTlsSessionState,
1225 &(HttpInstance->TlsSessionState),
1226 sizeof (EFI_TLS_SESSION_STATE)
1227 );
1228 if (EFI_ERROR (Status)) {
1229 return Status;
1230 }
1231
1232 BufferOutSize = DEF_BUF_LEN;
1233 BufferOut = AllocateZeroPool (BufferOutSize);
1234 if (BufferOut == NULL) {
1235 Status = EFI_OUT_OF_RESOURCES;
1236 return Status;
1237 }
1238
1239 Status = HttpInstance->Tls->BuildResponsePacket (
1240 HttpInstance->Tls,
1241 NULL,
1242 0,
1243 BufferOut,
1244 &BufferOutSize
1245 );
1246 if (Status == EFI_BUFFER_TOO_SMALL) {
1247 FreePool (BufferOut);
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 }
1262
1263 if (EFI_ERROR (Status)) {
1264 FreePool (BufferOut);
1265 return Status;
1266 }
1267
1268 PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
1269 DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
1270 CopyMem (DataOut, BufferOut, BufferOutSize);
1271
1272 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1273
1274 FreePool (BufferOut);
1275 NetbufFree (PacketOut);
1276
1277 if (EFI_ERROR (Status)) {
1278 return Status;
1279 }
1280
1281 return Status;
1282 }
1283
1284 /**
1285 Process one message according to the CryptMode.
1286
1287 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
1288 @param[in] Message Pointer to the message buffer needed to processed.
1289 @param[in] MessageSize Pointer to the message buffer size.
1290 @param[in] ProcessMode Process mode.
1291 @param[in, out] Fragment Only one Fragment returned after the Message is
1292 processed successfully.
1293
1294 @retval EFI_SUCCESS Message is processed successfully.
1295 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1296 @retval Others Other errors as indicated.
1297
1298 **/
1299 EFI_STATUS
1300 EFIAPI
1301 TlsProcessMessage (
1302 IN HTTP_PROTOCOL *HttpInstance,
1303 IN UINT8 *Message,
1304 IN UINTN MessageSize,
1305 IN EFI_TLS_CRYPT_MODE ProcessMode,
1306 IN OUT NET_FRAGMENT *Fragment
1307 )
1308 {
1309 EFI_STATUS Status;
1310 UINT8 *Buffer;
1311 UINT32 BufferSize;
1312 UINT32 BytesCopied;
1313 EFI_TLS_FRAGMENT_DATA *FragmentTable;
1314 UINT32 FragmentCount;
1315 EFI_TLS_FRAGMENT_DATA *OriginalFragmentTable;
1316 UINTN Index;
1317
1318 Status = EFI_SUCCESS;
1319 Buffer = NULL;
1320 BufferSize = 0;
1321 BytesCopied = 0;
1322 FragmentTable = NULL;
1323 OriginalFragmentTable = NULL;
1324
1325 //
1326 // Rebuild fragment table from BufferIn.
1327 //
1328 FragmentCount = 1;
1329 FragmentTable = AllocateZeroPool (FragmentCount * sizeof (EFI_TLS_FRAGMENT_DATA));
1330 if (FragmentTable == NULL) {
1331 Status = EFI_OUT_OF_RESOURCES;
1332 goto ON_EXIT;
1333 }
1334
1335 FragmentTable->FragmentLength = (UINT32) MessageSize;
1336 FragmentTable->FragmentBuffer = Message;
1337
1338 //
1339 // Record the original FragmentTable.
1340 //
1341 OriginalFragmentTable = FragmentTable;
1342
1343 //
1344 // Process the Message.
1345 //
1346 Status = HttpInstance->Tls->ProcessPacket (
1347 HttpInstance->Tls,
1348 &FragmentTable,
1349 &FragmentCount,
1350 ProcessMode
1351 );
1352 if (EFI_ERROR (Status)) {
1353 goto ON_EXIT;
1354 }
1355
1356 //
1357 // Calculate the size according to FragmentTable.
1358 //
1359 for (Index = 0; Index < FragmentCount; Index++) {
1360 BufferSize += FragmentTable[Index].FragmentLength;
1361 }
1362
1363 //
1364 // Allocate buffer for processed data.
1365 //
1366 Buffer = AllocateZeroPool (BufferSize);
1367 if (Buffer == NULL) {
1368 Status = EFI_OUT_OF_RESOURCES;
1369 goto ON_EXIT;
1370 }
1371
1372 //
1373 // Copy the new FragmentTable buffer into Buffer.
1374 //
1375 for (Index = 0; Index < FragmentCount; Index++) {
1376 CopyMem (
1377 (Buffer + BytesCopied),
1378 FragmentTable[Index].FragmentBuffer,
1379 FragmentTable[Index].FragmentLength
1380 );
1381 BytesCopied += FragmentTable[Index].FragmentLength;
1382
1383 //
1384 // Free the FragmentBuffer since it has been copied.
1385 //
1386 FreePool (FragmentTable[Index].FragmentBuffer);
1387 }
1388
1389 Fragment->Len = BufferSize;
1390 Fragment->Bulk = Buffer;
1391
1392 ON_EXIT:
1393
1394 if (OriginalFragmentTable != NULL) {
1395 FreePool (OriginalFragmentTable);
1396 OriginalFragmentTable = NULL;
1397 }
1398
1399 //
1400 // Caller has the responsibility to free the FragmentTable.
1401 //
1402 if (FragmentTable != NULL) {
1403 FreePool (FragmentTable);
1404 FragmentTable = NULL;
1405 }
1406
1407 return Status;
1408 }
1409
1410 /**
1411 Receive one fragment decrypted from one TLS record.
1412
1413 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
1414 @param[in, out] Fragment The received Fragment.
1415 @param[in] Timeout The time to wait for connection done.
1416
1417 @retval EFI_SUCCESS One fragment is received.
1418 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1419 @retval EFI_ABORTED Something wrong decryption the message.
1420 @retval Others Other errors as indicated.
1421
1422 **/
1423 EFI_STATUS
1424 EFIAPI
1425 HttpsReceive (
1426 IN HTTP_PROTOCOL *HttpInstance,
1427 IN OUT NET_FRAGMENT *Fragment,
1428 IN EFI_EVENT Timeout
1429 )
1430 {
1431 EFI_STATUS Status;
1432 NET_BUF *Pdu;
1433 TLS_RECORD_HEADER RecordHeader;
1434 UINT8 *BufferIn;
1435 UINTN BufferInSize;
1436 NET_FRAGMENT TempFragment;
1437 UINT8 *BufferOut;
1438 UINTN BufferOutSize;
1439 NET_BUF *PacketOut;
1440 UINT8 *DataOut;
1441 UINT8 *GetSessionDataBuffer;
1442 UINTN GetSessionDataBufferSize;
1443
1444 Status = EFI_SUCCESS;
1445 Pdu = NULL;
1446 BufferIn = NULL;
1447 BufferInSize = 0;
1448 BufferOut = NULL;
1449 BufferOutSize = 0;
1450 PacketOut = NULL;
1451 DataOut = NULL;
1452 GetSessionDataBuffer = NULL;
1453 GetSessionDataBufferSize = 0;
1454
1455 //
1456 // Receive only one TLS record
1457 //
1458 Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
1459 if (EFI_ERROR (Status)) {
1460 return Status;
1461 }
1462
1463 BufferInSize = Pdu->TotalSize;
1464 BufferIn = AllocateZeroPool (BufferInSize);
1465 if (BufferIn == NULL) {
1466 Status = EFI_OUT_OF_RESOURCES;
1467 NetbufFree (Pdu);
1468 return Status;
1469 }
1470
1471 NetbufCopy (Pdu, 0, (UINT32) BufferInSize, BufferIn);
1472
1473 NetbufFree (Pdu);
1474
1475 //
1476 // Handle Receive data.
1477 //
1478 RecordHeader = *(TLS_RECORD_HEADER *) BufferIn;
1479
1480 if ((RecordHeader.ContentType == TLS_CONTENT_TYPE_APPLICATION_DATA) &&
1481 (RecordHeader.Version.Major == 0x03) &&
1482 (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
1483 RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
1484 RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
1485 ) {
1486 //
1487 // Decrypt Packet.
1488 //
1489 Status = TlsProcessMessage (
1490 HttpInstance,
1491 BufferIn,
1492 BufferInSize,
1493 EfiTlsDecrypt,
1494 &TempFragment
1495 );
1496
1497 FreePool (BufferIn);
1498
1499 if (EFI_ERROR (Status)) {
1500 if (Status == EFI_ABORTED) {
1501 //
1502 // Something wrong decryption the message.
1503 // BuildResponsePacket() will be called to generate Error Alert message and send it out.
1504 //
1505 BufferOutSize = DEF_BUF_LEN;
1506 BufferOut = AllocateZeroPool (BufferOutSize);
1507 if (BufferOut == NULL) {
1508 Status = EFI_OUT_OF_RESOURCES;
1509 return Status;
1510 }
1511
1512 Status = HttpInstance->Tls->BuildResponsePacket (
1513 HttpInstance->Tls,
1514 NULL,
1515 0,
1516 BufferOut,
1517 &BufferOutSize
1518 );
1519 if (Status == EFI_BUFFER_TOO_SMALL) {
1520 FreePool (BufferOut);
1521 BufferOut = AllocateZeroPool (BufferOutSize);
1522 if (BufferOut == NULL) {
1523 Status = EFI_OUT_OF_RESOURCES;
1524 return Status;
1525 }
1526
1527 Status = HttpInstance->Tls->BuildResponsePacket (
1528 HttpInstance->Tls,
1529 NULL,
1530 0,
1531 BufferOut,
1532 &BufferOutSize
1533 );
1534 }
1535 if (EFI_ERROR (Status)) {
1536 FreePool(BufferOut);
1537 return Status;
1538 }
1539
1540 if (BufferOutSize != 0) {
1541 PacketOut = NetbufAlloc ((UINT32)BufferOutSize);
1542 DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
1543 CopyMem (DataOut, BufferOut, BufferOutSize);
1544
1545 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1546
1547 NetbufFree (PacketOut);
1548 }
1549
1550 FreePool(BufferOut);
1551
1552 if (EFI_ERROR (Status)) {
1553 return Status;
1554 }
1555
1556 return EFI_ABORTED;
1557 }
1558
1559 return Status;
1560 }
1561
1562 //
1563 // Parsing buffer.
1564 //
1565 ASSERT (((TLS_RECORD_HEADER *) (TempFragment.Bulk))->ContentType == TLS_CONTENT_TYPE_APPLICATION_DATA);
1566
1567 BufferInSize = ((TLS_RECORD_HEADER *) (TempFragment.Bulk))->Length;
1568 BufferIn = AllocateZeroPool (BufferInSize);
1569 if (BufferIn == NULL) {
1570 Status = EFI_OUT_OF_RESOURCES;
1571 return Status;
1572 }
1573
1574 CopyMem (BufferIn, TempFragment.Bulk + sizeof (TLS_RECORD_HEADER), BufferInSize);
1575
1576 //
1577 // Free the buffer in TempFragment.
1578 //
1579 FreePool (TempFragment.Bulk);
1580
1581 } else if ((RecordHeader.ContentType == TLS_CONTENT_TYPE_ALERT) &&
1582 (RecordHeader.Version.Major == 0x03) &&
1583 (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
1584 RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
1585 RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
1586 ) {
1587 BufferOutSize = DEF_BUF_LEN;
1588 BufferOut = AllocateZeroPool (BufferOutSize);
1589 if (BufferOut == NULL) {
1590 FreePool (BufferIn);
1591 Status = EFI_OUT_OF_RESOURCES;
1592 return Status;
1593 }
1594
1595 Status = HttpInstance->Tls->BuildResponsePacket (
1596 HttpInstance->Tls,
1597 BufferIn,
1598 BufferInSize,
1599 BufferOut,
1600 &BufferOutSize
1601 );
1602 if (Status == EFI_BUFFER_TOO_SMALL) {
1603 FreePool (BufferOut);
1604 BufferOut = AllocateZeroPool (BufferOutSize);
1605 if (BufferOut == NULL) {
1606 FreePool (BufferIn);
1607 Status = EFI_OUT_OF_RESOURCES;
1608 return Status;
1609 }
1610
1611 Status = HttpInstance->Tls->BuildResponsePacket (
1612 HttpInstance->Tls,
1613 BufferIn,
1614 BufferInSize,
1615 BufferOut,
1616 &BufferOutSize
1617 );
1618 }
1619
1620 FreePool (BufferIn);
1621
1622 if (EFI_ERROR (Status)) {
1623 FreePool (BufferOut);
1624 return Status;
1625 }
1626
1627 if (BufferOutSize != 0) {
1628 PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
1629 DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
1630 CopyMem (DataOut, BufferOut, BufferOutSize);
1631
1632 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1633
1634 NetbufFree (PacketOut);
1635 }
1636
1637 FreePool (BufferOut);
1638
1639 //
1640 // Get the session state.
1641 //
1642 GetSessionDataBufferSize = DEF_BUF_LEN;
1643 GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1644 if (GetSessionDataBuffer == NULL) {
1645 Status = EFI_OUT_OF_RESOURCES;
1646 return Status;
1647 }
1648
1649 Status = HttpInstance->Tls->GetSessionData (
1650 HttpInstance->Tls,
1651 EfiTlsSessionState,
1652 GetSessionDataBuffer,
1653 &GetSessionDataBufferSize
1654 );
1655 if (Status == EFI_BUFFER_TOO_SMALL) {
1656 FreePool (GetSessionDataBuffer);
1657 GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1658 if (GetSessionDataBuffer == NULL) {
1659 Status = EFI_OUT_OF_RESOURCES;
1660 return Status;
1661 }
1662
1663 Status = HttpInstance->Tls->GetSessionData (
1664 HttpInstance->Tls,
1665 EfiTlsSessionState,
1666 GetSessionDataBuffer,
1667 &GetSessionDataBufferSize
1668 );
1669 }
1670 if (EFI_ERROR (Status)) {
1671 FreePool (GetSessionDataBuffer);
1672 return Status;
1673 }
1674
1675 ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
1676 HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;
1677
1678 FreePool (GetSessionDataBuffer);
1679
1680 if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
1681 DEBUG ((EFI_D_ERROR, "TLS Session State Error!\n"));
1682 return EFI_ABORTED;
1683 }
1684
1685 BufferIn = NULL;
1686 BufferInSize = 0;
1687 }
1688
1689 Fragment->Bulk = BufferIn;
1690 Fragment->Len = (UINT32) BufferInSize;
1691
1692 return Status;
1693 }