]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/HttpDxe/HttpsSupport.c
NetworkPkg/HttpDxe: Fix the potential NULL dereference
[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 (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 == TLS_CONTENT_TYPE_HANDSHAKE ||
887 RecordHeader.ContentType == TLS_CONTENT_TYPE_ALERT ||
888 RecordHeader.ContentType == TLS_CONTENT_TYPE_CHANGE_CIPHER_SPEC ||
889 RecordHeader.ContentType == TLS_CONTENT_TYPE_APPLICATION_DATA) &&
890 (RecordHeader.Version.Major == 0x03) && /// Major versions are same.
891 (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
892 RecordHeader.Version.Minor ==TLS11_PROTOCOL_VERSION_MINOR ||
893 RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
894 ) {
895 InsertTailList (NbufList, &PduHdr->List);
896 } else {
897 Status = EFI_PROTOCOL_ERROR;
898 goto ON_EXIT;
899 }
900
901 Len = SwapBytes16(RecordHeader.Length);
902 if (Len == 0) {
903 //
904 // No TLS payload.
905 //
906 goto FORM_PDU;
907 }
908
909 //
910 // Allocate buffer to receive one TLS payload.
911 //
912 DataSeg = NetbufAlloc (Len);
913 if (DataSeg == NULL) {
914 Status = EFI_OUT_OF_RESOURCES;
915 goto ON_EXIT;
916 }
917
918 NetbufAllocSpace (DataSeg, Len, NET_BUF_TAIL);
919
920 //
921 // Second step, receive one TLS payload.
922 //
923 Status = TlsCommonReceive (HttpInstance, DataSeg, Timeout);
924 if (EFI_ERROR (Status)) {
925 goto ON_EXIT;
926 }
927
928 InsertTailList (NbufList, &DataSeg->List);
929
930 FORM_PDU:
931 //
932 // Form the PDU from a list of PDU.
933 //
934 *Pdu = NetbufFromBufList (NbufList, 0, 0, FreeNbufList, NbufList);
935 if (*Pdu == NULL) {
936 Status = EFI_OUT_OF_RESOURCES;
937 }
938
939 ON_EXIT:
940
941 if (EFI_ERROR (Status)) {
942 //
943 // Free the Nbufs in this NbufList and the NbufList itself.
944 //
945 FreeNbufList (NbufList);
946 }
947
948 return Status;
949 }
950
951 /**
952 Connect one TLS session by finishing the TLS handshake process.
953
954 @param[in] HttpInstance The HTTP instance private data.
955 @param[in] Timeout The time to wait for connection done.
956
957 @retval EFI_SUCCESS The TLS session is established.
958 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
959 @retval EFI_ABORTED TLS session state is incorrect.
960 @retval Others Other error as indicated.
961
962 **/
963 EFI_STATUS
964 EFIAPI
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 if (EFI_ERROR (Status)) {
1298 return Status;
1299 }
1300
1301 return Status;
1302 }
1303
1304 /**
1305 Process one message according to the CryptMode.
1306
1307 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
1308 @param[in] Message Pointer to the message buffer needed to processed.
1309 @param[in] MessageSize Pointer to the message buffer size.
1310 @param[in] ProcessMode Process mode.
1311 @param[in, out] Fragment Only one Fragment returned after the Message is
1312 processed successfully.
1313
1314 @retval EFI_SUCCESS Message is processed successfully.
1315 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1316 @retval Others Other errors as indicated.
1317
1318 **/
1319 EFI_STATUS
1320 EFIAPI
1321 TlsProcessMessage (
1322 IN HTTP_PROTOCOL *HttpInstance,
1323 IN UINT8 *Message,
1324 IN UINTN MessageSize,
1325 IN EFI_TLS_CRYPT_MODE ProcessMode,
1326 IN OUT NET_FRAGMENT *Fragment
1327 )
1328 {
1329 EFI_STATUS Status;
1330 UINT8 *Buffer;
1331 UINT32 BufferSize;
1332 UINT32 BytesCopied;
1333 EFI_TLS_FRAGMENT_DATA *FragmentTable;
1334 UINT32 FragmentCount;
1335 EFI_TLS_FRAGMENT_DATA *OriginalFragmentTable;
1336 UINTN Index;
1337
1338 Status = EFI_SUCCESS;
1339 Buffer = NULL;
1340 BufferSize = 0;
1341 BytesCopied = 0;
1342 FragmentTable = NULL;
1343 OriginalFragmentTable = NULL;
1344
1345 //
1346 // Rebuild fragment table from BufferIn.
1347 //
1348 FragmentCount = 1;
1349 FragmentTable = AllocateZeroPool (FragmentCount * sizeof (EFI_TLS_FRAGMENT_DATA));
1350 if (FragmentTable == NULL) {
1351 Status = EFI_OUT_OF_RESOURCES;
1352 goto ON_EXIT;
1353 }
1354
1355 FragmentTable->FragmentLength = (UINT32) MessageSize;
1356 FragmentTable->FragmentBuffer = Message;
1357
1358 //
1359 // Record the original FragmentTable.
1360 //
1361 OriginalFragmentTable = FragmentTable;
1362
1363 //
1364 // Process the Message.
1365 //
1366 Status = HttpInstance->Tls->ProcessPacket (
1367 HttpInstance->Tls,
1368 &FragmentTable,
1369 &FragmentCount,
1370 ProcessMode
1371 );
1372 if (EFI_ERROR (Status)) {
1373 goto ON_EXIT;
1374 }
1375
1376 //
1377 // Calculate the size according to FragmentTable.
1378 //
1379 for (Index = 0; Index < FragmentCount; Index++) {
1380 BufferSize += FragmentTable[Index].FragmentLength;
1381 }
1382
1383 //
1384 // Allocate buffer for processed data.
1385 //
1386 Buffer = AllocateZeroPool (BufferSize);
1387 if (Buffer == NULL) {
1388 Status = EFI_OUT_OF_RESOURCES;
1389 goto ON_EXIT;
1390 }
1391
1392 //
1393 // Copy the new FragmentTable buffer into Buffer.
1394 //
1395 for (Index = 0; Index < FragmentCount; Index++) {
1396 CopyMem (
1397 (Buffer + BytesCopied),
1398 FragmentTable[Index].FragmentBuffer,
1399 FragmentTable[Index].FragmentLength
1400 );
1401 BytesCopied += FragmentTable[Index].FragmentLength;
1402
1403 //
1404 // Free the FragmentBuffer since it has been copied.
1405 //
1406 FreePool (FragmentTable[Index].FragmentBuffer);
1407 }
1408
1409 Fragment->Len = BufferSize;
1410 Fragment->Bulk = Buffer;
1411
1412 ON_EXIT:
1413
1414 if (OriginalFragmentTable != NULL) {
1415 FreePool (OriginalFragmentTable);
1416 OriginalFragmentTable = NULL;
1417 }
1418
1419 //
1420 // Caller has the responsibility to free the FragmentTable.
1421 //
1422 if (FragmentTable != NULL) {
1423 FreePool (FragmentTable);
1424 FragmentTable = NULL;
1425 }
1426
1427 return Status;
1428 }
1429
1430 /**
1431 Receive one fragment decrypted from one TLS record.
1432
1433 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
1434 @param[in, out] Fragment The received Fragment.
1435 @param[in] Timeout The time to wait for connection done.
1436
1437 @retval EFI_SUCCESS One fragment is received.
1438 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1439 @retval EFI_ABORTED Something wrong decryption the message.
1440 @retval Others Other errors as indicated.
1441
1442 **/
1443 EFI_STATUS
1444 EFIAPI
1445 HttpsReceive (
1446 IN HTTP_PROTOCOL *HttpInstance,
1447 IN OUT NET_FRAGMENT *Fragment,
1448 IN EFI_EVENT Timeout
1449 )
1450 {
1451 EFI_STATUS Status;
1452 NET_BUF *Pdu;
1453 TLS_RECORD_HEADER RecordHeader;
1454 UINT8 *BufferIn;
1455 UINTN BufferInSize;
1456 NET_FRAGMENT TempFragment;
1457 UINT8 *BufferOut;
1458 UINTN BufferOutSize;
1459 NET_BUF *PacketOut;
1460 UINT8 *DataOut;
1461 UINT8 *GetSessionDataBuffer;
1462 UINTN GetSessionDataBufferSize;
1463
1464 Status = EFI_SUCCESS;
1465 Pdu = NULL;
1466 BufferIn = NULL;
1467 BufferInSize = 0;
1468 BufferOut = NULL;
1469 BufferOutSize = 0;
1470 PacketOut = NULL;
1471 DataOut = NULL;
1472 GetSessionDataBuffer = NULL;
1473 GetSessionDataBufferSize = 0;
1474
1475 //
1476 // Receive only one TLS record
1477 //
1478 Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
1479 if (EFI_ERROR (Status)) {
1480 return Status;
1481 }
1482
1483 BufferInSize = Pdu->TotalSize;
1484 BufferIn = AllocateZeroPool (BufferInSize);
1485 if (BufferIn == NULL) {
1486 Status = EFI_OUT_OF_RESOURCES;
1487 NetbufFree (Pdu);
1488 return Status;
1489 }
1490
1491 NetbufCopy (Pdu, 0, (UINT32) BufferInSize, BufferIn);
1492
1493 NetbufFree (Pdu);
1494
1495 //
1496 // Handle Receive data.
1497 //
1498 RecordHeader = *(TLS_RECORD_HEADER *) BufferIn;
1499
1500 if ((RecordHeader.ContentType == TLS_CONTENT_TYPE_APPLICATION_DATA) &&
1501 (RecordHeader.Version.Major == 0x03) &&
1502 (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
1503 RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
1504 RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
1505 ) {
1506 //
1507 // Decrypt Packet.
1508 //
1509 Status = TlsProcessMessage (
1510 HttpInstance,
1511 BufferIn,
1512 BufferInSize,
1513 EfiTlsDecrypt,
1514 &TempFragment
1515 );
1516
1517 FreePool (BufferIn);
1518
1519 if (EFI_ERROR (Status)) {
1520 if (Status == EFI_ABORTED) {
1521 //
1522 // Something wrong decryption the message.
1523 // BuildResponsePacket() will be called to generate Error Alert message and send it out.
1524 //
1525 BufferOutSize = DEF_BUF_LEN;
1526 BufferOut = AllocateZeroPool (BufferOutSize);
1527 if (BufferOut == NULL) {
1528 Status = EFI_OUT_OF_RESOURCES;
1529 return Status;
1530 }
1531
1532 Status = HttpInstance->Tls->BuildResponsePacket (
1533 HttpInstance->Tls,
1534 NULL,
1535 0,
1536 BufferOut,
1537 &BufferOutSize
1538 );
1539 if (Status == EFI_BUFFER_TOO_SMALL) {
1540 FreePool (BufferOut);
1541 BufferOut = AllocateZeroPool (BufferOutSize);
1542 if (BufferOut == NULL) {
1543 Status = EFI_OUT_OF_RESOURCES;
1544 return Status;
1545 }
1546
1547 Status = HttpInstance->Tls->BuildResponsePacket (
1548 HttpInstance->Tls,
1549 NULL,
1550 0,
1551 BufferOut,
1552 &BufferOutSize
1553 );
1554 }
1555 if (EFI_ERROR (Status)) {
1556 FreePool(BufferOut);
1557 return Status;
1558 }
1559
1560 if (BufferOutSize != 0) {
1561 PacketOut = NetbufAlloc ((UINT32)BufferOutSize);
1562 DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
1563 if (DataOut == NULL) {
1564 FreePool (BufferOut);
1565 return EFI_OUT_OF_RESOURCES;
1566 }
1567
1568 CopyMem (DataOut, BufferOut, BufferOutSize);
1569
1570 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1571
1572 NetbufFree (PacketOut);
1573 }
1574
1575 FreePool(BufferOut);
1576
1577 if (EFI_ERROR (Status)) {
1578 return Status;
1579 }
1580
1581 return EFI_ABORTED;
1582 }
1583
1584 return Status;
1585 }
1586
1587 //
1588 // Parsing buffer.
1589 //
1590 ASSERT (((TLS_RECORD_HEADER *) (TempFragment.Bulk))->ContentType == TLS_CONTENT_TYPE_APPLICATION_DATA);
1591
1592 BufferInSize = ((TLS_RECORD_HEADER *) (TempFragment.Bulk))->Length;
1593 BufferIn = AllocateZeroPool (BufferInSize);
1594 if (BufferIn == NULL) {
1595 Status = EFI_OUT_OF_RESOURCES;
1596 return Status;
1597 }
1598
1599 CopyMem (BufferIn, TempFragment.Bulk + sizeof (TLS_RECORD_HEADER), BufferInSize);
1600
1601 //
1602 // Free the buffer in TempFragment.
1603 //
1604 FreePool (TempFragment.Bulk);
1605
1606 } else if ((RecordHeader.ContentType == TLS_CONTENT_TYPE_ALERT) &&
1607 (RecordHeader.Version.Major == 0x03) &&
1608 (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
1609 RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
1610 RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
1611 ) {
1612 BufferOutSize = DEF_BUF_LEN;
1613 BufferOut = AllocateZeroPool (BufferOutSize);
1614 if (BufferOut == NULL) {
1615 FreePool (BufferIn);
1616 Status = EFI_OUT_OF_RESOURCES;
1617 return Status;
1618 }
1619
1620 Status = HttpInstance->Tls->BuildResponsePacket (
1621 HttpInstance->Tls,
1622 BufferIn,
1623 BufferInSize,
1624 BufferOut,
1625 &BufferOutSize
1626 );
1627 if (Status == EFI_BUFFER_TOO_SMALL) {
1628 FreePool (BufferOut);
1629 BufferOut = AllocateZeroPool (BufferOutSize);
1630 if (BufferOut == NULL) {
1631 FreePool (BufferIn);
1632 Status = EFI_OUT_OF_RESOURCES;
1633 return Status;
1634 }
1635
1636 Status = HttpInstance->Tls->BuildResponsePacket (
1637 HttpInstance->Tls,
1638 BufferIn,
1639 BufferInSize,
1640 BufferOut,
1641 &BufferOutSize
1642 );
1643 }
1644
1645 FreePool (BufferIn);
1646
1647 if (EFI_ERROR (Status)) {
1648 FreePool (BufferOut);
1649 return Status;
1650 }
1651
1652 if (BufferOutSize != 0) {
1653 PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
1654 DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
1655 if (DataOut == NULL) {
1656 FreePool (BufferOut);
1657 return EFI_OUT_OF_RESOURCES;
1658 }
1659
1660 CopyMem (DataOut, BufferOut, BufferOutSize);
1661
1662 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1663
1664 NetbufFree (PacketOut);
1665 }
1666
1667 FreePool (BufferOut);
1668
1669 //
1670 // Get the session state.
1671 //
1672 GetSessionDataBufferSize = DEF_BUF_LEN;
1673 GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1674 if (GetSessionDataBuffer == NULL) {
1675 Status = EFI_OUT_OF_RESOURCES;
1676 return Status;
1677 }
1678
1679 Status = HttpInstance->Tls->GetSessionData (
1680 HttpInstance->Tls,
1681 EfiTlsSessionState,
1682 GetSessionDataBuffer,
1683 &GetSessionDataBufferSize
1684 );
1685 if (Status == EFI_BUFFER_TOO_SMALL) {
1686 FreePool (GetSessionDataBuffer);
1687 GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1688 if (GetSessionDataBuffer == NULL) {
1689 Status = EFI_OUT_OF_RESOURCES;
1690 return Status;
1691 }
1692
1693 Status = HttpInstance->Tls->GetSessionData (
1694 HttpInstance->Tls,
1695 EfiTlsSessionState,
1696 GetSessionDataBuffer,
1697 &GetSessionDataBufferSize
1698 );
1699 }
1700 if (EFI_ERROR (Status)) {
1701 FreePool (GetSessionDataBuffer);
1702 return Status;
1703 }
1704
1705 ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
1706 HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;
1707
1708 FreePool (GetSessionDataBuffer);
1709
1710 if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
1711 DEBUG ((EFI_D_ERROR, "TLS Session State Error!\n"));
1712 return EFI_ABORTED;
1713 }
1714
1715 BufferIn = NULL;
1716 BufferInSize = 0;
1717 }
1718
1719 Fragment->Bulk = BufferIn;
1720 Fragment->Len = (UINT32) BufferInSize;
1721
1722 return Status;
1723 }