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