3 Copyright (c) 2004 - 2007, Intel Corporation
4 All rights reserved. This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution. The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
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 (CompareMem (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_CHAP_AUTH_DATA
*AuthData
;
126 LIST_ENTRY
*KeyValueList
;
132 UINT8 TargetRsp
[ISCSI_CHAP_RSP_LEN
];
135 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
136 ASSERT (Conn
->RspQue
.BufNum
!= 0);
138 Session
= Conn
->Session
;
139 AuthData
= &Session
->AuthData
;
141 Len
= Conn
->RspQue
.BufSize
;
142 Data
= AllocatePool (Len
);
144 return EFI_OUT_OF_RESOURCES
;
147 // Copy the data in case the data spans over multiple PDUs.
149 NetbufQueCopy (&Conn
->RspQue
, 0, Len
, Data
);
152 // Build the key-value list from the data segment of the Login Response.
154 KeyValueList
= IScsiBuildKeyValueList ((CHAR8
*) Data
, Len
);
155 if (KeyValueList
== NULL
) {
156 Status
= EFI_OUT_OF_RESOURCES
;
160 Status
= EFI_PROTOCOL_ERROR
;
162 switch (Conn
->CHAPStep
) {
163 case ISCSI_CHAP_INITIAL
:
165 // The first Login Response.
167 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG
);
172 Session
->TargetPortalGroupTag
= (UINT16
) AsciiStrDecimalToUintn (Value
);
174 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_AUTH_METHOD
);
179 // Initiator mandates CHAP authentication but target replies without "CHAP" or
180 // initiator suggets "None" but target replies with some kind of auth method.
182 if (AsciiStrCmp (Value
, ISCSI_AUTH_METHOD_CHAP
) == 0) {
183 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_NONE
) {
187 if (AuthData
->AuthConfig
.CHAPType
!= ISCSI_CHAP_NONE
) {
192 // Transit to CHAP step one.
194 Conn
->CHAPStep
= ISCSI_CHAP_STEP_ONE
;
195 Status
= EFI_SUCCESS
;
198 case ISCSI_CHAP_STEP_TWO
:
200 // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>
202 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_ALGORITHM
);
207 Algorithm
= AsciiStrDecimalToUintn (Value
);
208 if (Algorithm
!= ISCSI_CHAP_ALGORITHM_MD5
) {
210 // Unsupported algorithm is chosen by target.
215 Identifier
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_IDENTIFIER
);
216 if (Identifier
== NULL
) {
220 Challenge
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_CHALLENGE
);
221 if (Challenge
== NULL
) {
225 // Process the CHAP identifier and CHAP Challenge from Target
226 // Calculate Response value
228 AuthData
->InIdentifier
= (UINT32
) AsciiStrDecimalToUintn (Identifier
);
229 AuthData
->InChallengeLength
= ISCSI_CHAP_AUTH_MAX_LEN
;
230 IScsiHexToBin ((UINT8
*) AuthData
->InChallenge
, &AuthData
->InChallengeLength
, Challenge
);
231 Status
= IScsiCHAPCalculateResponse (
232 AuthData
->InIdentifier
,
233 AuthData
->AuthConfig
.CHAPSecret
,
234 (UINT32
) AsciiStrLen (AuthData
->AuthConfig
.CHAPSecret
),
235 AuthData
->InChallenge
,
236 AuthData
->InChallengeLength
,
237 AuthData
->CHAPResponse
241 // Transit to next step.
243 Conn
->CHAPStep
= ISCSI_CHAP_STEP_THREE
;
246 case ISCSI_CHAP_STEP_THREE
:
248 // one way CHAP authentication and the target would like to
251 Status
= EFI_SUCCESS
;
254 case ISCSI_CHAP_STEP_FOUR
:
255 ASSERT (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_MUTUAL
);
257 // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.
259 Name
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_NAME
);
264 Response
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_RESPONSE
);
265 if (Response
== NULL
) {
269 RspLen
= ISCSI_CHAP_RSP_LEN
;
270 IScsiHexToBin (TargetRsp
, &RspLen
, Response
);
273 // Check the CHAP Name and Response replied by Target.
275 Status
= IScsiCHAPAuthTarget (AuthData
, TargetRsp
);
284 IScsiFreeKeyValueList (KeyValueList
);
286 gBS
->FreePool (Data
);
293 IN ISCSI_CONNECTION
*Conn
,
300 This function fills the CHAP authentication information into the login PDU
301 during the security negotiation stage in the iSCSI connection login.
305 Conn - The iSCSI connection.
306 Pdu - The PDU to send out.
310 EFI_SUCCESS - All check passed and the phase-related CHAP authentication
311 info is filled into the iSCSI PDU.
312 EFI_OUT_OF_RESOURCES - Failed to allocate memory.
313 EFI_PROTOCOL_ERROR - Some kind of protocol error happend.
318 ISCSI_SESSION
*Session
;
319 ISCSI_LOGIN_REQUEST
*LoginReq
;
320 ISCSI_CHAP_AUTH_DATA
*AuthData
;
328 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
330 Session
= Conn
->Session
;
331 AuthData
= &Session
->AuthData
;
332 LoginReq
= (ISCSI_LOGIN_REQUEST
*) NetbufGetByte (Pdu
, 0, 0);
333 Status
= EFI_SUCCESS
;
335 RspLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
336 Response
= AllocatePool (RspLen
);
337 if (Response
== NULL
) {
338 return EFI_OUT_OF_RESOURCES
;
341 ChallengeLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
342 Challenge
= AllocatePool (ChallengeLen
);
343 if (Challenge
== NULL
) {
344 return EFI_OUT_OF_RESOURCES
;
347 switch (Conn
->CHAPStep
) {
348 case ISCSI_CHAP_INITIAL
:
350 // It's the initial Login Request. Fill in the key=value pairs mandatory
351 // for the initial Login Request.
353 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_INITIATOR_NAME
, Session
->InitiatorName
);
354 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_SESSION_TYPE
, "Normal");
355 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_TARGET_NAME
, Session
->ConfigData
.NvData
.TargetName
);
357 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_NONE
) {
358 Value
= ISCSI_KEY_VALUE_NONE
;
359 ISCSI_SET_FLAG (LoginReq
, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT
);
361 Value
= ISCSI_AUTH_METHOD_CHAP
;
364 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_AUTH_METHOD
, Value
);
368 case ISCSI_CHAP_STEP_ONE
:
370 // First step, send the Login Request with CHAP_A=<A1,A2...> key-value pair.
372 AsciiSPrint (ValueStr
, sizeof (ValueStr
), "%d", ISCSI_CHAP_ALGORITHM_MD5
);
373 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_ALGORITHM
, ValueStr
);
375 Conn
->CHAPStep
= ISCSI_CHAP_STEP_TWO
;
378 case ISCSI_CHAP_STEP_THREE
:
380 // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or
381 // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target ahtentication is
386 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_NAME
, (CHAR8
*) &AuthData
->AuthConfig
.CHAPName
);
390 IScsiBinToHex ((UINT8
*) AuthData
->CHAPResponse
, ISCSI_CHAP_RSP_LEN
, Response
, &RspLen
);
391 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_RESPONSE
, Response
);
393 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_MUTUAL
) {
397 IScsiGenRandom ((UINT8
*) &AuthData
->OutIdentifier
, 1);
398 AsciiSPrint (ValueStr
, sizeof (ValueStr
), "%d", AuthData
->OutIdentifier
);
399 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_IDENTIFIER
, ValueStr
);
403 IScsiGenRandom ((UINT8
*) AuthData
->OutChallenge
, ISCSI_CHAP_RSP_LEN
);
404 AuthData
->OutChallengeLength
= ISCSI_CHAP_RSP_LEN
;
405 IScsiBinToHex ((UINT8
*) AuthData
->OutChallenge
, ISCSI_CHAP_RSP_LEN
, Challenge
, &ChallengeLen
);
406 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_CHALLENGE
, Challenge
);
408 Conn
->CHAPStep
= ISCSI_CHAP_STEP_FOUR
;
411 // set the stage transition flag.
413 ISCSI_SET_FLAG (LoginReq
, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT
);
417 Status
= EFI_PROTOCOL_ERROR
;
421 gBS
->FreePool (Response
);
422 gBS
->FreePool (Challenge
);