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