REF: https://bugzilla.tianocore.org/show_bug.cgi?id=3737 Apply uncrustify changes to .c/.h files in the NetworkPkg package Cc: Andrew Fish <afish@apple.com> Cc: Leif Lindholm <leif@nuviainc.com> Cc: Michael D Kinney <michael.d.kinney@intel.com> Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com> Reviewed-by: Maciej Rabeda <maciej.rabeda@linux.intel.com>
		
			
				
	
	
		
			674 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			674 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
/** @file
 | 
						|
  This file is for Challenge-Handshake Authentication Protocol (CHAP)
 | 
						|
  Configuration.
 | 
						|
 | 
						|
Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
 | 
						|
SPDX-License-Identifier: BSD-2-Clause-Patent
 | 
						|
 | 
						|
**/
 | 
						|
 | 
						|
#include "IScsiImpl.h"
 | 
						|
 | 
						|
//
 | 
						|
// Supported CHAP hash algorithms, mapped to sets of BaseCryptLib APIs and
 | 
						|
// macros. CHAP_HASH structures at lower subscripts in the array are preferred
 | 
						|
// by the initiator.
 | 
						|
//
 | 
						|
STATIC CONST CHAP_HASH  mChapHash[] = {
 | 
						|
  {
 | 
						|
    ISCSI_CHAP_ALGORITHM_SHA256,
 | 
						|
    SHA256_DIGEST_SIZE,
 | 
						|
    Sha256GetContextSize,
 | 
						|
    Sha256Init,
 | 
						|
    Sha256Update,
 | 
						|
    Sha256Final
 | 
						|
  },
 | 
						|
 #ifdef ENABLE_MD5_DEPRECATED_INTERFACES
 | 
						|
  //
 | 
						|
  // Keep the deprecated MD5 entry at the end of the array (making MD5 the
 | 
						|
  // least preferred choice of the initiator).
 | 
						|
  //
 | 
						|
  {
 | 
						|
    ISCSI_CHAP_ALGORITHM_MD5,
 | 
						|
    MD5_DIGEST_SIZE,
 | 
						|
    Md5GetContextSize,
 | 
						|
    Md5Init,
 | 
						|
    Md5Update,
 | 
						|
    Md5Final
 | 
						|
  },
 | 
						|
 #endif // ENABLE_MD5_DEPRECATED_INTERFACES
 | 
						|
};
 | 
						|
 | 
						|
//
 | 
						|
// Ordered list of mChapHash[*].Algorithm values. It is formatted for the
 | 
						|
// CHAP_A=<A1,A2...> value string, by the IScsiCHAPInitHashList() function. It
 | 
						|
// is sent by the initiator in ISCSI_CHAP_STEP_ONE.
 | 
						|
//
 | 
						|
STATIC CHAR8  mChapHashListString[
 | 
						|
                                  3 +                                      // UINT8 identifier in
 | 
						|
                                                                           //   decimal
 | 
						|
                                  (1 + 3) * (ARRAY_SIZE (mChapHash) - 1) + // comma prepended for
 | 
						|
                                                                           //   entries after the
 | 
						|
                                                                           //   first
 | 
						|
                                  1 +                                      // extra character for
 | 
						|
                                                                           //   AsciiSPrint()
 | 
						|
                                                                           //   truncation check
 | 
						|
                                  1                                        // terminating NUL
 | 
						|
];
 | 
						|
 | 
						|
/**
 | 
						|
  Initiator calculates its own expected hash value.
 | 
						|
 | 
						|
  @param[in]   ChapIdentifier     iSCSI CHAP identifier sent by authenticator.
 | 
						|
  @param[in]   ChapSecret         iSCSI CHAP secret of the authenticator.
 | 
						|
  @param[in]   SecretLength       The length of iSCSI CHAP secret.
 | 
						|
  @param[in]   ChapChallenge      The challenge message sent by authenticator.
 | 
						|
  @param[in]   ChallengeLength    The length of iSCSI CHAP challenge message.
 | 
						|
  @param[in]   Hash               Pointer to the CHAP_HASH structure that
 | 
						|
                                  determines the hashing algorithm to use. The
 | 
						|
                                  caller is responsible for making Hash point
 | 
						|
                                  to an "mChapHash" element.
 | 
						|
  @param[out]  ChapResponse       The calculation of the expected hash value.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS             The expected hash value was calculatedly
 | 
						|
                                  successfully.
 | 
						|
  @retval EFI_PROTOCOL_ERROR      The length of the secret should be at least
 | 
						|
                                  the length of the hash value for the hashing
 | 
						|
                                  algorithm chosen.
 | 
						|
  @retval EFI_PROTOCOL_ERROR      Hash operation fails.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES    Failure to allocate resource to complete
 | 
						|
                                  hashing.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IScsiCHAPCalculateResponse (
 | 
						|
  IN  UINT32           ChapIdentifier,
 | 
						|
  IN  CHAR8            *ChapSecret,
 | 
						|
  IN  UINT32           SecretLength,
 | 
						|
  IN  UINT8            *ChapChallenge,
 | 
						|
  IN  UINT32           ChallengeLength,
 | 
						|
  IN  CONST CHAP_HASH  *Hash,
 | 
						|
  OUT UINT8            *ChapResponse
 | 
						|
  )
 | 
						|
{
 | 
						|
  UINTN       ContextSize;
 | 
						|
  VOID        *Ctx;
 | 
						|
  CHAR8       IdByte[1];
 | 
						|
  EFI_STATUS  Status;
 | 
						|
 | 
						|
  if (SecretLength < ISCSI_CHAP_SECRET_MIN_LEN) {
 | 
						|
    return EFI_PROTOCOL_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  ASSERT (Hash != NULL);
 | 
						|
 | 
						|
  ContextSize = Hash->GetContextSize ();
 | 
						|
  Ctx         = AllocatePool (ContextSize);
 | 
						|
  if (Ctx == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_PROTOCOL_ERROR;
 | 
						|
 | 
						|
  if (!Hash->Init (Ctx)) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Hash Identifier - Only calculate 1 byte data (RFC1994)
 | 
						|
  //
 | 
						|
  IdByte[0] = (CHAR8)ChapIdentifier;
 | 
						|
  if (!Hash->Update (Ctx, IdByte, 1)) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Hash Secret
 | 
						|
  //
 | 
						|
  if (!Hash->Update (Ctx, ChapSecret, SecretLength)) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Hash Challenge received from Target
 | 
						|
  //
 | 
						|
  if (!Hash->Update (Ctx, ChapChallenge, ChallengeLength)) {
 | 
						|
    goto Exit;
 | 
						|
  }
 | 
						|
 | 
						|
  if (Hash->Final (Ctx, ChapResponse)) {
 | 
						|
    Status = EFI_SUCCESS;
 | 
						|
  }
 | 
						|
 | 
						|
Exit:
 | 
						|
  FreePool (Ctx);
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  The initiator checks the CHAP response replied by target against its own
 | 
						|
  calculation of the expected hash value.
 | 
						|
 | 
						|
  @param[in]   AuthData             iSCSI CHAP authentication data.
 | 
						|
  @param[in]   TargetResponse       The response from target.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS               The response from target passed
 | 
						|
                                    authentication.
 | 
						|
  @retval EFI_SECURITY_VIOLATION    The response from target was not expected
 | 
						|
                                    value.
 | 
						|
  @retval Others                    Other errors as indicated.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IScsiCHAPAuthTarget (
 | 
						|
  IN  ISCSI_CHAP_AUTH_DATA  *AuthData,
 | 
						|
  IN  UINT8                 *TargetResponse
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS  Status;
 | 
						|
  UINT32      SecretSize;
 | 
						|
  UINT8       VerifyRsp[ISCSI_CHAP_MAX_DIGEST_SIZE];
 | 
						|
  INTN        Mismatch;
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  SecretSize = (UINT32)AsciiStrLen (AuthData->AuthConfig->ReverseCHAPSecret);
 | 
						|
 | 
						|
  ASSERT (AuthData->Hash != NULL);
 | 
						|
 | 
						|
  Status = IScsiCHAPCalculateResponse (
 | 
						|
             AuthData->OutIdentifier,
 | 
						|
             AuthData->AuthConfig->ReverseCHAPSecret,
 | 
						|
             SecretSize,
 | 
						|
             AuthData->OutChallenge,
 | 
						|
             AuthData->Hash->DigestSize,              // ChallengeLength
 | 
						|
             AuthData->Hash,
 | 
						|
             VerifyRsp
 | 
						|
             );
 | 
						|
 | 
						|
  Mismatch = CompareMem (
 | 
						|
               VerifyRsp,
 | 
						|
               TargetResponse,
 | 
						|
               AuthData->Hash->DigestSize
 | 
						|
               );
 | 
						|
  if (Mismatch != 0) {
 | 
						|
    Status = EFI_SECURITY_VIOLATION;
 | 
						|
  }
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function checks the received iSCSI Login Response during the security
 | 
						|
  negotiation stage.
 | 
						|
 | 
						|
  @param[in] Conn             The iSCSI connection.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS          The Login Response passed the CHAP validation.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
 | 
						|
  @retval EFI_PROTOCOL_ERROR   Some kind of protocol error occurred.
 | 
						|
  @retval Others               Other errors as indicated.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IScsiCHAPOnRspReceived (
 | 
						|
  IN ISCSI_CONNECTION  *Conn
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  ISCSI_SESSION         *Session;
 | 
						|
  ISCSI_CHAP_AUTH_DATA  *AuthData;
 | 
						|
  CHAR8                 *Value;
 | 
						|
  UINT8                 *Data;
 | 
						|
  UINT32                Len;
 | 
						|
  LIST_ENTRY            *KeyValueList;
 | 
						|
  UINTN                 Algorithm;
 | 
						|
  CHAR8                 *Identifier;
 | 
						|
  CHAR8                 *Challenge;
 | 
						|
  CHAR8                 *Name;
 | 
						|
  CHAR8                 *Response;
 | 
						|
  UINT8                 TargetRsp[ISCSI_CHAP_MAX_DIGEST_SIZE];
 | 
						|
  UINT32                RspLen;
 | 
						|
  UINTN                 Result;
 | 
						|
  UINTN                 HashIndex;
 | 
						|
 | 
						|
  ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);
 | 
						|
  ASSERT (Conn->RspQue.BufNum != 0);
 | 
						|
 | 
						|
  Session  = Conn->Session;
 | 
						|
  AuthData = &Session->AuthData.CHAP;
 | 
						|
  Len      = Conn->RspQue.BufSize;
 | 
						|
  Data     = AllocateZeroPool (Len);
 | 
						|
  if (Data == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  //
 | 
						|
  // Copy the data in case the data spans over multiple PDUs.
 | 
						|
  //
 | 
						|
  NetbufQueCopy (&Conn->RspQue, 0, Len, Data);
 | 
						|
 | 
						|
  //
 | 
						|
  // Build the key-value list from the data segment of the Login Response.
 | 
						|
  //
 | 
						|
  KeyValueList = IScsiBuildKeyValueList ((CHAR8 *)Data, Len);
 | 
						|
  if (KeyValueList == NULL) {
 | 
						|
    Status = EFI_OUT_OF_RESOURCES;
 | 
						|
    goto ON_EXIT;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_PROTOCOL_ERROR;
 | 
						|
 | 
						|
  switch (Conn->AuthStep) {
 | 
						|
    case ISCSI_AUTH_INITIAL:
 | 
						|
      //
 | 
						|
      // The first Login Response.
 | 
						|
      //
 | 
						|
      Value = IScsiGetValueByKeyFromList (
 | 
						|
                KeyValueList,
 | 
						|
                ISCSI_KEY_TARGET_PORTAL_GROUP_TAG
 | 
						|
                );
 | 
						|
      if (Value == NULL) {
 | 
						|
        goto ON_EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      Result = IScsiNetNtoi (Value);
 | 
						|
      if (Result > 0xFFFF) {
 | 
						|
        goto ON_EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      Session->TargetPortalGroupTag = (UINT16)Result;
 | 
						|
 | 
						|
      Value = IScsiGetValueByKeyFromList (
 | 
						|
                KeyValueList,
 | 
						|
                ISCSI_KEY_AUTH_METHOD
 | 
						|
                );
 | 
						|
      if (Value == NULL) {
 | 
						|
        goto ON_EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Initiator mandates CHAP authentication but target replies without
 | 
						|
      // "CHAP", or initiator suggets "None" but target replies with some kind of
 | 
						|
      // auth method.
 | 
						|
      //
 | 
						|
      if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) {
 | 
						|
        if (AsciiStrCmp (Value, ISCSI_KEY_VALUE_NONE) != 0) {
 | 
						|
          goto ON_EXIT;
 | 
						|
        }
 | 
						|
      } else if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) {
 | 
						|
        if (AsciiStrCmp (Value, ISCSI_AUTH_METHOD_CHAP) != 0) {
 | 
						|
          goto ON_EXIT;
 | 
						|
        }
 | 
						|
      } else {
 | 
						|
        goto ON_EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Transit to CHAP step one.
 | 
						|
      //
 | 
						|
      Conn->AuthStep = ISCSI_CHAP_STEP_ONE;
 | 
						|
      Status         = EFI_SUCCESS;
 | 
						|
      break;
 | 
						|
 | 
						|
    case ISCSI_CHAP_STEP_TWO:
 | 
						|
      //
 | 
						|
      // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>
 | 
						|
      //
 | 
						|
      Value = IScsiGetValueByKeyFromList (
 | 
						|
                KeyValueList,
 | 
						|
                ISCSI_KEY_CHAP_ALGORITHM
 | 
						|
                );
 | 
						|
      if (Value == NULL) {
 | 
						|
        goto ON_EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      Algorithm = IScsiNetNtoi (Value);
 | 
						|
      for (HashIndex = 0; HashIndex < ARRAY_SIZE (mChapHash); HashIndex++) {
 | 
						|
        if (Algorithm == mChapHash[HashIndex].Algorithm) {
 | 
						|
          break;
 | 
						|
        }
 | 
						|
      }
 | 
						|
 | 
						|
      if (HashIndex == ARRAY_SIZE (mChapHash)) {
 | 
						|
        //
 | 
						|
        // Unsupported algorithm is chosen by target.
 | 
						|
        //
 | 
						|
        goto ON_EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Remember the target's chosen hash algorithm.
 | 
						|
      //
 | 
						|
      ASSERT (AuthData->Hash == NULL);
 | 
						|
      AuthData->Hash = &mChapHash[HashIndex];
 | 
						|
 | 
						|
      Identifier = IScsiGetValueByKeyFromList (
 | 
						|
                     KeyValueList,
 | 
						|
                     ISCSI_KEY_CHAP_IDENTIFIER
 | 
						|
                     );
 | 
						|
      if (Identifier == NULL) {
 | 
						|
        goto ON_EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      Challenge = IScsiGetValueByKeyFromList (
 | 
						|
                    KeyValueList,
 | 
						|
                    ISCSI_KEY_CHAP_CHALLENGE
 | 
						|
                    );
 | 
						|
      if (Challenge == NULL) {
 | 
						|
        goto ON_EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Process the CHAP identifier and CHAP Challenge from Target.
 | 
						|
      // Calculate Response value.
 | 
						|
      //
 | 
						|
      Result = IScsiNetNtoi (Identifier);
 | 
						|
      if (Result > 0xFF) {
 | 
						|
        goto ON_EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      AuthData->InIdentifier      = (UINT32)Result;
 | 
						|
      AuthData->InChallengeLength = (UINT32)sizeof (AuthData->InChallenge);
 | 
						|
      Status                      = IScsiHexToBin (
 | 
						|
                                      (UINT8 *)AuthData->InChallenge,
 | 
						|
                                      &AuthData->InChallengeLength,
 | 
						|
                                      Challenge
 | 
						|
                                      );
 | 
						|
      if (EFI_ERROR (Status)) {
 | 
						|
        Status = EFI_PROTOCOL_ERROR;
 | 
						|
        goto ON_EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      Status = IScsiCHAPCalculateResponse (
 | 
						|
                 AuthData->InIdentifier,
 | 
						|
                 AuthData->AuthConfig->CHAPSecret,
 | 
						|
                 (UINT32)AsciiStrLen (AuthData->AuthConfig->CHAPSecret),
 | 
						|
                 AuthData->InChallenge,
 | 
						|
                 AuthData->InChallengeLength,
 | 
						|
                 AuthData->Hash,
 | 
						|
                 AuthData->CHAPResponse
 | 
						|
                 );
 | 
						|
 | 
						|
      //
 | 
						|
      // Transit to next step.
 | 
						|
      //
 | 
						|
      Conn->AuthStep = ISCSI_CHAP_STEP_THREE;
 | 
						|
      break;
 | 
						|
 | 
						|
    case ISCSI_CHAP_STEP_THREE:
 | 
						|
      //
 | 
						|
      // One way CHAP authentication and the target would like to
 | 
						|
      // authenticate us.
 | 
						|
      //
 | 
						|
      Status = EFI_SUCCESS;
 | 
						|
      break;
 | 
						|
 | 
						|
    case ISCSI_CHAP_STEP_FOUR:
 | 
						|
      ASSERT (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL);
 | 
						|
      //
 | 
						|
      // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.
 | 
						|
      //
 | 
						|
      Name = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_NAME);
 | 
						|
      if (Name == NULL) {
 | 
						|
        goto ON_EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      Response = IScsiGetValueByKeyFromList (
 | 
						|
                   KeyValueList,
 | 
						|
                   ISCSI_KEY_CHAP_RESPONSE
 | 
						|
                   );
 | 
						|
      if (Response == NULL) {
 | 
						|
        goto ON_EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      ASSERT (AuthData->Hash != NULL);
 | 
						|
      RspLen = AuthData->Hash->DigestSize;
 | 
						|
      Status = IScsiHexToBin (TargetRsp, &RspLen, Response);
 | 
						|
      if (EFI_ERROR (Status) || (RspLen != AuthData->Hash->DigestSize)) {
 | 
						|
        Status = EFI_PROTOCOL_ERROR;
 | 
						|
        goto ON_EXIT;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Check the CHAP Name and Response replied by Target.
 | 
						|
      //
 | 
						|
      Status = IScsiCHAPAuthTarget (AuthData, TargetRsp);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
ON_EXIT:
 | 
						|
 | 
						|
  if (KeyValueList != NULL) {
 | 
						|
    IScsiFreeKeyValueList (KeyValueList);
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (Data);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  This function fills the CHAP authentication information into the login PDU
 | 
						|
  during the security negotiation stage in the iSCSI connection login.
 | 
						|
 | 
						|
  @param[in]       Conn        The iSCSI connection.
 | 
						|
  @param[in, out]  Pdu         The PDU to send out.
 | 
						|
 | 
						|
  @retval EFI_SUCCESS           All check passed and the phase-related CHAP
 | 
						|
                                authentication info is filled into the iSCSI
 | 
						|
                                PDU.
 | 
						|
  @retval EFI_OUT_OF_RESOURCES  Failed to allocate memory.
 | 
						|
  @retval EFI_PROTOCOL_ERROR    Some kind of protocol error occurred.
 | 
						|
 | 
						|
**/
 | 
						|
EFI_STATUS
 | 
						|
IScsiCHAPToSendReq (
 | 
						|
  IN      ISCSI_CONNECTION  *Conn,
 | 
						|
  IN OUT  NET_BUF           *Pdu
 | 
						|
  )
 | 
						|
{
 | 
						|
  EFI_STATUS            Status;
 | 
						|
  ISCSI_SESSION         *Session;
 | 
						|
  ISCSI_LOGIN_REQUEST   *LoginReq;
 | 
						|
  ISCSI_CHAP_AUTH_DATA  *AuthData;
 | 
						|
  CHAR8                 *Value;
 | 
						|
  CHAR8                 ValueStr[256];
 | 
						|
  CHAR8                 *Response;
 | 
						|
  UINT32                RspLen;
 | 
						|
  CHAR8                 *Challenge;
 | 
						|
  UINT32                ChallengeLen;
 | 
						|
  EFI_STATUS            BinToHexStatus;
 | 
						|
 | 
						|
  ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);
 | 
						|
 | 
						|
  Session  = Conn->Session;
 | 
						|
  AuthData = &Session->AuthData.CHAP;
 | 
						|
  LoginReq = (ISCSI_LOGIN_REQUEST *)NetbufGetByte (Pdu, 0, 0);
 | 
						|
  if (LoginReq == NULL) {
 | 
						|
    return EFI_PROTOCOL_ERROR;
 | 
						|
  }
 | 
						|
 | 
						|
  Status = EFI_SUCCESS;
 | 
						|
 | 
						|
  RspLen   = 2 * ISCSI_CHAP_MAX_DIGEST_SIZE + 3;
 | 
						|
  Response = AllocateZeroPool (RspLen);
 | 
						|
  if (Response == NULL) {
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  ChallengeLen = 2 * ISCSI_CHAP_MAX_DIGEST_SIZE + 3;
 | 
						|
  Challenge    = AllocateZeroPool (ChallengeLen);
 | 
						|
  if (Challenge == NULL) {
 | 
						|
    FreePool (Response);
 | 
						|
    return EFI_OUT_OF_RESOURCES;
 | 
						|
  }
 | 
						|
 | 
						|
  switch (Conn->AuthStep) {
 | 
						|
    case ISCSI_AUTH_INITIAL:
 | 
						|
      //
 | 
						|
      // It's the initial Login Request. Fill in the key=value pairs mandatory
 | 
						|
      // for the initial Login Request.
 | 
						|
      //
 | 
						|
      IScsiAddKeyValuePair (
 | 
						|
        Pdu,
 | 
						|
        ISCSI_KEY_INITIATOR_NAME,
 | 
						|
        mPrivate->InitiatorName
 | 
						|
        );
 | 
						|
      IScsiAddKeyValuePair (Pdu, ISCSI_KEY_SESSION_TYPE, "Normal");
 | 
						|
      IScsiAddKeyValuePair (
 | 
						|
        Pdu,
 | 
						|
        ISCSI_KEY_TARGET_NAME,
 | 
						|
        Session->ConfigData->SessionConfigData.TargetName
 | 
						|
        );
 | 
						|
 | 
						|
      if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) {
 | 
						|
        Value = ISCSI_KEY_VALUE_NONE;
 | 
						|
        ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);
 | 
						|
      } else {
 | 
						|
        Value = ISCSI_AUTH_METHOD_CHAP;
 | 
						|
      }
 | 
						|
 | 
						|
      IScsiAddKeyValuePair (Pdu, ISCSI_KEY_AUTH_METHOD, Value);
 | 
						|
 | 
						|
      break;
 | 
						|
 | 
						|
    case ISCSI_CHAP_STEP_ONE:
 | 
						|
      //
 | 
						|
      // First step, send the Login Request with CHAP_A=<A1,A2...> key-value
 | 
						|
      // pair.
 | 
						|
      //
 | 
						|
      IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, mChapHashListString);
 | 
						|
 | 
						|
      Conn->AuthStep = ISCSI_CHAP_STEP_TWO;
 | 
						|
      break;
 | 
						|
 | 
						|
    case ISCSI_CHAP_STEP_THREE:
 | 
						|
      //
 | 
						|
      // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or
 | 
						|
      // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target authentication is
 | 
						|
      // required too.
 | 
						|
      //
 | 
						|
      // CHAP_N=<N>
 | 
						|
      //
 | 
						|
      IScsiAddKeyValuePair (
 | 
						|
        Pdu,
 | 
						|
        ISCSI_KEY_CHAP_NAME,
 | 
						|
        (CHAR8 *)&AuthData->AuthConfig->CHAPName
 | 
						|
        );
 | 
						|
      //
 | 
						|
      // CHAP_R=<R>
 | 
						|
      //
 | 
						|
      ASSERT (AuthData->Hash != NULL);
 | 
						|
      BinToHexStatus = IScsiBinToHex (
 | 
						|
                         (UINT8 *)AuthData->CHAPResponse,
 | 
						|
                         AuthData->Hash->DigestSize,
 | 
						|
                         Response,
 | 
						|
                         &RspLen
 | 
						|
                         );
 | 
						|
      ASSERT_EFI_ERROR (BinToHexStatus);
 | 
						|
      IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_RESPONSE, Response);
 | 
						|
 | 
						|
      if (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL) {
 | 
						|
        //
 | 
						|
        // CHAP_I=<I>
 | 
						|
        //
 | 
						|
        IScsiGenRandom ((UINT8 *)&AuthData->OutIdentifier, 1);
 | 
						|
        AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier);
 | 
						|
        IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr);
 | 
						|
        //
 | 
						|
        // CHAP_C=<C>
 | 
						|
        //
 | 
						|
        IScsiGenRandom (
 | 
						|
          (UINT8 *)AuthData->OutChallenge,
 | 
						|
          AuthData->Hash->DigestSize
 | 
						|
          );
 | 
						|
        BinToHexStatus = IScsiBinToHex (
 | 
						|
                           (UINT8 *)AuthData->OutChallenge,
 | 
						|
                           AuthData->Hash->DigestSize,
 | 
						|
                           Challenge,
 | 
						|
                           &ChallengeLen
 | 
						|
                           );
 | 
						|
        ASSERT_EFI_ERROR (BinToHexStatus);
 | 
						|
        IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_CHALLENGE, Challenge);
 | 
						|
 | 
						|
        Conn->AuthStep = ISCSI_CHAP_STEP_FOUR;
 | 
						|
      }
 | 
						|
 | 
						|
      //
 | 
						|
      // Set the stage transition flag.
 | 
						|
      //
 | 
						|
      ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);
 | 
						|
      break;
 | 
						|
 | 
						|
    default:
 | 
						|
      Status = EFI_PROTOCOL_ERROR;
 | 
						|
      break;
 | 
						|
  }
 | 
						|
 | 
						|
  FreePool (Response);
 | 
						|
  FreePool (Challenge);
 | 
						|
 | 
						|
  return Status;
 | 
						|
}
 | 
						|
 | 
						|
/**
 | 
						|
  Initialize the CHAP_A=<A1,A2...> *value* string for the entire driver, to be
 | 
						|
  sent by the initiator in ISCSI_CHAP_STEP_ONE.
 | 
						|
 | 
						|
  This function sanity-checks the internal table of supported CHAP hashing
 | 
						|
  algorithms, as well.
 | 
						|
**/
 | 
						|
VOID
 | 
						|
IScsiCHAPInitHashList (
 | 
						|
  VOID
 | 
						|
  )
 | 
						|
{
 | 
						|
  CHAR8            *Position;
 | 
						|
  UINTN            Left;
 | 
						|
  UINTN            HashIndex;
 | 
						|
  CONST CHAP_HASH  *Hash;
 | 
						|
  UINTN            Printed;
 | 
						|
 | 
						|
  Position = mChapHashListString;
 | 
						|
  Left     = sizeof (mChapHashListString);
 | 
						|
  for (HashIndex = 0; HashIndex < ARRAY_SIZE (mChapHash); HashIndex++) {
 | 
						|
    Hash = &mChapHash[HashIndex];
 | 
						|
 | 
						|
    //
 | 
						|
    // Format the next hash identifier.
 | 
						|
    //
 | 
						|
    // Assert that we can format at least one non-NUL character, i.e. that we
 | 
						|
    // can progress. Truncation is checked after printing.
 | 
						|
    //
 | 
						|
    ASSERT (Left >= 2);
 | 
						|
    Printed = AsciiSPrint (
 | 
						|
                Position,
 | 
						|
                Left,
 | 
						|
                "%a%d",
 | 
						|
                (HashIndex == 0) ? "" : ",",
 | 
						|
                Hash->Algorithm
 | 
						|
                );
 | 
						|
    //
 | 
						|
    // There's no way to differentiate between the "buffer filled to the brim,
 | 
						|
    // but not truncated" result and the "truncated" result of AsciiSPrint().
 | 
						|
    // This is why "mChapHashListString" has an extra byte allocated, and the
 | 
						|
    // reason why we use the less-than (rather than the less-than-or-equal-to)
 | 
						|
    // relational operator in the assertion below -- we enforce "no truncation"
 | 
						|
    // by excluding the "completely used up" case too.
 | 
						|
    //
 | 
						|
    ASSERT (Printed + 1 < Left);
 | 
						|
 | 
						|
    Position += Printed;
 | 
						|
    Left     -= Printed;
 | 
						|
 | 
						|
    //
 | 
						|
    // Sanity-check the digest size for Hash.
 | 
						|
    //
 | 
						|
    ASSERT (Hash->DigestSize <= ISCSI_CHAP_MAX_DIGEST_SIZE);
 | 
						|
  }
 | 
						|
}
 |