\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
@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
@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
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
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
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
//\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
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
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
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
\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