From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga09.intel.com (mga09.intel.com [134.134.136.24]) by mx.groups.io with SMTP id smtpd.web10.40983.1658238870842616104 for ; Tue, 19 Jul 2022 06:54:31 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=n45TNMoe; spf=pass (domain: intel.com, ip: 134.134.136.24, 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=1658238870; x=1689774870; h=from:to:cc:subject:date:message-id:in-reply-to: references:mime-version:content-transfer-encoding; bh=pibrWPlZqKEKuOinyHpGBWQpNm79J+HKaQ2skJsuv1w=; b=n45TNMoetQgEUCK8A4HS+Sxy/WUmz2r+eRnG5k8H6I4bPB/VhrcPFXkz rS+Jk1mr4NtHnxQtWi/1fDGApFLfYweyx2hQJ1HPMXzU8Ga4lRsTSdVAt Zfp/jX99WL9ObTkALGCHDScukBOx+DmWFa48V5dJEr46yATRWplvaDLmY Pndnkfrmk1iNv6H88BfpaPUrAcBlHzpJfgU/5udUjP9H1fGCI9vsksa0M zfbzi1sDtB9c5v6s+d4ANbapreJTzS0d9ndu6mELRENQ/8CpcBR8RCcZA Gn9SMBOrq+44Q9SOYya1Fcyz9Dg687MLPIdIbIx13X+5GAa3jZHrmA02u A==; X-IronPort-AV: E=McAfee;i="6400,9594,10412"; a="287239862" X-IronPort-AV: E=Sophos;i="5.92,284,1650956400"; d="scan'208";a="287239862" Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by orsmga102.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Jul 2022 06:54:30 -0700 X-IronPort-AV: E=Sophos;i="5.92,284,1650956400"; d="scan'208";a="601592862" Received: from fmbiosdev02.amr.corp.intel.com ([10.80.127.10]) by fmsmga007-auth.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 19 Jul 2022 06:54:30 -0700 From: "Saloni Kasbekar" To: devel@edk2.groups.io Cc: Saloni Kasbekar , Maciej Rabeda , Wu Jiaxin , Siyuan Fu Subject: [PATCH v4 1/1] NetworkPkg/HttpBootDxe: Add Support for HTTP Boot Basic Authentication Date: Tue, 19 Jul 2022 06:54:22 -0700 Message-Id: <1eb3e48dc7fe65db4ffc9424ace42c80c45f7e82.1658238840.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 REF:https://bugzilla.tianocore.org/show_bug.cgi?id=2504 Add support for TLS Client Authentication using Basic Authentication for HTTP Boot Cc: Maciej Rabeda Cc: Wu Jiaxin Cc: Siyuan Fu Signed-off-by: Saloni Kasbekar --- MdePkg/Include/IndustryStandard/Http11.h | 8 ++ MdePkg/Include/Protocol/HttpBootCallback.h | 6 +- NetworkPkg/HttpBootDxe/HttpBootClient.c | 99 +++++++++++++++++++++- NetworkPkg/HttpBootDxe/HttpBootClient.h | 6 +- NetworkPkg/HttpBootDxe/HttpBootDxe.h | 6 ++ NetworkPkg/HttpBootDxe/HttpBootImpl.c | 23 ++++- 6 files changed, 143 insertions(+), 5 deletions(-) diff --git a/MdePkg/Include/IndustryStandard/Http11.h b/MdePkg/Include/IndustryStandard/Http11.h index f1f113e04b69..2137ef1f1ac3 100644 --- a/MdePkg/Include/IndustryStandard/Http11.h +++ b/MdePkg/Include/IndustryStandard/Http11.h @@ -204,6 +204,14 @@ /// #define HTTP_HEADER_IF_NONE_MATCH "If-None-Match" +/// +/// The WWW-Authenticate Response Header +/// If a server receives a request for an access-protected object, and an +/// acceptable Authorization header is not sent, the server responds with +/// a "401 Unauthorized" status code, and a WWW-Authenticate header. +/// +#define HTTP_HEADER_WWW_AUTHENTICATE "WWW-Authenticate" + /// /// Authorization Request Header /// The Authorization field value consists of credentials diff --git a/MdePkg/Include/Protocol/HttpBootCallback.h b/MdePkg/Include/Protocol/HttpBootCallback.h index 926f6c1b3076..b56c631b1f4f 100644 --- a/MdePkg/Include/Protocol/HttpBootCallback.h +++ b/MdePkg/Include/Protocol/HttpBootCallback.h @@ -32,7 +32,7 @@ typedef enum { /// HttpBootDhcp6, /// - /// Data points to an EFI_HTTP_MESSAGE structure, whichcontians a HTTP request message + /// Data points to an EFI_HTTP_MESSAGE structure, which contains a HTTP request message /// to be transmitted. /// HttpBootHttpRequest, @@ -46,6 +46,10 @@ typedef enum { /// buffer of the entity body data. /// HttpBootHttpEntityBody, + /// + /// Data points to the authentication information to provide to the HTTP server. + /// + HttpBootHttpAuthInfo, HttpBootTypeMax } EFI_HTTP_BOOT_CALLBACK_DATA_TYPE; diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.c b/NetworkPkg/HttpBootDxe/HttpBootClient.c index 62e87238fef7..40f64fcb6bf8 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootClient.c +++ b/NetworkPkg/HttpBootDxe/HttpBootClient.c @@ -922,6 +922,7 @@ HttpBootGetBootFileCallback ( @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 The server needs to authenticate the client. @retval Others Unexpected error happened. **/ @@ -951,6 +952,9 @@ HttpBootGetBootFile ( CHAR16 *Url; BOOLEAN IdentityMode; UINTN ReceivedSize; + CHAR8 BaseAuthValue[80]; + EFI_HTTP_HEADER *HttpHeader; + CHAR8 *Data; ASSERT (Private != NULL); ASSERT (Private->HttpCreated); @@ -1009,8 +1013,9 @@ HttpBootGetBootFile ( // Host // Accept // User-Agent + // [Authorization] // - HttpIoHeader = HttpIoCreateHeader (3); + HttpIoHeader = HttpIoCreateHeader ((Private->AuthData != NULL) ? 4 : 3); if (HttpIoHeader == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ERROR_2; @@ -1063,6 +1068,35 @@ HttpBootGetBootFile ( goto ERROR_3; } + // + // Add HTTP header field 4: Authorization + // + if (Private->AuthData != NULL) { + ASSERT (HttpIoHeader->MaxHeaderCount == 4); + + if ((Private->AuthScheme != NULL) && (CompareMem (Private->AuthScheme, "Basic", 5) != 0)) { + Status = EFI_UNSUPPORTED; + goto ERROR_3; + } + + AsciiSPrint ( + BaseAuthValue, + sizeof (BaseAuthValue), + "%a %a", + "Basic", + Private->AuthData + ); + + Status = HttpIoSetHeader ( + HttpIoHeader, + HTTP_HEADER_AUTHORIZATION, + BaseAuthValue + ); + if (EFI_ERROR (Status)) { + goto ERROR_3; + } + } + // // 2.2 Build the rest of HTTP request info. // @@ -1111,6 +1145,7 @@ HttpBootGetBootFile ( goto ERROR_4; } + Data = NULL; Status = HttpIoRecvResponse ( &Private->HttpIo, TRUE, @@ -1121,6 +1156,68 @@ HttpBootGetBootFile ( StatusCode = HttpIo->RspToken.Message->Data.Response->StatusCode; HttpBootPrintErrorMessage (StatusCode); Status = ResponseData->Status; + if ((StatusCode == HTTP_STATUS_401_UNAUTHORIZED) || \ + (StatusCode == HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED)) + { + if ((Private->AuthData != NULL) || (Private->AuthScheme != NULL)) { + if (Private->AuthData != NULL) { + FreePool (Private->AuthData); + Private->AuthData = NULL; + } + + if (Private->AuthScheme != NULL) { + FreePool (Private->AuthScheme); + Private->AuthScheme = NULL; + } + + Status = EFI_ACCESS_DENIED; + goto ERROR_4; + } + + // + // Server indicates the user has to provide a user-id and password as a means of identification. + // + if (Private->HttpBootCallback != NULL) { + Data = AllocateZeroPool (sizeof (CHAR8) * HTTP_BOOT_AUTHENTICATION_INFO_MAX_LEN); + if (Data == NULL) { + Status = EFI_OUT_OF_RESOURCES; + goto ERROR_4; + } + + Status = Private->HttpBootCallback->Callback ( + Private->HttpBootCallback, + HttpBootHttpAuthInfo, + TRUE, + HTTP_BOOT_AUTHENTICATION_INFO_MAX_LEN, + Data + ); + if (EFI_ERROR (Status)) { + if (Data != NULL) { + FreePool (Data); + } + + goto ERROR_5; + } + + Private->AuthData = (CHAR8 *)Data; + } + + HttpHeader = HttpFindHeader ( + ResponseData->HeaderCount, + ResponseData->Headers, + HTTP_HEADER_WWW_AUTHENTICATE + ); + if (HttpHeader != NULL) { + Private->AuthScheme = AllocateZeroPool (AsciiStrLen (HttpHeader->FieldValue) + 1); + if (Private->AuthScheme == NULL) { + return EFI_OUT_OF_RESOURCES; + } + + CopyMem (Private->AuthScheme, HttpHeader->FieldValue, AsciiStrLen (HttpHeader->FieldValue)); + } + + Status = EFI_ACCESS_DENIED; + } } goto ERROR_5; diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.h b/NetworkPkg/HttpBootDxe/HttpBootClient.h index 406529dfd927..2fba71367950 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootClient.h +++ b/NetworkPkg/HttpBootDxe/HttpBootClient.h @@ -10,8 +10,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent #ifndef __EFI_HTTP_BOOT_HTTP_H__ #define __EFI_HTTP_BOOT_HTTP_H__ -#define HTTP_BOOT_BLOCK_SIZE 1500 -#define HTTP_USER_AGENT_EFI_HTTP_BOOT "UefiHttpBoot/1.0" +#define HTTP_BOOT_BLOCK_SIZE 1500 +#define HTTP_USER_AGENT_EFI_HTTP_BOOT "UefiHttpBoot/1.0" +#define HTTP_BOOT_AUTHENTICATION_INFO_MAX_LEN 255 // // Record the data length and start address of a data block. @@ -106,6 +107,7 @@ HttpBootCreateHttpIo ( @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 The server needs to authenticate the client. @retval Others Unexpected error happened. **/ diff --git a/NetworkPkg/HttpBootDxe/HttpBootDxe.h b/NetworkPkg/HttpBootDxe/HttpBootDxe.h index 5acbae9bfa76..5ff8ad4698b2 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDxe.h +++ b/NetworkPkg/HttpBootDxe/HttpBootDxe.h @@ -183,6 +183,12 @@ struct _HTTP_BOOT_PRIVATE_DATA { UINT64 ReceivedSize; UINT32 Percentage; + // + // Data for the server to authenticate the client + // + CHAR8 *AuthData; + CHAR8 *AuthScheme; + // // HII callback info block // diff --git a/NetworkPkg/HttpBootDxe/HttpBootImpl.c b/NetworkPkg/HttpBootDxe/HttpBootImpl.c index 3da585a29164..b4c61925b94f 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootImpl.c +++ b/NetworkPkg/HttpBootDxe/HttpBootImpl.c @@ -360,7 +360,18 @@ HttpBootLoadFile ( 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. + // + 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. // @@ -489,6 +500,16 @@ HttpBootStop ( } } + if (Private->AuthData != NULL) { + FreePool (Private->AuthData); + Private->AuthData = NULL; + } + + if (Private->AuthScheme != NULL) { + FreePool (Private->AuthScheme); + Private->AuthScheme = NULL; + } + if (Private->DnsServerIp != NULL) { FreePool (Private->DnsServerIp); Private->DnsServerIp = NULL; -- 2.36.1.windows.1