2 Challenge-Handshake Authentication Protocol (CHAP) Configuration
4 Copyright (c) 2004 - 2008, Intel Corporation
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.
19 This file is for CHAP configuration
23 #include "IScsiImpl.h"
26 EFI_GUID mIScsiCHAPAuthInfoGuid
= ISCSI_CHAP_AUTH_INFO_GUID
;
29 IScsiCHAPCalculateResponse (
30 IN UINT32 ChapIdentifier
,
32 IN UINT32 SecretLength
,
33 IN UINT8
*ChapChallenge
,
34 IN UINT32 ChallengeLength
,
35 OUT UINT8
*ChapResponse
42 Status
= MD5Init (&Md5Ctx
);
45 // Hash Identifier - Only calculate 1 byte data (RFC1994)
47 IdByte
[0] = (CHAR8
) ChapIdentifier
;
48 MD5Update (&Md5Ctx
, IdByte
, 1);
53 if (SecretLength
< ISCSI_CHAP_SECRET_MIN_LEN
- 1) {
54 return EFI_PROTOCOL_ERROR
;
57 MD5Update (&Md5Ctx
, ChapSecret
, SecretLength
);
60 // Hash Challenge received from Target
62 MD5Update (&Md5Ctx
, ChapChallenge
, ChallengeLength
);
64 Status
= MD5Final (&Md5Ctx
, ChapResponse
);
71 IN ISCSI_CHAP_AUTH_DATA
*AuthData
,
72 IN UINT8
*TargetResponse
77 UINT8 VerifyRsp
[ISCSI_CHAP_RSP_LEN
];
81 SecretSize
= (UINT32
) AsciiStrLen (AuthData
->AuthConfig
.ReverseCHAPSecret
);
82 Status
= IScsiCHAPCalculateResponse (
83 AuthData
->OutIdentifier
,
84 AuthData
->AuthConfig
.ReverseCHAPSecret
,
86 AuthData
->OutChallenge
,
87 AuthData
->OutChallengeLength
,
91 if (CompareMem (VerifyRsp
, TargetResponse
, ISCSI_CHAP_RSP_LEN
)) {
92 Status
= EFI_SECURITY_VIOLATION
;
99 This function checks the received iSCSI Login Response during the security
102 @param Conn[in] The iSCSI connection.
104 @param Transit[in] The transit flag of the latest iSCSI Login Response.
106 @retval EFI_SUCCESS The Login Response passed the CHAP validation.
108 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
110 @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.
114 IScsiCHAPOnRspReceived (
115 IN ISCSI_CONNECTION
*Conn
,
120 ISCSI_SESSION
*Session
;
121 ISCSI_CHAP_AUTH_DATA
*AuthData
;
125 LIST_ENTRY
*KeyValueList
;
131 UINT8 TargetRsp
[ISCSI_CHAP_RSP_LEN
];
134 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
135 ASSERT (Conn
->RspQue
.BufNum
!= 0);
137 Session
= Conn
->Session
;
138 AuthData
= &Session
->AuthData
;
140 Len
= Conn
->RspQue
.BufSize
;
141 Data
= AllocatePool (Len
);
143 return EFI_OUT_OF_RESOURCES
;
146 // Copy the data in case the data spans over multiple PDUs.
148 NetbufQueCopy (&Conn
->RspQue
, 0, Len
, Data
);
151 // Build the key-value list from the data segment of the Login Response.
153 KeyValueList
= IScsiBuildKeyValueList ((CHAR8
*) Data
, Len
);
154 if (KeyValueList
== NULL
) {
155 Status
= EFI_OUT_OF_RESOURCES
;
159 Status
= EFI_PROTOCOL_ERROR
;
161 switch (Conn
->CHAPStep
) {
162 case ISCSI_CHAP_INITIAL
:
164 // The first Login Response.
166 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG
);
171 Session
->TargetPortalGroupTag
= (UINT16
) AsciiStrDecimalToUintn (Value
);
173 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_AUTH_METHOD
);
178 // Initiator mandates CHAP authentication but target replies without "CHAP" or
179 // initiator suggets "None" but target replies with some kind of auth method.
181 if (AsciiStrCmp (Value
, ISCSI_AUTH_METHOD_CHAP
) == 0) {
182 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_NONE
) {
186 if (AuthData
->AuthConfig
.CHAPType
!= ISCSI_CHAP_NONE
) {
191 // Transit to CHAP step one.
193 Conn
->CHAPStep
= ISCSI_CHAP_STEP_ONE
;
194 Status
= EFI_SUCCESS
;
197 case ISCSI_CHAP_STEP_TWO
:
199 // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>
201 Value
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_ALGORITHM
);
206 Algorithm
= AsciiStrDecimalToUintn (Value
);
207 if (Algorithm
!= ISCSI_CHAP_ALGORITHM_MD5
) {
209 // Unsupported algorithm is chosen by target.
214 Identifier
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_IDENTIFIER
);
215 if (Identifier
== NULL
) {
219 Challenge
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_CHALLENGE
);
220 if (Challenge
== NULL
) {
224 // Process the CHAP identifier and CHAP Challenge from Target
225 // Calculate Response value
227 AuthData
->InIdentifier
= (UINT32
) AsciiStrDecimalToUintn (Identifier
);
228 AuthData
->InChallengeLength
= ISCSI_CHAP_AUTH_MAX_LEN
;
229 IScsiHexToBin ((UINT8
*) AuthData
->InChallenge
, &AuthData
->InChallengeLength
, Challenge
);
230 Status
= IScsiCHAPCalculateResponse (
231 AuthData
->InIdentifier
,
232 AuthData
->AuthConfig
.CHAPSecret
,
233 (UINT32
) AsciiStrLen (AuthData
->AuthConfig
.CHAPSecret
),
234 AuthData
->InChallenge
,
235 AuthData
->InChallengeLength
,
236 AuthData
->CHAPResponse
240 // Transit to next step.
242 Conn
->CHAPStep
= ISCSI_CHAP_STEP_THREE
;
245 case ISCSI_CHAP_STEP_THREE
:
247 // one way CHAP authentication and the target would like to
250 Status
= EFI_SUCCESS
;
253 case ISCSI_CHAP_STEP_FOUR
:
254 ASSERT (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_MUTUAL
);
256 // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.
258 Name
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_NAME
);
263 Response
= IScsiGetValueByKeyFromList (KeyValueList
, ISCSI_KEY_CHAP_RESPONSE
);
264 if (Response
== NULL
) {
268 RspLen
= ISCSI_CHAP_RSP_LEN
;
269 IScsiHexToBin (TargetRsp
, &RspLen
, Response
);
272 // Check the CHAP Name and Response replied by Target.
274 Status
= IScsiCHAPAuthTarget (AuthData
, TargetRsp
);
283 IScsiFreeKeyValueList (KeyValueList
);
285 gBS
->FreePool (Data
);
291 This function fills the CHAP authentication information into the login PDU
292 during the security negotiation stage in the iSCSI connection login.
294 @param Conn[in] The iSCSI connection.
296 @param Pdu[in] The PDU to send out.
298 @retval EFI_SUCCESS All check passed and the phase-related CHAP
299 authentication info is filled into the iSCSI PDU.
301 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.
303 @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.
308 IN ISCSI_CONNECTION
*Conn
,
313 ISCSI_SESSION
*Session
;
314 ISCSI_LOGIN_REQUEST
*LoginReq
;
315 ISCSI_CHAP_AUTH_DATA
*AuthData
;
323 ASSERT (Conn
->CurrentStage
== ISCSI_SECURITY_NEGOTIATION
);
325 Session
= Conn
->Session
;
326 AuthData
= &Session
->AuthData
;
327 LoginReq
= (ISCSI_LOGIN_REQUEST
*) NetbufGetByte (Pdu
, 0, 0);
328 Status
= EFI_SUCCESS
;
330 RspLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
331 Response
= AllocatePool (RspLen
);
332 if (Response
== NULL
) {
333 return EFI_OUT_OF_RESOURCES
;
336 ChallengeLen
= 2 * ISCSI_CHAP_RSP_LEN
+ 3;
337 Challenge
= AllocatePool (ChallengeLen
);
338 if (Challenge
== NULL
) {
339 return EFI_OUT_OF_RESOURCES
;
342 switch (Conn
->CHAPStep
) {
343 case ISCSI_CHAP_INITIAL
:
345 // It's the initial Login Request. Fill in the key=value pairs mandatory
346 // for the initial Login Request.
348 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_INITIATOR_NAME
, Session
->InitiatorName
);
349 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_SESSION_TYPE
, "Normal");
350 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_TARGET_NAME
, Session
->ConfigData
.NvData
.TargetName
);
352 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_NONE
) {
353 Value
= ISCSI_KEY_VALUE_NONE
;
354 ISCSI_SET_FLAG (LoginReq
, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT
);
356 Value
= ISCSI_AUTH_METHOD_CHAP
;
359 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_AUTH_METHOD
, Value
);
363 case ISCSI_CHAP_STEP_ONE
:
365 // First step, send the Login Request with CHAP_A=<A1,A2...> key-value pair.
367 AsciiSPrint (ValueStr
, sizeof (ValueStr
), "%d", ISCSI_CHAP_ALGORITHM_MD5
);
368 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_ALGORITHM
, ValueStr
);
370 Conn
->CHAPStep
= ISCSI_CHAP_STEP_TWO
;
373 case ISCSI_CHAP_STEP_THREE
:
375 // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or
376 // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target ahtentication is
381 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_NAME
, (CHAR8
*) &AuthData
->AuthConfig
.CHAPName
);
385 IScsiBinToHex ((UINT8
*) AuthData
->CHAPResponse
, ISCSI_CHAP_RSP_LEN
, Response
, &RspLen
);
386 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_RESPONSE
, Response
);
388 if (AuthData
->AuthConfig
.CHAPType
== ISCSI_CHAP_MUTUAL
) {
392 IScsiGenRandom ((UINT8
*) &AuthData
->OutIdentifier
, 1);
393 AsciiSPrint (ValueStr
, sizeof (ValueStr
), "%d", AuthData
->OutIdentifier
);
394 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_IDENTIFIER
, ValueStr
);
398 IScsiGenRandom ((UINT8
*) AuthData
->OutChallenge
, ISCSI_CHAP_RSP_LEN
);
399 AuthData
->OutChallengeLength
= ISCSI_CHAP_RSP_LEN
;
400 IScsiBinToHex ((UINT8
*) AuthData
->OutChallenge
, ISCSI_CHAP_RSP_LEN
, Challenge
, &ChallengeLen
);
401 IScsiAddKeyValuePair (Pdu
, ISCSI_KEY_CHAP_CHALLENGE
, Challenge
);
403 Conn
->CHAPStep
= ISCSI_CHAP_STEP_FOUR
;
406 // set the stage transition flag.
408 ISCSI_SET_FLAG (LoginReq
, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT
);
412 Status
= EFI_PROTOCOL_ERROR
;
416 gBS
->FreePool (Response
);
417 gBS
->FreePool (Challenge
);