diff -r 000000000000 -r 2c201484c85f cryptoservices/certificateandkeymgmt/tcertcommon/tcertutils.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/cryptoservices/certificateandkeymgmt/tcertcommon/tcertutils.cpp Wed Jul 08 11:25:26 2009 +0100 @@ -0,0 +1,769 @@ +/* +* Copyright (c) 2005-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: +* tcertuils.cpp +* +*/ + + +#include "tcertutils.h" +#include +#include +#include +#include +#include +#include + + +EXPORT_C CCertUtils* CCertUtils::NewL(RFs& aFs) + { + CCertUtils* self = CCertUtils::NewLC(aFs); + CleanupStack::Pop(self); + return self; + } + +EXPORT_C CCertUtils* CCertUtils::NewLC(RFs& aFs) + { + CCertUtils* self = new(ELeave) CCertUtils(aFs); + CleanupStack::PushL(self); + self->ConstructL(); + return self; + } + +CCertUtils::CCertUtils(RFs& aFs) +: CActive(EPriorityNormal), iFs(aFs) + { + CActiveScheduler::Add(this); + } + +EXPORT_C CCertUtils::~CCertUtils() + { + Cancel(); + + delete iCertificate; + delete iCreatedUnifiedCertStore; + + delete iCertData; + delete iLabelData; + delete iSecondCertUtils; + + delete iCAFilter; + delete iUserFilter; + + iCACertStoreEntries.Close(); // The entries are owned by us + iUserCertStoreEntries.Close(); // The entries are owned by us + iTrusters.Close(); + } + +/** +This function handles all the asynchronous calls. There is at least +one state for each of the functions of CCertUtils that requires +asynchronicity. +*/ +void CCertUtils::RunL() + { + if (iStatus != KErrNone) + { + User::RequestComplete(iOriginalRequestStatus, iStatus.Int()); + return; + } + + switch (iState) + { + // Used for AddCACerts + case EAddCACerts: + HandleEAddCACertsL(); + break; + + // Used for AddCert + case EAddCert: + TRAPD(err, HandleEAddCACertL()); + if (err != KErrNone) + { + iDiagnosticState = EAddCert; + User::RequestComplete(iOriginalRequestStatus, err); + } + break; + case EAddCACertGetCAEntry: + HandleEAddCACertGetCAEntry(); + break; + case EAddCACertSetApplications: + HandleEAddCACertSetApplicationsL(); + break; + case EAddCACertSetTrust: + HandleEAddCACertSetTrust(); + break; + case EAddCACertFinished: + HandleEAddCACertFinishedL(); + delete iCreatedUnifiedCertStore; + iCreatedUnifiedCertStore = 0; + break; + + // Used for RemoveCerts + case ERemoveCertsGetCACerts: + HandleERemoveCertsGetCACerts(); + break; + case ERemoveCertsCACertsRetrieved: + HandleERemoveCertsCACertsRetrieved(); + break; + case ERemoveCertsRemoveCACerts: + HandleERemoveCertsRemoveCACerts(); + break; + case ERemoveCertsGetUserCerts: + HandleERemoveCertsGetUserCerts(); + break; + case ERemoveCertsUserCertsRetrieved: + HandleERemoveCertsUserCertsRetrieved(); + break; + case ERemoveCertsRemoveUserCerts: + HandleERemoveCertsRemoveUserCerts(); + break; + case ERemoveCertsFinished: + HandleERemoveCertsFinished(); + delete iCreatedUnifiedCertStore; + iCreatedUnifiedCertStore = 0; + break; + + default: + break; + } + } + +TInt CCertUtils::RunError(TInt aError) + { + User::RequestComplete(iOriginalRequestStatus, aError); + return KErrNone; + } + +void CCertUtils::DoCancel() + { + if (iSecondCertUtils) + iSecondCertUtils->Cancel(); + + if (iUnifiedCertStore) + { + iUnifiedCertStore->Cancel(); + if (iUnifiedCertStore->WritableCertStoreCount() != 0) + { + MCTWritableCertStore *store; + store = &iUnifiedCertStore->WritableCertStore(0); + store->CancelRemove(); + store->CancelSetApplicability(); + } + } + + if (iStore) + iStore->CancelAdd(); + } + +EXPORT_C CCertificate* CCertUtils::CertFromFileLC(const TDesC& aFilename, + const TDesC& aPathname, + RFs& aFs, + TCertificateFormat aFormat) + { + TFileName fullname; + fullname.Append(aPathname); + fullname.Append(aFilename); + HBufC8* certBuf = Input::ReadFileLC(fullname, aFs); + CCertificate* cert = 0; + if (aFormat == EX509Certificate) + { + cert = CX509Certificate::NewLC(*certBuf); + } + else if (aFormat == EWTLSCertificate) + { + cert = CWTLSCertificate::NewLC(*certBuf); + } + CleanupStack::Pop();//cert + CleanupStack::PopAndDestroy();//buf + CleanupStack::PushL(cert); + return cert; + } + +EXPORT_C CCertificate* CCertUtils::CertFromFileL(const TDesC& aFilename, + const TDesC& aPathname, + RFs& aFs, + TCertificateFormat aFormat) + { + CCertificate* cert = CertFromFileLC(aFilename, aPathname, aFs, aFormat); + CleanupStack::Pop(); + return cert; + } + +EXPORT_C void CCertUtils::AddCertL(const TDesC& aLabel, + TCertificateFormat aFormat, + TCertificateOwnerType aCertificateOwnerType, + TInt aTrustedUsage, + const TDesC& aCertificatePath, + const TDesC& aCertificateFileName, + TRequestStatus& aStatus) + { + iOriginalRequestStatus = &aStatus; + aStatus = KRequestPending; + + // We set up the member variable as required for this function + iCertificateFileName = &aCertificateFileName; + iLabel = &aLabel; + iFormat = aFormat; + iTrustedUsage = aTrustedUsage; + iPath = &aCertificatePath; + iCertificateOwnerType = aCertificateOwnerType; + + if (iCreatedUnifiedCertStore) + { + delete iCreatedUnifiedCertStore; + } + + iCreatedUnifiedCertStore = CUnifiedCertStore::NewL(iFs, ETrue); // We want to open it for + // writing + iUnifiedCertStore = iCreatedUnifiedCertStore; + iCreatedUnifiedCertStore->Initialize(iStatus); + iState = EAddCert; + SetActive(); + } + +EXPORT_C void CCertUtils::AddCert(const TDesC& aLabel, + TCertificateFormat aFormat, + TCertificateOwnerType aCertificateOwnerType, + TInt aTrustedUsage, + const TDesC& aCertificatePath, + const TDesC& aCertificateFileName, + CUnifiedCertStore& aUnifiedCertStore, + TRequestStatus& aStatus) + { + iOriginalRequestStatus = &aStatus; + aStatus = KRequestPending; + + // We set up the member variable as required for this function + iCertificateFileName = &aCertificateFileName; + iLabel = &aLabel; + iFormat = aFormat; + iTrustedUsage = aTrustedUsage; + iPath = &aCertificatePath; + iCertificateOwnerType = aCertificateOwnerType; + iUnifiedCertStore = &aUnifiedCertStore; + + iState = EAddCert; + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + } + +EXPORT_C void CCertUtils::AddCACertsL(const CDesCArray& aRoots, + const CDesCArray& aLabels, + TCertificateFormat aFormat, + TInt aTrustedUsage, + const TDesC& aPath, + TRequestStatus& aStatus) + { + iOriginalRequestStatus = &aStatus; + aStatus = KRequestPending; + + // We set up the member variable as required for this function + iRoots = &aRoots; + iFormat = aFormat; + iLabels = &aLabels; + iTrustedUsage = aTrustedUsage; + iPath = &aPath; + + iIndex = -1; // -1 because it will be incremented before its first use + if (!iSecondCertUtils) + { + iSecondCertUtils = CCertUtils::NewL(iFs); + } + + if (iCreatedUnifiedCertStore) + { + delete iCreatedUnifiedCertStore; + } + + iCreatedUnifiedCertStore = CUnifiedCertStore::NewL(iFs, ETrue); // We want to open it for + // writing + iUnifiedCertStore = iCreatedUnifiedCertStore; + iCreatedUnifiedCertStore->Initialize(iStatus); + + iState = EAddCACerts; + SetActive(); + } + +EXPORT_C void CCertUtils::AddCACertsL(const CDesCArray& aRoots, + const CDesCArray& aLabels, + TCertificateFormat aFormat, + TInt aTrustedUsage, + const TDesC& aPath, + CUnifiedCertStore& aUnifiedCertStore, + TRequestStatus& aStatus) + { + iOriginalRequestStatus = &aStatus; + aStatus = KRequestPending; + + // We set up the member variable as required for this function + iRoots = &aRoots; + iFormat = aFormat; + iLabels = &aLabels; + iTrustedUsage = aTrustedUsage; + iPath = &aPath; + iUnifiedCertStore = &aUnifiedCertStore; + + iIndex = -1; // -1 because it will be incremented before its first use + if (!iSecondCertUtils) + { + iSecondCertUtils = CCertUtils::NewL(iFs); + } + + iState = EAddCACerts; + SetActive(); + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + } + +EXPORT_C void CCertUtils::RemoveCertsL(CUnifiedCertStore& aUnifiedCertStore, + TRequestStatus& aStatus) + { + iOriginalRequestStatus = &aStatus; + aStatus = KRequestPending; + iUnifiedCertStore = &aUnifiedCertStore; + + iState = ERemoveCertsGetCACerts; + TRequestStatus* status = &iStatus; + User::RequestComplete(status, KErrNone); + SetActive(); + } + +EXPORT_C void CCertUtils::RemoveCertsL(TRequestStatus& aStatus) + { + iOriginalRequestStatus = &aStatus; + aStatus = KRequestPending; + iState = ERemoveCertsGetCACerts; + + if (iCreatedUnifiedCertStore) + { + delete iCreatedUnifiedCertStore; + } + + iCreatedUnifiedCertStore = CUnifiedCertStore::NewL(iFs, ETrue); // We want to open it for + // writing + iUnifiedCertStore = iCreatedUnifiedCertStore; + iCreatedUnifiedCertStore->Initialize(iStatus); + SetActive(); + } + +EXPORT_C void CCertUtils::WriteError(TValidationError aError, Output& aOut) + { + aOut.writeString(CCertUtils::MapError(aError)); + } + +EXPORT_C TPtrC CCertUtils::MapError(TValidationError aError) + { + + switch(aError) + { + //errors + case EValidatedOK: + { + return (_L("Validated OK")); + } + case EChainHasNoRoot: + { + return(_L("Chain has no root")); + } + case ESignatureInvalid: + { + return(_L("Signature invalid")); + } + case EDateOutOfRange: + { + return(_L("Date out of range")); + } + case ENameIsExcluded: + { + return(_L("Name is excluded")); + } + case ENameNotPermitted: + { + return(_L("Name is not permitted")); + } + case ECertificateRevoked: + { + return(_L("Certificate revoked")); + } + case EUnrecognizedCriticalExtension: + { + return(_L("Unrecognized Critical Extension")); + } + case ENoBasicConstraintInCACert: + { + return(_L("CA cert with no Basic Constraint")); + } + case ENoAcceptablePolicy: + { + return(_L("No acceptable policy")); + } + case EPathTooLong: + { + return(_L("Path too long")); + } + case ENegativePathLengthSpecified: + { + return(_L("Negative path length specified")); + } + case ENamesDontChain: + { + return(_L("Names don't chain")); + } + case ERequiredPolicyNotFound: + { + return(_L("Required policy not found")); + } + case EBadKeyUsage: + { + return(_L("Bad key usage")); + } + case ENotCACert: + { + return(_L("Non-CA cert used as CA cert")); + } + //warnings + case ERootCertNotSelfSigned: + { + return(_L("Root cert not self-signed")); + } + case ECriticalExtendedKeyUsage: + { + return(_L("Critical extended key usage")); + } + case ECriticalCertPoliciesWithQualifiers: + { + return(_L("Critical cert policies with qualifiers")); + } + case ECriticalPolicyMapping: + { + return(_L("Critical policy mapping")); + } + case ECriticalDeviceId: + { + return(_L("Critical Device Id")); + } + case ECriticalSid: + { + return(_L("Critical Sid")); + } + case ECriticalVid: + { + return(_L("Critical Vid")); + } + case ECriticalCapabilities: + { + return(_L("Critical Capabilities")); + } + } + return (_L("Unknown Error")); + } + + +EXPORT_C HBufC* CCertUtils::DiagnosticLC() const + { + HBufC* result = HBufC::NewLC(600); + switch (iDiagnosticState) + { + case EAddCert: + result->Des().Append(_L("EAddCACert")); + result->Des().Append(_L(" : ")); + result->Des().Append(iDiagnosticMessage); + break; + + default: + break; + } + + return result; + } + +EXPORT_C void CCertUtils::AddApplicationL(const TDesC& aName, TUid aUid) const + { + CCertificateAppInfoManager* appManager = CCertificateAppInfoManager::NewL(iFs, ETrue); + CleanupStack::PushL(appManager); + + // Only add the application if it doesn't exist already + const RArray& apps = appManager->Applications(); + TInt i; + for (i = 0 ; i < apps.Count() ; ++i) + { + if (apps[i].Id() == aUid && apps[i].Name() == aName) + break; + } + + if (i == apps.Count()) + { + appManager->AddL(TCertificateAppInfo(aUid, aName)); + } + + CleanupStack::PopAndDestroy(appManager); + } + +EXPORT_C void CCertUtils::RemoveApplicationL(TUid aUid) const + { + CCertificateAppInfoManager* appManager = CCertificateAppInfoManager::NewL(iFs, ETrue); + CleanupStack::PushL(appManager); + appManager->RemoveL(aUid); + CleanupStack::PopAndDestroy(appManager); + } + + +void CCertUtils::ConstructL() + { + iCAFilter = CCertAttributeFilter::NewL(); + iCAFilter->SetOwnerType(ECACertificate); + iUserFilter = CCertAttributeFilter::NewL(); + iUserFilter->SetOwnerType(EUserCertificate); + } + +void CCertUtils::HandleEAddCACertsL() + { + iIndex++; + if (iIndex < iRoots->Count()) + { + // We still have some certificates to add + if (iCertData) + { + delete iCertData; + iCertData = 0; + } + iCertData = iRoots->MdcaPoint(iIndex).AllocL(); + if (iLabelData) + { + delete iLabelData; + iLabelData = 0; + } + iLabelData = iLabels->MdcaPoint(iIndex).AllocL(); + iSecondCertUtils->AddCert(*iLabelData, iFormat, ECACertificate, + iTrustedUsage, *iPath, *iCertData, *iUnifiedCertStore, iStatus); + SetActive(); + } + else + { + // We have finished adding all the certificates + delete iSecondCertUtils; + iSecondCertUtils = 0; + delete iCreatedUnifiedCertStore; + iCreatedUnifiedCertStore = 0; + User::RequestComplete(iOriginalRequestStatus, KErrNone); + } + } + +void CCertUtils::HandleEAddCACertL() + { + // At this stage we should always have an initialized iStoreManager + __ASSERT_DEBUG(iUnifiedCertStore, User::Panic(_L("TCertUtils"), 1)); + + // We use the first writable certstore + iStore = &iUnifiedCertStore->WritableCertStore(0); + + __ASSERT_DEBUG(!iCertificate, User::Panic(_L("TCertUtils"), 1)); + iCertificate = 0; + TRAPD(err, iCertificate = + CCertUtils::CertFromFileL(*iCertificateFileName, *iPath, iFs, iFormat)); + if (err != KErrNone) + { + if (err != KErrNoMemory) + { + iDiagnosticMessage.Zero(); + iDiagnosticMessage.Append(_L("CertFromFileL failed (")); + iDiagnosticMessage.Append(*iCertificateFileName); + iDiagnosticMessage.Append(_L(")")); + } + User::Leave(err); + } + iEncoding.Set(iCertificate->Encoding()); + iStore->Add(*iLabel, iFormat, iCertificateOwnerType, 0, 0, iEncoding, iStatus); + iState = EAddCACertGetCAEntry; + SetActive(); + } + +void CCertUtils::HandleEAddCACertGetCAEntry() + { + delete iCertificate; + iCertificate = 0; + iCACertStoreEntries.Close(); + iUnifiedCertStore->List(iCACertStoreEntries, *iCAFilter, iStatus); + iState = EAddCACertSetApplications; + SetActive(); + } + +void CCertUtils::HandleEAddCACertSetApplicationsL() + { + CCTCertInfo* entry = 0; + TInt iEnd = iCACertStoreEntries.Count(); + for (TInt i = 0; i < iEnd; i++) + { + if (iCACertStoreEntries[i]->Label() == *iLabel) + { + entry = iCACertStoreEntries[i]; + } + } + + __ASSERT_ALWAYS(entry, User::Panic(_L("TCertUtils"), 1)); + + iTrusters.Reset(); + TUid truster = { iTrustedUsage }; + User::LeaveIfError(iTrusters.Append(truster)); + + iUnifiedCertStore->SetApplicability(*entry, iTrusters, iStatus); + iState = EAddCACertSetTrust; + SetActive(); + } + +void CCertUtils::HandleEAddCACertSetTrust() + { + CCTCertInfo* entry = 0; + TInt iEnd = iCACertStoreEntries.Count(); + for (TInt i = 0; i < iEnd; i++) + { + if (iCACertStoreEntries[i]->Label() == *iLabel) + { + entry = iCACertStoreEntries[i]; + } + } + + __ASSERT_ALWAYS(entry, User::Panic(_L("TCertUtils"), 1)); + + iUnifiedCertStore->SetTrust(*entry, ETrue, iStatus); + iState = EAddCACertFinished; + SetActive(); + } + +void CCertUtils::HandleEAddCACertFinishedL() + { + User::RequestComplete(iOriginalRequestStatus, iStatus.Int()); + } + +void CCertUtils::HandleERemoveCertsGetCACerts() + { + // At this stage we should always have an initialized iStoreManager + __ASSERT_DEBUG(iUnifiedCertStore, User::Panic(_L("TCertUtils"), 1)); + + iCACertStoreEntries.Close(); + iUnifiedCertStore->List(iCACertStoreEntries, *iCAFilter, iStatus); + + iState = ERemoveCertsCACertsRetrieved; + SetActive(); + } + +void CCertUtils::HandleERemoveCertsCACertsRetrieved() + { + // This index will be used to keep track of the current entry + iIndex = -1; + + iState = ERemoveCertsRemoveCACerts; + TRequestStatus* status = &iStatus; + SetActive(); + User::RequestComplete(status, KErrNone); + } + +void CCertUtils::HandleERemoveCertsRemoveCACerts() + { + iIndex++; + if (iIndex < iCACertStoreEntries.Count()) + { + // Remove this certificate if it can be deleted. + + CCTCertInfo& cert = *iCACertStoreEntries[iIndex]; + + // Unfortunately, certs in non-writable stores can still be + // marked as deletable, so need to check if cert is also in a + // writable store. + + TBool isDeletable = cert.IsDeletable(); + + TBool inWritableStore = EFalse; + + TCTTokenObjectHandle certHandle(cert.Handle()); + TInt writeStoreCount = iUnifiedCertStore->WritableCertStoreCount(); + for (TInt i = 0; i < writeStoreCount; ++i) + { + MCTWritableCertStore& wcs = iUnifiedCertStore->WritableCertStore(i); + if (wcs.Token().Handle() == certHandle.iTokenHandle) + { + inWritableStore = ETrue; + break; + } + } + + if (isDeletable && inWritableStore) + { + iUnifiedCertStore->Remove(cert, iStatus); + SetActive(); + } + else + { + TRequestStatus* status = &iStatus; + SetActive(); + User::RequestComplete(status, KErrNone); + } + } + else + { + iState = ERemoveCertsGetUserCerts; + TRequestStatus* status = &iStatus; + SetActive(); + User::RequestComplete(status, KErrNone); + } + } + +void CCertUtils::HandleERemoveCertsGetUserCerts() + { + // At this stage we should always have an initialized iStoreManager + __ASSERT_DEBUG(iUnifiedCertStore, User::Panic(_L("TCertUtils"), 1)); + + iUserCertStoreEntries.Close(); + iUnifiedCertStore->List(iUserCertStoreEntries, *iUserFilter, iStatus); + + iState = ERemoveCertsUserCertsRetrieved; + SetActive(); + } + +void CCertUtils::HandleERemoveCertsUserCertsRetrieved() + { + iIndex = -1; + + iState = ERemoveCertsRemoveUserCerts; + TRequestStatus* status = &iStatus; + SetActive(); + User::RequestComplete(status, KErrNone); + } + +void CCertUtils::HandleERemoveCertsRemoveUserCerts() + { + // At this stage we should always have an initialized iStoreManager + __ASSERT_DEBUG(iUnifiedCertStore, User::Panic(_L("TCertUtils"), 1)); + + iIndex++; + if (iIndex < iUserCertStoreEntries.Count()) + { + iUnifiedCertStore->Remove(*iUserCertStoreEntries[iIndex], iStatus); + SetActive(); + } + else + { + iState = ERemoveCertsFinished; + TRequestStatus* status = &iStatus; + SetActive(); + User::RequestComplete(status, KErrNone); + } + } + +void CCertUtils::HandleERemoveCertsFinished() + { + User::RequestComplete(iOriginalRequestStatus, KErrNone); + }