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