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);
 | |
|   }
 | |
| }
 |