2 This file is for Challenge-Handshake Authentication Protocol (CHAP) Configuration.
4 Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "IScsiImpl.h"
18 Initator caculates its own expected hash value.
20 @param[in] ChapIdentifier iSCSI CHAP identifier sent by authenticator.
21 @param[in] ChapSecret iSCSI CHAP secret of the authenticator.
22 @param[in] SecretLength The length of iSCSI CHAP secret.
23 @param[in] ChapChallenge The challenge message sent by authenticator.
24 @param[in] ChallengeLength The length of iSCSI CHAP challenge message.
25 @param[out] ChapResponse The calculation of the expected hash value.
27 @retval EFI_SUCCESS The expected hash value was caculatedly successfully.
28 @retval EFI_PROTOCOL_ERROR The length of the secret should be at least the
29 length of the hash value for the hashing algorithm chosen.
30 @retval EFI_PROTOCOL_ERROR MD5 hash operation fail.
31 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete MD5.
35 IScsiCHAPCalculateResponse (
36 IN UINT32 ChapIdentifier
,
38 IN UINT32 SecretLength
,
39 IN UINT8
*ChapChallenge
,
40 IN UINT32 ChallengeLength
,
41 OUT UINT8
*ChapResponse
49 if (SecretLength
< ISCSI_CHAP_SECRET_MIN_LEN
) {
50 return EFI_PROTOCOL_ERROR
;
53 Md5ContextSize
= Md5GetContextSize ();
54 Md5Ctx
= AllocatePool (Md5ContextSize
);
56 return EFI_OUT_OF_RESOURCES
;
59 Status
= EFI_PROTOCOL_ERROR
;
61 if (!Md5Init (Md5Ctx
)) {
66 // Hash Identifier - Only calculate 1 byte data (RFC1994)
68 IdByte
[0] = (CHAR8
) ChapIdentifier
;
69 if (!Md5Update (Md5Ctx
, IdByte
, 1)) {
76 if (!Md5Update (Md5Ctx
, ChapSecret
, SecretLength
)) {
81 // Hash Challenge received from Target
83 if (!Md5Update (Md5Ctx
, ChapChallenge
, ChallengeLength
)) {
87 if (Md5Final (Md5Ctx
, ChapResponse
)) {
97 The initator checks the CHAP response replied by target against its own
98 calculation of the expected hash value.
100 @param[in] AuthData iSCSI CHAP authentication data.
101 @param[in] TargetResponse The response from target.
103 @retval EFI_SUCCESS The response from target passed authentication.
104 @retval EFI_SECURITY_VIOLATION The response from target was not expected value.
105 @retval Others Other errors as indicated.
109 IScsiCHAPAuthTarget (
110 IN ISCSI_CHAP_AUTH_DATA
*AuthData
,
111 IN UINT8
*TargetResponse
116 UINT8 VerifyRsp
[ISCSI_CHAP_RSP_LEN
];
118 Status
= EFI_SUCCESS
;
120 SecretSize
= (UINT32
) AsciiStrLen (AuthData
->AuthConfig
->ReverseCHAPSecret
);
121 Status
= IScsiCHAPCalculateResponse (
122 AuthData
->OutIdentifier
,
123 AuthData
->AuthConfig
->ReverseCHAPSecret
,
125 AuthData
->OutChallenge
,
126 AuthData
->OutChallengeLength
,
130 if (CompareMem (VerifyRsp
, TargetResponse
, ISCSI_CHAP_RSP_LEN
) != 0) {
131 Status
= EFI_SECURITY_VIOLATION
;
139 This function checks the received iSCSI Login Response during the security
142 @param[in] Conn The iSCSI connection.
144 @retval EFI_SUCCESS The Login Response passed the CHAP validation.
145 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
146 @retval EFI_PROTOCOL_ERROR Some kind of protocol error occurred.
147 @retval Others Other errors as indicated.
151 IScsiCHAPOnRspReceived (
152 IN ISCSI_CONNECTION
*Conn
156 ISCSI_SESSION
*Session
;
157 ISCSI_CHAP_AUTH_DATA
*AuthData
;
161 LIST_ENTRY
*KeyValueList
;
167 UINT8 TargetRsp
[ISCSI_CHAP_RSP_LEN
];
171 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
172 ASSERT (Conn
->RspQue
.BufNum
!= 0);
174 Session
= Conn
->Session
;
175 AuthData
= &Session
->AuthData
.CHAP
;
176 Len
= Conn
->RspQue
.BufSize
;
177 Data
= AllocateZeroPool (Len
);
179 return EFI_OUT_OF_RESOURCES
;
182 // Copy the data in case the data spans over multiple PDUs.
184 NetbufQueCopy (&Conn
->RspQue
, 0, Len
, Data
);
187 // Build the key-value list from the data segment of the Login Response.
189 KeyValueList
= IScsiBuildKeyValueList ((CHAR8
*) Data
, Len
);
190 if (KeyValueList
== NULL
) {
191 Status
= EFI_OUT_OF_RESOURCES
;
195 Status
= EFI_PROTOCOL_ERROR
;
197 switch (Conn
->AuthStep
) {
198 case ISCSI_AUTH_INITIAL
:
200 // The first Login Response.
202 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG
);
207 Result
= IScsiNetNtoi (Value
);
208 if (Result
> 0xFFFF) {
212 Session
->TargetPortalGroupTag
= (UINT16
) Result
;
214 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_AUTH_METHOD
);
219 // Initiator mandates CHAP authentication but target replies without "CHAP", or
220 // initiator suggets "None" but target replies with some kind of auth method.
222 if (Session
->AuthType
== ISCSI_AUTH_TYPE_NONE
) {
223 if (AsciiStrCmp (Value
, ISCSI_KEY_VALUE_NONE
) != 0) {
226 } else if (Session
->AuthType
== ISCSI_AUTH_TYPE_CHAP
) {
227 if (AsciiStrCmp (Value
, ISCSI_AUTH_METHOD_CHAP
) != 0) {
235 // Transit to CHAP step one.
237 Conn
->AuthStep
= ISCSI_CHAP_STEP_ONE
;
238 Status
= EFI_SUCCESS
;
241 case ISCSI_CHAP_STEP_TWO
:
243 // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>
245 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_ALGORITHM
);
250 Algorithm
= IScsiNetNtoi (Value
);
251 if (Algorithm
!= ISCSI_CHAP_ALGORITHM_MD5
) {
253 // Unsupported algorithm is chosen by target.
258 Identifier
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_IDENTIFIER
);
259 if (Identifier
== NULL
) {
263 Challenge
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_CHALLENGE
);
264 if (Challenge
== NULL
) {
268 // Process the CHAP identifier and CHAP Challenge from Target.
269 // Calculate Response value.
271 Result
= IScsiNetNtoi (Identifier
);
276 AuthData
->InIdentifier
= (UINT32
) Result
;
277 AuthData
->InChallengeLength
= ISCSI_CHAP_AUTH_MAX_LEN
;
278 IScsiHexToBin ((UINT8
*) AuthData
->InChallenge
, &AuthData
->InChallengeLength
, Challenge
);
279 Status
= IScsiCHAPCalculateResponse (
280 AuthData
->InIdentifier
,
281 AuthData
->AuthConfig
->CHAPSecret
,
282 (UINT32
) AsciiStrLen (AuthData
->AuthConfig
->CHAPSecret
),
283 AuthData
->InChallenge
,
284 AuthData
->InChallengeLength
,
285 AuthData
->CHAPResponse
289 // Transit to next step.
291 Conn
->AuthStep
= ISCSI_CHAP_STEP_THREE
;
294 case ISCSI_CHAP_STEP_THREE
:
296 // One way CHAP authentication and the target would like to
299 Status
= EFI_SUCCESS
;
302 case ISCSI_CHAP_STEP_FOUR
:
303 ASSERT (AuthData
->AuthConfig
->CHAPType
== ISCSI_CHAP_MUTUAL
);
305 // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.
307 Name
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_NAME
);
312 Response
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_RESPONSE
);
313 if (Response
== NULL
) {
317 RspLen
= ISCSI_CHAP_RSP_LEN
;
318 IScsiHexToBin (TargetRsp
, &RspLen
, Response
);
321 // Check the CHAP Name and Response replied by Target.
323 Status
= IScsiCHAPAuthTarget (AuthData
, TargetRsp
);
332 if (KeyValueList
!= NULL
) {
333 IScsiFreeKeyValueList (KeyValueList
);
343 This function fills the CHAP authentication information into the login PDU
344 during the security negotiation stage in the iSCSI connection login.
346 @param[in] Conn The iSCSI connection.
347 @param[in, out] Pdu The PDU to send out.
349 @retval EFI_SUCCESS All check passed and the phase-related CHAP
350 authentication info is filled into the iSCSI PDU.
351 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
352 @retval EFI_PROTOCOL_ERROR Some kind of protocol error occurred.
357 IN ISCSI_CONNECTION
*Conn
,
362 ISCSI_SESSION
*Session
;
363 ISCSI_LOGIN_REQUEST
*LoginReq
;
364 ISCSI_CHAP_AUTH_DATA
*AuthData
;
372 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
374 Session
= Conn
->Session
;
375 AuthData
= &Session
->AuthData
.CHAP
;
376 LoginReq
= (ISCSI_LOGIN_REQUEST
*) NetbufGetByte (Pdu
, 0, 0);
377 if (LoginReq
== NULL
) {
378 return EFI_PROTOCOL_ERROR
;
380 Status
= EFI_SUCCESS
;
382 RspLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
383 Response
= AllocateZeroPool (RspLen
);
384 if (Response
== NULL
) {
385 return EFI_OUT_OF_RESOURCES
;
388 ChallengeLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
389 Challenge
= AllocateZeroPool (ChallengeLen
);
390 if (Challenge
== NULL
) {
392 return EFI_OUT_OF_RESOURCES
;
395 switch (Conn
->AuthStep
) {
396 case ISCSI_AUTH_INITIAL
:
398 // It's the initial Login Request. Fill in the key=value pairs mandatory
399 // for the initial Login Request.
401 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_INITIATOR_NAME
, mPrivate
->InitiatorName
);
402 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_SESSION_TYPE
, "Normal");
403 IScsiAddKeyValuePair (
405 ISCSI_KEY_TARGET_NAME
,
406 Session
->ConfigData
->SessionConfigData
.TargetName
409 if (Session
->AuthType
== ISCSI_AUTH_TYPE_NONE
) {
410 Value
= ISCSI_KEY_VALUE_NONE
;
411 ISCSI_SET_FLAG (LoginReq
, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT
);
413 Value
= ISCSI_AUTH_METHOD_CHAP
;
416 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_AUTH_METHOD
, Value
);
420 case ISCSI_CHAP_STEP_ONE
:
422 // First step, send the Login Request with CHAP_A=<A1,A2...> key-value pair.
424 AsciiSPrint (ValueStr
, sizeof (ValueStr
), "%d", ISCSI_CHAP_ALGORITHM_MD5
);
425 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_ALGORITHM
, ValueStr
);
427 Conn
->AuthStep
= ISCSI_CHAP_STEP_TWO
;
430 case ISCSI_CHAP_STEP_THREE
:
432 // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or
433 // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target authentication is
438 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_NAME
, (CHAR8
*) &AuthData
->AuthConfig
->CHAPName
);
442 IScsiBinToHex ((UINT8
*) AuthData
->CHAPResponse
, ISCSI_CHAP_RSP_LEN
, Response
, &RspLen
);
443 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_RESPONSE
, Response
);
445 if (AuthData
->AuthConfig
->CHAPType
== ISCSI_CHAP_MUTUAL
) {
449 IScsiGenRandom ((UINT8
*) &AuthData
->OutIdentifier
, 1);
450 AsciiSPrint (ValueStr
, sizeof (ValueStr
), "%d", AuthData
->OutIdentifier
);
451 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_IDENTIFIER
, ValueStr
);
455 IScsiGenRandom ((UINT8
*) AuthData
->OutChallenge
, ISCSI_CHAP_RSP_LEN
);
456 AuthData
->OutChallengeLength
= ISCSI_CHAP_RSP_LEN
;
457 IScsiBinToHex ((UINT8
*) AuthData
->OutChallenge
, ISCSI_CHAP_RSP_LEN
, Challenge
, &ChallengeLen
);
458 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_CHALLENGE
, Challenge
);
460 Conn
->AuthStep
= ISCSI_CHAP_STEP_FOUR
;
463 // Set the stage transition flag.
465 ISCSI_SET_FLAG (LoginReq
, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT
);
469 Status
= EFI_PROTOCOL_ERROR
;
474 FreePool (Challenge
);