2 This file is for Challenge-Handshake Authentication Protocol (CHAP) Configuration.
4 Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
12 Initiator calculates its own expected hash value.
14 @param[in] ChapIdentifier iSCSI CHAP identifier sent by authenticator.
15 @param[in] ChapSecret iSCSI CHAP secret of the authenticator.
16 @param[in] SecretLength The length of iSCSI CHAP secret.
17 @param[in] ChapChallenge The challenge message sent by authenticator.
18 @param[in] ChallengeLength The length of iSCSI CHAP challenge message.
19 @param[out] ChapResponse The calculation of the expected hash value.
21 @retval EFI_SUCCESS The expected hash value was calculatedly successfully.
22 @retval EFI_PROTOCOL_ERROR The length of the secret should be at least the
23 length of the hash value for the hashing algorithm chosen.
24 @retval EFI_PROTOCOL_ERROR MD5 hash operation fail.
25 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete MD5.
29 IScsiCHAPCalculateResponse (
30 IN UINT32 ChapIdentifier
,
32 IN UINT32 SecretLength
,
33 IN UINT8
*ChapChallenge
,
34 IN UINT32 ChallengeLength
,
35 OUT UINT8
*ChapResponse
43 if (SecretLength
< ISCSI_CHAP_SECRET_MIN_LEN
) {
44 return EFI_PROTOCOL_ERROR
;
47 Md5ContextSize
= Md5GetContextSize ();
48 Md5Ctx
= AllocatePool (Md5ContextSize
);
50 return EFI_OUT_OF_RESOURCES
;
53 Status
= EFI_PROTOCOL_ERROR
;
55 if (!Md5Init (Md5Ctx
)) {
60 // Hash Identifier - Only calculate 1 byte data (RFC1994)
62 IdByte
[0] = (CHAR8
) ChapIdentifier
;
63 if (!Md5Update (Md5Ctx
, IdByte
, 1)) {
70 if (!Md5Update (Md5Ctx
, ChapSecret
, SecretLength
)) {
75 // Hash Challenge received from Target
77 if (!Md5Update (Md5Ctx
, ChapChallenge
, ChallengeLength
)) {
81 if (Md5Final (Md5Ctx
, ChapResponse
)) {
91 The initiator checks the CHAP response replied by target against its own
92 calculation of the expected hash value.
94 @param[in] AuthData iSCSI CHAP authentication data.
95 @param[in] TargetResponse The response from target.
97 @retval EFI_SUCCESS The response from target passed authentication.
98 @retval EFI_SECURITY_VIOLATION The response from target was not expected value.
99 @retval Others Other errors as indicated.
103 IScsiCHAPAuthTarget (
104 IN ISCSI_CHAP_AUTH_DATA
*AuthData
,
105 IN UINT8
*TargetResponse
110 UINT8 VerifyRsp
[ISCSI_CHAP_RSP_LEN
];
112 Status
= EFI_SUCCESS
;
114 SecretSize
= (UINT32
) AsciiStrLen (AuthData
->AuthConfig
->ReverseCHAPSecret
);
115 Status
= IScsiCHAPCalculateResponse (
116 AuthData
->OutIdentifier
,
117 AuthData
->AuthConfig
->ReverseCHAPSecret
,
119 AuthData
->OutChallenge
,
120 AuthData
->OutChallengeLength
,
124 if (CompareMem (VerifyRsp
, TargetResponse
, ISCSI_CHAP_RSP_LEN
) != 0) {
125 Status
= EFI_SECURITY_VIOLATION
;
133 This function checks the received iSCSI Login Response during the security
136 @param[in] Conn The iSCSI connection.
138 @retval EFI_SUCCESS The Login Response passed the CHAP validation.
139 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
140 @retval EFI_PROTOCOL_ERROR Some kind of protocol error occurred.
141 @retval Others Other errors as indicated.
145 IScsiCHAPOnRspReceived (
146 IN ISCSI_CONNECTION
*Conn
150 ISCSI_SESSION
*Session
;
151 ISCSI_CHAP_AUTH_DATA
*AuthData
;
155 LIST_ENTRY
*KeyValueList
;
161 UINT8 TargetRsp
[ISCSI_CHAP_RSP_LEN
];
165 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
166 ASSERT (Conn
->RspQue
.BufNum
!= 0);
168 Session
= Conn
->Session
;
169 AuthData
= &Session
->AuthData
.CHAP
;
170 Len
= Conn
->RspQue
.BufSize
;
171 Data
= AllocateZeroPool (Len
);
173 return EFI_OUT_OF_RESOURCES
;
176 // Copy the data in case the data spans over multiple PDUs.
178 NetbufQueCopy (&Conn
->RspQue
, 0, Len
, Data
);
181 // Build the key-value list from the data segment of the Login Response.
183 KeyValueList
= IScsiBuildKeyValueList ((CHAR8
*) Data
, Len
);
184 if (KeyValueList
== NULL
) {
185 Status
= EFI_OUT_OF_RESOURCES
;
189 Status
= EFI_PROTOCOL_ERROR
;
191 switch (Conn
->AuthStep
) {
192 case ISCSI_AUTH_INITIAL
:
194 // The first Login Response.
196 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG
);
201 Result
= IScsiNetNtoi (Value
);
202 if (Result
> 0xFFFF) {
206 Session
->TargetPortalGroupTag
= (UINT16
) Result
;
208 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_AUTH_METHOD
);
213 // Initiator mandates CHAP authentication but target replies without "CHAP", or
214 // initiator suggets "None" but target replies with some kind of auth method.
216 if (Session
->AuthType
== ISCSI_AUTH_TYPE_NONE
) {
217 if (AsciiStrCmp (Value
, ISCSI_KEY_VALUE_NONE
) != 0) {
220 } else if (Session
->AuthType
== ISCSI_AUTH_TYPE_CHAP
) {
221 if (AsciiStrCmp (Value
, ISCSI_AUTH_METHOD_CHAP
) != 0) {
229 // Transit to CHAP step one.
231 Conn
->AuthStep
= ISCSI_CHAP_STEP_ONE
;
232 Status
= EFI_SUCCESS
;
235 case ISCSI_CHAP_STEP_TWO
:
237 // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>
239 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_ALGORITHM
);
244 Algorithm
= IScsiNetNtoi (Value
);
245 if (Algorithm
!= ISCSI_CHAP_ALGORITHM_MD5
) {
247 // Unsupported algorithm is chosen by target.
252 Identifier
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_IDENTIFIER
);
253 if (Identifier
== NULL
) {
257 Challenge
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_CHALLENGE
);
258 if (Challenge
== NULL
) {
262 // Process the CHAP identifier and CHAP Challenge from Target.
263 // Calculate Response value.
265 Result
= IScsiNetNtoi (Identifier
);
270 AuthData
->InIdentifier
= (UINT32
) Result
;
271 AuthData
->InChallengeLength
= ISCSI_CHAP_AUTH_MAX_LEN
;
272 IScsiHexToBin ((UINT8
*) AuthData
->InChallenge
, &AuthData
->InChallengeLength
, Challenge
);
273 Status
= IScsiCHAPCalculateResponse (
274 AuthData
->InIdentifier
,
275 AuthData
->AuthConfig
->CHAPSecret
,
276 (UINT32
) AsciiStrLen (AuthData
->AuthConfig
->CHAPSecret
),
277 AuthData
->InChallenge
,
278 AuthData
->InChallengeLength
,
279 AuthData
->CHAPResponse
283 // Transit to next step.
285 Conn
->AuthStep
= ISCSI_CHAP_STEP_THREE
;
288 case ISCSI_CHAP_STEP_THREE
:
290 // One way CHAP authentication and the target would like to
293 Status
= EFI_SUCCESS
;
296 case ISCSI_CHAP_STEP_FOUR
:
297 ASSERT (AuthData
->AuthConfig
->CHAPType
== ISCSI_CHAP_MUTUAL
);
299 // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.
301 Name
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_NAME
);
306 Response
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_RESPONSE
);
307 if (Response
== NULL
) {
311 RspLen
= ISCSI_CHAP_RSP_LEN
;
312 IScsiHexToBin (TargetRsp
, &RspLen
, Response
);
315 // Check the CHAP Name and Response replied by Target.
317 Status
= IScsiCHAPAuthTarget (AuthData
, TargetRsp
);
326 if (KeyValueList
!= NULL
) {
327 IScsiFreeKeyValueList (KeyValueList
);
337 This function fills the CHAP authentication information into the login PDU
338 during the security negotiation stage in the iSCSI connection login.
340 @param[in] Conn The iSCSI connection.
341 @param[in, out] Pdu The PDU to send out.
343 @retval EFI_SUCCESS All check passed and the phase-related CHAP
344 authentication info is filled into the iSCSI PDU.
345 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
346 @retval EFI_PROTOCOL_ERROR Some kind of protocol error occurred.
351 IN ISCSI_CONNECTION
*Conn
,
356 ISCSI_SESSION
*Session
;
357 ISCSI_LOGIN_REQUEST
*LoginReq
;
358 ISCSI_CHAP_AUTH_DATA
*AuthData
;
366 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
368 Session
= Conn
->Session
;
369 AuthData
= &Session
->AuthData
.CHAP
;
370 LoginReq
= (ISCSI_LOGIN_REQUEST
*) NetbufGetByte (Pdu
, 0, 0);
371 if (LoginReq
== NULL
) {
372 return EFI_PROTOCOL_ERROR
;
374 Status
= EFI_SUCCESS
;
376 RspLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
377 Response
= AllocateZeroPool (RspLen
);
378 if (Response
== NULL
) {
379 return EFI_OUT_OF_RESOURCES
;
382 ChallengeLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
383 Challenge
= AllocateZeroPool (ChallengeLen
);
384 if (Challenge
== NULL
) {
386 return EFI_OUT_OF_RESOURCES
;
389 switch (Conn
->AuthStep
) {
390 case ISCSI_AUTH_INITIAL
:
392 // It's the initial Login Request. Fill in the key=value pairs mandatory
393 // for the initial Login Request.
395 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_INITIATOR_NAME
, mPrivate
->InitiatorName
);
396 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_SESSION_TYPE
, "Normal");
397 IScsiAddKeyValuePair (
399 ISCSI_KEY_TARGET_NAME
,
400 Session
->ConfigData
->SessionConfigData
.TargetName
403 if (Session
->AuthType
== ISCSI_AUTH_TYPE_NONE
) {
404 Value
= ISCSI_KEY_VALUE_NONE
;
405 ISCSI_SET_FLAG (LoginReq
, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT
);
407 Value
= ISCSI_AUTH_METHOD_CHAP
;
410 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_AUTH_METHOD
, Value
);
414 case ISCSI_CHAP_STEP_ONE
:
416 // First step, send the Login Request with CHAP_A=<A1,A2...> key-value pair.
418 AsciiSPrint (ValueStr
, sizeof (ValueStr
), "%d", ISCSI_CHAP_ALGORITHM_MD5
);
419 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_ALGORITHM
, ValueStr
);
421 Conn
->AuthStep
= ISCSI_CHAP_STEP_TWO
;
424 case ISCSI_CHAP_STEP_THREE
:
426 // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or
427 // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target authentication is
432 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_NAME
, (CHAR8
*) &AuthData
->AuthConfig
->CHAPName
);
436 IScsiBinToHex ((UINT8
*) AuthData
->CHAPResponse
, ISCSI_CHAP_RSP_LEN
, Response
, &RspLen
);
437 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_RESPONSE
, Response
);
439 if (AuthData
->AuthConfig
->CHAPType
== ISCSI_CHAP_MUTUAL
) {
443 IScsiGenRandom ((UINT8
*) &AuthData
->OutIdentifier
, 1);
444 AsciiSPrint (ValueStr
, sizeof (ValueStr
), "%d", AuthData
->OutIdentifier
);
445 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_IDENTIFIER
, ValueStr
);
449 IScsiGenRandom ((UINT8
*) AuthData
->OutChallenge
, ISCSI_CHAP_RSP_LEN
);
450 AuthData
->OutChallengeLength
= ISCSI_CHAP_RSP_LEN
;
451 IScsiBinToHex ((UINT8
*) AuthData
->OutChallenge
, ISCSI_CHAP_RSP_LEN
, Challenge
, &ChallengeLen
);
452 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_CHALLENGE
, Challenge
);
454 Conn
->AuthStep
= ISCSI_CHAP_STEP_FOUR
;
457 // Set the stage transition flag.
459 ISCSI_SET_FLAG (LoginReq
, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT
);
463 Status
= EFI_PROTOCOL_ERROR
;
468 FreePool (Challenge
);