2 This file is for Challenge-Handshake Authentication Protocol (CHAP) Configuration.
4 Copyright (c) 2004 - 2011, 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"
19 Initator caculates its own expected hash value.
21 @param[in] ChapIdentifier iSCSI CHAP identifier sent by authenticator.
22 @param[in] ChapSecret iSCSI CHAP secret of the authenticator.
23 @param[in] SecretLength The length of iSCSI CHAP secret.
24 @param[in] ChapChallenge The challenge message sent by authenticator.
25 @param[in] ChallengeLength The length of iSCSI CHAP challenge message.
26 @param[out] ChapResponse The calculation of the expected hash value.
28 @retval EFI_SUCCESS The expected hash value was caculatedly successfully.
29 @retval EFI_PROTOCOL_ERROR The length of the secret should be at least the
30 length of the hash value for the hashing algorithm chosen.
31 @retval Others Other errors as indicated.
34 IScsiCHAPCalculateResponse (
35 IN UINT32 ChapIdentifier
,
37 IN UINT32 SecretLength
,
38 IN UINT8
*ChapChallenge
,
39 IN UINT32 ChallengeLength
,
40 OUT UINT8
*ChapResponse
47 Status
= MD5Init (&Md5Ctx
);
50 // Hash Identifier - Only calculate 1 byte data (RFC1994)
52 IdByte
[0] = (CHAR8
) ChapIdentifier
;
53 MD5Update (&Md5Ctx
, IdByte
, 1);
58 if (SecretLength
< ISCSI_CHAP_SECRET_MIN_LEN
- 1) {
59 return EFI_PROTOCOL_ERROR
;
62 MD5Update (&Md5Ctx
, ChapSecret
, SecretLength
);
65 // Hash Challenge received from Target
67 MD5Update (&Md5Ctx
, ChapChallenge
, ChallengeLength
);
69 Status
= MD5Final (&Md5Ctx
, ChapResponse
);
75 The initator checks the CHAP response replied by target against its own
76 calculation of the expected hash value.
78 @param[in] AuthData iSCSI CHAP authentication data.
79 @param[in] TargetResponse The response from target.
81 @retval EFI_SUCCESS The response from target passed authentication.
82 @retval EFI_SECURITY_VIOLATION The response from target was not expected value.
83 @retval Others Other errors as indicated.
87 IN ISCSI_CHAP_AUTH_DATA
*AuthData
,
88 IN UINT8
*TargetResponse
93 UINT8 VerifyRsp
[ISCSI_CHAP_RSP_LEN
];
97 SecretSize
= (UINT32
) AsciiStrLen (AuthData
->AuthConfig
.ReverseCHAPSecret
);
98 Status
= IScsiCHAPCalculateResponse (
99 AuthData
->OutIdentifier
,
100 AuthData
->AuthConfig
.ReverseCHAPSecret
,
102 AuthData
->OutChallenge
,
103 AuthData
->OutChallengeLength
,
107 if (CompareMem (VerifyRsp
, TargetResponse
, ISCSI_CHAP_RSP_LEN
) != 0) {
108 Status
= EFI_SECURITY_VIOLATION
;
115 This function checks the received iSCSI Login Response during the security
118 @param[in] Conn The iSCSI connection.
120 @retval EFI_SUCCESS The Login Response passed the CHAP validation.
121 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
122 @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.
123 @retval Others Other errors as indicated.
126 IScsiCHAPOnRspReceived (
127 IN ISCSI_CONNECTION
*Conn
131 ISCSI_SESSION
*Session
;
132 ISCSI_CHAP_AUTH_DATA
*AuthData
;
136 LIST_ENTRY
*KeyValueList
;
142 UINT8 TargetRsp
[ISCSI_CHAP_RSP_LEN
];
145 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
146 ASSERT (Conn
->RspQue
.BufNum
!= 0);
148 Session
= Conn
->Session
;
149 AuthData
= &Session
->AuthData
;
151 Len
= Conn
->RspQue
.BufSize
;
152 Data
= AllocatePool (Len
);
154 return EFI_OUT_OF_RESOURCES
;
157 // Copy the data in case the data spans over multiple PDUs.
159 NetbufQueCopy (&Conn
->RspQue
, 0, Len
, Data
);
162 // Build the key-value list from the data segment of the Login Response.
164 KeyValueList
= IScsiBuildKeyValueList ((CHAR8
*) Data
, Len
);
165 if (KeyValueList
== NULL
) {
167 return EFI_OUT_OF_RESOURCES
;
170 Status
= EFI_PROTOCOL_ERROR
;
172 switch (Conn
->CHAPStep
) {
173 case ISCSI_CHAP_INITIAL
:
175 // The first Login Response.
177 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG
);
182 Session
->TargetPortalGroupTag
= (UINT16
) AsciiStrDecimalToUintn (Value
);
184 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_AUTH_METHOD
);
189 // Initiator mandates CHAP authentication but target replies without "CHAP" or
190 // initiator suggets "None" but target replies with some kind of auth method.
192 if (AsciiStrCmp (Value
, ISCSI_AUTH_METHOD_CHAP
) == 0) {
193 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_NONE
) {
197 if (AuthData
->AuthConfig
.CHAPType
!= ISCSI_CHAP_NONE
) {
202 // Transit to CHAP step one.
204 Conn
->CHAPStep
= ISCSI_CHAP_STEP_ONE
;
205 Status
= EFI_SUCCESS
;
208 case ISCSI_CHAP_STEP_TWO
:
210 // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>
212 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_ALGORITHM
);
217 Algorithm
= AsciiStrDecimalToUintn (Value
);
218 if (Algorithm
!= ISCSI_CHAP_ALGORITHM_MD5
) {
220 // Unsupported algorithm is chosen by target.
225 Identifier
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_IDENTIFIER
);
226 if (Identifier
== NULL
) {
230 Challenge
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_CHALLENGE
);
231 if (Challenge
== NULL
) {
235 // Process the CHAP identifier and CHAP Challenge from Target
236 // Calculate Response value
238 AuthData
->InIdentifier
= (UINT32
) AsciiStrDecimalToUintn (Identifier
);
239 AuthData
->InChallengeLength
= ISCSI_CHAP_AUTH_MAX_LEN
;
240 IScsiHexToBin ((UINT8
*) AuthData
->InChallenge
, &AuthData
->InChallengeLength
, Challenge
);
241 Status
= IScsiCHAPCalculateResponse (
242 AuthData
->InIdentifier
,
243 AuthData
->AuthConfig
.CHAPSecret
,
244 (UINT32
) AsciiStrLen (AuthData
->AuthConfig
.CHAPSecret
),
245 AuthData
->InChallenge
,
246 AuthData
->InChallengeLength
,
247 AuthData
->CHAPResponse
251 // Transit to next step.
253 Conn
->CHAPStep
= ISCSI_CHAP_STEP_THREE
;
256 case ISCSI_CHAP_STEP_THREE
:
258 // one way CHAP authentication and the target would like to
261 Status
= EFI_SUCCESS
;
264 case ISCSI_CHAP_STEP_FOUR
:
265 ASSERT (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_MUTUAL
);
267 // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.
269 Name
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_NAME
);
274 Response
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_RESPONSE
);
275 if (Response
== NULL
) {
279 RspLen
= ISCSI_CHAP_RSP_LEN
;
280 IScsiHexToBin (TargetRsp
, &RspLen
, Response
);
283 // Check the CHAP Response replied by Target.
285 Status
= IScsiCHAPAuthTarget (AuthData
, TargetRsp
);
294 IScsiFreeKeyValueList (KeyValueList
);
302 This function fills the CHAP authentication information into the login PDU
303 during the security negotiation stage in the iSCSI connection login.
305 @param[in] Conn The iSCSI connection.
306 @param[in, out] Pdu The PDU to send out.
308 @retval EFI_SUCCESS All check passed and the phase-related CHAP
309 authentication info is filled into the iSCSI PDU.
310 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
311 @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.
315 IN ISCSI_CONNECTION
*Conn
,
320 ISCSI_SESSION
*Session
;
321 ISCSI_LOGIN_REQUEST
*LoginReq
;
322 ISCSI_CHAP_AUTH_DATA
*AuthData
;
330 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
332 Session
= Conn
->Session
;
333 AuthData
= &Session
->AuthData
;
334 LoginReq
= (ISCSI_LOGIN_REQUEST
*) NetbufGetByte (Pdu
, 0, 0);
335 if (LoginReq
== NULL
) {
336 return EFI_PROTOCOL_ERROR
;
338 Status
= EFI_SUCCESS
;
340 RspLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
341 Response
= AllocatePool (RspLen
);
342 if (Response
== NULL
) {
343 return EFI_OUT_OF_RESOURCES
;
346 ChallengeLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
347 Challenge
= AllocatePool (ChallengeLen
);
348 if (Challenge
== NULL
) {
349 return EFI_OUT_OF_RESOURCES
;
352 switch (Conn
->CHAPStep
) {
353 case ISCSI_CHAP_INITIAL
:
355 // It's the initial Login Request. Fill in the key=value pairs mandatory
356 // for the initial Login Request.
358 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_INITIATOR_NAME
, Session
->InitiatorName
);
359 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_SESSION_TYPE
, "Normal");
360 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_TARGET_NAME
, Session
->ConfigData
.NvData
.TargetName
);
362 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_NONE
) {
363 Value
= ISCSI_KEY_VALUE_NONE
;
364 ISCSI_SET_FLAG (LoginReq
, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT
);
366 Value
= ISCSI_AUTH_METHOD_CHAP
;
369 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_AUTH_METHOD
, Value
);
373 case ISCSI_CHAP_STEP_ONE
:
375 // First step, send the Login Request with CHAP_A=<A1,A2...> key-value pair.
377 AsciiSPrint (ValueStr
, sizeof (ValueStr
), "%d", ISCSI_CHAP_ALGORITHM_MD5
);
378 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_ALGORITHM
, ValueStr
);
380 Conn
->CHAPStep
= ISCSI_CHAP_STEP_TWO
;
383 case ISCSI_CHAP_STEP_THREE
:
385 // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or
386 // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target ahtentication is
391 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_NAME
, (CHAR8
*) &AuthData
->AuthConfig
.CHAPName
);
395 IScsiBinToHex ((UINT8
*) AuthData
->CHAPResponse
, ISCSI_CHAP_RSP_LEN
, Response
, &RspLen
);
396 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_RESPONSE
, Response
);
398 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_MUTUAL
) {
402 IScsiGenRandom ((UINT8
*) &AuthData
->OutIdentifier
, 1);
403 AsciiSPrint (ValueStr
, sizeof (ValueStr
), "%d", AuthData
->OutIdentifier
);
404 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_IDENTIFIER
, ValueStr
);
408 IScsiGenRandom ((UINT8
*) AuthData
->OutChallenge
, ISCSI_CHAP_RSP_LEN
);
409 AuthData
->OutChallengeLength
= ISCSI_CHAP_RSP_LEN
;
410 IScsiBinToHex ((UINT8
*) AuthData
->OutChallenge
, ISCSI_CHAP_RSP_LEN
, Challenge
, &ChallengeLen
);
411 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_CHALLENGE
, Challenge
);
413 Conn
->CHAPStep
= ISCSI_CHAP_STEP_FOUR
;
416 // set the stage transition flag.
418 ISCSI_SET_FLAG (LoginReq
, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT
);
422 Status
= EFI_PROTOCOL_ERROR
;
427 FreePool (Challenge
);