]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/HttpDxe/HttpsSupport.c
NetworkPkg: Read HttpTlsCipherList variable and configure it for HTTPS session.
[mirror_edk2.git] / NetworkPkg / HttpDxe / HttpsSupport.c
1 /** @file
2 Miscellaneous routines specific to Https for HttpDxe driver.
3
4 Copyright (c) 2016 - 2018, 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] TlsSb Pointer to the TLS SERVICE_BINDING_PROTOCOL.
144 @param[out] TlsProto Pointer to the EFI_TLS_PROTOCOL instance.
145 @param[out] TlsConfiguration Pointer to the EFI_TLS_CONFIGURATION_PROTOCOL instance.
146
147 @return The child handle with opened EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
148
149 **/
150 EFI_HANDLE
151 EFIAPI
152 TlsCreateChild (
153 IN EFI_HANDLE ImageHandle,
154 OUT EFI_SERVICE_BINDING_PROTOCOL **TlsSb,
155 OUT EFI_TLS_PROTOCOL **TlsProto,
156 OUT EFI_TLS_CONFIGURATION_PROTOCOL **TlsConfiguration
157 )
158 {
159 EFI_STATUS Status;
160 EFI_HANDLE TlsChildHandle;
161
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 Read the HttpTlsCipherList variable and configure it for HTTPS session.
471
472 @param[in, out] HttpInstance The HTTP instance private data.
473
474 @retval EFI_SUCCESS The prefered HTTP TLS CipherList is configured.
475 @retval EFI_NOT_FOUND Fail to get 'HttpTlsCipherList' variable.
476 @retval EFI_INVALID_PARAMETER The contents of variable are invalid.
477 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
478
479 @retval Others Other error as indicated.
480
481 **/
482 EFI_STATUS
483 TlsConfigCipherList (
484 IN OUT HTTP_PROTOCOL *HttpInstance
485 )
486 {
487 EFI_STATUS Status;
488 UINT8 *CipherList;
489 UINTN CipherListSize;
490
491 CipherList = NULL;
492 CipherListSize = 0;
493
494 //
495 // Try to read the HttpTlsCipherList variable.
496 //
497 Status = gRT->GetVariable (
498 EDKII_HTTP_TLS_CIPHER_LIST_VARIABLE,
499 &gEdkiiHttpTlsCipherListGuid,
500 NULL,
501 &CipherListSize,
502 NULL
503 );
504 ASSERT (EFI_ERROR (Status));
505 if (Status != EFI_BUFFER_TOO_SMALL) {
506 return Status;
507 }
508
509 if (CipherListSize % sizeof (EFI_TLS_CIPHER) != 0) {
510 return EFI_INVALID_PARAMETER;
511 }
512
513 //
514 // Allocate buffer and read the config variable.
515 //
516 CipherList = AllocatePool (CipherListSize);
517 if (CipherList == NULL) {
518 return EFI_OUT_OF_RESOURCES;
519 }
520
521 Status = gRT->GetVariable (
522 EDKII_HTTP_TLS_CIPHER_LIST_VARIABLE,
523 &gEdkiiHttpTlsCipherListGuid,
524 NULL,
525 &CipherListSize,
526 CipherList
527 );
528 if (EFI_ERROR (Status)) {
529 //
530 // GetVariable still error or the variable is corrupted.
531 //
532 goto ON_EXIT;
533 }
534
535 ASSERT (CipherList != NULL);
536
537 Status = HttpInstance->Tls->SetSessionData (
538 HttpInstance->Tls,
539 EfiTlsCipherList,
540 CipherList,
541 CipherListSize
542 );
543
544 ON_EXIT:
545 FreePool (CipherList);
546
547 return Status;
548 }
549
550 /**
551 Configure TLS session data.
552
553 @param[in, out] HttpInstance The HTTP instance private data.
554
555 @retval EFI_SUCCESS TLS session data is configured.
556 @retval Others Other error as indicated.
557
558 **/
559 EFI_STATUS
560 EFIAPI
561 TlsConfigureSession (
562 IN OUT HTTP_PROTOCOL *HttpInstance
563 )
564 {
565 EFI_STATUS Status;
566
567 //
568 // TlsConfigData initialization
569 //
570 HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient;
571 HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER;
572 HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted;
573
574 //
575 // EfiTlsConnectionEnd,
576 // EfiTlsVerifyMethod
577 // EfiTlsSessionState
578 //
579 Status = HttpInstance->Tls->SetSessionData (
580 HttpInstance->Tls,
581 EfiTlsConnectionEnd,
582 &(HttpInstance->TlsConfigData.ConnectionEnd),
583 sizeof (EFI_TLS_CONNECTION_END)
584 );
585 if (EFI_ERROR (Status)) {
586 return Status;
587 }
588
589 Status = HttpInstance->Tls->SetSessionData (
590 HttpInstance->Tls,
591 EfiTlsVerifyMethod,
592 &HttpInstance->TlsConfigData.VerifyMethod,
593 sizeof (EFI_TLS_VERIFY)
594 );
595 if (EFI_ERROR (Status)) {
596 return Status;
597 }
598
599 Status = HttpInstance->Tls->SetSessionData (
600 HttpInstance->Tls,
601 EfiTlsSessionState,
602 &(HttpInstance->TlsConfigData.SessionState),
603 sizeof (EFI_TLS_SESSION_STATE)
604 );
605 if (EFI_ERROR (Status)) {
606 return Status;
607 }
608
609 //
610 // Tls Cipher List
611 //
612 Status = TlsConfigCipherList (HttpInstance);
613 if (EFI_ERROR (Status) && Status != EFI_NOT_FOUND) {
614 DEBUG ((EFI_D_ERROR, "TlsConfigCipherList: return %r error.\n", Status));
615 return Status;
616 }
617
618 //
619 // Tls Config Certificate
620 //
621 Status = TlsConfigCertificate (HttpInstance);
622 if (EFI_ERROR (Status)) {
623 DEBUG ((EFI_D_ERROR, "TLS Certificate Config Error!\n"));
624 return Status;
625 }
626
627 //
628 // TlsCreateTxRxEvent
629 //
630 Status = TlsCreateTxRxEvent (HttpInstance);
631 if (EFI_ERROR (Status)) {
632 goto ERROR;
633 }
634
635 return Status;
636
637 ERROR:
638 TlsCloseTxRxEvent (HttpInstance);
639
640 return Status;
641 }
642
643 /**
644 Transmit the Packet by processing the associated HTTPS token.
645
646 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
647 @param[in] Packet The packet to transmit.
648
649 @retval EFI_SUCCESS The packet is transmitted.
650 @retval EFI_INVALID_PARAMETER HttpInstance is NULL or Packet is NULL.
651 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
652 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
653 @retval Others Other errors as indicated.
654
655 **/
656 EFI_STATUS
657 EFIAPI
658 TlsCommonTransmit (
659 IN OUT HTTP_PROTOCOL *HttpInstance,
660 IN NET_BUF *Packet
661 )
662 {
663 EFI_STATUS Status;
664 VOID *Data;
665 UINTN Size;
666
667 if ((HttpInstance == NULL) || (Packet == NULL)) {
668 return EFI_INVALID_PARAMETER;
669 }
670
671 if (!HttpInstance->LocalAddressIsIPv6) {
672 Size = sizeof (EFI_TCP4_TRANSMIT_DATA) +
673 (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA);
674 } else {
675 Size = sizeof (EFI_TCP6_TRANSMIT_DATA) +
676 (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA);
677 }
678
679 Data = AllocatePool (Size);
680 if (Data == NULL) {
681 return EFI_OUT_OF_RESOURCES;
682 }
683
684 if (!HttpInstance->LocalAddressIsIPv6) {
685 ((EFI_TCP4_TRANSMIT_DATA *) Data)->Push = TRUE;
686 ((EFI_TCP4_TRANSMIT_DATA *) Data)->Urgent = FALSE;
687 ((EFI_TCP4_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
688
689 //
690 // Build the fragment table.
691 //
692 ((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
693
694 NetbufBuildExt (
695 Packet,
696 (NET_FRAGMENT *) &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentTable[0],
697 &((EFI_TCP4_TRANSMIT_DATA *) Data)->FragmentCount
698 );
699
700 HttpInstance->Tcp4TlsTxToken.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *) Data;
701
702 Status = EFI_DEVICE_ERROR;
703
704 //
705 // Transmit the packet.
706 //
707 Status = HttpInstance->Tcp4->Transmit (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsTxToken);
708 if (EFI_ERROR (Status)) {
709 goto ON_EXIT;
710 }
711
712 while (!HttpInstance->TlsIsTxDone) {
713 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
714 }
715
716 HttpInstance->TlsIsTxDone = FALSE;
717 Status = HttpInstance->Tcp4TlsTxToken.CompletionToken.Status;
718 } else {
719 ((EFI_TCP6_TRANSMIT_DATA *) Data)->Push = TRUE;
720 ((EFI_TCP6_TRANSMIT_DATA *) Data)->Urgent = FALSE;
721 ((EFI_TCP6_TRANSMIT_DATA *) Data)->DataLength = Packet->TotalSize;
722
723 //
724 // Build the fragment table.
725 //
726 ((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount = Packet->BlockOpNum;
727
728 NetbufBuildExt (
729 Packet,
730 (NET_FRAGMENT *) &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentTable[0],
731 &((EFI_TCP6_TRANSMIT_DATA *) Data)->FragmentCount
732 );
733
734 HttpInstance->Tcp6TlsTxToken.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *) Data;
735
736 Status = EFI_DEVICE_ERROR;
737
738 //
739 // Transmit the packet.
740 //
741 Status = HttpInstance->Tcp6->Transmit (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsTxToken);
742 if (EFI_ERROR (Status)) {
743 goto ON_EXIT;
744 }
745
746 while (!HttpInstance->TlsIsTxDone) {
747 HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
748 }
749
750 HttpInstance->TlsIsTxDone = FALSE;
751 Status = HttpInstance->Tcp6TlsTxToken.CompletionToken.Status;
752 }
753
754 ON_EXIT:
755 FreePool (Data);
756
757 return Status;
758 }
759
760 /**
761 Receive the Packet by processing the associated HTTPS token.
762
763 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
764 @param[in] Packet The packet to transmit.
765 @param[in] Timeout The time to wait for connection done.
766
767 @retval EFI_SUCCESS The Packet is received.
768 @retval EFI_INVALID_PARAMETER HttpInstance is NULL or Packet is NULL.
769 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
770 @retval EFI_TIMEOUT The operation is time out.
771 @retval Others Other error as indicated.
772
773 **/
774 EFI_STATUS
775 EFIAPI
776 TlsCommonReceive (
777 IN OUT HTTP_PROTOCOL *HttpInstance,
778 IN NET_BUF *Packet,
779 IN EFI_EVENT Timeout
780 )
781 {
782 EFI_TCP4_RECEIVE_DATA *Tcp4RxData;
783 EFI_TCP6_RECEIVE_DATA *Tcp6RxData;
784 EFI_STATUS Status;
785 NET_FRAGMENT *Fragment;
786 UINT32 FragmentCount;
787 UINT32 CurrentFragment;
788
789 Tcp4RxData = NULL;
790 Tcp6RxData = NULL;
791
792 if ((HttpInstance == NULL) || (Packet == NULL)) {
793 return EFI_INVALID_PARAMETER;
794 }
795
796 FragmentCount = Packet->BlockOpNum;
797 Fragment = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
798 if (Fragment == NULL) {
799 Status = EFI_OUT_OF_RESOURCES;
800 goto ON_EXIT;
801 }
802
803 //
804 // Build the fragment table.
805 //
806 NetbufBuildExt (Packet, Fragment, &FragmentCount);
807
808 if (!HttpInstance->LocalAddressIsIPv6) {
809 Tcp4RxData = HttpInstance->Tcp4TlsRxToken.Packet.RxData;
810 if (Tcp4RxData == NULL) {
811 return EFI_INVALID_PARAMETER;
812 }
813 Tcp4RxData->FragmentCount = 1;
814 } else {
815 Tcp6RxData = HttpInstance->Tcp6TlsRxToken.Packet.RxData;
816 if (Tcp6RxData == NULL) {
817 return EFI_INVALID_PARAMETER;
818 }
819 Tcp6RxData->FragmentCount = 1;
820 }
821
822 CurrentFragment = 0;
823 Status = EFI_SUCCESS;
824
825 while (CurrentFragment < FragmentCount) {
826 if (!HttpInstance->LocalAddressIsIPv6) {
827 Tcp4RxData->DataLength = Fragment[CurrentFragment].Len;
828 Tcp4RxData->FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len;
829 Tcp4RxData->FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk;
830 Status = HttpInstance->Tcp4->Receive (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken);
831 } else {
832 Tcp6RxData->DataLength = Fragment[CurrentFragment].Len;
833 Tcp6RxData->FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len;
834 Tcp6RxData->FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk;
835 Status = HttpInstance->Tcp6->Receive (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken);
836 }
837 if (EFI_ERROR (Status)) {
838 goto ON_EXIT;
839 }
840
841 while (!HttpInstance->TlsIsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
842 //
843 // Poll until some data is received or an error occurs.
844 //
845 if (!HttpInstance->LocalAddressIsIPv6) {
846 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
847 } else {
848 HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
849 }
850 }
851
852 if (!HttpInstance->TlsIsRxDone) {
853 //
854 // Timeout occurs, cancel the receive request.
855 //
856 if (!HttpInstance->LocalAddressIsIPv6) {
857 HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken.CompletionToken);
858 } else {
859 HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken.CompletionToken);
860 }
861
862 Status = EFI_TIMEOUT;
863 goto ON_EXIT;
864 } else {
865 HttpInstance->TlsIsRxDone = FALSE;
866 }
867
868 if (!HttpInstance->LocalAddressIsIPv6) {
869 Status = HttpInstance->Tcp4TlsRxToken.CompletionToken.Status;
870 if (EFI_ERROR (Status)) {
871 goto ON_EXIT;
872 }
873
874 Fragment[CurrentFragment].Len -= Tcp4RxData->FragmentTable[0].FragmentLength;
875 if (Fragment[CurrentFragment].Len == 0) {
876 CurrentFragment++;
877 } else {
878 Fragment[CurrentFragment].Bulk += Tcp4RxData->FragmentTable[0].FragmentLength;
879 }
880 } else {
881 Status = HttpInstance->Tcp6TlsRxToken.CompletionToken.Status;
882 if (EFI_ERROR (Status)) {
883 goto ON_EXIT;
884 }
885
886 Fragment[CurrentFragment].Len -= Tcp6RxData->FragmentTable[0].FragmentLength;
887 if (Fragment[CurrentFragment].Len == 0) {
888 CurrentFragment++;
889 } else {
890 Fragment[CurrentFragment].Bulk += Tcp6RxData->FragmentTable[0].FragmentLength;
891 }
892 }
893 }
894
895 ON_EXIT:
896
897 if (Fragment != NULL) {
898 FreePool (Fragment);
899 }
900
901 return Status;
902 }
903
904 /**
905 Receive one TLS PDU. An TLS PDU contains an TLS record header and it's
906 corresponding record data. These two parts will be put into two blocks of buffers in the
907 net buffer.
908
909 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
910 @param[out] Pdu The received TLS PDU.
911 @param[in] Timeout The time to wait for connection done.
912
913 @retval EFI_SUCCESS An TLS PDU is received.
914 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
915 @retval EFI_PROTOCOL_ERROR An unexpected TLS packet was received.
916 @retval Others Other errors as indicated.
917
918 **/
919 EFI_STATUS
920 EFIAPI
921 TlsReceiveOnePdu (
922 IN OUT HTTP_PROTOCOL *HttpInstance,
923 OUT NET_BUF **Pdu,
924 IN EFI_EVENT Timeout
925 )
926 {
927 EFI_STATUS Status;
928
929 LIST_ENTRY *NbufList;
930
931 UINT32 Len;
932
933 NET_BUF *PduHdr;
934 UINT8 *Header;
935 TLS_RECORD_HEADER RecordHeader;
936
937 NET_BUF *DataSeg;
938
939 NbufList = NULL;
940 PduHdr = NULL;
941 Header = NULL;
942 DataSeg = NULL;
943
944 NbufList = AllocatePool (sizeof (LIST_ENTRY));
945 if (NbufList == NULL) {
946 return EFI_OUT_OF_RESOURCES;
947 }
948
949 InitializeListHead (NbufList);
950
951 //
952 // Allocate buffer to receive one TLS header.
953 //
954 Len = sizeof (TLS_RECORD_HEADER);
955 PduHdr = NetbufAlloc (Len);
956 if (PduHdr == NULL) {
957 Status = EFI_OUT_OF_RESOURCES;
958 goto ON_EXIT;
959 }
960
961 Header = NetbufAllocSpace (PduHdr, Len, NET_BUF_TAIL);
962 if (Header == NULL) {
963 Status = EFI_OUT_OF_RESOURCES;
964 goto ON_EXIT;
965 }
966
967 //
968 // First step, receive one TLS header.
969 //
970 Status = TlsCommonReceive (HttpInstance, PduHdr, Timeout);
971 if (EFI_ERROR (Status)) {
972 goto ON_EXIT;
973 }
974
975 RecordHeader = *(TLS_RECORD_HEADER *) Header;
976 if ((RecordHeader.ContentType == TlsContentTypeHandshake ||
977 RecordHeader.ContentType == TlsContentTypeAlert ||
978 RecordHeader.ContentType == TlsContentTypeChangeCipherSpec ||
979 RecordHeader.ContentType == TlsContentTypeApplicationData) &&
980 (RecordHeader.Version.Major == 0x03) && /// Major versions are same.
981 (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
982 RecordHeader.Version.Minor ==TLS11_PROTOCOL_VERSION_MINOR ||
983 RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
984 ) {
985 InsertTailList (NbufList, &PduHdr->List);
986 } else {
987 Status = EFI_PROTOCOL_ERROR;
988 goto ON_EXIT;
989 }
990
991 Len = SwapBytes16(RecordHeader.Length);
992 if (Len == 0) {
993 //
994 // No TLS payload.
995 //
996 goto FORM_PDU;
997 }
998
999 //
1000 // Allocate buffer to receive one TLS payload.
1001 //
1002 DataSeg = NetbufAlloc (Len);
1003 if (DataSeg == NULL) {
1004 Status = EFI_OUT_OF_RESOURCES;
1005 goto ON_EXIT;
1006 }
1007
1008 NetbufAllocSpace (DataSeg, Len, NET_BUF_TAIL);
1009
1010 //
1011 // Second step, receive one TLS payload.
1012 //
1013 Status = TlsCommonReceive (HttpInstance, DataSeg, Timeout);
1014 if (EFI_ERROR (Status)) {
1015 goto ON_EXIT;
1016 }
1017
1018 InsertTailList (NbufList, &DataSeg->List);
1019
1020 FORM_PDU:
1021 //
1022 // Form the PDU from a list of PDU.
1023 //
1024 *Pdu = NetbufFromBufList (NbufList, 0, 0, FreeNbufList, NbufList);
1025 if (*Pdu == NULL) {
1026 Status = EFI_OUT_OF_RESOURCES;
1027 }
1028
1029 ON_EXIT:
1030
1031 if (EFI_ERROR (Status)) {
1032 //
1033 // Free the Nbufs in this NbufList and the NbufList itself.
1034 //
1035 FreeNbufList (NbufList);
1036 }
1037
1038 return Status;
1039 }
1040
1041 /**
1042 Connect one TLS session by finishing the TLS handshake process.
1043
1044 @param[in] HttpInstance The HTTP instance private data.
1045 @param[in] Timeout The time to wait for connection done.
1046
1047 @retval EFI_SUCCESS The TLS session is established.
1048 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1049 @retval EFI_ABORTED TLS session state is incorrect.
1050 @retval Others Other error as indicated.
1051
1052 **/
1053 EFI_STATUS
1054 EFIAPI
1055 TlsConnectSession (
1056 IN HTTP_PROTOCOL *HttpInstance,
1057 IN EFI_EVENT Timeout
1058 )
1059 {
1060 EFI_STATUS Status;
1061 UINT8 *BufferOut;
1062 UINTN BufferOutSize;
1063 NET_BUF *PacketOut;
1064 UINT8 *DataOut;
1065 NET_BUF *Pdu;
1066 UINT8 *BufferIn;
1067 UINTN BufferInSize;
1068 UINT8 *GetSessionDataBuffer;
1069 UINTN GetSessionDataBufferSize;
1070
1071 BufferOut = NULL;
1072 PacketOut = NULL;
1073 DataOut = NULL;
1074 Pdu = NULL;
1075 BufferIn = NULL;
1076
1077 //
1078 // Initialize TLS state.
1079 //
1080 HttpInstance->TlsSessionState = EfiTlsSessionNotStarted;
1081 Status = HttpInstance->Tls->SetSessionData (
1082 HttpInstance->Tls,
1083 EfiTlsSessionState,
1084 &(HttpInstance->TlsSessionState),
1085 sizeof (EFI_TLS_SESSION_STATE)
1086 );
1087 if (EFI_ERROR (Status)) {
1088 return Status;
1089 }
1090
1091 //
1092 // Create ClientHello
1093 //
1094 BufferOutSize = DEF_BUF_LEN;
1095 BufferOut = AllocateZeroPool (BufferOutSize);
1096 if (BufferOut == NULL) {
1097 Status = EFI_OUT_OF_RESOURCES;
1098 return Status;
1099 }
1100
1101 Status = HttpInstance->Tls->BuildResponsePacket (
1102 HttpInstance->Tls,
1103 NULL,
1104 0,
1105 BufferOut,
1106 &BufferOutSize
1107 );
1108 if (Status == EFI_BUFFER_TOO_SMALL) {
1109 FreePool (BufferOut);
1110 BufferOut = AllocateZeroPool (BufferOutSize);
1111 if (BufferOut == NULL) {
1112 Status = EFI_OUT_OF_RESOURCES;
1113 return Status;
1114 }
1115
1116 Status = HttpInstance->Tls->BuildResponsePacket (
1117 HttpInstance->Tls,
1118 NULL,
1119 0,
1120 BufferOut,
1121 &BufferOutSize
1122 );
1123 }
1124 if (EFI_ERROR (Status)) {
1125 FreePool (BufferOut);
1126 return Status;
1127 }
1128
1129 //
1130 // Transmit ClientHello
1131 //
1132 PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
1133 DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
1134 if (DataOut == NULL) {
1135 FreePool (BufferOut);
1136 return EFI_OUT_OF_RESOURCES;
1137 }
1138
1139 CopyMem (DataOut, BufferOut, BufferOutSize);
1140 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1141
1142 FreePool (BufferOut);
1143 NetbufFree (PacketOut);
1144
1145 if (EFI_ERROR (Status)) {
1146 return Status;
1147 }
1148
1149 while(HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring && \
1150 ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
1151 //
1152 // Receive one TLS record.
1153 //
1154 Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
1155 if (EFI_ERROR (Status)) {
1156 return Status;
1157 }
1158
1159 BufferInSize = Pdu->TotalSize;
1160 BufferIn = AllocateZeroPool (BufferInSize);
1161 if (BufferIn == NULL) {
1162 NetbufFree (Pdu);
1163 Status = EFI_OUT_OF_RESOURCES;
1164 return Status;
1165 }
1166
1167 NetbufCopy (Pdu, 0, (UINT32)BufferInSize, BufferIn);
1168
1169 NetbufFree (Pdu);
1170
1171 //
1172 // Handle Receive data.
1173 //
1174 BufferOutSize = DEF_BUF_LEN;
1175 BufferOut = AllocateZeroPool (BufferOutSize);
1176 if (BufferOut == NULL) {
1177 Status = EFI_OUT_OF_RESOURCES;
1178 return Status;
1179 }
1180
1181 Status = HttpInstance->Tls->BuildResponsePacket (
1182 HttpInstance->Tls,
1183 BufferIn,
1184 BufferInSize,
1185 BufferOut,
1186 &BufferOutSize
1187 );
1188 if (Status == EFI_BUFFER_TOO_SMALL) {
1189 FreePool (BufferOut);
1190 BufferOut = AllocateZeroPool (BufferOutSize);
1191 if (BufferOut == NULL) {
1192 FreePool (BufferIn);
1193 Status = EFI_OUT_OF_RESOURCES;
1194 return Status;
1195 }
1196
1197 Status = HttpInstance->Tls->BuildResponsePacket (
1198 HttpInstance->Tls,
1199 BufferIn,
1200 BufferInSize,
1201 BufferOut,
1202 &BufferOutSize
1203 );
1204 }
1205
1206 FreePool (BufferIn);
1207
1208 if (EFI_ERROR (Status)) {
1209 FreePool (BufferOut);
1210 return Status;
1211 }
1212
1213 if (BufferOutSize != 0) {
1214 //
1215 // Transmit the response packet.
1216 //
1217 PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
1218 DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
1219 if (DataOut == NULL) {
1220 FreePool (BufferOut);
1221 return EFI_OUT_OF_RESOURCES;
1222 }
1223
1224 CopyMem (DataOut, BufferOut, BufferOutSize);
1225
1226 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1227
1228 NetbufFree (PacketOut);
1229
1230 if (EFI_ERROR (Status)) {
1231 FreePool (BufferOut);
1232 return Status;
1233 }
1234 }
1235
1236 FreePool (BufferOut);
1237
1238 //
1239 // Get the session state, then decide whether need to continue handle received packet.
1240 //
1241 GetSessionDataBufferSize = DEF_BUF_LEN;
1242 GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1243 if (GetSessionDataBuffer == NULL) {
1244 Status = EFI_OUT_OF_RESOURCES;
1245 return Status;
1246 }
1247
1248 Status = HttpInstance->Tls->GetSessionData (
1249 HttpInstance->Tls,
1250 EfiTlsSessionState,
1251 GetSessionDataBuffer,
1252 &GetSessionDataBufferSize
1253 );
1254 if (Status == EFI_BUFFER_TOO_SMALL) {
1255 FreePool (GetSessionDataBuffer);
1256 GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1257 if (GetSessionDataBuffer == NULL) {
1258 Status = EFI_OUT_OF_RESOURCES;
1259 return Status;
1260 }
1261
1262 Status = HttpInstance->Tls->GetSessionData (
1263 HttpInstance->Tls,
1264 EfiTlsSessionState,
1265 GetSessionDataBuffer,
1266 &GetSessionDataBufferSize
1267 );
1268 }
1269 if (EFI_ERROR (Status)) {
1270 FreePool(GetSessionDataBuffer);
1271 return Status;
1272 }
1273
1274 ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
1275 HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;
1276
1277 FreePool (GetSessionDataBuffer);
1278
1279 if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
1280 return EFI_ABORTED;
1281 }
1282 }
1283
1284 if (HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring) {
1285 Status = EFI_ABORTED;
1286 }
1287
1288 return Status;
1289 }
1290
1291 /**
1292 Close the TLS session and send out the close notification message.
1293
1294 @param[in] HttpInstance The HTTP instance private data.
1295
1296 @retval EFI_SUCCESS The TLS session is closed.
1297 @retval EFI_INVALID_PARAMETER HttpInstance is NULL.
1298 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1299 @retval Others Other error as indicated.
1300
1301 **/
1302 EFI_STATUS
1303 EFIAPI
1304 TlsCloseSession (
1305 IN HTTP_PROTOCOL *HttpInstance
1306 )
1307 {
1308 EFI_STATUS Status;
1309
1310 UINT8 *BufferOut;
1311 UINTN BufferOutSize;
1312
1313 NET_BUF *PacketOut;
1314 UINT8 *DataOut;
1315
1316 Status = EFI_SUCCESS;
1317 BufferOut = NULL;
1318 PacketOut = NULL;
1319 DataOut = NULL;
1320
1321 if (HttpInstance == NULL) {
1322 return EFI_INVALID_PARAMETER;
1323 }
1324
1325 HttpInstance->TlsSessionState = EfiTlsSessionClosing;
1326
1327 Status = HttpInstance->Tls->SetSessionData (
1328 HttpInstance->Tls,
1329 EfiTlsSessionState,
1330 &(HttpInstance->TlsSessionState),
1331 sizeof (EFI_TLS_SESSION_STATE)
1332 );
1333 if (EFI_ERROR (Status)) {
1334 return Status;
1335 }
1336
1337 BufferOutSize = DEF_BUF_LEN;
1338 BufferOut = AllocateZeroPool (BufferOutSize);
1339 if (BufferOut == NULL) {
1340 Status = EFI_OUT_OF_RESOURCES;
1341 return Status;
1342 }
1343
1344 Status = HttpInstance->Tls->BuildResponsePacket (
1345 HttpInstance->Tls,
1346 NULL,
1347 0,
1348 BufferOut,
1349 &BufferOutSize
1350 );
1351 if (Status == EFI_BUFFER_TOO_SMALL) {
1352 FreePool (BufferOut);
1353 BufferOut = AllocateZeroPool (BufferOutSize);
1354 if (BufferOut == NULL) {
1355 Status = EFI_OUT_OF_RESOURCES;
1356 return Status;
1357 }
1358
1359 Status = HttpInstance->Tls->BuildResponsePacket (
1360 HttpInstance->Tls,
1361 NULL,
1362 0,
1363 BufferOut,
1364 &BufferOutSize
1365 );
1366 }
1367
1368 if (EFI_ERROR (Status)) {
1369 FreePool (BufferOut);
1370 return Status;
1371 }
1372
1373 PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
1374 DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
1375 if (DataOut == NULL) {
1376 FreePool (BufferOut);
1377 return EFI_OUT_OF_RESOURCES;
1378 }
1379
1380 CopyMem (DataOut, BufferOut, BufferOutSize);
1381
1382 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1383
1384 FreePool (BufferOut);
1385 NetbufFree (PacketOut);
1386
1387 return Status;
1388 }
1389
1390 /**
1391 Process one message according to the CryptMode.
1392
1393 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
1394 @param[in] Message Pointer to the message buffer needed to processed.
1395 @param[in] MessageSize Pointer to the message buffer size.
1396 @param[in] ProcessMode Process mode.
1397 @param[in, out] Fragment Only one Fragment returned after the Message is
1398 processed successfully.
1399
1400 @retval EFI_SUCCESS Message is processed successfully.
1401 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1402 @retval Others Other errors as indicated.
1403
1404 **/
1405 EFI_STATUS
1406 EFIAPI
1407 TlsProcessMessage (
1408 IN HTTP_PROTOCOL *HttpInstance,
1409 IN UINT8 *Message,
1410 IN UINTN MessageSize,
1411 IN EFI_TLS_CRYPT_MODE ProcessMode,
1412 IN OUT NET_FRAGMENT *Fragment
1413 )
1414 {
1415 EFI_STATUS Status;
1416 UINT8 *Buffer;
1417 UINT32 BufferSize;
1418 UINT32 BytesCopied;
1419 EFI_TLS_FRAGMENT_DATA *FragmentTable;
1420 UINT32 FragmentCount;
1421 EFI_TLS_FRAGMENT_DATA *OriginalFragmentTable;
1422 UINTN Index;
1423
1424 Status = EFI_SUCCESS;
1425 Buffer = NULL;
1426 BufferSize = 0;
1427 BytesCopied = 0;
1428 FragmentTable = NULL;
1429 OriginalFragmentTable = NULL;
1430
1431 //
1432 // Rebuild fragment table from BufferIn.
1433 //
1434 FragmentCount = 1;
1435 FragmentTable = AllocateZeroPool (FragmentCount * sizeof (EFI_TLS_FRAGMENT_DATA));
1436 if (FragmentTable == NULL) {
1437 Status = EFI_OUT_OF_RESOURCES;
1438 goto ON_EXIT;
1439 }
1440
1441 FragmentTable->FragmentLength = (UINT32) MessageSize;
1442 FragmentTable->FragmentBuffer = Message;
1443
1444 //
1445 // Record the original FragmentTable.
1446 //
1447 OriginalFragmentTable = FragmentTable;
1448
1449 //
1450 // Process the Message.
1451 //
1452 Status = HttpInstance->Tls->ProcessPacket (
1453 HttpInstance->Tls,
1454 &FragmentTable,
1455 &FragmentCount,
1456 ProcessMode
1457 );
1458 if (EFI_ERROR (Status)) {
1459 goto ON_EXIT;
1460 }
1461
1462 //
1463 // Calculate the size according to FragmentTable.
1464 //
1465 for (Index = 0; Index < FragmentCount; Index++) {
1466 BufferSize += FragmentTable[Index].FragmentLength;
1467 }
1468
1469 //
1470 // Allocate buffer for processed data.
1471 //
1472 Buffer = AllocateZeroPool (BufferSize);
1473 if (Buffer == NULL) {
1474 Status = EFI_OUT_OF_RESOURCES;
1475 goto ON_EXIT;
1476 }
1477
1478 //
1479 // Copy the new FragmentTable buffer into Buffer.
1480 //
1481 for (Index = 0; Index < FragmentCount; Index++) {
1482 CopyMem (
1483 (Buffer + BytesCopied),
1484 FragmentTable[Index].FragmentBuffer,
1485 FragmentTable[Index].FragmentLength
1486 );
1487 BytesCopied += FragmentTable[Index].FragmentLength;
1488
1489 //
1490 // Free the FragmentBuffer since it has been copied.
1491 //
1492 FreePool (FragmentTable[Index].FragmentBuffer);
1493 }
1494
1495 Fragment->Len = BufferSize;
1496 Fragment->Bulk = Buffer;
1497
1498 ON_EXIT:
1499
1500 if (OriginalFragmentTable != NULL) {
1501 FreePool (OriginalFragmentTable);
1502 OriginalFragmentTable = NULL;
1503 }
1504
1505 //
1506 // Caller has the responsibility to free the FragmentTable.
1507 //
1508 if (FragmentTable != NULL) {
1509 FreePool (FragmentTable);
1510 FragmentTable = NULL;
1511 }
1512
1513 return Status;
1514 }
1515
1516 /**
1517 Receive one fragment decrypted from one TLS record.
1518
1519 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
1520 @param[in, out] Fragment The received Fragment.
1521 @param[in] Timeout The time to wait for connection done.
1522
1523 @retval EFI_SUCCESS One fragment is received.
1524 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1525 @retval EFI_ABORTED Something wrong decryption the message.
1526 @retval Others Other errors as indicated.
1527
1528 **/
1529 EFI_STATUS
1530 EFIAPI
1531 HttpsReceive (
1532 IN HTTP_PROTOCOL *HttpInstance,
1533 IN OUT NET_FRAGMENT *Fragment,
1534 IN EFI_EVENT Timeout
1535 )
1536 {
1537 EFI_STATUS Status;
1538 NET_BUF *Pdu;
1539 TLS_RECORD_HEADER RecordHeader;
1540 UINT8 *BufferIn;
1541 UINTN BufferInSize;
1542 NET_FRAGMENT TempFragment;
1543 UINT8 *BufferOut;
1544 UINTN BufferOutSize;
1545 NET_BUF *PacketOut;
1546 UINT8 *DataOut;
1547 UINT8 *GetSessionDataBuffer;
1548 UINTN GetSessionDataBufferSize;
1549
1550 Status = EFI_SUCCESS;
1551 Pdu = NULL;
1552 BufferIn = NULL;
1553 BufferInSize = 0;
1554 BufferOut = NULL;
1555 BufferOutSize = 0;
1556 PacketOut = NULL;
1557 DataOut = NULL;
1558 GetSessionDataBuffer = NULL;
1559 GetSessionDataBufferSize = 0;
1560
1561 //
1562 // Receive only one TLS record
1563 //
1564 Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
1565 if (EFI_ERROR (Status)) {
1566 return Status;
1567 }
1568
1569 BufferInSize = Pdu->TotalSize;
1570 BufferIn = AllocateZeroPool (BufferInSize);
1571 if (BufferIn == NULL) {
1572 Status = EFI_OUT_OF_RESOURCES;
1573 NetbufFree (Pdu);
1574 return Status;
1575 }
1576
1577 NetbufCopy (Pdu, 0, (UINT32) BufferInSize, BufferIn);
1578
1579 NetbufFree (Pdu);
1580
1581 //
1582 // Handle Receive data.
1583 //
1584 RecordHeader = *(TLS_RECORD_HEADER *) BufferIn;
1585
1586 if ((RecordHeader.ContentType == TlsContentTypeApplicationData) &&
1587 (RecordHeader.Version.Major == 0x03) &&
1588 (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
1589 RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
1590 RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
1591 ) {
1592 //
1593 // Decrypt Packet.
1594 //
1595 Status = TlsProcessMessage (
1596 HttpInstance,
1597 BufferIn,
1598 BufferInSize,
1599 EfiTlsDecrypt,
1600 &TempFragment
1601 );
1602
1603 FreePool (BufferIn);
1604
1605 if (EFI_ERROR (Status)) {
1606 if (Status == EFI_ABORTED) {
1607 //
1608 // Something wrong decryption the message.
1609 // BuildResponsePacket() will be called to generate Error Alert message and send it out.
1610 //
1611 BufferOutSize = DEF_BUF_LEN;
1612 BufferOut = AllocateZeroPool (BufferOutSize);
1613 if (BufferOut == NULL) {
1614 Status = EFI_OUT_OF_RESOURCES;
1615 return Status;
1616 }
1617
1618 Status = HttpInstance->Tls->BuildResponsePacket (
1619 HttpInstance->Tls,
1620 NULL,
1621 0,
1622 BufferOut,
1623 &BufferOutSize
1624 );
1625 if (Status == EFI_BUFFER_TOO_SMALL) {
1626 FreePool (BufferOut);
1627 BufferOut = AllocateZeroPool (BufferOutSize);
1628 if (BufferOut == NULL) {
1629 Status = EFI_OUT_OF_RESOURCES;
1630 return Status;
1631 }
1632
1633 Status = HttpInstance->Tls->BuildResponsePacket (
1634 HttpInstance->Tls,
1635 NULL,
1636 0,
1637 BufferOut,
1638 &BufferOutSize
1639 );
1640 }
1641 if (EFI_ERROR (Status)) {
1642 FreePool(BufferOut);
1643 return Status;
1644 }
1645
1646 if (BufferOutSize != 0) {
1647 PacketOut = NetbufAlloc ((UINT32)BufferOutSize);
1648 DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
1649 if (DataOut == NULL) {
1650 FreePool (BufferOut);
1651 return EFI_OUT_OF_RESOURCES;
1652 }
1653
1654 CopyMem (DataOut, BufferOut, BufferOutSize);
1655
1656 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1657
1658 NetbufFree (PacketOut);
1659 }
1660
1661 FreePool(BufferOut);
1662
1663 if (EFI_ERROR (Status)) {
1664 return Status;
1665 }
1666
1667 return EFI_ABORTED;
1668 }
1669
1670 return Status;
1671 }
1672
1673 //
1674 // Parsing buffer.
1675 //
1676 ASSERT (((TLS_RECORD_HEADER *) (TempFragment.Bulk))->ContentType == TlsContentTypeApplicationData);
1677
1678 BufferInSize = ((TLS_RECORD_HEADER *) (TempFragment.Bulk))->Length;
1679 BufferIn = AllocateZeroPool (BufferInSize);
1680 if (BufferIn == NULL) {
1681 Status = EFI_OUT_OF_RESOURCES;
1682 return Status;
1683 }
1684
1685 CopyMem (BufferIn, TempFragment.Bulk + sizeof (TLS_RECORD_HEADER), BufferInSize);
1686
1687 //
1688 // Free the buffer in TempFragment.
1689 //
1690 FreePool (TempFragment.Bulk);
1691
1692 } else if ((RecordHeader.ContentType == TlsContentTypeAlert) &&
1693 (RecordHeader.Version.Major == 0x03) &&
1694 (RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR ||
1695 RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR ||
1696 RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR)
1697 ) {
1698 BufferOutSize = DEF_BUF_LEN;
1699 BufferOut = AllocateZeroPool (BufferOutSize);
1700 if (BufferOut == NULL) {
1701 FreePool (BufferIn);
1702 Status = EFI_OUT_OF_RESOURCES;
1703 return Status;
1704 }
1705
1706 Status = HttpInstance->Tls->BuildResponsePacket (
1707 HttpInstance->Tls,
1708 BufferIn,
1709 BufferInSize,
1710 BufferOut,
1711 &BufferOutSize
1712 );
1713 if (Status == EFI_BUFFER_TOO_SMALL) {
1714 FreePool (BufferOut);
1715 BufferOut = AllocateZeroPool (BufferOutSize);
1716 if (BufferOut == NULL) {
1717 FreePool (BufferIn);
1718 Status = EFI_OUT_OF_RESOURCES;
1719 return Status;
1720 }
1721
1722 Status = HttpInstance->Tls->BuildResponsePacket (
1723 HttpInstance->Tls,
1724 BufferIn,
1725 BufferInSize,
1726 BufferOut,
1727 &BufferOutSize
1728 );
1729 }
1730
1731 FreePool (BufferIn);
1732
1733 if (EFI_ERROR (Status)) {
1734 FreePool (BufferOut);
1735 return Status;
1736 }
1737
1738 if (BufferOutSize != 0) {
1739 PacketOut = NetbufAlloc ((UINT32) BufferOutSize);
1740 DataOut = NetbufAllocSpace (PacketOut, (UINT32) BufferOutSize, NET_BUF_TAIL);
1741 if (DataOut == NULL) {
1742 FreePool (BufferOut);
1743 return EFI_OUT_OF_RESOURCES;
1744 }
1745
1746 CopyMem (DataOut, BufferOut, BufferOutSize);
1747
1748 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1749
1750 NetbufFree (PacketOut);
1751 }
1752
1753 FreePool (BufferOut);
1754
1755 //
1756 // Get the session state.
1757 //
1758 GetSessionDataBufferSize = DEF_BUF_LEN;
1759 GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1760 if (GetSessionDataBuffer == NULL) {
1761 Status = EFI_OUT_OF_RESOURCES;
1762 return Status;
1763 }
1764
1765 Status = HttpInstance->Tls->GetSessionData (
1766 HttpInstance->Tls,
1767 EfiTlsSessionState,
1768 GetSessionDataBuffer,
1769 &GetSessionDataBufferSize
1770 );
1771 if (Status == EFI_BUFFER_TOO_SMALL) {
1772 FreePool (GetSessionDataBuffer);
1773 GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1774 if (GetSessionDataBuffer == NULL) {
1775 Status = EFI_OUT_OF_RESOURCES;
1776 return Status;
1777 }
1778
1779 Status = HttpInstance->Tls->GetSessionData (
1780 HttpInstance->Tls,
1781 EfiTlsSessionState,
1782 GetSessionDataBuffer,
1783 &GetSessionDataBufferSize
1784 );
1785 }
1786 if (EFI_ERROR (Status)) {
1787 FreePool (GetSessionDataBuffer);
1788 return Status;
1789 }
1790
1791 ASSERT(GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
1792 HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *) GetSessionDataBuffer;
1793
1794 FreePool (GetSessionDataBuffer);
1795
1796 if(HttpInstance->TlsSessionState == EfiTlsSessionError) {
1797 DEBUG ((EFI_D_ERROR, "TLS Session State Error!\n"));
1798 return EFI_ABORTED;
1799 }
1800
1801 BufferIn = NULL;
1802 BufferInSize = 0;
1803 }
1804
1805 Fragment->Bulk = BufferIn;
1806 Fragment->Len = (UINT32) BufferInSize;
1807
1808 return Status;
1809 }
1810