]> git.proxmox.com Git - mirror_edk2.git/blame_incremental - MdeModulePkg/Universal/Network/IScsiDxe/IScsiCHAP.c
Update the copyright notice format
[mirror_edk2.git] / MdeModulePkg / Universal / Network / IScsiDxe / IScsiCHAP.c
... / ...
CommitLineData
1/** @file\r
2 This file is for Challenge-Handshake Authentication Protocol (CHAP) Configuration.\r
3\r
4Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>\r
5This 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
12\r
13**/\r
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
20/**\r
21 Initator caculates its own expected hash value.\r
22\r
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
26 @param[in] ChapChallenge The challenge message sent by authenticator.\r
27 @param[in] ChallengeLength The length of iSCSI CHAP challenge message.\r
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
33 @retval Others Other errors as indicated.\r
34**/\r
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
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
80 @param[in] AuthData iSCSI CHAP authentication data.\r
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
85 @retval Others Other errors as indicated.\r
86**/\r
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
109 if (CompareMem (VerifyRsp, TargetResponse, ISCSI_CHAP_RSP_LEN) != 0) {\r
110 Status = EFI_SECURITY_VIOLATION;\r
111 }\r
112\r
113 return Status;\r
114}\r
115\r
116/**\r
117 This function checks the received iSCSI Login Response during the security\r
118 negotiation stage.\r
119\r
120 @param[in] Conn The iSCSI connection.\r
121\r
122 @retval EFI_SUCCESS The Login Response passed the CHAP validation.\r
123 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
124 @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.\r
125 @retval Others Other errors as indicated.\r
126**/\r
127EFI_STATUS\r
128IScsiCHAPOnRspReceived (\r
129 IN ISCSI_CONNECTION *Conn\r
130 )\r
131{\r
132 EFI_STATUS Status;\r
133 ISCSI_SESSION *Session;\r
134 ISCSI_CHAP_AUTH_DATA *AuthData;\r
135 CHAR8 *Value;\r
136 UINT8 *Data;\r
137 UINT32 Len;\r
138 LIST_ENTRY *KeyValueList;\r
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
151 AuthData = &Session->AuthData;\r
152\r
153 Len = Conn->RspQue.BufSize;\r
154 Data = AllocatePool (Len);\r
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
166 KeyValueList = IScsiBuildKeyValueList ((CHAR8 *) Data, Len);\r
167 if (KeyValueList == NULL) {\r
168 FreePool (Data);\r
169 return EFI_OUT_OF_RESOURCES;\r
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
285 // Check the CHAP Response replied by Target.\r
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
298 FreePool (Data);\r
299\r
300 return Status;\r
301}\r
302\r
303/**\r
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
306\r
307 @param[in] Conn The iSCSI connection.\r
308 @param[in, out] Pdu The PDU to send out.\r
309\r
310 @retval EFI_SUCCESS All check passed and the phase-related CHAP\r
311 authentication info is filled into the iSCSI PDU.\r
312 @retval EFI_OUT_OF_RESOURCES Failed to allocate memory.\r
313 @retval EFI_PROTOCOL_ERROR Some kind of protocol error happend.\r
314**/\r
315EFI_STATUS\r
316IScsiCHAPToSendReq (\r
317 IN ISCSI_CONNECTION *Conn,\r
318 IN OUT NET_BUF *Pdu\r
319 )\r
320{\r
321 EFI_STATUS Status;\r
322 ISCSI_SESSION *Session;\r
323 ISCSI_LOGIN_REQUEST *LoginReq;\r
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
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 = AllocatePool (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 = AllocatePool (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
390 IScsiAddKeyValuePair (Pdu, ISCSI_KEY_CHAP_NAME, (CHAR8 *) &AuthData->AuthConfig.CHAPName);\r
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 FreePool (Response);\r
426 FreePool (Challenge);\r
427\r
428 return Status;\r
429}\r