]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/IScsiDxe/IScsiCHAP.c
NetworkPkg/IScsiDxe: simplify "ISCSI_CHAP_AUTH_DATA.InChallenge" size
[mirror_edk2.git] / NetworkPkg / IScsiDxe / IScsiCHAP.c
CommitLineData
4c5a5e0c 1/** @file\r
83761337
LE
2 This file is for Challenge-Handshake Authentication Protocol (CHAP)\r
3 Configuration.\r
4c5a5e0c 4\r
f75a7f56 5Copyright (c) 2004 - 2018, Intel Corporation. All rights reserved.<BR>\r
ecf98fbc 6SPDX-License-Identifier: BSD-2-Clause-Patent\r
4c5a5e0c 7\r
8**/\r
9\r
10#include "IScsiImpl.h"\r
11\r
12/**\r
efb56593 13 Initiator calculates its own expected hash value.\r
f75a7f56 14\r
4c5a5e0c 15 @param[in] ChapIdentifier iSCSI CHAP identifier sent by authenticator.\r
16 @param[in] ChapSecret iSCSI CHAP secret of the authenticator.\r
17 @param[in] SecretLength The length of iSCSI CHAP secret.\r
18 @param[in] ChapChallenge The challenge message sent by authenticator.\r
19 @param[in] ChallengeLength The length of iSCSI CHAP challenge message.\r
20 @param[out] ChapResponse The calculation of the expected hash value.\r
f75a7f56 21\r
83761337
LE
22 @retval EFI_SUCCESS The expected hash value was calculatedly\r
23 successfully.\r
24 @retval EFI_PROTOCOL_ERROR The length of the secret should be at least\r
25 the length of the hash value for the hashing\r
26 algorithm chosen.\r
4c5a5e0c 27 @retval EFI_PROTOCOL_ERROR MD5 hash operation fail.\r
28 @retval EFI_OUT_OF_RESOURCES Fail to allocate resource to complete MD5.\r
29\r
30**/\r
31EFI_STATUS\r
32IScsiCHAPCalculateResponse (\r
33 IN UINT32 ChapIdentifier,\r
34 IN CHAR8 *ChapSecret,\r
35 IN UINT32 SecretLength,\r
36 IN UINT8 *ChapChallenge,\r
37 IN UINT32 ChallengeLength,\r
38 OUT UINT8 *ChapResponse\r
39 )\r
40{\r
41 UINTN Md5ContextSize;\r
42 VOID *Md5Ctx;\r
43 CHAR8 IdByte[1];\r
44 EFI_STATUS Status;\r
45\r
46 if (SecretLength < ISCSI_CHAP_SECRET_MIN_LEN) {\r
47 return EFI_PROTOCOL_ERROR;\r
48 }\r
49\r
50 Md5ContextSize = Md5GetContextSize ();\r
51 Md5Ctx = AllocatePool (Md5ContextSize);\r
52 if (Md5Ctx == NULL) {\r
53 return EFI_OUT_OF_RESOURCES;\r
54 }\r
55\r
56 Status = EFI_PROTOCOL_ERROR;\r
57\r
58 if (!Md5Init (Md5Ctx)) {\r
59 goto Exit;\r
60 }\r
61\r
62 //\r
63 // Hash Identifier - Only calculate 1 byte data (RFC1994)\r
64 //\r
65 IdByte[0] = (CHAR8) ChapIdentifier;\r
66 if (!Md5Update (Md5Ctx, IdByte, 1)) {\r
67 goto Exit;\r
68 }\r
69\r
70 //\r
71 // Hash Secret\r
72 //\r
73 if (!Md5Update (Md5Ctx, ChapSecret, SecretLength)) {\r
74 goto Exit;\r
75 }\r
76\r
77 //\r
78 // Hash Challenge received from Target\r
79 //\r
80 if (!Md5Update (Md5Ctx, ChapChallenge, ChallengeLength)) {\r
81 goto Exit;\r
82 }\r
83\r
84 if (Md5Final (Md5Ctx, ChapResponse)) {\r
85 Status = EFI_SUCCESS;\r
86 }\r
87\r
88Exit:\r
89 FreePool (Md5Ctx);\r
90 return Status;\r
91}\r
92\r
93/**\r
efb56593 94 The initiator checks the CHAP response replied by target against its own\r
f75a7f56
LG
95 calculation of the expected hash value.\r
96\r
97 @param[in] AuthData iSCSI CHAP authentication data.\r
98 @param[in] TargetResponse The response from target.\r
4c5a5e0c 99\r
83761337
LE
100 @retval EFI_SUCCESS The response from target passed\r
101 authentication.\r
102 @retval EFI_SECURITY_VIOLATION The response from target was not expected\r
103 value.\r
4c5a5e0c 104 @retval Others Other errors as indicated.\r
105\r
106**/\r
107EFI_STATUS\r
108IScsiCHAPAuthTarget (\r
109 IN ISCSI_CHAP_AUTH_DATA *AuthData,\r
110 IN UINT8 *TargetResponse\r
111 )\r
112{\r
113 EFI_STATUS Status;\r
114 UINT32 SecretSize;\r
115 UINT8 VerifyRsp[ISCSI_CHAP_RSP_LEN];\r
116\r
117 Status = EFI_SUCCESS;\r
118\r
119 SecretSize = (UINT32) AsciiStrLen (AuthData->AuthConfig->ReverseCHAPSecret);\r
120 Status = IScsiCHAPCalculateResponse (\r
121 AuthData->OutIdentifier,\r
122 AuthData->AuthConfig->ReverseCHAPSecret,\r
123 SecretSize,\r
124 AuthData->OutChallenge,\r
125 AuthData->OutChallengeLength,\r
126 VerifyRsp\r
127 );\r
128\r
129 if (CompareMem (VerifyRsp, TargetResponse, ISCSI_CHAP_RSP_LEN) != 0) {\r
130 Status = EFI_SECURITY_VIOLATION;\r
131 }\r
132\r
133 return Status;\r
134}\r
135\r
136\r
137/**\r
138 This function checks the received iSCSI Login Response during the security\r
139 negotiation stage.\r
140\r
141 @param[in] Conn The iSCSI connection.\r
142\r
143 @retval EFI_SUCCESS The Login Response passed the CHAP validation.\r
144 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
145 @retval EFI_PROTOCOL_ERROR Some kind of protocol error occurred.\r
146 @retval Others Other errors as indicated.\r
147\r
148**/\r
149EFI_STATUS\r
150IScsiCHAPOnRspReceived (\r
151 IN ISCSI_CONNECTION *Conn\r
152 )\r
153{\r
154 EFI_STATUS Status;\r
155 ISCSI_SESSION *Session;\r
156 ISCSI_CHAP_AUTH_DATA *AuthData;\r
157 CHAR8 *Value;\r
158 UINT8 *Data;\r
159 UINT32 Len;\r
160 LIST_ENTRY *KeyValueList;\r
161 UINTN Algorithm;\r
162 CHAR8 *Identifier;\r
163 CHAR8 *Challenge;\r
164 CHAR8 *Name;\r
165 CHAR8 *Response;\r
166 UINT8 TargetRsp[ISCSI_CHAP_RSP_LEN];\r
167 UINT32 RspLen;\r
168 UINTN Result;\r
169\r
170 ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
171 ASSERT (Conn->RspQue.BufNum != 0);\r
172\r
173 Session = Conn->Session;\r
174 AuthData = &Session->AuthData.CHAP;\r
175 Len = Conn->RspQue.BufSize;\r
176 Data = AllocateZeroPool (Len);\r
177 if (Data == NULL) {\r
178 return EFI_OUT_OF_RESOURCES;\r
179 }\r
180 //\r
181 // Copy the data in case the data spans over multiple PDUs.\r
182 //\r
183 NetbufQueCopy (&Conn->RspQue, 0, Len, Data);\r
184\r
185 //\r
186 // Build the key-value list from the data segment of the Login Response.\r
187 //\r
188 KeyValueList = IScsiBuildKeyValueList ((CHAR8 *) Data, Len);\r
189 if (KeyValueList == NULL) {\r
190 Status = EFI_OUT_OF_RESOURCES;\r
191 goto ON_EXIT;\r
192 }\r
193\r
194 Status = EFI_PROTOCOL_ERROR;\r
195\r
196 switch (Conn->AuthStep) {\r
197 case ISCSI_AUTH_INITIAL:\r
198 //\r
199 // The first Login Response.\r
200 //\r
83761337
LE
201 Value = IScsiGetValueByKeyFromList (\r
202 KeyValueList,\r
203 ISCSI_KEY_TARGET_PORTAL_GROUP_TAG\r
204 );\r
4c5a5e0c 205 if (Value == NULL) {\r
206 goto ON_EXIT;\r
207 }\r
208\r
209 Result = IScsiNetNtoi (Value);\r
210 if (Result > 0xFFFF) {\r
211 goto ON_EXIT;\r
212 }\r
213\r
214 Session->TargetPortalGroupTag = (UINT16) Result;\r
215\r
83761337
LE
216 Value = IScsiGetValueByKeyFromList (\r
217 KeyValueList,\r
218 ISCSI_KEY_AUTH_METHOD\r
219 );\r
4c5a5e0c 220 if (Value == NULL) {\r
221 goto ON_EXIT;\r
222 }\r
223 //\r
83761337
LE
224 // Initiator mandates CHAP authentication but target replies without\r
225 // "CHAP", or initiator suggets "None" but target replies with some kind of\r
226 // auth method.\r
4c5a5e0c 227 //\r
228 if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) {\r
229 if (AsciiStrCmp (Value, ISCSI_KEY_VALUE_NONE) != 0) {\r
230 goto ON_EXIT;\r
231 }\r
232 } else if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) {\r
233 if (AsciiStrCmp (Value, ISCSI_AUTH_METHOD_CHAP) != 0) {\r
234 goto ON_EXIT;\r
235 }\r
236 } else {\r
237 goto ON_EXIT;\r
238 }\r
239\r
240 //\r
241 // Transit to CHAP step one.\r
242 //\r
243 Conn->AuthStep = ISCSI_CHAP_STEP_ONE;\r
244 Status = EFI_SUCCESS;\r
245 break;\r
246\r
247 case ISCSI_CHAP_STEP_TWO:\r
248 //\r
249 // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>\r
250 //\r
83761337
LE
251 Value = IScsiGetValueByKeyFromList (\r
252 KeyValueList,\r
253 ISCSI_KEY_CHAP_ALGORITHM\r
254 );\r
4c5a5e0c 255 if (Value == NULL) {\r
256 goto ON_EXIT;\r
257 }\r
258\r
259 Algorithm = IScsiNetNtoi (Value);\r
260 if (Algorithm != ISCSI_CHAP_ALGORITHM_MD5) {\r
261 //\r
262 // Unsupported algorithm is chosen by target.\r
263 //\r
264 goto ON_EXIT;\r
265 }\r
266\r
83761337
LE
267 Identifier = IScsiGetValueByKeyFromList (\r
268 KeyValueList,\r
269 ISCSI_KEY_CHAP_IDENTIFIER\r
270 );\r
4c5a5e0c 271 if (Identifier == NULL) {\r
272 goto ON_EXIT;\r
273 }\r
274\r
83761337
LE
275 Challenge = IScsiGetValueByKeyFromList (\r
276 KeyValueList,\r
277 ISCSI_KEY_CHAP_CHALLENGE\r
278 );\r
4c5a5e0c 279 if (Challenge == NULL) {\r
280 goto ON_EXIT;\r
281 }\r
282 //\r
283 // Process the CHAP identifier and CHAP Challenge from Target.\r
284 // Calculate Response value.\r
f75a7f56 285 //\r
4c5a5e0c 286 Result = IScsiNetNtoi (Identifier);\r
287 if (Result > 0xFF) {\r
288 goto ON_EXIT;\r
f75a7f56
LG
289 }\r
290\r
4c5a5e0c 291 AuthData->InIdentifier = (UINT32) Result;\r
29cab43b 292 AuthData->InChallengeLength = (UINT32) sizeof (AuthData->InChallenge);\r
83761337
LE
293 IScsiHexToBin (\r
294 (UINT8 *) AuthData->InChallenge,\r
295 &AuthData->InChallengeLength,\r
296 Challenge\r
297 );\r
4c5a5e0c 298 Status = IScsiCHAPCalculateResponse (\r
299 AuthData->InIdentifier,\r
300 AuthData->AuthConfig->CHAPSecret,\r
301 (UINT32) AsciiStrLen (AuthData->AuthConfig->CHAPSecret),\r
302 AuthData->InChallenge,\r
303 AuthData->InChallengeLength,\r
304 AuthData->CHAPResponse\r
305 );\r
306\r
307 //\r
308 // Transit to next step.\r
309 //\r
310 Conn->AuthStep = ISCSI_CHAP_STEP_THREE;\r
311 break;\r
312\r
313 case ISCSI_CHAP_STEP_THREE:\r
314 //\r
315 // One way CHAP authentication and the target would like to\r
316 // authenticate us.\r
317 //\r
318 Status = EFI_SUCCESS;\r
319 break;\r
320\r
321 case ISCSI_CHAP_STEP_FOUR:\r
322 ASSERT (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL);\r
323 //\r
324 // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.\r
325 //\r
326 Name = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_NAME);\r
327 if (Name == NULL) {\r
328 goto ON_EXIT;\r
329 }\r
330\r
83761337
LE
331 Response = IScsiGetValueByKeyFromList (\r
332 KeyValueList,\r
333 ISCSI_KEY_CHAP_RESPONSE\r
334 );\r
4c5a5e0c 335 if (Response == NULL) {\r
336 goto ON_EXIT;\r
337 }\r
338\r
339 RspLen = ISCSI_CHAP_RSP_LEN;\r
340 IScsiHexToBin (TargetRsp, &RspLen, Response);\r
341\r
342 //\r
343 // Check the CHAP Name and Response replied by Target.\r
344 //\r
345 Status = IScsiCHAPAuthTarget (AuthData, TargetRsp);\r
346 break;\r
347\r
348 default:\r
349 break;\r
350 }\r
351\r
352ON_EXIT:\r
353\r
354 if (KeyValueList != NULL) {\r
355 IScsiFreeKeyValueList (KeyValueList);\r
f75a7f56 356 }\r
4c5a5e0c 357\r
358 FreePool (Data);\r
359\r
360 return Status;\r
361}\r
362\r
363\r
364/**\r
365 This function fills the CHAP authentication information into the login PDU\r
366 during the security negotiation stage in the iSCSI connection login.\r
367\r
368 @param[in] Conn The iSCSI connection.\r
369 @param[in, out] Pdu The PDU to send out.\r
370\r
371 @retval EFI_SUCCESS All check passed and the phase-related CHAP\r
83761337
LE
372 authentication info is filled into the iSCSI\r
373 PDU.\r
4c5a5e0c 374 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
375 @retval EFI_PROTOCOL_ERROR Some kind of protocol error occurred.\r
376\r
377**/\r
378EFI_STATUS\r
379IScsiCHAPToSendReq (\r
380 IN ISCSI_CONNECTION *Conn,\r
381 IN OUT NET_BUF *Pdu\r
382 )\r
383{\r
384 EFI_STATUS Status;\r
385 ISCSI_SESSION *Session;\r
386 ISCSI_LOGIN_REQUEST *LoginReq;\r
387 ISCSI_CHAP_AUTH_DATA *AuthData;\r
388 CHAR8 *Value;\r
389 CHAR8 ValueStr[256];\r
390 CHAR8 *Response;\r
391 UINT32 RspLen;\r
392 CHAR8 *Challenge;\r
393 UINT32 ChallengeLen;\r
394\r
395 ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
396\r
397 Session = Conn->Session;\r
398 AuthData = &Session->AuthData.CHAP;\r
399 LoginReq = (ISCSI_LOGIN_REQUEST *) NetbufGetByte (Pdu, 0, 0);\r
7a49cd08
ED
400 if (LoginReq == NULL) {\r
401 return EFI_PROTOCOL_ERROR;\r
402 }\r
4c5a5e0c 403 Status = EFI_SUCCESS;\r
404\r
405 RspLen = 2 * ISCSI_CHAP_RSP_LEN + 3;\r
406 Response = AllocateZeroPool (RspLen);\r
407 if (Response == NULL) {\r
408 return EFI_OUT_OF_RESOURCES;\r
409 }\r
410\r
411 ChallengeLen = 2 * ISCSI_CHAP_RSP_LEN + 3;\r
412 Challenge = AllocateZeroPool (ChallengeLen);\r
413 if (Challenge == NULL) {\r
414 FreePool (Response);\r
415 return EFI_OUT_OF_RESOURCES;\r
416 }\r
417\r
418 switch (Conn->AuthStep) {\r
419 case ISCSI_AUTH_INITIAL:\r
420 //\r
421 // It's the initial Login Request. Fill in the key=value pairs mandatory\r
422 // for the initial Login Request.\r
423 //\r
83761337
LE
424 IScsiAddKeyValuePair (\r
425 Pdu,\r
426 ISCSI_KEY_INITIATOR_NAME,\r
427 mPrivate->InitiatorName\r
428 );\r
4c5a5e0c 429 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_SESSION_TYPE, "Normal");\r
430 IScsiAddKeyValuePair (\r
431 Pdu,\r
432 ISCSI_KEY_TARGET_NAME,\r
433 Session->ConfigData->SessionConfigData.TargetName\r
434 );\r
435\r
436 if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) {\r
437 Value = ISCSI_KEY_VALUE_NONE;\r
438 ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
439 } else {\r
440 Value = ISCSI_AUTH_METHOD_CHAP;\r
441 }\r
442\r
443 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_AUTH_METHOD, Value);\r
444\r
445 break;\r
446\r
447 case ISCSI_CHAP_STEP_ONE:\r
448 //\r
83761337
LE
449 // First step, send the Login Request with CHAP_A=<A1,A2...> key-value\r
450 // pair.\r
4c5a5e0c 451 //\r
452 AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", ISCSI_CHAP_ALGORITHM_MD5);\r
453 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, ValueStr);\r
454\r
455 Conn->AuthStep = ISCSI_CHAP_STEP_TWO;\r
456 break;\r
457\r
458 case ISCSI_CHAP_STEP_THREE:\r
459 //\r
460 // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or\r
461 // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target authentication is\r
462 // required too.\r
463 //\r
464 // CHAP_N=<N>\r
465 //\r
83761337
LE
466 IScsiAddKeyValuePair (\r
467 Pdu,\r
468 ISCSI_KEY_CHAP_NAME,\r
469 (CHAR8 *) &AuthData->AuthConfig->CHAPName\r
470 );\r
4c5a5e0c 471 //\r
472 // CHAP_R=<R>\r
473 //\r
83761337
LE
474 IScsiBinToHex (\r
475 (UINT8 *) AuthData->CHAPResponse,\r
476 ISCSI_CHAP_RSP_LEN,\r
477 Response,\r
478 &RspLen\r
479 );\r
4c5a5e0c 480 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_RESPONSE, Response);\r
481\r
482 if (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL) {\r
483 //\r
484 // CHAP_I=<I>\r
485 //\r
486 IScsiGenRandom ((UINT8 *) &AuthData->OutIdentifier, 1);\r
487 AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier);\r
488 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr);\r
489 //\r
490 // CHAP_C=<C>\r
491 //\r
492 IScsiGenRandom ((UINT8 *) AuthData->OutChallenge, ISCSI_CHAP_RSP_LEN);\r
493 AuthData->OutChallengeLength = ISCSI_CHAP_RSP_LEN;\r
83761337
LE
494 IScsiBinToHex (\r
495 (UINT8 *) AuthData->OutChallenge,\r
496 ISCSI_CHAP_RSP_LEN,\r
497 Challenge,\r
498 &ChallengeLen\r
499 );\r
4c5a5e0c 500 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_CHALLENGE, Challenge);\r
501\r
502 Conn->AuthStep = ISCSI_CHAP_STEP_FOUR;\r
503 }\r
504 //\r
505 // Set the stage transition flag.\r
506 //\r
507 ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
508 break;\r
509\r
510 default:\r
511 Status = EFI_PROTOCOL_ERROR;\r
512 break;\r
513 }\r
514\r
515 FreePool (Response);\r
516 FreePool (Challenge);\r
517\r
518 return Status;\r
519}\r