First public contribution.
2 * Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
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".
9 * Initial Contributors:
10 * Nokia Corporation - initial contribution.
19 #include "CCheckedCertStore.h"
23 #include <x509certext.h>
26 #include <securityerr.h>
28 #include "certificateapps.h"
30 _LIT(KPanicCategory, "CCheckedCertStore");
31 #define assert(x) __ASSERT_ALWAYS((x), User::Panic(KPanicCategory, 1));
33 /////////////////////////////////////////////////////////////////////
35 /////////////////////////////////////////////////////////////////////
37 CCheckedCertStore::~CCheckedCertStore()
42 // Release the cert store - no need to release the token since this would
43 // have been done as part of MCTTokenInterface::Release()
49 CCheckedCertStore::CCheckedCertStore(MCTCertStore& aTokenIF, RProperty& aProperty)
50 : CActive(EPriorityStandard),
52 iPSCertstoreChangePropertyRef(aProperty)
54 // need to add reference since we now have the token
55 iCertStore.Token().AddRef();
58 CCheckedCertStore::CCheckedCertStore(MCTWritableCertStore& aTokenIF, RProperty& aProperty)
59 : CActive(EPriorityStandard),
61 iWritableCertStore(&aTokenIF),
62 iPSCertstoreChangePropertyRef(aProperty)
64 // need to add reference since we now have the token
65 iCertStore.Token().AddRef();
68 /*static*/ CCheckedCertStore* CCheckedCertStore::NewCheckedCertStoreL(MCTTokenInterface* aTokenIF, RProperty& aProperty)
71 MCTCertStore& tokenInterface = static_cast<MCTCertStore&>(*aTokenIF);
72 CCheckedCertStore* me = new (ELeave) CCheckedCertStore(tokenInterface, aProperty);
73 CleanupReleasePushL(*me);
79 /*static*/ CCheckedCertStore* CCheckedCertStore::NewCheckedWritableCertStoreL(MCTTokenInterface* aTokenIF, RProperty& aProperty)
82 MCTWritableCertStore& tokenInterface = static_cast<MCTWritableCertStore&>(*aTokenIF);
83 CCheckedCertStore* me = new (ELeave) CCheckedCertStore(tokenInterface, aProperty);
84 CleanupReleasePushL(*me);
90 void CCheckedCertStore::ConstructL()
92 User::LeaveIfError(iFs.Connect());
93 CActiveScheduler::Add(this);
96 MCTToken& CCheckedCertStore::Token()
98 return iCertStore.Token();
101 // May require checking against the keystore *after* calling the server to complete
103 void CCheckedCertStore::List(RMPointerArray<CCTCertInfo>& aCerts, const CCertAttributeFilter& aFilter,
104 TRequestStatus& aStatus)
106 assert(iState == EIdleState);
108 // Only allow filtering on key usage for user certs
109 if (aFilter.iKeyUsage != EX509UsageAll &&
110 (!aFilter.iOwnerTypeIsSet || EUserCertificate != aFilter.iOwnerType))
112 TRequestStatus* status = &aStatus;
113 User::RequestComplete(status, KErrNotSupported);
117 // Store caller parameters for later reference
118 iCallerCerts = &aCerts;
119 iCallerFilter = &aFilter;
120 aStatus = KRequestPending;
121 iCallerStatus = &aStatus;
124 iCertStore.List(aCerts, aFilter, iStatus);
128 void CCheckedCertStore::CancelList()
130 if (iState == EList ||
131 iState == EInitKeyStoreForList ||
132 iState == EGetKeyInfosForList)
138 void CCheckedCertStore::GetCert(CCTCertInfo*& aCertInfo, const TCTTokenObjectHandle& aHandle,
139 TRequestStatus& aStatus)
141 assert(iState == EIdleState);
142 iCertStore.GetCert(aCertInfo, aHandle, aStatus);
145 void CCheckedCertStore::CancelGetCert()
147 iCertStore.CancelGetCert();
150 void CCheckedCertStore::Applications(const CCTCertInfo& aCertInfo, RArray<TUid>& aApplications,
151 TRequestStatus& aStatus)
153 assert(iState == EIdleState);
154 iCertStore.Applications(aCertInfo, aApplications, aStatus);
157 void CCheckedCertStore::CancelApplications()
159 iCertStore.CancelApplications();
162 void CCheckedCertStore::IsApplicable(const CCTCertInfo& aCertInfo, TUid aApplication,
163 TBool& aIsApplicable, TRequestStatus& aStatus)
165 assert(iState == EIdleState);
166 iCertStore.IsApplicable(aCertInfo, aApplication, aIsApplicable, aStatus);
169 void CCheckedCertStore::CancelIsApplicable()
171 iCertStore.CancelIsApplicable();
174 void CCheckedCertStore::Trusted(const CCTCertInfo& aCertInfo, TBool& aTrusted,
175 TRequestStatus& aStatus)
177 assert(iState == EIdleState);
178 iCertStore.Trusted(aCertInfo, aTrusted, aStatus);
181 void CCheckedCertStore::CancelTrusted()
183 iCertStore.CancelTrusted();
186 void CCheckedCertStore::Retrieve(const CCTCertInfo& aCertInfo, TDes8& aEncodedCert,
187 TRequestStatus& aStatus)
189 assert(iState == EIdleState);
190 iCertStore.Retrieve(aCertInfo, aEncodedCert, aStatus);
193 void CCheckedCertStore::CancelRetrieve()
195 iCertStore.CancelRetrieve();
199 void CCheckedCertStore::Add(const TDesC& aLabel,
200 TCertificateFormat aFormat,
201 TCertificateOwnerType aCertificateOwnerType,
202 const TKeyIdentifier* aSubjectKeyId,
203 const TKeyIdentifier* aIssuerKeyId,
205 TRequestStatus& aStatus)
207 // default value for aDeletable = ETrue
208 Add( aLabel, aFormat, aCertificateOwnerType, aSubjectKeyId,
209 aIssuerKeyId, aCert, ETrue, aStatus );
212 // new Add(.., TBool aDeletable, ..) method from MCTWritableCertStore
213 void CCheckedCertStore::Add( const TDesC& aLabel,
214 TCertificateFormat aFormat,
215 TCertificateOwnerType aCertificateOwnerType,
216 const TKeyIdentifier* aSubjectKeyId,
217 const TKeyIdentifier* aIssuerKeyId,
219 const TBool aDeletable,
220 TRequestStatus& aStatus
223 assert(iWritableCertStore);
224 assert(iState == EIdleState);
226 TRAPD(err, DoAddL( aLabel,
228 aCertificateOwnerType,
242 void CCheckedCertStore::DoAddL( const TDesC& aLabel,
243 TCertificateFormat aFormat,
244 TCertificateOwnerType aCertificateOwnerType,
245 const TKeyIdentifier* aSubjectKeyId,
246 const TKeyIdentifier* aIssuerKeyId,
248 const TBool aDeletable,
249 TRequestStatus& aStatus)
252 // Store caller parameters for later use
253 aStatus = KRequestPending;
254 iCallerStatus = &aStatus;
256 iCertificateOwnerType = aCertificateOwnerType;
257 iSubjectKeyId = aSubjectKeyId;
258 iIssuerKeyId = aIssuerKeyId;
259 iDeletable = aDeletable;
261 // Store (copy) aCert (cert data) into iCertificate[:HBufC8]
262 assert(!iCertificate);
263 iCertificate = HBufC8::NewMaxL(aCert.Size());
264 TPtr8 theCert(iCertificate->Des());
268 // Store (copy) aLabel (cert label) into iCertLabel[:HBufC]
270 iCertLabel = HBufC::NewMaxL(aLabel.Length());
271 TPtr theLabel(iCertLabel->Des());
273 theLabel.Copy(aLabel);
275 // Checks subject key ID with certificate data, and sets up key filter
276 // which is used later to determine whether there is a key with the
277 // appropriate subject and thus, if it is OK to add the certificate
278 ComputeAndCheckSubjectKeyIdL();
280 // Is keystore checking required? Only if a user certificate
281 if (EUserCertificate==aCertificateOwnerType)
283 InitialiseKeyStoreL(EInitKeyStoreForAdd);
289 // try new method first
290 iWritableCertStore->Add( *iCertLabel, // call new method
292 iCertificateOwnerType,
296 iDeletable, // with deletable param
304 void CCheckedCertStore::CancelAdd()
306 if (iState == EInitKeyStoreForAdd ||
307 iState == EGetKeyInfosForAdd ||
308 iState == EAdd || iState == EOldAdd )
314 void CCheckedCertStore::ComputeAndCheckSubjectKeyIdL()
318 case EX509Certificate:
320 TPtr8 thePtr(iCertificate->Des());
321 CX509Certificate* cert = CX509Certificate::NewLC(thePtr);
323 TKeyUsageX509 x509Usage = EX509UsageNone;
324 const CX509CertExtension* ext = cert->Extension(KKeyUsage);
328 x509Usage = EX509UsageAll;
332 CX509KeyUsageExt* keyUsageExt = CX509KeyUsageExt::NewLC(ext->Data());
334 if (keyUsageExt->IsSet(EX509DigitalSignature))
336 x509Usage |= EX509UsageDigitalSignature;
338 if (keyUsageExt->IsSet(EX509NonRepudiation))
340 x509Usage |= EX509UsageNonRepudiation;
342 if (keyUsageExt->IsSet(EX509KeyEncipherment))
344 x509Usage |= EX509UsageKeyEncipherment;
346 if (keyUsageExt->IsSet(EX509DataEncipherment))
348 x509Usage |= EX509UsageDataEncipherment;
350 if (keyUsageExt->IsSet(EX509KeyAgreement))
352 x509Usage |= EX509UsageKeyAgreement;
354 if (keyUsageExt->IsSet(EX509KeyCertSign))
356 x509Usage |= EX509UsageKeyCertSign;
358 if (keyUsageExt->IsSet(EX509CRLSign))
360 x509Usage |= EX509UsageCRLSign;
362 if (keyUsageExt->IsSet(EX509EncipherOnly))
364 x509Usage |= EX509UsageEncipherOnly;
366 if (keyUsageExt->IsSet(EX509DecipherOnly))
368 x509Usage |= EX509UsageDecipherOnly;
371 CleanupStack::PopAndDestroy(keyUsageExt);
374 iKeyFilter.iUsage = KeyUsageX509ToPKCS15Private(x509Usage);
376 iComputedSubjectKeyId.Zero();
377 // For non-user ceriticates (i.e. CA certificates), we use the SubjectKeyIdentifier API, as it
378 // tries to get the extension from cert., and calculates a value only if it is not found. This behaviour corresponds to the RFC.
379 // For user ceritificates, the key identifier is used for matching key store with cert store, so we cannot use the value in the certificate itself.
380 if (iCertificateOwnerType != EUserCertificate)
382 iComputedSubjectKeyId = cert->SubjectKeyIdentifierL();
386 // For non-CA certs, use the recommended method of computing it from RFC3280, section 4.2.1.2
387 iComputedSubjectKeyId = cert->KeyIdentifierL();
389 if (!iSubjectKeyId || *iSubjectKeyId == KNullDesC8)
391 iSubjectKeyId = &iComputedSubjectKeyId;
393 else if (iSubjectKeyId->Compare(iComputedSubjectKeyId)!=0)
394 {// Different subject ids
395 User::Leave(KErrArgument);
398 CleanupStack::PopAndDestroy(cert);
402 case EWTLSCertificate:
404 CCertificate* cert = CWTLSCertificate::NewLC(*iCertificate);
405 iComputedSubjectKeyId = cert->KeyIdentifierL();
406 if (!iSubjectKeyId || *iSubjectKeyId == KNullDesC8)
408 iSubjectKeyId = &iComputedSubjectKeyId;
410 else if (iSubjectKeyId->Compare(iComputedSubjectKeyId)!=0)
411 {// Different subject ids
412 User::Leave(KErrArgument);
415 CleanupStack::PopAndDestroy(cert);
419 case EX509CertificateUrl:
421 iKeyFilter.iUsage = EPKCS15UsageAll;
423 if (!iSubjectKeyId || *iSubjectKeyId == KNullDesC8)
425 User::Leave(KErrArgument);
431 User::Leave(KErrNotSupported);
435 iKeyFilter.iKeyId = *iSubjectKeyId;
438 void CCheckedCertStore::Remove(const CCTCertInfo& aCertInfo, TRequestStatus& aStatus)
440 assert(iWritableCertStore);
441 assert(iState == EIdleState);
442 aStatus = KRequestPending;
443 iCallerStatus = &aStatus;
445 iWritableCertStore->Remove(aCertInfo, iStatus);
449 void CCheckedCertStore::CancelRemove()
451 if (iState == ERemove)
457 void CCheckedCertStore::SetApplicability(const CCTCertInfo& aCertInfo, const RArray<TUid>& aApplications, TRequestStatus &aStatus)
459 assert(iWritableCertStore);
460 assert(iState == EIdleState);
461 aStatus = KRequestPending;
462 iCallerStatus = &aStatus;
463 iState = ESetApplicability;
464 iWritableCertStore->SetApplicability(aCertInfo, aApplications, iStatus);
468 void CCheckedCertStore::CancelSetApplicability()
470 if (iState == ESetApplicability)
476 void CCheckedCertStore::SetTrust(const CCTCertInfo& aCertInfo, TBool aTrusted, TRequestStatus& aStatus)
478 assert(iWritableCertStore);
479 assert(iState == EIdleState);
480 aStatus = KRequestPending;
481 iCallerStatus = &aStatus;
483 iWritableCertStore->SetTrust(aCertInfo, aTrusted, iStatus);
487 void CCheckedCertStore::CancelSetTrust()
489 if (iState == ESetTrust)
495 TInt CCheckedCertStore::RunError(TInt aError)
501 void CCheckedCertStore::DoCancel()
503 // (see notes on cancellation in CUnifiedCertStore::DoCancel)
507 case EGetKeyInfosForList:
510 case ESetApplicability:
512 if (iStatus == KRequestPending)
514 // Attempt to cancel outstanding request and pass status back to
516 CancelOutstandingRequest();
517 Complete(iStatus.Int());
521 // We've already been completed - call RunL() to process results
522 // and complete client
532 CancelOutstandingRequest();
533 Complete(KErrCancel);
538 void CCheckedCertStore::CancelOutstandingRequest()
543 iCertStore.CancelList();
546 case EInitKeyStoreForAdd:
547 case EInitKeyStoreForList:
548 assert(iUnifiedKeyStore);
549 iUnifiedKeyStore->CancelInitialize();
552 case EGetKeyInfosForAdd:
553 case EGetKeyInfosForList:
554 assert(iUnifiedKeyStore);
555 iUnifiedKeyStore->CancelList();
560 assert(iWritableCertStore);
561 iWritableCertStore->CancelAdd();
565 assert(iWritableCertStore);
566 iWritableCertStore->CancelRemove();
569 case ESetApplicability:
570 assert(iWritableCertStore);
571 iWritableCertStore->CancelSetApplicability();
575 assert(iWritableCertStore);
576 iWritableCertStore->CancelSetTrust();
585 Complete(KErrCancel);
588 void CCheckedCertStore::RunL()
590 assert(iCallerStatus);
592 // we allow only KErrNone OR, possibly, KErrNotSupported after new Add()
593 // otherwise - Leave!
594 if (iStatus!=KErrNone &&
595 !(iStatus==KErrNotSupported && iState==EAdd) &&
596 !(iStatus == KErrNotFound && (iState==EList || iState==EGetKeyInfosForList || iState==EInitKeyStoreForList)))
598 User::Leave(iStatus.Int());
604 if (iCallerFilter->iKeyUsage == EX509UsageAll)
606 // No key usage filter, so we're done
611 // Set up key filter according list cert parameters
612 if (iCallerFilter->iSubjectKeyIdIsSet)
614 iKeyFilter.iKeyId = iCallerFilter->iSubjectKeyId;
618 iKeyFilter.iKeyId = KNullDesC8;
620 iKeyFilter.iUsage = KeyUsageX509ToPKCS15Private(iCallerFilter->iKeyUsage);
621 InitialiseKeyStoreL(EInitKeyStoreForList);
625 case EInitKeyStoreForAdd:
626 case EInitKeyStoreForList:
627 assert(iUnifiedKeyStore);
628 iState = (iState == EInitKeyStoreForAdd) ? EGetKeyInfosForAdd : EGetKeyInfosForList;
629 iUnifiedKeyStore->List(iKeyInfos, iKeyFilter, iStatus);
633 case EGetKeyInfosForList:
634 BuildCheckedCertificateListL(); // Not async
638 case EGetKeyInfosForAdd:
639 // We have a filter list of keys - there should be one with
640 // the appropriate subject if we are to add it
641 if (iKeyInfos.Count() == 0)
643 // The private key can't be found in any key store
644 Complete(KErrPrivateKeyNotFound);
648 // OK to go ahead and add the key
649 assert(iWritableCertStore);
652 // try to use new Add(.., TBool aDeletable, ..)
653 // if it's not supported it will return with
654 // iStatus set to KErrNotSupported
655 iWritableCertStore->Add( *iCertLabel, // call new Add() method
657 iCertificateOwnerType,
661 iDeletable, // with deletable param
668 if (iStatus!=KErrNotSupported)
670 // Set published property
671 iPSCertstoreChangePropertyRef.Set(KUnifiedCertStorePropertyCat, // category
672 EUnifiedCertStoreFlag, // key
675 // when here means MCTWritableCertStore was able to find
676 // child's new Add(..,aDeletable,..) method
677 // thus, ok and complete with whatever result it returned
678 Complete(iStatus.Int());
682 // here: call to the new Add() method above didn't work,
683 // try to call old Add() method
685 iStatus = KRequestPending;
686 iWritableCertStore->Add( *iCertLabel,
688 iCertificateOwnerType,
699 case ESetApplicability:
701 // Set published property
702 iPSCertstoreChangePropertyRef.Set(KUnifiedCertStorePropertyCat, // category
703 EUnifiedCertStoreFlag, // key
705 Complete(iStatus.Int());
714 void CCheckedCertStore::InitialiseKeyStoreL(TState aNextState)
716 assert(aNextState == EInitKeyStoreForAdd || aNextState == EInitKeyStoreForList);
717 assert(!iUnifiedKeyStore);
719 iUnifiedKeyStore = CUnifiedKeyStore::NewL(iFs);
720 iUnifiedKeyStore->Initialize(iStatus);
725 void CCheckedCertStore::BuildCheckedCertificateListL()
727 TInt certCount = iCallerCerts->Count();
728 TInt keyCount = iKeyInfos.Count();
730 // Iterate backwards through cert array so remove doesn't affect indicies
731 for (TInt i = certCount - 1 ; i >= 0 ; --i)
733 CCTCertInfo* certInfo = (*iCallerCerts)[i];
735 // It's problem in the certstore implementation if the list contains NULL pointers
738 // Check for key with corresponding id
739 TBool accept = EFalse;
740 for (TInt j = 0 ; j < keyCount ; ++j)
742 if (iKeyInfos[j]->ID()==certInfo->SubjectKeyId())
749 // If we don't have it, remove and release the cert info
752 iCallerCerts->Remove(i);
758 void CCheckedCertStore::Complete(TInt aError)
762 User::RequestComplete(iCallerStatus, aError);
767 void CCheckedCertStore::Cleanup()
769 // Reset the state machine
772 iSubjectKeyId = NULL;
781 delete iUnifiedKeyStore;
782 iUnifiedKeyStore = 0;
785 iCallerFilter = NULL;