/*
* 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:
*
*/
#include "CSWICertStoreImpl.h"
#include "CSWICertStoreEntryList.h"
#include "CSWICertStoreEntry.h"
#include "CSWICertStoreTokenType.h"
#include "CSWICertStoreToken.h"
#include "unifiedcertstore.h"
#include "log.h"
#include <certstorepatchdata.h>
#include <ccertattributefilter.h>
#include <f32file.h>
#include <u32hal.h>
#include <e32svr.h>
_LIT(KSWICertStoreZFilename,"z:\\resource\\swicertstore.dat");
_LIT(KSWIWritableCertStorePath,"!:\\resource\\swicertstore\\dat\\");
_LIT(KSWIROMCertStoreFilenamePattern,"z:\\resource\\swicertstore*.dat");
/////////////////////////////////////////////////////////////////////////////////////////
//CFSCertStoreServer
/////////////////////////////////////////////////////////////////////////////////////////
CSWICertStoreImpl* CSWICertStoreImpl::NewL(MCTToken& aToken, RFs& aFs)
{
CSWICertStoreImpl* self = new (ELeave) CSWICertStoreImpl(aToken, aFs);
CleanupStack::PushL(self);
self->ConstructL();
CleanupStack::Pop(self);
return self;
}
CSWICertStoreImpl::CSWICertStoreImpl(MCTToken& aToken, RFs& aFs) :
CActive(EPriorityStandard), iToken(aToken), iFs(aFs)
{
CActiveScheduler::Add(this);
}
void CSWICertStoreImpl::ConstructL()
{
TInt err = iSwicertstoreProperty.Attach(KUnifiedCertStorePropertyCat,
EUnifiedCertStoreFlag, EOwnerThread);
User::LeaveIfError(err);
iPatchableConst = KAggregateCertStore;
#ifdef __WINS__
// For the emulator allow the constant to be patched via epoc.ini
UserSvr::HalFunction(EHalGroupEmulator, EEmulatorHalIntProperty,
(TAny*)"KAggregateCertStore", &iPatchableConst); // read emulator property (if present)
#endif
// if patchable constant is enabled
if(iPatchableConst)
{
// Setup composite ROM Certstore
SetupCompositeROMCertStoreL();
}
else
{
// Setup the ROM CertStore
SetupROMCertStoreL();
}
// Setup the Writable CertStore
// Bear in mind we need to trap NewL(), OpenLC() etc.
// Any error occurs, it should still setup the z:\ certstore
TRAP_IGNORE(SetupWritableCertStoreL());
// aggregate ROM composite certstore and writable certstore if patchable constant is enabled
if(iPatchableConst)
{
if(iCEntryList)
{
// ETrue to indicate that we are passing 'iZEntryList'.
// This action will remove duplicate entries from 'iZEntryList'.
MergeCertificateEntryListsL(*iZEntryList, ETrue);
}
}
// Subscribe to the Property
iSwicertstoreProperty.Subscribe(iStatus);
SetActive();
}
void CSWICertStoreImpl::DoCancel()
{
// Cancel outstanding request
iSwicertstoreProperty.Cancel();
}
void CSWICertStoreImpl::RunL()
{
// Resubscribe before processing new value to prevent missing updates
iSwicertstoreProperty.Subscribe(iStatus);
SetActive();
// Bear in mind we need to trap NewL(), OpenLC() etc.
TRAP_IGNORE(SetupWritableCertStoreL());
}
void CSWICertStoreImpl::SetupWritableCertStoreL()
{
TInt err = KErrNone;
delete iCEntryList;
iCEntryList = NULL;
// The attached file will be freed as well.
delete iCStore;
iCStore = NULL;
do
{
// Open the store if it is there
RFile file;
CDir* entryList = NULL;
TPath writableSwiCertStorePath(KSWIWritableCertStorePath);
TChar systemDriveChar = RFs::GetSystemDriveChar();
writableSwiCertStorePath[0] = systemDriveChar;
if (KErrNone == iFs.GetDir (writableSwiCertStorePath, KEntryAttNormal,
ESortByName|EDirsFirst, entryList))
{
if (entryList)
{
CleanupStack::PushL(entryList);
TFileName certstoreFile;
TInt count = entryList->Count();
if (count > 0)
{
// Get the highest version certstore file
const TEntry& entry = (*entryList)[count - 1];
certstoreFile.Append(writableSwiCertStorePath);
certstoreFile.Append(entry.iName);
CleanupStack::PopAndDestroy(1, entryList);
}
else
{
CleanupStack::PopAndDestroy(1, entryList);
// No certstore in this directory
// Currently there should not have any directory in this path
return;
}
err = file.Open(iFs, certstoreFile, EFileShareReadersOnly);
if (err != KErrNone && err != KErrNotFound)
{
// Log the error to the system file.
DEBUG_PRINTF2(_L8("Error Opening SWI writable certstore: %S."), &certstoreFile);
return;
}
if (err == KErrNone)
{
// File exist
CleanupClosePushL(file);
TRAP_IGNORE(iCStore = CPermanentFileStore::FromL(file));
if (iCStore)
{
CleanupStack::Pop(&file); // now owned by store
// Read id of cert list stream
TStreamId streamId;
RStoreReadStream stream;
stream.OpenLC(*iCStore, iCStore->Root());
stream >> streamId;
CleanupStack::PopAndDestroy(&stream);
// Read the certificate list
RStoreReadStream entryStream;
entryStream.OpenLC(*iCStore, streamId);
iCEntryList = CSWICertStoreEntryList::NewL(entryStream, iToken, iCertIndex);
CleanupStack::PopAndDestroy(&entryStream);
// Record the writable certstore index
// The index will then be used to set the tokenId in the
// in handle, so to make the handle unique.
iCertIndex += iCEntryList->Count();
}
else
{
// The file format might not comply to the CPermanentFileStore format
CleanupStack::PopAndDestroy(&file);
// Log the error to the system file.
DEBUG_PRINTF2(_L8("Error Opening SWI writable certstore: %S."), &certstoreFile);
return;
}
}
}
}
}while (err == KErrNotFound); // There is a very slight chance that the file has been deleted
}
void CSWICertStoreImpl::MergeCertificateEntryListsL(const CSWICertStoreEntryList& aSourceList, TBool aIsZEntryList)
{
ASSERT(iPatchableConst);
// if patchable constant is enabled
TInt sourceCount = aSourceList.Count();
for(TInt i = 0; i < sourceCount; i++)
{
if(!aIsZEntryList)
{
if (!iZEntryList->LabelExists(aSourceList.GetByIndex(i).CertInfo().Label()))
{
// Aggregation: Append this entry in the ROM composite list
const CSWICertStoreEntry& entry = aSourceList.GetByIndex(i);
CSWICertStoreEntry* newEntry = CSWICertStoreEntry::NewL(entry.CertInfo(),
entry.CertificateApps(),
entry.Trusted(),
entry.DataStreamId(),
entry.CertMetaInfo(),
entry.StoreIndex());
CleanupStack::PushL(newEntry);
iZEntryList->AppendL(newEntry);
// iZEntryList has taken ownership
CleanupStack::Pop(newEntry);
}
// Eclipsing: Higher order store certificates with same labels take precedence over lower order store certificates.
// therefore the later are not included in the composite certificate entry list.
// N.B iCertIndex will not give total count of certificates because of Eclipsing mechanism.
// Higher order store certificates are ones which are aggregated prior to other certificates.
}
else
{
// remove duplicate label entries from the 'iZEntryList'
if (iCEntryList->LabelExists(aSourceList.GetByIndex(i).CertInfo().Label()))
{
// Remove entries from iZEntryList having same labels as in iCEntryList.
iZEntryList->Remove(i);
}
}
}
}
void CSWICertStoreImpl::SetupCompositeROMCertStoreL()
{
ASSERT(iPatchableConst);
// Collect the file present in ROM certstore private directory.
//The files in this list will be in descending order by name.
CDir* filenameList = NULL;
User::LeaveIfError(iFs.GetDir(KSWIROMCertStoreFilenamePattern, KEntryAttNormal, ESortByName|EDescending, filenameList));
CleanupStack::PushL(filenameList);
TInt count = filenameList->Count();
TStreamId streamId;
// make full path to the certstore files residing on ROM drive
// N.B filenameList will contain filenames in descending order.
RFile file;
RStoreReadStream stream;
// create an empty list, this will be the composite certificate entry list
iZEntryList = CSWICertStoreEntryList::NewL();
// the 'corruptCount' is used for proper correctly referencing valid certstores
TInt corruptCount=0;
for(TInt i = 0; i < count; i++)
{
RBuf romFile;
romFile.CreateL(KMaxFileName);
CleanupClosePushL(romFile);
romFile.Append(_L("z:\\resource\\"));
romFile.Append(((*filenameList)[i]).iName);
User::LeaveIfError(file.Open(iFs,romFile,EFileShareReadersOnly));
CleanupClosePushL(file);
// open and append the store in array of stores
CPermanentFileStore* store = NULL;
// if there is any corrupt certstore present then we will simply ignore its
// aggregation and proceed with aggregating remaining stores.
// ownership is transfered to 'iZArrayOfStores'
TRAPD(err, store = CPermanentFileStore::FromL(file));
if(err != KErrNone)
{
corruptCount++;
//cleanup file and romFile.
CleanupStack::PopAndDestroy(2, &romFile);
continue;
}
iZArrayOfStores.AppendL(store);
TInt index = i - corruptCount;
// open the root stream containing the streamId of info stream.
stream.OpenLC(*(iZArrayOfStores)[index],(iZArrayOfStores[index])->Root());
stream >> streamId;
CleanupStack::PopAndDestroy(&stream);
// re-open the info stream containing the certificates entry list.
stream.OpenLC(*(iZArrayOfStores)[index],streamId);
// store index for these entries will be 'index'.
// iCertIndex will be 0 for the first certificate entry list passed.
CSWICertStoreEntryList* temp_list = CSWICertStoreEntryList::NewL(stream, iToken,iCertIndex,index);
// increment to have unique certificate Ids allocation.
iCertIndex += temp_list->Count();
CleanupStack::PushL(temp_list);
MergeCertificateEntryListsL(*temp_list);
//temp_list, stream, file and romFile.
CleanupStack::PopAndDestroy(4, &romFile);
}
CleanupStack::PopAndDestroy(filenameList);
}
void CSWICertStoreImpl::SetupROMCertStoreL()
{
// Open the store
RFile file;
User::LeaveIfError(file.Open(iFs, KSWICertStoreZFilename, EFileShareReadersOnly));
CleanupClosePushL(file);
iZStore = CPermanentFileStore::FromL(file);
CleanupStack::Pop(&file); // now owned by store
// Read id of cert list stream
TStreamId streamId;
RStoreReadStream stream;
stream.OpenLC(*iZStore, iZStore->Root());
stream >> streamId;
CleanupStack::PopAndDestroy(&stream);
// Read the certificate list
RStoreReadStream entryStream;
entryStream.OpenLC(*iZStore, streamId);
iZEntryList = CSWICertStoreEntryList::NewL(entryStream, iToken);
CleanupStack::PopAndDestroy(&entryStream);
// set the valid indexes of writable certstore
iCertIndex = iZEntryList->Count();
}
CSWICertStoreImpl::~CSWICertStoreImpl()
{
Cancel();
iSwicertstoreProperty.Close();
delete iCEntryList;
delete iZEntryList;
delete iCStore;
delete iZStore;
iZArrayOfStores.ResetAndDestroy();
}
void CSWICertStoreImpl::ListL(RMPointerArray<CCTCertInfo>& aCerts,
const CCertAttributeFilter& aFilter)
{
if (iCEntryList)
{
FilterCertificateListL(aCerts, aFilter, *iCEntryList);
}
FilterCertificateListL(aCerts, aFilter, *iZEntryList);
}
CCTCertInfo* CSWICertStoreImpl::GetCertL(const TCTTokenObjectHandle& aHandle)
{
TBool isCEntryHandle = EFalse;
const CSWICertStoreEntry* entry = GetCSWICertStoreEntryL(aHandle, isCEntryHandle);
return CCTCertInfo::NewL(entry->CertInfo());
}
void CSWICertStoreImpl::ApplicationsL(const TCTTokenObjectHandle& aHandle, RArray<TUid>& aApplications)
{
TBool isCEntryHandle = EFalse;
const CSWICertStoreEntry* entry = GetCSWICertStoreEntryL(aHandle, isCEntryHandle);
const RArray<TUid>& apps = entry->CertificateApps();
TInt count = apps.Count();
for (TInt i = 0 ; i < count ; ++i)
{
User::LeaveIfError(aApplications.Append(apps[i]));
}
}
TBool CSWICertStoreImpl::IsApplicableL(const TCTTokenObjectHandle& aHandle, TUid aApplication)
{
TBool isCEntryHandle = EFalse;
const CSWICertStoreEntry* entry = GetCSWICertStoreEntryL(aHandle, isCEntryHandle);
return entry->IsApplicable(aApplication);
}
TBool CSWICertStoreImpl::TrustedL(const TCTTokenObjectHandle& aHandle)
{
TBool isCEntryHandle = EFalse;
const CSWICertStoreEntry* entry = GetCSWICertStoreEntryL(aHandle, isCEntryHandle);
return entry->Trusted();
}
void CSWICertStoreImpl::RetrieveL(const TCTTokenObjectHandle& aHandle, TDes8& aEncodedCert)
{
TBool isCEntryHandle = EFalse;
const CSWICertStoreEntry* entry = GetCSWICertStoreEntryL(aHandle, isCEntryHandle);
RStoreReadStream stream;
if (iCEntryList && isCEntryHandle)
{
stream.OpenLC(*iCStore, entry->DataStreamId());
}
else
{
// if patchable constant is enabled
if (iPatchableConst)
{
stream.OpenLC(*(iZArrayOfStores[entry->StoreIndex()]), entry->DataStreamId());
}
else
{
stream.OpenLC(*iZStore, entry->DataStreamId());
}
}
TInt size = entry->CertInfo().Size();
if (aEncodedCert.MaxLength() < size)
{
User::Leave(KErrOverflow);
}
stream.ReadL(aEncodedCert, size);
CleanupStack::PopAndDestroy(&stream);
}
const TCertMetaInfo& CSWICertStoreImpl::CertMetaInfoL(const TCTTokenObjectHandle& aHandle) const
{
TBool isCEntryHandle = EFalse;
const CSWICertStoreEntry* entry = GetCSWICertStoreEntryL(aHandle, isCEntryHandle);
return entry->CertMetaInfo();
}
const CSWICertStoreEntry* CSWICertStoreImpl::GetCSWICertStoreEntryL(const TCTTokenObjectHandle& aHandle, TBool& aCEntryHandle) const
{
if (iCEntryList)
{
const CSWICertStoreEntry* entry = NULL;
TRAPD (retCode, entry = &(iCEntryList->GetByHandleL(aHandle)));
if (entry && (retCode == KErrNone))
{
aCEntryHandle = ETrue;
return entry;
}
}
return &iZEntryList->GetByHandleL(aHandle);
}
void CSWICertStoreImpl::AddIfMatchesFilterL(RMPointerArray<CCTCertInfo>& aCerts, const CCertAttributeFilter& aFilter, const CSWICertStoreEntry& aEntry)
{
const CCTCertInfo& certInfo = aEntry.CertInfo();
TBool accept = ETrue;
if (aFilter.iUidIsSet)
{
accept = aEntry.IsApplicable(aFilter.iUid);
}
if (aFilter.iFormatIsSet && accept)
{
accept = (aFilter.iFormat == certInfo.CertificateFormat());
}
if (aFilter.iOwnerTypeIsSet && accept)
{
accept = (aFilter.iOwnerType == certInfo.CertificateOwnerType());
}
if (aFilter.iSubjectKeyIdIsSet && accept)
{
accept = (aFilter.iSubjectKeyId == certInfo.SubjectKeyId());
}
if (aFilter.iLabelIsSet && accept)
{
accept = (aFilter.iLabel == certInfo.Label());
}
if (accept)
{
CCTCertInfo* newCertInfo = CCTCertInfo::NewLC(certInfo);
User::LeaveIfError(aCerts.Append(newCertInfo));
CleanupStack::Pop(newCertInfo);
}
}
void CSWICertStoreImpl::FilterCertificateListL(RMPointerArray<CCTCertInfo>& aCerts,
const CCertAttributeFilter& aFilter, const CSWICertStoreEntryList& aEntryList)
{
TInt count = aEntryList.Count();
for (TInt index = 0; index < count; index++)
{
const CSWICertStoreEntry& entry = aEntryList.GetByIndex(index);
AddIfMatchesFilterL(aCerts, aFilter, entry);
}
}