VirtualBox

source: vbox/trunk/src/VBox/Devices/EFI/Firmware/NetworkPkg/IScsiDxe/IScsiCHAP.c@ 58466

最後變更 在這個檔案從58466是 58466,由 vboxsync 提交於 9 年 前

EFI/Firmware: Merged in the svn:eol-style, svn:mime-type and trailing whitespace cleanup that was done after the initial UDK2014.SP1 import: svn merge /vendor/edk2/UDK2014.SP1 /vendor/edk2/current .

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

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette