--- a/cryptoservices/certificateandkeymgmt/certstore/CCheckedCertStore.cpp Tue Jul 21 01:04:32 2009 +0100
+++ b/cryptoservices/certificateandkeymgmt/certstore/CCheckedCertStore.cpp Thu Sep 10 14:01:51 2009 +0300
@@ -1,786 +1,786 @@
-/*
-* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
-* All rights reserved.
-* This component and the accompanying materials are made available
-* under the terms of the License "Eclipse Public License v1.0"
-* which accompanies this distribution, and is available
-* at the URL "http://www.eclipse.org/legal/epl-v10.html".
-*
-* Initial Contributors:
-* Nokia Corporation - initial contribution.
-*
-* Contributors:
-*
-* Description:
-*
-*/
-
-
-#include "CCheckedCertStore.h"
-
-#include <signed.h>
-#include <x509cert.h>
-#include <x509certext.h>
-#include <wtlscert.h>
-#include <x509keys.h>
-#include <securityerr.h>
-
-#include "certificateapps.h"
-
-_LIT(KPanicCategory, "CCheckedCertStore");
-#define assert(x) __ASSERT_ALWAYS((x), User::Panic(KPanicCategory, 1));
-
-/////////////////////////////////////////////////////////////////////
-// CCheckedCertStore
-/////////////////////////////////////////////////////////////////////
-
-CCheckedCertStore::~CCheckedCertStore()
- {
- Cancel();
- Cleanup();
-
- // Release the cert store - no need to release the token since this would
- // have been done as part of MCTTokenInterface::Release()
- iCertStore.Release();
-
- iFs.Close();
- }
-
-CCheckedCertStore::CCheckedCertStore(MCTCertStore& aTokenIF, RProperty& aProperty)
-: CActive(EPriorityStandard),
- iCertStore(aTokenIF),
- iPSCertstoreChangePropertyRef(aProperty)
- {
- // need to add reference since we now have the token
- iCertStore.Token().AddRef();
- }
-
-CCheckedCertStore::CCheckedCertStore(MCTWritableCertStore& aTokenIF, RProperty& aProperty)
-: CActive(EPriorityStandard),
- iCertStore(aTokenIF),
- iWritableCertStore(&aTokenIF),
- iPSCertstoreChangePropertyRef(aProperty)
- {
- // need to add reference since we now have the token
- iCertStore.Token().AddRef();
- }
-
-/*static*/ CCheckedCertStore* CCheckedCertStore::NewCheckedCertStoreL(MCTTokenInterface* aTokenIF, RProperty& aProperty)
- {
- assert(aTokenIF);
- MCTCertStore& tokenInterface = static_cast<MCTCertStore&>(*aTokenIF);
- CCheckedCertStore* me = new (ELeave) CCheckedCertStore(tokenInterface, aProperty);
- CleanupReleasePushL(*me);
- me->ConstructL();
- CleanupStack::Pop();
- return (me);
- }
-
-/*static*/ CCheckedCertStore* CCheckedCertStore::NewCheckedWritableCertStoreL(MCTTokenInterface* aTokenIF, RProperty& aProperty)
- {
- assert(aTokenIF);
- MCTWritableCertStore& tokenInterface = static_cast<MCTWritableCertStore&>(*aTokenIF);
- CCheckedCertStore* me = new (ELeave) CCheckedCertStore(tokenInterface, aProperty);
- CleanupReleasePushL(*me);
- me->ConstructL();
- CleanupStack::Pop();
- return (me);
- }
-
-void CCheckedCertStore::ConstructL()
- {
- User::LeaveIfError(iFs.Connect());
- CActiveScheduler::Add(this);
- }
-
-MCTToken& CCheckedCertStore::Token()
- {
- return iCertStore.Token();
- }
-
-// May require checking against the keystore *after* calling the server to complete
-// the List request
-void CCheckedCertStore::List(RMPointerArray<CCTCertInfo>& aCerts, const CCertAttributeFilter& aFilter,
- TRequestStatus& aStatus)
- {
- assert(iState == EIdleState);
-
- // Only allow filtering on key usage for user certs
- if (aFilter.iKeyUsage != EX509UsageAll &&
- (!aFilter.iOwnerTypeIsSet || EUserCertificate != aFilter.iOwnerType))
- {
- TRequestStatus* status = &aStatus;
- User::RequestComplete(status, KErrNotSupported);
- return;
- }
-
- // Store caller parameters for later reference
- iCallerCerts = &aCerts;
- iCallerFilter = &aFilter;
- aStatus = KRequestPending;
- iCallerStatus = &aStatus;
-
- iState = EList;
- iCertStore.List(aCerts, aFilter, iStatus);
- SetActive();
- }
-
-void CCheckedCertStore::CancelList()
- {
- if (iState == EList ||
- iState == EInitKeyStoreForList ||
- iState == EGetKeyInfosForList)
- {
- Cancel();
- }
- }
-
-void CCheckedCertStore::GetCert(CCTCertInfo*& aCertInfo, const TCTTokenObjectHandle& aHandle,
- TRequestStatus& aStatus)
- {
- assert(iState == EIdleState);
- iCertStore.GetCert(aCertInfo, aHandle, aStatus);
- }
-
-void CCheckedCertStore::CancelGetCert()
- {
- iCertStore.CancelGetCert();
- }
-
-void CCheckedCertStore::Applications(const CCTCertInfo& aCertInfo, RArray<TUid>& aApplications,
- TRequestStatus& aStatus)
- {
- assert(iState == EIdleState);
- iCertStore.Applications(aCertInfo, aApplications, aStatus);
- }
-
-void CCheckedCertStore::CancelApplications()
- {
- iCertStore.CancelApplications();
- }
-
-void CCheckedCertStore::IsApplicable(const CCTCertInfo& aCertInfo, TUid aApplication,
- TBool& aIsApplicable, TRequestStatus& aStatus)
- {
- assert(iState == EIdleState);
- iCertStore.IsApplicable(aCertInfo, aApplication, aIsApplicable, aStatus);
- }
-
-void CCheckedCertStore::CancelIsApplicable()
- {
- iCertStore.CancelIsApplicable();
- }
-
-void CCheckedCertStore::Trusted(const CCTCertInfo& aCertInfo, TBool& aTrusted,
- TRequestStatus& aStatus)
- {
- assert(iState == EIdleState);
- iCertStore.Trusted(aCertInfo, aTrusted, aStatus);
- }
-
-void CCheckedCertStore::CancelTrusted()
- {
- iCertStore.CancelTrusted();
- }
-
-void CCheckedCertStore::Retrieve(const CCTCertInfo& aCertInfo, TDes8& aEncodedCert,
- TRequestStatus& aStatus)
- {
- assert(iState == EIdleState);
- iCertStore.Retrieve(aCertInfo, aEncodedCert, aStatus);
- }
-
-void CCheckedCertStore::CancelRetrieve()
- {
- iCertStore.CancelRetrieve();
- }
-
-
-void CCheckedCertStore::Add(const TDesC& aLabel,
- TCertificateFormat aFormat,
- TCertificateOwnerType aCertificateOwnerType,
- const TKeyIdentifier* aSubjectKeyId,
- const TKeyIdentifier* aIssuerKeyId,
- const TDesC8& aCert,
- TRequestStatus& aStatus)
- {
- // default value for aDeletable = ETrue
- Add( aLabel, aFormat, aCertificateOwnerType, aSubjectKeyId,
- aIssuerKeyId, aCert, ETrue, aStatus );
- }
-
-// new Add(.., TBool aDeletable, ..) method from MCTWritableCertStore
-void CCheckedCertStore::Add( const TDesC& aLabel,
- TCertificateFormat aFormat,
- TCertificateOwnerType aCertificateOwnerType,
- const TKeyIdentifier* aSubjectKeyId,
- const TKeyIdentifier* aIssuerKeyId,
- const TDesC8& aCert,
- const TBool aDeletable,
- TRequestStatus& aStatus
- )
- {
- assert(iWritableCertStore);
- assert(iState == EIdleState);
-
- TRAPD(err, DoAddL( aLabel,
- aFormat,
- aCertificateOwnerType,
- aSubjectKeyId,
- aIssuerKeyId,
- aCert,
- aDeletable,
- aStatus ) );
-
- if (err != KErrNone)
- {
- Complete(err);
- }
- }
-
-
-void CCheckedCertStore::DoAddL( const TDesC& aLabel,
- TCertificateFormat aFormat,
- TCertificateOwnerType aCertificateOwnerType,
- const TKeyIdentifier* aSubjectKeyId,
- const TKeyIdentifier* aIssuerKeyId,
- const TDesC8& aCert,
- const TBool aDeletable,
- TRequestStatus& aStatus)
- {
-
- // Store caller parameters for later use
- aStatus = KRequestPending;
- iCallerStatus = &aStatus;
- iFormat = aFormat;
- iCertificateOwnerType = aCertificateOwnerType;
- iSubjectKeyId = aSubjectKeyId;
- iIssuerKeyId = aIssuerKeyId;
- iDeletable = aDeletable;
-
- // Store (copy) aCert (cert data) into iCertificate[:HBufC8]
- assert(!iCertificate);
- iCertificate = HBufC8::NewMaxL(aCert.Size());
- TPtr8 theCert(iCertificate->Des());
- theCert.FillZ();
- theCert.Copy(aCert);
-
- // Store (copy) aLabel (cert label) into iCertLabel[:HBufC]
- assert(!iCertLabel);
- iCertLabel = HBufC::NewMaxL(aLabel.Length());
- TPtr theLabel(iCertLabel->Des());
- theLabel.FillZ();
- theLabel.Copy(aLabel);
-
- // Checks subject key ID with certificate data, and sets up key filter
- // which is used later to determine whether there is a key with the
- // appropriate subject and thus, if it is OK to add the certificate
- ComputeAndCheckSubjectKeyIdL();
-
- // Is keystore checking required? Only if a user certificate
- if (EUserCertificate==aCertificateOwnerType)
- {
- InitialiseKeyStoreL(EInitKeyStoreForAdd);
- }
- else
- {
- iState = EAdd;
-
- // try new method first
- iWritableCertStore->Add( *iCertLabel, // call new method
- iFormat,
- iCertificateOwnerType,
- iSubjectKeyId,
- iIssuerKeyId,
- *iCertificate,
- iDeletable, // with deletable param
- iStatus );
- SetActive();
- }
- }
-
-
-
-void CCheckedCertStore::CancelAdd()
- {
- if (iState == EInitKeyStoreForAdd ||
- iState == EGetKeyInfosForAdd ||
- iState == EAdd || iState == EOldAdd )
- {
- Cancel();
- }
- }
-
-void CCheckedCertStore::ComputeAndCheckSubjectKeyIdL()
- {
- switch (iFormat)
- {
- case EX509Certificate:
- {
- TPtr8 thePtr(iCertificate->Des());
- CX509Certificate* cert = CX509Certificate::NewLC(thePtr);
-
- TKeyUsageX509 x509Usage = EX509UsageNone;
- const CX509CertExtension* ext = cert->Extension(KKeyUsage);
-
- if (!ext)
- {
- x509Usage = EX509UsageAll;
- }
- else
- {
- CX509KeyUsageExt* keyUsageExt = CX509KeyUsageExt::NewLC(ext->Data());
-
- if (keyUsageExt->IsSet(EX509DigitalSignature))
- {
- x509Usage |= EX509UsageDigitalSignature;
- }
- if (keyUsageExt->IsSet(EX509NonRepudiation))
- {
- x509Usage |= EX509UsageNonRepudiation;
- }
- if (keyUsageExt->IsSet(EX509KeyEncipherment))
- {
- x509Usage |= EX509UsageKeyEncipherment;
- }
- if (keyUsageExt->IsSet(EX509DataEncipherment))
- {
- x509Usage |= EX509UsageDataEncipherment;
- }
- if (keyUsageExt->IsSet(EX509KeyAgreement))
- {
- x509Usage |= EX509UsageKeyAgreement;
- }
- if (keyUsageExt->IsSet(EX509KeyCertSign))
- {
- x509Usage |= EX509UsageKeyCertSign;
- }
- if (keyUsageExt->IsSet(EX509CRLSign))
- {
- x509Usage |= EX509UsageCRLSign;
- }
- if (keyUsageExt->IsSet(EX509EncipherOnly))
- {
- x509Usage |= EX509UsageEncipherOnly;
- }
- if (keyUsageExt->IsSet(EX509DecipherOnly))
- {
- x509Usage |= EX509UsageDecipherOnly;
- }
-
- CleanupStack::PopAndDestroy(keyUsageExt);
- }
-
- iKeyFilter.iUsage = KeyUsageX509ToPKCS15Private(x509Usage);
-
- iComputedSubjectKeyId.Zero();
- // For non-user ceriticates (i.e. CA certificates), we use the SubjectKeyIdentifier API, as it
- // tries to get the extension from cert., and calculates a value only if it is not found. This behaviour corresponds to the RFC.
- // 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.
- if (iCertificateOwnerType != EUserCertificate)
- {
- iComputedSubjectKeyId = cert->SubjectKeyIdentifierL();
- }
- else
- {
- // For non-CA certs, use the recommended method of computing it from RFC3280, section 4.2.1.2
- iComputedSubjectKeyId = cert->KeyIdentifierL();
- }
- if (!iSubjectKeyId || *iSubjectKeyId == KNullDesC8)
- {
- iSubjectKeyId = &iComputedSubjectKeyId;
- }
- else if (iSubjectKeyId->Compare(iComputedSubjectKeyId)!=0)
- {// Different subject ids
- User::Leave(KErrArgument);
- }
-
- CleanupStack::PopAndDestroy(cert);
- }
- break;
-
- case EWTLSCertificate:
- {
- CCertificate* cert = CWTLSCertificate::NewLC(*iCertificate);
- iComputedSubjectKeyId = cert->KeyIdentifierL();
- if (!iSubjectKeyId || *iSubjectKeyId == KNullDesC8)
- {
- iSubjectKeyId = &iComputedSubjectKeyId;
- }
- else if (iSubjectKeyId->Compare(iComputedSubjectKeyId)!=0)
- {// Different subject ids
- User::Leave(KErrArgument);
- }
-
- CleanupStack::PopAndDestroy(cert);
- }
- break;
-
- case EX509CertificateUrl:
- {
- iKeyFilter.iUsage = EPKCS15UsageAll;
-
- if (!iSubjectKeyId || *iSubjectKeyId == KNullDesC8)
- {
- User::Leave(KErrArgument);
- }
- }
- break;
-
- default:
- User::Leave(KErrNotSupported);
- break;
- }
-
- iKeyFilter.iKeyId = *iSubjectKeyId;
- }
-
-void CCheckedCertStore::Remove(const CCTCertInfo& aCertInfo, TRequestStatus& aStatus)
- {
- assert(iWritableCertStore);
- assert(iState == EIdleState);
- aStatus = KRequestPending;
- iCallerStatus = &aStatus;
- iState = ERemove;
- iWritableCertStore->Remove(aCertInfo, iStatus);
- SetActive();
- }
-
-void CCheckedCertStore::CancelRemove()
- {
- if (iState == ERemove)
- {
- Cancel();
- }
- }
-
-void CCheckedCertStore::SetApplicability(const CCTCertInfo& aCertInfo, const RArray<TUid>& aApplications, TRequestStatus &aStatus)
- {
- assert(iWritableCertStore);
- assert(iState == EIdleState);
- aStatus = KRequestPending;
- iCallerStatus = &aStatus;
- iState = ESetApplicability;
- iWritableCertStore->SetApplicability(aCertInfo, aApplications, iStatus);
- SetActive();
- }
-
-void CCheckedCertStore::CancelSetApplicability()
- {
- if (iState == ESetApplicability)
- {
- Cancel();
- }
- }
-
-void CCheckedCertStore::SetTrust(const CCTCertInfo& aCertInfo, TBool aTrusted, TRequestStatus& aStatus)
- {
- assert(iWritableCertStore);
- assert(iState == EIdleState);
- aStatus = KRequestPending;
- iCallerStatus = &aStatus;
- iState = ESetTrust;
- iWritableCertStore->SetTrust(aCertInfo, aTrusted, iStatus);
- SetActive();
- }
-
-void CCheckedCertStore::CancelSetTrust()
- {
- if (iState == ESetTrust)
- {
- Cancel();
- }
- }
-
-TInt CCheckedCertStore::RunError(TInt aError)
- {
- Complete(aError);
- return KErrNone;
- }
-
-void CCheckedCertStore::DoCancel()
- {
- // (see notes on cancellation in CUnifiedCertStore::DoCancel)
-
- switch (iState)
- {
- case EGetKeyInfosForList:
- case EAdd:
- case ERemove:
- case ESetApplicability:
- case ESetTrust:
- if (iStatus == KRequestPending)
- {
- // Attempt to cancel outstanding request and pass status back to
- // client
- CancelOutstandingRequest();
- Complete(iStatus.Int());
- }
- else
- {
- // We've already been completed - call RunL() to process results
- // and complete client
- TRAPD(err, RunL());
- if (err != KErrNone)
- {
- RunError(err);
- }
- }
- break;
-
- default:
- CancelOutstandingRequest();
- Complete(KErrCancel);
- break;
- }
- }
-
-void CCheckedCertStore::CancelOutstandingRequest()
- {
- switch (iState)
- {
- case EList:
- iCertStore.CancelList();
- break;
-
- case EInitKeyStoreForAdd:
- case EInitKeyStoreForList:
- assert(iUnifiedKeyStore);
- iUnifiedKeyStore->CancelInitialize();
- break;
-
- case EGetKeyInfosForAdd:
- case EGetKeyInfosForList:
- assert(iUnifiedKeyStore);
- iUnifiedKeyStore->CancelList();
- break;
-
- case EAdd:
- case EOldAdd:
- assert(iWritableCertStore);
- iWritableCertStore->CancelAdd();
- break;
-
- case ERemove:
- assert(iWritableCertStore);
- iWritableCertStore->CancelRemove();
- break;
-
- case ESetApplicability:
- assert(iWritableCertStore);
- iWritableCertStore->CancelSetApplicability();
- break;
-
- case ESetTrust:
- assert(iWritableCertStore);
- iWritableCertStore->CancelSetTrust();
- break;
-
-
- default:
- assert(EFalse);
- break;
- }
-
- Complete(KErrCancel);
- }
-
-void CCheckedCertStore::RunL()
- {
- assert(iCallerStatus);
-
- // we allow only KErrNone OR, possibly, KErrNotSupported after new Add()
- // otherwise - Leave!
- if (iStatus!=KErrNone &&
- !(iStatus==KErrNotSupported && iState==EAdd) &&
- !(iStatus == KErrNotFound && (iState==EList || iState==EGetKeyInfosForList || iState==EInitKeyStoreForList)))
- {
- User::Leave(iStatus.Int());
- }
-
- switch (iState)
- {
- case EList:
- if (iCallerFilter->iKeyUsage == EX509UsageAll)
- {
- // No key usage filter, so we're done
- Complete(KErrNone);
- }
- else
- {
- // Set up key filter according list cert parameters
- if (iCallerFilter->iSubjectKeyIdIsSet)
- {
- iKeyFilter.iKeyId = iCallerFilter->iSubjectKeyId;
- }
- else
- {
- iKeyFilter.iKeyId = KNullDesC8;
- }
- iKeyFilter.iUsage = KeyUsageX509ToPKCS15Private(iCallerFilter->iKeyUsage);
- InitialiseKeyStoreL(EInitKeyStoreForList);
- }
- break;
-
- case EInitKeyStoreForAdd:
- case EInitKeyStoreForList:
- assert(iUnifiedKeyStore);
- iState = (iState == EInitKeyStoreForAdd) ? EGetKeyInfosForAdd : EGetKeyInfosForList;
- iUnifiedKeyStore->List(iKeyInfos, iKeyFilter, iStatus);
- SetActive();
- break;
-
- case EGetKeyInfosForList:
- BuildCheckedCertificateListL(); // Not async
- Complete(KErrNone);
- break;
-
- case EGetKeyInfosForAdd:
- // We have a filter list of keys - there should be one with
- // the appropriate subject if we are to add it
- if (iKeyInfos.Count() == 0)
- {
- // The private key can't be found in any key store
- Complete(KErrPrivateKeyNotFound);
- }
- else
- {
- // OK to go ahead and add the key
- assert(iWritableCertStore);
- iState = EAdd;
-
- // try to use new Add(.., TBool aDeletable, ..)
- // if it's not supported it will return with
- // iStatus set to KErrNotSupported
- iWritableCertStore->Add( *iCertLabel, // call new Add() method
- iFormat,
- iCertificateOwnerType,
- iSubjectKeyId,
- iIssuerKeyId,
- *iCertificate,
- iDeletable, // with deletable param
- iStatus);
- SetActive();
- }
- break;
-
- case EAdd:
- if (iStatus!=KErrNotSupported)
- {
- // Set published property
- iPSCertstoreChangePropertyRef.Set(KUnifiedCertStorePropertyCat, // category
- EUnifiedCertStoreFlag, // key
- 1); // value
-
- // when here means MCTWritableCertStore was able to find
- // child's new Add(..,aDeletable,..) method
- // thus, ok and complete with whatever result it returned
- Complete(iStatus.Int());
- }
- else
- {
- // here: call to the new Add() method above didn't work,
- // try to call old Add() method
- iState = EOldAdd;
- iStatus = KRequestPending;
- iWritableCertStore->Add( *iCertLabel,
- iFormat,
- iCertificateOwnerType,
- iSubjectKeyId,
- iIssuerKeyId,
- *iCertificate,
- iStatus);
- SetActive();
- }
- break;
-
- case EOldAdd:
- case ERemove:
- case ESetApplicability:
- case ESetTrust:
- // Set published property
- iPSCertstoreChangePropertyRef.Set(KUnifiedCertStorePropertyCat, // category
- EUnifiedCertStoreFlag, // key
- 1); // value
- Complete(iStatus.Int());
- break;
-
- default:
- assert(EFalse);
- break;
- }
- }
-
-void CCheckedCertStore::InitialiseKeyStoreL(TState aNextState)
- {
- assert(aNextState == EInitKeyStoreForAdd || aNextState == EInitKeyStoreForList);
- assert(!iUnifiedKeyStore);
-
- iUnifiedKeyStore = CUnifiedKeyStore::NewL(iFs);
- iUnifiedKeyStore->Initialize(iStatus);
- iState = aNextState;
- SetActive();
- }
-
-void CCheckedCertStore::BuildCheckedCertificateListL()
- {
- TInt certCount = iCallerCerts->Count();
- TInt keyCount = iKeyInfos.Count();
-
- // Iterate backwards through cert array so remove doesn't affect indicies
- for (TInt i = certCount - 1 ; i >= 0 ; --i)
- {
- CCTCertInfo* certInfo = (*iCallerCerts)[i];
-
- // It's problem in the certstore implementation if the list contains NULL pointers
- assert(certInfo);
-
- // Check for key with corresponding id
- TBool accept = EFalse;
- for (TInt j = 0 ; j < keyCount ; ++j)
- {
- if (iKeyInfos[j]->ID()==certInfo->SubjectKeyId())
- {
- accept = ETrue;
- break;
- }
- }
-
- // If we don't have it, remove and release the cert info
- if (!accept)
- {
- iCallerCerts->Remove(i);
- certInfo->Release();
- }
- }
- }
-
-void CCheckedCertStore::Complete(TInt aError)
- {
- if (iCallerStatus)
- {
- User::RequestComplete(iCallerStatus, aError);
- }
- Cleanup();
- }
-
-void CCheckedCertStore::Cleanup()
- {
- // Reset the state machine
- iState = EIdleState;
- iKeyInfos.Close();
- iSubjectKeyId = NULL;
- iIssuerKeyId = NULL;
-
- delete iCertLabel;
- iCertLabel = NULL;
-
- delete iCertificate;
- iCertificate = NULL;
-
- delete iUnifiedKeyStore;
- iUnifiedKeyStore = 0;
-
- iCallerCerts = NULL;
- iCallerFilter = NULL;
- }
+/*
+* Copyright (c) 2002-2009 Nokia Corporation and/or its subsidiary(-ies).
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of the License "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:
+*
+*/
+
+
+#include "CCheckedCertStore.h"
+
+#include <signed.h>
+#include <x509cert.h>
+#include <x509certext.h>
+#include <wtlscert.h>
+#include <x509keys.h>
+#include <securityerr.h>
+
+#include "certificateapps.h"
+
+_LIT(KPanicCategory, "CCheckedCertStore");
+#define assert(x) __ASSERT_ALWAYS((x), User::Panic(KPanicCategory, 1));
+
+/////////////////////////////////////////////////////////////////////
+// CCheckedCertStore
+/////////////////////////////////////////////////////////////////////
+
+CCheckedCertStore::~CCheckedCertStore()
+ {
+ Cancel();
+ Cleanup();
+
+ // Release the cert store - no need to release the token since this would
+ // have been done as part of MCTTokenInterface::Release()
+ iCertStore.Release();
+
+ iFs.Close();
+ }
+
+CCheckedCertStore::CCheckedCertStore(MCTCertStore& aTokenIF, RProperty& aProperty)
+: CActive(EPriorityStandard),
+ iCertStore(aTokenIF),
+ iPSCertstoreChangePropertyRef(aProperty)
+ {
+ // need to add reference since we now have the token
+ iCertStore.Token().AddRef();
+ }
+
+CCheckedCertStore::CCheckedCertStore(MCTWritableCertStore& aTokenIF, RProperty& aProperty)
+: CActive(EPriorityStandard),
+ iCertStore(aTokenIF),
+ iWritableCertStore(&aTokenIF),
+ iPSCertstoreChangePropertyRef(aProperty)
+ {
+ // need to add reference since we now have the token
+ iCertStore.Token().AddRef();
+ }
+
+/*static*/ CCheckedCertStore* CCheckedCertStore::NewCheckedCertStoreL(MCTTokenInterface* aTokenIF, RProperty& aProperty)
+ {
+ assert(aTokenIF);
+ MCTCertStore& tokenInterface = static_cast<MCTCertStore&>(*aTokenIF);
+ CCheckedCertStore* me = new (ELeave) CCheckedCertStore(tokenInterface, aProperty);
+ CleanupReleasePushL(*me);
+ me->ConstructL();
+ CleanupStack::Pop();
+ return (me);
+ }
+
+/*static*/ CCheckedCertStore* CCheckedCertStore::NewCheckedWritableCertStoreL(MCTTokenInterface* aTokenIF, RProperty& aProperty)
+ {
+ assert(aTokenIF);
+ MCTWritableCertStore& tokenInterface = static_cast<MCTWritableCertStore&>(*aTokenIF);
+ CCheckedCertStore* me = new (ELeave) CCheckedCertStore(tokenInterface, aProperty);
+ CleanupReleasePushL(*me);
+ me->ConstructL();
+ CleanupStack::Pop();
+ return (me);
+ }
+
+void CCheckedCertStore::ConstructL()
+ {
+ User::LeaveIfError(iFs.Connect());
+ CActiveScheduler::Add(this);
+ }
+
+MCTToken& CCheckedCertStore::Token()
+ {
+ return iCertStore.Token();
+ }
+
+// May require checking against the keystore *after* calling the server to complete
+// the List request
+void CCheckedCertStore::List(RMPointerArray<CCTCertInfo>& aCerts, const CCertAttributeFilter& aFilter,
+ TRequestStatus& aStatus)
+ {
+ assert(iState == EIdleState);
+
+ // Only allow filtering on key usage for user certs
+ if (aFilter.iKeyUsage != EX509UsageAll &&
+ (!aFilter.iOwnerTypeIsSet || EUserCertificate != aFilter.iOwnerType))
+ {
+ TRequestStatus* status = &aStatus;
+ User::RequestComplete(status, KErrNotSupported);
+ return;
+ }
+
+ // Store caller parameters for later reference
+ iCallerCerts = &aCerts;
+ iCallerFilter = &aFilter;
+ aStatus = KRequestPending;
+ iCallerStatus = &aStatus;
+
+ iState = EList;
+ iCertStore.List(aCerts, aFilter, iStatus);
+ SetActive();
+ }
+
+void CCheckedCertStore::CancelList()
+ {
+ if (iState == EList ||
+ iState == EInitKeyStoreForList ||
+ iState == EGetKeyInfosForList)
+ {
+ Cancel();
+ }
+ }
+
+void CCheckedCertStore::GetCert(CCTCertInfo*& aCertInfo, const TCTTokenObjectHandle& aHandle,
+ TRequestStatus& aStatus)
+ {
+ assert(iState == EIdleState);
+ iCertStore.GetCert(aCertInfo, aHandle, aStatus);
+ }
+
+void CCheckedCertStore::CancelGetCert()
+ {
+ iCertStore.CancelGetCert();
+ }
+
+void CCheckedCertStore::Applications(const CCTCertInfo& aCertInfo, RArray<TUid>& aApplications,
+ TRequestStatus& aStatus)
+ {
+ assert(iState == EIdleState);
+ iCertStore.Applications(aCertInfo, aApplications, aStatus);
+ }
+
+void CCheckedCertStore::CancelApplications()
+ {
+ iCertStore.CancelApplications();
+ }
+
+void CCheckedCertStore::IsApplicable(const CCTCertInfo& aCertInfo, TUid aApplication,
+ TBool& aIsApplicable, TRequestStatus& aStatus)
+ {
+ assert(iState == EIdleState);
+ iCertStore.IsApplicable(aCertInfo, aApplication, aIsApplicable, aStatus);
+ }
+
+void CCheckedCertStore::CancelIsApplicable()
+ {
+ iCertStore.CancelIsApplicable();
+ }
+
+void CCheckedCertStore::Trusted(const CCTCertInfo& aCertInfo, TBool& aTrusted,
+ TRequestStatus& aStatus)
+ {
+ assert(iState == EIdleState);
+ iCertStore.Trusted(aCertInfo, aTrusted, aStatus);
+ }
+
+void CCheckedCertStore::CancelTrusted()
+ {
+ iCertStore.CancelTrusted();
+ }
+
+void CCheckedCertStore::Retrieve(const CCTCertInfo& aCertInfo, TDes8& aEncodedCert,
+ TRequestStatus& aStatus)
+ {
+ assert(iState == EIdleState);
+ iCertStore.Retrieve(aCertInfo, aEncodedCert, aStatus);
+ }
+
+void CCheckedCertStore::CancelRetrieve()
+ {
+ iCertStore.CancelRetrieve();
+ }
+
+
+void CCheckedCertStore::Add(const TDesC& aLabel,
+ TCertificateFormat aFormat,
+ TCertificateOwnerType aCertificateOwnerType,
+ const TKeyIdentifier* aSubjectKeyId,
+ const TKeyIdentifier* aIssuerKeyId,
+ const TDesC8& aCert,
+ TRequestStatus& aStatus)
+ {
+ // default value for aDeletable = ETrue
+ Add( aLabel, aFormat, aCertificateOwnerType, aSubjectKeyId,
+ aIssuerKeyId, aCert, ETrue, aStatus );
+ }
+
+// new Add(.., TBool aDeletable, ..) method from MCTWritableCertStore
+void CCheckedCertStore::Add( const TDesC& aLabel,
+ TCertificateFormat aFormat,
+ TCertificateOwnerType aCertificateOwnerType,
+ const TKeyIdentifier* aSubjectKeyId,
+ const TKeyIdentifier* aIssuerKeyId,
+ const TDesC8& aCert,
+ const TBool aDeletable,
+ TRequestStatus& aStatus
+ )
+ {
+ assert(iWritableCertStore);
+ assert(iState == EIdleState);
+
+ TRAPD(err, DoAddL( aLabel,
+ aFormat,
+ aCertificateOwnerType,
+ aSubjectKeyId,
+ aIssuerKeyId,
+ aCert,
+ aDeletable,
+ aStatus ) );
+
+ if (err != KErrNone)
+ {
+ Complete(err);
+ }
+ }
+
+
+void CCheckedCertStore::DoAddL( const TDesC& aLabel,
+ TCertificateFormat aFormat,
+ TCertificateOwnerType aCertificateOwnerType,
+ const TKeyIdentifier* aSubjectKeyId,
+ const TKeyIdentifier* aIssuerKeyId,
+ const TDesC8& aCert,
+ const TBool aDeletable,
+ TRequestStatus& aStatus)
+ {
+
+ // Store caller parameters for later use
+ aStatus = KRequestPending;
+ iCallerStatus = &aStatus;
+ iFormat = aFormat;
+ iCertificateOwnerType = aCertificateOwnerType;
+ iSubjectKeyId = aSubjectKeyId;
+ iIssuerKeyId = aIssuerKeyId;
+ iDeletable = aDeletable;
+
+ // Store (copy) aCert (cert data) into iCertificate[:HBufC8]
+ assert(!iCertificate);
+ iCertificate = HBufC8::NewMaxL(aCert.Size());
+ TPtr8 theCert(iCertificate->Des());
+ theCert.FillZ();
+ theCert.Copy(aCert);
+
+ // Store (copy) aLabel (cert label) into iCertLabel[:HBufC]
+ assert(!iCertLabel);
+ iCertLabel = HBufC::NewMaxL(aLabel.Length());
+ TPtr theLabel(iCertLabel->Des());
+ theLabel.FillZ();
+ theLabel.Copy(aLabel);
+
+ // Checks subject key ID with certificate data, and sets up key filter
+ // which is used later to determine whether there is a key with the
+ // appropriate subject and thus, if it is OK to add the certificate
+ ComputeAndCheckSubjectKeyIdL();
+
+ // Is keystore checking required? Only if a user certificate
+ if (EUserCertificate==aCertificateOwnerType)
+ {
+ InitialiseKeyStoreL(EInitKeyStoreForAdd);
+ }
+ else
+ {
+ iState = EAdd;
+
+ // try new method first
+ iWritableCertStore->Add( *iCertLabel, // call new method
+ iFormat,
+ iCertificateOwnerType,
+ iSubjectKeyId,
+ iIssuerKeyId,
+ *iCertificate,
+ iDeletable, // with deletable param
+ iStatus );
+ SetActive();
+ }
+ }
+
+
+
+void CCheckedCertStore::CancelAdd()
+ {
+ if (iState == EInitKeyStoreForAdd ||
+ iState == EGetKeyInfosForAdd ||
+ iState == EAdd || iState == EOldAdd )
+ {
+ Cancel();
+ }
+ }
+
+void CCheckedCertStore::ComputeAndCheckSubjectKeyIdL()
+ {
+ switch (iFormat)
+ {
+ case EX509Certificate:
+ {
+ TPtr8 thePtr(iCertificate->Des());
+ CX509Certificate* cert = CX509Certificate::NewLC(thePtr);
+
+ TKeyUsageX509 x509Usage = EX509UsageNone;
+ const CX509CertExtension* ext = cert->Extension(KKeyUsage);
+
+ if (!ext)
+ {
+ x509Usage = EX509UsageAll;
+ }
+ else
+ {
+ CX509KeyUsageExt* keyUsageExt = CX509KeyUsageExt::NewLC(ext->Data());
+
+ if (keyUsageExt->IsSet(EX509DigitalSignature))
+ {
+ x509Usage |= EX509UsageDigitalSignature;
+ }
+ if (keyUsageExt->IsSet(EX509NonRepudiation))
+ {
+ x509Usage |= EX509UsageNonRepudiation;
+ }
+ if (keyUsageExt->IsSet(EX509KeyEncipherment))
+ {
+ x509Usage |= EX509UsageKeyEncipherment;
+ }
+ if (keyUsageExt->IsSet(EX509DataEncipherment))
+ {
+ x509Usage |= EX509UsageDataEncipherment;
+ }
+ if (keyUsageExt->IsSet(EX509KeyAgreement))
+ {
+ x509Usage |= EX509UsageKeyAgreement;
+ }
+ if (keyUsageExt->IsSet(EX509KeyCertSign))
+ {
+ x509Usage |= EX509UsageKeyCertSign;
+ }
+ if (keyUsageExt->IsSet(EX509CRLSign))
+ {
+ x509Usage |= EX509UsageCRLSign;
+ }
+ if (keyUsageExt->IsSet(EX509EncipherOnly))
+ {
+ x509Usage |= EX509UsageEncipherOnly;
+ }
+ if (keyUsageExt->IsSet(EX509DecipherOnly))
+ {
+ x509Usage |= EX509UsageDecipherOnly;
+ }
+
+ CleanupStack::PopAndDestroy(keyUsageExt);
+ }
+
+ iKeyFilter.iUsage = KeyUsageX509ToPKCS15Private(x509Usage);
+
+ iComputedSubjectKeyId.Zero();
+ // For non-user ceriticates (i.e. CA certificates), we use the SubjectKeyIdentifier API, as it
+ // tries to get the extension from cert., and calculates a value only if it is not found. This behaviour corresponds to the RFC.
+ // 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.
+ if (iCertificateOwnerType != EUserCertificate)
+ {
+ iComputedSubjectKeyId = cert->SubjectKeyIdentifierL();
+ }
+ else
+ {
+ // For non-CA certs, use the recommended method of computing it from RFC3280, section 4.2.1.2
+ iComputedSubjectKeyId = cert->KeyIdentifierL();
+ }
+ if (!iSubjectKeyId || *iSubjectKeyId == KNullDesC8)
+ {
+ iSubjectKeyId = &iComputedSubjectKeyId;
+ }
+ else if (iSubjectKeyId->Compare(iComputedSubjectKeyId)!=0)
+ {// Different subject ids
+ User::Leave(KErrArgument);
+ }
+
+ CleanupStack::PopAndDestroy(cert);
+ }
+ break;
+
+ case EWTLSCertificate:
+ {
+ CCertificate* cert = CWTLSCertificate::NewLC(*iCertificate);
+ iComputedSubjectKeyId = cert->KeyIdentifierL();
+ if (!iSubjectKeyId || *iSubjectKeyId == KNullDesC8)
+ {
+ iSubjectKeyId = &iComputedSubjectKeyId;
+ }
+ else if (iSubjectKeyId->Compare(iComputedSubjectKeyId)!=0)
+ {// Different subject ids
+ User::Leave(KErrArgument);
+ }
+
+ CleanupStack::PopAndDestroy(cert);
+ }
+ break;
+
+ case EX509CertificateUrl:
+ {
+ iKeyFilter.iUsage = EPKCS15UsageAll;
+
+ if (!iSubjectKeyId || *iSubjectKeyId == KNullDesC8)
+ {
+ User::Leave(KErrArgument);
+ }
+ }
+ break;
+
+ default:
+ User::Leave(KErrNotSupported);
+ break;
+ }
+
+ iKeyFilter.iKeyId = *iSubjectKeyId;
+ }
+
+void CCheckedCertStore::Remove(const CCTCertInfo& aCertInfo, TRequestStatus& aStatus)
+ {
+ assert(iWritableCertStore);
+ assert(iState == EIdleState);
+ aStatus = KRequestPending;
+ iCallerStatus = &aStatus;
+ iState = ERemove;
+ iWritableCertStore->Remove(aCertInfo, iStatus);
+ SetActive();
+ }
+
+void CCheckedCertStore::CancelRemove()
+ {
+ if (iState == ERemove)
+ {
+ Cancel();
+ }
+ }
+
+void CCheckedCertStore::SetApplicability(const CCTCertInfo& aCertInfo, const RArray<TUid>& aApplications, TRequestStatus &aStatus)
+ {
+ assert(iWritableCertStore);
+ assert(iState == EIdleState);
+ aStatus = KRequestPending;
+ iCallerStatus = &aStatus;
+ iState = ESetApplicability;
+ iWritableCertStore->SetApplicability(aCertInfo, aApplications, iStatus);
+ SetActive();
+ }
+
+void CCheckedCertStore::CancelSetApplicability()
+ {
+ if (iState == ESetApplicability)
+ {
+ Cancel();
+ }
+ }
+
+void CCheckedCertStore::SetTrust(const CCTCertInfo& aCertInfo, TBool aTrusted, TRequestStatus& aStatus)
+ {
+ assert(iWritableCertStore);
+ assert(iState == EIdleState);
+ aStatus = KRequestPending;
+ iCallerStatus = &aStatus;
+ iState = ESetTrust;
+ iWritableCertStore->SetTrust(aCertInfo, aTrusted, iStatus);
+ SetActive();
+ }
+
+void CCheckedCertStore::CancelSetTrust()
+ {
+ if (iState == ESetTrust)
+ {
+ Cancel();
+ }
+ }
+
+TInt CCheckedCertStore::RunError(TInt aError)
+ {
+ Complete(aError);
+ return KErrNone;
+ }
+
+void CCheckedCertStore::DoCancel()
+ {
+ // (see notes on cancellation in CUnifiedCertStore::DoCancel)
+
+ switch (iState)
+ {
+ case EGetKeyInfosForList:
+ case EAdd:
+ case ERemove:
+ case ESetApplicability:
+ case ESetTrust:
+ if (iStatus == KRequestPending)
+ {
+ // Attempt to cancel outstanding request and pass status back to
+ // client
+ CancelOutstandingRequest();
+ Complete(iStatus.Int());
+ }
+ else
+ {
+ // We've already been completed - call RunL() to process results
+ // and complete client
+ TRAPD(err, RunL());
+ if (err != KErrNone)
+ {
+ RunError(err);
+ }
+ }
+ break;
+
+ default:
+ CancelOutstandingRequest();
+ Complete(KErrCancel);
+ break;
+ }
+ }
+
+void CCheckedCertStore::CancelOutstandingRequest()
+ {
+ switch (iState)
+ {
+ case EList:
+ iCertStore.CancelList();
+ break;
+
+ case EInitKeyStoreForAdd:
+ case EInitKeyStoreForList:
+ assert(iUnifiedKeyStore);
+ iUnifiedKeyStore->CancelInitialize();
+ break;
+
+ case EGetKeyInfosForAdd:
+ case EGetKeyInfosForList:
+ assert(iUnifiedKeyStore);
+ iUnifiedKeyStore->CancelList();
+ break;
+
+ case EAdd:
+ case EOldAdd:
+ assert(iWritableCertStore);
+ iWritableCertStore->CancelAdd();
+ break;
+
+ case ERemove:
+ assert(iWritableCertStore);
+ iWritableCertStore->CancelRemove();
+ break;
+
+ case ESetApplicability:
+ assert(iWritableCertStore);
+ iWritableCertStore->CancelSetApplicability();
+ break;
+
+ case ESetTrust:
+ assert(iWritableCertStore);
+ iWritableCertStore->CancelSetTrust();
+ break;
+
+
+ default:
+ assert(EFalse);
+ break;
+ }
+
+ Complete(KErrCancel);
+ }
+
+void CCheckedCertStore::RunL()
+ {
+ assert(iCallerStatus);
+
+ // we allow only KErrNone OR, possibly, KErrNotSupported after new Add()
+ // otherwise - Leave!
+ if (iStatus!=KErrNone &&
+ !(iStatus==KErrNotSupported && iState==EAdd) &&
+ !(iStatus == KErrNotFound && (iState==EList || iState==EGetKeyInfosForList || iState==EInitKeyStoreForList)))
+ {
+ User::Leave(iStatus.Int());
+ }
+
+ switch (iState)
+ {
+ case EList:
+ if (iCallerFilter->iKeyUsage == EX509UsageAll)
+ {
+ // No key usage filter, so we're done
+ Complete(KErrNone);
+ }
+ else
+ {
+ // Set up key filter according list cert parameters
+ if (iCallerFilter->iSubjectKeyIdIsSet)
+ {
+ iKeyFilter.iKeyId = iCallerFilter->iSubjectKeyId;
+ }
+ else
+ {
+ iKeyFilter.iKeyId = KNullDesC8;
+ }
+ iKeyFilter.iUsage = KeyUsageX509ToPKCS15Private(iCallerFilter->iKeyUsage);
+ InitialiseKeyStoreL(EInitKeyStoreForList);
+ }
+ break;
+
+ case EInitKeyStoreForAdd:
+ case EInitKeyStoreForList:
+ assert(iUnifiedKeyStore);
+ iState = (iState == EInitKeyStoreForAdd) ? EGetKeyInfosForAdd : EGetKeyInfosForList;
+ iUnifiedKeyStore->List(iKeyInfos, iKeyFilter, iStatus);
+ SetActive();
+ break;
+
+ case EGetKeyInfosForList:
+ BuildCheckedCertificateListL(); // Not async
+ Complete(KErrNone);
+ break;
+
+ case EGetKeyInfosForAdd:
+ // We have a filter list of keys - there should be one with
+ // the appropriate subject if we are to add it
+ if (iKeyInfos.Count() == 0)
+ {
+ // The private key can't be found in any key store
+ Complete(KErrPrivateKeyNotFound);
+ }
+ else
+ {
+ // OK to go ahead and add the key
+ assert(iWritableCertStore);
+ iState = EAdd;
+
+ // try to use new Add(.., TBool aDeletable, ..)
+ // if it's not supported it will return with
+ // iStatus set to KErrNotSupported
+ iWritableCertStore->Add( *iCertLabel, // call new Add() method
+ iFormat,
+ iCertificateOwnerType,
+ iSubjectKeyId,
+ iIssuerKeyId,
+ *iCertificate,
+ iDeletable, // with deletable param
+ iStatus);
+ SetActive();
+ }
+ break;
+
+ case EAdd:
+ if (iStatus!=KErrNotSupported)
+ {
+ // Set published property
+ iPSCertstoreChangePropertyRef.Set(KUnifiedCertStorePropertyCat, // category
+ EUnifiedCertStoreFlag, // key
+ 1); // value
+
+ // when here means MCTWritableCertStore was able to find
+ // child's new Add(..,aDeletable,..) method
+ // thus, ok and complete with whatever result it returned
+ Complete(iStatus.Int());
+ }
+ else
+ {
+ // here: call to the new Add() method above didn't work,
+ // try to call old Add() method
+ iState = EOldAdd;
+ iStatus = KRequestPending;
+ iWritableCertStore->Add( *iCertLabel,
+ iFormat,
+ iCertificateOwnerType,
+ iSubjectKeyId,
+ iIssuerKeyId,
+ *iCertificate,
+ iStatus);
+ SetActive();
+ }
+ break;
+
+ case EOldAdd:
+ case ERemove:
+ case ESetApplicability:
+ case ESetTrust:
+ // Set published property
+ iPSCertstoreChangePropertyRef.Set(KUnifiedCertStorePropertyCat, // category
+ EUnifiedCertStoreFlag, // key
+ 1); // value
+ Complete(iStatus.Int());
+ break;
+
+ default:
+ assert(EFalse);
+ break;
+ }
+ }
+
+void CCheckedCertStore::InitialiseKeyStoreL(TState aNextState)
+ {
+ assert(aNextState == EInitKeyStoreForAdd || aNextState == EInitKeyStoreForList);
+ assert(!iUnifiedKeyStore);
+
+ iUnifiedKeyStore = CUnifiedKeyStore::NewL(iFs);
+ iUnifiedKeyStore->Initialize(iStatus);
+ iState = aNextState;
+ SetActive();
+ }
+
+void CCheckedCertStore::BuildCheckedCertificateListL()
+ {
+ TInt certCount = iCallerCerts->Count();
+ TInt keyCount = iKeyInfos.Count();
+
+ // Iterate backwards through cert array so remove doesn't affect indicies
+ for (TInt i = certCount - 1 ; i >= 0 ; --i)
+ {
+ CCTCertInfo* certInfo = (*iCallerCerts)[i];
+
+ // It's problem in the certstore implementation if the list contains NULL pointers
+ assert(certInfo);
+
+ // Check for key with corresponding id
+ TBool accept = EFalse;
+ for (TInt j = 0 ; j < keyCount ; ++j)
+ {
+ if (iKeyInfos[j]->ID()==certInfo->SubjectKeyId())
+ {
+ accept = ETrue;
+ break;
+ }
+ }
+
+ // If we don't have it, remove and release the cert info
+ if (!accept)
+ {
+ iCallerCerts->Remove(i);
+ certInfo->Release();
+ }
+ }
+ }
+
+void CCheckedCertStore::Complete(TInt aError)
+ {
+ if (iCallerStatus)
+ {
+ User::RequestComplete(iCallerStatus, aError);
+ }
+ Cleanup();
+ }
+
+void CCheckedCertStore::Cleanup()
+ {
+ // Reset the state machine
+ iState = EIdleState;
+ iKeyInfos.Close();
+ iSubjectKeyId = NULL;
+ iIssuerKeyId = NULL;
+
+ delete iCertLabel;
+ iCertLabel = NULL;
+
+ delete iCertificate;
+ iCertificate = NULL;
+
+ delete iUnifiedKeyStore;
+ iUnifiedKeyStore = 0;
+
+ iCallerCerts = NULL;
+ iCallerFilter = NULL;
+ }