+++ /dev/null
-/** @file\r
- This file is for Challenge-Handshake Authentication Protocol (CHAP) Configuration.\r
-\r
-Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>\r
-This program and the accompanying materials\r
-are licensed and made available under the terms and conditions of the BSD License\r
-which accompanies this distribution. The full text of the license may be found at\r
-http://opensource.org/licenses/bsd-license.php\r
-\r
-THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
-WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
-\r
-**/\r
-\r
-#include "IScsiImpl.h"\r
-#include "Md5.h"\r
-\r
-/**\r
- Initator calculates its own expected hash value.\r
-\r
- @param[in] ChapIdentifier iSCSI CHAP identifier sent by authenticator.\r
- @param[in] ChapSecret iSCSI CHAP secret of the authenticator.\r
- @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[out] ChapResponse The calculation of the expected hash value.\r
-\r
- @retval EFI_SUCCESS The expected hash value was calculatedly successfully.\r
- @retval EFI_PROTOCOL_ERROR The length of the secret should be at least the\r
- length of the hash value for the hashing algorithm chosen.\r
- @retval Others Other errors as indicated.\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
- )\r
-{\r
- MD5_CTX Md5Ctx;\r
- CHAR8 IdByte[1];\r
- EFI_STATUS Status;\r
-\r
- Status = MD5Init (&Md5Ctx);\r
-\r
- //\r
- // Hash Identifier - Only calculate 1 byte data (RFC1994)\r
- //\r
- IdByte[0] = (CHAR8) ChapIdentifier;\r
- MD5Update (&Md5Ctx, IdByte, 1);\r
-\r
- //\r
- // Hash Secret\r
- //\r
- if (SecretLength < ISCSI_CHAP_SECRET_MIN_LEN - 1) {\r
- return EFI_PROTOCOL_ERROR;\r
- }\r
-\r
- MD5Update (&Md5Ctx, ChapSecret, SecretLength);\r
-\r
- //\r
- // Hash Challenge received from Target\r
- //\r
- MD5Update (&Md5Ctx, ChapChallenge, ChallengeLength);\r
-\r
- Status = MD5Final (&Md5Ctx, ChapResponse);\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- The initator checks the CHAP response replied by target against its own\r
- calculation of the expected hash value.\r
-\r
- @param[in] AuthData iSCSI CHAP authentication data.\r
- @param[in] TargetResponse The response from target.\r
-\r
- @retval EFI_SUCCESS The response from target passed authentication.\r
- @retval EFI_SECURITY_VIOLATION The response from target was not expected value.\r
- @retval Others Other errors as indicated.\r
-**/\r
-EFI_STATUS\r
-IScsiCHAPAuthTarget (\r
- IN ISCSI_CHAP_AUTH_DATA *AuthData,\r
- IN UINT8 *TargetResponse\r
- )\r
-{\r
- EFI_STATUS Status;\r
- UINT32 SecretSize;\r
- UINT8 VerifyRsp[ISCSI_CHAP_RSP_LEN];\r
-\r
- Status = EFI_SUCCESS;\r
-\r
- SecretSize = (UINT32) AsciiStrLen (AuthData->AuthConfig.ReverseCHAPSecret);\r
- Status = IScsiCHAPCalculateResponse (\r
- AuthData->OutIdentifier,\r
- AuthData->AuthConfig.ReverseCHAPSecret,\r
- SecretSize,\r
- AuthData->OutChallenge,\r
- AuthData->OutChallengeLength,\r
- VerifyRsp\r
- );\r
-\r
- if (CompareMem (VerifyRsp, TargetResponse, ISCSI_CHAP_RSP_LEN) != 0) {\r
- Status = EFI_SECURITY_VIOLATION;\r
- }\r
-\r
- return Status;\r
-}\r
-\r
-/**\r
- This function checks the received iSCSI Login Response during the security\r
- negotiation stage.\r
-\r
- @param[in] Conn The iSCSI connection.\r
-\r
- @retval EFI_SUCCESS The Login Response passed the CHAP validation.\r
- @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
- @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.\r
- @retval Others Other errors as indicated.\r
-**/\r
-EFI_STATUS\r
-IScsiCHAPOnRspReceived (\r
- 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_RSP_LEN];\r
- UINT32 RspLen;\r
-\r
- ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
- ASSERT (Conn->RspQue.BufNum != 0);\r
-\r
- Session = Conn->Session;\r
- AuthData = &Session->AuthData;\r
-\r
- Len = Conn->RspQue.BufSize;\r
- Data = AllocatePool (Len);\r
- if (Data == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
- //\r
- // Copy the data in case the data spans over multiple PDUs.\r
- //\r
- NetbufQueCopy (&Conn->RspQue, 0, Len, Data);\r
-\r
- //\r
- // Build the key-value list from the data segment of the Login Response.\r
- //\r
- KeyValueList = IScsiBuildKeyValueList ((CHAR8 *) Data, Len);\r
- if (KeyValueList == NULL) {\r
- FreePool (Data);\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- Status = EFI_PROTOCOL_ERROR;\r
-\r
- switch (Conn->CHAPStep) {\r
- case ISCSI_CHAP_INITIAL:\r
- //\r
- // The first Login Response.\r
- //\r
- Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG);\r
- if (Value == NULL) {\r
- goto ON_EXIT;\r
- }\r
-\r
- Session->TargetPortalGroupTag = (UINT16) AsciiStrDecimalToUintn (Value);\r
-\r
- Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_AUTH_METHOD);\r
- if (Value == NULL) {\r
- goto ON_EXIT;\r
- }\r
- //\r
- // Initiator mandates CHAP authentication but target replies without "CHAP" or\r
- // initiator suggets "None" but target replies with some kind of auth method.\r
- //\r
- if (AsciiStrCmp (Value, ISCSI_AUTH_METHOD_CHAP) == 0) {\r
- if (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_NONE) {\r
- goto ON_EXIT;\r
- }\r
- } else {\r
- if (AuthData->AuthConfig.CHAPType != ISCSI_CHAP_NONE) {\r
- goto ON_EXIT;\r
- }\r
- }\r
- //\r
- // Transit to CHAP step one.\r
- //\r
- Conn->CHAPStep = ISCSI_CHAP_STEP_ONE;\r
- Status = EFI_SUCCESS;\r
- break;\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 (KeyValueList, ISCSI_KEY_CHAP_ALGORITHM);\r
- if (Value == NULL) {\r
- goto ON_EXIT;\r
- }\r
-\r
- Algorithm = AsciiStrDecimalToUintn (Value);\r
- if (Algorithm != ISCSI_CHAP_ALGORITHM_MD5) {\r
- //\r
- // Unsupported algorithm is chosen by target.\r
- //\r
- goto ON_EXIT;\r
- }\r
-\r
- Identifier = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_IDENTIFIER);\r
- if (Identifier == NULL) {\r
- goto ON_EXIT;\r
- }\r
-\r
- Challenge = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_CHALLENGE);\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
- AuthData->InIdentifier = (UINT32) AsciiStrDecimalToUintn (Identifier);\r
- AuthData->InChallengeLength = ISCSI_CHAP_AUTH_MAX_LEN;\r
- IScsiHexToBin ((UINT8 *) AuthData->InChallenge, &AuthData->InChallengeLength, Challenge);\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
- //\r
- // Transit to next step.\r
- //\r
- Conn->CHAPStep = ISCSI_CHAP_STEP_THREE;\r
- break;\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
-\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 (KeyValueList, ISCSI_KEY_CHAP_RESPONSE);\r
- if (Response == NULL) {\r
- goto ON_EXIT;\r
- }\r
-\r
- RspLen = ISCSI_CHAP_RSP_LEN;\r
- IScsiHexToBin (TargetRsp, &RspLen, Response);\r
-\r
- //\r
- // Check the CHAP Response replied by Target.\r
- //\r
- Status = IScsiCHAPAuthTarget (AuthData, TargetRsp);\r
- break;\r
-\r
- default:\r
- break;\r
- }\r
-\r
-ON_EXIT:\r
-\r
- IScsiFreeKeyValueList (KeyValueList);\r
-\r
- FreePool (Data);\r
-\r
- return Status;\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
-\r
- @param[in] Conn The iSCSI connection.\r
- @param[in, out] Pdu The PDU to send out.\r
-\r
- @retval EFI_SUCCESS All check passed and the phase-related CHAP\r
- authentication info is filled into the iSCSI PDU.\r
- @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
- @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.\r
-**/\r
-EFI_STATUS\r
-IScsiCHAPToSendReq (\r
- IN ISCSI_CONNECTION *Conn,\r
- 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
-\r
- ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
-\r
- Session = Conn->Session;\r
- AuthData = &Session->AuthData;\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_RSP_LEN + 3;\r
- Response = AllocatePool (RspLen);\r
- if (Response == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- ChallengeLen = 2 * ISCSI_CHAP_RSP_LEN + 3;\r
- Challenge = AllocatePool (ChallengeLen);\r
- if (Challenge == NULL) {\r
- return EFI_OUT_OF_RESOURCES;\r
- }\r
-\r
- switch (Conn->CHAPStep) {\r
- case ISCSI_CHAP_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 (Pdu, ISCSI_KEY_INITIATOR_NAME, Session->InitiatorName);\r
- IScsiAddKeyValuePair (Pdu, ISCSI_KEY_SESSION_TYPE, "Normal");\r
- IScsiAddKeyValuePair (Pdu, ISCSI_KEY_TARGET_NAME, Session->ConfigData.NvData.TargetName);\r
-\r
- if (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_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
-\r
- break;\r
-\r
- case ISCSI_CHAP_STEP_ONE:\r
- //\r
- // First step, send the Login Request with CHAP_A=<A1,A2...> key-value pair.\r
- //\r
- AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", ISCSI_CHAP_ALGORITHM_MD5);\r
- IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, ValueStr);\r
-\r
- Conn->CHAPStep = 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 ahtentication is\r
- // required too.\r
- //\r
- // CHAP_N=<N>\r
- //\r
- IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_NAME, (CHAR8 *) &AuthData->AuthConfig.CHAPName);\r
- //\r
- // CHAP_R=<R>\r
- //\r
- IScsiBinToHex ((UINT8 *) AuthData->CHAPResponse, ISCSI_CHAP_RSP_LEN, Response, &RspLen);\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 ((UINT8 *) AuthData->OutChallenge, ISCSI_CHAP_RSP_LEN);\r
- AuthData->OutChallengeLength = ISCSI_CHAP_RSP_LEN;\r
- IScsiBinToHex ((UINT8 *) AuthData->OutChallenge, ISCSI_CHAP_RSP_LEN, Challenge, &ChallengeLen);\r
- IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_CHALLENGE, Challenge);\r
-\r
- Conn->CHAPStep = 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
- default:\r
- Status = EFI_PROTOCOL_ERROR;\r
- break;\r
- }\r
-\r
- FreePool (Response);\r
- FreePool (Challenge);\r
-\r
- return Status;\r
-}\r