]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/IScsiDxe/IScsiCHAP.c
NetworkPkg/IScsiDxe: support SHA256 in CHAP
[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
903ce1d8
LE
12//\r
13// Supported CHAP hash algorithms, mapped to sets of BaseCryptLib APIs and\r
14// macros. CHAP_HASH structures at lower subscripts in the array are preferred\r
15// by the initiator.\r
16//\r
17STATIC CONST CHAP_HASH mChapHash[] = {\r
47fea2ab
LE
18 {\r
19 ISCSI_CHAP_ALGORITHM_SHA256,\r
20 SHA256_DIGEST_SIZE,\r
21 Sha256GetContextSize,\r
22 Sha256Init,\r
23 Sha256Update,\r
24 Sha256Final\r
25 },\r
26 //\r
27 // Keep the deprecated MD5 entry at the end of the array (making MD5 the\r
28 // least preferred choice of the initiator).\r
29 //\r
903ce1d8
LE
30 {\r
31 ISCSI_CHAP_ALGORITHM_MD5,\r
32 MD5_DIGEST_SIZE,\r
33 Md5GetContextSize,\r
34 Md5Init,\r
35 Md5Update,\r
36 Md5Final\r
37 },\r
38};\r
39\r
40//\r
41// Ordered list of mChapHash[*].Algorithm values. It is formatted for the\r
42// CHAP_A=<A1,A2...> value string, by the IScsiCHAPInitHashList() function. It\r
43// is sent by the initiator in ISCSI_CHAP_STEP_ONE.\r
44//\r
45STATIC CHAR8 mChapHashListString[\r
46 3 + // UINT8 identifier in\r
47 // decimal\r
48 (1 + 3) * (ARRAY_SIZE (mChapHash) - 1) + // comma prepended for\r
49 // entries after the\r
50 // first\r
51 1 + // extra character for\r
52 // AsciiSPrint()\r
53 // truncation check\r
54 1 // terminating NUL\r
55 ];\r
56\r
4c5a5e0c 57/**\r
efb56593 58 Initiator calculates its own expected hash value.\r
f75a7f56 59\r
4c5a5e0c 60 @param[in] ChapIdentifier iSCSI CHAP identifier sent by authenticator.\r
61 @param[in] ChapSecret iSCSI CHAP secret of the authenticator.\r
62 @param[in] SecretLength The length of iSCSI CHAP secret.\r
63 @param[in] ChapChallenge The challenge message sent by authenticator.\r
64 @param[in] ChallengeLength The length of iSCSI CHAP challenge message.\r
903ce1d8
LE
65 @param[in] Hash Pointer to the CHAP_HASH structure that\r
66 determines the hashing algorithm to use. The\r
67 caller is responsible for making Hash point\r
68 to an "mChapHash" element.\r
4c5a5e0c 69 @param[out] ChapResponse The calculation of the expected hash value.\r
f75a7f56 70\r
83761337
LE
71 @retval EFI_SUCCESS The expected hash value was calculatedly\r
72 successfully.\r
73 @retval EFI_PROTOCOL_ERROR The length of the secret should be at least\r
74 the length of the hash value for the hashing\r
75 algorithm chosen.\r
903ce1d8
LE
76 @retval EFI_PROTOCOL_ERROR Hash operation fails.\r
77 @retval EFI_OUT_OF_RESOURCES Failure to allocate resource to complete\r
78 hashing.\r
4c5a5e0c 79\r
80**/\r
81EFI_STATUS\r
82IScsiCHAPCalculateResponse (\r
7eba9f69
LE
83 IN UINT32 ChapIdentifier,\r
84 IN CHAR8 *ChapSecret,\r
85 IN UINT32 SecretLength,\r
86 IN UINT8 *ChapChallenge,\r
87 IN UINT32 ChallengeLength,\r
903ce1d8 88 IN CONST CHAP_HASH *Hash,\r
7eba9f69 89 OUT UINT8 *ChapResponse\r
4c5a5e0c 90 )\r
91{\r
903ce1d8
LE
92 UINTN ContextSize;\r
93 VOID *Ctx;\r
4c5a5e0c 94 CHAR8 IdByte[1];\r
95 EFI_STATUS Status;\r
96\r
97 if (SecretLength < ISCSI_CHAP_SECRET_MIN_LEN) {\r
98 return EFI_PROTOCOL_ERROR;\r
99 }\r
100\r
903ce1d8
LE
101 ASSERT (Hash != NULL);\r
102\r
103 ContextSize = Hash->GetContextSize ();\r
104 Ctx = AllocatePool (ContextSize);\r
105 if (Ctx == NULL) {\r
4c5a5e0c 106 return EFI_OUT_OF_RESOURCES;\r
107 }\r
108\r
109 Status = EFI_PROTOCOL_ERROR;\r
110\r
903ce1d8 111 if (!Hash->Init (Ctx)) {\r
4c5a5e0c 112 goto Exit;\r
113 }\r
114\r
115 //\r
116 // Hash Identifier - Only calculate 1 byte data (RFC1994)\r
117 //\r
118 IdByte[0] = (CHAR8) ChapIdentifier;\r
903ce1d8 119 if (!Hash->Update (Ctx, IdByte, 1)) {\r
4c5a5e0c 120 goto Exit;\r
121 }\r
122\r
123 //\r
124 // Hash Secret\r
125 //\r
903ce1d8 126 if (!Hash->Update (Ctx, ChapSecret, SecretLength)) {\r
4c5a5e0c 127 goto Exit;\r
128 }\r
129\r
130 //\r
131 // Hash Challenge received from Target\r
132 //\r
903ce1d8 133 if (!Hash->Update (Ctx, ChapChallenge, ChallengeLength)) {\r
4c5a5e0c 134 goto Exit;\r
135 }\r
136\r
903ce1d8 137 if (Hash->Final (Ctx, ChapResponse)) {\r
4c5a5e0c 138 Status = EFI_SUCCESS;\r
139 }\r
140\r
141Exit:\r
903ce1d8 142 FreePool (Ctx);\r
4c5a5e0c 143 return Status;\r
144}\r
145\r
146/**\r
efb56593 147 The initiator checks the CHAP response replied by target against its own\r
f75a7f56
LG
148 calculation of the expected hash value.\r
149\r
150 @param[in] AuthData iSCSI CHAP authentication data.\r
151 @param[in] TargetResponse The response from target.\r
4c5a5e0c 152\r
83761337
LE
153 @retval EFI_SUCCESS The response from target passed\r
154 authentication.\r
155 @retval EFI_SECURITY_VIOLATION The response from target was not expected\r
156 value.\r
4c5a5e0c 157 @retval Others Other errors as indicated.\r
158\r
159**/\r
160EFI_STATUS\r
161IScsiCHAPAuthTarget (\r
162 IN ISCSI_CHAP_AUTH_DATA *AuthData,\r
163 IN UINT8 *TargetResponse\r
164 )\r
165{\r
166 EFI_STATUS Status;\r
167 UINT32 SecretSize;\r
7b6c2b2a 168 UINT8 VerifyRsp[ISCSI_CHAP_MAX_DIGEST_SIZE];\r
903ce1d8 169 INTN Mismatch;\r
4c5a5e0c 170\r
171 Status = EFI_SUCCESS;\r
172\r
173 SecretSize = (UINT32) AsciiStrLen (AuthData->AuthConfig->ReverseCHAPSecret);\r
903ce1d8
LE
174\r
175 ASSERT (AuthData->Hash != NULL);\r
176\r
4c5a5e0c 177 Status = IScsiCHAPCalculateResponse (\r
178 AuthData->OutIdentifier,\r
179 AuthData->AuthConfig->ReverseCHAPSecret,\r
180 SecretSize,\r
181 AuthData->OutChallenge,\r
903ce1d8
LE
182 AuthData->Hash->DigestSize, // ChallengeLength\r
183 AuthData->Hash,\r
4c5a5e0c 184 VerifyRsp\r
185 );\r
186\r
903ce1d8
LE
187 Mismatch = CompareMem (\r
188 VerifyRsp,\r
189 TargetResponse,\r
190 AuthData->Hash->DigestSize\r
191 );\r
192 if (Mismatch != 0) {\r
4c5a5e0c 193 Status = EFI_SECURITY_VIOLATION;\r
194 }\r
195\r
196 return Status;\r
197}\r
198\r
199\r
200/**\r
201 This function checks the received iSCSI Login Response during the security\r
202 negotiation stage.\r
203\r
204 @param[in] Conn The iSCSI connection.\r
205\r
206 @retval EFI_SUCCESS The Login Response passed the CHAP validation.\r
207 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
208 @retval EFI_PROTOCOL_ERROR Some kind of protocol error occurred.\r
209 @retval Others Other errors as indicated.\r
210\r
211**/\r
212EFI_STATUS\r
213IScsiCHAPOnRspReceived (\r
214 IN ISCSI_CONNECTION *Conn\r
215 )\r
216{\r
217 EFI_STATUS Status;\r
218 ISCSI_SESSION *Session;\r
219 ISCSI_CHAP_AUTH_DATA *AuthData;\r
220 CHAR8 *Value;\r
221 UINT8 *Data;\r
222 UINT32 Len;\r
223 LIST_ENTRY *KeyValueList;\r
224 UINTN Algorithm;\r
225 CHAR8 *Identifier;\r
226 CHAR8 *Challenge;\r
227 CHAR8 *Name;\r
228 CHAR8 *Response;\r
7b6c2b2a 229 UINT8 TargetRsp[ISCSI_CHAP_MAX_DIGEST_SIZE];\r
4c5a5e0c 230 UINT32 RspLen;\r
231 UINTN Result;\r
903ce1d8 232 UINTN HashIndex;\r
4c5a5e0c 233\r
234 ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
235 ASSERT (Conn->RspQue.BufNum != 0);\r
236\r
237 Session = Conn->Session;\r
238 AuthData = &Session->AuthData.CHAP;\r
239 Len = Conn->RspQue.BufSize;\r
240 Data = AllocateZeroPool (Len);\r
241 if (Data == NULL) {\r
242 return EFI_OUT_OF_RESOURCES;\r
243 }\r
244 //\r
245 // Copy the data in case the data spans over multiple PDUs.\r
246 //\r
247 NetbufQueCopy (&Conn->RspQue, 0, Len, Data);\r
248\r
249 //\r
250 // Build the key-value list from the data segment of the Login Response.\r
251 //\r
252 KeyValueList = IScsiBuildKeyValueList ((CHAR8 *) Data, Len);\r
253 if (KeyValueList == NULL) {\r
254 Status = EFI_OUT_OF_RESOURCES;\r
255 goto ON_EXIT;\r
256 }\r
257\r
258 Status = EFI_PROTOCOL_ERROR;\r
259\r
260 switch (Conn->AuthStep) {\r
261 case ISCSI_AUTH_INITIAL:\r
262 //\r
263 // The first Login Response.\r
264 //\r
83761337
LE
265 Value = IScsiGetValueByKeyFromList (\r
266 KeyValueList,\r
267 ISCSI_KEY_TARGET_PORTAL_GROUP_TAG\r
268 );\r
4c5a5e0c 269 if (Value == NULL) {\r
270 goto ON_EXIT;\r
271 }\r
272\r
273 Result = IScsiNetNtoi (Value);\r
274 if (Result > 0xFFFF) {\r
275 goto ON_EXIT;\r
276 }\r
277\r
278 Session->TargetPortalGroupTag = (UINT16) Result;\r
279\r
83761337
LE
280 Value = IScsiGetValueByKeyFromList (\r
281 KeyValueList,\r
282 ISCSI_KEY_AUTH_METHOD\r
283 );\r
4c5a5e0c 284 if (Value == NULL) {\r
285 goto ON_EXIT;\r
286 }\r
287 //\r
83761337
LE
288 // Initiator mandates CHAP authentication but target replies without\r
289 // "CHAP", or initiator suggets "None" but target replies with some kind of\r
290 // auth method.\r
4c5a5e0c 291 //\r
292 if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) {\r
293 if (AsciiStrCmp (Value, ISCSI_KEY_VALUE_NONE) != 0) {\r
294 goto ON_EXIT;\r
295 }\r
296 } else if (Session->AuthType == ISCSI_AUTH_TYPE_CHAP) {\r
297 if (AsciiStrCmp (Value, ISCSI_AUTH_METHOD_CHAP) != 0) {\r
298 goto ON_EXIT;\r
299 }\r
300 } else {\r
301 goto ON_EXIT;\r
302 }\r
303\r
304 //\r
305 // Transit to CHAP step one.\r
306 //\r
307 Conn->AuthStep = ISCSI_CHAP_STEP_ONE;\r
308 Status = EFI_SUCCESS;\r
309 break;\r
310\r
311 case ISCSI_CHAP_STEP_TWO:\r
312 //\r
313 // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>\r
314 //\r
83761337
LE
315 Value = IScsiGetValueByKeyFromList (\r
316 KeyValueList,\r
317 ISCSI_KEY_CHAP_ALGORITHM\r
318 );\r
4c5a5e0c 319 if (Value == NULL) {\r
320 goto ON_EXIT;\r
321 }\r
322\r
323 Algorithm = IScsiNetNtoi (Value);\r
903ce1d8
LE
324 for (HashIndex = 0; HashIndex < ARRAY_SIZE (mChapHash); HashIndex++) {\r
325 if (Algorithm == mChapHash[HashIndex].Algorithm) {\r
326 break;\r
327 }\r
328 }\r
329 if (HashIndex == ARRAY_SIZE (mChapHash)) {\r
4c5a5e0c 330 //\r
331 // Unsupported algorithm is chosen by target.\r
332 //\r
333 goto ON_EXIT;\r
334 }\r
903ce1d8
LE
335 //\r
336 // Remember the target's chosen hash algorithm.\r
337 //\r
338 ASSERT (AuthData->Hash == NULL);\r
339 AuthData->Hash = &mChapHash[HashIndex];\r
4c5a5e0c 340\r
83761337
LE
341 Identifier = IScsiGetValueByKeyFromList (\r
342 KeyValueList,\r
343 ISCSI_KEY_CHAP_IDENTIFIER\r
344 );\r
4c5a5e0c 345 if (Identifier == NULL) {\r
346 goto ON_EXIT;\r
347 }\r
348\r
83761337
LE
349 Challenge = IScsiGetValueByKeyFromList (\r
350 KeyValueList,\r
351 ISCSI_KEY_CHAP_CHALLENGE\r
352 );\r
4c5a5e0c 353 if (Challenge == NULL) {\r
354 goto ON_EXIT;\r
355 }\r
356 //\r
357 // Process the CHAP identifier and CHAP Challenge from Target.\r
358 // Calculate Response value.\r
f75a7f56 359 //\r
4c5a5e0c 360 Result = IScsiNetNtoi (Identifier);\r
361 if (Result > 0xFF) {\r
362 goto ON_EXIT;\r
f75a7f56
LG
363 }\r
364\r
4c5a5e0c 365 AuthData->InIdentifier = (UINT32) Result;\r
29cab43b 366 AuthData->InChallengeLength = (UINT32) sizeof (AuthData->InChallenge);\r
b8649cf2
LE
367 Status = IScsiHexToBin (\r
368 (UINT8 *) AuthData->InChallenge,\r
369 &AuthData->InChallengeLength,\r
370 Challenge\r
371 );\r
372 if (EFI_ERROR (Status)) {\r
373 Status = EFI_PROTOCOL_ERROR;\r
374 goto ON_EXIT;\r
375 }\r
4c5a5e0c 376 Status = IScsiCHAPCalculateResponse (\r
377 AuthData->InIdentifier,\r
378 AuthData->AuthConfig->CHAPSecret,\r
379 (UINT32) AsciiStrLen (AuthData->AuthConfig->CHAPSecret),\r
380 AuthData->InChallenge,\r
381 AuthData->InChallengeLength,\r
903ce1d8 382 AuthData->Hash,\r
4c5a5e0c 383 AuthData->CHAPResponse\r
384 );\r
385\r
386 //\r
387 // Transit to next step.\r
388 //\r
389 Conn->AuthStep = ISCSI_CHAP_STEP_THREE;\r
390 break;\r
391\r
392 case ISCSI_CHAP_STEP_THREE:\r
393 //\r
394 // One way CHAP authentication and the target would like to\r
395 // authenticate us.\r
396 //\r
397 Status = EFI_SUCCESS;\r
398 break;\r
399\r
400 case ISCSI_CHAP_STEP_FOUR:\r
401 ASSERT (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL);\r
402 //\r
403 // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.\r
404 //\r
405 Name = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_NAME);\r
406 if (Name == NULL) {\r
407 goto ON_EXIT;\r
408 }\r
409\r
83761337
LE
410 Response = IScsiGetValueByKeyFromList (\r
411 KeyValueList,\r
412 ISCSI_KEY_CHAP_RESPONSE\r
413 );\r
4c5a5e0c 414 if (Response == NULL) {\r
415 goto ON_EXIT;\r
416 }\r
417\r
903ce1d8
LE
418 ASSERT (AuthData->Hash != NULL);\r
419 RspLen = AuthData->Hash->DigestSize;\r
b8649cf2 420 Status = IScsiHexToBin (TargetRsp, &RspLen, Response);\r
903ce1d8 421 if (EFI_ERROR (Status) || RspLen != AuthData->Hash->DigestSize) {\r
b8649cf2
LE
422 Status = EFI_PROTOCOL_ERROR;\r
423 goto ON_EXIT;\r
424 }\r
4c5a5e0c 425\r
426 //\r
427 // Check the CHAP Name and Response replied by Target.\r
428 //\r
429 Status = IScsiCHAPAuthTarget (AuthData, TargetRsp);\r
430 break;\r
431\r
432 default:\r
433 break;\r
434 }\r
435\r
436ON_EXIT:\r
437\r
438 if (KeyValueList != NULL) {\r
439 IScsiFreeKeyValueList (KeyValueList);\r
f75a7f56 440 }\r
4c5a5e0c 441\r
442 FreePool (Data);\r
443\r
444 return Status;\r
445}\r
446\r
447\r
448/**\r
449 This function fills the CHAP authentication information into the login PDU\r
450 during the security negotiation stage in the iSCSI connection login.\r
451\r
452 @param[in] Conn The iSCSI connection.\r
453 @param[in, out] Pdu The PDU to send out.\r
454\r
455 @retval EFI_SUCCESS All check passed and the phase-related CHAP\r
83761337
LE
456 authentication info is filled into the iSCSI\r
457 PDU.\r
4c5a5e0c 458 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
459 @retval EFI_PROTOCOL_ERROR Some kind of protocol error occurred.\r
460\r
461**/\r
462EFI_STATUS\r
463IScsiCHAPToSendReq (\r
464 IN ISCSI_CONNECTION *Conn,\r
465 IN OUT NET_BUF *Pdu\r
466 )\r
467{\r
468 EFI_STATUS Status;\r
469 ISCSI_SESSION *Session;\r
470 ISCSI_LOGIN_REQUEST *LoginReq;\r
471 ISCSI_CHAP_AUTH_DATA *AuthData;\r
472 CHAR8 *Value;\r
473 CHAR8 ValueStr[256];\r
474 CHAR8 *Response;\r
475 UINT32 RspLen;\r
476 CHAR8 *Challenge;\r
477 UINT32 ChallengeLen;\r
d90fff40 478 EFI_STATUS BinToHexStatus;\r
4c5a5e0c 479\r
480 ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
481\r
482 Session = Conn->Session;\r
483 AuthData = &Session->AuthData.CHAP;\r
484 LoginReq = (ISCSI_LOGIN_REQUEST *) NetbufGetByte (Pdu, 0, 0);\r
7a49cd08
ED
485 if (LoginReq == NULL) {\r
486 return EFI_PROTOCOL_ERROR;\r
487 }\r
4c5a5e0c 488 Status = EFI_SUCCESS;\r
489\r
7b6c2b2a 490 RspLen = 2 * ISCSI_CHAP_MAX_DIGEST_SIZE + 3;\r
4c5a5e0c 491 Response = AllocateZeroPool (RspLen);\r
492 if (Response == NULL) {\r
493 return EFI_OUT_OF_RESOURCES;\r
494 }\r
495\r
7b6c2b2a 496 ChallengeLen = 2 * ISCSI_CHAP_MAX_DIGEST_SIZE + 3;\r
4c5a5e0c 497 Challenge = AllocateZeroPool (ChallengeLen);\r
498 if (Challenge == NULL) {\r
499 FreePool (Response);\r
500 return EFI_OUT_OF_RESOURCES;\r
501 }\r
502\r
503 switch (Conn->AuthStep) {\r
504 case ISCSI_AUTH_INITIAL:\r
505 //\r
506 // It's the initial Login Request. Fill in the key=value pairs mandatory\r
507 // for the initial Login Request.\r
508 //\r
83761337
LE
509 IScsiAddKeyValuePair (\r
510 Pdu,\r
511 ISCSI_KEY_INITIATOR_NAME,\r
512 mPrivate->InitiatorName\r
513 );\r
4c5a5e0c 514 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_SESSION_TYPE, "Normal");\r
515 IScsiAddKeyValuePair (\r
516 Pdu,\r
517 ISCSI_KEY_TARGET_NAME,\r
518 Session->ConfigData->SessionConfigData.TargetName\r
519 );\r
520\r
521 if (Session->AuthType == ISCSI_AUTH_TYPE_NONE) {\r
522 Value = ISCSI_KEY_VALUE_NONE;\r
523 ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
524 } else {\r
525 Value = ISCSI_AUTH_METHOD_CHAP;\r
526 }\r
527\r
528 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_AUTH_METHOD, Value);\r
529\r
530 break;\r
531\r
532 case ISCSI_CHAP_STEP_ONE:\r
533 //\r
83761337
LE
534 // First step, send the Login Request with CHAP_A=<A1,A2...> key-value\r
535 // pair.\r
4c5a5e0c 536 //\r
903ce1d8 537 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, mChapHashListString);\r
4c5a5e0c 538\r
539 Conn->AuthStep = ISCSI_CHAP_STEP_TWO;\r
540 break;\r
541\r
542 case ISCSI_CHAP_STEP_THREE:\r
543 //\r
544 // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or\r
545 // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target authentication is\r
546 // required too.\r
547 //\r
548 // CHAP_N=<N>\r
549 //\r
83761337
LE
550 IScsiAddKeyValuePair (\r
551 Pdu,\r
552 ISCSI_KEY_CHAP_NAME,\r
553 (CHAR8 *) &AuthData->AuthConfig->CHAPName\r
554 );\r
4c5a5e0c 555 //\r
556 // CHAP_R=<R>\r
557 //\r
903ce1d8 558 ASSERT (AuthData->Hash != NULL);\r
d90fff40
LE
559 BinToHexStatus = IScsiBinToHex (\r
560 (UINT8 *) AuthData->CHAPResponse,\r
903ce1d8 561 AuthData->Hash->DigestSize,\r
d90fff40
LE
562 Response,\r
563 &RspLen\r
564 );\r
565 ASSERT_EFI_ERROR (BinToHexStatus);\r
4c5a5e0c 566 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_RESPONSE, Response);\r
567\r
568 if (AuthData->AuthConfig->CHAPType == ISCSI_CHAP_MUTUAL) {\r
569 //\r
570 // CHAP_I=<I>\r
571 //\r
572 IScsiGenRandom ((UINT8 *) &AuthData->OutIdentifier, 1);\r
573 AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier);\r
574 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr);\r
575 //\r
576 // CHAP_C=<C>\r
577 //\r
903ce1d8
LE
578 IScsiGenRandom (\r
579 (UINT8 *) AuthData->OutChallenge,\r
580 AuthData->Hash->DigestSize\r
581 );\r
d90fff40
LE
582 BinToHexStatus = IScsiBinToHex (\r
583 (UINT8 *) AuthData->OutChallenge,\r
903ce1d8 584 AuthData->Hash->DigestSize,\r
d90fff40
LE
585 Challenge,\r
586 &ChallengeLen\r
587 );\r
588 ASSERT_EFI_ERROR (BinToHexStatus);\r
4c5a5e0c 589 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_CHALLENGE, Challenge);\r
590\r
591 Conn->AuthStep = ISCSI_CHAP_STEP_FOUR;\r
592 }\r
593 //\r
594 // Set the stage transition flag.\r
595 //\r
596 ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
597 break;\r
598\r
599 default:\r
600 Status = EFI_PROTOCOL_ERROR;\r
601 break;\r
602 }\r
603\r
604 FreePool (Response);\r
605 FreePool (Challenge);\r
606\r
607 return Status;\r
608}\r
903ce1d8
LE
609\r
610/**\r
611 Initialize the CHAP_A=<A1,A2...> *value* string for the entire driver, to be\r
612 sent by the initiator in ISCSI_CHAP_STEP_ONE.\r
613\r
614 This function sanity-checks the internal table of supported CHAP hashing\r
615 algorithms, as well.\r
616**/\r
617VOID\r
618IScsiCHAPInitHashList (\r
619 VOID\r
620 )\r
621{\r
622 CHAR8 *Position;\r
623 UINTN Left;\r
624 UINTN HashIndex;\r
625 CONST CHAP_HASH *Hash;\r
626 UINTN Printed;\r
627\r
628 Position = mChapHashListString;\r
629 Left = sizeof (mChapHashListString);\r
630 for (HashIndex = 0; HashIndex < ARRAY_SIZE (mChapHash); HashIndex++) {\r
631 Hash = &mChapHash[HashIndex];\r
632\r
633 //\r
634 // Format the next hash identifier.\r
635 //\r
636 // Assert that we can format at least one non-NUL character, i.e. that we\r
637 // can progress. Truncation is checked after printing.\r
638 //\r
639 ASSERT (Left >= 2);\r
640 Printed = AsciiSPrint (\r
641 Position,\r
642 Left,\r
643 "%a%d",\r
644 (HashIndex == 0) ? "" : ",",\r
645 Hash->Algorithm\r
646 );\r
647 //\r
648 // There's no way to differentiate between the "buffer filled to the brim,\r
649 // but not truncated" result and the "truncated" result of AsciiSPrint().\r
650 // This is why "mChapHashListString" has an extra byte allocated, and the\r
651 // reason why we use the less-than (rather than the less-than-or-equal-to)\r
652 // relational operator in the assertion below -- we enforce "no truncation"\r
653 // by excluding the "completely used up" case too.\r
654 //\r
655 ASSERT (Printed + 1 < Left);\r
656\r
657 Position += Printed;\r
658 Left -= Printed;\r
659\r
660 //\r
661 // Sanity-check the digest size for Hash.\r
662 //\r
663 ASSERT (Hash->DigestSize <= ISCSI_CHAP_MAX_DIGEST_SIZE);\r
664 }\r
665}\r