1 /* |
|
2 * Copyright (c) 2006-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of the License "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: |
|
15 * CPinPluginAO implementation |
|
16 * |
|
17 */ |
|
18 |
|
19 |
|
20 /** |
|
21 @file |
|
22 */ |
|
23 |
|
24 #include "pinpluginao.h" |
|
25 #include <hash.h> |
|
26 #include <authserver/auth_srv_errs.h> |
|
27 #include <authserver/authtypes.h> |
|
28 #include <e32math.h> |
|
29 |
|
30 using namespace AuthServer; |
|
31 |
|
32 /** |
|
33 KDefaultPinDigit is used to generate the default pinvalue for the DefaultData(). |
|
34 The default pinvalue is generated by appending KDefaultPinDigit for iPinSize times. |
|
35 */ |
|
36 const TUint KDefaultPinDigit = 1; |
|
37 |
|
38 /** |
|
39 The selected pin index for the Train/Retrain operation, returned by |
|
40 Dialog Notifier should be in the range KIndexLow and KIndexHigh. This should |
|
41 be validated in the Dialog implementation. If Pinplugin receives any other |
|
42 values, then pinplugin will panic. |
|
43 */ |
|
44 const TInt KIndexLow = 0; |
|
45 const TInt KIndexHigh = 3; |
|
46 |
|
47 CPinPluginAO* CPinPluginAO::NewL(TInt aPinSize, TInt aPinMinSize, TInt aPinMaxSize, TInt aRetryCount) |
|
48 { |
|
49 CPinPluginAO* self = CPinPluginAO::NewLC(aPinSize, aPinMinSize, aPinMaxSize, aRetryCount); |
|
50 CleanupStack::Pop(self); |
|
51 return self; |
|
52 } |
|
53 |
|
54 CPinPluginAO* CPinPluginAO::NewLC(TInt aPinSize, TInt aPinMinSize, TInt aPinMaxSize, TInt aRetryCount) |
|
55 { |
|
56 CPinPluginAO* self = new(ELeave) CPinPluginAO(aPinSize, aPinMinSize, aPinMaxSize, aRetryCount); |
|
57 CleanupStack::PushL(self); |
|
58 self->ConstructL(); |
|
59 return self; |
|
60 } |
|
61 |
|
62 CPinPluginAO::CPinPluginAO(TInt aPinSize, TInt aPinMinSize, TInt aPinMaxSize, TInt aRetryCount) |
|
63 :CActive(EPriorityStandard), iRetryCount(aRetryCount), iPinSize(aPinSize), iPinMinSize(aPinMinSize), |
|
64 iPinMaxSize(aPinMaxSize) |
|
65 { |
|
66 CActiveScheduler::Add(this); |
|
67 } |
|
68 |
|
69 void CPinPluginAO::ConstructL() |
|
70 { |
|
71 iNewPinSize = iPinSize; |
|
72 |
|
73 // construct PinpluginDialog |
|
74 iPinPluginDialog = CPinPluginDialog::NewL(); |
|
75 // construct the DB |
|
76 iPinPluginDb = CPinPluginDB::NewL(); |
|
77 iDialogResult = new (ELeave) TPinPluginDialogResult; |
|
78 iRetryRefCount = iRetryCount; |
|
79 } |
|
80 |
|
81 CPinPluginAO::~CPinPluginAO() |
|
82 { |
|
83 Deque(); |
|
84 delete iDialogResult; |
|
85 delete iPinPluginDialog; |
|
86 delete iPinPluginDb; |
|
87 iPinList.ResetAndDestroy(); |
|
88 iIdKeyList.ResetAndDestroy(); |
|
89 iIdKeyHashList.ResetAndDestroy(); |
|
90 } |
|
91 |
|
92 void CPinPluginAO::Identify(TIdentityId& aId, const TDesC& aClientMessage, |
|
93 HBufC8*& aResult, TRequestStatus& aRequest) |
|
94 { |
|
95 iState = EIdentify; |
|
96 iIdentityId = aId; |
|
97 iIdentityIdPtr = &aId; |
|
98 |
|
99 aRequest = KRequestPending; |
|
100 iRequestStatus = &aRequest; |
|
101 |
|
102 iClientMessage = static_cast<const HBufC*>(&aClientMessage); |
|
103 iResult = &aResult; |
|
104 aResult = NULL; |
|
105 |
|
106 SetActive(); |
|
107 TRequestStatus* stat = &iStatus; |
|
108 User::RequestComplete(stat, KErrNone); |
|
109 } |
|
110 |
|
111 void CPinPluginAO::Train(TIdentityId aId, HBufC8*& aResult, TRequestStatus& aRequest) |
|
112 { |
|
113 iState = ETrain; |
|
114 iIdentityId = aId; |
|
115 |
|
116 aRequest = KRequestPending; |
|
117 iRequestStatus = &aRequest; |
|
118 |
|
119 iResult = &aResult; |
|
120 aResult = NULL; |
|
121 |
|
122 SetActive(); |
|
123 TRequestStatus* stat = &iStatus; |
|
124 User::RequestComplete(stat, KErrNone); |
|
125 } |
|
126 |
|
127 TInt CPinPluginAO::DefaultData(TIdentityId aId, HBufC8*& aOutputBuf) |
|
128 { |
|
129 aOutputBuf = NULL; |
|
130 TPinValue defaultPin; |
|
131 for (TInt i = 0; i < iPinSize; i++) |
|
132 { |
|
133 defaultPin.AppendNum(KDefaultPinDigit); |
|
134 } |
|
135 |
|
136 HBufC8* identityKey = NULL; |
|
137 HBufC8* identityKeyHash = NULL; |
|
138 TRAPD(err, |
|
139 identityKeyHash = GenerateKeyHashL(defaultPin, identityKey); |
|
140 CleanupStack::PushL(identityKeyHash); |
|
141 CleanupStack::PushL(identityKey); |
|
142 aOutputBuf = (*identityKey).AllocL(); |
|
143 iPinPluginDb->AddPinL(aId, *identityKeyHash); |
|
144 CleanupStack::PopAndDestroy(2, identityKeyHash)); |
|
145 |
|
146 return err; |
|
147 } |
|
148 |
|
149 TInt CPinPluginAO::Forget(TIdentityId aId) |
|
150 { |
|
151 TInt err = KErrNone; |
|
152 TRAP(err, iPinPluginDb->RemovePinL(aId)); |
|
153 if (err == KErrNotFound) |
|
154 { |
|
155 err = KErrAuthServNoSuchIdentity; |
|
156 } |
|
157 return err; |
|
158 } |
|
159 |
|
160 void CPinPluginAO::ResetL(TIdentityId aIdentityId, const TDesC& aRegistrationData, HBufC8*& aResult) |
|
161 { |
|
162 // Remove the current trained information and register using the newly supplied registration |
|
163 // data (Since pin plugin is a knowledge based plugin, the registration data supplied is assumed to be the pin) |
|
164 // For other plugin types this information is ignored and the identity is simply set as untrained |
|
165 |
|
166 // If no registration data is supplied then just perform a forget |
|
167 if (aRegistrationData == KNullDesC) |
|
168 { |
|
169 aResult = NULL; |
|
170 TInt err = Forget(aIdentityId); |
|
171 User::LeaveIfError(err); |
|
172 return; |
|
173 } |
|
174 |
|
175 // Ensure registration data length is less than or equal to max allowed pin length |
|
176 TInt pinLen = aRegistrationData.Length(); |
|
177 if (pinLen > KMaxPinLength) |
|
178 { |
|
179 User::Leave(KErrArgument); |
|
180 } |
|
181 |
|
182 // Convert registration data to 8 bit |
|
183 // Note that no unicode conversion is being done here since a pin cannot be in unicode |
|
184 RBuf8 pinBuf; |
|
185 pinBuf.CreateL(pinLen); |
|
186 CleanupClosePushL(pinBuf); |
|
187 pinBuf.Copy(aRegistrationData.Left(pinLen)); |
|
188 TPinValue pin(pinBuf); |
|
189 CleanupStack::PopAndDestroy(&pinBuf); |
|
190 |
|
191 // Generate the identity key and identity key hash |
|
192 HBufC8* identityKey = NULL; |
|
193 HBufC8* identityKeyHash = GenerateKeyHashL(pin, identityKey); |
|
194 CleanupStack::PushL(identityKeyHash); |
|
195 CleanupStack::PushL(identityKey); |
|
196 |
|
197 // Ensure another identity doesn't have the same pin |
|
198 TIdentityId tempId = iPinPluginDb->IdFromPin(*identityKeyHash); |
|
199 if ((tempId != aIdentityId) && (tempId != KUnknownIdentity)) |
|
200 { |
|
201 CleanupStack::PopAndDestroy(2, identityKeyHash); |
|
202 // This appears to be the most appropriate error code - The important point is to convery Reset has failed. |
|
203 User::Leave(KErrInUse); |
|
204 } |
|
205 else if (tempId == aIdentityId) |
|
206 { |
|
207 // Nothing to do |
|
208 aResult = identityKey; // Ownership transferred to caller |
|
209 CleanupStack::Pop(identityKey); |
|
210 CleanupStack::PopAndDestroy(identityKeyHash); |
|
211 return; |
|
212 } |
|
213 |
|
214 // Replace the training data |
|
215 iPinPluginDb->UpdatePinL(aIdentityId, *identityKeyHash); |
|
216 aResult = identityKey; // Ownership transferred to caller |
|
217 CleanupStack::Pop(identityKey); |
|
218 CleanupStack::PopAndDestroy(identityKeyHash); |
|
219 } |
|
220 |
|
221 void CPinPluginAO::DoCancel() |
|
222 { |
|
223 iPinPluginDialog->Cancel(); |
|
224 if(iRequestStatus) |
|
225 { |
|
226 User::RequestComplete(iRequestStatus, KErrCancel); |
|
227 } |
|
228 } |
|
229 |
|
230 void CPinPluginAO::RunL() |
|
231 { |
|
232 // Leave if there has been an error |
|
233 User::LeaveIfError(iStatus.Int()); |
|
234 |
|
235 switch(iState) |
|
236 { |
|
237 case EIdentify: |
|
238 { |
|
239 IdentifyId(); |
|
240 } |
|
241 break; |
|
242 case EIdentifyResult: |
|
243 { |
|
244 if (*iDialogResult == EOk) |
|
245 { |
|
246 IdentifyResultL(); |
|
247 } |
|
248 else if (*iDialogResult == ECancel) |
|
249 { |
|
250 User::RequestComplete(iRequestStatus, KErrAuthServPluginCancelled); |
|
251 } |
|
252 else if (*iDialogResult == EQuit) |
|
253 { |
|
254 User::RequestComplete(iRequestStatus, KErrAuthServPluginQuit); |
|
255 } |
|
256 *iDialogResult = static_cast<TPinPluginDialogResult>(0); |
|
257 } |
|
258 break; |
|
259 case ETrain: |
|
260 { |
|
261 TrainIdL(); |
|
262 } |
|
263 break; |
|
264 case ETrainResult: |
|
265 { |
|
266 if (*iDialogResult == EOk) |
|
267 { |
|
268 AddTrainResultToDBL(); |
|
269 } |
|
270 else if (*iDialogResult == ECancel) |
|
271 { |
|
272 User::RequestComplete(iRequestStatus, KErrAuthServPluginCancelled); |
|
273 } |
|
274 else if (*iDialogResult == EQuit) |
|
275 { |
|
276 User::RequestComplete(iRequestStatus, KErrAuthServPluginQuit); |
|
277 } |
|
278 else if (*iDialogResult == ENext) |
|
279 { |
|
280 iState = ETrain; |
|
281 TRequestStatus* status = &iStatus; |
|
282 User::RequestComplete(status, KErrNone); |
|
283 SetActive(); |
|
284 } |
|
285 *iDialogResult = static_cast<TPinPluginDialogResult>(0); |
|
286 } |
|
287 break; |
|
288 case EInfo: |
|
289 { |
|
290 iPinPluginDialog->PinInfo(iMessage, iStatus); |
|
291 iState = EFinished; |
|
292 SetActive(); |
|
293 } |
|
294 break; |
|
295 case EFinished: |
|
296 { |
|
297 User::RequestComplete(iRequestStatus, iStatus.Int()); |
|
298 } |
|
299 break; |
|
300 default: |
|
301 { |
|
302 User::Leave(KErrNotSupported); |
|
303 } |
|
304 break; |
|
305 } |
|
306 } |
|
307 |
|
308 TInt CPinPluginAO::RunError(TInt aError) |
|
309 { |
|
310 if(iRequestStatus) |
|
311 { |
|
312 User::RequestComplete(iRequestStatus, aError); |
|
313 } |
|
314 return KErrNone; |
|
315 } |
|
316 |
|
317 void CPinPluginAO::IdentifyId() |
|
318 { |
|
319 if (iRetryRefCount--) |
|
320 { |
|
321 iPinPluginDialog->PinIdentify(iPinMinSize, iPinMaxSize, ETrue, iPinValue, *iDialogResult, iStatus); |
|
322 iState = EIdentifyResult; |
|
323 } |
|
324 else |
|
325 { |
|
326 iRetryRefCount = iRetryCount; |
|
327 *iIdentityIdPtr = KUnknownIdentity; |
|
328 iMessage = EPinPluginIdentificationFailure; |
|
329 TRequestStatus* status = &iStatus; |
|
330 User::RequestComplete(status, KErrNone); |
|
331 iState = EInfo; |
|
332 } |
|
333 SetActive(); |
|
334 } |
|
335 |
|
336 void CPinPluginAO::IdentifyResultL() |
|
337 { |
|
338 TIdentityId identityId; |
|
339 HBufC8* identityKey = NULL; |
|
340 HBufC8* identityKeyHash = GenerateKeyHashL(iPinValue, identityKey); |
|
341 CleanupStack::PushL(identityKeyHash); |
|
342 CleanupStack::PushL(identityKey); |
|
343 identityId = iPinPluginDb->IdFromPin(*identityKeyHash); |
|
344 if (identityId != KUnknownIdentity) |
|
345 { |
|
346 *iIdentityIdPtr = identityId; |
|
347 iRetryRefCount = iRetryCount; |
|
348 *iResult = identityKey; |
|
349 iMessage = EPinPluginIdentificationSuccess; |
|
350 iState = EInfo; |
|
351 CleanupStack::Pop(identityKey); |
|
352 } |
|
353 else |
|
354 { |
|
355 CleanupStack::PopAndDestroy(identityKey); |
|
356 iState = EIdentify; |
|
357 } |
|
358 CleanupStack::PopAndDestroy(identityKeyHash); |
|
359 TRequestStatus* status = &iStatus; |
|
360 User::RequestComplete(status, KErrNone); |
|
361 SetActive(); |
|
362 } |
|
363 |
|
364 void CPinPluginAO::TrainIdL() |
|
365 { |
|
366 // Check for invalid pinsize. |
|
367 if( !(iNewPinSize >= iPinMinSize && iNewPinSize <= iPinMaxSize) ) |
|
368 { |
|
369 User::Leave(KErrAuthServRegistrationFailed); |
|
370 } |
|
371 |
|
372 |
|
373 iPinList.ResetAndDestroy(); |
|
374 iIdKeyList.ResetAndDestroy(); |
|
375 iIdKeyHashList.ResetAndDestroy(); |
|
376 GenerateUniquePinsL(iPinList, iIdKeyList, iIdKeyHashList); |
|
377 TInt indexValue = iPinPluginDb->IdIndex(iIdentityId); |
|
378 TPinPluginTrainingMessage trainMessage; |
|
379 if (indexValue >= 0) |
|
380 { |
|
381 trainMessage = EReTraining; |
|
382 } |
|
383 else |
|
384 { |
|
385 trainMessage = ETraining; |
|
386 } |
|
387 iPinPluginDialog->PinTraining(trainMessage, iPinList, iPinMinSize, iPinMaxSize, iIndex, iNewPinSize, *iDialogResult, iStatus); |
|
388 iState = ETrainResult; |
|
389 SetActive(); |
|
390 } |
|
391 |
|
392 void CPinPluginAO::AddTrainResultToDBL() |
|
393 { |
|
394 __ASSERT_ALWAYS(iIndex >= KIndexLow && iIndex <= KIndexHigh, |
|
395 User::Panic(KPinPluginPanicString(), EPinPanicIncorrectIndex)); |
|
396 |
|
397 TInt indexValue = iPinPluginDb->IdIndex(iIdentityId); |
|
398 if (indexValue >= 0) |
|
399 { |
|
400 iPinPluginDb->UpdatePinL(iIdentityId, *iIdKeyHashList[iIndex]); |
|
401 iMessage = EPinPluginReTrainingSuccess; |
|
402 } |
|
403 else |
|
404 { |
|
405 iPinPluginDb->AddPinL(iIdentityId, *iIdKeyHashList[iIndex]); |
|
406 iMessage = EPinPluginTrainingSuccess; |
|
407 } |
|
408 TPtrC8 idKeyPtr = *iIdKeyList[iIndex]; |
|
409 HBufC8* identityKey = idKeyPtr.AllocL(); |
|
410 *iResult = identityKey; |
|
411 iNewPinSize = iPinSize; |
|
412 iState = EInfo; |
|
413 TRequestStatus* status = &iStatus; |
|
414 User::RequestComplete(status, KErrNone); |
|
415 SetActive(); |
|
416 } |
|
417 |
|
418 HBufC8* CPinPluginAO::GenerateKeyHashL(TPinValue& aPinValue, HBufC8*& aIdentityKey) |
|
419 { |
|
420 CSHA1* sha1 = CSHA1::NewL(); |
|
421 CleanupStack::PushL(sha1); |
|
422 HBufC8* pinValue = aPinValue.AllocLC(); |
|
423 TPtrC8 hash = sha1->Hash(*pinValue); |
|
424 CleanupStack::PopAndDestroy(pinValue); |
|
425 aIdentityKey = hash.AllocLC(); |
|
426 TPtrC8 hash1 = sha1->Hash(hash); |
|
427 HBufC8* idkeyHash = hash1.AllocL(); |
|
428 CleanupStack::Pop(aIdentityKey); |
|
429 CleanupStack::PopAndDestroy(sha1); |
|
430 return idkeyHash; |
|
431 } |
|
432 |
|
433 |
|
434 void CPinPluginAO::GenerateUniquePinsL(RPointerArray<TPinValue>& aPinList, |
|
435 RPointerArray<HBufC8>& aIdKeyList, RPointerArray<HBufC8>& aIdKeyHashList) |
|
436 { |
|
437 TInt count = 4; |
|
438 while (count) |
|
439 { |
|
440 TPinValue* randomPin = new (ELeave) TPinValue; |
|
441 CleanupStack::PushL(randomPin); |
|
442 for (TInt k = 0; k < iNewPinSize ; k++) |
|
443 { |
|
444 TUint8 num = Math::Random(); |
|
445 num = num % 10; |
|
446 randomPin->AppendNum(num); |
|
447 } |
|
448 HBufC8* identityKey = NULL; |
|
449 HBufC8* identityKeyHash = GenerateKeyHashL(*randomPin, identityKey); |
|
450 CleanupStack::PushL(identityKeyHash); |
|
451 CleanupStack::PushL(identityKey); |
|
452 if (iPinPluginDb->IsUniquePin(*identityKeyHash)) |
|
453 { |
|
454 aIdKeyList.AppendL(identityKey); |
|
455 CleanupStack::Pop(identityKey); |
|
456 aIdKeyHashList.AppendL(identityKeyHash); |
|
457 CleanupStack::Pop(identityKeyHash); |
|
458 aPinList.AppendL(randomPin); |
|
459 CleanupStack::Pop(randomPin); |
|
460 count--; |
|
461 } |
|
462 } |
|
463 } |
|
464 |
|
465 |
|
466 |
|
467 |
|
468 |
|
469 |
|
470 |
|
471 |
|
472 |
|
473 |
|
474 |
|
475 |
|
476 |
|
477 |
|