3 Copyright (c) 2007 Intel Corporation. All rights reserved
4 This software and associated documentation (if any) is furnished
5 under a license and may only be used or copied in accordance
6 with the terms of the license. Except as permitted by such
7 license, no part of this software or documentation may be
8 reproduced, stored in a retrieval system, or transmitted in any
9 form or by any means without the express written consent of
20 #include "IScsiImpl.h"
23 EFI_GUID mIScsiCHAPAuthInfoGuid
= ISCSI_CHAP_AUTH_INFO_GUID
;
26 IScsiCHAPCalculateResponse (
27 IN UINT32 ChapIdentifier
,
29 IN UINT32 SecretLength
,
30 IN UINT8
*ChapChallenge
,
31 IN UINT32 ChallengeLength
,
32 OUT UINT8
*ChapResponse
39 Status
= MD5Init (&Md5Ctx
);
42 // Hash Identifier - Only calculate 1 byte data (RFC1994)
44 IdByte
[0] = (CHAR8
) ChapIdentifier
;
45 MD5Update (&Md5Ctx
, IdByte
, 1);
50 if (SecretLength
< ISCSI_CHAP_SECRET_MIN_LEN
- 1) {
51 return EFI_PROTOCOL_ERROR
;
54 MD5Update (&Md5Ctx
, ChapSecret
, SecretLength
);
57 // Hash Challenge received from Target
59 MD5Update (&Md5Ctx
, ChapChallenge
, ChallengeLength
);
61 Status
= MD5Final (&Md5Ctx
, ChapResponse
);
68 IN ISCSI_CHAP_AUTH_DATA
*AuthData
,
69 IN UINT8
*TargetResponse
74 UINT8 VerifyRsp
[ISCSI_CHAP_RSP_LEN
];
78 SecretSize
= (UINT32
) AsciiStrLen (AuthData
->AuthConfig
.ReverseCHAPSecret
);
79 Status
= IScsiCHAPCalculateResponse (
80 AuthData
->OutIdentifier
,
81 AuthData
->AuthConfig
.ReverseCHAPSecret
,
83 AuthData
->OutChallenge
,
84 AuthData
->OutChallengeLength
,
88 if (NetCompareMem (VerifyRsp
, TargetResponse
, ISCSI_CHAP_RSP_LEN
)) {
89 Status
= EFI_SECURITY_VIOLATION
;
96 IScsiCHAPOnRspReceived (
97 IN ISCSI_CONNECTION
*Conn
,
104 This function checks the received iSCSI Login Response during the security
109 Conn - The iSCSI connection.
110 Transit - The transit flag of the latest iSCSI Login Response.
114 EFI_SUCCESS - The Login Response passed the CHAP validation.
115 EFI_OUT_OF_RESOURCES - Failed to allocate memory.
116 EFI_PROTOCOL_ERROR - Some kind of protocol error happend.
121 ISCSI_SESSION
*Session
;
122 ISCSI_SESSION_CONFIG_DATA
*ConfigData
;
123 ISCSI_CHAP_AUTH_DATA
*AuthData
;
127 NET_LIST_ENTRY
*KeyValueList
;
133 UINT8 TargetRsp
[ISCSI_CHAP_RSP_LEN
];
136 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
137 ASSERT (Conn
->RspQue
.BufNum
!= 0);
139 Session
= Conn
->Session
;
140 ConfigData
= &Session
->ConfigData
;
141 AuthData
= &Session
->AuthData
;
143 Len
= Conn
->RspQue
.BufSize
;
144 Data
= NetAllocatePool (Len
);
146 return EFI_OUT_OF_RESOURCES
;
149 // Copy the data in case the data spans over multiple PDUs.
151 NetbufQueCopy (&Conn
->RspQue
, 0, Len
, Data
);
154 // Build the key-value list from the data segment of the Login Response.
156 KeyValueList
= IScsiBuildKeyValueList (Data
, Len
);
157 if (KeyValueList
== NULL
) {
158 Status
= EFI_OUT_OF_RESOURCES
;
162 Status
= EFI_PROTOCOL_ERROR
;
164 switch (Conn
->CHAPStep
) {
165 case ISCSI_CHAP_INITIAL
:
167 // The first Login Response.
169 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG
);
174 Session
->TargetPortalGroupTag
= (UINT16
) AsciiStrDecimalToUintn (Value
);
176 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_AUTH_METHOD
);
181 // Initiator mandates CHAP authentication but target replies without "CHAP" or
182 // initiator suggets "None" but target replies with some kind of auth method.
184 if (AsciiStrCmp (Value
, ISCSI_AUTH_METHOD_CHAP
) == 0) {
185 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_NONE
) {
189 if (AuthData
->AuthConfig
.CHAPType
!= ISCSI_CHAP_NONE
) {
194 // Transit to CHAP step one.
196 Conn
->CHAPStep
= ISCSI_CHAP_STEP_ONE
;
197 Status
= EFI_SUCCESS
;
200 case ISCSI_CHAP_STEP_TWO
:
202 // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>
204 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_ALGORITHM
);
209 Algorithm
= AsciiStrDecimalToUintn (Value
);
210 if (Algorithm
!= ISCSI_CHAP_ALGORITHM_MD5
) {
212 // Unsupported algorithm is chosen by target.
217 Identifier
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_IDENTIFIER
);
218 if (Identifier
== NULL
) {
222 Challenge
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_CHALLENGE
);
223 if (Challenge
== NULL
) {
227 // Process the CHAP identifier and CHAP Challenge from Target
228 // Calculate Response value
230 AuthData
->InIdentifier
= (UINT32
) AsciiStrDecimalToUintn (Identifier
);
231 AuthData
->InChallengeLength
= ISCSI_CHAP_AUTH_MAX_LEN
;
232 IScsiHexToBin ((UINT8
*) AuthData
->InChallenge
, &AuthData
->InChallengeLength
, Challenge
);
233 Status
= IScsiCHAPCalculateResponse (
234 AuthData
->InIdentifier
,
235 AuthData
->AuthConfig
.CHAPSecret
,
236 (UINT32
) AsciiStrLen (AuthData
->AuthConfig
.CHAPSecret
),
237 AuthData
->InChallenge
,
238 AuthData
->InChallengeLength
,
239 AuthData
->CHAPResponse
243 // Transit to next step.
245 Conn
->CHAPStep
= ISCSI_CHAP_STEP_THREE
;
248 case ISCSI_CHAP_STEP_THREE
:
250 // one way CHAP authentication and the target would like to
253 Status
= EFI_SUCCESS
;
256 case ISCSI_CHAP_STEP_FOUR
:
257 ASSERT (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_MUTUAL
);
259 // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.
261 Name
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_NAME
);
266 Response
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_RESPONSE
);
267 if (Response
== NULL
) {
271 RspLen
= ISCSI_CHAP_RSP_LEN
;
272 IScsiHexToBin (TargetRsp
, &RspLen
, Response
);
275 // Check the CHAP Name and Response replied by Target.
277 Status
= IScsiCHAPAuthTarget (AuthData
, TargetRsp
);
286 IScsiFreeKeyValueList (KeyValueList
);
295 IN ISCSI_CONNECTION
*Conn
,
302 This function fills the CHAP authentication information into the login PDU
303 during the security negotiation stage in the iSCSI connection login.
307 Conn - The iSCSI connection.
308 Pdu - The PDU to send out.
312 EFI_SUCCESS - All check passed and the phase-related CHAP authentication
313 info is filled into the iSCSI PDU.
314 EFI_OUT_OF_RESOURCES - Failed to allocate memory.
315 EFI_PROTOCOL_ERROR - Some kind of protocol error happend.
320 ISCSI_SESSION
*Session
;
321 ISCSI_LOGIN_REQUEST
*LoginReq
;
322 ISCSI_SESSION_CONFIG_DATA
*ConfigData
;
323 ISCSI_CHAP_AUTH_DATA
*AuthData
;
331 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
333 Session
= Conn
->Session
;
334 ConfigData
= &Session
->ConfigData
;
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
= NetAllocatePool (RspLen
);
341 if (Response
== NULL
) {
342 return EFI_OUT_OF_RESOURCES
;
345 ChallengeLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
346 Challenge
= NetAllocatePool (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
, (UINT8
*) &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
;
425 NetFreePool (Response
);
426 NetFreePool (Challenge
);