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