]> git.proxmox.com Git - mirror_edk2.git/blobdiff - NetworkPkg/IScsiDxe/IScsiCHAP.c
NetworkPkg: Apply uncrustify changes
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiCHAP.c
index 744824e63d233e7fa0562796b913c5e9d13b8648..b507f11cd45e258a038427ef0f125476df816711 100644 (file)
@@ -9,6 +9,53 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
 \r
 #include "IScsiImpl.h"\r
 \r
+//\r
+// Supported CHAP hash algorithms, mapped to sets of BaseCryptLib APIs and\r
+// macros. CHAP_HASH structures at lower subscripts in the array are preferred\r
+// by the initiator.\r
+//\r
+STATIC CONST CHAP_HASH  mChapHash[] = {\r
+  {\r
+    ISCSI_CHAP_ALGORITHM_SHA256,\r
+    SHA256_DIGEST_SIZE,\r
+    Sha256GetContextSize,\r
+    Sha256Init,\r
+    Sha256Update,\r
+    Sha256Final\r
+  },\r
+ #ifdef ENABLE_MD5_DEPRECATED_INTERFACES\r
+  //\r
+  // Keep the deprecated MD5 entry at the end of the array (making MD5 the\r
+  // least preferred choice of the initiator).\r
+  //\r
+  {\r
+    ISCSI_CHAP_ALGORITHM_MD5,\r
+    MD5_DIGEST_SIZE,\r
+    Md5GetContextSize,\r
+    Md5Init,\r
+    Md5Update,\r
+    Md5Final\r
+  },\r
+ #endif // ENABLE_MD5_DEPRECATED_INTERFACES\r
+};\r
+\r
+//\r
+// Ordered list of mChapHash[*].Algorithm values. It is formatted for the\r
+// CHAP_A=<A1,A2...> value string, by the IScsiCHAPInitHashList() function. It\r
+// is sent by the initiator in ISCSI_CHAP_STEP_ONE.\r
+//\r
+STATIC CHAR8  mChapHashListString[\r
+                                  3 +                                      // UINT8 identifier in\r
+                                                                           //   decimal\r
+                                  (1 + 3) * (ARRAY_SIZE (mChapHash) - 1) + // comma prepended for\r
+                                                                           //   entries after the\r
+                                                                           //   first\r
+                                  1 +                                      // extra character for\r
+                                                                           //   AsciiSPrint()\r
+                                                                           //   truncation check\r
+                                  1                                        // terminating NUL\r
+];\r
+\r
 /**\r
   Initiator calculates its own expected hash value.\r
 \r
@@ -17,6 +64,10 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
   @param[in]   SecretLength       The length of iSCSI CHAP secret.\r
   @param[in]   ChapChallenge      The challenge message sent by authenticator.\r
   @param[in]   ChallengeLength    The length of iSCSI CHAP challenge message.\r
+  @param[in]   Hash               Pointer to the CHAP_HASH structure that\r
+                                  determines the hashing algorithm to use. The\r
+                                  caller is responsible for making Hash point\r
+                                  to an "mChapHash" element.\r
   @param[out]  ChapResponse       The calculation of the expected hash value.\r
 \r
   @retval EFI_SUCCESS             The expected hash value was calculatedly\r
@@ -24,22 +75,24 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
   @retval EFI_PROTOCOL_ERROR      The length of the secret should be at least\r
                                   the length of the hash value for the hashing\r
                                   algorithm chosen.\r
-  @retval EFI_PROTOCOL_ERROR      MD5 hash operation fail.\r
-  @retval EFI_OUT_OF_RESOURCES    Fail to allocate resource to complete MD5.\r
+  @retval EFI_PROTOCOL_ERROR      Hash operation fails.\r
+  @retval EFI_OUT_OF_RESOURCES    Failure to allocate resource to complete\r
+                                  hashing.\r
 \r
 **/\r
 EFI_STATUS\r
 IScsiCHAPCalculateResponse (\r
-  IN  UINT32          ChapIdentifier,\r
-  IN  CHAR8           *ChapSecret,\r
-  IN  UINT32          SecretLength,\r
-  IN  UINT8           *ChapChallenge,\r
-  IN  UINT32          ChallengeLength,\r
-  OUT UINT8           *ChapResponse\r
+  IN  UINT32           ChapIdentifier,\r
+  IN  CHAR8            *ChapSecret,\r
+  IN  UINT32           SecretLength,\r
+  IN  UINT8            *ChapChallenge,\r
+  IN  UINT32           ChallengeLength,\r
+  IN  CONST CHAP_HASH  *Hash,\r
+  OUT UINT8            *ChapResponse\r
   )\r
 {\r
-  UINTN       Md5ContextSize;\r
-  VOID        *Md5Ctx;\r
+  UINTN       ContextSize;\r
+  VOID        *Ctx;\r
   CHAR8       IdByte[1];\r
   EFI_STATUS  Status;\r
 \r
@@ -47,46 +100,48 @@ IScsiCHAPCalculateResponse (
     return EFI_PROTOCOL_ERROR;\r
   }\r
 \r
-  Md5ContextSize = Md5GetContextSize ();\r
-  Md5Ctx = AllocatePool (Md5ContextSize);\r
-  if (Md5Ctx == NULL) {\r
+  ASSERT (Hash != NULL);\r
+\r
+  ContextSize = Hash->GetContextSize ();\r
+  Ctx         = AllocatePool (ContextSize);\r
+  if (Ctx == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
   Status = EFI_PROTOCOL_ERROR;\r
 \r
-  if (!Md5Init (Md5Ctx)) {\r
+  if (!Hash->Init (Ctx)) {\r
     goto Exit;\r
   }\r
 \r
   //\r
   // Hash Identifier - Only calculate 1 byte data (RFC1994)\r
   //\r
-  IdByte[0] = (CHAR8) ChapIdentifier;\r
-  if (!Md5Update (Md5Ctx, IdByte, 1)) {\r
+  IdByte[0] = (CHAR8)ChapIdentifier;\r
+  if (!Hash->Update (Ctx, IdByte, 1)) {\r
     goto Exit;\r
   }\r
 \r
   //\r
   // Hash Secret\r
   //\r
-  if (!Md5Update (Md5Ctx, ChapSecret, SecretLength)) {\r
+  if (!Hash->Update (Ctx, ChapSecret, SecretLength)) {\r
     goto Exit;\r
   }\r
 \r
   //\r
   // Hash Challenge received from Target\r
   //\r
-  if (!Md5Update (Md5Ctx, ChapChallenge, ChallengeLength)) {\r
+  if (!Hash->Update (Ctx, ChapChallenge, ChallengeLength)) {\r
     goto Exit;\r
   }\r
 \r
-  if (Md5Final (Md5Ctx, ChapResponse)) {\r
+  if (Hash->Final (Ctx, ChapResponse)) {\r
     Status = EFI_SUCCESS;\r
   }\r
 \r
 Exit:\r
-  FreePool (Md5Ctx);\r
+  FreePool (Ctx);\r
   return Status;\r
 }\r
 \r
@@ -113,27 +168,36 @@ IScsiCHAPAuthTarget (
   EFI_STATUS  Status;\r
   UINT32      SecretSize;\r
   UINT8       VerifyRsp[ISCSI_CHAP_MAX_DIGEST_SIZE];\r
+  INTN        Mismatch;\r
+\r
+  Status = EFI_SUCCESS;\r
 \r
-  Status      = EFI_SUCCESS;\r
+  SecretSize = (UINT32)AsciiStrLen (AuthData->AuthConfig->ReverseCHAPSecret);\r
+\r
+  ASSERT (AuthData->Hash != NULL);\r
 \r
-  SecretSize  = (UINT32) AsciiStrLen (AuthData->AuthConfig->ReverseCHAPSecret);\r
   Status = IScsiCHAPCalculateResponse (\r
              AuthData->OutIdentifier,\r
              AuthData->AuthConfig->ReverseCHAPSecret,\r
              SecretSize,\r
              AuthData->OutChallenge,\r
-             MD5_DIGEST_SIZE,                         // ChallengeLength\r
+             AuthData->Hash->DigestSize,              // ChallengeLength\r
+             AuthData->Hash,\r
              VerifyRsp\r
              );\r
 \r
-  if (CompareMem (VerifyRsp, TargetResponse, MD5_DIGEST_SIZE) != 0) {\r
+  Mismatch = CompareMem (\r
+               VerifyRsp,\r
+               TargetResponse,\r
+               AuthData->Hash->DigestSize\r
+               );\r
+  if (Mismatch != 0) {\r
     Status = EFI_SECURITY_VIOLATION;\r
   }\r
 \r
   return Status;\r
 }\r
 \r
-\r
 /**\r
   This function checks the received iSCSI Login Response during the security\r
   negotiation stage.\r
@@ -151,32 +215,34 @@ IScsiCHAPOnRspReceived (
   IN ISCSI_CONNECTION  *Conn\r
   )\r
 {\r
-  EFI_STATUS                  Status;\r
-  ISCSI_SESSION               *Session;\r
-  ISCSI_CHAP_AUTH_DATA        *AuthData;\r
-  CHAR8                       *Value;\r
-  UINT8                       *Data;\r
-  UINT32                      Len;\r
-  LIST_ENTRY                  *KeyValueList;\r
-  UINTN                       Algorithm;\r
-  CHAR8                       *Identifier;\r
-  CHAR8                       *Challenge;\r
-  CHAR8                       *Name;\r
-  CHAR8                       *Response;\r
-  UINT8                       TargetRsp[ISCSI_CHAP_MAX_DIGEST_SIZE];\r
-  UINT32                      RspLen;\r
-  UINTN                       Result;\r
+  EFI_STATUS            Status;\r
+  ISCSI_SESSION         *Session;\r
+  ISCSI_CHAP_AUTH_DATA  *AuthData;\r
+  CHAR8                 *Value;\r
+  UINT8                 *Data;\r
+  UINT32                Len;\r
+  LIST_ENTRY            *KeyValueList;\r
+  UINTN                 Algorithm;\r
+  CHAR8                 *Identifier;\r
+  CHAR8                 *Challenge;\r
+  CHAR8                 *Name;\r
+  CHAR8                 *Response;\r
+  UINT8                 TargetRsp[ISCSI_CHAP_MAX_DIGEST_SIZE];\r
+  UINT32                RspLen;\r
+  UINTN                 Result;\r
+  UINTN                 HashIndex;\r
 \r
   ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
   ASSERT (Conn->RspQue.BufNum != 0);\r
 \r
-  Session     = Conn->Session;\r
-  AuthData    = &Session->AuthData.CHAP;\r
-  Len         = Conn->RspQue.BufSize;\r
-  Data        = AllocateZeroPool (Len);\r
+  Session  = Conn->Session;\r
+  AuthData = &Session->AuthData.CHAP;\r
+  Len      = Conn->RspQue.BufSize;\r
+  Data     = AllocateZeroPool (Len);\r
   if (Data == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
+\r
   //\r
   // Copy the data in case the data spans over multiple PDUs.\r
   //\r
@@ -185,7 +251,7 @@ IScsiCHAPOnRspReceived (
   //\r
   // Build the key-value list from the data segment of the Login Response.\r
   //\r
-  KeyValueList = IScsiBuildKeyValueList ((CHAR8 *) Data, Len);\r
+  KeyValueList = IScsiBuildKeyValueList ((CHAR8 *)Data, Len);\r
   if (KeyValueList == NULL) {\r
     Status = EFI_OUT_OF_RESOURCES;\r
     goto ON_EXIT;\r
@@ -194,167 +260,184 @@ IScsiCHAPOnRspReceived (
   Status = EFI_PROTOCOL_ERROR;\r
 \r
   switch (Conn->AuthStep) {\r
-  case ISCSI_AUTH_INITIAL:\r
-    //\r
-    // The first Login Response.\r
-    //\r
-    Value = IScsiGetValueByKeyFromList (\r
-              KeyValueList,\r
-              ISCSI_KEY_TARGET_PORTAL_GROUP_TAG\r
-              );\r
-    if (Value == NULL) {\r
-      goto ON_EXIT;\r
-    }\r
-\r
-    Result = IScsiNetNtoi (Value);\r
-    if (Result > 0xFFFF) {\r
-      goto ON_EXIT;\r
-    }\r
-\r
-    Session->TargetPortalGroupTag = (UINT16) Result;\r
-\r
-    Value                         = IScsiGetValueByKeyFromList (\r
-                                      KeyValueList,\r
-                                      ISCSI_KEY_AUTH_METHOD\r
-                                      );\r
-    if (Value == NULL) {\r
-      goto ON_EXIT;\r
-    }\r
-    //\r
-    // Initiator mandates CHAP authentication but target replies without\r
-    // "CHAP", or initiator suggets "None" but target replies with some kind of\r
-    // auth method.\r
-    //\r
-    if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) {\r
-      if (AsciiStrCmp (Value, ISCSI_KEY_VALUE_NONE) != 0) {\r
+    case ISCSI_AUTH_INITIAL:\r
+      //\r
+      // The first Login Response.\r
+      //\r
+      Value = IScsiGetValueByKeyFromList (\r
+                KeyValueList,\r
+                ISCSI_KEY_TARGET_PORTAL_GROUP_TAG\r
+                );\r
+      if (Value == NULL) {\r
         goto ON_EXIT;\r
       }\r
-    } else if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) {\r
-      if (AsciiStrCmp (Value, ISCSI_AUTH_METHOD_CHAP) != 0) {\r
+\r
+      Result = IScsiNetNtoi (Value);\r
+      if (Result > 0xFFFF) {\r
         goto ON_EXIT;\r
       }\r
-    } else {\r
-      goto ON_EXIT;\r
-    }\r
 \r
-    //\r
-    // Transit to CHAP step one.\r
-    //\r
-    Conn->AuthStep  = ISCSI_CHAP_STEP_ONE;\r
-    Status          = EFI_SUCCESS;\r
-    break;\r
+      Session->TargetPortalGroupTag = (UINT16)Result;\r
+\r
+      Value = IScsiGetValueByKeyFromList (\r
+                KeyValueList,\r
+                ISCSI_KEY_AUTH_METHOD\r
+                );\r
+      if (Value == NULL) {\r
+        goto ON_EXIT;\r
+      }\r
 \r
-  case ISCSI_CHAP_STEP_TWO:\r
-    //\r
-    // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>\r
-    //\r
-    Value = IScsiGetValueByKeyFromList (\r
-              KeyValueList,\r
-              ISCSI_KEY_CHAP_ALGORITHM\r
-              );\r
-    if (Value == NULL) {\r
-      goto ON_EXIT;\r
-    }\r
-\r
-    Algorithm = IScsiNetNtoi (Value);\r
-    if (Algorithm != ISCSI_CHAP_ALGORITHM_MD5) {\r
       //\r
-      // Unsupported algorithm is chosen by target.\r
+      // Initiator mandates CHAP authentication but target replies without\r
+      // "CHAP", or initiator suggets "None" but target replies with some kind of\r
+      // auth method.\r
       //\r
-      goto ON_EXIT;\r
-    }\r
+      if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) {\r
+        if (AsciiStrCmp (Value, ISCSI_KEY_VALUE_NONE) != 0) {\r
+          goto ON_EXIT;\r
+        }\r
+      } else if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) {\r
+        if (AsciiStrCmp (Value, ISCSI_AUTH_METHOD_CHAP) != 0) {\r
+          goto ON_EXIT;\r
+        }\r
+      } else {\r
+        goto ON_EXIT;\r
+      }\r
 \r
-    Identifier = IScsiGetValueByKeyFromList (\r
-                   KeyValueList,\r
-                   ISCSI_KEY_CHAP_IDENTIFIER\r
-                   );\r
-    if (Identifier == NULL) {\r
-      goto ON_EXIT;\r
-    }\r
-\r
-    Challenge = IScsiGetValueByKeyFromList (\r
-                  KeyValueList,\r
-                  ISCSI_KEY_CHAP_CHALLENGE\r
-                  );\r
-    if (Challenge == NULL) {\r
-      goto ON_EXIT;\r
-    }\r
-    //\r
-    // Process the CHAP identifier and CHAP Challenge from Target.\r
-    // Calculate Response value.\r
-    //\r
-    Result = IScsiNetNtoi (Identifier);\r
-    if (Result > 0xFF) {\r
-      goto ON_EXIT;\r
-    }\r
-\r
-    AuthData->InIdentifier      = (UINT32) Result;\r
-    AuthData->InChallengeLength = (UINT32) sizeof (AuthData->InChallenge);\r
-    Status = IScsiHexToBin (\r
-               (UINT8 *) AuthData->InChallenge,\r
-               &AuthData->InChallengeLength,\r
-               Challenge\r
-               );\r
-    if (EFI_ERROR (Status)) {\r
-      Status = EFI_PROTOCOL_ERROR;\r
-      goto ON_EXIT;\r
-    }\r
-    Status = IScsiCHAPCalculateResponse (\r
-               AuthData->InIdentifier,\r
-               AuthData->AuthConfig->CHAPSecret,\r
-               (UINT32) AsciiStrLen (AuthData->AuthConfig->CHAPSecret),\r
-               AuthData->InChallenge,\r
-               AuthData->InChallengeLength,\r
-               AuthData->CHAPResponse\r
-               );\r
+      //\r
+      // Transit to CHAP step one.\r
+      //\r
+      Conn->AuthStep = ISCSI_CHAP_STEP_ONE;\r
+      Status         = EFI_SUCCESS;\r
+      break;\r
 \r
-    //\r
-    // Transit to next step.\r
-    //\r
-    Conn->AuthStep = ISCSI_CHAP_STEP_THREE;\r
-    break;\r
+    case ISCSI_CHAP_STEP_TWO:\r
+      //\r
+      // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>\r
+      //\r
+      Value = IScsiGetValueByKeyFromList (\r
+                KeyValueList,\r
+                ISCSI_KEY_CHAP_ALGORITHM\r
+                );\r
+      if (Value == NULL) {\r
+        goto ON_EXIT;\r
+      }\r
 \r
-  case ISCSI_CHAP_STEP_THREE:\r
-    //\r
-    // One way CHAP authentication and the target would like to\r
-    // authenticate us.\r
-    //\r
-    Status = EFI_SUCCESS;\r
-    break;\r
+      Algorithm = IScsiNetNtoi (Value);\r
+      for (HashIndex = 0; HashIndex < ARRAY_SIZE (mChapHash); HashIndex++) {\r
+        if (Algorithm == mChapHash[HashIndex].Algorithm) {\r
+          break;\r
+        }\r
+      }\r
 \r
-  case ISCSI_CHAP_STEP_FOUR:\r
-    ASSERT (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL);\r
-    //\r
-    // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.\r
-    //\r
-    Name = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_NAME);\r
-    if (Name == NULL) {\r
-      goto ON_EXIT;\r
-    }\r
-\r
-    Response = IScsiGetValueByKeyFromList (\r
-                 KeyValueList,\r
-                 ISCSI_KEY_CHAP_RESPONSE\r
+      if (HashIndex == ARRAY_SIZE (mChapHash)) {\r
+        //\r
+        // Unsupported algorithm is chosen by target.\r
+        //\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      //\r
+      // Remember the target's chosen hash algorithm.\r
+      //\r
+      ASSERT (AuthData->Hash == NULL);\r
+      AuthData->Hash = &mChapHash[HashIndex];\r
+\r
+      Identifier = IScsiGetValueByKeyFromList (\r
+                     KeyValueList,\r
+                     ISCSI_KEY_CHAP_IDENTIFIER\r
+                     );\r
+      if (Identifier == NULL) {\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      Challenge = IScsiGetValueByKeyFromList (\r
+                    KeyValueList,\r
+                    ISCSI_KEY_CHAP_CHALLENGE\r
+                    );\r
+      if (Challenge == NULL) {\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      //\r
+      // Process the CHAP identifier and CHAP Challenge from Target.\r
+      // Calculate Response value.\r
+      //\r
+      Result = IScsiNetNtoi (Identifier);\r
+      if (Result > 0xFF) {\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      AuthData->InIdentifier      = (UINT32)Result;\r
+      AuthData->InChallengeLength = (UINT32)sizeof (AuthData->InChallenge);\r
+      Status                      = IScsiHexToBin (\r
+                                      (UINT8 *)AuthData->InChallenge,\r
+                                      &AuthData->InChallengeLength,\r
+                                      Challenge\r
+                                      );\r
+      if (EFI_ERROR (Status)) {\r
+        Status = EFI_PROTOCOL_ERROR;\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      Status = IScsiCHAPCalculateResponse (\r
+                 AuthData->InIdentifier,\r
+                 AuthData->AuthConfig->CHAPSecret,\r
+                 (UINT32)AsciiStrLen (AuthData->AuthConfig->CHAPSecret),\r
+                 AuthData->InChallenge,\r
+                 AuthData->InChallengeLength,\r
+                 AuthData->Hash,\r
+                 AuthData->CHAPResponse\r
                  );\r
-    if (Response == NULL) {\r
-      goto ON_EXIT;\r
-    }\r
 \r
-    RspLen = MD5_DIGEST_SIZE;\r
-    Status = IScsiHexToBin (TargetRsp, &RspLen, Response);\r
-    if (EFI_ERROR (Status) || RspLen != MD5_DIGEST_SIZE) {\r
-      Status = EFI_PROTOCOL_ERROR;\r
-      goto ON_EXIT;\r
-    }\r
+      //\r
+      // Transit to next step.\r
+      //\r
+      Conn->AuthStep = ISCSI_CHAP_STEP_THREE;\r
+      break;\r
 \r
-    //\r
-    // Check the CHAP Name and Response replied by Target.\r
-    //\r
-    Status = IScsiCHAPAuthTarget (AuthData, TargetRsp);\r
-    break;\r
+    case ISCSI_CHAP_STEP_THREE:\r
+      //\r
+      // One way CHAP authentication and the target would like to\r
+      // authenticate us.\r
+      //\r
+      Status = EFI_SUCCESS;\r
+      break;\r
+\r
+    case ISCSI_CHAP_STEP_FOUR:\r
+      ASSERT (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL);\r
+      //\r
+      // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.\r
+      //\r
+      Name = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_NAME);\r
+      if (Name == NULL) {\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      Response = IScsiGetValueByKeyFromList (\r
+                   KeyValueList,\r
+                   ISCSI_KEY_CHAP_RESPONSE\r
+                   );\r
+      if (Response == NULL) {\r
+        goto ON_EXIT;\r
+      }\r
 \r
-  default:\r
-    break;\r
+      ASSERT (AuthData->Hash != NULL);\r
+      RspLen = AuthData->Hash->DigestSize;\r
+      Status = IScsiHexToBin (TargetRsp, &RspLen, Response);\r
+      if (EFI_ERROR (Status) || (RspLen != AuthData->Hash->DigestSize)) {\r
+        Status = EFI_PROTOCOL_ERROR;\r
+        goto ON_EXIT;\r
+      }\r
+\r
+      //\r
+      // Check the CHAP Name and Response replied by Target.\r
+      //\r
+      Status = IScsiCHAPAuthTarget (AuthData, TargetRsp);\r
+      break;\r
+\r
+    default:\r
+      break;\r
   }\r
 \r
 ON_EXIT:\r
@@ -368,7 +451,6 @@ ON_EXIT:
   return Status;\r
 }\r
 \r
-\r
 /**\r
   This function fills the CHAP authentication information into the login PDU\r
   during the security negotiation stage in the iSCSI connection login.\r
@@ -389,137 +471,142 @@ IScsiCHAPToSendReq (
   IN OUT  NET_BUF           *Pdu\r
   )\r
 {\r
-  EFI_STATUS                  Status;\r
-  ISCSI_SESSION               *Session;\r
-  ISCSI_LOGIN_REQUEST         *LoginReq;\r
-  ISCSI_CHAP_AUTH_DATA        *AuthData;\r
-  CHAR8                       *Value;\r
-  CHAR8                       ValueStr[256];\r
-  CHAR8                       *Response;\r
-  UINT32                      RspLen;\r
-  CHAR8                       *Challenge;\r
-  UINT32                      ChallengeLen;\r
-  EFI_STATUS                  BinToHexStatus;\r
+  EFI_STATUS            Status;\r
+  ISCSI_SESSION         *Session;\r
+  ISCSI_LOGIN_REQUEST   *LoginReq;\r
+  ISCSI_CHAP_AUTH_DATA  *AuthData;\r
+  CHAR8                 *Value;\r
+  CHAR8                 ValueStr[256];\r
+  CHAR8                 *Response;\r
+  UINT32                RspLen;\r
+  CHAR8                 *Challenge;\r
+  UINT32                ChallengeLen;\r
+  EFI_STATUS            BinToHexStatus;\r
 \r
   ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
 \r
-  Session     = Conn->Session;\r
-  AuthData    = &Session->AuthData.CHAP;\r
-  LoginReq    = (ISCSI_LOGIN_REQUEST *) NetbufGetByte (Pdu, 0, 0);\r
+  Session  = Conn->Session;\r
+  AuthData = &Session->AuthData.CHAP;\r
+  LoginReq = (ISCSI_LOGIN_REQUEST *)NetbufGetByte (Pdu, 0, 0);\r
   if (LoginReq == NULL) {\r
     return EFI_PROTOCOL_ERROR;\r
   }\r
-  Status      = EFI_SUCCESS;\r
 \r
-  RspLen      = 2 * ISCSI_CHAP_MAX_DIGEST_SIZE + 3;\r
-  Response    = AllocateZeroPool (RspLen);\r
+  Status = EFI_SUCCESS;\r
+\r
+  RspLen   = 2 * ISCSI_CHAP_MAX_DIGEST_SIZE + 3;\r
+  Response = AllocateZeroPool (RspLen);\r
   if (Response == NULL) {\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
-  ChallengeLen  = 2 * ISCSI_CHAP_MAX_DIGEST_SIZE + 3;\r
-  Challenge     = AllocateZeroPool (ChallengeLen);\r
+  ChallengeLen = 2 * ISCSI_CHAP_MAX_DIGEST_SIZE + 3;\r
+  Challenge    = AllocateZeroPool (ChallengeLen);\r
   if (Challenge == NULL) {\r
     FreePool (Response);\r
     return EFI_OUT_OF_RESOURCES;\r
   }\r
 \r
   switch (Conn->AuthStep) {\r
-  case ISCSI_AUTH_INITIAL:\r
-    //\r
-    // It's the initial Login Request. Fill in the key=value pairs mandatory\r
-    // for the initial Login Request.\r
-    //\r
-    IScsiAddKeyValuePair (\r
-      Pdu,\r
-      ISCSI_KEY_INITIATOR_NAME,\r
-      mPrivate->InitiatorName\r
-      );\r
-    IScsiAddKeyValuePair (Pdu, ISCSI_KEY_SESSION_TYPE, "Normal");\r
-    IScsiAddKeyValuePair (\r
-      Pdu,\r
-      ISCSI_KEY_TARGET_NAME,\r
-      Session->ConfigData->SessionConfigData.TargetName\r
-      );\r
-\r
-    if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) {\r
-      Value = ISCSI_KEY_VALUE_NONE;\r
-      ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
-    } else {\r
-      Value = ISCSI_AUTH_METHOD_CHAP;\r
-    }\r
+    case ISCSI_AUTH_INITIAL:\r
+      //\r
+      // It's the initial Login Request. Fill in the key=value pairs mandatory\r
+      // for the initial Login Request.\r
+      //\r
+      IScsiAddKeyValuePair (\r
+        Pdu,\r
+        ISCSI_KEY_INITIATOR_NAME,\r
+        mPrivate->InitiatorName\r
+        );\r
+      IScsiAddKeyValuePair (Pdu, ISCSI_KEY_SESSION_TYPE, "Normal");\r
+      IScsiAddKeyValuePair (\r
+        Pdu,\r
+        ISCSI_KEY_TARGET_NAME,\r
+        Session->ConfigData->SessionConfigData.TargetName\r
+        );\r
+\r
+      if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) {\r
+        Value = ISCSI_KEY_VALUE_NONE;\r
+        ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
+      } else {\r
+        Value = ISCSI_AUTH_METHOD_CHAP;\r
+      }\r
 \r
-    IScsiAddKeyValuePair (Pdu, ISCSI_KEY_AUTH_METHOD, Value);\r
+      IScsiAddKeyValuePair (Pdu, ISCSI_KEY_AUTH_METHOD, Value);\r
 \r
-    break;\r
+      break;\r
 \r
-  case ISCSI_CHAP_STEP_ONE:\r
-    //\r
-    // First step, send the Login Request with CHAP_A=<A1,A2...> key-value\r
-    // pair.\r
-    //\r
-    AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", ISCSI_CHAP_ALGORITHM_MD5);\r
-    IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, ValueStr);\r
+    case ISCSI_CHAP_STEP_ONE:\r
+      //\r
+      // First step, send the Login Request with CHAP_A=<A1,A2...> key-value\r
+      // pair.\r
+      //\r
+      IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, mChapHashListString);\r
 \r
-    Conn->AuthStep = ISCSI_CHAP_STEP_TWO;\r
-    break;\r
+      Conn->AuthStep = ISCSI_CHAP_STEP_TWO;\r
+      break;\r
 \r
-  case ISCSI_CHAP_STEP_THREE:\r
-    //\r
-    // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or\r
-    // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target authentication is\r
-    // required too.\r
-    //\r
-    // CHAP_N=<N>\r
-    //\r
-    IScsiAddKeyValuePair (\r
-      Pdu,\r
-      ISCSI_KEY_CHAP_NAME,\r
-      (CHAR8 *) &AuthData->AuthConfig->CHAPName\r
-      );\r
-    //\r
-    // CHAP_R=<R>\r
-    //\r
-    BinToHexStatus = IScsiBinToHex (\r
-                       (UINT8 *) AuthData->CHAPResponse,\r
-                       MD5_DIGEST_SIZE,\r
-                       Response,\r
-                       &RspLen\r
-                       );\r
-    ASSERT_EFI_ERROR (BinToHexStatus);\r
-    IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_RESPONSE, Response);\r
-\r
-    if (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL) {\r
+    case ISCSI_CHAP_STEP_THREE:\r
+      //\r
+      // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or\r
+      // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target authentication is\r
+      // required too.\r
       //\r
-      // CHAP_I=<I>\r
+      // CHAP_N=<N>\r
       //\r
-      IScsiGenRandom ((UINT8 *) &AuthData->OutIdentifier, 1);\r
-      AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier);\r
-      IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr);\r
+      IScsiAddKeyValuePair (\r
+        Pdu,\r
+        ISCSI_KEY_CHAP_NAME,\r
+        (CHAR8 *)&AuthData->AuthConfig->CHAPName\r
+        );\r
       //\r
-      // CHAP_C=<C>\r
+      // CHAP_R=<R>\r
       //\r
-      IScsiGenRandom ((UINT8 *) AuthData->OutChallenge, MD5_DIGEST_SIZE);\r
+      ASSERT (AuthData->Hash != NULL);\r
       BinToHexStatus = IScsiBinToHex (\r
-                         (UINT8 *) AuthData->OutChallenge,\r
-                         MD5_DIGEST_SIZE,\r
-                         Challenge,\r
-                         &ChallengeLen\r
+                         (UINT8 *)AuthData->CHAPResponse,\r
+                         AuthData->Hash->DigestSize,\r
+                         Response,\r
+                         &RspLen\r
                          );\r
       ASSERT_EFI_ERROR (BinToHexStatus);\r
-      IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_CHALLENGE, Challenge);\r
+      IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_RESPONSE, Response);\r
+\r
+      if (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL) {\r
+        //\r
+        // CHAP_I=<I>\r
+        //\r
+        IScsiGenRandom ((UINT8 *)&AuthData->OutIdentifier, 1);\r
+        AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier);\r
+        IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr);\r
+        //\r
+        // CHAP_C=<C>\r
+        //\r
+        IScsiGenRandom (\r
+          (UINT8 *)AuthData->OutChallenge,\r
+          AuthData->Hash->DigestSize\r
+          );\r
+        BinToHexStatus = IScsiBinToHex (\r
+                           (UINT8 *)AuthData->OutChallenge,\r
+                           AuthData->Hash->DigestSize,\r
+                           Challenge,\r
+                           &ChallengeLen\r
+                           );\r
+        ASSERT_EFI_ERROR (BinToHexStatus);\r
+        IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_CHALLENGE, Challenge);\r
+\r
+        Conn->AuthStep = ISCSI_CHAP_STEP_FOUR;\r
+      }\r
 \r
-      Conn->AuthStep = ISCSI_CHAP_STEP_FOUR;\r
-    }\r
-    //\r
-    // Set the stage transition flag.\r
-    //\r
-    ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
-    break;\r
+      //\r
+      // Set the stage transition flag.\r
+      //\r
+      ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
+      break;\r
 \r
-  default:\r
-    Status = EFI_PROTOCOL_ERROR;\r
-    break;\r
+    default:\r
+      Status = EFI_PROTOCOL_ERROR;\r
+      break;\r
   }\r
 \r
   FreePool (Response);\r
@@ -527,3 +614,60 @@ IScsiCHAPToSendReq (
 \r
   return Status;\r
 }\r
+\r
+/**\r
+  Initialize the CHAP_A=<A1,A2...> *value* string for the entire driver, to be\r
+  sent by the initiator in ISCSI_CHAP_STEP_ONE.\r
+\r
+  This function sanity-checks the internal table of supported CHAP hashing\r
+  algorithms, as well.\r
+**/\r
+VOID\r
+IScsiCHAPInitHashList (\r
+  VOID\r
+  )\r
+{\r
+  CHAR8            *Position;\r
+  UINTN            Left;\r
+  UINTN            HashIndex;\r
+  CONST CHAP_HASH  *Hash;\r
+  UINTN            Printed;\r
+\r
+  Position = mChapHashListString;\r
+  Left     = sizeof (mChapHashListString);\r
+  for (HashIndex = 0; HashIndex < ARRAY_SIZE (mChapHash); HashIndex++) {\r
+    Hash = &mChapHash[HashIndex];\r
+\r
+    //\r
+    // Format the next hash identifier.\r
+    //\r
+    // Assert that we can format at least one non-NUL character, i.e. that we\r
+    // can progress. Truncation is checked after printing.\r
+    //\r
+    ASSERT (Left >= 2);\r
+    Printed = AsciiSPrint (\r
+                Position,\r
+                Left,\r
+                "%a%d",\r
+                (HashIndex == 0) ? "" : ",",\r
+                Hash->Algorithm\r
+                );\r
+    //\r
+    // There's no way to differentiate between the "buffer filled to the brim,\r
+    // but not truncated" result and the "truncated" result of AsciiSPrint().\r
+    // This is why "mChapHashListString" has an extra byte allocated, and the\r
+    // reason why we use the less-than (rather than the less-than-or-equal-to)\r
+    // relational operator in the assertion below -- we enforce "no truncation"\r
+    // by excluding the "completely used up" case too.\r
+    //\r
+    ASSERT (Printed + 1 < Left);\r
+\r
+    Position += Printed;\r
+    Left     -= Printed;\r
+\r
+    //\r
+    // Sanity-check the digest size for Hash.\r
+    //\r
+    ASSERT (Hash->DigestSize <= ISCSI_CHAP_MAX_DIGEST_SIZE);\r
+  }\r
+}\r