pkiutilities/CertSaver/src/CertSaverModel.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Wed, 13 Oct 2010 15:30:47 +0300
branchRCL_3
changeset 67 79bd6bd83ec3
parent 54 94da73d93b58
permissions -rw-r--r--
Revision: 201039 Kit: 201041

/*
* Copyright (c) 2003-2007 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:   Class that handles user input and launching of dialogs
*
*/


// INCLUDE FILES
#include <aknnotewrappers.h>        // Note dialogs
#include <aknmessagequerydialog.h>  // For CAknMessageQueryDialog
#include <StringLoader.h>           // For loading resource strings
#include <unifiedcertstore.h>       // For saving the certificates
#include <mctwritablecertstore.h>   // For saving the certificates
#include <sysutil.h>                // For FFSSpaceBelowCriticalLevelL(..)
#include <X509CertNameParser.h>     // For default label
#include <x509cert.h>               // For CX509Certificate
#include <wtlscert.h>               // For WTLSCertificate
#include <hash.h>                   // MD5 fingerprint
#include <certificateapps.h>
#include <mctkeystore.h>
#include <securityerr.h>
#include <asnpkcs.h>
#include <unifiedkeystore.h>
#include <x509certext.h>
#include <mctkeystore.h>
#include <TrustedSitesStore.h>

#include <CertSaver.rsg>
#include "CertSaverModel.h"
#include "CertSaverDocument.h"
#include "CertSaverAppUi.h"
#include "CertSaverSyncWrapper.h"
#include "certsaver.hrh"
#include "securityuisvariant.hrh"

// CONSTANTS
const TInt32 KWTLSTrusterUID( 268479059 );
const TInt32 KInternetTrusterUID( 268441661 );
const TInt32 KApplicationControllerTrusterUID( 268452523 );
const TInt32 KJavaInstallTrusterUID( 270506792 );
const TInt32 KOCSPTrusterUID( 268478646 );
const TInt32 KVPNUID( 270498195 );

const TInt KTrusterArrayInitSize( 2 );

const TInt KMaxLengthTextMeassageBody( 5000 );
const TInt KMaxLengthTextDateString( 11 );    // "dd/mm/yyyy0"

//Issuer and Owner max visible length
const TInt KMaxLengthTextCertIdentifierVisible( 1000 );
const TInt KAttempts( 3 );

const TInt KFingerprintLength( 50 );

_LIT( KCertSaverListBoxItemPrefix, "1\t" );
const TInt KItemBufLen = 2 + KMaxName;

_LIT( KPrivateKeyLabel, "PrivateKey " );
const TInt KPrivaKeyLabelLength( 50 );
_LIT( KDateString,"%D%M%Y%1%2%3" );
_LIT( KTimeString,"%-B%:0%J%:1%T%:2%S%:3%+B" );
_LIT( KSpace, " " );
_LIT( KDoubleEnter, "\n\n" );
_LIT( KEnter, "\n" );

const TUid KTrustedServerTokenUid = { 0x101FB66F };
const TUid KFileTokensUid = { 0x101F501A };

_LIT_SECURITY_POLICY_V1( KSymbianKeyStoreMgmtPolicy,
                         VID_DEFAULT, ECapabilityWriteUserData );
_LIT_SECURITY_POLICY_C1( KSymbianKeyStoreUsePolicy, ECapabilityReadUserData );


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

// Destructor
CCertSaverModel::~CCertSaverModel()
    {
    delete iWrapper;
    iEntries.Close();
    delete iUnifiedCertStore;
    iTrusterUids.Close();
    }

// ----------------------------------------------------------
// CCertSaverModel::CCertSaverModel(
//    const CCertSaverDocument* aDocument, CCertSaverAppUi* aAppUi)
// ----------------------------------------------------------
//
CCertSaverModel::CCertSaverModel(
    CCertSaverAppUi* aAppUi,
    const CCertParser& aParser ):
    iAppUi( aAppUi ), iFs( iAppUi->CoeEnv()->FsSession() ), iParser( aParser ),
    iSavedCACertsCount( 0 ), iSavedKeysCount( 0 ),
    iSavedUserCertsCount( 0 ), iKeyAlreadyExists( EFalse )
    {
    }

// ----------------------------------------------------------
// CCertSaverModel::SaveCertificateL()
// ----------------------------------------------------------
//
void CCertSaverModel::SaveCertificateL(
            const CX509Certificate& aCertificate,
            const TCertificateOwnerType& aOwnerType,
            const TCertificateFormat& aCertFormat )
    {
    iCertOwnerType = aOwnerType;
    iCertFormat = aCertFormat;
    iNewCert = &aCertificate;

    if ( aOwnerType == EPeerCertificate )
        {
        TInt ret = QueryTrustedSiteL();
        if ( ret != KErrNone )
            {
             return;
            }
        }

    SaveCertL();
    }

// ----------------------------------------------------------
// CCertSaverModel::DoSavePrivateKeyL()
//
// ----------------------------------------------------------
//
void CCertSaverModel::DoSavePrivateKeyL( const TDesC8& aKey )
    {
    CheckFSSpaceL( aKey );

    TKeyIdentifier keyIdentifier;
    CDecPKCS8Data* pkcs8Data = TASN1DecPKCS8::DecodeDERL( aKey );
    CleanupStack::PushL( pkcs8Data );
    MPKCS8DecodedKeyPairData* keyPairData = pkcs8Data->KeyPairData();
    keyPairData->GetKeyIdentifierL( keyIdentifier );

    TTime startDate;
    TTime endDate;
    GetKeyValidityPeriodL( startDate, endDate, keyIdentifier );

    TInt err = KErrNone;
    CCTKeyInfo* keyInfo = NULL;
    TBuf<KPrivaKeyLabelLength> keyLabel( KPrivateKeyLabel );
    TKeyUsagePKCS15 keyUsage = KeyUsageL( keyIdentifier, pkcs8Data->Algorithm() );
    CleanupStack::PopAndDestroy( pkcs8Data );
    if (KeyAlreadyExistsL( startDate, endDate, keyIdentifier, keyUsage) )
        {
        User::Leave( KErrNone );
        }

    TInt accessType( 0 );

    accessType |= CCTKeyInfo::EExtractable;

    for ( TInt i = 0; i < KAttempts; i++ )
        {
        CreateKeyLabelL( keyLabel );
        // Should not use hardcoded index
        err = iWrapper->AddKey( 0, aKey, keyUsage, keyLabel,
            accessType, startDate, endDate, keyInfo );
        if ( err != KErrAlreadyExists )
            {
            i = KAttempts;
            }
        keyLabel.Zero();
        }

    TCTTokenObjectHandle handle;
    if ( keyInfo )
        {
        handle = keyInfo->Handle();
        keyInfo->Release();
        keyInfo = NULL;
        }

    switch ( err )
        {
        case KErrNone:
            {
            ++iSavedKeysCount;
            break;
            }
        case KErrKeySize:
        case KErrArgument:
            {
            ShowErrorNoteL( R_CERTSAVER_KEY_TYPE_NOT_SUPPORTED );
            User::Leave( KErrCancel );
            break;
            }
        case KErrKeyValidity:
            {
            ShowInformationNoteL( R_CERTSAVER_QTN_CM_PKCS12_EXPIRED );
            User::Leave( KErrCancel );
            }
        case KErrKeyUsage:
            {
            ShowErrorNoteL( R_CERTSAVER_PRIVATE_KEY_CORRUPTED );
            User::Leave( KErrCancel );
            break;
            }
        case KErrCancel:
        case KErrPermissionDenied:
            {
            ShowErrorNoteL( R_CERTSAVER_PKCS12_DISCARDED );
            User::Leave( KErrCancel );
            break;
            }
        case KErrCorrupt:
        case KErrEof:
            {
            ShowErrorNoteL( R_CERTSAVER_KEYSTORE_CORRUPTED );
            User::Leave( KErrCancel );
            break;
            }
        case KErrAlreadyExists:
            {
            User::Leave( KErrCancel );
            break;
            }
        default:
            {
            User::Leave( err );
            break;
            }
        }

    User::LeaveIfError(
        iWrapper->SetManagementPolicy( handle, KSymbianKeyStoreMgmtPolicy) );
    User::LeaveIfError(
        iWrapper->SetUsePolicy( handle, KSymbianKeyStoreUsePolicy ) );
    }

// ----------------------------------------------------------
// TBool CCertSaverModel::KeyAlreadyExistsL()
//
// ----------------------------------------------------------
//
TBool CCertSaverModel::KeyAlreadyExistsL(
    TTime& aStartDate,
    TTime& aEndDate,
    const TKeyIdentifier& aKeyIdentifier,
    TKeyUsagePKCS15& aKeyUsage )
    {
    TBool ret = EFalse;
    TCTKeyAttributeFilter keyFilter;
    keyFilter.iKeyAlgorithm = CKeyInfoBase::EInvalidAlgorithm;
    keyFilter.iKeyId = aKeyIdentifier;
    keyFilter.iPolicyFilter = TCTKeyAttributeFilter::EManageableKeys;
    keyFilter.iUsage = aKeyUsage;
    RMPointerArray<CCTKeyInfo> keyArray;
    TInt err = iWrapper->ListKeys( keyArray, keyFilter );
    CleanupClosePushL( keyArray );
    switch ( err )
        {
        case KErrNone:
            {
            break;
            }
        case KErrCorrupt:
        case KErrEof:
            {
            ShowErrorNoteL( R_CERTSAVER_KEYSTORE_CORRUPTED );
            User::Leave( KErrCancel );
            }
        default:
            {
            User::Leave( err );
            }
        }
    for ( TInt i = 0; ret == EFalse && i < keyArray.Count(); i++ )
        {
        if ( keyArray[i]->StartDate() == aStartDate &&
             keyArray[i]->EndDate() == aEndDate )
            {
            ret = ETrue;
            iKeyAlreadyExists = ETrue;
            }
        }
    CleanupStack::PopAndDestroy( &keyArray );
    return ret;
    }

// ----------------------------------------------------------
// CCertSaverModel::GetKeyValidityPeriodL()
//
// ----------------------------------------------------------
//
void CCertSaverModel::GetKeyValidityPeriodL(
    TTime& aStartDate,
    TTime& aEndDate,
    const TKeyIdentifier& aKeyIdentifier )
    {

    for ( TInt i = 0; i < iParser.UserCertificates().Count(); i++ )
        {
        const CX509Certificate* cert = iParser.UserCertificates().At( i );
        if ( cert->KeyIdentifierL() == aKeyIdentifier )
            {
            // Associated certificate found
            // In the first round aStartDate and aEndDate is initialised.
            if ( i == 0 || aStartDate > cert->ValidityPeriod().Start() )
                {
                aStartDate = cert->ValidityPeriod().Start();
                }
            if ( i == 0 || aEndDate < cert->ValidityPeriod().Finish() )
                {
                aEndDate = cert->ValidityPeriod().Finish();
                }
            }
        }
    }

// ----------------------------------------------------------
// CCertSaverModel::CreateKeyLabelL()
//
// ----------------------------------------------------------
//
void CCertSaverModel::CreateKeyLabelL( TDes& aLabel )
    {
    TTime time;
    time.UniversalTime();
    TBuf<KPrivaKeyLabelLength> dateBuf;
    time.FormatL( dateBuf, KDateString );
    aLabel.Append( dateBuf );
    dateBuf.Zero();
    aLabel.Append( KSpace );

    time.FormatL( dateBuf, KTimeString );
    aLabel.Append( dateBuf );
    }

// ----------------------------------------------------------
// CCertSaverModel::SavePrivateKeyL()
//
// ----------------------------------------------------------
//
void CCertSaverModel::SavePrivateKeyL()
    {
    if ( iParser.Keys().Count() <= 0 )
        {
        return;
        }
    if ( NULL == iWrapper )
        {
        iWrapper = CCertSaverSyncWrapper::NewL();
        }
    TInt err = iWrapper->InitializeKeyStoreL( iFs );

    TInt keyStoreCount = iWrapper->UnifiedKeyStore().KeyStoreManagerCount();
    if ( keyStoreCount <= 0 )
        {
        User::Leave( KErrCancel );
        }
    else
        {
        for ( TInt i = 0; i < keyStoreCount; ++i )
            {
            TUid uid =
            iWrapper->UnifiedKeyStore().KeyStoreManager(i).Token().TokenType().Type();
            if ( uid == TUid::Uid( KTokenTypeFileKeystore ) )
                // if this is not found, we use the first one,
                // which is already initialised
                {
                iSelectedKeyStore = i;
                }
            }
        }

    for ( TInt i = 0; i < iParser.Keys().Count(); i++ )
        {
        const HBufC8* key = iParser.Keys().At( i );
        TRAP(err, DoSavePrivateKeyL( *key ));
        User::LeaveIfError( err );
        }
    }

// ----------------------------------------------------------
// CCertSaverModel::KeyUsageL(
//    const TKeyIdentifier& aKeyIdentifier, TAlgorithmId aAlgorithm)
// ----------------------------------------------------------
//
TKeyUsagePKCS15 CCertSaverModel::KeyUsageL(
    const TKeyIdentifier& aKeyIdentifier,
    TAlgorithmId aAlgorithm )
    {

    TKeyUsagePKCS15 pkcs15KeyUsage = EPKCS15UsageNone;
    TKeyUsageX509 x509Usage = EX509UsageNone;

    for ( TInt i = 0; i < iParser.UserCertificates().Count(); i++ )
        {
        const CX509Certificate* cert = iParser.UserCertificates().At( i );
        if ( cert->KeyIdentifierL() == aKeyIdentifier )
            {
            const CX509CertExtension* ext = cert->Extension( KKeyUsage );
            if (ext)
                {
                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 );
                }
            }
        }

    pkcs15KeyUsage = KeyUsageX509ToPKCS15Private( x509Usage );
    // If any certificate in the file did not include key usage,
    // let's use default values.
    if ( EPKCS15UsageNone == pkcs15KeyUsage )
        {
        switch ( aAlgorithm )
            {
            case ERSA:
                {
                pkcs15KeyUsage |= EPKCS15UsageSignSignRecover;
                pkcs15KeyUsage |= EPKCS15UsageDecryptUnwrap;
                break;
                }
            case EDSA:
                {
                pkcs15KeyUsage |= EPKCS15UsageSignSignRecover;
                break;
                }
            default:
                {
                break;
                }
            }
        }
    return pkcs15KeyUsage;
    }

// ----------------------------------------------------------
// CCertSaverModel::CheckFSSpaceL(
//    const TDesC8& aDataToSave)
// ----------------------------------------------------------
//
void CCertSaverModel::CheckFSSpaceL( const TDesC8& aDataToSave )
    {
    if (SysUtil::FFSSpaceBelowCriticalLevelL( &iFs, aDataToSave.Size() ))
        {
        HBufC* p = StringLoader::LoadLC( R_CERTSAVER_MEMORY );
        CAknErrorNote* note = new (ELeave) CAknErrorNote( ETrue );
        note->ExecuteLD( p->Des() );
        CleanupStack::PopAndDestroy( p );
        User::Leave( KErrExitApp );
        }
    }

// ----------------------------------------------------------
// CCertSaverModel::SaveCertL()
// Saves certificate
// ----------------------------------------------------------
//
void CCertSaverModel::SaveCertL()
  {
    if ( !CertificateOkL() )
        {
        User::Leave( KErrCancel );
        }

    HBufC* message = HBufC::NewLC( KMaxLengthTextMeassageBody );
    TPtr msgPtr = message->Des();
    ConstructMessageL( msgPtr );
    CAknMessageQueryDialog* dlg = CAknMessageQueryDialog::NewL( *message );
    CleanupStack::PopAndDestroy( message );
    CleanupStack::PushL( dlg );


    dlg->PrepareLC( R_MESSAGE_QUERY_DOSAVE );

    HBufC* header = StringLoader::LoadLC( R_CERTSAVER_DETAILS_HEADING );
    dlg->QueryHeading()->SetTextL( header->Des() );
    CleanupStack::PopAndDestroy( header );
    CleanupStack::Pop( dlg );
    TBool doSave = dlg->RunLD();

    if ( doSave && iCertOwnerType == ECACertificate )
        {
        // warn user about security risk
        CAknQueryDialog* warningDialog = CAknQueryDialog::NewL();
        doSave = warningDialog->ExecuteLD( R_CERTSAVER_WARNING_NOTE );
        }

    if ( doSave )
        {
        //Check that there still is enough space to store the
        //certificate.
        CheckFSSpaceL( iNewCert->Encoding() );
        DoSaveCertL();
        }
    else
        {
        ShowConfirmationNoteL( R_CERTSAVER_CERT_DISCARDED );
        User::Leave( KErrCancel );
        }
  }

// ----------------------------------------------------------
// CCertSaverModel::InitCertStoreL()
//
// ----------------------------------------------------------
//
void CCertSaverModel::InitCertStoreL()
    {
    if ( !iUnifiedCertStore )
        {
        TRAPD( status, iUnifiedCertStore = CUnifiedCertStore::NewL( iFs, ETrue ) );
        if ( status != KErrNone )
            {
            ShowErrorNoteL( R_CERTSAVER_ERROR_CACERTS_DB_CORRUPTED );
            User::Leave( KErrExitApp );
            }
        // initialize unified cert store
        status = iWrapper->InitializeCertStore( *iUnifiedCertStore );
        if ( status )
            {
            HandleSaveErrorL( status );
            User::Leave( KErrExitApp );
            }
        }
    }

// ----------------------------------------------------------
// CCertSaverModel::DoSaveCertL()
// Tries to save the certificate to phone memory.
// ----------------------------------------------------------
//
void CCertSaverModel::DoSaveCertL()
    {
    TInt status = KErrNone;
    CCertAttributeFilter* filter = NULL;
    TCertificateFormat certFormat = EX509Certificate;
    HBufC* secondaryName = NULL;
    TCertLabel labelBuf;
    CCertificate* certificate = NULL;
    HBufC* label = NULL;

    if ( NULL == iWrapper )
        {
        iWrapper = CCertSaverSyncWrapper::NewL();
        }
    // Init unified certstore
    InitCertStoreL();

    // Check that certificate doesn't already exist.
    // Fingerprint of certificate is used to confirm this.
    filter = CCertAttributeFilter::NewL();
    filter->SetFormat( iCertFormat );
    filter->SetOwnerType( iCertOwnerType );
    // Delete old array first
    iEntries.Close();
    status = iWrapper->ListCerts( *iUnifiedCertStore, iEntries, *filter );
    delete filter;
    filter = NULL;
    if ( status )
        {
        if ( status != KErrCancel )
            {
            HandleSaveErrorL( status );
            }
        User::Leave( KErrExitApp );
        }

    TBool found = EFalse;

    for ( TInt i = 0; i < iEntries.Count() && !found; ++i )
        {
        iWrapper->Retrieve( *iUnifiedCertStore, *iEntries[i], certificate );
        // Compare fingerprint of listed certificates to
        // fingerprint of new certificate
        // If the certificate is already in CACerts.dat,
        // then don't save it
        if ( iNewCert->Fingerprint() == certificate->Fingerprint() &&
            (( *iEntries[i]).Handle().iTokenHandle.iTokenTypeUid == KFileTokensUid ) )
            {
            found = ETrue;
            }
        delete certificate;
        certificate = NULL;
        }

    // Cancel if certificate already exists.
    if ( found )
        {
        HandleSaveErrorL( KErrAlreadyExists );
        User::Leave( KErrCancel );
        }

    // Create default label from the certificate
    X509CertNameParser::PrimaryAndSecondaryNameL(
        (*(CX509Certificate*)iNewCert), label, secondaryName );
    CleanupStack::PushL( label );
    delete secondaryName;
    secondaryName = NULL;
    labelBuf = label->Des().Left( CERTSAVER_MAX_LABEL_LEN );
    CleanupStack::PopAndDestroy( label );
    label = NULL;
    // Asks unique label from user.
    status = QueryLabelL( labelBuf, *iUnifiedCertStore );
    if ( status )
        {
        if ( status != KErrCancel )
            {
            HandleSaveErrorL( status );
            }
        User::Leave( KErrCancel );
        }

    if ( ECACertificate == iCertOwnerType )
        {
        // Query trusted UIDs
        status = QueryTrusterUidsL( iTrusterUids );
        if ( status )
            {
            HandleSaveErrorL( status );
            User::Leave( KErrCancel );
            }
        }

    // Get interface to writable store.
    TInt certstoreIndex( -1 );
    TInt count = iUnifiedCertStore->WritableCertStoreCount();
    if ( count > 0 )
        {
        for ( TInt i = 0; i < count; i++ )
            {
            MCTWritableCertStore& writableCertStore =
                    iUnifiedCertStore->WritableCertStore( i );

            MCTToken& token = writableCertStore.Token();
            TUid tokenuid = token.Handle().iTokenTypeUid;
            if ( ( tokenuid == KTrustedServerTokenUid ) && ( iCertOwnerType == EPeerCertificate ) ||
                 ( tokenuid == KFileTokensUid ) && ( iCertOwnerType == ECACertificate ) ||
                 ( tokenuid == KFileTokensUid ) && ( iCertOwnerType == EUserCertificate ) )
                {
                certstoreIndex = i;
                break;
                }
            }

        if ( certstoreIndex < 0 )
            {
            // Couldn't find certificate storage
            ShowErrorNoteL( R_CERTSAVER_ERROR_CACERTS_DB_CORRUPTED );
            User::Leave( KErrExitApp );
            }

        status = iWrapper->AddCert( iUnifiedCertStore->WritableCertStore( certstoreIndex ),
                        labelBuf, iCertFormat, iCertOwnerType, 0, 0, iNewCert->Encoding() );

        if ( ( status == KErrNone ) && ( iCertOwnerType == EPeerCertificate) )
            {
            // Adding certificate succeded. Update trust site storage
            CTrustSitesStore* trustedSitesStore = CTrustSitesStore::NewL();
            CleanupStack::PushL( trustedSitesStore );
            TPtrC8 certBuf = iParser.CertificateBuf();
            TInt err = trustedSitesStore->AddL( certBuf, labelBuf );
            CleanupStack::PopAndDestroy( trustedSitesStore );
            }

        // If error happened, show error note and give up. Otherwise, continue
        HandleSaveErrorL( status );
        if ( status )
            {
            User::Leave( KErrCancel );
            }
        else
            {
            if ( ECACertificate == iCertOwnerType )
                {
                ++iSavedCACertsCount;
                }
            else
                {
                ++iSavedUserCertsCount;
                }
            }
        }
    else
        {
        // If there is none WritableCertStore,
        // then at least cacerts.dat is corrupted.
        ShowErrorNoteL( R_CERTSAVER_ERROR_CACERTS_DB_CORRUPTED );
        User::Leave( KErrExitApp );
        }

    if ( ECACertificate == iCertOwnerType )
        {
        // get just saved certificate
        // first, create a filter
        filter = CCertAttributeFilter::NewL();
        filter->SetLabel( labelBuf );
        filter->SetFormat( certFormat );
        filter->SetOwnerType( ECACertificate );

        // Delete array
        iEntries.Close();
        // then list certificates
        status = iWrapper->ListCerts( *iUnifiedCertStore, iEntries, *filter );
        delete filter;
        filter = NULL;

        // If error happened, show error note and give up. Otherwise, continue
        if ( status )
            {
            HandleSaveErrorL( status );
            User::Leave( KErrExitApp );
            }

        // takes ownership of trusterUids
        status = iWrapper->SetApplicability(
            iUnifiedCertStore->WritableCertStore( certstoreIndex ), *(iEntries[0]), iTrusterUids );

        // If error happened, show error note and give up. Otherwise, continue
        if ( status )
            {
            HandleSaveErrorL( status );
            User::Leave( KErrExitApp );
            }

        // Downloaded certificate is trusted by default
        status = iWrapper->SetTrust(
            iUnifiedCertStore->WritableCertStore(certstoreIndex), *(iEntries[0]), ETrue );
        if ( status )
            {
            HandleSaveErrorL( status );
            }


        } // if ( ECACertificate == iCertOwnerType )
    }
// ----------------------------------------------------------
// CCertSaverModel::QueryLabel()
// Queries label from user and confirms that it doesn't
// already exist.
// ----------------------------------------------------------
//
TInt CCertSaverModel::QueryLabelL( TCertLabel& aLabel, CUnifiedCertStore& aStore )
    {
    CCertAttributeFilter* filter = NULL;
    TInt status = KErrNone;
    RMPointerArray<CCTCertInfo> entries;
    TBool loop = ETrue;

    while ( loop )
        {
        CAknTextQueryDialog* dialog = CAknTextQueryDialog::NewL( aLabel );
      if ( !dialog->ExecuteLD( R_CERTSAVER_LABEL_QUERY ) )
            {
            // cancel
            ShowConfirmationNoteL( R_CERTSAVER_CERT_DISCARDED );
            return KErrCancel;
            }
        // Create filter to confirm that label doesn't already exist.
        filter = CCertAttributeFilter::NewL();
        filter->SetLabel( aLabel );

        // then list certificates
        status = iWrapper->ListCerts( aStore, entries, *filter );
        CleanupClosePushL( entries );
        delete filter;

        // If error happened, show error note and give up. Otherwise, continue
        if ( status )
            {
            HandleSaveErrorL( status );
            User::Leave( KErrExitApp );
            }

        if ( entries.Count() )
            {
            // Label already exists. Label is queried again.
            HandleSaveErrorL( KErrBadName );
            }
        else
            {
            // Label didn't exist.
            loop = EFalse;
            }
        CleanupStack::PopAndDestroy( &entries ); // entries
        } // while

    return status;
    }

// ----------------------------------------------------------
// CCertSaverModel::HandleSaveErrorL() const
// Shows a note according to aStatus. aStatus is the status
// of the save operation.
// ----------------------------------------------------------
//
void CCertSaverModel::HandleSaveErrorL( TInt aStatus ) const
    {
    switch ( aStatus )
        {
        case KErrNone:
            {
            ShowConfirmationNoteL( R_CERTSAVER_ERROR_SAVEOK );
            break;
            }
        case KErrNotSupported:
            {
            ShowErrorNoteL( R_CERTSAVER_ERROR_UNSUPPORTED_CERT );
            break;
            }
        case KErrBadName:
            {
            ShowErrorNoteL( R_CERTSAVER_ERROR_LABEL_ALREADY_EXISTS );
            break;
            }
        case KErrAlreadyExists:
            {
            ShowErrorNoteL( R_CERTSAVER_ERROR_ALREADY_EXISTS );
            break;
            }
        case KErrArgument:
            {
            ShowErrorNoteL( R_CERTSAVER_ERROR_CACERTS_DB_CORRUPTED );
            break;
            }
        default:
            {
            //No error note defined for unknown error.
            User::Leave( aStatus );
            break;
            }
        }   //switch
    }

// ----------------------------------------------------------
// CCertSaverModel::AddToMessageWithStringL() const
// String loaded from resources with StringLoader.
// ----------------------------------------------------------
//
void CCertSaverModel::AddToMessageWithStringL(
    TDes& aMessage, TInt aStringResID, const TDesC& aString ) const
    {
    HBufC* promptPtr = NULL;
    promptPtr = StringLoader::LoadL( aStringResID, aString );
    CleanupStack::PushL( promptPtr );
    TPtrC prompt( promptPtr->Des() );

    aMessage.Append( prompt );

    CleanupStack::PopAndDestroy( promptPtr ); // promptPtr
    }

// ----------------------------------------------------------
// CCertSaverModel::AddToMessageWithStringL() const
// String loaded from resources with StringLoader.
// ----------------------------------------------------------
//
void CCertSaverModel::AddToMessageWithIntL(
    TDes& aMessage,
    TInt aStringResID,
    TInt aInt ) const
    {
    HBufC* promptPtr = NULL;
    promptPtr = StringLoader::LoadL( aStringResID, aInt );
    CleanupStack::PushL( promptPtr );
    TPtrC prompt( promptPtr->Des() );

    aMessage.Append( prompt );
    aMessage.Append( KEnter );

    CleanupStack::PopAndDestroy( promptPtr ); // promptPtr
    }

// ----------------------------------------------------------
// CCertSaverModel::AddToMessageL() const
// String loaded from resources with StringLoader.
// ----------------------------------------------------------
//
void CCertSaverModel::AddToMessageL( TDes& aMessage, TInt aStringResID ) const
    {
    HBufC* promptPtr = NULL;
    promptPtr = StringLoader::LoadL( aStringResID );
    CleanupStack::PushL( promptPtr );
    TPtrC prompt( promptPtr->Des() );

    aMessage.Append( prompt );
    aMessage.Append( KEnter );

    CleanupStack::PopAndDestroy( promptPtr ); // promptPtr
    }

// ----------------------------------------------------------
// CCertSaverModel::ConstructMessageL() const
// Creates the certificate details message shown to the user.
// ----------------------------------------------------------
//
void CCertSaverModel::ConstructMessageL( TDes& aMessage ) const
    {
    HBufC16* issuerName = NULL;
    HBufC16* subjectName = NULL;


    X509CertNameParser::SubjectFullNameL( *((CX509Certificate*)iNewCert),
        subjectName );
    CleanupStack::PushL( subjectName );

    X509CertNameParser::IssuerFullNameL( *((CX509Certificate*)iNewCert),
        issuerName );
    CleanupStack::PushL( issuerName );

    AddToMessageWithStringL( aMessage, R_CERTSAVER_TEXT_LABEL,
        CutCertificateField(*subjectName) );
    AddNewlinesToMessage( aMessage );

    AddToMessageWithStringL( aMessage, R_CERTSAVER_TEXT_ISSUER,
        CutCertificateField( *issuerName ) );
    CleanupStack::PopAndDestroy( 2, subjectName );
    AddNewlinesToMessage( aMessage );

    if ( iCertOwnerType==EUserCertificate )
        {
        AddKeyUsageL( aMessage, *((CX509Certificate*)iNewCert) );
        }

    AddValidityPeriodL( aMessage, *((CX509Certificate*)iNewCert) );

    // SHA-1 fingerprint
    TBuf<KFingerprintLength> divided_fingerprint;
    DivideToBlocks( iNewCert->Fingerprint(), divided_fingerprint );
    AddToMessageWithStringL( aMessage, R_CERTSAVER_TEXT_FINGERPRINT,
        divided_fingerprint );

    AddNewlinesToMessage( aMessage );
    divided_fingerprint.Zero();

    // MD5 fingerprint
    CMD5* md5 = CMD5::NewL();
    CleanupStack::PushL( md5 );
    TPtrC8 MD5fingerprint = md5->Hash( iNewCert->Encoding() );

    // Divide fingerprint to blocks
    DivideToBlocks( MD5fingerprint, divided_fingerprint );
    CleanupStack::PopAndDestroy( md5 );
    AddToMessageWithStringL( aMessage, R_CERTSAVER_TEXT_FINGERPRINT_MD5,
        divided_fingerprint );
    AddNewlinesToMessage( aMessage );
    }

// -----------------------------------------------------------------------------
// CCTSecurityDialogsAO::AddKeyUsageL(...)
// -----------------------------------------------------------------------------
//
void CCertSaverModel::AddKeyUsageL( TDes& aMessage, const CX509Certificate& aCert ) const
    {
    TKeyUsageX509 x509Usage = EX509UsageNone;
    TKeyUsagePKCS15 pkcs15KeyUsage = EPKCS15UsageNone;
    const CX509CertExtension* ext = aCert.Extension( KKeyUsage );
    if (ext)
        {
        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 );
        }

    pkcs15KeyUsage = KeyUsageX509ToPKCS15Private( x509Usage );

    TInt usage = 0;
    switch( pkcs15KeyUsage )
        {
        case EPKCS15UsageSignSignRecover:
        case EPKCS15UsageSign:
        case EPKCS15UsageSignDecrypt:
            {
            usage = R_QTN_CM_CLIENT_AUTHENTICATION;
            break;
            }
        case EPKCS15UsageNonRepudiation:
            {
            usage = R_QTN_CM_DIGITAL_SIGNING;
            break;
            }
        default:
            {
            usage = R_QTN_CM_NOT_DEFINED;
            break;
            }
        }
    AddToMessageL( aMessage, R_QTN_CM_KEY_USAGE );
    HBufC* usageString = iAppUi->CoeEnv()->AllocReadResourceLC( usage );
    aMessage.Append( *usageString );
    CleanupStack::PopAndDestroy( usageString );
    AddNewlinesToMessage( aMessage );
    }

// -----------------------------------------------------------------------------
// CCTSecurityDialogsAO::AddValidityPeriodL(...)
// -----------------------------------------------------------------------------
//
void CCertSaverModel::AddValidityPeriodL(
    TDes& aMessage, const CX509Certificate& aCert ) const
    {
    // Hometime's offset to UTC
    TLocale locale;
    TTimeIntervalSeconds offSet = locale.UniversalTimeOffset();
    AddToMessageL( aMessage, R_CERTSAVER_QTN_CM_VALID_FROM );

    const CValidityPeriod& validityPeriod = aCert.ValidityPeriod();
    TTime startValue = validityPeriod.Start();
    startValue += offSet;
    TBuf<KMaxLengthTextDateString> startString;
    // read format string from AVKON resource
    HBufC* dateFormatString = iAppUi->CoeEnv()->AllocReadResourceLC(
        R_QTN_DATE_USUAL_WITH_ZERO );
    // format the date to user readable format. The format is locale dependent
    startValue.FormatL( startString, *dateFormatString );
    AknTextUtils::DisplayTextLanguageSpecificNumberConversion( startString );
    CleanupStack::PopAndDestroy( dateFormatString ); // dateFormatString
    aMessage.Append( startString );
    AddNewlinesToMessage( aMessage );

    AddToMessageL( aMessage, R_CERTSAVER_QTN_CM_VALID_UNTIL );
    TTime finishValue = validityPeriod.Finish();
    finishValue += offSet;
    TBuf<KMaxLengthTextDateString> finishString;
    // read format string from AVKON resource
    dateFormatString = iAppUi->CoeEnv()->AllocReadResourceLC(
        R_QTN_DATE_USUAL_WITH_ZERO );
    // format the date to user readable format. The format is locale dependent
    finishValue.FormatL( finishString, *dateFormatString );
    AknTextUtils::DisplayTextLanguageSpecificNumberConversion( finishString );
    CleanupStack::PopAndDestroy(); // dateFormatString
    aMessage.Append( finishString );
    AddNewlinesToMessage( aMessage );
    }

// ----------------------------------------------------------
// CCertSaverModel::AddNewlinesToMessage() const
// Adds two new lines to message.
// ----------------------------------------------------------
//
void CCertSaverModel::AddNewlinesToMessage( TDes& aMessage ) const
    {
    aMessage.Append( KDoubleEnter );
    }

// ----------------------------------------------------------
// CCertSaverModel::CertificateSupported() const
// Checks that cert is of supported type.
// ----------------------------------------------------------
//
TBool CCertSaverModel::CertificateSupported() const
    {
    if ( iCertFormat == EX509Certificate &&
       ( iCertOwnerType == ECACertificate ||
         iCertOwnerType == EPeerCertificate ||
         iCertOwnerType == EUserCertificate))
        {
        return ETrue;
        }
    return EFalse;
    }


// ----------------------------------------------------------
// CCertSaverModel::CertificateOkL() const
// Checks that cert is ok. Shows an error note if not.
// If certificate is not valid yet/anymore an error note is shown
// but ETrue is returned so that user can still save the
// certificate.
// ----------------------------------------------------------
//
TBool CCertSaverModel::CertificateOkL() const
    {
    if ( !CertificateSupported() )
        {
        ShowErrorNoteL( R_CERTSAVER_ERROR_UNSUPPORTED_CERT );
        return EFalse;
        }
    if ( CertNotValidAnymore() )
        {
        ShowErrorNoteL( R_CERTSAVER_ERROR_CERT_NOT_VALID );
        return ETrue;
        }
    else if ( CertNotValidYet() )
        {
        ShowErrorNoteL( R_CERTSAVER_ERROR_CERT_NOT_VALID_YET );
        }
    return ETrue;
    }

// ----------------------------------------------------------
// CCertSaverModel::CertNotValidAnymore() const
// Checks if cert isn't valid anymore.
// ----------------------------------------------------------
//
TBool CCertSaverModel::CertNotValidAnymore() const
    {
    TTime homeTime;
    homeTime.HomeTime();
    if ( iNewCert->ValidityPeriod().Finish() < homeTime )
        {
        return ETrue;
        }
    return EFalse;
    }

// ----------------------------------------------------------
// CCertSaverModel::CertNotValidYet() const
// Checks if cert isn't valid yet.
// ----------------------------------------------------------
//
TBool CCertSaverModel::CertNotValidYet() const
    {
    TTime homeTime;
    homeTime.HomeTime();
    if ( iNewCert->ValidityPeriod().Start() > homeTime )
        {
        return ETrue;
        }
    return EFalse;
    }

// ----------------------------------------------------------
// CCertSaverModel::ShowInformationNoteL() const
// Creates and shows a confirmation note.
// ----------------------------------------------------------
//
void CCertSaverModel::ShowInformationNoteL( TInt aResourceID ) const
    {
    HBufC* buffer = iAppUi->CoeEnv()->AllocReadResourceLC( aResourceID );
    CAknInformationNote* note = new (ELeave) CAknInformationNote( ETrue );
    note->ExecuteLD( buffer->Des() );
    CleanupStack::PopAndDestroy( buffer );
    }
// ----------------------------------------------------------
// CCertSaverModel::ShowConfirmationNoteL() const
// Creates and shows a confirmation note.
// ----------------------------------------------------------
//
void CCertSaverModel::ShowConfirmationNoteL( TInt aResourceID ) const
    {
    HBufC* buffer = iAppUi->CoeEnv()->AllocReadResourceLC( aResourceID );
    CAknConfirmationNote* note = new (ELeave) CAknConfirmationNote( ETrue );
    note->ExecuteLD( buffer->Des() );
    CleanupStack::PopAndDestroy( buffer );
    }

// ----------------------------------------------------------
// CCertSaverModel::ShowErrorNoteL() const
// Creates and shows an error note.
// ----------------------------------------------------------
//
void CCertSaverModel::ShowErrorNoteL( TInt aResourceID ) const
    {
    HBufC* buffer = iAppUi->CoeEnv()->AllocReadResourceLC( aResourceID );
    CAknErrorNote* note = new (ELeave) CAknErrorNote( ETrue );
    note->ExecuteLD(buffer->Des());
    CleanupStack::PopAndDestroy( buffer );
    }

// ----------------------------------------------------------
// CCertSaverModel::TrimCertificateFields() const
// Trims given descriptor so that everything after and
// including the fourth semicolon (;) is cropped.
// Returns the trimmed certificate field.
// ----------------------------------------------------------
//
TPtrC CCertSaverModel::TrimCertificateFields( TPtrC aField ) const
    {
    TPtrC cutField = CutCertificateField( aField );
    // Find one semicolon at a time and crop the
    // helpField from the left to search for the next semicolon
    TInt position = cutField.Locate( ';' ); // 1st semicolon
    TInt fieldLength = cutField.Length();

    // Need to check that position is not bigger than the length of cutField
    if ( position != KErrNotFound && position < fieldLength )
        {
        // Locate function counts from zero, Mid function
        // counts also from zero, add one to exclude the found semicolon
        TInt totalPosition = position;
        TPtrC field = cutField.Mid(totalPosition + 1);
        position = field.Locate(';'); // 2nd semicolon
        fieldLength = field.Length();

        if ( position != KErrNotFound && position < fieldLength )
            {
            totalPosition += position + 1;
            TPtrC field = cutField.Mid( totalPosition + 1 );
            position = field.Locate( ';' ); // 3rd semicolon
            fieldLength = field.Length();

            if ( position != KErrNotFound && position < fieldLength )
                {
                totalPosition += position + 1;
                TPtrC field = cutField.Mid( totalPosition + 1 );
                position = field.Locate( ';' ); // 4th semicolon
                fieldLength = field.Length();

                if ( position != KErrNotFound && position < fieldLength )
                  {
                  totalPosition += position + 1;
                  // Extract the leftmost part of the data field up to n:th character
                  TPtrC field = cutField.Mid( 0, totalPosition );
                  return field;
                  } // if
                } // if
            } // if
        } // if
    return cutField;
    }

// ----------------------------------------------------------
// CCertSaverModel::CutCertificateField() const
// If given descriptor is larger than defined maximum length
// this function cuts it.
// ----------------------------------------------------------
//
TPtrC CCertSaverModel::CutCertificateField( TPtrC aField ) const
    {
    TInt fieldLength = aField.Length();
    if ( fieldLength >= KMaxLengthTextCertIdentifierVisible )
        {
        TPtrC cutCertLabel = aField.Mid( 0, KMaxLengthTextCertIdentifierVisible );
        return cutCertLabel;
        }
    return aField;
    }

// ----------------------------------------------------------
// CCertSaverModel::QueryTrusterUidsL()
// Does needed tasks to exit.
// ----------------------------------------------------------
//
TInt CCertSaverModel::QueryTrusterUidsL( RArray<TUid>& aUids )
    {
    TInt ret = KErrCancel;
    CArrayFixFlat<TInt>* selectionArray =
        new (ELeave)  CArrayFixFlat<TInt>( KTrusterArrayInitSize );
    CleanupStack::PushL( selectionArray );
    CDesCArray* itemsArray = new (ELeave) CDesCArrayFlat( KTrusterArrayInitSize );
    CleanupStack::PushL( itemsArray );

    CCertificateAppInfoManager* appInfoManager =
        CCertificateAppInfoManager::NewL( iFs, EFalse );
    CleanupStack::PushL( appInfoManager );
    // copy applications to own array
    const RArray<TCertificateAppInfo>& apps = appInfoManager->Applications();
    RArray<TCertificateAppInfo> appsInItemArray( KTrusterArrayInitSize );
    CleanupClosePushL( appsInItemArray );
    UpdateTrustListboxItemL( apps, appsInItemArray, *itemsArray );

    CAknListQueryDialog* dlg = new (ELeave) CAknListQueryDialog( selectionArray );
    CleanupStack::PushL( dlg );
    dlg->PrepareLC( R_CERTSAVER_TRUST_SETTINGS_QUERY );
    dlg->SetItemTextArray( itemsArray );
    dlg->SetOwnershipType( ELbmDoesNotOwnItemArray );
    if ( dlg->RunLD() )
        {
        aUids.Reset();
        for ( TInt i = 0; i < selectionArray->Count(); ++i )
            {
            TInt ii = (*selectionArray)[ i ];
            aUids.Append( appsInItemArray[ ii ].Id() );
            }
        ret = KErrNone;
        }
    else
        {
        ShowConfirmationNoteL( R_CERTSAVER_CERT_DISCARDED );
        ret = KErrCancel;
        }
    CleanupStack::Pop( dlg );
    CleanupStack::PopAndDestroy( 4, selectionArray );
    return ret;
    }

// ----------------------------------------------------------
// CCertSaverModel::QueryTrustedSiteL()
// Shows query for trusted site certificate
// ----------------------------------------------------------
//
TInt CCertSaverModel::QueryTrustedSiteL()
    {
    TInt ret = KErrCancel;
    HBufC* label = NULL;
    HBufC* secondaryName = NULL;
    TCertLabel labelBuf;

    X509CertNameParser::PrimaryAndSecondaryNameL(
        (*(CX509Certificate*)iNewCert), label, secondaryName );
    CleanupStack::PushL( label );
    delete secondaryName;
    secondaryName = NULL;
    labelBuf = label->Des().Left( CERTSAVER_MAX_LABEL_LEN );


    HBufC* prompt = StringLoader::LoadLC( R_CERTSAVER_TRUSTEDSITE_WARNING, labelBuf );

    CAknMessageQueryDialog* note = CAknMessageQueryDialog::NewL( *prompt );

    note->PrepareLC( R_CERTSAVER_TRUSTED_SITE_QUERY );
    note->SetPromptL( *prompt );

    if ( note->RunLD() )
        {
        ret = KErrNone;
        }
    else
        {
        ShowConfirmationNoteL( R_CERTSAVER_CERT_DISCARDED );
        ret = KErrCancel;
        }

    CleanupStack::PopAndDestroy( prompt );

    CleanupStack::PopAndDestroy( label );
    return ret;
    }

// ----------------------------------------------------------
// CCertSaverModel::UpdateTrustListboxItemL()
// Updates trust setting listbox items
// ----------------------------------------------------------
//
void CCertSaverModel::UpdateTrustListboxItemL(
    const RArray<TCertificateAppInfo>& aApps,
    RArray<TCertificateAppInfo>& aAppsInItemArray,
    CDesCArray& aItemsArray ) const
  {
    for ( TInt i = 0; i < aApps.Count(); i++ )
        {
        TCertificateAppInfo appInfo = aApps[ i ];
        TBuf<KItemBufLen> item;
        item.Append( KCertSaverListBoxItemPrefix );
        TBuf<KMaxName> resource;

        switch( appInfo.Id().iUid )
            {
            case KWTLSTrusterUID:
                {
                // X.509 certiticate isn't needed with WTLS
                break;
                }
            case KInternetTrusterUID:
                {
               iAppUi->CoeEnv()->ReadResource(
                resource, R_CERTSAVER_ITEM_MAIL_IMAGE_CONN );
                break;
                }
            case KApplicationControllerTrusterUID:
                {
                // SWI certs are ROM based in platsec world.
                break;
                }
            case KJavaInstallTrusterUID:
                {
                // MIDP certstore is read-only..
                break;
                }
            case KOCSPTrusterUID:
                {
                iAppUi->CoeEnv()->ReadResource( resource, R_CERTSAVER_ITEM_OCSP );
                break;
                }
            case KVPNUID:
                {
                iAppUi->CoeEnv()->ReadResource( resource, R_CERTSAVER_ITEM_VPN );
                break;
                }
            default:
                {
                resource = appInfo.Name();
                break;
                }
            }
        if ( 0 < resource.Length())
            {
            item.Append( resource );
            aItemsArray.AppendL( item );
            aAppsInItemArray.Append( appInfo );
            resource.Zero();
            }
        }
  }

// ---------------------------------------------------------
// CCertManUIViewAuthority::DevideToBlocks
// ---------------------------------------------------------
//
void CCertSaverModel::DivideToBlocks( const TDesC8& aInput, TDes& aOutput ) const
    {
    _LIT( KBlockSeparator, " " );
    const TInt KBlockLength = 2;
    TInt blockIndex = 0;
    for ( TInt j = 0 ; j < aInput.Length() ; j++ )
        {
        if ( blockIndex == KBlockLength )
            {
            aOutput.Append( KBlockSeparator );
            blockIndex = 0;
            }
        aOutput.AppendNumFixedWidthUC( (TUint)(aInput[ j ]), EHex, 2 );
        ++blockIndex;
        }
    }

// ----------------------------------------------------
// CCertSaverModel::SavePKCS12L()
// Saves content of the PKCS#12 file
// ----------------------------------------------------
//
void CCertSaverModel::SavePKCS12L()
    {
    HBufC* message = HBufC::NewLC( KMaxLengthTextMeassageBody );
    TPtr msgPtr = message->Des();
    ConstructPKCS12QueryMsgL(msgPtr, iParser.Keys().Count(),
                            iParser.UserCertificates().Count(),
                            iParser.CACertificates().Count() );
    TBool save = DoMessageQueryL(
        R_MESSAGE_QUERY_DOSAVE, R_CERTSAVER_HEADER_PKCS12_FILE_CONTAINS,
        *message );
    CleanupStack::PopAndDestroy( message );
    message = NULL;
    if ( !save )
        {
        ShowInformationNoteL( R_CERTSAVER_PKCS12_DISCARDED );
        User::Leave( KErrExitApp );
        }
    TInt status = KErrNone;
    // save private keys
    TRAP( status, SavePrivateKeyL() );

    // save user certificates if private key was saved.
    if ( ( iSavedKeysCount > 0 || iKeyAlreadyExists ) && iParser.UserCertificates().Count() > 0 )
        {
        for ( TInt i = 0; i < iParser.UserCertificates().Count(); i++ )
            {
            const CX509Certificate* cert = iParser.UserCertificates().At(i);
            iCertOwnerType = EUserCertificate;
            iCertFormat = EX509Certificate;
            iNewCert = cert;
            TRAP( status, SaveCertL() );
            if ( KErrExitApp == status )
                {
                User::Leave( KErrExitApp );
                }
            }
        }
    // save CA certificates
    if ( iParser.CACertificates().Count() > 0 )
        {
        for ( TInt i = 0; i < iParser.CACertificates().Count(); i++ )
            {
            const CX509Certificate* cert = iParser.CACertificates().At( i );
            iCertOwnerType = ECACertificate;
            iCertFormat = EX509Certificate;
            iNewCert = cert;
            TRAP( status, SaveCertL() );
            if ( KErrExitApp == status )
                {
                User::Leave( KErrExitApp );
                }
            }
        }
    if ( iSavedCACertsCount != 0 || iSavedKeysCount != 0
        || iSavedUserCertsCount != 0 )
        {
        message = HBufC::NewLC( KMaxLengthTextMeassageBody );
        TPtr msgPtr2 = message->Des();
        ConstructPKCS12QueryMsgL(
            msgPtr2, iSavedKeysCount, iSavedUserCertsCount, iSavedCACertsCount );
        DoMessageQueryL(
            R_MESSAGE_QUERY_SAVED, R_CERTSAVER_HEADER_SAVED, *message );
        CleanupStack::PopAndDestroy( message );
        }
    else
        {
        ShowInformationNoteL( R_QTN_CM_PKCS12_SAVING_FAILED );
        }
    }

// ----------------------------------------------------------
// CCertSaverModel::DoMessageQuery()
// Displays message query dialog for user.
// ----------------------------------------------------------
//
TBool CCertSaverModel::DoMessageQueryL(
    TInt aDialogResId,
    TInt aHeadingResId,
    TDesC& aMessage )
    {
    CAknMessageQueryDialog* dlg = CAknMessageQueryDialog::NewL( aMessage );
    CleanupStack::PushL( dlg );
    dlg->PrepareLC( aDialogResId );

    HBufC* header = StringLoader::LoadLC( aHeadingResId );
    dlg->QueryHeading()->SetTextL( header->Des() );
    CleanupStack::PopAndDestroy( header );
    CleanupStack::Pop( dlg );
    return dlg->RunLD();
    }

// ----------------------------------------------------------
// CCertSaverModel::ConstructPKCS12QueryMsgL() const
// Creates the certificate details message shown to the user.
// ----------------------------------------------------------
//
void CCertSaverModel::ConstructPKCS12QueryMsgL(
    TDes& aMessage,
    TInt aPrivateKeys,
    TInt aUserCerts,
    TInt aCACerts ) const
    {
    if ( aPrivateKeys > 0 )
        {
        if ( aPrivateKeys == 1 )
            {
            AddToMessageL( aMessage, R_CERTSAVER_ONE_PRIVATE_KEY );
            }
        else
            {
            AddToMessageWithIntL( aMessage, R_CERTSAVER_PRIVATE_KEYS, aPrivateKeys );
            }
        }
    if ( aUserCerts > 0 )
        {
        if ( aUserCerts == 1 )
            {
            AddToMessageL(
                aMessage, R_CERTSAVER_ONE_PERSONAL_CERTIFICATE );
            }
        else
            {
            AddToMessageWithIntL(
                aMessage, R_CERTSAVER_PERSONAL_CERTIFICATES, aUserCerts );
            }
        }
    if ( aCACerts > 0 )
        {

        if ( aCACerts == 1 )
            {
            AddToMessageL(
                aMessage, R_CERTSAVER_ONE_AUTHORITY_CERTIFICATE );
            }
        else
            {
            AddToMessageWithIntL(
                aMessage, R_CERTSAVER_AUTHORITY_CERTIFICATES, aCACerts );
            }
        }
    }

// End of File