|
1 // Copyright (c) 1997-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
2 // All rights reserved. |
|
3 // This component and the accompanying materials are made available |
|
4 // under the terms of "Eclipse Public License v1.0" |
|
5 // which accompanies this distribution, and is available |
|
6 // at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
7 // |
|
8 // Initial Contributors: |
|
9 // Nokia Corporation - initial contribution. |
|
10 // |
|
11 // Contributors: |
|
12 // |
|
13 // Description: |
|
14 // Authentication Protocol (CHAP) - RFC 1994, containing source code |
|
15 // common to all PPP authentication protocols derived from CHAP. |
|
16 // |
|
17 // |
|
18 |
|
19 /** |
|
20 @file |
|
21 @brief Source file for the implementation of PPP Challenge Handshake |
|
22 @internalComponent |
|
23 */ |
|
24 |
|
25 #include "PPPCHAP.H" |
|
26 |
|
27 CPppChap::~CPppChap() |
|
28 /** |
|
29 Destructor. |
|
30 @internalComponent |
|
31 */ |
|
32 { |
|
33 if (iPppLcp != 0) |
|
34 { |
|
35 iChallengePacket.Free(); |
|
36 TimerDelete(); |
|
37 } |
|
38 } |
|
39 |
|
40 void CPppChap::InitL(CPppLcp* aLcp) |
|
41 /** |
|
42 @copydoc CPppAuthentication::InitL(CPppLcp*) |
|
43 @see CPppAuthentication::InitL(CPppLcp*) |
|
44 @internalComponent |
|
45 */ |
|
46 { |
|
47 CPppAuthentication::InitL(aLcp); |
|
48 TimerConstructL(KPppFsmTimerPriority); |
|
49 Register(); |
|
50 } |
|
51 |
|
52 void CPppChap::LowerLayerUp() |
|
53 /** |
|
54 @copydoc MPppRecvr::LowerLayerUp() |
|
55 @see MPppRecvr::LowerLayerUp() |
|
56 @internalComponent |
|
57 */ |
|
58 { |
|
59 ASSERT(iPppLcp != 0); |
|
60 AuthenticateRequest(); |
|
61 } |
|
62 |
|
63 |
|
64 void CPppChap::LowerLayerDown(TInt /*aStatus*/) |
|
65 /** |
|
66 @copydoc MPppRecvr::LowerLayerDown(TInt) |
|
67 @see MPppRecvr::LowerLayerDown(TInt) |
|
68 @internalComponent |
|
69 */ |
|
70 { |
|
71 ASSERT(iPppLcp != 0); |
|
72 TimerCancel(); |
|
73 } |
|
74 |
|
75 |
|
76 void CPppChap::AuthenticateComplete(TInt aStatus) |
|
77 /** |
|
78 @copydoc CPppAuthentication::AuthenticateComplete(TInt) |
|
79 @see CPppAuthentication::AuthenticateComplete(TInt) |
|
80 @internalComponent |
|
81 */ |
|
82 { |
|
83 ASSERT(iPppLcp != 0); |
|
84 if (aStatus==KErrNone) |
|
85 { |
|
86 if (!iChallengePacket.IsEmpty()) |
|
87 { |
|
88 iResponseRetryCount = 0; |
|
89 //ignore Error, if fails it will time out |
|
90 //and try again anyway. |
|
91 TRAP_IGNORE(RespondL()); |
|
92 } |
|
93 } |
|
94 else |
|
95 DoFail(aStatus); |
|
96 } |
|
97 |
|
98 |
|
99 TBool CPppChap::RecvFrame(RMBufChain& aPacket) |
|
100 /** |
|
101 @copydoc MPppRecvr::RecvFrame(RMBufChain&) |
|
102 @see MPppRecvr::RecvFrame(RMBufChain&) |
|
103 @internalComponent |
|
104 */ |
|
105 { |
|
106 ASSERT(iPppLcp != 0); |
|
107 |
|
108 RMBufPacket pkt; |
|
109 pkt.Assign(aPacket); |
|
110 pkt.Unpack(); |
|
111 RMBufPktInfo* info = pkt.Info(); |
|
112 |
|
113 if (IsInactive()) |
|
114 { |
|
115 pkt.Free(); |
|
116 return EFalse; |
|
117 } |
|
118 |
|
119 |
|
120 // Extract and drop LCP header |
|
121 pkt.Align(4); |
|
122 |
|
123 if (info->iLength < KPppChapCodeFieldSize + |
|
124 KPppChapIdFieldSize + |
|
125 KPppChapLengthFieldSize) |
|
126 { |
|
127 // Too short! |
|
128 pkt.Free(); |
|
129 return EFalse; |
|
130 } |
|
131 |
|
132 |
|
133 // check that the length of the packet is OK |
|
134 TUint16 length = BigEndian::Get16(pkt.First()->Ptr() + |
|
135 KPppChapCodeFieldSize + |
|
136 KPppChapIdFieldSize); |
|
137 |
|
138 if (info->iLength < length) |
|
139 { |
|
140 // Too short! |
|
141 pkt.Free(); |
|
142 return EFalse; |
|
143 } |
|
144 else if (info->iLength > length) |
|
145 pkt.TrimEnd(length); |
|
146 |
|
147 ASSERT(pkt.Length()==length); |
|
148 |
|
149 TUint8 code = *(pkt.First()->Ptr()); |
|
150 |
|
151 TInt ret; |
|
152 switch (code) |
|
153 { |
|
154 case KPppChapChallengeCode: |
|
155 { |
|
156 TRAP(ret, ChallengeL(pkt)); |
|
157 } |
|
158 break; |
|
159 |
|
160 case KPppChapResponseCode: |
|
161 // { |
|
162 // TInt vc = *ptr++; |
|
163 // TUint8* vp = ptr; |
|
164 // TInt nc = len-(vc+1); |
|
165 // TUint8* np = ptr+vc; |
|
166 // } |
|
167 break; |
|
168 |
|
169 case KPppChapSuccessCode: |
|
170 { |
|
171 TRAP(ret, SuccessL(pkt)); |
|
172 } |
|
173 break; |
|
174 |
|
175 case KPppChapFailureCode: |
|
176 { |
|
177 TRAP(ret, FailureL(pkt)); |
|
178 |
|
179 if (ret!=KErrNone) |
|
180 DoFail(KErrIfAuthenticationFailure); |
|
181 } |
|
182 break; |
|
183 |
|
184 // default: invalid CHAP packet code |
|
185 // simply ignore the packet |
|
186 } |
|
187 |
|
188 pkt.Free(); |
|
189 return EFalse; |
|
190 } |
|
191 |
|
192 // RFC 1994: "The Challenge-Handshake Authentication Protocol (CHAP) |
|
193 // is used to periodically verify the identity of the peer using a |
|
194 // 3-way handshake. This is done upon initial link establishment, and |
|
195 // MAY be repeated anytime after the link has been established." |
|
196 |
|
197 |
|
198 void CPppChap::ChallengeL(RMBufPacket& aPacket) |
|
199 /** |
|
200 Processes a CHAP Challenge packet and attempts to respond to the |
|
201 challenge. |
|
202 @param aPacket [in] The CHAP Challenge packet to be processed. |
|
203 @internalComponent |
|
204 */ |
|
205 { |
|
206 TimerCancel(); |
|
207 ProcessChallengePacketL(aPacket); |
|
208 |
|
209 if (IsAuthenticateRequestDone()) |
|
210 { |
|
211 iResponseRetryCount = 0; |
|
212 RespondL(); |
|
213 } |
|
214 } |
|
215 |
|
216 |
|
217 void CPppChap::CheckChallengePacketL(RMBufPacket& aPacket) |
|
218 /** |
|
219 Checks that a CHAP Challenge packet is valid. Leaves if the packet |
|
220 is malformed. |
|
221 @param aPacket [in] The CHAP Challenge packet to be checked. |
|
222 @internalComponent |
|
223 */ |
|
224 { |
|
225 // In the case of MS-CHAP-V1 and MS-CHAP-V2 the Challenge Name may be |
|
226 // empty. RFC 1994: "The Name field is one or more octets [...]". |
|
227 // RFC2433, RFC2759: "Microsoft authenticators do not currently |
|
228 // provide information in the Name field. This may change in the |
|
229 // future." |
|
230 __ASSERT_ALWAYS(aPacket.Length() >= KPppChapCodeFieldSize + |
|
231 KPppChapIdFieldSize + |
|
232 KPppChapLengthFieldSize + |
|
233 KPppChapValueSizeFieldSize + |
|
234 KPppChapMinValueSize, |
|
235 User::Leave(KErrUnderflow)); |
|
236 |
|
237 TUint8 valueSize = *(aPacket.First()->Ptr() + |
|
238 KPppChapCodeFieldSize + |
|
239 KPppChapIdFieldSize + |
|
240 KPppChapLengthFieldSize); |
|
241 |
|
242 __ASSERT_ALWAYS(valueSize >= KPppChapMinValueSize, |
|
243 User::Leave(KErrUnderflow)); |
|
244 |
|
245 __ASSERT_ALWAYS(valueSize <= aPacket.Length() - |
|
246 KPppChapCodeFieldSize - |
|
247 KPppChapIdFieldSize - |
|
248 KPppChapLengthFieldSize - |
|
249 KPppChapValueSizeFieldSize, |
|
250 User::Leave(KErrOverflow)); |
|
251 } |
|
252 |
|
253 |
|
254 void CPppChap::ProcessChallengePacketL(RMBufPacket& aPacket) |
|
255 /** |
|
256 Processes a CHAP Challenge packet. |
|
257 @param aPacket [in] The CHAP Challenge packet to be processed. |
|
258 @internalComponent |
|
259 */ |
|
260 { |
|
261 CheckChallengePacketL(aPacket); |
|
262 |
|
263 iChallengePacket.Free(); |
|
264 iChallengePacket.Assign(aPacket); |
|
265 |
|
266 // go past the CHAP Code field and |
|
267 // read the CHAP Identifier field |
|
268 iCurrentId = *(iChallengePacket.First()->Ptr() |
|
269 + KPppChapCodeFieldSize); |
|
270 |
|
271 // Go past the CHAP Code field, the CHAP Identifier field and the CHAP |
|
272 // Length field and read the CHAP Value-Size field. |
|
273 TUint8 valueSize = *(iChallengePacket.First()->Ptr() + |
|
274 KPppChapCodeFieldSize + |
|
275 KPppChapIdFieldSize + |
|
276 KPppChapLengthFieldSize); |
|
277 |
|
278 // Go past the CHAP Code field, the CHAP Identifier field, the CHAP |
|
279 // Length field and the CHAP Value-Size field and read the CHAP Value |
|
280 // field |
|
281 iChallengeRef.Set(iChallengePacket.First()->Ptr() + |
|
282 KPppChapCodeFieldSize + |
|
283 KPppChapIdFieldSize + |
|
284 KPppChapLengthFieldSize + |
|
285 KPppChapValueSizeFieldSize, |
|
286 valueSize, |
|
287 valueSize); |
|
288 } |
|
289 |
|
290 |
|
291 void CPppChap::RespondL() |
|
292 /** |
|
293 Responds to the latest CHAP Challenge received. |
|
294 @internalComponent |
|
295 */ |
|
296 { |
|
297 ASSERT(!iChallengePacket.IsEmpty()); |
|
298 ASSERT(IsAuthenticateRequestDone()); |
|
299 |
|
300 MakeResponseL(iCurrentId, |
|
301 iChallengeRef, |
|
302 iResponseValueRef, |
|
303 iResponseNameRef); |
|
304 SendResponseL(iCurrentId, iResponseValueRef, iResponseNameRef); |
|
305 |
|
306 if (++iResponseRetryCount < KPppChapMaxResponseRetryCount) |
|
307 TimerAfter(KPppChapResponseRetryTimerPeriod* 1000); |
|
308 } |
|
309 |
|
310 |
|
311 void CPppChap::MakeResponsePacketLC(TUint8 aIdentifier, |
|
312 const TDesC8& aValue, |
|
313 const TDesC8& aName, |
|
314 RMBufPacket& aPacket) |
|
315 /** |
|
316 Creates a CHAP response Packet. |
|
317 @param aIdentifier [in] The CHAP Response Identifier. |
|
318 @param aValue [in] The CHAP Response Value. |
|
319 @param aName [in] The CHAP Response Name. |
|
320 @param aPacket [out] The CHAP Response packet. |
|
321 @internalComponent |
|
322 */ |
|
323 { |
|
324 ASSERT(aValue.Length() <= KMaxTInt8); |
|
325 ASSERT(aName.Length() <= |
|
326 KMaxTInt16 - |
|
327 KPppChapCodeFieldSize - |
|
328 KPppChapIdFieldSize - |
|
329 KPppChapLengthFieldSize - |
|
330 KPppChapValueSizeFieldSize - |
|
331 aValue.Length()); |
|
332 |
|
333 TUint16 length = static_cast<TUint16>(KPppChapCodeFieldSize + |
|
334 KPppChapIdFieldSize + |
|
335 KPppChapLengthFieldSize + |
|
336 KPppChapValueSizeFieldSize + |
|
337 aValue.Length() + |
|
338 aName.Length()); |
|
339 |
|
340 aPacket.AllocL(length); |
|
341 CleanupStack::PushL(aPacket); |
|
342 RMBufPktInfo* info = aPacket.NewInfoL(); |
|
343 |
|
344 // Construct packet header |
|
345 TUint8* ptr = aPacket.First()->Ptr(); |
|
346 |
|
347 // write the CHAP Code field |
|
348 *ptr = KPppChapResponseCode; |
|
349 ptr += KPppChapCodeFieldSize; |
|
350 |
|
351 // write the CHAP Identifier field |
|
352 *ptr = aIdentifier; |
|
353 ptr += KPppChapIdFieldSize; |
|
354 |
|
355 // write the CHAP Length field |
|
356 BigEndian::Put16(ptr, length); |
|
357 ptr += KPppChapLengthFieldSize; |
|
358 |
|
359 // write the CHAP Value-Size field |
|
360 *ptr = static_cast<TUint8>(aValue.Length()); |
|
361 ptr += KPppChapValueSizeFieldSize; |
|
362 |
|
363 Mem::Copy(ptr, aValue.Ptr(), aValue.Length()); |
|
364 ptr += aValue.Length(); |
|
365 |
|
366 Mem::Copy(ptr, aName.Ptr(), aName.Length()); |
|
367 ptr += aName.Length(); |
|
368 |
|
369 info->iLength = length; |
|
370 TPppAddr::Cast((info->iDstAddr)).SetProtocol(KPppIdChap); |
|
371 aPacket.Pack(); |
|
372 } |
|
373 |
|
374 |
|
375 void CPppChap::SendResponseL(TUint8 aResponseId, |
|
376 const TDesC8& aResponseValue, |
|
377 const TDesC8& aResponseName) |
|
378 /** |
|
379 Generates a CHAP Response packet and sends it to the peer. |
|
380 @param aResponseId [in] The CHAP Response Identifier. |
|
381 @param aResponseValue [in] The CHAP Response Value. |
|
382 @param aResponseName [in] The CHAP Response Name. |
|
383 @internalComponent |
|
384 */ |
|
385 { |
|
386 RMBufPacket packet; |
|
387 MakeResponsePacketLC(aResponseId, |
|
388 aResponseValue, |
|
389 aResponseName, |
|
390 packet); |
|
391 SendFrame(packet); |
|
392 CleanupStack::Pop(); // packet |
|
393 } |
|
394 |
|
395 |
|
396 void CPppChap::SuccessL(RMBufPacket& aPacket) |
|
397 /** |
|
398 Processes a CHAP Success packet and takes action to complete the |
|
399 authentication. |
|
400 @param aPacket [in] The CHAP Success packet to be processed. |
|
401 @internalComponent |
|
402 */ |
|
403 { |
|
404 __ASSERT_ALWAYS(aPacket.Length() >= KPppChapCodeFieldSize + |
|
405 KPppChapIdFieldSize + |
|
406 KPppChapLengthFieldSize, |
|
407 User::Leave(KErrUnderflow)); |
|
408 |
|
409 // check the id |
|
410 if (!CheckIdentifier(aPacket)) |
|
411 User::Leave(KErrGeneral); |
|
412 |
|
413 TimerCancel(); |
|
414 DoSucceed(); |
|
415 if (iPppLcp->CallbackEnabled() && |
|
416 iPppLcp->CallbackRequestType() != |
|
417 ECallbackIETFRequestTypeMSCBCP) |
|
418 { |
|
419 iPppLcp->CallbackGrantedAndAuthenticated(); |
|
420 iPppLcp->TerminateLink(MNifIfNotify::ECallBack); |
|
421 } |
|
422 } |
|
423 |
|
424 |
|
425 void CPppChap::FailureL(RMBufPacket& aPacket) |
|
426 /** |
|
427 Processes a CHAP Failure packet and takes action to handle the |
|
428 authentication failure. |
|
429 @param aPacket [in] The CHAP Failure packet to be processed. |
|
430 @internalComponent |
|
431 */ |
|
432 { |
|
433 __ASSERT_ALWAYS(aPacket.Length() >= KPppChapCodeFieldSize + |
|
434 KPppChapIdFieldSize + |
|
435 KPppChapLengthFieldSize, |
|
436 User::Leave(KErrUnderflow)); |
|
437 |
|
438 // check the id |
|
439 if (!CheckIdentifier(aPacket)) |
|
440 User::Leave(KErrGeneral); |
|
441 |
|
442 TimerCancel(); |
|
443 DoFail(KErrIfAuthenticationFailure); |
|
444 } |
|
445 |
|
446 |
|
447 void CPppChap::TimerComplete(TInt /*aStatus*/) |
|
448 /** |
|
449 Signals that the response retry timer has expired. |
|
450 @param aStatus [in] A status code. |
|
451 @see MTimer::TimerComplete(TInt) |
|
452 @internalComponent |
|
453 */ |
|
454 { |
|
455 ASSERT(iPppLcp != 0); |
|
456 //ignore Error, if fails it will time out |
|
457 //and try again anyway. |
|
458 TRAP_IGNORE(RetryResponseL()); |
|
459 } |
|
460 |
|
461 |
|
462 void CPppChap::RetryResponseL() |
|
463 /** |
|
464 Resends the latest CHAP Response sent. |
|
465 @internalComponent |
|
466 */ |
|
467 { |
|
468 SendResponseL(iCurrentId, iResponseValueRef, iResponseNameRef); |
|
469 |
|
470 if (++iResponseRetryCount < KPppChapMaxResponseRetryCount) |
|
471 TimerAfter(KPppChapResponseRetryTimerPeriod* 1000); |
|
472 } |