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