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