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