From 671b0cea510ad6de02ee9d6dbdf8f9bbb881f35d Mon Sep 17 00:00:00 2001 From: Saloni Kasbekar Date: Tue, 19 Jul 2022 06:54:22 -0700 Subject: NetworkPkg/HttpBootDxe: Add Support for HTTP Boot Basic Authentication 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 Reviewed-by: Maciej Rabeda --- NetworkPkg/HttpBootDxe/HttpBootClient.c | 99 ++++++++++++++++++++++++++++++++- NetworkPkg/HttpBootDxe/HttpBootClient.h | 6 +- NetworkPkg/HttpBootDxe/HttpBootDxe.h | 6 ++ NetworkPkg/HttpBootDxe/HttpBootImpl.c | 23 +++++++- 4 files changed, 130 insertions(+), 4 deletions(-) (limited to 'NetworkPkg') diff --git a/NetworkPkg/HttpBootDxe/HttpBootClient.c b/NetworkPkg/HttpBootDxe/HttpBootClient.c index 62e8723..40f64fc 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; @@ -1064,6 +1069,35 @@ HttpBootGetBootFile ( } // + // 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. // RequestData = AllocatePool (sizeof (EFI_HTTP_REQUEST_DATA)); @@ -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 406529d..2fba713 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 5acbae9..5ff8ad4 100644 --- a/NetworkPkg/HttpBootDxe/HttpBootDxe.h +++ b/NetworkPkg/HttpBootDxe/HttpBootDxe.h @@ -184,6 +184,12 @@ struct _HTTP_BOOT_PRIVATE_DATA { UINT32 Percentage; // + // Data for the server to authenticate the client + // + CHAR8 *AuthData; + CHAR8 *AuthScheme; + + // // HII callback info block // HTTP_BOOT_FORM_CALLBACK_INFO CallbackInfo; diff --git a/NetworkPkg/HttpBootDxe/HttpBootImpl.c b/NetworkPkg/HttpBootDxe/HttpBootImpl.c index 3da585a..b4c6192 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; -- cgit v1.1