pkiutilities/DeviceToken/Src/Certstore/server/DevandTruSrvCertStoreServer.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Tue, 26 Jan 2010 15:20:08 +0200
changeset 0 164170e6151a
child 11 9971b621ef6c
permissions -rw-r--r--
Revision: 201004

/*
* Copyright (c) 2006 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "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:   Implementation of DevandTruSrvCertStoreServer
*
*/


#include <ccertattributefilter.h>
#include <signed.h>
#include <x509cert.h>
#include <x509certext.h>
#include <x509keys.h>
#include <wtlscert.h>
#include <x500dn.h>
#include "DevandTruSrvCertStoreServer.h"
#include "DevandTruSrvCertStoreConduit.h"
#include "DevandTruSrvCertStoreSession.h"
#include "DevandTruSrvCertStoreEntry.h"
#include "DevandTruSrvCertStoreEntryList.h"
#include "DevTokenCliServ.h"
#include "DevTokenUtil.h"
#include "DevTokenDataTypes.h"
#include "TrustedSitesServer.h"

_LIT(KCertStoreFilename,"devandtrusrvcerts.dat");

const TInt KSHA1Length = 20;

// API policing 
_LIT_SECURITY_POLICY_PASS(KPolicyAlwaysPass);
_LIT_SECURITY_POLICY_FAIL(KPolicyAlwaysFail);
_LIT_SECURITY_POLICY_C1(KPolicyRequireReadUserData, ECapabilityReadUserData);
_LIT_SECURITY_POLICY_C1(KPolicyRequireWriteDeviceData, ECapabilityWriteDeviceData);

// ======== MEMBER FUNCTIONS ========

//CDevandTruSrvCertStoreServer

// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::NewL()
// ---------------------------------------------------------------------------
//
CDevandTruSrvCertStoreServer* CDevandTruSrvCertStoreServer::NewL(CTrustedSitesServer* aTrustedSitesServer )
    {
    CDevandTruSrvCertStoreServer* self = new (ELeave) CDevandTruSrvCertStoreServer( aTrustedSitesServer );
    CleanupStack::PushL(self);
    self->ConstructL();
    CleanupStack::Pop(self);
    return self;
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::CDevandTruSrvCertStoreServer()
// ---------------------------------------------------------------------------
//
CDevandTruSrvCertStoreServer::CDevandTruSrvCertStoreServer( CTrustedSitesServer* aTrustedSitesServer )
: iTrustedSitesServer( aTrustedSitesServer )
    {
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::ConstructL()
// ---------------------------------------------------------------------------
//
void CDevandTruSrvCertStoreServer::ConstructL()
    {
    iConduit = CDevandTruSrvCertStoreConduit::NewL(*this);
    User::LeaveIfError(iFs.Connect());
    OpenStoreL();
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::~CDevandTruSrvCertStoreServer()
// ---------------------------------------------------------------------------
//
CDevandTruSrvCertStoreServer::~CDevandTruSrvCertStoreServer()
    {
    delete iStore;
    delete iEntryList;
    delete iConduit;
    iFs.Close();
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::CreateSessionL()
// ---------------------------------------------------------------------------
//
CDevandTruSrvCertStoreSession* CDevandTruSrvCertStoreServer::CreateSessionL()
    {
    return CDevandTruSrvCertStoreSession::NewL(*iConduit);
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::ListPolicy()
// ---------------------------------------------------------------------------
//
const TSecurityPolicy& CDevandTruSrvCertStoreServer::ListPolicy(TCertificateOwnerType aOwnerType) const
    {
    switch (aOwnerType)
        {
        case EUserCertificate:
            return KPolicyAlwaysPass;
        case EPeerCertificate:
            return KPolicyRequireReadUserData;

        default:
            return KPolicyAlwaysFail;
        }
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::AddRemovePolicy()
// ---------------------------------------------------------------------------
//
const TSecurityPolicy& CDevandTruSrvCertStoreServer::AddRemovePolicy(TCertificateOwnerType aOwnerType) const
    {
    switch (aOwnerType)
        {
        case EUserCertificate:
        case EPeerCertificate:
            return KPolicyRequireWriteDeviceData;

        default:
            return KPolicyAlwaysFail;
        }
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::RetrievePolicy()
// ---------------------------------------------------------------------------
//
const TSecurityPolicy& CDevandTruSrvCertStoreServer::RetrievePolicy(TCertificateOwnerType aOwnerType) const
    {
    switch (aOwnerType)
        {
        case EUserCertificate:
        case EPeerCertificate:
            return KPolicyRequireReadUserData;

        default:
            return KPolicyAlwaysFail;
        }
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::WriteTrustSettingsPolicy()
// ---------------------------------------------------------------------------
//
const TSecurityPolicy& CDevandTruSrvCertStoreServer::WriteTrustSettingsPolicy() const
    {
    return KPolicyRequireWriteDeviceData;
    }


// Read-only interface 

// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::ListL()
// ---------------------------------------------------------------------------
//
void CDevandTruSrvCertStoreServer::ListL(const CCertAttributeFilter& aFilter,
                 RPointerArray<CDevTokenCertInfo>& aCertsOut,
                 const RMessage2& aMessage, TBool aFromTruSiteSrv ) const
    {

    // check that if KeyUsage is set, only User certificates are requested
    if (aFilter.iKeyUsage != EX509UsageAll &&
    (!aFilter.iOwnerTypeIsSet || aFilter.iOwnerType != EUserCertificate))
        {
        User::Leave(KErrArgument);
        }

    // API policing
    if (!aFromTruSiteSrv)
        {
        if (!ListPolicy( aFilter.iOwnerType ).CheckPolicy(aMessage))
            {
            User::Leave(KErrPermissionDenied);
            } 	
        } 

    TInt count = iEntryList->Count();
    for (TInt index = 0; index < count; index++)
        {
        const CDevandTruSrvCertStoreEntry& entry = iEntryList->GetByIndex(index);

        if (CertEntryMatchesFilter(aFilter, entry))
            {
            User::LeaveIfError(aCertsOut.Append(&entry.CertInfo()));
            }
        }
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::CertEntryMatchesFilter()
// ---------------------------------------------------------------------------
//
TBool CDevandTruSrvCertStoreServer::CertEntryMatchesFilter(const CCertAttributeFilter& aFilter,
                         const CDevandTruSrvCertStoreEntry& aEntry) const
    {
    if (aFilter.iUidIsSet && !aEntry.IsApplicable(aFilter.iUid))
        {
        return EFalse;
        }

    const CDevTokenCertInfo& certInfo = aEntry.CertInfo();

    if (aFilter.iFormatIsSet && aFilter.iFormat != certInfo.CertificateFormat())
        {
        return EFalse;
        }

    if (aFilter.iOwnerTypeIsSet && aFilter.iOwnerType != certInfo.CertificateOwnerType())
        {
        return EFalse;
        }

    if (aFilter.iSubjectKeyIdIsSet && aFilter.iSubjectKeyId != certInfo.SubjectKeyId())
        {
        return EFalse;
        }

    if (aFilter.iLabelIsSet && aFilter.iLabel != certInfo.Label())
        {
        return EFalse;
        }

    return ETrue;
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::GetCertL()
// ---------------------------------------------------------------------------
//
const CDevTokenCertInfo& CDevandTruSrvCertStoreServer::GetCertL(TInt aHandle) const 
    {
    // Leaves if not found
    return iEntryList->GetByHandleL(aHandle).CertInfo();
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::ApplicationsL()
// ---------------------------------------------------------------------------
//
const RArray<TUid>& CDevandTruSrvCertStoreServer::ApplicationsL(TInt aHandle) const
    {
    return iEntryList->GetByHandleL(aHandle).CertificateApps();
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::IsApplicableL()
// ---------------------------------------------------------------------------
//
TBool CDevandTruSrvCertStoreServer::IsApplicableL(TInt aHandle, TUid aApplication) const
    {
    return iEntryList->GetByHandleL(aHandle).IsApplicable(aApplication);
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::TrustedL()
// ---------------------------------------------------------------------------
//
TBool CDevandTruSrvCertStoreServer::TrustedL(TInt aHandle) const
    { 
    return iEntryList->GetByHandleL(aHandle).Trusted();
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::RetrieveLC()
// ---------------------------------------------------------------------------
//
HBufC8* CDevandTruSrvCertStoreServer::RetrieveLC(TInt aHandle, const RMessage2& aMessage, TBool aFromTruSiteSrv) const
    {
    const CDevandTruSrvCertStoreEntry& entry = iEntryList->GetByHandleL(aHandle);

    // API policing
    if ( !aFromTruSiteSrv )
        {
        if (!RetrievePolicy(entry.CertInfo().CertificateOwnerType()).CheckPolicy(aMessage))
            {
            User::Leave( KErrPermissionDenied );
            }	
        }

    TInt size = entry.CertInfo().Size();
    HBufC8* buf = HBufC8::NewMaxLC(size);
    TPtr8 ptr = buf->Des();
    ptr.FillZ();

    RStoreReadStream stream;
    stream.OpenLC(*iStore, entry.DataStreamId());
    stream.ReadL(ptr, size);
    CleanupStack::PopAndDestroy(&stream);

    return buf;
    }


// Writable interface

// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::AddL()
// ---------------------------------------------------------------------------
//
void CDevandTruSrvCertStoreServer::AddL(const TDevTokenAddCertDataStruct& aInfo,
                const TDesC8& aCert,
                const RMessage2& aMessage, TBool aFromTruSiteSrv )
    {
    // Check if a certificate with this name already exists
    if (iEntryList->LabelExists(aInfo.iLabel))
        {
        User::Leave(KErrBadName);
        }

    // Check subject key id and cert data are supplied, issuer key id is optional
    if (aInfo.iSubjectKeyId == KNullDesC8 || aCert == KNullDesC8)
        {
        User::Leave(KErrArgument);
        }

    // Create cert entry (this sanity checks the rest of the arguments)
    CDevTokenCertInfo* certInfo = CDevTokenCertInfo::NewLC(
        aInfo.iLabel,
        aInfo.iFormat, 
        aInfo.iCertificateOwnerType,
        aCert.Length(),
        &aInfo.iSubjectKeyId,
        &aInfo.iIssuerKeyId,
        iEntryList->NextFreeHandle(),
        aInfo.iDeletable);

    // API policing
    if ( !aFromTruSiteSrv )
        {
        if (!AddRemovePolicy(aInfo.iCertificateOwnerType).CheckPolicy(aMessage))
            {
            User::Leave(KErrPermissionDenied);
            }	
        }

    CompactStoreL();

    TRAPD(err, DoAddL(*certInfo, aCert));
    CleanupStack::PopAndDestroy(certInfo);

    if (err != KErrNone)
        {
        iStore->Revert();
        User::Leave(err);
        }
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::DoAddL()
// ---------------------------------------------------------------------------
//
void CDevandTruSrvCertStoreServer::DoAddL(const CDevTokenCertInfo& aCertInfo, const TDesC8& aCertData)
    {
    TStreamId dataStreamId = WriteCertDataStreamL(aCertData);

    RArray<TUid> initialApps;
    CleanupClosePushL(initialApps);

    CDevandTruSrvCertStoreEntry* entry = CDevandTruSrvCertStoreEntry::NewL(
        aCertInfo,
        initialApps,
        EFalse,
        dataStreamId);
    CleanupStack::PopAndDestroy(&initialApps);
    CleanupStack::PushL(entry);

    TInt index = iEntryList->AppendL(entry);
    CleanupStack::Pop(entry); // iEntryList has taken ownership

    TRAPD(err, UpdateStoreL());
    if ( (err == KErrNone) && (aCertInfo.CertificateOwnerType() == EPeerCertificate ))
        {
        CX509Certificate* cert = CX509Certificate::NewLC( aCertData );
        TBuf8<KSHA1Length> certHash;
        certHash.Copy(cert->Fingerprint()); 
         
          
        const CX500DistinguishedName& dName = cert->SubjectName();
        // Retrieve CN
        HBufC* cn = dName.ExtractFieldL( KX520CommonName );  
        CleanupStack::PushL(cn);  
        iTrustedSitesServer->AddL( certHash, *cn );

        CleanupStack::PopAndDestroy( 2 );//cert, cn	
        }
    if (err != KErrNone)
        {
        iEntryList->Remove(index);
        delete entry;
        User::Leave(err);
        }
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::WriteCertDataStreamL()
// ---------------------------------------------------------------------------
//
TStreamId CDevandTruSrvCertStoreServer::WriteCertDataStreamL(const TDesC8& aData)
    {
    RStoreWriteStream stream;
    TStreamId streamId = stream.CreateLC(*iStore);
    stream.WriteL(aData);
    stream.CommitL();
    CleanupStack::PopAndDestroy(&stream);
    return streamId;
    } 


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::RemoveL()
// ---------------------------------------------------------------------------
//
void CDevandTruSrvCertStoreServer::RemoveL(TInt aHandle, const RMessage2& aMessage,  TBool aFromTruSiteSrv)
    {
    TInt index = iEntryList->IndexForHandle(aHandle);
    User::LeaveIfError(index);

    // API policing
    const CDevandTruSrvCertStoreEntry& entry = iEntryList->GetByIndex(index);
    if (!aFromTruSiteSrv)
        {
        if (!AddRemovePolicy(entry.CertInfo().CertificateOwnerType()).CheckPolicy(aMessage))
            {
            User::Leave(KErrPermissionDenied);
            }	
        }

    CompactStoreL();

    CDevandTruSrvCertStoreEntry* oldEntry = iEntryList->Remove(index);
    TRAPD(err, UpdateStoreL());
    if (err == KErrNone)
        {
        // If trusted site certificate is removed, the corresponding records
        // in trusted site store should also be removed to stop trusting.
        if( oldEntry->CertInfo().CertificateOwnerType() == EPeerCertificate )
            {
            TInt size = oldEntry->CertInfo().Size();
            HBufC8* buf = HBufC8::NewMaxLC(size);
            TPtr8 ptr = buf->Des();
            ptr.FillZ();

            RStoreReadStream stream;
            stream.OpenLC(*iStore, oldEntry->DataStreamId());
            stream.ReadL(ptr, size);
            CleanupStack::PopAndDestroy(&stream);


            CX509Certificate* cert = CX509Certificate::NewLC(*buf);
            TBuf8<KSHA1Length> certHash;
            certHash.Copy(cert->Fingerprint()); 

            iTrustedSitesServer->RemoveL( certHash );

            CleanupStack::PopAndDestroy( 2 );//buf, cert
            }
        delete oldEntry;
        }
    else
        {
        iStore->Revert();
        // This will always succeed because we just did a remove
        iEntryList->AppendL(oldEntry);
        }
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::SetApplicabilityL()
// ---------------------------------------------------------------------------
//
void CDevandTruSrvCertStoreServer::SetApplicabilityL(TInt /*aHandle*/,
                       const RArray<TUid>& /*aApps*/,
                       const RMessage2& aMessage)
    {
    // Setting Applicability is meant for CA certificate only.
    // in DevandTruSrvCertStore, we only store Personal ceritificate(Device Cert )
    // and Peer certificate( trust server cert ).
    
    aMessage.Complete( KErrNotSupported ); 
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::SetTrustL()
// ---------------------------------------------------------------------------
//
void CDevandTruSrvCertStoreServer::SetTrustL(TInt /*aHandle*/,
                   TBool /*aTrusted*/,
                   const RMessage2& aMessage)
    {
    // Setting Trust is meant for CA certificate only.
    // in DevandTruSrvCertStore, we only store Personal ceritificate(Device Cert )
    // and Peer certificate( trust server cert ).
    
    aMessage.Complete( KErrNotSupported ); 
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::UpdateStoreL()
// ---------------------------------------------------------------------------
//
void CDevandTruSrvCertStoreServer::UpdateStoreL()
    {
    RStoreWriteStream stream;
    stream.ReplaceLC(*iStore, iStreamId);
    stream << *iEntryList;
    stream.CommitL();
    CleanupStack::PopAndDestroy(&stream);

    iStore->CommitL();
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::CompactStoreL()
// ---------------------------------------------------------------------------
//
void CDevandTruSrvCertStoreServer::CompactStoreL()
    {
    iStore->ReclaimL();
    iStore->CompactL();
    iStore->CommitL();
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::RestoreL()
// ---------------------------------------------------------------------------
//
void CDevandTruSrvCertStoreServer::RestoreL(const TDesC& aFilename)
    {
    // Make sure the store is not read-only
    User::LeaveIfError(iFs.SetAtt(aFilename, KEntryAttNormal, KEntryAttReadOnly));

    // Open the store
    RFile file;
    User::LeaveIfError(file.Open(iFs, aFilename, EFileRead | EFileWrite));
    CleanupClosePushL(file);
    CPermanentFileStore* store = CPermanentFileStore::FromL(file);
    CleanupStack::Pop(&file); // now owned by store
    CleanupStack::PushL(store);

    // Read id of cert list stream
    TStreamId caCertEntryStreamId;
    RStoreReadStream stream;
    stream.OpenLC(*store, store->Root());
    stream >> iStreamId;
    CleanupStack::PopAndDestroy(&stream);

    // Read the certificate list
    RStoreReadStream caCertEntryStream;
    caCertEntryStream.OpenLC(*store, iStreamId);
    iEntryList = CDevandTruSrvCertStoreEntryList::NewL(caCertEntryStream);
    CleanupStack::PopAndDestroy(&caCertEntryStream);

    assert(!iStore, EPanicCertStoreRestoreState);
    iStore = store;
    CleanupStack::Pop(store);
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::OpenStoreL()
// ---------------------------------------------------------------------------
//
void CDevandTruSrvCertStoreServer::OpenStoreL()
    {
    TBuf<KMaxFilenameLength> filename;
    FileUtils::MakePrivateFilenameL(iFs, KCertStoreFilename, filename);

    TRAPD(err, RestoreL(filename));

    if (err == KErrNoMemory || err == KErrInUse)
        {
        User::Leave(err);
        }

    if (err != KErrNone)
        {
        // Couldn't open RAM based store, copy from ROM 

        FileUtils::EnsurePathL(iFs, filename);

        TBuf<KMaxFilenameLength> romFilename;
        FileUtils::MakePrivateROMFilenameL(iFs, KCertStoreFilename, romFilename);

        if (FileUtils::ExistsL(iFs, romFilename))
            {
            FileUtils::CopyL(iFs, romFilename, filename);
            }
        else
            {
            CreateStoreFileL(filename);
            }

        // Retry open, and leave on failure
        RestoreL(filename);
        }

    assert(iStore, EPanicCertStoreOpenState);
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::CreateStoreFileL()
// ---------------------------------------------------------------------------
//
void CDevandTruSrvCertStoreServer::CreateStoreFileL(const TDesC& aFile)
    {
    TRAPD(err, DoCreateStoreFileL(aFile));
    if (err != KErrNone)
        {
        // Attempt to delete file, but don't complain if it fails
        iFs.Delete(aFile);  
        User::Leave(err);
        }
    }


// ---------------------------------------------------------------------------
// CDevandTruSrvCertStoreServer::DoCreateStoreFileL()
// ---------------------------------------------------------------------------
//
void CDevandTruSrvCertStoreServer::DoCreateStoreFileL(const TDesC& aFile)
    {
    CPermanentFileStore* fileStore = CPermanentFileStore::ReplaceLC(iFs, aFile, EFileRead | EFileWrite | EFileShareExclusive);
    fileStore->SetTypeL(KPermanentFileStoreLayoutUid);

    // Create info stream
    CDevandTruSrvCertStoreEntryList* emptyCertList = CDevandTruSrvCertStoreEntryList::NewLC();  
    RStoreWriteStream infoStream;
    TStreamId streamId = infoStream.CreateLC(*fileStore);
    infoStream << *emptyCertList;
    infoStream.CommitL();
    CleanupStack::PopAndDestroy(2, emptyCertList);

    // Create root stream - just contains id of info stream
    RStoreWriteStream rootStream;
    TStreamId rootStreamId = rootStream.CreateLC(*fileStore);
    fileStore->SetRootL(rootStreamId);
    rootStream << streamId;
    rootStream.CommitL();
    CleanupStack::PopAndDestroy(&rootStream);

    fileStore->CommitL();
    CleanupStack::PopAndDestroy(fileStore);
    }

//EOF