]> git.proxmox.com Git - mirror_edk2.git/blame - MdeModulePkg/Universal/iScsi/IScsiCHAP.c
Suppress the divide-by-zero warning for package validation of MdeModulePkg. The APIs...
[mirror_edk2.git] / MdeModulePkg / Universal / iScsi / IScsiCHAP.c
CommitLineData
6a690e23 1/*++\r
2\r
3Copyright (c) 2007 Intel Corporation. All rights reserved\r
4This software and associated documentation (if any) is furnished\r
5under a license and may only be used or copied in accordance\r
6with the terms of the license. Except as permitted by such\r
7license, no part of this software or documentation may be\r
8reproduced, stored in a retrieval system, or transmitted in any\r
9form or by any means without the express written consent of\r
10Intel Corporation.\r
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
93e3992d 122 ISCSI_SESSION_CONFIG_DATA *ConfigData;\r
6a690e23 123 ISCSI_CHAP_AUTH_DATA *AuthData;\r
124 CHAR8 *Value;\r
125 UINT8 *Data;\r
126 UINT32 Len;\r
127 NET_LIST_ENTRY *KeyValueList;\r
128 UINTN Algorithm;\r
129 CHAR8 *Identifier;\r
130 CHAR8 *Challenge;\r
131 CHAR8 *Name;\r
132 CHAR8 *Response;\r
133 UINT8 TargetRsp[ISCSI_CHAP_RSP_LEN];\r
134 UINT32 RspLen;\r
135\r
136 ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
137 ASSERT (Conn->RspQue.BufNum != 0);\r
138\r
139 Session = Conn->Session;\r
93e3992d 140 ConfigData = &Session->ConfigData;\r
6a690e23 141 AuthData = &Session->AuthData;\r
142\r
143 Len = Conn->RspQue.BufSize;\r
144 Data = NetAllocatePool (Len);\r
145 if (Data == NULL) {\r
146 return EFI_OUT_OF_RESOURCES;\r
147 }\r
148 //\r
149 // Copy the data in case the data spans over multiple PDUs.\r
150 //\r
151 NetbufQueCopy (&Conn->RspQue, 0, Len, Data);\r
152\r
153 //\r
154 // Build the key-value list from the data segment of the Login Response.\r
155 //\r
93e3992d 156 KeyValueList = IScsiBuildKeyValueList (Data, Len);\r
6a690e23 157 if (KeyValueList == NULL) {\r
158 Status = EFI_OUT_OF_RESOURCES;\r
159 goto ON_EXIT;\r
160 }\r
161\r
162 Status = EFI_PROTOCOL_ERROR;\r
163\r
164 switch (Conn->CHAPStep) {\r
165 case ISCSI_CHAP_INITIAL:\r
166 //\r
167 // The first Login Response.\r
168 //\r
169 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_TARGET_PORTAL_GROUP_TAG);\r
170 if (Value == NULL) {\r
171 goto ON_EXIT;\r
172 }\r
173\r
174 Session->TargetPortalGroupTag = (UINT16) AsciiStrDecimalToUintn (Value);\r
175\r
176 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_AUTH_METHOD);\r
177 if (Value == NULL) {\r
178 goto ON_EXIT;\r
179 }\r
180 //\r
181 // Initiator mandates CHAP authentication but target replies without "CHAP" or\r
182 // initiator suggets "None" but target replies with some kind of auth method.\r
183 //\r
184 if (AsciiStrCmp (Value, ISCSI_AUTH_METHOD_CHAP) == 0) {\r
185 if (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_NONE) {\r
186 goto ON_EXIT;\r
187 }\r
188 } else {\r
189 if (AuthData->AuthConfig.CHAPType != ISCSI_CHAP_NONE) {\r
190 goto ON_EXIT;\r
191 }\r
192 }\r
193 //\r
194 // Transit to CHAP step one.\r
195 //\r
196 Conn->CHAPStep = ISCSI_CHAP_STEP_ONE;\r
197 Status = EFI_SUCCESS;\r
198 break;\r
199\r
200 case ISCSI_CHAP_STEP_TWO:\r
201 //\r
202 // The Target replies with CHAP_A=<A> CHAP_I=<I> CHAP_C=<C>\r
203 //\r
204 Value = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_ALGORITHM);\r
205 if (Value == NULL) {\r
206 goto ON_EXIT;\r
207 }\r
208\r
209 Algorithm = AsciiStrDecimalToUintn (Value);\r
210 if (Algorithm != ISCSI_CHAP_ALGORITHM_MD5) {\r
211 //\r
212 // Unsupported algorithm is chosen by target.\r
213 //\r
214 goto ON_EXIT;\r
215 }\r
216\r
217 Identifier = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_IDENTIFIER);\r
218 if (Identifier == NULL) {\r
219 goto ON_EXIT;\r
220 }\r
221\r
222 Challenge = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_CHALLENGE);\r
223 if (Challenge == NULL) {\r
224 goto ON_EXIT;\r
225 }\r
226 //\r
227 // Process the CHAP identifier and CHAP Challenge from Target\r
228 // Calculate Response value\r
229 //\r
230 AuthData->InIdentifier = (UINT32) AsciiStrDecimalToUintn (Identifier);\r
231 AuthData->InChallengeLength = ISCSI_CHAP_AUTH_MAX_LEN;\r
232 IScsiHexToBin ((UINT8 *) AuthData->InChallenge, &AuthData->InChallengeLength, Challenge);\r
233 Status = IScsiCHAPCalculateResponse (\r
234 AuthData->InIdentifier,\r
235 AuthData->AuthConfig.CHAPSecret,\r
236 (UINT32) AsciiStrLen (AuthData->AuthConfig.CHAPSecret),\r
237 AuthData->InChallenge,\r
238 AuthData->InChallengeLength,\r
239 AuthData->CHAPResponse\r
240 );\r
241\r
242 //\r
243 // Transit to next step.\r
244 //\r
245 Conn->CHAPStep = ISCSI_CHAP_STEP_THREE;\r
246 break;\r
247\r
248 case ISCSI_CHAP_STEP_THREE:\r
249 //\r
250 // one way CHAP authentication and the target would like to\r
251 // authenticate us.\r
252 //\r
253 Status = EFI_SUCCESS;\r
254 break;\r
255\r
256 case ISCSI_CHAP_STEP_FOUR:\r
257 ASSERT (AuthData->AuthConfig.CHAPType == ISCSI_CHAP_MUTUAL);\r
258 //\r
259 // The forth step, CHAP_N=<N> CHAP_R=<R> is received from Target.\r
260 //\r
261 Name = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_NAME);\r
262 if (Name == NULL) {\r
263 goto ON_EXIT;\r
264 }\r
265\r
266 Response = IScsiGetValueByKeyFromList (KeyValueList, ISCSI_KEY_CHAP_RESPONSE);\r
267 if (Response == NULL) {\r
268 goto ON_EXIT;\r
269 }\r
270\r
271 RspLen = ISCSI_CHAP_RSP_LEN;\r
272 IScsiHexToBin (TargetRsp, &RspLen, Response);\r
273\r
274 //\r
275 // Check the CHAP Name and Response replied by Target.\r
276 //\r
277 Status = IScsiCHAPAuthTarget (AuthData, TargetRsp);\r
278 break;\r
279\r
280 default:\r
281 break;\r
282 }\r
283\r
284ON_EXIT:\r
285\r
286 IScsiFreeKeyValueList (KeyValueList);\r
287\r
288 NetFreePool (Data);\r
289\r
290 return Status;\r
291}\r
292\r
293EFI_STATUS\r
294IScsiCHAPToSendReq (\r
295 IN ISCSI_CONNECTION *Conn,\r
296 IN NET_BUF *Pdu\r
297 )\r
298/*++\r
299\r
300Routine Description:\r
301\r
302 This function fills the CHAP authentication information into the login PDU\r
303 during the security negotiation stage in the iSCSI connection login.\r
304 \r
305Arguments:\r
306\r
307 Conn - The iSCSI connection.\r
308 Pdu - The PDU to send out.\r
309\r
310Returns:\r
311\r
312 EFI_SUCCESS - All check passed and the phase-related CHAP authentication\r
313 info is filled into the iSCSI PDU.\r
314 EFI_OUT_OF_RESOURCES - Failed to allocate memory.\r
315 EFI_PROTOCOL_ERROR - Some kind of protocol error happend.\r
316\r
317--*/\r
318{\r
319 EFI_STATUS Status;\r
320 ISCSI_SESSION *Session;\r
321 ISCSI_LOGIN_REQUEST *LoginReq;\r
93e3992d 322 ISCSI_SESSION_CONFIG_DATA *ConfigData;\r
6a690e23 323 ISCSI_CHAP_AUTH_DATA *AuthData;\r
324 CHAR8 *Value;\r
325 CHAR8 ValueStr[256];\r
326 CHAR8 *Response;\r
327 UINT32 RspLen;\r
328 CHAR8 *Challenge;\r
329 UINT32 ChallengeLen;\r
330\r
331 ASSERT (Conn->CurrentStage == ISCSI_SECURITY_NEGOTIATION);\r
332\r
333 Session = Conn->Session;\r
93e3992d 334 ConfigData = &Session->ConfigData;\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
340 Response = NetAllocatePool (RspLen);\r
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
346 Challenge = NetAllocatePool (ChallengeLen);\r
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
93e3992d 390 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_NAME, (UINT8 *) &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
425 NetFreePool (Response);\r
426 NetFreePool (Challenge);\r
427\r
428 return Status;\r
429}\r