X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=NetworkPkg%2FIScsiDxe%2FIScsiCHAP.c;h=b507f11cd45e258a038427ef0f125476df816711;hb=d1050b9dff1cace252aff86630bfdb59dff5f507;hp=744824e63d233e7fa0562796b913c5e9d13b8648;hpb=7b6c2b2a26d0ae0a1d0beb8a9ac81cd934646c99;p=mirror_edk2.git diff --git a/NetworkPkg/IScsiDxe/IScsiCHAP.c b/NetworkPkg/IScsiDxe/IScsiCHAP.c index 744824e63d..b507f11cd4 100644 --- a/NetworkPkg/IScsiDxe/IScsiCHAP.c +++ b/NetworkPkg/IScsiDxe/IScsiCHAP.c @@ -9,6 +9,53 @@ 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= 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. @@ -17,6 +64,10 @@ SPDX-License-Identifier: BSD-2-Clause-Patent @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 @@ -24,22 +75,24 @@ SPDX-License-Identifier: BSD-2-Clause-Patent @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 MD5 hash operation fail. - @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete MD5. + @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, - OUT UINT8 *ChapResponse + IN UINT32 ChapIdentifier, + IN CHAR8 *ChapSecret, + IN UINT32 SecretLength, + IN UINT8 *ChapChallenge, + IN UINT32 ChallengeLength, + IN CONST CHAP_HASH *Hash, + OUT UINT8 *ChapResponse ) { - UINTN Md5ContextSize; - VOID *Md5Ctx; + UINTN ContextSize; + VOID *Ctx; CHAR8 IdByte[1]; EFI_STATUS Status; @@ -47,46 +100,48 @@ IScsiCHAPCalculateResponse ( return EFI_PROTOCOL_ERROR; } - Md5ContextSize = Md5GetContextSize (); - Md5Ctx = AllocatePool (Md5ContextSize); - if (Md5Ctx == NULL) { + ASSERT (Hash != NULL); + + ContextSize = Hash->GetContextSize (); + Ctx = AllocatePool (ContextSize); + if (Ctx == NULL) { return EFI_OUT_OF_RESOURCES; } Status = EFI_PROTOCOL_ERROR; - if (!Md5Init (Md5Ctx)) { + if (!Hash->Init (Ctx)) { goto Exit; } // // Hash Identifier - Only calculate 1 byte data (RFC1994) // - IdByte[0] = (CHAR8) ChapIdentifier; - if (!Md5Update (Md5Ctx, IdByte, 1)) { + IdByte[0] = (CHAR8)ChapIdentifier; + if (!Hash->Update (Ctx, IdByte, 1)) { goto Exit; } // // Hash Secret // - if (!Md5Update (Md5Ctx, ChapSecret, SecretLength)) { + if (!Hash->Update (Ctx, ChapSecret, SecretLength)) { goto Exit; } // // Hash Challenge received from Target // - if (!Md5Update (Md5Ctx, ChapChallenge, ChallengeLength)) { + if (!Hash->Update (Ctx, ChapChallenge, ChallengeLength)) { goto Exit; } - if (Md5Final (Md5Ctx, ChapResponse)) { + if (Hash->Final (Ctx, ChapResponse)) { Status = EFI_SUCCESS; } Exit: - FreePool (Md5Ctx); + FreePool (Ctx); return Status; } @@ -113,27 +168,36 @@ IScsiCHAPAuthTarget ( EFI_STATUS Status; UINT32 SecretSize; UINT8 VerifyRsp[ISCSI_CHAP_MAX_DIGEST_SIZE]; + INTN Mismatch; + + Status = EFI_SUCCESS; - Status = EFI_SUCCESS; + SecretSize = (UINT32)AsciiStrLen (AuthData->AuthConfig->ReverseCHAPSecret); + + ASSERT (AuthData->Hash != NULL); - SecretSize = (UINT32) AsciiStrLen (AuthData->AuthConfig->ReverseCHAPSecret); Status = IScsiCHAPCalculateResponse ( AuthData->OutIdentifier, AuthData->AuthConfig->ReverseCHAPSecret, SecretSize, AuthData->OutChallenge, - MD5_DIGEST_SIZE, // ChallengeLength + AuthData->Hash->DigestSize, // ChallengeLength + AuthData->Hash, VerifyRsp ); - if (CompareMem (VerifyRsp, TargetResponse, MD5_DIGEST_SIZE) != 0) { + 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. @@ -151,32 +215,34 @@ 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; + 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); + 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. // @@ -185,7 +251,7 @@ IScsiCHAPOnRspReceived ( // // Build the key-value list from the data segment of the Login Response. // - KeyValueList = IScsiBuildKeyValueList ((CHAR8 *) Data, Len); + KeyValueList = IScsiBuildKeyValueList ((CHAR8 *)Data, Len); if (KeyValueList == NULL) { Status = EFI_OUT_OF_RESOURCES; goto ON_EXIT; @@ -194,167 +260,184 @@ IScsiCHAPOnRspReceived ( 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) { + case ISCSI_AUTH_INITIAL: + // + // The first Login Response. + // + Value = IScsiGetValueByKeyFromList ( + KeyValueList, + ISCSI_KEY_TARGET_PORTAL_GROUP_TAG + ); + if (Value == NULL) { goto ON_EXIT; } - } else if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) { - if (AsciiStrCmp (Value, ISCSI_AUTH_METHOD_CHAP) != 0) { + + Result = IScsiNetNtoi (Value); + if (Result > 0xFFFF) { goto ON_EXIT; } - } else { - goto ON_EXIT; - } - // - // Transit to CHAP step one. - // - Conn->AuthStep = ISCSI_CHAP_STEP_ONE; - Status = EFI_SUCCESS; - break; + Session->TargetPortalGroupTag = (UINT16)Result; + + Value = IScsiGetValueByKeyFromList ( + KeyValueList, + ISCSI_KEY_AUTH_METHOD + ); + if (Value == NULL) { + goto ON_EXIT; + } - case ISCSI_CHAP_STEP_TWO: - // - // The Target replies with CHAP_A= CHAP_I= CHAP_C= - // - Value = IScsiGetValueByKeyFromList ( - KeyValueList, - ISCSI_KEY_CHAP_ALGORITHM - ); - if (Value == NULL) { - goto ON_EXIT; - } - - Algorithm = IScsiNetNtoi (Value); - if (Algorithm != ISCSI_CHAP_ALGORITHM_MD5) { // - // Unsupported algorithm is chosen by target. + // Initiator mandates CHAP authentication but target replies without + // "CHAP", or initiator suggets "None" but target replies with some kind of + // auth method. // - goto ON_EXIT; - } + 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; + } - 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->CHAPResponse - ); + // + // Transit to CHAP step one. + // + Conn->AuthStep = ISCSI_CHAP_STEP_ONE; + Status = EFI_SUCCESS; + break; - // - // Transit to next step. - // - Conn->AuthStep = ISCSI_CHAP_STEP_THREE; - break; + case ISCSI_CHAP_STEP_TWO: + // + // The Target replies with CHAP_A= CHAP_I= CHAP_C= + // + Value = IScsiGetValueByKeyFromList ( + KeyValueList, + ISCSI_KEY_CHAP_ALGORITHM + ); + if (Value == NULL) { + goto ON_EXIT; + } - case ISCSI_CHAP_STEP_THREE: - // - // One way CHAP authentication and the target would like to - // authenticate us. - // - Status = EFI_SUCCESS; - break; + Algorithm = IScsiNetNtoi (Value); + for (HashIndex = 0; HashIndex < ARRAY_SIZE (mChapHash); HashIndex++) { + if (Algorithm == mChapHash[HashIndex].Algorithm) { + break; + } + } - case ISCSI_CHAP_STEP_FOUR: - ASSERT (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL); - // - // The forth step, CHAP_N= CHAP_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 (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 ); - if (Response == NULL) { - goto ON_EXIT; - } - RspLen = MD5_DIGEST_SIZE; - Status = IScsiHexToBin (TargetRsp, &RspLen, Response); - if (EFI_ERROR (Status) || RspLen != MD5_DIGEST_SIZE) { - Status = EFI_PROTOCOL_ERROR; - goto ON_EXIT; - } + // + // Transit to next step. + // + Conn->AuthStep = ISCSI_CHAP_STEP_THREE; + break; - // - // Check the CHAP Name and Response replied by Target. - // - Status = IScsiCHAPAuthTarget (AuthData, TargetRsp); - 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= CHAP_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; + } - default: - break; + 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: @@ -368,7 +451,6 @@ ON_EXIT: return Status; } - /** This function fills the CHAP authentication information into the login PDU during the security negotiation stage in the iSCSI connection login. @@ -389,137 +471,142 @@ IScsiCHAPToSendReq ( 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; + 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); + 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); + 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); + 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; - } + 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); + IScsiAddKeyValuePair (Pdu, ISCSI_KEY_AUTH_METHOD, Value); - break; + break; - case ISCSI_CHAP_STEP_ONE: - // - // First step, send the Login Request with CHAP_A= key-value - // pair. - // - AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", ISCSI_CHAP_ALGORITHM_MD5); - IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, ValueStr); + case ISCSI_CHAP_STEP_ONE: + // + // First step, send the Login Request with CHAP_A= key-value + // pair. + // + IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, mChapHashListString); - Conn->AuthStep = ISCSI_CHAP_STEP_TWO; - break; + Conn->AuthStep = ISCSI_CHAP_STEP_TWO; + break; - case ISCSI_CHAP_STEP_THREE: - // - // Third step, send the Login Request with CHAP_N= CHAP_R= or - // CHAP_N= CHAP_R= CHAP_I= CHAP_C= if target authentication is - // required too. - // - // CHAP_N= - // - IScsiAddKeyValuePair ( - Pdu, - ISCSI_KEY_CHAP_NAME, - (CHAR8 *) &AuthData->AuthConfig->CHAPName - ); - // - // CHAP_R= - // - BinToHexStatus = IScsiBinToHex ( - (UINT8 *) AuthData->CHAPResponse, - MD5_DIGEST_SIZE, - Response, - &RspLen - ); - ASSERT_EFI_ERROR (BinToHexStatus); - IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_RESPONSE, Response); - - if (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL) { + case ISCSI_CHAP_STEP_THREE: + // + // Third step, send the Login Request with CHAP_N= CHAP_R= or + // CHAP_N= CHAP_R= CHAP_I= CHAP_C= if target authentication is + // required too. // - // CHAP_I= + // CHAP_N= // - IScsiGenRandom ((UINT8 *) &AuthData->OutIdentifier, 1); - AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier); - IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr); + IScsiAddKeyValuePair ( + Pdu, + ISCSI_KEY_CHAP_NAME, + (CHAR8 *)&AuthData->AuthConfig->CHAPName + ); // - // CHAP_C= + // CHAP_R= // - IScsiGenRandom ((UINT8 *) AuthData->OutChallenge, MD5_DIGEST_SIZE); + ASSERT (AuthData->Hash != NULL); BinToHexStatus = IScsiBinToHex ( - (UINT8 *) AuthData->OutChallenge, - MD5_DIGEST_SIZE, - Challenge, - &ChallengeLen + (UINT8 *)AuthData->CHAPResponse, + AuthData->Hash->DigestSize, + Response, + &RspLen ); ASSERT_EFI_ERROR (BinToHexStatus); - IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_CHALLENGE, Challenge); + IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_RESPONSE, Response); + + if (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL) { + // + // CHAP_I= + // + IScsiGenRandom ((UINT8 *)&AuthData->OutIdentifier, 1); + AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier); + IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr); + // + // CHAP_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; + } - Conn->AuthStep = ISCSI_CHAP_STEP_FOUR; - } - // - // Set the stage transition flag. - // - ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT); - break; + // + // Set the stage transition flag. + // + ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT); + break; - default: - Status = EFI_PROTOCOL_ERROR; - break; + default: + Status = EFI_PROTOCOL_ERROR; + break; } FreePool (Response); @@ -527,3 +614,60 @@ IScsiCHAPToSendReq ( return Status; } + +/** + Initialize the CHAP_A= *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); + } +}