From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga14.intel.com (mga14.intel.com [192.55.52.115]) by mx.groups.io with SMTP id smtpd.web08.1829.1662588400044650735 for ; Wed, 07 Sep 2022 15:06:40 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=HV5Q2fHq; spf=permerror, err=too many SPF records (domain: intel.com, ip: 192.55.52.115, mailfrom: saloni.kasbekar@intel.com) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1662588399; x=1694124399; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=DD2UkxgZ/vSIxy8HEwCejOhkH1D9O7CnXErkwConzHs=; b=HV5Q2fHqGEbH6BzwV8WIRqMCydUjluraqWYOjfaDayH3PHWjI9bqeVgX uey2TC2yW4jUnrq+52ua7Ce3EnUrTl9Mdd2qJXgFCSN+gxlxqufpc2GBD OL1lmTX5O2RJlc69LYhuP8e1qo3ZpqeY4XjFDBQhSQYyKak7+VRP3Qf2M Amquuo8DN+CSsV3KuJEdWrNS0cva45H9Fg4dl041gRXIzUSdnSDfmxqFh D2ZhzxuaR/hmbxC9CPDunsHR1H/t+8o1uTCRn2yiL+ahem/NK7djJ2z7B aa1a0w5Pqf2ikDgRWWDyPN1xNhAStZdspKY1cOhS/WcvmvlmOR9nECRxy A==; X-IronPort-AV: E=McAfee;i="6500,9779,10463"; a="297008231" X-IronPort-AV: E=Sophos;i="5.93,298,1654585200"; d="scan'208";a="297008231" Received: from fmsmga006.fm.intel.com ([10.253.24.20]) by fmsmga103.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Sep 2022 15:06:26 -0700 X-IronPort-AV: E=Sophos;i="5.93,298,1654585200"; d="scan'208";a="859803689" Received: from fmbiosdev02.amr.corp.intel.com ([10.80.127.10]) by fmsmga006-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Sep 2022 15:06:26 -0700 From: "Saloni Kasbekar" To: devel@edk2.groups.io Cc: Saloni Kasbekar , Maciej Rabeda , Wu Jiaxin , Siyuan Fu , Jian J Wang , Liming Gao Subject: [PATCH v4 1/1] NetworkPkg/HttpBootDxe: Add Support for HTTPS Proxy Server for HTTP Boot Date: Wed, 7 Sep 2022 15:06:21 -0700 Message-Id: <793a7931886b6478cc9009b9a8b79ad7a705eb9b.1662588341.git.saloni.kasbekar@intel.com> X-Mailer: git-send-email 2.36.1.windows.1 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit Add CONNECT HTTP command to create a tunnel from Proxy to EndPoint Server. Add support to connect through proxy server using multi-URI DevicePath sent to the Boot Manager. Cc: Maciej Rabeda Cc: Wu Jiaxin Cc: Siyuan Fu Cc: Jian J Wang Cc: Liming Gao Signed-off-by: Saloni Kasbekar --- .../Library/UefiBootManagerLib/BmBoot.c | 28 +++ .../UefiBootManagerLib/BmBootDescription.c | 4 +- MdePkg/Include/Protocol/Http.h | 5 + NetworkPkg/HttpBootDxe/HttpBootClient.c | 206 ++++++++++++++++- NetworkPkg/HttpBootDxe/HttpBootClient.h | 15 ++ NetworkPkg/HttpBootDxe/HttpBootDxe.h | 6 + NetworkPkg/HttpBootDxe/HttpBootImpl.c | 211 +++++++++++++----- NetworkPkg/HttpBootDxe/HttpBootImpl.h | 8 + NetworkPkg/HttpBootDxe/HttpBootSupport.c | 18 +- NetworkPkg/HttpBootDxe/HttpBootSupport.h | 8 +- NetworkPkg/HttpDxe/HttpDriver.h | 2 + NetworkPkg/HttpDxe/HttpDxe.inf | 1 + NetworkPkg/HttpDxe/HttpImpl.c | 131 +++++++++-- NetworkPkg/HttpDxe/HttpProto.c | 41 ++-- NetworkPkg/HttpDxe/HttpProto.h | 14 +- NetworkPkg/HttpDxe/HttpsSupport.c | 14 +- NetworkPkg/Library/DxeHttpLib/DxeHttpLib.c | 5 + 17 files changed, 607 insertions(+), 110 deletions(-) diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c index 962892d38f14..fdef1ba292e2 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmBoot.c @@ -1513,6 +1513,9 @@ BmExpandLoadFiles ( UINTN HandleCount; UINTN Index; EFI_DEVICE_PATH_PROTOCOL *Node; + URI_DEVICE_PATH *NullUriPath; + + NullUriPath = NULL; // // Get file buffer from load file instance. @@ -1545,11 +1548,36 @@ BmExpandLoadFiles ( for (Index = 0; Index < HandleCount; Index++) { if (BmMatchHttpBootDevicePath (DevicePathFromHandle (Handles[Index]), FilePath)) { + // + // Matches HTTP Boot Device Path described as + // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)[/Dns(...)]/Uri(...) + // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)[/Dns(...)]/Uri(...) + // + Handle = Handles[Index]; + goto Done; + } + } + + NullUriPath = (URI_DEVICE_PATH *)CreateDeviceNode ( + MESSAGING_DEVICE_PATH, + MSG_URI_DP, + (UINT16)(sizeof (URI_DEVICE_PATH)) + ); + for (Index = 0; Index < HandleCount; Index++) { + if (BmMatchHttpBootDevicePath (AppendDevicePathNode (DevicePathFromHandle (Handles[Index]), (EFI_DEVICE_PATH_PROTOCOL *)NullUriPath), FilePath)) { + // + // Matches HTTP Boot Device Path described as + // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)[/Dns(...)]/Uri(...)/Uri(...) + // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)[/Dns(...)]/Uri(...)/Uri(...) + // Handle = Handles[Index]; break; } } + FreePool (NullUriPath); + +Done: if (Handles != NULL) { FreePool (Handles); } diff --git a/MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c b/MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c index fac33b9ee915..19b7cd14575f 100644 --- a/MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c +++ b/MdeModulePkg/Library/UefiBootManagerLib/BmBootDescription.c @@ -412,8 +412,8 @@ BmGetNetworkDescription ( // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...) // // The HTTP device path is like: - // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)[/Dns(...)]/Uri(...) - // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)[/Dns(...)]/Uri(...) + // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)[/Dns(...)]/Uri(...)[/Uri(...)] + // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)[/Dns(...)]/Uri(...)[/Uri(...)] // while (!IsDevicePathEnd (DevicePath) && ((DevicePathType (DevicePath) != MESSAGING_DEVICE_PATH) || diff --git a/MdePkg/Include/Protocol/Http.h b/MdePkg/Include/Protocol/Http.h index 28e622159392..d47092c58e5a 100644 --- a/MdePkg/Include/Protocol/Http.h +++ b/MdePkg/Include/Protocol/Http.h @@ -191,6 +191,11 @@ typedef struct { /// is assumed. See RFC 3986 for more details on URI syntax. /// CHAR16 *Url; + /// + /// The URI of an endpoint host if the Url field contains the address of a proxy server. + /// This field will be NULL there is no proxy server in the device path. + /// + CHAR16 *EndPointUrl; } EFI_HTTP_REQUEST_DATA; /// diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.c b/NetworkPkg/HttpBootDxe/HttpBootClient.c index 40f64fcb6bf8..2bdf07560382 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootClient.c +++ b/NetworkPkg/HttpBootDxe/HttpBootClient.c @@ -901,6 +901,188 @@ HttpBootGetBootFileCallback ( return EFI_SUCCESS; } +/** + This function establishes a connection through a proxy server + + @param[in] Private The pointer to the driver's private data. + + @retval EFI_SUCCESS Connection successful. + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources + @retval Others Unexpected error happened. + +**/ +EFI_STATUS +HttpBootConnectProxy ( + IN HTTP_BOOT_PRIVATE_DATA *Private + ) +{ + EFI_STATUS Status; + EFI_HTTP_STATUS_CODE StatusCode; + CHAR8 *HostName; + EFI_HTTP_REQUEST_DATA *RequestData; + HTTP_IO_RESPONSE_DATA *ResponseData; + HTTP_IO *HttpIo; + HTTP_IO_HEADER *HttpIoHeader; + CHAR16 *Url; + CHAR16 *EndPointUrl; + UINTN UrlSize; + VOID *UrlParser; + + UrlSize = AsciiStrSize (Private->BootFileUri); + Url = AllocatePool (UrlSize * sizeof (CHAR16)); + if (Url == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + AsciiStrToUnicodeStrS (Private->BootFileUri, Url, UrlSize); + + UrlSize = AsciiStrSize (Private->EndPointUri); + EndPointUrl = AllocatePool (UrlSize * (sizeof (CHAR16))); + if (EndPointUrl == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ERROR_1; + } + + AsciiStrToUnicodeStrS (Private->EndPointUri, EndPointUrl, UrlSize); + + // + // Send HTTP request message. + // + + // + // Build HTTP header for the request, 2 headers are needed to send a CONNECT method: + // Host + // User + // + HttpIoHeader = HttpIoCreateHeader (2); + if (HttpIoHeader == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ERROR_2; + } + + // + // Add HTTP header field 1: Host (EndPoint URI) + // + Status = HttpParseUrl (Private->EndPointUri, (UINT32)AsciiStrLen (Private->EndPointUri), FALSE, &UrlParser); + if (EFI_ERROR (Status)) { + goto ERROR_2; + } + + Status = HttpUrlGetHostName ( + Private->EndPointUri, + UrlParser, + &HostName + ); + if (EFI_ERROR (Status)) { + goto ERROR_2; + } + + Status = HttpIoSetHeader ( + HttpIoHeader, + HTTP_HEADER_HOST, + HostName + ); + if (EFI_ERROR (Status)) { + goto ERROR_2; + } + + // + // Add HTTP header field 2: User-Agent + // + Status = HttpIoSetHeader ( + HttpIoHeader, + HTTP_HEADER_USER_AGENT, + HTTP_USER_AGENT_EFI_HTTP_BOOT + ); + if (EFI_ERROR (Status)) { + goto ERROR_2; + } + + // + // Build the rest of HTTP request info. + // + RequestData = AllocatePool (sizeof (EFI_HTTP_REQUEST_DATA)); + if (RequestData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ERROR_2; + } + + RequestData->Method = HttpMethodConnect; + RequestData->Url = Url; + RequestData->EndPointUrl = EndPointUrl; + + // + // Send out the request to HTTP server. + // + HttpIo = &Private->HttpIo; + Status = HttpIoSendRequest ( + HttpIo, + RequestData, + HttpIoHeader->HeaderCount, + HttpIoHeader->Headers, + 0, + NULL + ); + if (EFI_ERROR (Status)) { + goto ERROR_3; + } + + // + // Receive HTTP response message. + // + + // + // Use zero BodyLength to only receive the response headers. + // + ResponseData = AllocateZeroPool (sizeof (HTTP_IO_RESPONSE_DATA)); + if (ResponseData == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ERROR_3; + } + + Status = HttpIoRecvResponse ( + &Private->HttpIo, + TRUE, + ResponseData + ); + + if (EFI_ERROR (Status) || EFI_ERROR (ResponseData->Status)) { + if (EFI_ERROR (ResponseData->Status)) { + StatusCode = HttpIo->RspToken.Message->Data.Response->StatusCode; + HttpBootPrintErrorMessage (StatusCode); + Status = ResponseData->Status; + } + + goto ERROR_4; + } + + return Status; + +ERROR_4: + if (ResponseData != NULL) { + FreePool (ResponseData); + } + +ERROR_3: + if (RequestData != NULL) { + FreePool (RequestData); + } + +ERROR_2: + HttpIoFreeHeader (HttpIoHeader); + +ERROR_1: + if (EndPointUrl != NULL) { + FreePool (EndPointUrl); + } + + if (Url != NULL) { + FreePool (Url); + } + + return Status; +} + /** This function download the boot file by using UEFI HTTP protocol. @@ -950,6 +1132,7 @@ HttpBootGetBootFile ( UINT8 *Block; UINTN UrlSize; CHAR16 *Url; + CHAR16 *EndPointUrl; BOOLEAN IdentityMode; UINTN ReceivedSize; CHAR8 BaseAuthValue[80]; @@ -977,6 +1160,20 @@ HttpBootGetBootFile ( } AsciiStrToUnicodeStrS (Private->BootFileUri, Url, UrlSize); + + if (Private->EndPointUri != NULL) { + UrlSize = AsciiStrSize (Private->EndPointUri); + EndPointUrl = AllocatePool (UrlSize * (sizeof (CHAR16))); + if (EndPointUrl == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ERROR_1; + } + + AsciiStrToUnicodeStrS (Private->EndPointUri, EndPointUrl, UrlSize); + } else { + EndPointUrl = NULL; + } + if (!HeaderOnly && (Buffer != NULL)) { Status = HttpBootGetFileFromCache (Private, Url, BufferSize, Buffer, ImageType); if (Status != EFI_NOT_FOUND) { @@ -1106,8 +1303,9 @@ HttpBootGetBootFile ( goto ERROR_3; } - RequestData->Method = HeaderOnly ? HttpMethodHead : HttpMethodGet; - RequestData->Url = Url; + RequestData->Method = HeaderOnly ? HttpMethodHead : HttpMethodGet; + RequestData->Url = Url; + RequestData->EndPointUrl = EndPointUrl; // // 2.3 Record the request info in a temp cache item. @@ -1441,6 +1639,10 @@ ERROR_2: } ERROR_1: + if (EndPointUrl != NULL) { + FreePool (EndPointUrl); + } + if (Url != NULL) { FreePool (Url); } diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.h b/NetworkPkg/HttpBootDxe/HttpBootClient.h index 2fba71367950..fcd624f536a3 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootClient.h +++ b/NetworkPkg/HttpBootDxe/HttpBootClient.h @@ -86,6 +86,21 @@ HttpBootCreateHttpIo ( IN HTTP_BOOT_PRIVATE_DATA *Private ); +/** + This function establishes a connection through a proxy server + + @param[in] Private The pointer to the driver's private data. + + @retval EFI_SUCCESS Connection successful. + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources + @retval Others Unexpected error happened. + +**/ +EFI_STATUS +HttpBootConnectProxy ( + IN HTTP_BOOT_PRIVATE_DATA *Private + ); + /** This function download the boot file by using UEFI HTTP protocol. diff --git a/NetworkPkg/HttpBootDxe/HttpBootDxe.h b/NetworkPkg/HttpBootDxe/HttpBootDxe.h index 5ff8ad4698b2..e2eb1ffc4544 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDxe.h +++ b/NetworkPkg/HttpBootDxe/HttpBootDxe.h @@ -223,6 +223,12 @@ struct _HTTP_BOOT_PRIVATE_DATA { CHAR8 *FilePathUri; VOID *FilePathUriParser; + // + // URI string for the endpoint host if BootFileUri contains a proxy + // server in the path + // + CHAR8 *EndPointUri; + // // Cached HTTP data // diff --git a/NetworkPkg/HttpBootDxe/HttpBootImpl.c b/NetworkPkg/HttpBootDxe/HttpBootImpl.c index b4c61925b94f..d5332f2bac71 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootImpl.c +++ b/NetworkPkg/HttpBootDxe/HttpBootImpl.c @@ -116,8 +116,10 @@ HttpBootStart ( UINTN Index; EFI_STATUS Status; CHAR8 *Uri; + CHAR8 *EndPointUri; - Uri = NULL; + Uri = NULL; + EndPointUri = NULL; if ((Private == NULL) || (FilePath == NULL)) { return EFI_INVALID_PARAMETER; @@ -127,7 +129,7 @@ HttpBootStart ( // Check the URI in the input FilePath, in order to see whether it is // required to boot from a new specified boot file. // - Status = HttpBootParseFilePath (FilePath, &Uri); + Status = HttpBootParseFilePath (FilePath, &Uri, &EndPointUri); if (EFI_ERROR (Status)) { return EFI_INVALID_PARAMETER; } @@ -154,6 +156,10 @@ HttpBootStart ( FreePool (Uri); } + if (EndPointUri != NULL) { + FreePool (EndPointUri); + } + return Status; } } else { @@ -164,6 +170,10 @@ HttpBootStart ( FreePool (Uri); } + if (EndPointUri != NULL) { + FreePool (EndPointUri); + } + return EFI_ALREADY_STARTED; } } @@ -180,6 +190,10 @@ HttpBootStart ( FreePool (Uri); } + if (EndPointUri != NULL) { + FreePool (EndPointUri); + } + return EFI_UNSUPPORTED; } @@ -187,6 +201,7 @@ HttpBootStart ( // Record the specified URI and prepare the URI parser if needed. // Private->FilePathUri = Uri; + Private->EndPointUri = EndPointUri; if (Private->FilePathUri != NULL) { Status = HttpParseUrl ( Private->FilePathUri, @@ -274,6 +289,136 @@ HttpBootDhcp ( return Status; } +/** + Issue calls to HttpBootGetBootFile() based on current Boot File State + + @param[in] Private The pointer to the driver's private data. + @param[in, out] BufferSize On input the size of Buffer in bytes. On output with a return + code of EFI_SUCCESS, the amount of data transferred to + Buffer. On output with a return code of EFI_BUFFER_TOO_SMALL, + the size of Buffer required to retrieve the requested file. + @param[in] Buffer The memory buffer to transfer the file to. If Buffer is NULL, + then the size of the requested file is returned in + BufferSize. + @param[out] ImageType The image type of the downloaded file. + + @retval EFI_SUCCESS The file was loaded. + @retval EFI_INVALID_PARAMETER BufferSize is NULL or Buffer Size is not NULL but Buffer is NULL. + @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources + @retval EFI_BUFFER_TOO_SMALL The BufferSize is too small to read the current directory entry. + BufferSize has been updated with the size needed to complete + the request. + @retval EFI_ACCESS_DENIED Server authentication failed. + @retval Others Unexpected error happened. + +**/ +EFI_STATUS +HttpBootGetBootFileCaller ( + IN HTTP_BOOT_PRIVATE_DATA *Private, + IN OUT UINTN *BufferSize, + IN VOID *Buffer OPTIONAL, + OUT HTTP_BOOT_IMAGE_TYPE *ImageType + ) +{ + HTTP_GET_BOOT_FILE_STATE State; + EFI_STATUS Status; + + if (Private->BootFileSize == 0) { + if (Private->EndPointUri != NULL) { + State = ConnectToProxy; + } else { + State = GetBootFileHead; + } + } else { + State = LoadBootFile; + } + + for ( ; ;) { + switch (State) { + case GetBootFileHead: + // + // Try to use HTTP HEAD method. + // + Status = HttpBootGetBootFile ( + Private, + TRUE, + &Private->BootFileSize, + NULL, + &Private->ImageType + ); + if ((EFI_ERROR (Status)) && (Status != EFI_BUFFER_TOO_SMALL)) { + if ((Private->AuthData != NULL) && (Status == EFI_ACCESS_DENIED)) { + // + // Try to use HTTP HEAD method again since the Authentication information is provided. + // + State = GetBootFileHead; + } else { + State = GetBootFileGet; + } + } else { + State = LoadBootFile; + } + + break; + + case GetBootFileGet: + // + // Failed to get file size by HEAD method, may be trunked encoding, try HTTP GET method. + // + ASSERT (Private->BootFileSize == 0); + Status = HttpBootGetBootFile ( + Private, + FALSE, + &Private->BootFileSize, + NULL, + &Private->ImageType + ); + if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) { + State = GetBootFileError; + } else { + State = LoadBootFile; + } + + break; + + case ConnectToProxy: + Status = HttpBootConnectProxy (Private); + if (Status == EFI_SUCCESS) { + State = GetBootFileHead; + } else { + State = GetBootFileError; + } + + break; + + case LoadBootFile: + if (*BufferSize < Private->BootFileSize) { + *BufferSize = Private->BootFileSize; + *ImageType = Private->ImageType; + Status = EFI_BUFFER_TOO_SMALL; + return Status; + } + + // + // Load the boot file into Buffer + // + Status = HttpBootGetBootFile ( + Private, + FALSE, + BufferSize, + Buffer, + ImageType + ); + return Status; + + case GetBootFileError: + default: + AsciiPrint ("\n Error: Could not retrieve NBP file size from HTTP server.\n"); + return Status; + } + } +} + /** Attempt to download the boot file through HTTP message exchange. @@ -345,68 +490,10 @@ HttpBootLoadFile ( } } - if (Private->BootFileSize == 0) { - // - // Discover the information about the bootfile if we haven't. - // - - // - // Try to use HTTP HEAD method. - // - Status = HttpBootGetBootFile ( - Private, - TRUE, - &Private->BootFileSize, - NULL, - &Private->ImageType - ); - if ((Private->AuthData != NULL) && (Status == EFI_ACCESS_DENIED)) { - // - // Try to use HTTP HEAD method again since the Authentication information is provided. - // - Status = HttpBootGetBootFile ( - Private, - TRUE, - &Private->BootFileSize, - NULL, - &Private->ImageType - ); - } else if ((EFI_ERROR (Status)) && (Status != EFI_BUFFER_TOO_SMALL)) { - // - // Failed to get file size by HEAD method, may be trunked encoding, try HTTP GET method. - // - ASSERT (Private->BootFileSize == 0); - Status = HttpBootGetBootFile ( - Private, - FALSE, - &Private->BootFileSize, - NULL, - &Private->ImageType - ); - if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) { - AsciiPrint ("\n Error: Could not retrieve NBP file size from HTTP server.\n"); - goto ON_EXIT; - } - } - } - - if (*BufferSize < Private->BootFileSize) { - *BufferSize = Private->BootFileSize; - *ImageType = Private->ImageType; - Status = EFI_BUFFER_TOO_SMALL; - goto ON_EXIT; - } - // - // Load the boot file into Buffer + // Load the Boot File // - Status = HttpBootGetBootFile ( - Private, - FALSE, - BufferSize, - Buffer, - ImageType - ); + Status = HttpBootGetBootFileCaller (Private, BufferSize, Buffer, ImageType); ON_EXIT: HttpBootUninstallCallback (Private); diff --git a/NetworkPkg/HttpBootDxe/HttpBootImpl.h b/NetworkPkg/HttpBootDxe/HttpBootImpl.h index 55adc9cb500f..e4ffc3ed48e5 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootImpl.h +++ b/NetworkPkg/HttpBootDxe/HttpBootImpl.h @@ -11,6 +11,14 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #define HTTP_BOOT_CHECK_MEDIA_WAITING_TIME EFI_TIMER_PERIOD_SECONDS(20) +typedef enum { + GetBootFileHead, + GetBootFileGet, + ConnectToProxy, + LoadBootFile, + GetBootFileError +} HTTP_GET_BOOT_FILE_STATE; + /** Attempt to complete a DHCPv4 D.O.R.A or DHCPv6 S.R.A.A sequence to retrieve the boot resource information. diff --git a/NetworkPkg/HttpBootDxe/HttpBootSupport.c b/NetworkPkg/HttpBootDxe/HttpBootSupport.c index 236ef259318b..fddcf8b16746 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootSupport.c +++ b/NetworkPkg/HttpBootDxe/HttpBootSupport.c @@ -558,6 +558,7 @@ HttpBootCheckUriScheme ( @param[in] FilePath Pointer to the device path which contains a URI device path node. @param[out] UriAddress The URI address string extract from the device path. + @param[out] EndPointUriAddress The URI address string for the endpoint host if UriAddress contains the address of a proxy server @retval EFI_SUCCESS The URI string is returned. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. @@ -566,7 +567,8 @@ HttpBootCheckUriScheme ( EFI_STATUS HttpBootParseFilePath ( IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - OUT CHAR8 **UriAddress + OUT CHAR8 **UriAddress, + OUT CHAR8 **EndPointUriAddress ) { EFI_DEVICE_PATH_PROTOCOL *TempDevicePath; @@ -578,8 +580,9 @@ HttpBootParseFilePath ( return EFI_INVALID_PARAMETER; } - *UriAddress = NULL; - + Uri = NULL; + *UriAddress = NULL; + *EndPointUriAddress = NULL; // // Extract the URI address from the FilePath // @@ -601,6 +604,15 @@ HttpBootParseFilePath ( break; } + if (Uri != NULL) { + // + // Device Path with Proxy Server will be described as + // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv4(...)[/Dns(...)]/Uri(EndPointServer)/Uri(ProxyServer/FilePath) + // ....../Mac(...)[/Vlan(...)][/Wi-Fi(...)]/IPv6(...)[/Dns(...)]/Uri(EndPointServer)/Uri(ProxyServer/FilePath) + // + *EndPointUriAddress = Uri; + } + Uri = AllocatePool (UriStrLength + 1); if (Uri == NULL) { return EFI_OUT_OF_RESOURCES; diff --git a/NetworkPkg/HttpBootDxe/HttpBootSupport.h b/NetworkPkg/HttpBootDxe/HttpBootSupport.h index 3698e5593642..6228f37e3676 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootSupport.h +++ b/NetworkPkg/HttpBootDxe/HttpBootSupport.h @@ -138,8 +138,9 @@ HttpBootCheckUriScheme ( Caller need to free the buffer in the UriAddress pointer. - @param[in] FilePath Pointer to the device path which contains a URI device path node. - @param[out] UriAddress The URI address string extract from the device path. + @param[in] FilePath Pointer to the device path which contains a URI device path node. + @param[out] UriAddress The URI address string extract from the device path. + @param[out] EndPointUriAddress The URI address string for the endpoint host if UriAddress contains the address of a proxy server @retval EFI_SUCCESS The URI string is returned. @retval EFI_OUT_OF_RESOURCES Failed to allocate memory. @@ -148,7 +149,8 @@ HttpBootCheckUriScheme ( EFI_STATUS HttpBootParseFilePath ( IN EFI_DEVICE_PATH_PROTOCOL *FilePath, - OUT CHAR8 **UriAddress + OUT CHAR8 **UriAddress, + OUT CHAR8 **EndPointUriAddress ); /** diff --git a/NetworkPkg/HttpDxe/HttpDriver.h b/NetworkPkg/HttpDxe/HttpDriver.h index 01a6bb7f4b7a..e0917f431e53 100644 --- a/NetworkPkg/HttpDxe/HttpDriver.h +++ b/NetworkPkg/HttpDxe/HttpDriver.h @@ -26,6 +26,7 @@ #include #include #include +#include // // UEFI Driver Model Protocols @@ -64,6 +65,7 @@ // Driver Version // #define HTTP_DRIVER_VERSION 0xa +#define URI_STR_MAX_SIZE 255 // // Protocol instances diff --git a/NetworkPkg/HttpDxe/HttpDxe.inf b/NetworkPkg/HttpDxe/HttpDxe.inf index c9502d0bb6d0..30b7de1951d1 100644 --- a/NetworkPkg/HttpDxe/HttpDxe.inf +++ b/NetworkPkg/HttpDxe/HttpDxe.inf @@ -47,6 +47,7 @@ NetLib HttpLib DpcLib + PrintLib [Protocols] gEfiHttpServiceBindingProtocolGuid ## BY_START diff --git a/NetworkPkg/HttpDxe/HttpImpl.c b/NetworkPkg/HttpDxe/HttpImpl.c index 7c5c925cf78b..b27fb021776c 100644 --- a/NetworkPkg/HttpDxe/HttpImpl.c +++ b/NetworkPkg/HttpDxe/HttpImpl.c @@ -233,35 +233,45 @@ EfiHttpRequest ( EFI_HTTP_MESSAGE *HttpMsg; EFI_HTTP_REQUEST_DATA *Request; VOID *UrlParser; + VOID *EndPointUrlParser; EFI_STATUS Status; CHAR8 *HostName; + CHAR8 *EndPointHostName; UINTN HostNameSize; UINT16 RemotePort; + UINT16 EndPointRemotePort; HTTP_PROTOCOL *HttpInstance; BOOLEAN Configure; BOOLEAN ReConfigure; BOOLEAN TlsConfigure; CHAR8 *RequestMsg; CHAR8 *Url; + CHAR8 *EndPointUrl; UINTN UrlLen; CHAR16 *HostNameStr; HTTP_TOKEN_WRAP *Wrap; CHAR8 *FileUrl; UINTN RequestMsgSize; EFI_HANDLE ImageHandle; + CHAR8 *EndPointUrlMsg; // // Initializations // - Url = NULL; - UrlParser = NULL; - RemotePort = 0; - HostName = NULL; - RequestMsg = NULL; - HostNameStr = NULL; - Wrap = NULL; - FileUrl = NULL; - TlsConfigure = FALSE; + Url = NULL; + UrlParser = NULL; + EndPointUrlParser = NULL; + RemotePort = 0; + EndPointRemotePort = 0; + HostName = NULL; + EndPointHostName = NULL; + RequestMsg = NULL; + HostNameStr = NULL; + Wrap = NULL; + FileUrl = NULL; + TlsConfigure = FALSE; + EndPointUrl = NULL; + EndPointUrlMsg = NULL; if ((This == NULL) || (Token == NULL)) { return EFI_INVALID_PARAMETER; @@ -275,16 +285,20 @@ EfiHttpRequest ( Request = HttpMsg->Data.Request; // - // Only support GET, HEAD, DELETE, PATCH, PUT and POST method in current implementation. + // Only support GET, HEAD, DELETE, PATCH, PUT, CONNECT and POST method in current implementation. // if ((Request != NULL) && (Request->Method != HttpMethodGet) && (Request->Method != HttpMethodHead) && (Request->Method != HttpMethodDelete) && (Request->Method != HttpMethodPut) && (Request->Method != HttpMethodPost) && - (Request->Method != HttpMethodPatch)) + (Request->Method != HttpMethodPatch) && (Request->Method != HttpMethodConnect)) { return EFI_UNSUPPORTED; } + if ((Request->Method == HttpMethodConnect) && (Request->EndPointUrl == NULL)) { + return EFI_INVALID_PARAMETER; + } + HttpInstance = HTTP_INSTANCE_FROM_PROTOCOL (This); // @@ -353,11 +367,25 @@ EfiHttpRequest ( UnicodeStrToAsciiStrS (Request->Url, Url, UrlLen); + if (Request->EndPointUrl != NULL) { + UrlLen = StrLen (Request->EndPointUrl) + 1; + EndPointUrl = AllocateZeroPool (UrlLen); + if (EndPointUrl == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + UnicodeStrToAsciiStrS (Request->EndPointUrl, EndPointUrl, UrlLen); + } + // // From the information in Url, the HTTP instance will // be able to determine whether to use http or https. // - HttpInstance->UseHttps = IsHttpsUrl (Url); + if (HttpInstance->ProxyConnected) { + HttpInstance->UseHttps = IsHttpsUrl (EndPointUrl); + } else { + HttpInstance->UseHttps = IsHttpsUrl (Url); + } // // HTTP is disabled, return directly if the URI is not HTTPS. @@ -444,9 +472,10 @@ EfiHttpRequest ( if ((HttpInstance->ConnectionClose == FALSE) && (HttpInstance->RemotePort == RemotePort) && (AsciiStrCmp (HttpInstance->RemoteHost, HostName) == 0) && - (!HttpInstance->UseHttps || (HttpInstance->UseHttps && - !TlsConfigure && - (HttpInstance->TlsSessionState == EfiTlsSessionDataTransferring)))) + (!HttpInstance->UseHttps || + HttpInstance->ProxyConnected || (HttpInstance->UseHttps && + !TlsConfigure && + (HttpInstance->TlsSessionState == EfiTlsSessionDataTransferring)))) { // // Host Name and port number of the request URL are the same with previous call to Request(). @@ -599,7 +628,7 @@ EfiHttpRequest ( goto Error2; } - if (!Configure && !ReConfigure && !TlsConfigure) { + if ((!Configure && !ReConfigure) && ((HttpInstance->ProxyConnected && TlsConfigure) || (!TlsConfigure))) { // // For the new HTTP token, create TX TCP token events. // @@ -632,7 +661,48 @@ EfiHttpRequest ( } } - Status = HttpGenRequestMessage (HttpMsg, FileUrl, &RequestMsg, &RequestMsgSize); + if (HttpInstance->Method == HttpMethodConnect) { + Status = HttpParseUrl (EndPointUrl, (UINT32)AsciiStrLen (EndPointUrl), FALSE, &EndPointUrlParser); + if (EFI_ERROR (Status)) { + goto Error3; + } + + Status = HttpUrlGetHostName ( + EndPointUrl, + EndPointUrlParser, + &EndPointHostName + ); + if (EFI_ERROR (Status)) { + goto Error3; + } + + Status = HttpUrlGetPort (EndPointUrl, EndPointUrlParser, &EndPointRemotePort); + if (EFI_ERROR (Status)) { + if (IsHttpsUrl (EndPointUrl)) { + EndPointRemotePort = HTTPS_DEFAULT_PORT; + } else { + EndPointRemotePort = HTTP_DEFAULT_PORT; + } + } + + EndPointUrlMsg = AllocateZeroPool (URI_STR_MAX_SIZE); + if (EndPointUrlMsg == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto Error3; + } + + AsciiSPrint ( + EndPointUrlMsg, + URI_STR_MAX_SIZE, + "%a:%d", + EndPointHostName, + EndPointRemotePort + ); + + Status = HttpGenRequestMessage (HttpMsg, EndPointUrlMsg, &RequestMsg, &RequestMsgSize); + } else { + Status = HttpGenRequestMessage (HttpMsg, FileUrl, &RequestMsg, &RequestMsgSize); + } if (EFI_ERROR (Status) || (NULL == RequestMsg)) { goto Error3; @@ -668,6 +738,19 @@ EfiHttpRequest ( DispatchDpc (); + if (HttpInstance->Method == HttpMethodConnect) { + HttpInstance->ProxyConnected = TRUE; + HttpInstance->EndPointRemoteHost = EndPointHostName; + + if (EndPointUrlParser != NULL) { + HttpUrlFreeParser (EndPointUrlParser); + } + } + + if (EndPointUrlMsg != NULL) { + FreePool (EndPointUrlMsg); + } + if (HostName != NULL) { FreePool (HostName); } @@ -698,6 +781,20 @@ Error3: TlsCloseTxRxEvent (HttpInstance); } + if (HttpInstance->Method == HttpMethodConnect) { + if (EndPointHostName != NULL) { + FreePool (EndPointHostName); + } + + if (EndPointUrlParser != NULL) { + HttpUrlFreeParser (EndPointUrlParser); + } + } + + if (EndPointUrlMsg != NULL) { + FreePool (EndPointUrlMsg); + } + Error2: HttpCloseConnection (HttpInstance); diff --git a/NetworkPkg/HttpDxe/HttpProto.c b/NetworkPkg/HttpDxe/HttpProto.c index 33ae622c3f0b..b87fbeeb543f 100644 --- a/NetworkPkg/HttpDxe/HttpProto.c +++ b/NetworkPkg/HttpDxe/HttpProto.c @@ -849,6 +849,11 @@ HttpCleanProtocol ( HttpInstance->Url = NULL; } + if (HttpInstance->EndPointRemoteHost != NULL) { + FreePool (HttpInstance->EndPointRemoteHost); + HttpInstance->EndPointRemoteHost = NULL; + } + NetMapClean (&HttpInstance->TxTokens); NetMapClean (&HttpInstance->RxTokens); @@ -1206,6 +1211,7 @@ HttpConfigureTcp6 ( connect one TLS session if required. @param[in] HttpInstance The HTTP instance private data. + @param[in] TlsConfigure The Flag indicates whether it's the new Tls session. @retval EFI_SUCCESS The TCP connection is established. @retval EFI_NOT_READY TCP4 protocol child is not created or configured. @@ -1214,7 +1220,8 @@ HttpConfigureTcp6 ( **/ EFI_STATUS HttpConnectTcp4 ( - IN HTTP_PROTOCOL *HttpInstance + IN HTTP_PROTOCOL *HttpInstance, + IN BOOLEAN TlsConfigure ) { EFI_STATUS Status; @@ -1237,16 +1244,18 @@ HttpConnectTcp4 ( return Status; } - if (Tcp4State == Tcp4StateEstablished) { + if ((Tcp4State == Tcp4StateEstablished) && (!HttpInstance->ProxyConnected || !TlsConfigure)) { return EFI_SUCCESS; } else if (Tcp4State > Tcp4StateEstablished ) { HttpCloseConnection (HttpInstance); } - Status = HttpCreateConnection (HttpInstance); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "Tcp4 Connection fail - %x\n", Status)); - return Status; + if (!HttpInstance->ProxyConnected) { + Status = HttpCreateConnection (HttpInstance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Tcp4 Connection fail - %x\n", Status)); + return Status; + } } // @@ -1298,6 +1307,7 @@ HttpConnectTcp4 ( connect one TLS session if required. @param[in] HttpInstance The HTTP instance private data. + @param[in] TlsConfigure The Flag indicates whether it's the new Tls session. @retval EFI_SUCCESS The TCP connection is established. @retval EFI_NOT_READY TCP6 protocol child is not created or configured. @@ -1306,7 +1316,8 @@ HttpConnectTcp4 ( **/ EFI_STATUS HttpConnectTcp6 ( - IN HTTP_PROTOCOL *HttpInstance + IN HTTP_PROTOCOL *HttpInstance, + IN BOOLEAN TlsConfigure ) { EFI_STATUS Status; @@ -1330,16 +1341,18 @@ HttpConnectTcp6 ( return Status; } - if (Tcp6State == Tcp6StateEstablished) { + if ((Tcp6State == Tcp6StateEstablished) && (!HttpInstance->ProxyConnected || !TlsConfigure)) { return EFI_SUCCESS; } else if (Tcp6State > Tcp6StateEstablished ) { HttpCloseConnection (HttpInstance); } - Status = HttpCreateConnection (HttpInstance); - if (EFI_ERROR (Status)) { - DEBUG ((DEBUG_ERROR, "Tcp6 Connection fail - %x\n", Status)); - return Status; + if (!HttpInstance->ProxyConnected) { + Status = HttpCreateConnection (HttpInstance); + if (EFI_ERROR (Status)) { + DEBUG ((DEBUG_ERROR, "Tcp6 Connection fail - %x\n", Status)); + return Status; + } } // @@ -1434,7 +1447,7 @@ HttpInitSession ( // // Connect TCP. // - Status = HttpConnectTcp4 (HttpInstance); + Status = HttpConnectTcp4 (HttpInstance, TlsConfigure); if (EFI_ERROR (Status)) { return Status; } @@ -1452,7 +1465,7 @@ HttpInitSession ( // // Connect TCP. // - Status = HttpConnectTcp6 (HttpInstance); + Status = HttpConnectTcp6 (HttpInstance, TlsConfigure); if (EFI_ERROR (Status)) { return Status; } diff --git a/NetworkPkg/HttpDxe/HttpProto.h b/NetworkPkg/HttpDxe/HttpProto.h index 620eb3915843..2e8d51635993 100644 --- a/NetworkPkg/HttpDxe/HttpProto.h +++ b/NetworkPkg/HttpDxe/HttpProto.h @@ -165,6 +165,12 @@ typedef struct _HTTP_PROTOCOL { CHAR8 *Url; + // + // Proxy Server Support + // + CHAR8 *EndPointRemoteHost; + BOOLEAN ProxyConnected; + // // Https Support // @@ -398,6 +404,7 @@ HttpConfigureTcp6 ( connect one TLS session if required. @param[in] HttpInstance The HTTP instance private data. + @param[in] TlsConfigure The Flag indicates whether it's the new Tls session. @retval EFI_SUCCESS The TCP connection is established. @retval EFI_NOT_READY TCP4 protocol child is not created or configured. @@ -406,7 +413,8 @@ HttpConfigureTcp6 ( **/ EFI_STATUS HttpConnectTcp4 ( - IN HTTP_PROTOCOL *HttpInstance + IN HTTP_PROTOCOL *HttpInstance, + IN BOOLEAN TlsConfigure ); /** @@ -414,6 +422,7 @@ HttpConnectTcp4 ( connect one TLS session if required. @param[in] HttpInstance The HTTP instance private data. + @param[in] TlsConfigure The Flag indicates whether it's the new Tls session. @retval EFI_SUCCESS The TCP connection is established. @retval EFI_NOT_READY TCP6 protocol child is not created or configured. @@ -422,7 +431,8 @@ HttpConnectTcp4 ( **/ EFI_STATUS HttpConnectTcp6 ( - IN HTTP_PROTOCOL *HttpInstance + IN HTTP_PROTOCOL *HttpInstance, + IN BOOLEAN TlsConfigure ); /** diff --git a/NetworkPkg/HttpDxe/HttpsSupport.c b/NetworkPkg/HttpDxe/HttpsSupport.c index ad611e7c3836..7dc2b752ec47 100644 --- a/NetworkPkg/HttpDxe/HttpsSupport.c +++ b/NetworkPkg/HttpDxe/HttpsSupport.c @@ -644,11 +644,15 @@ TlsConfigureSession ( // // TlsConfigData initialization // - HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient; - HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER; - HttpInstance->TlsConfigData.VerifyHost.Flags = EFI_TLS_VERIFY_FLAG_NONE; - HttpInstance->TlsConfigData.VerifyHost.HostName = HttpInstance->RemoteHost; - HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted; + HttpInstance->TlsConfigData.ConnectionEnd = EfiTlsClient; + HttpInstance->TlsConfigData.SessionState = EfiTlsSessionNotStarted; + HttpInstance->TlsConfigData.VerifyMethod = EFI_TLS_VERIFY_PEER; + HttpInstance->TlsConfigData.VerifyHost.Flags = EFI_TLS_VERIFY_FLAG_NONE; + if (HttpInstance->ProxyConnected) { + HttpInstance->TlsConfigData.VerifyHost.HostName = HttpInstance->EndPointRemoteHost; + } else { + HttpInstance->TlsConfigData.VerifyHost.HostName = HttpInstance->RemoteHost; + } // // EfiTlsConnectionEnd, diff --git a/NetworkPkg/Library/DxeHttpLib/DxeHttpLib.c b/NetworkPkg/Library/DxeHttpLib/DxeHttpLib.c index 6a5d78629bb3..45087a19350a 100644 --- a/NetworkPkg/Library/DxeHttpLib/DxeHttpLib.c +++ b/NetworkPkg/Library/DxeHttpLib/DxeHttpLib.c @@ -1927,6 +1927,11 @@ HttpGenRequestMessage ( CopyMem (RequestPtr, HTTP_METHOD_DELETE, StrLength); RequestPtr += StrLength; break; + case HttpMethodConnect: + StrLength = sizeof (HTTP_METHOD_CONNECT) - 1; + CopyMem (RequestPtr, HTTP_METHOD_CONNECT, StrLength); + RequestPtr += StrLength; + break; default: ASSERT (FALSE); Status = EFI_INVALID_PARAMETER; -- 2.36.1.windows.1