]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/IScsiDxe/IScsiCHAP.c
NetworkPkg/IScsiDxe: check IScsiHexToBin() return values
[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
95616b86 125 ISCSI_CHAP_RSP_LEN, // ChallengeLength\r
4c5a5e0c 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
b8649cf2
LE
293 Status = IScsiHexToBin (\r
294 (UINT8 *) AuthData->InChallenge,\r
295 &AuthData->InChallengeLength,\r
296 Challenge\r
297 );\r
298 if (EFI_ERROR (Status)) {\r
299 Status = EFI_PROTOCOL_ERROR;\r
300 goto ON_EXIT;\r
301 }\r
4c5a5e0c 302 Status = IScsiCHAPCalculateResponse (\r
303 AuthData->InIdentifier,\r
304 AuthData->AuthConfig->CHAPSecret,\r
305 (UINT32) AsciiStrLen (AuthData->AuthConfig->CHAPSecret),\r
306 AuthData->InChallenge,\r
307 AuthData->InChallengeLength,\r
308 AuthData->CHAPResponse\r
309 );\r
310\r
311 //\r
312 // Transit to next step.\r
313 //\r
314 Conn->AuthStep = ISCSI_CHAP_STEP_THREE;\r
315 break;\r
316\r
317 case ISCSI_CHAP_STEP_THREE:\r
318 //\r
319 // One way CHAP authentication and the target would like to\r
320 // authenticate us.\r
321 //\r
322 Status = EFI_SUCCESS;\r
323 break;\r
324\r
325 case ISCSI_CHAP_STEP_FOUR:\r
326 ASSERT (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL);\r
327 //\r
328 // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.\r
329 //\r
330 Name = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_NAME);\r
331 if (Name == NULL) {\r
332 goto ON_EXIT;\r
333 }\r
334\r
83761337
LE
335 Response = IScsiGetValueByKeyFromList (\r
336 KeyValueList,\r
337 ISCSI_KEY_CHAP_RESPONSE\r
338 );\r
4c5a5e0c 339 if (Response == NULL) {\r
340 goto ON_EXIT;\r
341 }\r
342\r
343 RspLen = ISCSI_CHAP_RSP_LEN;\r
b8649cf2
LE
344 Status = IScsiHexToBin (TargetRsp, &RspLen, Response);\r
345 if (EFI_ERROR (Status) || RspLen != ISCSI_CHAP_RSP_LEN) {\r
346 Status = EFI_PROTOCOL_ERROR;\r
347 goto ON_EXIT;\r
348 }\r
4c5a5e0c 349\r
350 //\r
351 // Check the CHAP Name and Response replied by Target.\r
352 //\r
353 Status = IScsiCHAPAuthTarget (AuthData, TargetRsp);\r
354 break;\r
355\r
356 default:\r
357 break;\r
358 }\r
359\r
360ON_EXIT:\r
361\r
362 if (KeyValueList != NULL) {\r
363 IScsiFreeKeyValueList (KeyValueList);\r
f75a7f56 364 }\r
4c5a5e0c 365\r
366 FreePool (Data);\r
367\r
368 return Status;\r
369}\r
370\r
371\r
372/**\r
373 This function fills the CHAP authentication information into the login PDU\r
374 during the security negotiation stage in the iSCSI connection login.\r
375\r
376 @param[in] Conn The iSCSI connection.\r
377 @param[in, out] Pdu The PDU to send out.\r
378\r
379 @retval EFI_SUCCESS All check passed and the phase-related CHAP\r
83761337
LE
380 authentication info is filled into the iSCSI\r
381 PDU.\r
4c5a5e0c 382 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
383 @retval EFI_PROTOCOL_ERROR Some kind of protocol error occurred.\r
384\r
385**/\r
386EFI_STATUS\r
387IScsiCHAPToSendReq (\r
388 IN ISCSI_CONNECTION *Conn,\r
389 IN OUT NET_BUF *Pdu\r
390 )\r
391{\r
392 EFI_STATUS Status;\r
393 ISCSI_SESSION *Session;\r
394 ISCSI_LOGIN_REQUEST *LoginReq;\r
395 ISCSI_CHAP_AUTH_DATA *AuthData;\r
396 CHAR8 *Value;\r
397 CHAR8 ValueStr[256];\r
398 CHAR8 *Response;\r
399 UINT32 RspLen;\r
400 CHAR8 *Challenge;\r
401 UINT32 ChallengeLen;\r
d90fff40 402 EFI_STATUS BinToHexStatus;\r
4c5a5e0c 403\r
404 ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
405\r
406 Session = Conn->Session;\r
407 AuthData = &Session->AuthData.CHAP;\r
408 LoginReq = (ISCSI_LOGIN_REQUEST *) NetbufGetByte (Pdu, 0, 0);\r
7a49cd08
ED
409 if (LoginReq == NULL) {\r
410 return EFI_PROTOCOL_ERROR;\r
411 }\r
4c5a5e0c 412 Status = EFI_SUCCESS;\r
413\r
414 RspLen = 2 * ISCSI_CHAP_RSP_LEN + 3;\r
415 Response = AllocateZeroPool (RspLen);\r
416 if (Response == NULL) {\r
417 return EFI_OUT_OF_RESOURCES;\r
418 }\r
419\r
420 ChallengeLen = 2 * ISCSI_CHAP_RSP_LEN + 3;\r
421 Challenge = AllocateZeroPool (ChallengeLen);\r
422 if (Challenge == NULL) {\r
423 FreePool (Response);\r
424 return EFI_OUT_OF_RESOURCES;\r
425 }\r
426\r
427 switch (Conn->AuthStep) {\r
428 case ISCSI_AUTH_INITIAL:\r
429 //\r
430 // It's the initial Login Request. Fill in the key=value pairs mandatory\r
431 // for the initial Login Request.\r
432 //\r
83761337
LE
433 IScsiAddKeyValuePair (\r
434 Pdu,\r
435 ISCSI_KEY_INITIATOR_NAME,\r
436 mPrivate->InitiatorName\r
437 );\r
4c5a5e0c 438 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_SESSION_TYPE, "Normal");\r
439 IScsiAddKeyValuePair (\r
440 Pdu,\r
441 ISCSI_KEY_TARGET_NAME,\r
442 Session->ConfigData->SessionConfigData.TargetName\r
443 );\r
444\r
445 if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) {\r
446 Value = ISCSI_KEY_VALUE_NONE;\r
447 ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
448 } else {\r
449 Value = ISCSI_AUTH_METHOD_CHAP;\r
450 }\r
451\r
452 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_AUTH_METHOD, Value);\r
453\r
454 break;\r
455\r
456 case ISCSI_CHAP_STEP_ONE:\r
457 //\r
83761337
LE
458 // First step, send the Login Request with CHAP_A=<A1,A2...> key-value\r
459 // pair.\r
4c5a5e0c 460 //\r
461 AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", ISCSI_CHAP_ALGORITHM_MD5);\r
462 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, ValueStr);\r
463\r
464 Conn->AuthStep = ISCSI_CHAP_STEP_TWO;\r
465 break;\r
466\r
467 case ISCSI_CHAP_STEP_THREE:\r
468 //\r
469 // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or\r
470 // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target authentication is\r
471 // required too.\r
472 //\r
473 // CHAP_N=<N>\r
474 //\r
83761337
LE
475 IScsiAddKeyValuePair (\r
476 Pdu,\r
477 ISCSI_KEY_CHAP_NAME,\r
478 (CHAR8 *) &AuthData->AuthConfig->CHAPName\r
479 );\r
4c5a5e0c 480 //\r
481 // CHAP_R=<R>\r
482 //\r
d90fff40
LE
483 BinToHexStatus = IScsiBinToHex (\r
484 (UINT8 *) AuthData->CHAPResponse,\r
485 ISCSI_CHAP_RSP_LEN,\r
486 Response,\r
487 &RspLen\r
488 );\r
489 ASSERT_EFI_ERROR (BinToHexStatus);\r
4c5a5e0c 490 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_RESPONSE, Response);\r
491\r
492 if (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL) {\r
493 //\r
494 // CHAP_I=<I>\r
495 //\r
496 IScsiGenRandom ((UINT8 *) &AuthData->OutIdentifier, 1);\r
497 AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier);\r
498 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr);\r
499 //\r
500 // CHAP_C=<C>\r
501 //\r
502 IScsiGenRandom ((UINT8 *) AuthData->OutChallenge, ISCSI_CHAP_RSP_LEN);\r
d90fff40
LE
503 BinToHexStatus = IScsiBinToHex (\r
504 (UINT8 *) AuthData->OutChallenge,\r
505 ISCSI_CHAP_RSP_LEN,\r
506 Challenge,\r
507 &ChallengeLen\r
508 );\r
509 ASSERT_EFI_ERROR (BinToHexStatus);\r
4c5a5e0c 510 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_CHALLENGE, Challenge);\r
511\r
512 Conn->AuthStep = ISCSI_CHAP_STEP_FOUR;\r
513 }\r
514 //\r
515 // Set the stage transition flag.\r
516 //\r
517 ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
518 break;\r
519\r
520 default:\r
521 Status = EFI_PROTOCOL_ERROR;\r
522 break;\r
523 }\r
524\r
525 FreePool (Response);\r
526 FreePool (Challenge);\r
527\r
528 return Status;\r
529}\r