]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/Network/IScsiDxe/IScsiCHAP.c
Remove dependency on PCI Root Bridge I/O Protocol. This library should only layer...
[mirror_edk2.git] / MdeModulePkg / Universal / Network / IScsiDxe / IScsiCHAP.c
CommitLineData
12618416 1/** @file\r
11e0ec6b 2 This file is for Challenge-Handshake Authentication Protocol (CHAP) Configuration.\r
3 \r
894d038a 4Copyright (c) 2004 - 2009, Intel Corporation.<BR>\r
7a444476 5All rights reserved. This program and the accompanying materials\r
6are licensed and made available under the terms and conditions of the BSD License\r
7which accompanies this distribution. The full text of the license may be found at\r
8http://opensource.org/licenses/bsd-license.php\r
9\r
10THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
11WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
6a690e23 12\r
12618416 13**/\r
6a690e23 14\r
15#include "IScsiImpl.h"\r
16#include "Md5.h"\r
17\r
18EFI_GUID mIScsiCHAPAuthInfoGuid = ISCSI_CHAP_AUTH_INFO_GUID;\r
19\r
11e0ec6b 20/**\r
21 Initator caculates its own expected hash value. \r
22 \r
55a64ae0 23 @param[in] ChapIdentifier iSCSI CHAP identifier sent by authenticator. \r
24 @param[in] ChapSecret iSCSI CHAP secret of the authenticator. \r
25 @param[in] SecretLength The length of iSCSI CHAP secret.\r
11e0ec6b 26 @param[in] ChapChallenge The challenge message sent by authenticator. \r
55a64ae0 27 @param[in] ChallengeLength The length of iSCSI CHAP challenge message.\r
11e0ec6b 28 @param[out] ChapResponse The calculation of the expected hash value.\r
29 \r
30 @retval EFI_SUCCESS The expected hash value was caculatedly successfully.\r
31 @retval EFI_PROTOCOL_ERROR The length of the secret should be at least the \r
32 length of the hash value for the hashing algorithm chosen.\r
963dbb30 33 @retval Others Other errors as indicated. \r
11e0ec6b 34**/\r
6a690e23 35EFI_STATUS\r
36IScsiCHAPCalculateResponse (\r
37 IN UINT32 ChapIdentifier,\r
38 IN CHAR8 *ChapSecret,\r
39 IN UINT32 SecretLength,\r
40 IN UINT8 *ChapChallenge,\r
41 IN UINT32 ChallengeLength,\r
42 OUT UINT8 *ChapResponse\r
43 )\r
44{\r
45 MD5_CTX Md5Ctx;\r
46 CHAR8 IdByte[1];\r
47 EFI_STATUS Status;\r
48\r
49 Status = MD5Init (&Md5Ctx);\r
50\r
51 //\r
52 // Hash Identifier - Only calculate 1 byte data (RFC1994)\r
53 //\r
54 IdByte[0] = (CHAR8) ChapIdentifier;\r
55 MD5Update (&Md5Ctx, IdByte, 1);\r
56\r
57 //\r
58 // Hash Secret\r
59 //\r
60 if (SecretLength < ISCSI_CHAP_SECRET_MIN_LEN - 1) {\r
61 return EFI_PROTOCOL_ERROR;\r
62 }\r
63\r
64 MD5Update (&Md5Ctx, ChapSecret, SecretLength);\r
65\r
66 //\r
67 // Hash Challenge received from Target\r
68 //\r
69 MD5Update (&Md5Ctx, ChapChallenge, ChallengeLength);\r
70\r
71 Status = MD5Final (&Md5Ctx, ChapResponse);\r
72\r
73 return Status;\r
74}\r
75\r
11e0ec6b 76/**\r
77 The initator checks the CHAP response replied by target against its own\r
78 calculation of the expected hash value. \r
79 \r
55a64ae0 80 @param[in] AuthData iSCSI CHAP authentication data. \r
11e0ec6b 81 @param[in] TargetResponse The response from target. \r
82\r
83 @retval EFI_SUCCESS The response from target passed authentication.\r
84 @retval EFI_SECURITY_VIOLATION The response from target was not expected value.\r
963dbb30 85 @retval Others Other errors as indicated.\r
11e0ec6b 86**/\r
6a690e23 87EFI_STATUS\r
88IScsiCHAPAuthTarget (\r
89 IN ISCSI_CHAP_AUTH_DATA *AuthData,\r
90 IN UINT8 *TargetResponse\r
91 )\r
92{\r
93 EFI_STATUS Status;\r
94 UINT32 SecretSize;\r
95 UINT8 VerifyRsp[ISCSI_CHAP_RSP_LEN];\r
96\r
97 Status = EFI_SUCCESS;\r
98\r
99 SecretSize = (UINT32) AsciiStrLen (AuthData->AuthConfig.ReverseCHAPSecret);\r
100 Status = IScsiCHAPCalculateResponse (\r
101 AuthData->OutIdentifier,\r
102 AuthData->AuthConfig.ReverseCHAPSecret,\r
103 SecretSize,\r
104 AuthData->OutChallenge,\r
105 AuthData->OutChallengeLength,\r
106 VerifyRsp\r
107 );\r
108\r
e48e37fc 109 if (CompareMem (VerifyRsp, TargetResponse, ISCSI_CHAP_RSP_LEN)) {\r
6a690e23 110 Status = EFI_SECURITY_VIOLATION;\r
111 }\r
112\r
113 return Status;\r
114}\r
115\r
12618416 116/**\r
6a690e23 117 This function checks the received iSCSI Login Response during the security\r
118 negotiation stage.\r
119 \r
11e0ec6b 120 @param[in] Conn The iSCSI connection.\r
6a690e23 121\r
12618416 122 @retval EFI_SUCCESS The Login Response passed the CHAP validation.\r
12618416 123 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
12618416 124 @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.\r
963dbb30 125 @retval Others Other errors as indicated.\r
12618416 126**/\r
127EFI_STATUS\r
128IScsiCHAPOnRspReceived (\r
c5de0d55 129 IN ISCSI_CONNECTION *Conn\r
12618416 130 )\r
6a690e23 131{\r
132 EFI_STATUS Status;\r
133 ISCSI_SESSION *Session;\r
6a690e23 134 ISCSI_CHAP_AUTH_DATA *AuthData;\r
135 CHAR8 *Value;\r
136 UINT8 *Data;\r
137 UINT32 Len;\r
e48e37fc 138 LIST_ENTRY *KeyValueList;\r
6a690e23 139 UINTN Algorithm;\r
140 CHAR8 *Identifier;\r
141 CHAR8 *Challenge;\r
142 CHAR8 *Name;\r
143 CHAR8 *Response;\r
144 UINT8 TargetRsp[ISCSI_CHAP_RSP_LEN];\r
145 UINT32 RspLen;\r
146\r
147 ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
148 ASSERT (Conn->RspQue.BufNum != 0);\r
149\r
150 Session = Conn->Session;\r
6a690e23 151 AuthData = &Session->AuthData;\r
152\r
153 Len = Conn->RspQue.BufSize;\r
e48e37fc 154 Data = AllocatePool (Len);\r
6a690e23 155 if (Data == NULL) {\r
156 return EFI_OUT_OF_RESOURCES;\r
157 }\r
158 //\r
159 // Copy the data in case the data spans over multiple PDUs.\r
160 //\r
161 NetbufQueCopy (&Conn->RspQue, 0, Len, Data);\r
162\r
163 //\r
164 // Build the key-value list from the data segment of the Login Response.\r
165 //\r
69b0882d 166 KeyValueList = IScsiBuildKeyValueList ((CHAR8 *) Data, Len);\r
6a690e23 167 if (KeyValueList == NULL) {\r
766c7483 168 FreePool (Data);\r
894d038a 169 return EFI_OUT_OF_RESOURCES;\r
6a690e23 170 }\r
171\r
172 Status = EFI_PROTOCOL_ERROR;\r
173\r
174 switch (Conn->CHAPStep) {\r
175 case ISCSI_CHAP_INITIAL:\r
176 //\r
177 // The first Login Response.\r
178 //\r
179 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG);\r
180 if (Value == NULL) {\r
181 goto ON_EXIT;\r
182 }\r
183\r
184 Session->TargetPortalGroupTag = (UINT16) AsciiStrDecimalToUintn (Value);\r
185\r
186 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_AUTH_METHOD);\r
187 if (Value == NULL) {\r
188 goto ON_EXIT;\r
189 }\r
190 //\r
191 // Initiator mandates CHAP authentication but target replies without "CHAP" or\r
192 // initiator suggets "None" but target replies with some kind of auth method.\r
193 //\r
194 if (AsciiStrCmp (Value, ISCSI_AUTH_METHOD_CHAP) == 0) {\r
195 if (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_NONE) {\r
196 goto ON_EXIT;\r
197 }\r
198 } else {\r
199 if (AuthData->AuthConfig.CHAPType != ISCSI_CHAP_NONE) {\r
200 goto ON_EXIT;\r
201 }\r
202 }\r
203 //\r
204 // Transit to CHAP step one.\r
205 //\r
206 Conn->CHAPStep = ISCSI_CHAP_STEP_ONE;\r
207 Status = EFI_SUCCESS;\r
208 break;\r
209\r
210 case ISCSI_CHAP_STEP_TWO:\r
211 //\r
212 // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>\r
213 //\r
214 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_ALGORITHM);\r
215 if (Value == NULL) {\r
216 goto ON_EXIT;\r
217 }\r
218\r
219 Algorithm = AsciiStrDecimalToUintn (Value);\r
220 if (Algorithm != ISCSI_CHAP_ALGORITHM_MD5) {\r
221 //\r
222 // Unsupported algorithm is chosen by target.\r
223 //\r
224 goto ON_EXIT;\r
225 }\r
226\r
227 Identifier = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_IDENTIFIER);\r
228 if (Identifier == NULL) {\r
229 goto ON_EXIT;\r
230 }\r
231\r
232 Challenge = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_CHALLENGE);\r
233 if (Challenge == NULL) {\r
234 goto ON_EXIT;\r
235 }\r
236 //\r
237 // Process the CHAP identifier and CHAP Challenge from Target\r
238 // Calculate Response value\r
239 //\r
240 AuthData->InIdentifier = (UINT32) AsciiStrDecimalToUintn (Identifier);\r
241 AuthData->InChallengeLength = ISCSI_CHAP_AUTH_MAX_LEN;\r
242 IScsiHexToBin ((UINT8 *) AuthData->InChallenge, &AuthData->InChallengeLength, Challenge);\r
243 Status = IScsiCHAPCalculateResponse (\r
244 AuthData->InIdentifier,\r
245 AuthData->AuthConfig.CHAPSecret,\r
246 (UINT32) AsciiStrLen (AuthData->AuthConfig.CHAPSecret),\r
247 AuthData->InChallenge,\r
248 AuthData->InChallengeLength,\r
249 AuthData->CHAPResponse\r
250 );\r
251\r
252 //\r
253 // Transit to next step.\r
254 //\r
255 Conn->CHAPStep = ISCSI_CHAP_STEP_THREE;\r
256 break;\r
257\r
258 case ISCSI_CHAP_STEP_THREE:\r
259 //\r
260 // one way CHAP authentication and the target would like to\r
261 // authenticate us.\r
262 //\r
263 Status = EFI_SUCCESS;\r
264 break;\r
265\r
266 case ISCSI_CHAP_STEP_FOUR:\r
267 ASSERT (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_MUTUAL);\r
268 //\r
269 // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.\r
270 //\r
271 Name = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_NAME);\r
272 if (Name == NULL) {\r
273 goto ON_EXIT;\r
274 }\r
275\r
276 Response = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_RESPONSE);\r
277 if (Response == NULL) {\r
278 goto ON_EXIT;\r
279 }\r
280\r
281 RspLen = ISCSI_CHAP_RSP_LEN;\r
282 IScsiHexToBin (TargetRsp, &RspLen, Response);\r
283\r
284 //\r
11e0ec6b 285 // Check the CHAP Response replied by Target.\r
6a690e23 286 //\r
287 Status = IScsiCHAPAuthTarget (AuthData, TargetRsp);\r
288 break;\r
289\r
290 default:\r
291 break;\r
292 }\r
293\r
294ON_EXIT:\r
295\r
296 IScsiFreeKeyValueList (KeyValueList);\r
297\r
766c7483 298 FreePool (Data);\r
6a690e23 299\r
300 return Status;\r
301}\r
302\r
12618416 303/**\r
6a690e23 304 This function fills the CHAP authentication information into the login PDU\r
305 during the security negotiation stage in the iSCSI connection login.\r
6a690e23 306\r
c5de0d55 307 @param[in] Conn The iSCSI connection.\r
308 @param[in, out] Pdu The PDU to send out.\r
6a690e23 309\r
12618416 310 @retval EFI_SUCCESS All check passed and the phase-related CHAP\r
311 authentication info is filled into the iSCSI PDU.\r
12618416 312 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
12618416 313 @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.\r
12618416 314**/\r
315EFI_STATUS\r
316IScsiCHAPToSendReq (\r
c5de0d55 317 IN ISCSI_CONNECTION *Conn,\r
318 IN OUT NET_BUF *Pdu\r
12618416 319 )\r
6a690e23 320{\r
321 EFI_STATUS Status;\r
322 ISCSI_SESSION *Session;\r
323 ISCSI_LOGIN_REQUEST *LoginReq;\r
6a690e23 324 ISCSI_CHAP_AUTH_DATA *AuthData;\r
325 CHAR8 *Value;\r
326 CHAR8 ValueStr[256];\r
327 CHAR8 *Response;\r
328 UINT32 RspLen;\r
329 CHAR8 *Challenge;\r
330 UINT32 ChallengeLen;\r
331\r
332 ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
333\r
334 Session = Conn->Session;\r
6a690e23 335 AuthData = &Session->AuthData;\r
336 LoginReq = (ISCSI_LOGIN_REQUEST *) NetbufGetByte (Pdu, 0, 0);\r
337 Status = EFI_SUCCESS;\r
338\r
339 RspLen = 2 * ISCSI_CHAP_RSP_LEN + 3;\r
e48e37fc 340 Response = AllocatePool (RspLen);\r
6a690e23 341 if (Response == NULL) {\r
342 return EFI_OUT_OF_RESOURCES;\r
343 }\r
344\r
345 ChallengeLen = 2 * ISCSI_CHAP_RSP_LEN + 3;\r
e48e37fc 346 Challenge = AllocatePool (ChallengeLen);\r
6a690e23 347 if (Challenge == NULL) {\r
348 return EFI_OUT_OF_RESOURCES;\r
349 }\r
350\r
351 switch (Conn->CHAPStep) {\r
352 case ISCSI_CHAP_INITIAL:\r
353 //\r
354 // It's the initial Login Request. Fill in the key=value pairs mandatory\r
355 // for the initial Login Request.\r
356 //\r
357 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_INITIATOR_NAME, Session->InitiatorName);\r
358 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_SESSION_TYPE, "Normal");\r
359 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_TARGET_NAME, Session->ConfigData.NvData.TargetName);\r
360\r
361 if (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_NONE) {\r
362 Value = ISCSI_KEY_VALUE_NONE;\r
363 ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
364 } else {\r
365 Value = ISCSI_AUTH_METHOD_CHAP;\r
366 }\r
367\r
368 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_AUTH_METHOD, Value);\r
369\r
370 break;\r
371\r
372 case ISCSI_CHAP_STEP_ONE:\r
373 //\r
374 // First step, send the Login Request with CHAP_A=<A1,A2...> key-value pair.\r
375 //\r
376 AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", ISCSI_CHAP_ALGORITHM_MD5);\r
377 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_ALGORITHM, ValueStr);\r
378\r
379 Conn->CHAPStep = ISCSI_CHAP_STEP_TWO;\r
380 break;\r
381\r
382 case ISCSI_CHAP_STEP_THREE:\r
383 //\r
384 // Third step, send the Login Request with CHAP_N=<N> CHAP_R=<R> or\r
385 // CHAP_N=<N> CHAP_R=<R> CHAP_I=<I> CHAP_C=<C> if target ahtentication is\r
386 // required too.\r
387 //\r
388 // CHAP_N=<N>\r
389 //\r
69b0882d 390 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_NAME, (CHAR8 *) &AuthData->AuthConfig.CHAPName);\r
6a690e23 391 //\r
392 // CHAP_R=<R>\r
393 //\r
394 IScsiBinToHex ((UINT8 *) AuthData->CHAPResponse, ISCSI_CHAP_RSP_LEN, Response, &RspLen);\r
395 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_RESPONSE, Response);\r
396\r
397 if (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_MUTUAL) {\r
398 //\r
399 // CHAP_I=<I>\r
400 //\r
401 IScsiGenRandom ((UINT8 *) &AuthData->OutIdentifier, 1);\r
402 AsciiSPrint (ValueStr, sizeof (ValueStr), "%d", AuthData->OutIdentifier);\r
403 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_IDENTIFIER, ValueStr);\r
404 //\r
405 // CHAP_C=<C>\r
406 //\r
407 IScsiGenRandom ((UINT8 *) AuthData->OutChallenge, ISCSI_CHAP_RSP_LEN);\r
408 AuthData->OutChallengeLength = ISCSI_CHAP_RSP_LEN;\r
409 IScsiBinToHex ((UINT8 *) AuthData->OutChallenge, ISCSI_CHAP_RSP_LEN, Challenge, &ChallengeLen);\r
410 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_CHALLENGE, Challenge);\r
411\r
412 Conn->CHAPStep = ISCSI_CHAP_STEP_FOUR;\r
413 }\r
414 //\r
415 // set the stage transition flag.\r
416 //\r
417 ISCSI_SET_FLAG (LoginReq, ISCSI_LOGIN_REQ_PDU_FLAG_TRANSIT);\r
418 break;\r
419\r
420 default:\r
421 Status = EFI_PROTOCOL_ERROR;\r
422 break;\r
423 }\r
424\r
766c7483 425 FreePool (Response);\r
426 FreePool (Challenge);\r
6a690e23 427\r
428 return Status;\r
429}\r