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