2 This file is for Challenge-Handshake Authentication Protocol (CHAP) Configuration.
4 Copyright (c) 2004 - 2008, Intel Corporation.<BR>
5 All rights reserved. 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 Some unexpected error happened.
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 Some unexpected error happened.
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
)) {
110 Status
= EFI_SECURITY_VIOLATION
;
117 This function checks the received iSCSI Login Response during the security
120 @param[in] Conn The iSCSI connection.
121 @param[in] Transit The transit flag of the latest iSCSI Login Response.
123 @retval EFI_SUCCESS The Login Response passed the CHAP validation.
124 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
125 @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.
126 @retval Others Some unexpected error happend.
129 IScsiCHAPOnRspReceived (
130 IN ISCSI_CONNECTION
*Conn
,
135 ISCSI_SESSION
*Session
;
136 ISCSI_CHAP_AUTH_DATA
*AuthData
;
140 LIST_ENTRY
*KeyValueList
;
146 UINT8 TargetRsp
[ISCSI_CHAP_RSP_LEN
];
149 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
150 ASSERT (Conn
->RspQue
.BufNum
!= 0);
152 Session
= Conn
->Session
;
153 AuthData
= &Session
->AuthData
;
155 Len
= Conn
->RspQue
.BufSize
;
156 Data
= AllocatePool (Len
);
158 return EFI_OUT_OF_RESOURCES
;
161 // Copy the data in case the data spans over multiple PDUs.
163 NetbufQueCopy (&Conn
->RspQue
, 0, Len
, Data
);
166 // Build the key-value list from the data segment of the Login Response.
168 KeyValueList
= IScsiBuildKeyValueList ((CHAR8
*) Data
, Len
);
169 if (KeyValueList
== NULL
) {
170 Status
= EFI_OUT_OF_RESOURCES
;
174 Status
= EFI_PROTOCOL_ERROR
;
176 switch (Conn
->CHAPStep
) {
177 case ISCSI_CHAP_INITIAL
:
179 // The first Login Response.
181 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG
);
186 Session
->TargetPortalGroupTag
= (UINT16
) AsciiStrDecimalToUintn (Value
);
188 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_AUTH_METHOD
);
193 // Initiator mandates CHAP authentication but target replies without "CHAP" or
194 // initiator suggets "None" but target replies with some kind of auth method.
196 if (AsciiStrCmp (Value
, ISCSI_AUTH_METHOD_CHAP
) == 0) {
197 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_NONE
) {
201 if (AuthData
->AuthConfig
.CHAPType
!= ISCSI_CHAP_NONE
) {
206 // Transit to CHAP step one.
208 Conn
->CHAPStep
= ISCSI_CHAP_STEP_ONE
;
209 Status
= EFI_SUCCESS
;
212 case ISCSI_CHAP_STEP_TWO
:
214 // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>
216 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_ALGORITHM
);
221 Algorithm
= AsciiStrDecimalToUintn (Value
);
222 if (Algorithm
!= ISCSI_CHAP_ALGORITHM_MD5
) {
224 // Unsupported algorithm is chosen by target.
229 Identifier
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_IDENTIFIER
);
230 if (Identifier
== NULL
) {
234 Challenge
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_CHALLENGE
);
235 if (Challenge
== NULL
) {
239 // Process the CHAP identifier and CHAP Challenge from Target
240 // Calculate Response value
242 AuthData
->InIdentifier
= (UINT32
) AsciiStrDecimalToUintn (Identifier
);
243 AuthData
->InChallengeLength
= ISCSI_CHAP_AUTH_MAX_LEN
;
244 IScsiHexToBin ((UINT8
*) AuthData
->InChallenge
, &AuthData
->InChallengeLength
, Challenge
);
245 Status
= IScsiCHAPCalculateResponse (
246 AuthData
->InIdentifier
,
247 AuthData
->AuthConfig
.CHAPSecret
,
248 (UINT32
) AsciiStrLen (AuthData
->AuthConfig
.CHAPSecret
),
249 AuthData
->InChallenge
,
250 AuthData
->InChallengeLength
,
251 AuthData
->CHAPResponse
255 // Transit to next step.
257 Conn
->CHAPStep
= ISCSI_CHAP_STEP_THREE
;
260 case ISCSI_CHAP_STEP_THREE
:
262 // one way CHAP authentication and the target would like to
265 Status
= EFI_SUCCESS
;
268 case ISCSI_CHAP_STEP_FOUR
:
269 ASSERT (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_MUTUAL
);
271 // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.
273 Name
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_NAME
);
278 Response
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_RESPONSE
);
279 if (Response
== NULL
) {
283 RspLen
= ISCSI_CHAP_RSP_LEN
;
284 IScsiHexToBin (TargetRsp
, &RspLen
, Response
);
287 // Check the CHAP Response replied by Target.
289 Status
= IScsiCHAPAuthTarget (AuthData
, TargetRsp
);
298 IScsiFreeKeyValueList (KeyValueList
);
300 gBS
->FreePool (Data
);
306 This function fills the CHAP authentication information into the login PDU
307 during the security negotiation stage in the iSCSI connection login.
309 @param[in] Conn The iSCSI connection.
310 @param[in] Pdu The PDU to send out.
312 @retval EFI_SUCCESS All check passed and the phase-related CHAP
313 authentication info is filled into the iSCSI PDU.
314 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
315 @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.
319 IN ISCSI_CONNECTION
*Conn
,
324 ISCSI_SESSION
*Session
;
325 ISCSI_LOGIN_REQUEST
*LoginReq
;
326 ISCSI_CHAP_AUTH_DATA
*AuthData
;
334 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
336 Session
= Conn
->Session
;
337 AuthData
= &Session
->AuthData
;
338 LoginReq
= (ISCSI_LOGIN_REQUEST
*) NetbufGetByte (Pdu
, 0, 0);
339 Status
= EFI_SUCCESS
;
341 RspLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
342 Response
= AllocatePool (RspLen
);
343 if (Response
== NULL
) {
344 return EFI_OUT_OF_RESOURCES
;
347 ChallengeLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
348 Challenge
= AllocatePool (ChallengeLen
);
349 if (Challenge
== NULL
) {
350 return EFI_OUT_OF_RESOURCES
;
353 switch (Conn
->CHAPStep
) {
354 case ISCSI_CHAP_INITIAL
:
356 // It's the initial Login Request. Fill in the key=value pairs mandatory
357 // for the initial Login Request.
359 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_INITIATOR_NAME
, Session
->InitiatorName
);
360 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_SESSION_TYPE
, "Normal");
361 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_TARGET_NAME
, Session
->ConfigData
.NvData
.TargetName
);
363 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_NONE
) {
364 Value
= ISCSI_KEY_VALUE_NONE
;
365 ISCSI_SET_FLAG (LoginReq
, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT
);
367 Value
= ISCSI_AUTH_METHOD_CHAP
;
370 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_AUTH_METHOD
, Value
);
374 case ISCSI_CHAP_STEP_ONE
:
376 // First step, send the Login Request with CHAP_A=<A1,A2...> key-value pair.
378 AsciiSPrint (ValueStr
, sizeof (ValueStr
), "%d", ISCSI_CHAP_ALGORITHM_MD5
);
379 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_ALGORITHM
, ValueStr
);
381 Conn
->CHAPStep
= ISCSI_CHAP_STEP_TWO
;
384 case ISCSI_CHAP_STEP_THREE
:
386 // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or
387 // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target ahtentication is
392 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_NAME
, (CHAR8
*) &AuthData
->AuthConfig
.CHAPName
);
396 IScsiBinToHex ((UINT8
*) AuthData
->CHAPResponse
, ISCSI_CHAP_RSP_LEN
, Response
, &RspLen
);
397 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_RESPONSE
, Response
);
399 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_MUTUAL
) {
403 IScsiGenRandom ((UINT8
*) &AuthData
->OutIdentifier
, 1);
404 AsciiSPrint (ValueStr
, sizeof (ValueStr
), "%d", AuthData
->OutIdentifier
);
405 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_IDENTIFIER
, ValueStr
);
409 IScsiGenRandom ((UINT8
*) AuthData
->OutChallenge
, ISCSI_CHAP_RSP_LEN
);
410 AuthData
->OutChallengeLength
= ISCSI_CHAP_RSP_LEN
;
411 IScsiBinToHex ((UINT8
*) AuthData
->OutChallenge
, ISCSI_CHAP_RSP_LEN
, Challenge
, &ChallengeLen
);
412 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_CHALLENGE
, Challenge
);
414 Conn
->CHAPStep
= ISCSI_CHAP_STEP_FOUR
;
417 // set the stage transition flag.
419 ISCSI_SET_FLAG (LoginReq
, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT
);
423 Status
= EFI_PROTOCOL_ERROR
;
427 gBS
->FreePool (Response
);
428 gBS
->FreePool (Challenge
);