From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from mga02.intel.com (mga02.intel.com [134.134.136.20]) by mx.groups.io with SMTP id smtpd.web12.1852.1655494568111241883 for ; Fri, 17 Jun 2022 12:36:09 -0700 Authentication-Results: mx.groups.io; dkim=fail reason="unable to parse pub key" header.i=@intel.com header.s=intel header.b=Z+tf98Rk; spf=pass (domain: intel.com, ip: 134.134.136.20, 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=1655494568; x=1687030568; h=from:to:cc:subject:date:message-id:mime-version: content-transfer-encoding; bh=J5MGJI/vMb2J5HX9WARA9PoXg2bNctI5rTGTyElpmWg=; b=Z+tf98RkTRu6kITzlbgWkCsY5uhDCaez7i8fsUIAySSRshtOeFbmcgKl n36rUR26WIZ7Jf7u+T2+XE42serIHpMAquXjWuyFqiwTcnzj/KzQxzosc CfvD3sYVkSpAYoXG/3oCBSPyAfV2FS9fVJHsBnZjpX3nxNx7dgIanSGLT RI7viKxGpDPhkllLTFdRDqZXu+6DVBqmrDdhbTs85aZzESdVZIGC2VUHO Ux9QkWr/d6GIy/COBfq80sUskj/AZQ7V67S7KEVjT9Oz7Kg21TBdTy2sz 98BZI4BMUIYMXhQHTHANrCbaLXXEyo/tvYdkodejUDQXzPvVj2KRyGycg Q==; X-IronPort-AV: E=McAfee;i="6400,9594,10380"; a="268287990" X-IronPort-AV: E=Sophos;i="5.92,306,1650956400"; d="scan'208";a="268287990" Received: from fmsmga007.fm.intel.com ([10.253.24.52]) by orsmga101.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 17 Jun 2022 12:36:06 -0700 X-IronPort-AV: E=Sophos;i="5.92,306,1650956400"; d="scan'208";a="590243779" 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; 17 Jun 2022 12:36:06 -0700 From: saloni.kasbekar@intel.com To: devel@edk2.groups.io Cc: Saloni Kasbekar , Maciej Rabeda , Wu Jiaxin , Siyuan Fu Subject: [PATCH] NetworkPkg/HttpBootDxe: Add Support for HTTP Boot Basic Authentication Date: Fri, 17 Jun 2022 12:35:59 -0700 Message-Id: <23405fd0316d53f7976b38f0576a70df34440df8.1655487158.git.saloni.kasbekar@intel.com> X-Mailer: git-send-email 2.36.1.windows.1 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 | 84 +++++++++++++++++++++- NetworkPkg/HttpBootDxe/HttpBootClient.h | 6 +- NetworkPkg/HttpBootDxe/HttpBootDxe.h | 6 ++ NetworkPkg/HttpBootDxe/HttpBootImpl.c | 23 +++++- 6 files changed, 128 insertions(+), 5 deletions(-) diff --git a/MdePkg/Include/IndustryStandard/Http11.h b/MdePkg/Include/IndustryStandard/Http11.h index f1f113e04b..2137ef1f1a 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 926f6c1b30..b56c631b1f 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 62e87238fe..448141fb7c 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,53 @@ 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)) + { + // + // 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 406529dfd9..2fba713679 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 5acbae9bfa..5ff8ad4698 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 3da585a291..b4c61925b9 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.26.2.windows.1