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