]> git.proxmox.com Git - mirror_edk2.git/blob - NetworkPkg/HttpDxe/HttpsSupport.c
ad611e7c383688ab253d862b46fed10c7611309b
[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 SPDX-License-Identifier: BSD-2-Clause-Patent
7
8 **/
9
10 #include "HttpDriver.h"
11
12 /**
13 Returns the first occurrence of a Null-terminated ASCII sub-string in a Null-terminated
14 ASCII string and ignore case during the search process.
15
16 This function scans the contents of the ASCII string specified by String
17 and returns the first occurrence of SearchString and ignore case during the search process.
18 If SearchString is not found in String, then NULL is returned. If the length of SearchString
19 is zero, then String is returned.
20
21 If String is NULL, then ASSERT().
22 If SearchString is NULL, then ASSERT().
23
24 @param[in] String A pointer to a Null-terminated ASCII string.
25 @param[in] SearchString A pointer to a Null-terminated ASCII string to search for.
26
27 @retval NULL If the SearchString does not appear in String.
28 @retval others If there is a match return the first occurrence of SearchingString.
29 If the length of SearchString is zero,return String.
30
31 **/
32 CHAR8 *
33 AsciiStrCaseStr (
34 IN CONST CHAR8 *String,
35 IN CONST CHAR8 *SearchString
36 )
37 {
38 CONST CHAR8 *FirstMatch;
39 CONST CHAR8 *SearchStringTmp;
40
41 CHAR8 Src;
42 CHAR8 Dst;
43
44 //
45 // ASSERT both strings are less long than PcdMaximumAsciiStringLength
46 //
47 ASSERT (AsciiStrSize (String) != 0);
48 ASSERT (AsciiStrSize (SearchString) != 0);
49
50 if (*SearchString == '\0') {
51 return (CHAR8 *)String;
52 }
53
54 while (*String != '\0') {
55 SearchStringTmp = SearchString;
56 FirstMatch = String;
57
58 while ( (*SearchStringTmp != '\0')
59 && (*String != '\0'))
60 {
61 Src = *String;
62 Dst = *SearchStringTmp;
63
64 if ((Src >= 'A') && (Src <= 'Z')) {
65 Src += ('a' - 'A');
66 }
67
68 if ((Dst >= 'A') && (Dst <= 'Z')) {
69 Dst += ('a' - 'A');
70 }
71
72 if (Src != Dst) {
73 break;
74 }
75
76 String++;
77 SearchStringTmp++;
78 }
79
80 if (*SearchStringTmp == '\0') {
81 return (CHAR8 *)FirstMatch;
82 }
83
84 String = FirstMatch + 1;
85 }
86
87 return NULL;
88 }
89
90 /**
91 The callback function to free the net buffer list.
92
93 @param[in] Arg The opaque parameter.
94
95 **/
96 VOID
97 EFIAPI
98 FreeNbufList (
99 IN VOID *Arg
100 )
101 {
102 ASSERT (Arg != NULL);
103
104 NetbufFreeList ((LIST_ENTRY *)Arg);
105 FreePool (Arg);
106 }
107
108 /**
109 Check whether the Url is from Https.
110
111 @param[in] Url The pointer to a HTTP or HTTPS URL string.
112
113 @retval TRUE The Url is from HTTPS.
114 @retval FALSE The Url is from HTTP.
115
116 **/
117 BOOLEAN
118 IsHttpsUrl (
119 IN CHAR8 *Url
120 )
121 {
122 CHAR8 *Tmp;
123
124 Tmp = NULL;
125
126 Tmp = AsciiStrCaseStr (Url, HTTPS_FLAG);
127 if ((Tmp != NULL) && (Tmp == Url)) {
128 return TRUE;
129 }
130
131 return FALSE;
132 }
133
134 /**
135 Creates a Tls child handle, open EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
136
137 @param[in] ImageHandle The firmware allocated handle for the UEFI image.
138 @param[out] TlsSb Pointer to the TLS SERVICE_BINDING_PROTOCOL.
139 @param[out] TlsProto Pointer to the EFI_TLS_PROTOCOL instance.
140 @param[out] TlsConfiguration Pointer to the EFI_TLS_CONFIGURATION_PROTOCOL instance.
141
142 @return The child handle with opened EFI_TLS_PROTOCOL and EFI_TLS_CONFIGURATION_PROTOCOL.
143
144 **/
145 EFI_HANDLE
146 EFIAPI
147 TlsCreateChild (
148 IN EFI_HANDLE ImageHandle,
149 OUT EFI_SERVICE_BINDING_PROTOCOL **TlsSb,
150 OUT EFI_TLS_PROTOCOL **TlsProto,
151 OUT EFI_TLS_CONFIGURATION_PROTOCOL **TlsConfiguration
152 )
153 {
154 EFI_STATUS Status;
155 EFI_HANDLE TlsChildHandle;
156
157 TlsChildHandle = 0;
158
159 //
160 // Locate TlsServiceBinding protocol.
161 //
162 gBS->LocateProtocol (
163 &gEfiTlsServiceBindingProtocolGuid,
164 NULL,
165 (VOID **)TlsSb
166 );
167 if (*TlsSb == NULL) {
168 return NULL;
169 }
170
171 Status = (*TlsSb)->CreateChild (*TlsSb, &TlsChildHandle);
172 if (EFI_ERROR (Status)) {
173 return NULL;
174 }
175
176 Status = gBS->OpenProtocol (
177 TlsChildHandle,
178 &gEfiTlsProtocolGuid,
179 (VOID **)TlsProto,
180 ImageHandle,
181 TlsChildHandle,
182 EFI_OPEN_PROTOCOL_GET_PROTOCOL
183 );
184 if (EFI_ERROR (Status)) {
185 (*TlsSb)->DestroyChild (*TlsSb, TlsChildHandle);
186 return NULL;
187 }
188
189 Status = gBS->OpenProtocol (
190 TlsChildHandle,
191 &gEfiTlsConfigurationProtocolGuid,
192 (VOID **)TlsConfiguration,
193 ImageHandle,
194 TlsChildHandle,
195 EFI_OPEN_PROTOCOL_GET_PROTOCOL
196 );
197 if (EFI_ERROR (Status)) {
198 (*TlsSb)->DestroyChild (*TlsSb, TlsChildHandle);
199 return NULL;
200 }
201
202 return TlsChildHandle;
203 }
204
205 /**
206 Create event for the TLS receive and transmit tokens which are used to receive and
207 transmit TLS related messages.
208
209 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
210
211 @retval EFI_SUCCESS The events are created successfully.
212 @retval others Other error as indicated.
213
214 **/
215 EFI_STATUS
216 EFIAPI
217 TlsCreateTxRxEvent (
218 IN OUT HTTP_PROTOCOL *HttpInstance
219 )
220 {
221 EFI_STATUS Status;
222
223 if (!HttpInstance->LocalAddressIsIPv6) {
224 //
225 // For Tcp4TlsTxToken.
226 //
227 Status = gBS->CreateEvent (
228 EVT_NOTIFY_SIGNAL,
229 TPL_NOTIFY,
230 HttpCommonNotify,
231 &HttpInstance->TlsIsTxDone,
232 &HttpInstance->Tcp4TlsTxToken.CompletionToken.Event
233 );
234 if (EFI_ERROR (Status)) {
235 goto ERROR;
236 }
237
238 HttpInstance->Tcp4TlsTxData.Push = TRUE;
239 HttpInstance->Tcp4TlsTxData.Urgent = FALSE;
240 HttpInstance->Tcp4TlsTxData.DataLength = 0;
241 HttpInstance->Tcp4TlsTxData.FragmentCount = 1;
242 HttpInstance->Tcp4TlsTxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp4TlsTxData.DataLength;
243 HttpInstance->Tcp4TlsTxData.FragmentTable[0].FragmentBuffer = NULL;
244 HttpInstance->Tcp4TlsTxToken.Packet.TxData = &HttpInstance->Tcp4TlsTxData;
245 HttpInstance->Tcp4TlsTxToken.CompletionToken.Status = EFI_NOT_READY;
246
247 //
248 // For Tcp4TlsRxToken.
249 //
250 Status = gBS->CreateEvent (
251 EVT_NOTIFY_SIGNAL,
252 TPL_NOTIFY,
253 HttpCommonNotify,
254 &HttpInstance->TlsIsRxDone,
255 &HttpInstance->Tcp4TlsRxToken.CompletionToken.Event
256 );
257 if (EFI_ERROR (Status)) {
258 goto ERROR;
259 }
260
261 HttpInstance->Tcp4TlsRxData.DataLength = 0;
262 HttpInstance->Tcp4TlsRxData.FragmentCount = 1;
263 HttpInstance->Tcp4TlsRxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp4TlsRxData.DataLength;
264 HttpInstance->Tcp4TlsRxData.FragmentTable[0].FragmentBuffer = NULL;
265 HttpInstance->Tcp4TlsRxToken.Packet.RxData = &HttpInstance->Tcp4TlsRxData;
266 HttpInstance->Tcp4TlsRxToken.CompletionToken.Status = EFI_NOT_READY;
267 } else {
268 //
269 // For Tcp6TlsTxToken.
270 //
271 Status = gBS->CreateEvent (
272 EVT_NOTIFY_SIGNAL,
273 TPL_NOTIFY,
274 HttpCommonNotify,
275 &HttpInstance->TlsIsTxDone,
276 &HttpInstance->Tcp6TlsTxToken.CompletionToken.Event
277 );
278 if (EFI_ERROR (Status)) {
279 goto ERROR;
280 }
281
282 HttpInstance->Tcp6TlsTxData.Push = TRUE;
283 HttpInstance->Tcp6TlsTxData.Urgent = FALSE;
284 HttpInstance->Tcp6TlsTxData.DataLength = 0;
285 HttpInstance->Tcp6TlsTxData.FragmentCount = 1;
286 HttpInstance->Tcp6TlsTxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp6TlsTxData.DataLength;
287 HttpInstance->Tcp6TlsTxData.FragmentTable[0].FragmentBuffer = NULL;
288 HttpInstance->Tcp6TlsTxToken.Packet.TxData = &HttpInstance->Tcp6TlsTxData;
289 HttpInstance->Tcp6TlsTxToken.CompletionToken.Status = EFI_NOT_READY;
290
291 //
292 // For Tcp6TlsRxToken.
293 //
294 Status = gBS->CreateEvent (
295 EVT_NOTIFY_SIGNAL,
296 TPL_NOTIFY,
297 HttpCommonNotify,
298 &HttpInstance->TlsIsRxDone,
299 &HttpInstance->Tcp6TlsRxToken.CompletionToken.Event
300 );
301 if (EFI_ERROR (Status)) {
302 goto ERROR;
303 }
304
305 HttpInstance->Tcp6TlsRxData.DataLength = 0;
306 HttpInstance->Tcp6TlsRxData.FragmentCount = 1;
307 HttpInstance->Tcp6TlsRxData.FragmentTable[0].FragmentLength = HttpInstance->Tcp6TlsRxData.DataLength;
308 HttpInstance->Tcp6TlsRxData.FragmentTable[0].FragmentBuffer = NULL;
309 HttpInstance->Tcp6TlsRxToken.Packet.RxData = &HttpInstance->Tcp6TlsRxData;
310 HttpInstance->Tcp6TlsRxToken.CompletionToken.Status = EFI_NOT_READY;
311 }
312
313 return Status;
314
315 ERROR:
316 //
317 // Error handling
318 //
319 TlsCloseTxRxEvent (HttpInstance);
320
321 return Status;
322 }
323
324 /**
325 Close events in the TlsTxToken and TlsRxToken.
326
327 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
328
329 **/
330 VOID
331 EFIAPI
332 TlsCloseTxRxEvent (
333 IN HTTP_PROTOCOL *HttpInstance
334 )
335 {
336 ASSERT (HttpInstance != NULL);
337 if (!HttpInstance->LocalAddressIsIPv6) {
338 if (NULL != HttpInstance->Tcp4TlsTxToken.CompletionToken.Event) {
339 gBS->CloseEvent (HttpInstance->Tcp4TlsTxToken.CompletionToken.Event);
340 HttpInstance->Tcp4TlsTxToken.CompletionToken.Event = NULL;
341 }
342
343 if (NULL != HttpInstance->Tcp4TlsRxToken.CompletionToken.Event) {
344 gBS->CloseEvent (HttpInstance->Tcp4TlsRxToken.CompletionToken.Event);
345 HttpInstance->Tcp4TlsRxToken.CompletionToken.Event = NULL;
346 }
347 } else {
348 if (NULL != HttpInstance->Tcp6TlsTxToken.CompletionToken.Event) {
349 gBS->CloseEvent (HttpInstance->Tcp6TlsTxToken.CompletionToken.Event);
350 HttpInstance->Tcp6TlsTxToken.CompletionToken.Event = NULL;
351 }
352
353 if (NULL != HttpInstance->Tcp6TlsRxToken.CompletionToken.Event) {
354 gBS->CloseEvent (HttpInstance->Tcp6TlsRxToken.CompletionToken.Event);
355 HttpInstance->Tcp6TlsRxToken.CompletionToken.Event = NULL;
356 }
357 }
358 }
359
360 /**
361 Read the TlsCaCertificate variable and configure it.
362
363 @param[in, out] HttpInstance The HTTP instance private data.
364
365 @retval EFI_SUCCESS TlsCaCertificate is configured.
366 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
367 @retval EFI_NOT_FOUND Fail to get 'TlsCaCertificate' variable.
368 @retval Others Other error as indicated.
369
370 **/
371 EFI_STATUS
372 TlsConfigCertificate (
373 IN OUT HTTP_PROTOCOL *HttpInstance
374 )
375 {
376 EFI_STATUS Status;
377 UINT8 *CACert;
378 UINTN CACertSize;
379 UINT32 Index;
380 EFI_SIGNATURE_LIST *CertList;
381 EFI_SIGNATURE_DATA *Cert;
382 UINTN CertArraySizeInBytes;
383 UINTN CertCount;
384 UINT32 ItemDataSize;
385
386 CACert = NULL;
387 CACertSize = 0;
388
389 //
390 // Try to read the TlsCaCertificate variable.
391 //
392 Status = gRT->GetVariable (
393 EFI_TLS_CA_CERTIFICATE_VARIABLE,
394 &gEfiTlsCaCertificateGuid,
395 NULL,
396 &CACertSize,
397 NULL
398 );
399
400 if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {
401 return Status;
402 }
403
404 //
405 // Allocate buffer and read the config variable.
406 //
407 CACert = AllocatePool (CACertSize);
408 if (CACert == NULL) {
409 return EFI_OUT_OF_RESOURCES;
410 }
411
412 Status = gRT->GetVariable (
413 EFI_TLS_CA_CERTIFICATE_VARIABLE,
414 &gEfiTlsCaCertificateGuid,
415 NULL,
416 &CACertSize,
417 CACert
418 );
419 if (EFI_ERROR (Status)) {
420 //
421 // GetVariable still error or the variable is corrupted.
422 //
423 goto FreeCACert;
424 }
425
426 ASSERT (CACert != NULL);
427
428 //
429 // Sanity check
430 //
431 Status = EFI_INVALID_PARAMETER;
432 CertCount = 0;
433 ItemDataSize = (UINT32)CACertSize;
434 while (ItemDataSize > 0) {
435 if (ItemDataSize < sizeof (EFI_SIGNATURE_LIST)) {
436 DEBUG ((
437 DEBUG_ERROR,
438 "%a: truncated EFI_SIGNATURE_LIST header\n",
439 __FUNCTION__
440 ));
441 goto FreeCACert;
442 }
443
444 CertList = (EFI_SIGNATURE_LIST *)(CACert + (CACertSize - ItemDataSize));
445
446 if (CertList->SignatureListSize < sizeof (EFI_SIGNATURE_LIST)) {
447 DEBUG ((
448 DEBUG_ERROR,
449 "%a: SignatureListSize too small for EFI_SIGNATURE_LIST\n",
450 __FUNCTION__
451 ));
452 goto FreeCACert;
453 }
454
455 if (CertList->SignatureListSize > ItemDataSize) {
456 DEBUG ((
457 DEBUG_ERROR,
458 "%a: truncated EFI_SIGNATURE_LIST body\n",
459 __FUNCTION__
460 ));
461 goto FreeCACert;
462 }
463
464 if (!CompareGuid (&CertList->SignatureType, &gEfiCertX509Guid)) {
465 DEBUG ((
466 DEBUG_ERROR,
467 "%a: only X509 certificates are supported\n",
468 __FUNCTION__
469 ));
470 Status = EFI_UNSUPPORTED;
471 goto FreeCACert;
472 }
473
474 if (CertList->SignatureHeaderSize != 0) {
475 DEBUG ((
476 DEBUG_ERROR,
477 "%a: SignatureHeaderSize must be 0 for X509\n",
478 __FUNCTION__
479 ));
480 goto FreeCACert;
481 }
482
483 if (CertList->SignatureSize < sizeof (EFI_SIGNATURE_DATA)) {
484 DEBUG ((
485 DEBUG_ERROR,
486 "%a: SignatureSize too small for EFI_SIGNATURE_DATA\n",
487 __FUNCTION__
488 ));
489 goto FreeCACert;
490 }
491
492 CertArraySizeInBytes = (CertList->SignatureListSize -
493 sizeof (EFI_SIGNATURE_LIST));
494 if (CertArraySizeInBytes % CertList->SignatureSize != 0) {
495 DEBUG ((
496 DEBUG_ERROR,
497 "%a: EFI_SIGNATURE_DATA array not a multiple of SignatureSize\n",
498 __FUNCTION__
499 ));
500 goto FreeCACert;
501 }
502
503 CertCount += CertArraySizeInBytes / CertList->SignatureSize;
504 ItemDataSize -= CertList->SignatureListSize;
505 }
506
507 if (CertCount == 0) {
508 DEBUG ((DEBUG_ERROR, "%a: no X509 certificates provided\n", __FUNCTION__));
509 goto FreeCACert;
510 }
511
512 //
513 // Enumerate all data and erasing the target item.
514 //
515 ItemDataSize = (UINT32)CACertSize;
516 CertList = (EFI_SIGNATURE_LIST *)CACert;
517 while ((ItemDataSize > 0) && (ItemDataSize >= CertList->SignatureListSize)) {
518 Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)CertList + sizeof (EFI_SIGNATURE_LIST) + CertList->SignatureHeaderSize);
519 CertCount = (CertList->SignatureListSize - sizeof (EFI_SIGNATURE_LIST) - CertList->SignatureHeaderSize) / CertList->SignatureSize;
520 for (Index = 0; Index < CertCount; Index++) {
521 //
522 // EfiTlsConfigDataTypeCACertificate
523 //
524 Status = HttpInstance->TlsConfiguration->SetData (
525 HttpInstance->TlsConfiguration,
526 EfiTlsConfigDataTypeCACertificate,
527 Cert->SignatureData,
528 CertList->SignatureSize - sizeof (Cert->SignatureOwner)
529 );
530 if (EFI_ERROR (Status)) {
531 goto FreeCACert;
532 }
533
534 Cert = (EFI_SIGNATURE_DATA *)((UINT8 *)Cert + CertList->SignatureSize);
535 }
536
537 ItemDataSize -= CertList->SignatureListSize;
538 CertList = (EFI_SIGNATURE_LIST *)((UINT8 *)CertList + CertList->SignatureListSize);
539 }
540
541 FreeCACert:
542 FreePool (CACert);
543 return Status;
544 }
545
546 /**
547 Read the HttpTlsCipherList variable and configure it for HTTPS session.
548
549 @param[in, out] HttpInstance The HTTP instance private data.
550
551 @retval EFI_SUCCESS The prefered HTTP TLS CipherList is configured.
552 @retval EFI_NOT_FOUND Fail to get 'HttpTlsCipherList' variable.
553 @retval EFI_INVALID_PARAMETER The contents of variable are invalid.
554 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
555
556 @retval Others Other error as indicated.
557
558 **/
559 EFI_STATUS
560 TlsConfigCipherList (
561 IN OUT HTTP_PROTOCOL *HttpInstance
562 )
563 {
564 EFI_STATUS Status;
565 UINT8 *CipherList;
566 UINTN CipherListSize;
567
568 CipherList = NULL;
569 CipherListSize = 0;
570
571 //
572 // Try to read the HttpTlsCipherList variable.
573 //
574 Status = gRT->GetVariable (
575 EDKII_HTTP_TLS_CIPHER_LIST_VARIABLE,
576 &gEdkiiHttpTlsCipherListGuid,
577 NULL,
578 &CipherListSize,
579 NULL
580 );
581 ASSERT (EFI_ERROR (Status));
582 if (Status != EFI_BUFFER_TOO_SMALL) {
583 return Status;
584 }
585
586 if (CipherListSize % sizeof (EFI_TLS_CIPHER) != 0) {
587 return EFI_INVALID_PARAMETER;
588 }
589
590 //
591 // Allocate buffer and read the config variable.
592 //
593 CipherList = AllocatePool (CipherListSize);
594 if (CipherList == NULL) {
595 return EFI_OUT_OF_RESOURCES;
596 }
597
598 Status = gRT->GetVariable (
599 EDKII_HTTP_TLS_CIPHER_LIST_VARIABLE,
600 &gEdkiiHttpTlsCipherListGuid,
601 NULL,
602 &CipherListSize,
603 CipherList
604 );
605 if (EFI_ERROR (Status)) {
606 //
607 // GetVariable still error or the variable is corrupted.
608 //
609 goto ON_EXIT;
610 }
611
612 ASSERT (CipherList != NULL);
613
614 Status = HttpInstance->Tls->SetSessionData (
615 HttpInstance->Tls,
616 EfiTlsCipherList,
617 CipherList,
618 CipherListSize
619 );
620
621 ON_EXIT:
622 FreePool (CipherList);
623
624 return Status;
625 }
626
627 /**
628 Configure TLS session data.
629
630 @param[in, out] HttpInstance The HTTP instance private data.
631
632 @retval EFI_SUCCESS TLS session data is configured.
633 @retval Others Other error as indicated.
634
635 **/
636 EFI_STATUS
637 EFIAPI
638 TlsConfigureSession (
639 IN OUT HTTP_PROTOCOL *HttpInstance
640 )
641 {
642 EFI_STATUS Status;
643
644 //
645 // TlsConfigData initialization
646 //
647 HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient;
648 HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER;
649 HttpInstance->TlsConfigData.VerifyHost.Flags = EFI_TLS_VERIFY_FLAG_NONE;
650 HttpInstance->TlsConfigData.VerifyHost.HostName = HttpInstance->RemoteHost;
651 HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted;
652
653 //
654 // EfiTlsConnectionEnd,
655 // EfiTlsVerifyMethod,
656 // EfiTlsVerifyHost,
657 // EfiTlsSessionState
658 //
659 Status = HttpInstance->Tls->SetSessionData (
660 HttpInstance->Tls,
661 EfiTlsConnectionEnd,
662 &(HttpInstance->TlsConfigData.ConnectionEnd),
663 sizeof (EFI_TLS_CONNECTION_END)
664 );
665 if (EFI_ERROR (Status)) {
666 return Status;
667 }
668
669 Status = HttpInstance->Tls->SetSessionData (
670 HttpInstance->Tls,
671 EfiTlsVerifyMethod,
672 &HttpInstance->TlsConfigData.VerifyMethod,
673 sizeof (EFI_TLS_VERIFY)
674 );
675 if (EFI_ERROR (Status)) {
676 return Status;
677 }
678
679 Status = HttpInstance->Tls->SetSessionData (
680 HttpInstance->Tls,
681 EfiTlsVerifyHost,
682 &HttpInstance->TlsConfigData.VerifyHost,
683 sizeof (EFI_TLS_VERIFY_HOST)
684 );
685 if (EFI_ERROR (Status)) {
686 return Status;
687 }
688
689 Status = HttpInstance->Tls->SetSessionData (
690 HttpInstance->Tls,
691 EfiTlsSessionState,
692 &(HttpInstance->TlsConfigData.SessionState),
693 sizeof (EFI_TLS_SESSION_STATE)
694 );
695 if (EFI_ERROR (Status)) {
696 return Status;
697 }
698
699 //
700 // Tls Cipher List
701 //
702 Status = TlsConfigCipherList (HttpInstance);
703 if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
704 DEBUG ((DEBUG_ERROR, "TlsConfigCipherList: return %r error.\n", Status));
705 return Status;
706 }
707
708 //
709 // Tls Config Certificate
710 //
711 Status = TlsConfigCertificate (HttpInstance);
712 if (EFI_ERROR (Status)) {
713 DEBUG ((DEBUG_ERROR, "TLS Certificate Config Error!\n"));
714 return Status;
715 }
716
717 //
718 // TlsCreateTxRxEvent
719 //
720 Status = TlsCreateTxRxEvent (HttpInstance);
721 if (EFI_ERROR (Status)) {
722 goto ERROR;
723 }
724
725 return Status;
726
727 ERROR:
728 TlsCloseTxRxEvent (HttpInstance);
729
730 return Status;
731 }
732
733 /**
734 Transmit the Packet by processing the associated HTTPS token.
735
736 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
737 @param[in] Packet The packet to transmit.
738
739 @retval EFI_SUCCESS The packet is transmitted.
740 @retval EFI_INVALID_PARAMETER HttpInstance is NULL or Packet is NULL.
741 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
742 @retval EFI_DEVICE_ERROR An unexpected system or network error occurred.
743 @retval Others Other errors as indicated.
744
745 **/
746 EFI_STATUS
747 EFIAPI
748 TlsCommonTransmit (
749 IN OUT HTTP_PROTOCOL *HttpInstance,
750 IN NET_BUF *Packet
751 )
752 {
753 EFI_STATUS Status;
754 VOID *Data;
755 UINTN Size;
756
757 if ((HttpInstance == NULL) || (Packet == NULL)) {
758 return EFI_INVALID_PARAMETER;
759 }
760
761 if (!HttpInstance->LocalAddressIsIPv6) {
762 Size = sizeof (EFI_TCP4_TRANSMIT_DATA) +
763 (Packet->BlockOpNum - 1) * sizeof (EFI_TCP4_FRAGMENT_DATA);
764 } else {
765 Size = sizeof (EFI_TCP6_TRANSMIT_DATA) +
766 (Packet->BlockOpNum - 1) * sizeof (EFI_TCP6_FRAGMENT_DATA);
767 }
768
769 Data = AllocatePool (Size);
770 if (Data == NULL) {
771 return EFI_OUT_OF_RESOURCES;
772 }
773
774 if (!HttpInstance->LocalAddressIsIPv6) {
775 ((EFI_TCP4_TRANSMIT_DATA *)Data)->Push = TRUE;
776 ((EFI_TCP4_TRANSMIT_DATA *)Data)->Urgent = FALSE;
777 ((EFI_TCP4_TRANSMIT_DATA *)Data)->DataLength = Packet->TotalSize;
778
779 //
780 // Build the fragment table.
781 //
782 ((EFI_TCP4_TRANSMIT_DATA *)Data)->FragmentCount = Packet->BlockOpNum;
783
784 NetbufBuildExt (
785 Packet,
786 (NET_FRAGMENT *)&((EFI_TCP4_TRANSMIT_DATA *)Data)->FragmentTable[0],
787 &((EFI_TCP4_TRANSMIT_DATA *)Data)->FragmentCount
788 );
789
790 HttpInstance->Tcp4TlsTxToken.Packet.TxData = (EFI_TCP4_TRANSMIT_DATA *)Data;
791
792 Status = EFI_DEVICE_ERROR;
793
794 //
795 // Transmit the packet.
796 //
797 Status = HttpInstance->Tcp4->Transmit (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsTxToken);
798 if (EFI_ERROR (Status)) {
799 goto ON_EXIT;
800 }
801
802 while (!HttpInstance->TlsIsTxDone) {
803 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
804 }
805
806 HttpInstance->TlsIsTxDone = FALSE;
807 Status = HttpInstance->Tcp4TlsTxToken.CompletionToken.Status;
808 } else {
809 ((EFI_TCP6_TRANSMIT_DATA *)Data)->Push = TRUE;
810 ((EFI_TCP6_TRANSMIT_DATA *)Data)->Urgent = FALSE;
811 ((EFI_TCP6_TRANSMIT_DATA *)Data)->DataLength = Packet->TotalSize;
812
813 //
814 // Build the fragment table.
815 //
816 ((EFI_TCP6_TRANSMIT_DATA *)Data)->FragmentCount = Packet->BlockOpNum;
817
818 NetbufBuildExt (
819 Packet,
820 (NET_FRAGMENT *)&((EFI_TCP6_TRANSMIT_DATA *)Data)->FragmentTable[0],
821 &((EFI_TCP6_TRANSMIT_DATA *)Data)->FragmentCount
822 );
823
824 HttpInstance->Tcp6TlsTxToken.Packet.TxData = (EFI_TCP6_TRANSMIT_DATA *)Data;
825
826 Status = EFI_DEVICE_ERROR;
827
828 //
829 // Transmit the packet.
830 //
831 Status = HttpInstance->Tcp6->Transmit (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsTxToken);
832 if (EFI_ERROR (Status)) {
833 goto ON_EXIT;
834 }
835
836 while (!HttpInstance->TlsIsTxDone) {
837 HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
838 }
839
840 HttpInstance->TlsIsTxDone = FALSE;
841 Status = HttpInstance->Tcp6TlsTxToken.CompletionToken.Status;
842 }
843
844 ON_EXIT:
845 FreePool (Data);
846
847 return Status;
848 }
849
850 /**
851 Receive the Packet by processing the associated HTTPS token.
852
853 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
854 @param[in] Packet The packet to transmit.
855 @param[in] Timeout The time to wait for connection done.
856
857 @retval EFI_SUCCESS The Packet is received.
858 @retval EFI_INVALID_PARAMETER HttpInstance is NULL or Packet is NULL.
859 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
860 @retval EFI_TIMEOUT The operation is time out.
861 @retval Others Other error as indicated.
862
863 **/
864 EFI_STATUS
865 EFIAPI
866 TlsCommonReceive (
867 IN OUT HTTP_PROTOCOL *HttpInstance,
868 IN NET_BUF *Packet,
869 IN EFI_EVENT Timeout
870 )
871 {
872 EFI_TCP4_RECEIVE_DATA *Tcp4RxData;
873 EFI_TCP6_RECEIVE_DATA *Tcp6RxData;
874 EFI_STATUS Status;
875 NET_FRAGMENT *Fragment;
876 UINT32 FragmentCount;
877 UINT32 CurrentFragment;
878
879 Tcp4RxData = NULL;
880 Tcp6RxData = NULL;
881
882 if ((HttpInstance == NULL) || (Packet == NULL)) {
883 return EFI_INVALID_PARAMETER;
884 }
885
886 FragmentCount = Packet->BlockOpNum;
887 Fragment = AllocatePool (FragmentCount * sizeof (NET_FRAGMENT));
888 if (Fragment == NULL) {
889 Status = EFI_OUT_OF_RESOURCES;
890 goto ON_EXIT;
891 }
892
893 //
894 // Build the fragment table.
895 //
896 NetbufBuildExt (Packet, Fragment, &FragmentCount);
897
898 if (!HttpInstance->LocalAddressIsIPv6) {
899 Tcp4RxData = HttpInstance->Tcp4TlsRxToken.Packet.RxData;
900 if (Tcp4RxData == NULL) {
901 return EFI_INVALID_PARAMETER;
902 }
903
904 Tcp4RxData->FragmentCount = 1;
905 } else {
906 Tcp6RxData = HttpInstance->Tcp6TlsRxToken.Packet.RxData;
907 if (Tcp6RxData == NULL) {
908 return EFI_INVALID_PARAMETER;
909 }
910
911 Tcp6RxData->FragmentCount = 1;
912 }
913
914 CurrentFragment = 0;
915 Status = EFI_SUCCESS;
916
917 while (CurrentFragment < FragmentCount) {
918 if (!HttpInstance->LocalAddressIsIPv6) {
919 Tcp4RxData->DataLength = Fragment[CurrentFragment].Len;
920 Tcp4RxData->FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len;
921 Tcp4RxData->FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk;
922 Status = HttpInstance->Tcp4->Receive (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken);
923 } else {
924 Tcp6RxData->DataLength = Fragment[CurrentFragment].Len;
925 Tcp6RxData->FragmentTable[0].FragmentLength = Fragment[CurrentFragment].Len;
926 Tcp6RxData->FragmentTable[0].FragmentBuffer = Fragment[CurrentFragment].Bulk;
927 Status = HttpInstance->Tcp6->Receive (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken);
928 }
929
930 if (EFI_ERROR (Status)) {
931 goto ON_EXIT;
932 }
933
934 while (!HttpInstance->TlsIsRxDone && ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout)))) {
935 //
936 // Poll until some data is received or an error occurs.
937 //
938 if (!HttpInstance->LocalAddressIsIPv6) {
939 HttpInstance->Tcp4->Poll (HttpInstance->Tcp4);
940 } else {
941 HttpInstance->Tcp6->Poll (HttpInstance->Tcp6);
942 }
943 }
944
945 if (!HttpInstance->TlsIsRxDone) {
946 //
947 // Timeout occurs, cancel the receive request.
948 //
949 if (!HttpInstance->LocalAddressIsIPv6) {
950 HttpInstance->Tcp4->Cancel (HttpInstance->Tcp4, &HttpInstance->Tcp4TlsRxToken.CompletionToken);
951 } else {
952 HttpInstance->Tcp6->Cancel (HttpInstance->Tcp6, &HttpInstance->Tcp6TlsRxToken.CompletionToken);
953 }
954
955 Status = EFI_TIMEOUT;
956 goto ON_EXIT;
957 } else {
958 HttpInstance->TlsIsRxDone = FALSE;
959 }
960
961 if (!HttpInstance->LocalAddressIsIPv6) {
962 Status = HttpInstance->Tcp4TlsRxToken.CompletionToken.Status;
963 if (EFI_ERROR (Status)) {
964 goto ON_EXIT;
965 }
966
967 Fragment[CurrentFragment].Len -= Tcp4RxData->FragmentTable[0].FragmentLength;
968 if (Fragment[CurrentFragment].Len == 0) {
969 CurrentFragment++;
970 } else {
971 Fragment[CurrentFragment].Bulk += Tcp4RxData->FragmentTable[0].FragmentLength;
972 }
973 } else {
974 Status = HttpInstance->Tcp6TlsRxToken.CompletionToken.Status;
975 if (EFI_ERROR (Status)) {
976 goto ON_EXIT;
977 }
978
979 Fragment[CurrentFragment].Len -= Tcp6RxData->FragmentTable[0].FragmentLength;
980 if (Fragment[CurrentFragment].Len == 0) {
981 CurrentFragment++;
982 } else {
983 Fragment[CurrentFragment].Bulk += Tcp6RxData->FragmentTable[0].FragmentLength;
984 }
985 }
986 }
987
988 ON_EXIT:
989
990 if (Fragment != NULL) {
991 FreePool (Fragment);
992 }
993
994 return Status;
995 }
996
997 /**
998 Receive one TLS PDU. An TLS PDU contains an TLS record header and its
999 corresponding record data. These two parts will be put into two blocks of buffers in the
1000 net buffer.
1001
1002 @param[in, out] HttpInstance Pointer to HTTP_PROTOCOL structure.
1003 @param[out] Pdu The received TLS PDU.
1004 @param[in] Timeout The time to wait for connection done.
1005
1006 @retval EFI_SUCCESS An TLS PDU is received.
1007 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1008 @retval EFI_PROTOCOL_ERROR An unexpected TLS packet was received.
1009 @retval Others Other errors as indicated.
1010
1011 **/
1012 EFI_STATUS
1013 EFIAPI
1014 TlsReceiveOnePdu (
1015 IN OUT HTTP_PROTOCOL *HttpInstance,
1016 OUT NET_BUF **Pdu,
1017 IN EFI_EVENT Timeout
1018 )
1019 {
1020 EFI_STATUS Status;
1021
1022 LIST_ENTRY *NbufList;
1023
1024 UINT32 Len;
1025
1026 NET_BUF *PduHdr;
1027 UINT8 *Header;
1028 TLS_RECORD_HEADER RecordHeader;
1029
1030 NET_BUF *DataSeg;
1031
1032 NbufList = NULL;
1033 PduHdr = NULL;
1034 Header = NULL;
1035 DataSeg = NULL;
1036
1037 NbufList = AllocatePool (sizeof (LIST_ENTRY));
1038 if (NbufList == NULL) {
1039 return EFI_OUT_OF_RESOURCES;
1040 }
1041
1042 InitializeListHead (NbufList);
1043
1044 //
1045 // Allocate buffer to receive one TLS header.
1046 //
1047 Len = TLS_RECORD_HEADER_LENGTH;
1048 PduHdr = NetbufAlloc (Len);
1049 if (PduHdr == NULL) {
1050 Status = EFI_OUT_OF_RESOURCES;
1051 goto ON_EXIT;
1052 }
1053
1054 Header = NetbufAllocSpace (PduHdr, Len, NET_BUF_TAIL);
1055 if (Header == NULL) {
1056 Status = EFI_OUT_OF_RESOURCES;
1057 goto ON_EXIT;
1058 }
1059
1060 //
1061 // First step, receive one TLS header.
1062 //
1063 Status = TlsCommonReceive (HttpInstance, PduHdr, Timeout);
1064 if (EFI_ERROR (Status)) {
1065 goto ON_EXIT;
1066 }
1067
1068 RecordHeader = *(TLS_RECORD_HEADER *)Header;
1069 if (((RecordHeader.ContentType == TlsContentTypeHandshake) ||
1070 (RecordHeader.ContentType == TlsContentTypeAlert) ||
1071 (RecordHeader.ContentType == TlsContentTypeChangeCipherSpec) ||
1072 (RecordHeader.ContentType == TlsContentTypeApplicationData)) &&
1073 (RecordHeader.Version.Major == 0x03) && /// Major versions are same.
1074 ((RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR) ||
1075 (RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR) ||
1076 (RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR))
1077 )
1078 {
1079 InsertTailList (NbufList, &PduHdr->List);
1080 } else {
1081 Status = EFI_PROTOCOL_ERROR;
1082 goto ON_EXIT;
1083 }
1084
1085 Len = SwapBytes16 (RecordHeader.Length);
1086 if (Len == 0) {
1087 //
1088 // No TLS payload.
1089 //
1090 goto FORM_PDU;
1091 }
1092
1093 //
1094 // Allocate buffer to receive one TLS payload.
1095 //
1096 DataSeg = NetbufAlloc (Len);
1097 if (DataSeg == NULL) {
1098 Status = EFI_OUT_OF_RESOURCES;
1099 goto ON_EXIT;
1100 }
1101
1102 NetbufAllocSpace (DataSeg, Len, NET_BUF_TAIL);
1103
1104 //
1105 // Second step, receive one TLS payload.
1106 //
1107 Status = TlsCommonReceive (HttpInstance, DataSeg, Timeout);
1108 if (EFI_ERROR (Status)) {
1109 goto ON_EXIT;
1110 }
1111
1112 InsertTailList (NbufList, &DataSeg->List);
1113
1114 FORM_PDU:
1115 //
1116 // Form the PDU from a list of PDU.
1117 //
1118 *Pdu = NetbufFromBufList (NbufList, 0, 0, FreeNbufList, NbufList);
1119 if (*Pdu == NULL) {
1120 Status = EFI_OUT_OF_RESOURCES;
1121 }
1122
1123 ON_EXIT:
1124
1125 if (EFI_ERROR (Status)) {
1126 //
1127 // Free the Nbufs in this NbufList and the NbufList itself.
1128 //
1129 FreeNbufList (NbufList);
1130 }
1131
1132 return Status;
1133 }
1134
1135 /**
1136 Connect one TLS session by finishing the TLS handshake process.
1137
1138 @param[in] HttpInstance The HTTP instance private data.
1139 @param[in] Timeout The time to wait for connection done.
1140
1141 @retval EFI_SUCCESS The TLS session is established.
1142 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1143 @retval EFI_ABORTED TLS session state is incorrect.
1144 @retval Others Other error as indicated.
1145
1146 **/
1147 EFI_STATUS
1148 EFIAPI
1149 TlsConnectSession (
1150 IN HTTP_PROTOCOL *HttpInstance,
1151 IN EFI_EVENT Timeout
1152 )
1153 {
1154 EFI_STATUS Status;
1155 UINT8 *BufferOut;
1156 UINTN BufferOutSize;
1157 NET_BUF *PacketOut;
1158 UINT8 *DataOut;
1159 NET_BUF *Pdu;
1160 UINT8 *BufferIn;
1161 UINTN BufferInSize;
1162 UINT8 *GetSessionDataBuffer;
1163 UINTN GetSessionDataBufferSize;
1164
1165 BufferOut = NULL;
1166 PacketOut = NULL;
1167 DataOut = NULL;
1168 Pdu = NULL;
1169 BufferIn = NULL;
1170
1171 //
1172 // Initialize TLS state.
1173 //
1174 HttpInstance->TlsSessionState = EfiTlsSessionNotStarted;
1175 Status = HttpInstance->Tls->SetSessionData (
1176 HttpInstance->Tls,
1177 EfiTlsSessionState,
1178 &(HttpInstance->TlsSessionState),
1179 sizeof (EFI_TLS_SESSION_STATE)
1180 );
1181 if (EFI_ERROR (Status)) {
1182 return Status;
1183 }
1184
1185 //
1186 // Create ClientHello
1187 //
1188 BufferOutSize = DEF_BUF_LEN;
1189 BufferOut = AllocateZeroPool (BufferOutSize);
1190 if (BufferOut == NULL) {
1191 Status = EFI_OUT_OF_RESOURCES;
1192 return Status;
1193 }
1194
1195 Status = HttpInstance->Tls->BuildResponsePacket (
1196 HttpInstance->Tls,
1197 NULL,
1198 0,
1199 BufferOut,
1200 &BufferOutSize
1201 );
1202 if (Status == EFI_BUFFER_TOO_SMALL) {
1203 FreePool (BufferOut);
1204 BufferOut = AllocateZeroPool (BufferOutSize);
1205 if (BufferOut == NULL) {
1206 Status = EFI_OUT_OF_RESOURCES;
1207 return Status;
1208 }
1209
1210 Status = HttpInstance->Tls->BuildResponsePacket (
1211 HttpInstance->Tls,
1212 NULL,
1213 0,
1214 BufferOut,
1215 &BufferOutSize
1216 );
1217 }
1218
1219 if (EFI_ERROR (Status)) {
1220 FreePool (BufferOut);
1221 return Status;
1222 }
1223
1224 //
1225 // Transmit ClientHello
1226 //
1227 PacketOut = NetbufAlloc ((UINT32)BufferOutSize);
1228 DataOut = NetbufAllocSpace (PacketOut, (UINT32)BufferOutSize, NET_BUF_TAIL);
1229 if (DataOut == NULL) {
1230 FreePool (BufferOut);
1231 return EFI_OUT_OF_RESOURCES;
1232 }
1233
1234 CopyMem (DataOut, BufferOut, BufferOutSize);
1235 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1236
1237 FreePool (BufferOut);
1238 NetbufFree (PacketOut);
1239
1240 if (EFI_ERROR (Status)) {
1241 return Status;
1242 }
1243
1244 while (HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring && \
1245 ((Timeout == NULL) || EFI_ERROR (gBS->CheckEvent (Timeout))))
1246 {
1247 //
1248 // Receive one TLS record.
1249 //
1250 Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
1251 if (EFI_ERROR (Status)) {
1252 return Status;
1253 }
1254
1255 BufferInSize = Pdu->TotalSize;
1256 BufferIn = AllocateZeroPool (BufferInSize);
1257 if (BufferIn == NULL) {
1258 NetbufFree (Pdu);
1259 Status = EFI_OUT_OF_RESOURCES;
1260 return Status;
1261 }
1262
1263 NetbufCopy (Pdu, 0, (UINT32)BufferInSize, BufferIn);
1264
1265 NetbufFree (Pdu);
1266
1267 //
1268 // Handle Receive data.
1269 //
1270 BufferOutSize = DEF_BUF_LEN;
1271 BufferOut = AllocateZeroPool (BufferOutSize);
1272 if (BufferOut == NULL) {
1273 Status = EFI_OUT_OF_RESOURCES;
1274 return Status;
1275 }
1276
1277 Status = HttpInstance->Tls->BuildResponsePacket (
1278 HttpInstance->Tls,
1279 BufferIn,
1280 BufferInSize,
1281 BufferOut,
1282 &BufferOutSize
1283 );
1284 if (Status == EFI_BUFFER_TOO_SMALL) {
1285 FreePool (BufferOut);
1286 BufferOut = AllocateZeroPool (BufferOutSize);
1287 if (BufferOut == NULL) {
1288 FreePool (BufferIn);
1289 Status = EFI_OUT_OF_RESOURCES;
1290 return Status;
1291 }
1292
1293 Status = HttpInstance->Tls->BuildResponsePacket (
1294 HttpInstance->Tls,
1295 BufferIn,
1296 BufferInSize,
1297 BufferOut,
1298 &BufferOutSize
1299 );
1300 }
1301
1302 FreePool (BufferIn);
1303
1304 if (EFI_ERROR (Status)) {
1305 FreePool (BufferOut);
1306 return Status;
1307 }
1308
1309 if (BufferOutSize != 0) {
1310 //
1311 // Transmit the response packet.
1312 //
1313 PacketOut = NetbufAlloc ((UINT32)BufferOutSize);
1314 DataOut = NetbufAllocSpace (PacketOut, (UINT32)BufferOutSize, NET_BUF_TAIL);
1315 if (DataOut == NULL) {
1316 FreePool (BufferOut);
1317 return EFI_OUT_OF_RESOURCES;
1318 }
1319
1320 CopyMem (DataOut, BufferOut, BufferOutSize);
1321
1322 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1323
1324 NetbufFree (PacketOut);
1325
1326 if (EFI_ERROR (Status)) {
1327 FreePool (BufferOut);
1328 return Status;
1329 }
1330 }
1331
1332 FreePool (BufferOut);
1333
1334 //
1335 // Get the session state, then decide whether need to continue handle received packet.
1336 //
1337 GetSessionDataBufferSize = DEF_BUF_LEN;
1338 GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1339 if (GetSessionDataBuffer == NULL) {
1340 Status = EFI_OUT_OF_RESOURCES;
1341 return Status;
1342 }
1343
1344 Status = HttpInstance->Tls->GetSessionData (
1345 HttpInstance->Tls,
1346 EfiTlsSessionState,
1347 GetSessionDataBuffer,
1348 &GetSessionDataBufferSize
1349 );
1350 if (Status == EFI_BUFFER_TOO_SMALL) {
1351 FreePool (GetSessionDataBuffer);
1352 GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1353 if (GetSessionDataBuffer == NULL) {
1354 Status = EFI_OUT_OF_RESOURCES;
1355 return Status;
1356 }
1357
1358 Status = HttpInstance->Tls->GetSessionData (
1359 HttpInstance->Tls,
1360 EfiTlsSessionState,
1361 GetSessionDataBuffer,
1362 &GetSessionDataBufferSize
1363 );
1364 }
1365
1366 if (EFI_ERROR (Status)) {
1367 FreePool (GetSessionDataBuffer);
1368 return Status;
1369 }
1370
1371 ASSERT (GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
1372 HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *)GetSessionDataBuffer;
1373
1374 FreePool (GetSessionDataBuffer);
1375
1376 if (HttpInstance->TlsSessionState == EfiTlsSessionError) {
1377 return EFI_ABORTED;
1378 }
1379 }
1380
1381 if (HttpInstance->TlsSessionState != EfiTlsSessionDataTransferring) {
1382 Status = EFI_ABORTED;
1383 }
1384
1385 return Status;
1386 }
1387
1388 /**
1389 Close the TLS session and send out the close notification message.
1390
1391 @param[in] HttpInstance The HTTP instance private data.
1392
1393 @retval EFI_SUCCESS The TLS session is closed.
1394 @retval EFI_INVALID_PARAMETER HttpInstance is NULL.
1395 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1396 @retval Others Other error as indicated.
1397
1398 **/
1399 EFI_STATUS
1400 EFIAPI
1401 TlsCloseSession (
1402 IN HTTP_PROTOCOL *HttpInstance
1403 )
1404 {
1405 EFI_STATUS Status;
1406
1407 UINT8 *BufferOut;
1408 UINTN BufferOutSize;
1409
1410 NET_BUF *PacketOut;
1411 UINT8 *DataOut;
1412
1413 Status = EFI_SUCCESS;
1414 BufferOut = NULL;
1415 PacketOut = NULL;
1416 DataOut = NULL;
1417
1418 if (HttpInstance == NULL) {
1419 return EFI_INVALID_PARAMETER;
1420 }
1421
1422 HttpInstance->TlsSessionState = EfiTlsSessionClosing;
1423
1424 Status = HttpInstance->Tls->SetSessionData (
1425 HttpInstance->Tls,
1426 EfiTlsSessionState,
1427 &(HttpInstance->TlsSessionState),
1428 sizeof (EFI_TLS_SESSION_STATE)
1429 );
1430 if (EFI_ERROR (Status)) {
1431 return Status;
1432 }
1433
1434 BufferOutSize = DEF_BUF_LEN;
1435 BufferOut = AllocateZeroPool (BufferOutSize);
1436 if (BufferOut == NULL) {
1437 Status = EFI_OUT_OF_RESOURCES;
1438 return Status;
1439 }
1440
1441 Status = HttpInstance->Tls->BuildResponsePacket (
1442 HttpInstance->Tls,
1443 NULL,
1444 0,
1445 BufferOut,
1446 &BufferOutSize
1447 );
1448 if (Status == EFI_BUFFER_TOO_SMALL) {
1449 FreePool (BufferOut);
1450 BufferOut = AllocateZeroPool (BufferOutSize);
1451 if (BufferOut == NULL) {
1452 Status = EFI_OUT_OF_RESOURCES;
1453 return Status;
1454 }
1455
1456 Status = HttpInstance->Tls->BuildResponsePacket (
1457 HttpInstance->Tls,
1458 NULL,
1459 0,
1460 BufferOut,
1461 &BufferOutSize
1462 );
1463 }
1464
1465 if (EFI_ERROR (Status)) {
1466 FreePool (BufferOut);
1467 return Status;
1468 }
1469
1470 PacketOut = NetbufAlloc ((UINT32)BufferOutSize);
1471 DataOut = NetbufAllocSpace (PacketOut, (UINT32)BufferOutSize, NET_BUF_TAIL);
1472 if (DataOut == NULL) {
1473 FreePool (BufferOut);
1474 return EFI_OUT_OF_RESOURCES;
1475 }
1476
1477 CopyMem (DataOut, BufferOut, BufferOutSize);
1478
1479 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1480
1481 FreePool (BufferOut);
1482 NetbufFree (PacketOut);
1483
1484 return Status;
1485 }
1486
1487 /**
1488 Process one message according to the CryptMode.
1489
1490 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
1491 @param[in] Message Pointer to the message buffer needed to processed.
1492 If ProcessMode is EfiTlsEncrypt, the message contain the TLS
1493 header and plain text TLS APP payload.
1494 If ProcessMode is EfiTlsDecrypt, the message contain the TLS
1495 header and cipher text TLS APP payload.
1496 @param[in] MessageSize Pointer to the message buffer size.
1497 @param[in] ProcessMode Process mode.
1498 @param[in, out] Fragment Only one Fragment returned after the Message is
1499 processed successfully.
1500 If ProcessMode is EfiTlsEncrypt, the fragment contain the TLS
1501 header and cipher text TLS APP payload.
1502 If ProcessMode is EfiTlsDecrypt, the fragment contain the TLS
1503 header and plain text TLS APP payload.
1504
1505 @retval EFI_SUCCESS Message is processed successfully.
1506 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1507 @retval Others Other errors as indicated.
1508
1509 **/
1510 EFI_STATUS
1511 EFIAPI
1512 TlsProcessMessage (
1513 IN HTTP_PROTOCOL *HttpInstance,
1514 IN UINT8 *Message,
1515 IN UINTN MessageSize,
1516 IN EFI_TLS_CRYPT_MODE ProcessMode,
1517 IN OUT NET_FRAGMENT *Fragment
1518 )
1519 {
1520 EFI_STATUS Status;
1521 UINT8 *Buffer;
1522 UINT32 BufferSize;
1523 UINT32 BytesCopied;
1524 EFI_TLS_FRAGMENT_DATA *FragmentTable;
1525 UINT32 FragmentCount;
1526 EFI_TLS_FRAGMENT_DATA *OriginalFragmentTable;
1527 UINTN Index;
1528
1529 Status = EFI_SUCCESS;
1530 Buffer = NULL;
1531 BufferSize = 0;
1532 BytesCopied = 0;
1533 FragmentTable = NULL;
1534 OriginalFragmentTable = NULL;
1535
1536 //
1537 // Rebuild fragment table from BufferIn.
1538 //
1539 FragmentCount = 1;
1540 FragmentTable = AllocateZeroPool (FragmentCount * sizeof (EFI_TLS_FRAGMENT_DATA));
1541 if (FragmentTable == NULL) {
1542 Status = EFI_OUT_OF_RESOURCES;
1543 goto ON_EXIT;
1544 }
1545
1546 FragmentTable->FragmentLength = (UINT32)MessageSize;
1547 FragmentTable->FragmentBuffer = Message;
1548
1549 //
1550 // Record the original FragmentTable.
1551 //
1552 OriginalFragmentTable = FragmentTable;
1553
1554 //
1555 // Process the Message.
1556 //
1557 Status = HttpInstance->Tls->ProcessPacket (
1558 HttpInstance->Tls,
1559 &FragmentTable,
1560 &FragmentCount,
1561 ProcessMode
1562 );
1563 if (EFI_ERROR (Status)) {
1564 goto ON_EXIT;
1565 }
1566
1567 //
1568 // Calculate the size according to FragmentTable.
1569 //
1570 for (Index = 0; Index < FragmentCount; Index++) {
1571 BufferSize += FragmentTable[Index].FragmentLength;
1572 }
1573
1574 //
1575 // Allocate buffer for processed data.
1576 //
1577 Buffer = AllocateZeroPool (BufferSize);
1578 if (Buffer == NULL) {
1579 Status = EFI_OUT_OF_RESOURCES;
1580 goto ON_EXIT;
1581 }
1582
1583 //
1584 // Copy the new FragmentTable buffer into Buffer.
1585 //
1586 for (Index = 0; Index < FragmentCount; Index++) {
1587 CopyMem (
1588 (Buffer + BytesCopied),
1589 FragmentTable[Index].FragmentBuffer,
1590 FragmentTable[Index].FragmentLength
1591 );
1592 BytesCopied += FragmentTable[Index].FragmentLength;
1593
1594 //
1595 // Free the FragmentBuffer since it has been copied.
1596 //
1597 FreePool (FragmentTable[Index].FragmentBuffer);
1598 }
1599
1600 Fragment->Len = BufferSize;
1601 Fragment->Bulk = Buffer;
1602
1603 ON_EXIT:
1604
1605 if (OriginalFragmentTable != NULL) {
1606 if ( FragmentTable == OriginalFragmentTable) {
1607 FragmentTable = NULL;
1608 }
1609
1610 FreePool (OriginalFragmentTable);
1611 OriginalFragmentTable = NULL;
1612 }
1613
1614 //
1615 // Caller has the responsibility to free the FragmentTable.
1616 //
1617 if (FragmentTable != NULL) {
1618 FreePool (FragmentTable);
1619 FragmentTable = NULL;
1620 }
1621
1622 return Status;
1623 }
1624
1625 /**
1626 Receive one fragment decrypted from one TLS record.
1627
1628 @param[in] HttpInstance Pointer to HTTP_PROTOCOL structure.
1629 @param[in, out] Fragment The received Fragment.
1630 @param[in] Timeout The time to wait for connection done.
1631
1632 @retval EFI_SUCCESS One fragment is received.
1633 @retval EFI_OUT_OF_RESOURCES Can't allocate memory resources.
1634 @retval EFI_ABORTED Something wrong decryption the message.
1635 @retval Others Other errors as indicated.
1636
1637 **/
1638 EFI_STATUS
1639 EFIAPI
1640 HttpsReceive (
1641 IN HTTP_PROTOCOL *HttpInstance,
1642 IN OUT NET_FRAGMENT *Fragment,
1643 IN EFI_EVENT Timeout
1644 )
1645 {
1646 EFI_STATUS Status;
1647 NET_BUF *Pdu;
1648 TLS_RECORD_HEADER RecordHeader;
1649 UINT8 *BufferIn;
1650 UINTN BufferInSize;
1651 NET_FRAGMENT TempFragment;
1652 UINT8 *BufferOut;
1653 UINTN BufferOutSize;
1654 NET_BUF *PacketOut;
1655 UINT8 *DataOut;
1656 UINT8 *GetSessionDataBuffer;
1657 UINTN GetSessionDataBufferSize;
1658
1659 Status = EFI_SUCCESS;
1660 Pdu = NULL;
1661 BufferIn = NULL;
1662 BufferInSize = 0;
1663 BufferOut = NULL;
1664 BufferOutSize = 0;
1665 PacketOut = NULL;
1666 DataOut = NULL;
1667 GetSessionDataBuffer = NULL;
1668 GetSessionDataBufferSize = 0;
1669
1670 //
1671 // Receive only one TLS record
1672 //
1673 Status = TlsReceiveOnePdu (HttpInstance, &Pdu, Timeout);
1674 if (EFI_ERROR (Status)) {
1675 return Status;
1676 }
1677
1678 BufferInSize = Pdu->TotalSize;
1679 BufferIn = AllocateZeroPool (BufferInSize);
1680 if (BufferIn == NULL) {
1681 Status = EFI_OUT_OF_RESOURCES;
1682 NetbufFree (Pdu);
1683 return Status;
1684 }
1685
1686 NetbufCopy (Pdu, 0, (UINT32)BufferInSize, BufferIn);
1687
1688 NetbufFree (Pdu);
1689
1690 //
1691 // Handle Receive data.
1692 //
1693 RecordHeader = *(TLS_RECORD_HEADER *)BufferIn;
1694
1695 if ((RecordHeader.ContentType == TlsContentTypeApplicationData) &&
1696 (RecordHeader.Version.Major == 0x03) &&
1697 ((RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR) ||
1698 (RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR) ||
1699 (RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR))
1700 )
1701 {
1702 //
1703 // Decrypt Packet.
1704 //
1705 Status = TlsProcessMessage (
1706 HttpInstance,
1707 BufferIn,
1708 BufferInSize,
1709 EfiTlsDecrypt,
1710 &TempFragment
1711 );
1712
1713 FreePool (BufferIn);
1714
1715 if (EFI_ERROR (Status)) {
1716 if (Status == EFI_ABORTED) {
1717 //
1718 // Something wrong decryption the message.
1719 // BuildResponsePacket() will be called to generate Error Alert message and send it out.
1720 //
1721 BufferOutSize = DEF_BUF_LEN;
1722 BufferOut = AllocateZeroPool (BufferOutSize);
1723 if (BufferOut == NULL) {
1724 Status = EFI_OUT_OF_RESOURCES;
1725 return Status;
1726 }
1727
1728 Status = HttpInstance->Tls->BuildResponsePacket (
1729 HttpInstance->Tls,
1730 NULL,
1731 0,
1732 BufferOut,
1733 &BufferOutSize
1734 );
1735 if (Status == EFI_BUFFER_TOO_SMALL) {
1736 FreePool (BufferOut);
1737 BufferOut = AllocateZeroPool (BufferOutSize);
1738 if (BufferOut == NULL) {
1739 Status = EFI_OUT_OF_RESOURCES;
1740 return Status;
1741 }
1742
1743 Status = HttpInstance->Tls->BuildResponsePacket (
1744 HttpInstance->Tls,
1745 NULL,
1746 0,
1747 BufferOut,
1748 &BufferOutSize
1749 );
1750 }
1751
1752 if (EFI_ERROR (Status)) {
1753 FreePool (BufferOut);
1754 return Status;
1755 }
1756
1757 if (BufferOutSize != 0) {
1758 PacketOut = NetbufAlloc ((UINT32)BufferOutSize);
1759 DataOut = NetbufAllocSpace (PacketOut, (UINT32)BufferOutSize, NET_BUF_TAIL);
1760 if (DataOut == NULL) {
1761 FreePool (BufferOut);
1762 return EFI_OUT_OF_RESOURCES;
1763 }
1764
1765 CopyMem (DataOut, BufferOut, BufferOutSize);
1766
1767 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1768
1769 NetbufFree (PacketOut);
1770 }
1771
1772 FreePool (BufferOut);
1773
1774 if (EFI_ERROR (Status)) {
1775 return Status;
1776 }
1777
1778 return EFI_ABORTED;
1779 }
1780
1781 return Status;
1782 }
1783
1784 //
1785 // Parsing buffer.
1786 //
1787 ASSERT (((TLS_RECORD_HEADER *)(TempFragment.Bulk))->ContentType == TlsContentTypeApplicationData);
1788
1789 BufferInSize = ((TLS_RECORD_HEADER *)(TempFragment.Bulk))->Length;
1790 BufferIn = AllocateZeroPool (BufferInSize);
1791 if (BufferIn == NULL) {
1792 Status = EFI_OUT_OF_RESOURCES;
1793 return Status;
1794 }
1795
1796 CopyMem (BufferIn, TempFragment.Bulk + TLS_RECORD_HEADER_LENGTH, BufferInSize);
1797
1798 //
1799 // Free the buffer in TempFragment.
1800 //
1801 FreePool (TempFragment.Bulk);
1802 } else if ((RecordHeader.ContentType == TlsContentTypeAlert) &&
1803 (RecordHeader.Version.Major == 0x03) &&
1804 ((RecordHeader.Version.Minor == TLS10_PROTOCOL_VERSION_MINOR) ||
1805 (RecordHeader.Version.Minor == TLS11_PROTOCOL_VERSION_MINOR) ||
1806 (RecordHeader.Version.Minor == TLS12_PROTOCOL_VERSION_MINOR))
1807 )
1808 {
1809 BufferOutSize = DEF_BUF_LEN;
1810 BufferOut = AllocateZeroPool (BufferOutSize);
1811 if (BufferOut == NULL) {
1812 FreePool (BufferIn);
1813 Status = EFI_OUT_OF_RESOURCES;
1814 return Status;
1815 }
1816
1817 Status = HttpInstance->Tls->BuildResponsePacket (
1818 HttpInstance->Tls,
1819 BufferIn,
1820 BufferInSize,
1821 BufferOut,
1822 &BufferOutSize
1823 );
1824 if (Status == EFI_BUFFER_TOO_SMALL) {
1825 FreePool (BufferOut);
1826 BufferOut = AllocateZeroPool (BufferOutSize);
1827 if (BufferOut == NULL) {
1828 FreePool (BufferIn);
1829 Status = EFI_OUT_OF_RESOURCES;
1830 return Status;
1831 }
1832
1833 Status = HttpInstance->Tls->BuildResponsePacket (
1834 HttpInstance->Tls,
1835 BufferIn,
1836 BufferInSize,
1837 BufferOut,
1838 &BufferOutSize
1839 );
1840 }
1841
1842 FreePool (BufferIn);
1843
1844 if (EFI_ERROR (Status)) {
1845 FreePool (BufferOut);
1846 return Status;
1847 }
1848
1849 if (BufferOutSize != 0) {
1850 PacketOut = NetbufAlloc ((UINT32)BufferOutSize);
1851 DataOut = NetbufAllocSpace (PacketOut, (UINT32)BufferOutSize, NET_BUF_TAIL);
1852 if (DataOut == NULL) {
1853 FreePool (BufferOut);
1854 return EFI_OUT_OF_RESOURCES;
1855 }
1856
1857 CopyMem (DataOut, BufferOut, BufferOutSize);
1858
1859 Status = TlsCommonTransmit (HttpInstance, PacketOut);
1860
1861 NetbufFree (PacketOut);
1862 }
1863
1864 FreePool (BufferOut);
1865
1866 //
1867 // Get the session state.
1868 //
1869 GetSessionDataBufferSize = DEF_BUF_LEN;
1870 GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1871 if (GetSessionDataBuffer == NULL) {
1872 Status = EFI_OUT_OF_RESOURCES;
1873 return Status;
1874 }
1875
1876 Status = HttpInstance->Tls->GetSessionData (
1877 HttpInstance->Tls,
1878 EfiTlsSessionState,
1879 GetSessionDataBuffer,
1880 &GetSessionDataBufferSize
1881 );
1882 if (Status == EFI_BUFFER_TOO_SMALL) {
1883 FreePool (GetSessionDataBuffer);
1884 GetSessionDataBuffer = AllocateZeroPool (GetSessionDataBufferSize);
1885 if (GetSessionDataBuffer == NULL) {
1886 Status = EFI_OUT_OF_RESOURCES;
1887 return Status;
1888 }
1889
1890 Status = HttpInstance->Tls->GetSessionData (
1891 HttpInstance->Tls,
1892 EfiTlsSessionState,
1893 GetSessionDataBuffer,
1894 &GetSessionDataBufferSize
1895 );
1896 }
1897
1898 if (EFI_ERROR (Status)) {
1899 FreePool (GetSessionDataBuffer);
1900 return Status;
1901 }
1902
1903 ASSERT (GetSessionDataBufferSize == sizeof (EFI_TLS_SESSION_STATE));
1904 HttpInstance->TlsSessionState = *(EFI_TLS_SESSION_STATE *)GetSessionDataBuffer;
1905
1906 FreePool (GetSessionDataBuffer);
1907
1908 if (HttpInstance->TlsSessionState == EfiTlsSessionError) {
1909 DEBUG ((DEBUG_ERROR, "TLS Session State Error!\n"));
1910 return EFI_ABORTED;
1911 }
1912
1913 BufferIn = NULL;
1914 BufferInSize = 0;
1915 }
1916
1917 Fragment->Bulk = BufferIn;
1918 Fragment->Len = (UINT32)BufferInSize;
1919
1920 return Status;
1921 }