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 <maciej.rab...@linux.intel.com>
Cc: Wu Jiaxin <jiaxin...@intel.com>
Cc: Siyuan Fu <siyuan...@intel.com>
Signed-off-by: Saloni Kasbekar <saloni.kasbe...@intel.com>
---
 MdePkg/Include/IndustryStandard/Http11.h   |  8 ++
 MdePkg/Include/Protocol/HttpBootCallback.h |  6 +-
 NetworkPkg/HttpBootDxe/HttpBootClient.c    | 91 +++++++++++++++++++++-
 NetworkPkg/HttpBootDxe/HttpBootClient.h    |  6 +-
 NetworkPkg/HttpBootDxe/HttpBootDxe.h       |  6 ++
 NetworkPkg/HttpBootDxe/HttpBootImpl.c      | 23 +++++-
 6 files changed, 135 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..deeea6f38669 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,60 @@ 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) {
+          FreePool (Private->AuthData);
+          Private->AuthData = 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



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#91069): https://edk2.groups.io/g/devel/message/91069
Mute This Topic: https://groups.io/mt/92193893/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to