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