]> git.proxmox.com Git - mirror_edk2.git/commitdiff
NetworkPkg/HttpBootDxe: Add Support for HTTP Boot Basic Authentication
authorSaloni Kasbekar <saloni.kasbekar@intel.com>
Tue, 19 Jul 2022 13:54:22 +0000 (06:54 -0700)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Tue, 19 Jul 2022 17:43:07 +0000 (17:43 +0000)
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.rabeda@linux.intel.com>
Cc: Wu Jiaxin <jiaxin.wu@intel.com>
Cc: Siyuan Fu <siyuan.fu@intel.com>
Signed-off-by: Saloni Kasbekar <saloni.kasbekar@intel.com>
Reviewed-by: Maciej Rabeda <maciej.rabeda@linux.intel.com>
MdePkg/Include/IndustryStandard/Http11.h
MdePkg/Include/Protocol/HttpBootCallback.h
NetworkPkg/HttpBootDxe/HttpBootClient.c
NetworkPkg/HttpBootDxe/HttpBootClient.h
NetworkPkg/HttpBootDxe/HttpBootDxe.h
NetworkPkg/HttpBootDxe/HttpBootImpl.c

index f1f113e04b69a12f39fe18c452d0810000e74fb9..2137ef1f1ac314650fb7dc6fff0f16d38218e25c 100644 (file)
 ///\r
 #define HTTP_HEADER_IF_NONE_MATCH  "If-None-Match"\r
 \r
+///\r
+/// The WWW-Authenticate Response Header\r
+/// If a server receives a request for an access-protected object, and an\r
+/// acceptable Authorization header is not sent, the server responds with\r
+/// a "401 Unauthorized" status code, and a WWW-Authenticate header.\r
+///\r
+#define HTTP_HEADER_WWW_AUTHENTICATE  "WWW-Authenticate"\r
+\r
 ///\r
 /// Authorization Request Header\r
 /// The Authorization field value consists of credentials\r
index 926f6c1b3076f82abf588be3bd00da920aa1f624..b56c631b1f4fef8a9b51038764226a9ec193cf2a 100644 (file)
@@ -32,7 +32,7 @@ typedef enum {
   ///\r
   HttpBootDhcp6,\r
   ///\r
-  /// Data points to an EFI_HTTP_MESSAGE structure, whichcontians a HTTP request message\r
+  /// Data points to an EFI_HTTP_MESSAGE structure, which contains a HTTP request message\r
   /// to be transmitted.\r
   ///\r
   HttpBootHttpRequest,\r
@@ -46,6 +46,10 @@ typedef enum {
   /// buffer of the entity body data.\r
   ///\r
   HttpBootHttpEntityBody,\r
+  ///\r
+  /// Data points to the authentication information to provide to the HTTP server.\r
+  ///\r
+  HttpBootHttpAuthInfo,\r
   HttpBootTypeMax\r
 } EFI_HTTP_BOOT_CALLBACK_DATA_TYPE;\r
 \r
index 62e87238fef7bc9d577c7099ebf92355c13a503c..40f64fcb6bf82ccec2de6d41ab22f75b4f890b7b 100644 (file)
@@ -922,6 +922,7 @@ HttpBootGetBootFileCallback (
   @retval EFI_BUFFER_TOO_SMALL     The BufferSize is too small to read the current directory entry.\r
                                    BufferSize has been updated with the size needed to complete\r
                                    the request.\r
+  @retval EFI_ACCESS_DENIED        The server needs to authenticate the client.\r
   @retval Others                   Unexpected error happened.\r
 \r
 **/\r
@@ -951,6 +952,9 @@ HttpBootGetBootFile (
   CHAR16                   *Url;\r
   BOOLEAN                  IdentityMode;\r
   UINTN                    ReceivedSize;\r
+  CHAR8                    BaseAuthValue[80];\r
+  EFI_HTTP_HEADER          *HttpHeader;\r
+  CHAR8                    *Data;\r
 \r
   ASSERT (Private != NULL);\r
   ASSERT (Private->HttpCreated);\r
@@ -1009,8 +1013,9 @@ HttpBootGetBootFile (
   //       Host\r
   //       Accept\r
   //       User-Agent\r
+  //       [Authorization]\r
   //\r
-  HttpIoHeader = HttpIoCreateHeader (3);\r
+  HttpIoHeader = HttpIoCreateHeader ((Private->AuthData != NULL) ? 4 : 3);\r
   if (HttpIoHeader == NULL) {\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto ERROR_2;\r
@@ -1063,6 +1068,35 @@ HttpBootGetBootFile (
     goto ERROR_3;\r
   }\r
 \r
+  //\r
+  // Add HTTP header field 4: Authorization\r
+  //\r
+  if (Private->AuthData != NULL) {\r
+    ASSERT (HttpIoHeader->MaxHeaderCount == 4);\r
+\r
+    if ((Private->AuthScheme != NULL) && (CompareMem (Private->AuthScheme, "Basic", 5) != 0)) {\r
+      Status = EFI_UNSUPPORTED;\r
+      goto ERROR_3;\r
+    }\r
+\r
+    AsciiSPrint (\r
+      BaseAuthValue,\r
+      sizeof (BaseAuthValue),\r
+      "%a %a",\r
+      "Basic",\r
+      Private->AuthData\r
+      );\r
+\r
+    Status = HttpIoSetHeader (\r
+               HttpIoHeader,\r
+               HTTP_HEADER_AUTHORIZATION,\r
+               BaseAuthValue\r
+               );\r
+    if (EFI_ERROR (Status)) {\r
+      goto ERROR_3;\r
+    }\r
+  }\r
+\r
   //\r
   // 2.2 Build the rest of HTTP request info.\r
   //\r
@@ -1111,6 +1145,7 @@ HttpBootGetBootFile (
     goto ERROR_4;\r
   }\r
 \r
+  Data   = NULL;\r
   Status = HttpIoRecvResponse (\r
              &Private->HttpIo,\r
              TRUE,\r
@@ -1121,6 +1156,68 @@ HttpBootGetBootFile (
       StatusCode = HttpIo->RspToken.Message->Data.Response->StatusCode;\r
       HttpBootPrintErrorMessage (StatusCode);\r
       Status = ResponseData->Status;\r
+      if ((StatusCode == HTTP_STATUS_401_UNAUTHORIZED) || \\r
+          (StatusCode == HTTP_STATUS_407_PROXY_AUTHENTICATION_REQUIRED))\r
+      {\r
+        if ((Private->AuthData != NULL) || (Private->AuthScheme != NULL)) {\r
+          if (Private->AuthData != NULL) {\r
+            FreePool (Private->AuthData);\r
+            Private->AuthData = NULL;\r
+          }\r
+\r
+          if (Private->AuthScheme != NULL) {\r
+            FreePool (Private->AuthScheme);\r
+            Private->AuthScheme = NULL;\r
+          }\r
+\r
+          Status = EFI_ACCESS_DENIED;\r
+          goto ERROR_4;\r
+        }\r
+\r
+        //\r
+        // Server indicates the user has to provide a user-id and password as a means of identification.\r
+        //\r
+        if (Private->HttpBootCallback != NULL) {\r
+          Data = AllocateZeroPool (sizeof (CHAR8) * HTTP_BOOT_AUTHENTICATION_INFO_MAX_LEN);\r
+          if (Data == NULL) {\r
+            Status = EFI_OUT_OF_RESOURCES;\r
+            goto ERROR_4;\r
+          }\r
+\r
+          Status = Private->HttpBootCallback->Callback (\r
+                                                Private->HttpBootCallback,\r
+                                                HttpBootHttpAuthInfo,\r
+                                                TRUE,\r
+                                                HTTP_BOOT_AUTHENTICATION_INFO_MAX_LEN,\r
+                                                Data\r
+                                                );\r
+          if (EFI_ERROR (Status)) {\r
+            if (Data != NULL) {\r
+              FreePool (Data);\r
+            }\r
+\r
+            goto ERROR_5;\r
+          }\r
+\r
+          Private->AuthData = (CHAR8 *)Data;\r
+        }\r
+\r
+        HttpHeader = HttpFindHeader (\r
+                       ResponseData->HeaderCount,\r
+                       ResponseData->Headers,\r
+                       HTTP_HEADER_WWW_AUTHENTICATE\r
+                       );\r
+        if (HttpHeader != NULL) {\r
+          Private->AuthScheme = AllocateZeroPool (AsciiStrLen (HttpHeader->FieldValue) + 1);\r
+          if (Private->AuthScheme == NULL) {\r
+            return EFI_OUT_OF_RESOURCES;\r
+          }\r
+\r
+          CopyMem (Private->AuthScheme, HttpHeader->FieldValue, AsciiStrLen (HttpHeader->FieldValue));\r
+        }\r
+\r
+        Status = EFI_ACCESS_DENIED;\r
+      }\r
     }\r
 \r
     goto ERROR_5;\r
index 406529dfd927e7e233d5c422a1e954484bc02f84..2fba713679504db2e1ecfa44bbe2aff4edaf2f02 100644 (file)
@@ -10,8 +10,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 #ifndef __EFI_HTTP_BOOT_HTTP_H__\r
 #define __EFI_HTTP_BOOT_HTTP_H__\r
 \r
-#define HTTP_BOOT_BLOCK_SIZE           1500\r
-#define HTTP_USER_AGENT_EFI_HTTP_BOOT  "UefiHttpBoot/1.0"\r
+#define HTTP_BOOT_BLOCK_SIZE                   1500\r
+#define HTTP_USER_AGENT_EFI_HTTP_BOOT          "UefiHttpBoot/1.0"\r
+#define HTTP_BOOT_AUTHENTICATION_INFO_MAX_LEN  255\r
 \r
 //\r
 // Record the data length and start address of a data block.\r
@@ -106,6 +107,7 @@ HttpBootCreateHttpIo (
   @retval EFI_BUFFER_TOO_SMALL     The BufferSize is too small to read the current directory entry.\r
                                    BufferSize has been updated with the size needed to complete\r
                                    the request.\r
+  @retval EFI_ACCESS_DENIED        The server needs to authenticate the client.\r
   @retval Others                   Unexpected error happened.\r
 \r
 **/\r
index 5acbae9bfa7684902aec803150f4f387fffd43a0..5ff8ad4698b2e74209b978aaa6cd664729e6dbe2 100644 (file)
@@ -183,6 +183,12 @@ struct _HTTP_BOOT_PRIVATE_DATA {
   UINT64                                       ReceivedSize;\r
   UINT32                                       Percentage;\r
 \r
+  //\r
+  // Data for the server to authenticate the client\r
+  //\r
+  CHAR8                                        *AuthData;\r
+  CHAR8                                        *AuthScheme;\r
+\r
   //\r
   // HII callback info block\r
   //\r
index 3da585a29164c8c05f1c7c904730c63ae571cd4b..b4c61925b94f83d6eb1e778caf13a07ff3ea76d5 100644 (file)
@@ -360,7 +360,18 @@ HttpBootLoadFile (
                NULL,\r
                &Private->ImageType\r
                );\r
-    if (EFI_ERROR (Status) && (Status != EFI_BUFFER_TOO_SMALL)) {\r
+    if ((Private->AuthData != NULL) && (Status == EFI_ACCESS_DENIED)) {\r
+      //\r
+      // Try to use HTTP HEAD method again since the Authentication information is provided.\r
+      //\r
+      Status = HttpBootGetBootFile (\r
+                 Private,\r
+                 TRUE,\r
+                 &Private->BootFileSize,\r
+                 NULL,\r
+                 &Private->ImageType\r
+                 );\r
+    } else if ((EFI_ERROR (Status)) && (Status != EFI_BUFFER_TOO_SMALL)) {\r
       //\r
       // Failed to get file size by HEAD method, may be trunked encoding, try HTTP GET method.\r
       //\r
@@ -489,6 +500,16 @@ HttpBootStop (
     }\r
   }\r
 \r
+  if (Private->AuthData != NULL) {\r
+    FreePool (Private->AuthData);\r
+    Private->AuthData = NULL;\r
+  }\r
+\r
+  if (Private->AuthScheme != NULL) {\r
+    FreePool (Private->AuthScheme);\r
+    Private->AuthScheme = NULL;\r
+  }\r
+\r
   if (Private->DnsServerIp != NULL) {\r
     FreePool (Private->DnsServerIp);\r
     Private->DnsServerIp = NULL;\r