]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/IScsiDxe/IScsiCHAP.c
GenFds enable display FV space information when incremental build.
[mirror_edk2.git] / MdeModulePkg / Universal / Network / IScsiDxe / IScsiCHAP.c
CommitLineData
12618416 1/** @file\r
11e0ec6b 2 This file is for Challenge-Handshake Authentication Protocol (CHAP) Configuration.\r
3 \r
4Copyright (c) 2004 - 2008, Intel Corporation.<BR>\r
7a444476 5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
6a690e23 12\r
12618416 13**/\r
6a690e23 14\r
15#include "IScsiImpl.h"\r
16#include "Md5.h"\r
17\r
18EFI_GUID mIScsiCHAPAuthInfoGuid = ISCSI_CHAP_AUTH_INFO_GUID;\r
19\r
11e0ec6b 20/**\r
21 Initator caculates its own expected hash value. \r
22 \r
23 @param[in] ChapIdentifier ISCSI CHAP identifier sent by authenticator. \r
24 @param[in] ChapSecret ISCSI CHAP secret of the authenticator. \r
25 @param[in] SecretLength The length of ISCSI CHAP secret.\r
26 @param[in] ChapChallenge The challenge message sent by authenticator. \r
27 @param[in] ChallengeLength The length of ISCSI CHAP challenge message.\r
28 @param[out] ChapResponse The calculation of the expected hash value.\r
29 \r
30 @retval EFI_SUCCESS The expected hash value was caculatedly successfully.\r
31 @retval EFI_PROTOCOL_ERROR The length of the secret should be at least the \r
32 length of the hash value for the hashing algorithm chosen.\r
33 @retval Others Some unexpected error happened. \r
34**/\r
6a690e23 35EFI_STATUS\r
36IScsiCHAPCalculateResponse (\r
37 IN UINT32 ChapIdentifier,\r
38 IN CHAR8 *ChapSecret,\r
39 IN UINT32 SecretLength,\r
40 IN UINT8 *ChapChallenge,\r
41 IN UINT32 ChallengeLength,\r
42 OUT UINT8 *ChapResponse\r
43 )\r
44{\r
45 MD5_CTX Md5Ctx;\r
46 CHAR8 IdByte[1];\r
47 EFI_STATUS Status;\r
48\r
49 Status = MD5Init (&Md5Ctx);\r
50\r
51 //\r
52 // Hash Identifier - Only calculate 1 byte data (RFC1994)\r
53 //\r
54 IdByte[0] = (CHAR8) ChapIdentifier;\r
55 MD5Update (&Md5Ctx, IdByte, 1);\r
56\r
57 //\r
58 // Hash Secret\r
59 //\r
60 if (SecretLength < ISCSI_CHAP_SECRET_MIN_LEN - 1) {\r
61 return EFI_PROTOCOL_ERROR;\r
62 }\r
63\r
64 MD5Update (&Md5Ctx, ChapSecret, SecretLength);\r
65\r
66 //\r
67 // Hash Challenge received from Target\r
68 //\r
69 MD5Update (&Md5Ctx, ChapChallenge, ChallengeLength);\r
70\r
71 Status = MD5Final (&Md5Ctx, ChapResponse);\r
72\r
73 return Status;\r
74}\r
75\r
11e0ec6b 76/**\r
77 The initator checks the CHAP response replied by target against its own\r
78 calculation of the expected hash value. \r
79 \r
80 @param[in] AuthData ISCSI CHAP authentication data. \r
81 @param[in] TargetResponse The response from target. \r
82\r
83 @retval EFI_SUCCESS The response from target passed authentication.\r
84 @retval EFI_SECURITY_VIOLATION The response from target was not expected value.\r
85 @retval Others Some unexpected error happened.\r
86**/\r
6a690e23 87EFI_STATUS\r
88IScsiCHAPAuthTarget (\r
89 IN ISCSI_CHAP_AUTH_DATA *AuthData,\r
90 IN UINT8 *TargetResponse\r
91 )\r
92{\r
93 EFI_STATUS Status;\r
94 UINT32 SecretSize;\r
95 UINT8 VerifyRsp[ISCSI_CHAP_RSP_LEN];\r
96\r
97 Status = EFI_SUCCESS;\r
98\r
99 SecretSize = (UINT32) AsciiStrLen (AuthData->AuthConfig.ReverseCHAPSecret);\r
100 Status = IScsiCHAPCalculateResponse (\r
101 AuthData->OutIdentifier,\r
102 AuthData->AuthConfig.ReverseCHAPSecret,\r
103 SecretSize,\r
104 AuthData->OutChallenge,\r
105 AuthData->OutChallengeLength,\r
106 VerifyRsp\r
107 );\r
108\r
e48e37fc 109 if (CompareMem (VerifyRsp, TargetResponse, ISCSI_CHAP_RSP_LEN)) {\r
6a690e23 110 Status = EFI_SECURITY_VIOLATION;\r
111 }\r
112\r
113 return Status;\r
114}\r
115\r
12618416 116/**\r
6a690e23 117 This function checks the received iSCSI Login Response during the security\r
118 negotiation stage.\r
119 \r
11e0ec6b 120 @param[in] Conn The iSCSI connection.\r
121 @param[in] Transit The transit flag of the latest iSCSI Login Response.\r
6a690e23 122\r
12618416 123 @retval EFI_SUCCESS The Login Response passed the CHAP validation.\r
12618416 124 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
12618416 125 @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.\r
11e0ec6b 126 @retval Others Some unexpected error happend.\r
12618416 127**/\r
128EFI_STATUS\r
129IScsiCHAPOnRspReceived (\r
130 IN ISCSI_CONNECTION *Conn,\r
131 IN BOOLEAN Transit\r
132 )\r
6a690e23 133{\r
134 EFI_STATUS Status;\r
135 ISCSI_SESSION *Session;\r
6a690e23 136 ISCSI_CHAP_AUTH_DATA *AuthData;\r
137 CHAR8 *Value;\r
138 UINT8 *Data;\r
139 UINT32 Len;\r
e48e37fc 140 LIST_ENTRY *KeyValueList;\r
6a690e23 141 UINTN Algorithm;\r
142 CHAR8 *Identifier;\r
143 CHAR8 *Challenge;\r
144 CHAR8 *Name;\r
145 CHAR8 *Response;\r
146 UINT8 TargetRsp[ISCSI_CHAP_RSP_LEN];\r
147 UINT32 RspLen;\r
148\r
149 ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
150 ASSERT (Conn->RspQue.BufNum != 0);\r
151\r
152 Session = Conn->Session;\r
6a690e23 153 AuthData = &Session->AuthData;\r
154\r
155 Len = Conn->RspQue.BufSize;\r
e48e37fc 156 Data = AllocatePool (Len);\r
6a690e23 157 if (Data == NULL) {\r
158 return EFI_OUT_OF_RESOURCES;\r
159 }\r
160 //\r
161 // Copy the data in case the data spans over multiple PDUs.\r
162 //\r
163 NetbufQueCopy (&Conn->RspQue, 0, Len, Data);\r
164\r
165 //\r
166 // Build the key-value list from the data segment of the Login Response.\r
167 //\r
69b0882d 168 KeyValueList = IScsiBuildKeyValueList ((CHAR8 *) Data, Len);\r
6a690e23 169 if (KeyValueList == NULL) {\r
170 Status = EFI_OUT_OF_RESOURCES;\r
171 goto ON_EXIT;\r
172 }\r
173\r
174 Status = EFI_PROTOCOL_ERROR;\r
175\r
176 switch (Conn->CHAPStep) {\r
177 case ISCSI_CHAP_INITIAL:\r
178 //\r
179 // The first Login Response.\r
180 //\r
181 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG);\r
182 if (Value == NULL) {\r
183 goto ON_EXIT;\r
184 }\r
185\r
186 Session->TargetPortalGroupTag = (UINT16) AsciiStrDecimalToUintn (Value);\r
187\r
188 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_AUTH_METHOD);\r
189 if (Value == NULL) {\r
190 goto ON_EXIT;\r
191 }\r
192 //\r
193 // Initiator mandates CHAP authentication but target replies without "CHAP" or\r
194 // initiator suggets "None" but target replies with some kind of auth method.\r
195 //\r
196 if (AsciiStrCmp (Value, ISCSI_AUTH_METHOD_CHAP) == 0) {\r
197 if (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_NONE) {\r
198 goto ON_EXIT;\r
199 }\r
200 } else {\r
201 if (AuthData->AuthConfig.CHAPType != ISCSI_CHAP_NONE) {\r
202 goto ON_EXIT;\r
203 }\r
204 }\r
205 //\r
206 // Transit to CHAP step one.\r
207 //\r
208 Conn->CHAPStep = ISCSI_CHAP_STEP_ONE;\r
209 Status = EFI_SUCCESS;\r
210 break;\r
211\r
212 case ISCSI_CHAP_STEP_TWO:\r
213 //\r
214 // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>\r
215 //\r
216 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_ALGORITHM);\r
217 if (Value == NULL) {\r
218 goto ON_EXIT;\r
219 }\r
220\r
221 Algorithm = AsciiStrDecimalToUintn (Value);\r
222 if (Algorithm != ISCSI_CHAP_ALGORITHM_MD5) {\r
223 //\r
224 // Unsupported algorithm is chosen by target.\r
225 //\r
226 goto ON_EXIT;\r
227 }\r
228\r
229 Identifier = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_IDENTIFIER);\r
230 if (Identifier == NULL) {\r
231 goto ON_EXIT;\r
232 }\r
233\r
234 Challenge = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_CHALLENGE);\r
235 if (Challenge == NULL) {\r
236 goto ON_EXIT;\r
237 }\r
238 //\r
239 // Process the CHAP identifier and CHAP Challenge from Target\r
240 // Calculate Response value\r
241 //\r
242 AuthData->InIdentifier = (UINT32) AsciiStrDecimalToUintn (Identifier);\r
243 AuthData->InChallengeLength = ISCSI_CHAP_AUTH_MAX_LEN;\r
244 IScsiHexToBin ((UINT8 *) AuthData->InChallenge, &AuthData->InChallengeLength, Challenge);\r
245 Status = IScsiCHAPCalculateResponse (\r
246 AuthData->InIdentifier,\r
247 AuthData->AuthConfig.CHAPSecret,\r
248 (UINT32) AsciiStrLen (AuthData->AuthConfig.CHAPSecret),\r
249 AuthData->InChallenge,\r
250 AuthData->InChallengeLength,\r
251 AuthData->CHAPResponse\r
252 );\r
253\r
254 //\r
255 // Transit to next step.\r
256 //\r
257 Conn->CHAPStep = ISCSI_CHAP_STEP_THREE;\r
258 break;\r
259\r
260 case ISCSI_CHAP_STEP_THREE:\r
261 //\r
262 // one way CHAP authentication and the target would like to\r
263 // authenticate us.\r
264 //\r
265 Status = EFI_SUCCESS;\r
266 break;\r
267\r
268 case ISCSI_CHAP_STEP_FOUR:\r
269 ASSERT (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_MUTUAL);\r
270 //\r
271 // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.\r
272 //\r
273 Name = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_NAME);\r
274 if (Name == NULL) {\r
275 goto ON_EXIT;\r
276 }\r
277\r
278 Response = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_RESPONSE);\r
279 if (Response == NULL) {\r
280 goto ON_EXIT;\r
281 }\r
282\r
283 RspLen = ISCSI_CHAP_RSP_LEN;\r
284 IScsiHexToBin (TargetRsp, &RspLen, Response);\r
285\r
286 //\r
11e0ec6b 287 // Check the CHAP Response replied by Target.\r
6a690e23 288 //\r
289 Status = IScsiCHAPAuthTarget (AuthData, TargetRsp);\r
290 break;\r
291\r
292 default:\r
293 break;\r
294 }\r
295\r
296ON_EXIT:\r
297\r
298 IScsiFreeKeyValueList (KeyValueList);\r
299\r
e48e37fc 300 gBS->FreePool (Data);\r
6a690e23 301\r
302 return Status;\r
303}\r
304\r
12618416 305/**\r
6a690e23 306 This function fills the CHAP authentication information into the login PDU\r
307 during the security negotiation stage in the iSCSI connection login.\r
6a690e23 308\r
11e0ec6b 309 @param[in] Conn The iSCSI connection.\r
310 @param[in] Pdu The PDU to send out.\r
6a690e23 311\r
12618416 312 @retval EFI_SUCCESS All check passed and the phase-related CHAP\r
313 authentication info is filled into the iSCSI PDU.\r
12618416 314 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
12618416 315 @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.\r
12618416 316**/\r
317EFI_STATUS\r
318IScsiCHAPToSendReq (\r
319 IN ISCSI_CONNECTION *Conn,\r
320 IN NET_BUF *Pdu\r
321 )\r
6a690e23 322{\r
323 EFI_STATUS Status;\r
324 ISCSI_SESSION *Session;\r
325 ISCSI_LOGIN_REQUEST *LoginReq;\r
6a690e23 326 ISCSI_CHAP_AUTH_DATA *AuthData;\r
327 CHAR8 *Value;\r
328 CHAR8 ValueStr[256];\r
329 CHAR8 *Response;\r
330 UINT32 RspLen;\r
331 CHAR8 *Challenge;\r
332 UINT32 ChallengeLen;\r
333\r
334 ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
335\r
336 Session = Conn->Session;\r
6a690e23 337 AuthData = &Session->AuthData;\r
338 LoginReq = (ISCSI_LOGIN_REQUEST *) NetbufGetByte (Pdu, 0, 0);\r
339 Status = EFI_SUCCESS;\r
340\r
341 RspLen = 2 * ISCSI_CHAP_RSP_LEN + 3;\r
e48e37fc 342 Response = AllocatePool (RspLen);\r
6a690e23 343 if (Response == NULL) {\r
344 return EFI_OUT_OF_RESOURCES;\r
345 }\r
346\r
347 ChallengeLen = 2 * ISCSI_CHAP_RSP_LEN + 3;\r
e48e37fc 348 Challenge = AllocatePool (ChallengeLen);\r
6a690e23 349 if (Challenge == NULL) {\r
350 return EFI_OUT_OF_RESOURCES;\r
351 }\r
352\r
353 switch (Conn->CHAPStep) {\r
354 case ISCSI_CHAP_INITIAL:\r
355 //\r
356 // It's the initial Login Request. Fill in the key=value pairs mandatory\r
357 // for the initial Login Request.\r
358 //\r
359 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_INITIATOR_NAME, Session->InitiatorName);\r
360 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_SESSION_TYPE, "Normal");\r
361 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_TARGET_NAME, Session->ConfigData.NvData.TargetName);\r
362\r
363 if (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_NONE) {\r
364 Value = ISCSI_KEY_VALUE_NONE;\r
365 ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
366 } else {\r
367 Value = ISCSI_AUTH_METHOD_CHAP;\r
368 }\r
369\r
370 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_AUTH_METHOD, Value);\r
371\r
372 break;\r
373\r
374 case ISCSI_CHAP_STEP_ONE:\r
375 //\r
376 // First step, send the Login Request with CHAP_A=<A1,A2...> key-value pair.\r
377 //\r
378 AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", ISCSI_CHAP_ALGORITHM_MD5);\r
379 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, ValueStr);\r
380\r
381 Conn->CHAPStep = ISCSI_CHAP_STEP_TWO;\r
382 break;\r
383\r
384 case ISCSI_CHAP_STEP_THREE:\r
385 //\r
386 // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or\r
387 // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target ahtentication is\r
388 // required too.\r
389 //\r
390 // CHAP_N=<N>\r
391 //\r
69b0882d 392 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_NAME, (CHAR8 *) &AuthData->AuthConfig.CHAPName);\r
6a690e23 393 //\r
394 // CHAP_R=<R>\r
395 //\r
396 IScsiBinToHex ((UINT8 *) AuthData->CHAPResponse, ISCSI_CHAP_RSP_LEN, Response, &RspLen);\r
397 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_RESPONSE, Response);\r
398\r
399 if (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_MUTUAL) {\r
400 //\r
401 // CHAP_I=<I>\r
402 //\r
403 IScsiGenRandom ((UINT8 *) &AuthData->OutIdentifier, 1);\r
404 AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier);\r
405 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr);\r
406 //\r
407 // CHAP_C=<C>\r
408 //\r
409 IScsiGenRandom ((UINT8 *) AuthData->OutChallenge, ISCSI_CHAP_RSP_LEN);\r
410 AuthData->OutChallengeLength = ISCSI_CHAP_RSP_LEN;\r
411 IScsiBinToHex ((UINT8 *) AuthData->OutChallenge, ISCSI_CHAP_RSP_LEN, Challenge, &ChallengeLen);\r
412 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_CHALLENGE, Challenge);\r
413\r
414 Conn->CHAPStep = ISCSI_CHAP_STEP_FOUR;\r
415 }\r
416 //\r
417 // set the stage transition flag.\r
418 //\r
419 ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
420 break;\r
421\r
422 default:\r
423 Status = EFI_PROTOCOL_ERROR;\r
424 break;\r
425 }\r
426\r
e48e37fc 427 gBS->FreePool (Response);\r
428 gBS->FreePool (Challenge);\r
6a690e23 429\r
430 return Status;\r
431}\r