2 This file is for Challenge-Handshake Authentication Protocol (CHAP) Configuration.
4 Copyright (c) 2004 - 2010, 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 EFI_GUID mIScsiCHAPAuthInfoGuid
= ISCSI_CHAP_AUTH_INFO_GUID
;
21 Initator caculates its own expected hash value.
23 @param[in] ChapIdentifier iSCSI CHAP identifier sent by authenticator.
24 @param[in] ChapSecret iSCSI CHAP secret of the authenticator.
25 @param[in] SecretLength The length of iSCSI CHAP secret.
26 @param[in] ChapChallenge The challenge message sent by authenticator.
27 @param[in] ChallengeLength The length of iSCSI CHAP challenge message.
28 @param[out] ChapResponse The calculation of the expected hash value.
30 @retval EFI_SUCCESS The expected hash value was caculatedly successfully.
31 @retval EFI_PROTOCOL_ERROR The length of the secret should be at least the
32 length of the hash value for the hashing algorithm chosen.
33 @retval Others Other errors as indicated.
36 IScsiCHAPCalculateResponse (
37 IN UINT32 ChapIdentifier
,
39 IN UINT32 SecretLength
,
40 IN UINT8
*ChapChallenge
,
41 IN UINT32 ChallengeLength
,
42 OUT UINT8
*ChapResponse
49 Status
= MD5Init (&Md5Ctx
);
52 // Hash Identifier - Only calculate 1 byte data (RFC1994)
54 IdByte
[0] = (CHAR8
) ChapIdentifier
;
55 MD5Update (&Md5Ctx
, IdByte
, 1);
60 if (SecretLength
< ISCSI_CHAP_SECRET_MIN_LEN
- 1) {
61 return EFI_PROTOCOL_ERROR
;
64 MD5Update (&Md5Ctx
, ChapSecret
, SecretLength
);
67 // Hash Challenge received from Target
69 MD5Update (&Md5Ctx
, ChapChallenge
, ChallengeLength
);
71 Status
= MD5Final (&Md5Ctx
, ChapResponse
);
77 The initator checks the CHAP response replied by target against its own
78 calculation of the expected hash value.
80 @param[in] AuthData iSCSI CHAP authentication data.
81 @param[in] TargetResponse The response from target.
83 @retval EFI_SUCCESS The response from target passed authentication.
84 @retval EFI_SECURITY_VIOLATION The response from target was not expected value.
85 @retval Others Other errors as indicated.
89 IN ISCSI_CHAP_AUTH_DATA
*AuthData
,
90 IN UINT8
*TargetResponse
95 UINT8 VerifyRsp
[ISCSI_CHAP_RSP_LEN
];
99 SecretSize
= (UINT32
) AsciiStrLen (AuthData
->AuthConfig
.ReverseCHAPSecret
);
100 Status
= IScsiCHAPCalculateResponse (
101 AuthData
->OutIdentifier
,
102 AuthData
->AuthConfig
.ReverseCHAPSecret
,
104 AuthData
->OutChallenge
,
105 AuthData
->OutChallengeLength
,
109 if (CompareMem (VerifyRsp
, TargetResponse
, ISCSI_CHAP_RSP_LEN
) != 0) {
110 Status
= EFI_SECURITY_VIOLATION
;
117 This function checks the received iSCSI Login Response during the security
120 @param[in] Conn The iSCSI connection.
122 @retval EFI_SUCCESS The Login Response passed the CHAP validation.
123 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
124 @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.
125 @retval Others Other errors as indicated.
128 IScsiCHAPOnRspReceived (
129 IN ISCSI_CONNECTION
*Conn
133 ISCSI_SESSION
*Session
;
134 ISCSI_CHAP_AUTH_DATA
*AuthData
;
138 LIST_ENTRY
*KeyValueList
;
144 UINT8 TargetRsp
[ISCSI_CHAP_RSP_LEN
];
147 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
148 ASSERT (Conn
->RspQue
.BufNum
!= 0);
150 Session
= Conn
->Session
;
151 AuthData
= &Session
->AuthData
;
153 Len
= Conn
->RspQue
.BufSize
;
154 Data
= AllocatePool (Len
);
156 return EFI_OUT_OF_RESOURCES
;
159 // Copy the data in case the data spans over multiple PDUs.
161 NetbufQueCopy (&Conn
->RspQue
, 0, Len
, Data
);
164 // Build the key-value list from the data segment of the Login Response.
166 KeyValueList
= IScsiBuildKeyValueList ((CHAR8
*) Data
, Len
);
167 if (KeyValueList
== NULL
) {
169 return EFI_OUT_OF_RESOURCES
;
172 Status
= EFI_PROTOCOL_ERROR
;
174 switch (Conn
->CHAPStep
) {
175 case ISCSI_CHAP_INITIAL
:
177 // The first Login Response.
179 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG
);
184 Session
->TargetPortalGroupTag
= (UINT16
) AsciiStrDecimalToUintn (Value
);
186 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_AUTH_METHOD
);
191 // Initiator mandates CHAP authentication but target replies without "CHAP" or
192 // initiator suggets "None" but target replies with some kind of auth method.
194 if (AsciiStrCmp (Value
, ISCSI_AUTH_METHOD_CHAP
) == 0) {
195 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_NONE
) {
199 if (AuthData
->AuthConfig
.CHAPType
!= ISCSI_CHAP_NONE
) {
204 // Transit to CHAP step one.
206 Conn
->CHAPStep
= ISCSI_CHAP_STEP_ONE
;
207 Status
= EFI_SUCCESS
;
210 case ISCSI_CHAP_STEP_TWO
:
212 // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>
214 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_ALGORITHM
);
219 Algorithm
= AsciiStrDecimalToUintn (Value
);
220 if (Algorithm
!= ISCSI_CHAP_ALGORITHM_MD5
) {
222 // Unsupported algorithm is chosen by target.
227 Identifier
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_IDENTIFIER
);
228 if (Identifier
== NULL
) {
232 Challenge
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_CHALLENGE
);
233 if (Challenge
== NULL
) {
237 // Process the CHAP identifier and CHAP Challenge from Target
238 // Calculate Response value
240 AuthData
->InIdentifier
= (UINT32
) AsciiStrDecimalToUintn (Identifier
);
241 AuthData
->InChallengeLength
= ISCSI_CHAP_AUTH_MAX_LEN
;
242 IScsiHexToBin ((UINT8
*) AuthData
->InChallenge
, &AuthData
->InChallengeLength
, Challenge
);
243 Status
= IScsiCHAPCalculateResponse (
244 AuthData
->InIdentifier
,
245 AuthData
->AuthConfig
.CHAPSecret
,
246 (UINT32
) AsciiStrLen (AuthData
->AuthConfig
.CHAPSecret
),
247 AuthData
->InChallenge
,
248 AuthData
->InChallengeLength
,
249 AuthData
->CHAPResponse
253 // Transit to next step.
255 Conn
->CHAPStep
= ISCSI_CHAP_STEP_THREE
;
258 case ISCSI_CHAP_STEP_THREE
:
260 // one way CHAP authentication and the target would like to
263 Status
= EFI_SUCCESS
;
266 case ISCSI_CHAP_STEP_FOUR
:
267 ASSERT (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_MUTUAL
);
269 // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.
271 Name
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_NAME
);
276 Response
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_RESPONSE
);
277 if (Response
== NULL
) {
281 RspLen
= ISCSI_CHAP_RSP_LEN
;
282 IScsiHexToBin (TargetRsp
, &RspLen
, Response
);
285 // Check the CHAP Response replied by Target.
287 Status
= IScsiCHAPAuthTarget (AuthData
, TargetRsp
);
296 IScsiFreeKeyValueList (KeyValueList
);
304 This function fills the CHAP authentication information into the login PDU
305 during the security negotiation stage in the iSCSI connection login.
307 @param[in] Conn The iSCSI connection.
308 @param[in, out] Pdu The PDU to send out.
310 @retval EFI_SUCCESS All check passed and the phase-related CHAP
311 authentication info is filled into the iSCSI PDU.
312 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
313 @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.
317 IN ISCSI_CONNECTION
*Conn
,
322 ISCSI_SESSION
*Session
;
323 ISCSI_LOGIN_REQUEST
*LoginReq
;
324 ISCSI_CHAP_AUTH_DATA
*AuthData
;
332 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
334 Session
= Conn
->Session
;
335 AuthData
= &Session
->AuthData
;
336 LoginReq
= (ISCSI_LOGIN_REQUEST
*) NetbufGetByte (Pdu
, 0, 0);
337 Status
= EFI_SUCCESS
;
339 RspLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
340 Response
= AllocatePool (RspLen
);
341 if (Response
== NULL
) {
342 return EFI_OUT_OF_RESOURCES
;
345 ChallengeLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
346 Challenge
= AllocatePool (ChallengeLen
);
347 if (Challenge
== NULL
) {
348 return EFI_OUT_OF_RESOURCES
;
351 switch (Conn
->CHAPStep
) {
352 case ISCSI_CHAP_INITIAL
:
354 // It's the initial Login Request. Fill in the key=value pairs mandatory
355 // for the initial Login Request.
357 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_INITIATOR_NAME
, Session
->InitiatorName
);
358 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_SESSION_TYPE
, "Normal");
359 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_TARGET_NAME
, Session
->ConfigData
.NvData
.TargetName
);
361 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_NONE
) {
362 Value
= ISCSI_KEY_VALUE_NONE
;
363 ISCSI_SET_FLAG (LoginReq
, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT
);
365 Value
= ISCSI_AUTH_METHOD_CHAP
;
368 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_AUTH_METHOD
, Value
);
372 case ISCSI_CHAP_STEP_ONE
:
374 // First step, send the Login Request with CHAP_A=<A1,A2...> key-value pair.
376 AsciiSPrint (ValueStr
, sizeof (ValueStr
), "%d", ISCSI_CHAP_ALGORITHM_MD5
);
377 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_ALGORITHM
, ValueStr
);
379 Conn
->CHAPStep
= ISCSI_CHAP_STEP_TWO
;
382 case ISCSI_CHAP_STEP_THREE
:
384 // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or
385 // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target ahtentication is
390 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_NAME
, (CHAR8
*) &AuthData
->AuthConfig
.CHAPName
);
394 IScsiBinToHex ((UINT8
*) AuthData
->CHAPResponse
, ISCSI_CHAP_RSP_LEN
, Response
, &RspLen
);
395 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_RESPONSE
, Response
);
397 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_MUTUAL
) {
401 IScsiGenRandom ((UINT8
*) &AuthData
->OutIdentifier
, 1);
402 AsciiSPrint (ValueStr
, sizeof (ValueStr
), "%d", AuthData
->OutIdentifier
);
403 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_IDENTIFIER
, ValueStr
);
407 IScsiGenRandom ((UINT8
*) AuthData
->OutChallenge
, ISCSI_CHAP_RSP_LEN
);
408 AuthData
->OutChallengeLength
= ISCSI_CHAP_RSP_LEN
;
409 IScsiBinToHex ((UINT8
*) AuthData
->OutChallenge
, ISCSI_CHAP_RSP_LEN
, Challenge
, &ChallengeLen
);
410 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_CHALLENGE
, Challenge
);
412 Conn
->CHAPStep
= ISCSI_CHAP_STEP_FOUR
;
415 // set the stage transition flag.
417 ISCSI_SET_FLAG (LoginReq
, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT
);
421 Status
= EFI_PROTOCOL_ERROR
;
426 FreePool (Challenge
);