gba/gbaserver/src/bootstrap.cpp
author hgs
Wed, 20 Oct 2010 14:51:23 +0300
changeset 66 67b3e3c1fc87
parent 15 318c4eab2439
permissions -rw-r--r--
201041

/*
* Copyright (c) 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:  Implementation of bootstrap functions
*
*/


// This component has the following responsibilities 
// 1. Allow configuration of the BSF URL   
// 2. Open http connection to bsf    
// 3. On digest auth req get nonce  
// 4. Use this to find RAND AUTN 
// 5. Execute SIM auth, get back SRES, IK,CK 
// 6. return SRES 
// 7. Store keymaterial  to a token   

#include <s32stor.h>
#include <s32file.h>
#include <tconvbase64.h>                   //for base64 en/decoding

#include <ecom.h>
#include "dataretriever.h"
#include "bootstrap.h" 
#include "GbaCommon.h"
#include "GBALogger.h"
#include "GbaSession.h"

const TInt KKsNAFMaxLength = 128;
const TInt KStringLength = 80;
const TInt KMaxLengthIMPI = 255;
const TInt KMaxLengthNAFID = 255; 
const TInt KMaxLengthBTID = 255;
const TInt KMaxLengthKs = 32;
const TInt KMaxLengthRES = 16;          //16 bytes for RES
const TInt KMaxLengthAUTS = 16;         //16 bytes for AUTS
const TInt KMaxLengthEnAUTS = 20;
const TInt KMaxLengthRAND = 16;         //16 bytes for RAND
const TInt KMaxLengthTimeString = 30 ;
const TInt KHTTPTagLength = 7;
const TInt KAlgorithmTybeBufferLength = 32;
const TInt KBufferSize255 = 255;
const TInt KVariableIndex0 = 0;
const TInt KVariableIndex1 = 1;
const TInt KVariableIndex2 = 2;
const TInt KVariableIndex3 = 3;
const TInt KVariableIndex4 = 4;
const TInt KVariableIndex5 = 5;
const TInt KVariableIndex6 = 6;

#define GBA_UICC_INTERFACE_IMPLE        0x20029F0F
#define GBA_SOFTISIM_INTERFACE_IMPLE    0x20029F0E

// XML tags
_LIT8(KBTIDFlag,"<btid>");
_LIT8(KBTIDEndFlag,"</btid>");
_LIT8(KLifetimeFlag,"<lifetime>");
_LIT8(KLifetimeEndFlag,"</lifetime>");
_LIT(KGbaCredentialsFileName, "GbaCredentials.dat");
_LIT(KGBAStoreStandardDrive, "C:");
_LIT(KTimeFormat, "time %d,%d,%d,%d,%d,%d");
_LIT(KErrorMessage, "FAILED error = %d");
_LIT(Kakav1, "akav1");

// -----------------------------------------------------------------------------
// C3GPPBootstrap::NewL()
// -----------------------------------------------------------------------------
//
C3GPPBootstrap* C3GPPBootstrap::NewL( CGbaServerSession* aSession )
    {
    C3GPPBootstrap* self = NewLC( aSession );
    CleanupStack::Pop(self);
    return(self) ;
    }

// -----------------------------------------------------------------------------
// C3GPPBootstrap::NewLC()
// -----------------------------------------------------------------------------
//
C3GPPBootstrap* C3GPPBootstrap::NewLC( CGbaServerSession* aSession )
    {
    C3GPPBootstrap* self = new (ELeave) C3GPPBootstrap( aSession );
    CleanupStack::PushL(self);
    self->ConstructL();
    return self;
    }


// -----------------------------------------------------------------------------
// C3GPPBootstrap::~C3GPPBootstrap()
// -----------------------------------------------------------------------------
//
C3GPPBootstrap::~C3GPPBootstrap()
    {
    REComSession::DestroyedImplementation(iDtorIDKey);  
    if(IsActive())
        Cancel();
    if( iSmartCardInterface )
        {
        iSmartCardInterface->Release();
        REComSession::FinalClose();
        }
    delete iKsNAF;
    delete iNAFID;
    delete iRand;
    delete iBTID;
    delete iIdentity;
    delete iMasterKey;
    delete iDataRetriever;
    }


// -----------------------------------------------------------------------------
// C3GPPBootstrap::ConstructL()
// -----------------------------------------------------------------------------
//
void C3GPPBootstrap::ConstructL()
    {
    GBA_TRACE_BEGIN();

    GBA_TRACE_DEBUG(("initializing buffers"));
    iKsNAF = HBufC8::NewL(KKsNAFMaxLength);
    iBTID = HBufC8::NewL(KMaxLengthBTID);
    iNAFID = HBufC8::NewL(KMaxLengthNAFID);
    iIdentity = HBufC8::NewL(KMaxLengthIMPI);
    iMasterKey = HBufC8::NewL(KMaxLengthKs);
    iRand = HBufC8::NewL(KMaxLengthRAND);

    GBA_TRACE_DEBUG(("initializing http handler"));
    iDataRetriever  = CDataRetriever::NewL( this );
    
    iImplementationUID.iUid = GBA_UICC_INTERFACE_IMPLE;
    //if want softisim for testing
    //iImplementationUID.iUid = GBA_SOFTISIM_INTERFACE_IMPLE;
    
    //Interface is initialized based on the plug in
    if ( !IsPluginExistL() )
        {
        GBA_TRACE_DEBUG(("There aren't plug-in existing"));
        User::LeaveIfError( KErrGeneral );
        }
     
    GBA_TRACE_DEBUG(("requesting uicc handler"));
    iSmartCardInterface = RequestUICCInterfaceL();
    GBA_TRACE_DEBUG(("request made"));
    
    if ( !iSmartCardInterface )
        {
        GBA_TRACE_DEBUG(("Get interface failed"));
        User::LeaveIfError( KErrGeneral );
        }
    
    CActiveScheduler::Add( this );

    GBA_TRACE_END();
    }


// -----------------------------------------------------------------------------
// C3GPPBootstrap::C3GPPBootstrap()
// -----------------------------------------------------------------------------
//
C3GPPBootstrap::C3GPPBootstrap( CGbaServerSession* aSession ): CActive( EPriorityStandard ),
        iSmartCardInterface( NULL ), iLifetime ( 0 ),iGBARunType( ENoType ), iBSState(EIdle), iSession ( aSession )
    {
    }


// ---------------------------------------------------------------------------
// CBootstrapStateMachine::InitializeL()
// ---------------------------------------------------------------------------
//
void C3GPPBootstrap::InitializeL()
    {
    if ( IsActive() )
        {
        User::LeaveIfError( KErrInUse );
        }
    
    iBSState = EInitialize;
    GBA_TRACE_DEBUG(("Bootstrapping State machine startL()"));
    iStatus = KRequestPending;
    SetActive();
    TRequestStatus* status = &iStatus;
    User::RequestComplete( status, KErrNone );
    }


// ---------------------------------------------------------------------------
// C3GPPBootstrap::RunL()
// ---------------------------------------------------------------------------
//
void C3GPPBootstrap::RunL()
    {
    GBA_TRACE_DEBUG(("C3GPPBootstrap::RunL() -enter"));
    
    GBA_TRACE_DEBUG_NUM(("C3GPPBootstrap::RunL iStatus=%d"), iStatus.Int() );
    GBA_TRACE_DEBUG_NUM(("C3GPPBootstrap::RunL iBSState=%d"), iBSState );
    
    if((iBSState == ECancel) & iStatus.Int() == KErrCancel)
        {
        iBSState = EIdle;
        return;
        }
    
    User::LeaveIfError( iStatus.Int() );
    
    switch(iBSState)
        {
        case EInitialize:
            {
            GBA_TRACE_DEBUG(("C3GPPBootstrap::RunL() - EInitialize"));
            DoBootstrapL();
            GBA_TRACE_DEBUG(("C3GPPBootstrap::RunL() - EInitialize end"));
            break;  
            }
           
        case EBusy:
            {
            GBA_TRACE_DEBUG(("C3GPPBootstrap::RunL() - EBusy"));
            iSession->StateMachineCallBack( iStatus.Int() );
            Cleanup();
            GBA_TRACE_DEBUG(("C3GPPBootstrap::RunL() - EBusy end"));
            break;
            }
  
       default:
           GBA_TRACE_DEBUG(("C3GPPBootstrap::RunL() - default"));
           break;
       }
    GBA_TRACE_DEBUG(("C3GPPBootstrap::RunL() -exit"));
    }


TInt C3GPPBootstrap::RunError(TInt aError)
    {
    GBA_TRACE_DEBUG_NUM(("Failed with error = %d"), aError );
    iSession->StateMachineCallBack( aError );
    //Back to EBootstrapIdle
    iBSState = EIdle;
    return KErrNone;
    }

// ---------------------------------------------------------------------------
// C3GPPBootstrap::DoCancel()
// ---------------------------------------------------------------------------
//
void C3GPPBootstrap::DoCancel()
    {
    GBA_TRACE_DEBUG(("C3GPPBootstrap::DoCancel()"));
    switch(iBSState)
        {
         case EInitialize:
         case EBusy:
             {
             GBA_TRACE_DEBUG(("C3GPPBootstrap::DoCancel() EBootstrapDone"));
             CancelBootstrap();
             break;
             }
        default:
            break;
        };
    Cleanup();
    }


// -----------------------------------------------------------------------------
// C3GPPBootstrap::CancelBootstrap()
// -----------------------------------------------------------------------------
//
void C3GPPBootstrap::CancelBootstrap()
    {
    GBA_TRACE_BEGIN();
    iBSState = ECancel;
    iDataRetriever->CancelRequest();
    GBA_TRACE_END();
    }


// -----------------------------------------------------------------------------
// C3GPPBootstrap::DoBootstrapL()
// -----------------------------------------------------------------------------
//
void C3GPPBootstrap::DoBootstrapL( )
    {

    HBufC8 *BsfUrl = HBufC8::NewLC(KMaxURLLength);
    TPtr8 PtrBSFUrl( BsfUrl->Des() );
    
    // fetch bsf address override if available
    if ( !iSession->Server()->ReadOptionL( KGbaBSFConfiguration, PtrBSFUrl ) )
        {
        //If no preset bsf, empty the buffer
        //We will calculate the address ourselves
        PtrBSFUrl.Zero();
        }
    
    GBA_TRACE_DEBUG((" BSF server address:"));
    GBA_TRACE_DEBUG( PtrBSFUrl );
    
    GetBootstrappingMaterialL(
                                   PtrBSFUrl,
                                   iSession->iGbaInputParams.iNAFName,
                                   iSession->iGbaInputParams.iUICCLabel,
                                   iSession->iGbaInputParams.iFlags,
                                   iSession->iGbaInputParams.iProtocolIdentifier,
                                   iSession->iGbaOutputParams.iKNAF, 
                                   iSession->iGbaOutputParams.iBTID, 
                                   iSession->iGbaOutputParams.iLifetime,
                                   iSession->iGbaOutputParams.iGbaRunType,
                                   iSession->iGbaInputParams.iAPID );
    
    GBA_TRACE_DEBUG(("Bootstrap Request is sent out, let us wait for callback "));
    
    CleanupStack::PopAndDestroy( BsfUrl );
    }

// -----------------------------------------------------------------------------
// C3GPPBootstrap::GetBootstrappingMaterialL()
// -----------------------------------------------------------------------------
//
void C3GPPBootstrap::GetBootstrappingMaterialL(
                                    const TDesC8& aBSFAddress, 
                                    const TDesC8& aNAFURL,
                                    const TDesC8& /*aUICC_LABEL*/,
                                    const TUint8& aFlags,
                                    const TDesC8& aKeyUsage,
                                    TDes8 &aKsNAF, 
                                    TDes8 &aBTID,
                                    TTime &aLifetime,
                                    EGBARunType& aGBARunType, 
                                    const TInt& aIAPID )
    { 
    GBA_TRACE_BEGIN();
    //save the return buffer's pointer. Copy the databack when bootstrapping is done
    iCallerKsNAFBuf = &aKsNAF;
    iCallerLifetime = &aLifetime;
    iCallerBTIDBuf  = &aBTID;
    iCallerGBARunType = &aGBARunType;

    TUriParser8 uriparser;
    

    GBA_TRACE_DEBUG(("the given naf url is:"));    
    GBA_TRACE_DEBUG(aNAFURL);
    
    //this implementation is used to solve symbian API's problem
    // when parsing pure ip address
    if ( (aNAFURL.FindF(KHTTPTag) != KErrNotFound) || (aNAFURL.FindF(KHTTPSTag) != KErrNotFound) )
        {
        //the naf url has http tag
        User::LeaveIfError( uriparser.Parse(aNAFURL) );
        } 
    else
        {
        GBA_TRACE_DEBUG(("the naf url has no http tag, add one for parser"));
        HBufC8* temp = HBufC8::NewL( aNAFURL.Length() +  KHTTPTagLength );
        CleanupStack::PushL(temp);
        TPtr8 ptrtemp = temp->Des();
        ptrtemp.Copy( KHTTPTag );
        ptrtemp.Append(aNAFURL);
        GBA_TRACE_DEBUG( *temp );
        User::LeaveIfError( uriparser.Parse( *temp ) );
        CleanupStack::PopAndDestroy(temp);
        }
    
  
    //Calculate the NAFID, NAFID= NAF_FQDN + keyusage
    
    TPtr8 ptrNAFID = iNAFID->Des();
    //parse the FQDN out from NAFaddress
    ptrNAFID.Copy( uriparser.Extract(EUriHost) );
    ptrNAFID.Append( aKeyUsage );
    
    GBA_TRACE_DEBUG(("NAF ID ="));
    GBA_TRACE_DEBUG(*iNAFID);
	
    //GBA_TRACE_DEBUG(("UICC label is:"));
    //GBA_TRACE_DEBUG(aUICC_LABEL);
  
    // Get IMPI   
    TPtr8 ptrIdentity = iIdentity->Des();
    //Clean the buffer and Set Length to 0
    ptrIdentity.Zero();
  
    //get the IMPI from smart card
    iSmartCardInterface->QueryIdentityL(ptrIdentity);
  
    GBA_TRACE_DEBUG(("IMPI is:"));
    GBA_TRACE_DEBUG( *iIdentity );
  
    // Get GBA_U availability 
    // EFalse means the call is not from gba client directly.
    iGBAUAvailable = CheckGBAUAvailabilityL( EFalse );

  
    if ( iGBAUAvailable )
        {
        GBA_TRACE_DEBUG(("GBA-U is available"));    
        }
    else
        {
        GBA_TRACE_DEBUG(("GBA-U is not available"));
        }   
  
    // Load Credentails from store.
    // First compare the IMPI and key lifetime
    // If IMPI is different or key expires, then return EFalse to 
    // start a new bootstrapping.
  
    // If IMPI & key lifetime checking both ok,
    // GBA_U will load B-TID and key lifetime and ask smart card to 
    // calculate the Ks_NAF
    // GBA_ME will load Ks, Rand, B-TId and key lifetime and calculate it
    // by ourselves.
    
    // The GBA run type is also taken from cached store
    
    if( !(aFlags & EGBAForce) && LoadCredentialsL() ) 
        {
        GBA_TRACE_DEBUG(("Still ok ???"));
        iStatus = KRequestPending;
        SetActive();
        iBSState = EBusy;
        TRequestStatus* callerStatus = &iStatus;
        User::RequestComplete(callerStatus, KErrNone);
        return;
        }
  
    // check if the BSF URL was overriden
    TBuf8<KMaxURLLength> BsfUrl;
    
    if ( aBSFAddress.Length() == 0 )
        {
        GBA_TRACE_DEBUG(("No preset BSF URL, calcuate from IMPI"));
        iSmartCardInterface->QueryHomeNetworkDnL(BsfUrl);
        }
    else
        {
        if ( iSmartCardInterface->InterfaceIs2G() )
            { 
            BsfUrl.Copy( KHTTPSTag );
            }
        else
            {
            BsfUrl.Copy( KHTTPTag ); 
            }    
       BsfUrl.Append( aBSFAddress );
       }
  
    GBA_TRACE_DEBUG(("The bsf url is:"));
    GBA_TRACE_DEBUG(BsfUrl);
    
    // dataretriever makes the actual http connection to the bsf
    // when it completes values can be retrieved 
    TUriParser8 uriparser1;
    User::LeaveIfError( uriparser1.Parse(BsfUrl) );
    
    iStatus = KRequestPending;
    SetActive(); // event should come from bootstrapper 
    iBSState = EBusy;

    
    //set reaml as FQDN of bsf
    iDataRetriever->MakeRequestL( &iStatus, *iIdentity, uriparser1.Extract( EUriHost ), BsfUrl, aNAFURL, aIAPID );
    GBA_TRACE_END();
    }

// -----------------------------------------------------------------------------
// C3GPPBootstrap::GBAUAvailabilityL()
// -----------------------------------------------------------------------------
//
TBool C3GPPBootstrap::GBAUAvailabilityL()
    {
    //the call is from gba client directly
    return CheckGBAUAvailabilityL( ETrue );
    }

// -----------------------------------------------------------------------------
// C3GPPBootstrap::GetState()
// -----------------------------------------------------------------------------
//
TInt C3GPPBootstrap::GetState() const 
    {   
    return iBSState;  
    };    

// -----------------------------------------------------------------------------
// C3GPPBootstrap::CompleteBootStrappingL()
// This is the callback function called by datareceiver
// when B-TID and key lifetime is received from BSF
// -----------------------------------------------------------------------------
//
void C3GPPBootstrap::CompleteBootStrappingL( TInt aError )
    {
    // check that we have handler to receive data  
    GBA_TRACE_DEBUG(("C3GPPBootstrapImpl::CompleteBootStrappingL"));

    // Check if triplet auth failed.
    if ( aError != KErrNone ) 
        {
        GBA_TRACE_DEBUG(("Bootstrap failed"));
        return;
        }
  
    HBufC8* rspbody = iDataRetriever->QueryResponseValueL();
    if (!rspbody)
        {
        GBA_TRACE_DEBUG(("Error no response body"));
        User::LeaveIfError( KErrGeneral );
        }
    CleanupStack::PushL( rspbody );
    GBA_TRACE_DEBUG(("response body is received. Loaded response:"));
    GBA_TRACE_DEBUG(*rspbody);

    // make sure it contains a B-TID
    TInt p = rspbody->FindC(KBTIDFlag);
    TInt e = rspbody->FindC(KBTIDEndFlag);
    if ( p != KErrNotFound && e != KErrNotFound)
        {
        p += TPtrC8(KBTIDFlag).Length();
        TInt length = e-p;
        
        //Copy the B-TID value to caller's buffer
        //Continue getting Ks_(ext)_NAF
        iCallerBTIDBuf->Copy(rspbody->Mid(p,length)); 
        
        //The B-TID needs to be stored in smart card.
        //Must save here for later use.
        TPtr8 ptrBTID = iBTID->Des();
        ptrBTID.Copy(*iCallerBTIDBuf);
        } 
    else 
        {  
        GBA_TRACE_DEBUG(("Error didn't contain BTID"));
        CleanupStack::PopAndDestroy(rspbody);
        User::LeaveIfError( KErrGeneral );
        }
  
    GBA_TRACE_DEBUG(("Extracted B-TID:"));
    GBA_TRACE_DEBUG(*iBTID);

    TBuf8<KMaxLengthTimeString> LifetimeBuf;
    p = rspbody->FindC(KLifetimeFlag);
    e = rspbody->FindC(KLifetimeEndFlag);
    if ( p != KErrNotFound && e != KErrNotFound )
        {
        p += TPtrC8(KLifetimeFlag).Length();
        TInt length = e-p;
        LifetimeBuf.Copy( rspbody->Mid(p,length) );
        } 

    CleanupStack::PopAndDestroy(rspbody);

    GBA_TRACE_DEBUG(("Lifetime in string:"));
    GBA_TRACE_DEBUG(LifetimeBuf);
    
    //Convert the string to TTime object
    //
    if ( !ConvertStringToTTime( LifetimeBuf, &iLifetime ) )
        {
        GBA_TRACE_DEBUG(("Couldn't convert lifetime"));
        User::LeaveIfError( KErrGeneral );
        }

    // Set the lifetime to caller's buffer
    *iCallerLifetime = iLifetime;
    
    //After bootstrap is succesful, the B-TID and keylifetime
    //should be sent back to smart card to store in GBA_U.
    if ( iGBAUAvailable )
        {
        HBufC8* lifetime = HBufC8::NewLC( LifetimeBuf.Length() );
        TPtr8 lifetimePtr = lifetime->Des();
        lifetimePtr.Copy( LifetimeBuf );
        TInt err = iSmartCardInterface->UpdateGBADataL( *iBTID, *lifetime );
        CleanupStack::PopAndDestroy( lifetime );
        User::LeaveIfError( err );
        iGBARunType = EGBAU;
        }
    else
        {
        if ( iSmartCardInterface->InterfaceIs2G() )
            {
            iGBARunType = E2GGBA;
            }
        else
            {
            iGBARunType = E3GGBAME;
            }    
        }

    // Set the GBA run type back to caller   
    *iCallerGBARunType = iGBARunType;  
    // cache the new fangled credentials
    StoreCredentialsL();
  
    // Generate Key material and copy it to parameter being returned 
    if ( GenerateKeyMaterialL() )
        {
    
        if ( iGBAUAvailable )
            {
            GBA_TRACE_DEBUG(("It is GBA_U mode,The ks_ext_naf is calculated by smart card"));
            GBA_TRACE_DEBUG_BINARY( *iKsNAF); 
            }
        else
            {
            GBA_TRACE_DEBUG(("It is GBA_ME mode,The ks_naf is calculated by gbamodule"));
            GBA_TRACE_DEBUG_BINARY( *iKsNAF );  
            GBA_TRACE_DEBUG(("It is GBA_ME mode,The ks_naf is calculated by gbamodule 1"));
            }
        //Set KsNAF back to caller's buffer
        iCallerKsNAFBuf->Copy(*iKsNAF);     
        }
    else
        {
        GBA_TRACE_DEBUG(("Error no keys"));
        User::LeaveIfError( KErrGeneral );
        }
    GBA_TRACE_END();
    }


// -----------------------------------------------------------------------------
// C3GPPBootstrap::GetCredentialsL()
// function GetCredentialsL
// discussion:  Gets URI, Realm, Nonce and AuthenticationType, and gives back Username and Password.
// param: :aURI : the address of the bsf.
// param: :aRealm : the realm of the bsf.
// param: :aNonce : the nonce sent by the bsf.
// param: :aAuthenticationType : the authentication type sent by the bsf.
// param: :aUsername : Generated Username by underlying algorithm (AKA or SIM).
// param: :aPassword : Generated Password by underlying algorithm (AKA or SIM).
// result:  The result of the operation: true for success and false for failure!
// ----------------------------------------------------------------------------- 
TBool C3GPPBootstrap::GetCredentialsL(const TUriC8& /*aURI*/, RString aRealm, RString aNonce, 
                      RString aAlgorithm,
                      RString& aUsername, 
                      RString& aPassword,
                      RString& aResync,
                      TBool& aResyncRequired)
    {
    GBA_TRACE_BEGIN();    
    
    // smartcard interface returns true if credentials are received
    TBool GotKeys = EFalse;
    TInt pushCount = 0;
  
    HBufC *algType=HBufC::NewLC( KAlgorithmTybeBufferLength );
    pushCount++;
    
    TPtr pAlgType(algType->Des());
    pAlgType.Copy(aAlgorithm.DesC());
    pAlgType.LowerCase();
  
    TInt SecurityAlgorithm;
    
    //AuthenticationType MUST be AKAV1-MD5
    //Find() function returns the offset of the data sequence from the beginning of 
    //this descriptor's data. KErrNotFound, if the data sequence cannot be found.
    if ( pAlgType.Find(Kakav1) != KErrNotFound ) 
        {
        GBA_TRACE_DEBUG((" algorithm is akav1")); 
        SecurityAlgorithm = EAKAv1;
        }
    else 
        {
        GBA_TRACE_DEBUG((" algorithm is unknown")); 
        SecurityAlgorithm = ESecAlgUnknown;
        }   
  
    HBufC8 *nonce = HBufC8::NewLC(KStringLength);
    pushCount++;

    TPtr8 ptrNonce = nonce->Des();
    ptrNonce.Copy(aNonce.DesC());
    
    GBA_TRACE_DEBUG((" The base64 encoded nonce value from BSF server (RAND + AUTN)"));
    GBA_TRACE_DEBUG(aNonce.DesC());
    GBA_TRACE_DEBUG((" The base64 encoded nonce value after copying into buffer:"));
    GBA_TRACE_DEBUG(*nonce);
  
    //buffer used to store decoded nonce value
    HBufC8 *decodedNonce = HBufC8::NewLC(KStringLength);
    pushCount++;

    TPtr8 ptrDecNonce = decodedNonce->Des();
    
    //fill the buffer with zeros.
    ptrDecNonce.FillZ();
    
    // decodes the base64 nonce
    TBase64 b64coder;
    b64coder.Decode( *nonce, ptrDecNonce );
    
    GBA_TRACE_DEBUG((" The decoded nonce value in binary"));
    GBA_TRACE_DEBUG_BINARY( *decodedNonce );
  
    //Allocate buffer RES, password for http digest
    HBufC8* RES = HBufC8::NewLC( KMaxLengthRES );
    pushCount++;
    TPtr8 ptrRES = RES->Des();
    
    //Allocate buffer AUTS, if the out of sync happens        
    HBufC8* AUTS = HBufC8::NewLC( KMaxLengthAUTS );
    pushCount++;
    TPtr8 ptrAUTS = AUTS->Des();
    
    GBA_TRACE_DEBUG((" check algorithm value"));
    switch (SecurityAlgorithm) 
        {
    case EAKAv1: 
        {  
        GBA_TRACE_DEBUG((" EAKAv1"));  
        aResyncRequired = EFalse;
        //Set the RAND AUTN to smart card
        GotKeys = iSmartCardInterface->QueryAuthenticationL( *decodedNonce, ptrRES, ptrAUTS );
        
        TBool AUTSBufEmpty = EFalse;

        // No out of sync detected
        if ( GotKeys || AUTS->Length() == 0 )
            {
            GBA_TRACE_DEBUG(("AUTS is not returned. No out of sync detected"));
            AUTSBufEmpty = ETrue;
            }
          
        if ( !GotKeys && !AUTSBufEmpty && AUTS->Length()>0 )
            {
            aResyncRequired = ETrue;
            GBA_TRACE_DEBUG(("AUTS is returned. Resync is required"));
            GBA_TRACE_DEBUG_BINARY(*AUTS);
            }
            
      // keep rand
      // as the first 16 bytes in Nonce as RAND
      TPtr8 ptrRand = iRand->Des();
      ptrRand.Copy( ptrDecNonce.Left(KMaxLengthRAND) );
      
      GBA_TRACE_DEBUG(("RAND is:"));
      GBA_TRACE_DEBUG_BINARY(*iRand);
      
      //if GBA_U is available, we donot need to save the 
      //Ks. It is stored on smart card
      
      if( GotKeys && !iGBAUAvailable ) 
          {
          // keep master key
          TPtr8 ptrMasterKey = iMasterKey->Des();
          if ( !iSmartCardInterface->QueryKs( ptrMasterKey ) )
              {
              User::LeaveIfError( KErrGeneral );
              }   
          }
      }
        break;
    
      case ESecAlgUnknown:
          {
          User::LeaveIfError( KErrArgument );
          }
          break;
        
      default:
           {
           User::LeaveIfError( KErrArgument );    
           } 
        break;
        }
  

    GBA_TRACE_DEBUG(("AKA password RES for BSF"));
    GBA_TRACE_DEBUG_BINARY( *RES );
  
    // if received keys or auts then we can attempt to authenticate towards the BSF 
    // is this code setting the password? Password should be the RES or empty
        
    if ( aResyncRequired )
    //AUTS returned
        {
        _LIT8(KEmptyPwd,"");
        aPassword = aRealm.Pool().OpenStringL(KEmptyPwd);
        }

    if(GotKeys)
        {
        //Set RES as password
        TRAPD( err,aPassword = aRealm.Pool().OpenStringL(*RES) );
        err = err;
        GBA_TRACE_DEBUG_NUM((" Set RES as password error %d"), err );
        }
    
    //Set IMPI as username
    aUsername = aRealm.Pool().OpenStringL(iIdentity->Des());
    
    // convert received auts into a string
    if ( aResyncRequired )
        {
        GBA_TRACE_DEBUG(("adding auts to the headers"));      
        HBufC8 *encodedAUTS = HBufC8::NewLC( KMaxLengthEnAUTS );
        pushCount++;
        TPtr8 ptrEncAUTS = encodedAUTS->Des();
        ptrEncAUTS.FillZ();

        b64coder.Encode( *AUTS, ptrEncAUTS );
                
        GBA_TRACE_DEBUG(*encodedAUTS);
      
        aResync = aRealm.Pool().OpenStringL(*encodedAUTS);
        }
      
    CleanupStack::PopAndDestroy(pushCount);
    GBA_TRACE_END();
    return GotKeys;
    }

// -----------------------------------------------------------------------------
// C3GPPBootstrap::GenerateKeyMaterialL()
// ----------------------------------------------------------------------------- 
TBool C3GPPBootstrap::GenerateKeyMaterialL() 
    {
    TPtr8 derivedKey(iKsNAF->Des());
    
    if ( iGBAUAvailable )
        {
        iSmartCardInterface->QueryKeyMaterialL(
              KNullDesC8,
              KNullDesC8,
              iIdentity->Des(),
              *iNAFID,
              derivedKey
              );
        return ETrue; 
        }
    else
        {
        iSmartCardInterface->QueryKeyMaterialL(
                                  iMasterKey->Des(),
                                  iRand->Des(),
                                  iIdentity->Des(),
                                  *iNAFID,
                                  derivedKey
                                  );
        return ETrue; 
        }
    }


// -----------------------------------------------------------------------------
// C3GPPBootstrap::Cleanup()
// ----------------------------------------------------------------------------- 
void C3GPPBootstrap::Cleanup()
    {
    GBA_TRACE_DEBUG(("Enter "));
    iBSState = EIdle;
    iGBAUAvailable = EFalse;
    iGBARunType = ENoType;
    
    iKsNAF->Des().Zero(); 
    iBTID->Des().Zero();   
    iLifetime = 0; 

    iIdentity->Des().Zero(); //buffer for impi
    iNAFID->Des().Zero();    //buffer for nafid
    iRand->Des().Zero();     //buffer for rand
    iMasterKey->Des().Zero(); //buffer for Ks
    GBA_TRACE_DEBUG(("Exit "));
    }


// -----------------------------------------------------------------------------
// C3GPPBootstrap::LoadCredentials()
// GBA_ME, load the cached credentails to calculate ks_naf 
// ----------------------------------------------------------------------------- 
TBool C3GPPBootstrap::LoadCredentialsL()
    {
    GBA_TRACE_DEBUG(("Enter "));
    TBool result = EFalse;
  
    // check if the values are in memory
    // IsStillValid needs to be implemented
    //if( iMasterKey && IsStillValid( &iLifetime ))
      //{
      //GBA_TRACE_DEBUG(("using the Ks in memory"));
      //return ETrue;
      //}
    
    GBA_TRACE_DEBUG(("Checking if the credtials are stored"));
    
    RFs fs;
    User::LeaveIfError( fs.Connect() ); 
    CleanupClosePushL(fs);
    TFindFile folder( fs );
    
    TFileName fullPath;
    
    MakePrivateFilenameL(fs, KGbaCredentialsFileName, fullPath);
    GBA_TRACE_DEBUG(fullPath);
    
    TInt err = folder.FindByDir( fullPath, KNullDesC);
  
    if (  err != KErrNone )
        {
        GBA_TRACE_DEBUG(("No credentials store available"));
        CleanupStack::PopAndDestroy(&fs);
        return result;
        }
    else
        {
        GBA_TRACE_DEBUG(("Found credentials store "));
        CDictionaryFileStore* pStore = CDictionaryFileStore::OpenLC(fs,fullPath,KUidGBACredRoot);    
        
        TInt length = 0;
        HBufC8* tmpIdentity = NULL;

        //Read IMPI
        if ( pStore->IsPresentL( KUidIMPI ) )
            {
            GBA_TRACE_DEBUG(("IMPI is present "));
            RDictionaryReadStream reader;
            CleanupClosePushL(reader);
            reader.OpenL(*pStore,KUidIMPI); 
            length = reader.ReadInt32L();
            tmpIdentity = HBufC8::NewL(length);
            TPtr8 ptrtmpIdentity = tmpIdentity->Des();
      
            reader.ReadL(ptrtmpIdentity,length);
            GBA_TRACE_DEBUG(("IMPI = ")); 
            GBA_TRACE_DEBUG(ptrtmpIdentity);
            CleanupStack::PopAndDestroy( &reader );
            }
        
        //Read ks
        if ( pStore->IsPresentL( KUidKs ) )
            {
            GBA_TRACE_DEBUG(("Ks is present, the cached credentials are from GBA_ME "));
            GBA_TRACE_DEBUG(("Ks is present "));
            RDictionaryReadStream reader1;
            CleanupClosePushL(reader1);
            reader1.OpenL(*pStore,KUidKs); 
            length = reader1.ReadInt32L();
            
            TPtr8 ptrmk = iMasterKey->Des();
            ptrmk.Zero();
            reader1.ReadL(ptrmk,length);
            ptrmk.SetLength(length);
            GBA_TRACE_DEBUG(("Ks = ")); 
            GBA_TRACE_DEBUG_BINARY(ptrmk);
            CleanupStack::PopAndDestroy( &reader1 );
            }
      
      
      //Read rand
        if ( pStore->IsPresentL( KUidRand ) )
            {
            GBA_TRACE_DEBUG(("Rand is present "));
            RDictionaryReadStream reader2;
            CleanupClosePushL(reader2);
            reader2.OpenL(*pStore,KUidRand); 
            length = reader2.ReadInt32L();

            TPtr8 ptrRand = iRand->Des();
            ptrRand.Zero();
            reader2.ReadL(ptrRand,length);
            ptrRand.SetLength(length);
            GBA_TRACE_DEBUG(("Rand = ")); 
            GBA_TRACE_DEBUG_BINARY(ptrRand);  
            CleanupStack::PopAndDestroy( &reader2 );
            }  
        
        //Read BTID
        if ( pStore->IsPresentL( KUidBTID ) )
            {
            GBA_TRACE_DEBUG(("B-TID is present "));
            RDictionaryReadStream reader3;
            CleanupClosePushL(reader3);
            reader3.OpenL(*pStore,KUidBTID); 
            length = reader3.ReadInt32L();

            TPtr8 ptrBTID = iBTID->Des();
            ptrBTID.Zero();
            reader3.ReadL(ptrBTID,length);
            ptrBTID.SetLength(length);
            GBA_TRACE_DEBUG(("BTID = ")); 
            GBA_TRACE_DEBUG(ptrBTID); 
            CleanupStack::PopAndDestroy( &reader3 );
            }
      
        //Read key lifetime
        if ( pStore->IsPresentL( KUidkeylifetime ) )
            {
            GBA_TRACE_DEBUG(("key lifetime is present "));
            RDictionaryReadStream reader4;
            CleanupClosePushL(reader4);
            reader4.OpenL(*pStore,KUidkeylifetime); 
            iLifetime = NULL;
            TPtr8 ptrkeylifetime((TUint8*)&iLifetime,sizeof(TTime));
          
            reader4.ReadL(ptrkeylifetime,sizeof(TTime));
            GBA_TRACE_DEBUG(("keylifetime = "));
            GBA_TRACE_TIME( iLifetime );
            CleanupStack::PopAndDestroy( &reader4 );
            }  
      
        //Read GBA run type
        if ( pStore->IsPresentL( KUidGBARunType ) )
            {
            GBA_TRACE_DEBUG(("GBARunType is present "));
            RDictionaryReadStream reader5;
            CleanupClosePushL(reader5);
            reader5.OpenL(*pStore,KUidGBARunType); 
            iGBARunType = (EGBARunType)reader5.ReadInt8L();  
            CleanupStack::PopAndDestroy( &reader5 );
            }
      
      
        //done with store
        CleanupStack::PopAndDestroy( pStore );
	    CleanupStack::PopAndDestroy(&fs);
                                           
        result = IsStillValid( &iLifetime ) && *tmpIdentity == *iIdentity;
        
        //smart card has been changed
        if ( *tmpIdentity != *iIdentity )
            {
        	iSmartCardInterface->NotifyCardChangeL();
            }
        
        GBA_TRACE_DEBUG(("Cached IMPI = ")); 
        if(tmpIdentity != NULL)
        	GBA_TRACE_DEBUG(*tmpIdentity);
        GBA_TRACE_DEBUG(("IMPI from smart card = ")); 
        GBA_TRACE_DEBUG(*iIdentity);
        
        // this has served its purpose
        delete tmpIdentity;

        // if the credentials aren't valid delete the old key
        if ( !result )
            {
            GBA_TRACE_DEBUG(("clean buffers since the key wasn't valid anymore or the card had been changed"));
            // clean up the created buffers;
            iMasterKey->Des().Zero();
            iRand->Des().Zero();
            iBTID->Des().Zero();
            iLifetime = NULL;
            }
        else
            {
            GBA_TRACE_DEBUG(("cached keys were still valid"));
            GBA_TRACE_DEBUG(("Cached B-TID is:"));
            GBA_TRACE_DEBUG(*iBTID );
            
            iCallerBTIDBuf->Copy( *iBTID );
            
            // Set the run type
            *iCallerGBARunType = iGBARunType;
            
            //Set key life time
            *iCallerLifetime = iLifetime;
            
            // generate material based on the stored credentials
            if ( GenerateKeyMaterialL() )
                {
                if ( iGBAUAvailable )
                    {
                    GBA_TRACE_DEBUG(("Calu from Cached Ks: It is GBA_U mode,The ks_ext_naf is calculated by smart card"));
                    GBA_TRACE_DEBUG_BINARY( *iKsNAF ); 
                    GBA_TRACE_DEBUG(("Calu test11"));

                    }
                else
                    {
                    GBA_TRACE_DEBUG(("Calu from Cached Ks. It is GBA_ME mode,The ks_naf is calculated by gbamodule"));
                    GBA_TRACE_DEBUG_BINARY( *iKsNAF ); 
                    }
                    //Set KsNAF back to caller's buffer
                iCallerKsNAFBuf->Copy(*iKsNAF);       
                }
            else
                {
                GBA_TRACE_DEBUG(("Error no keys"));
                result = EFalse;
                }
            }
         GBA_TRACE_DEBUG(("Calu test11"));   
        }
    return result;
    }



// -----------------------------------------------------------------------------
// C3GPPBootstrap::StoreCredentialsL()
// Store bootstrapping credentails into the store
// GBA_ME: IMPI, Ks, Rand, B-TID, key lifetime
// GBA_U:  IMPI, B-TID, key lifetime
// ----------------------------------------------------------------------------- 
void C3GPPBootstrap::StoreCredentialsL()
    {
    GBA_TRACE_DEBUG(("Save credentials into dictionary store"));
  
    RFs fs;    
    User::LeaveIfError(fs.Connect());
    CleanupClosePushL(fs);
    TFindFile folder( fs );
    
    TFileName fullPath;
    
    MakePrivateFilenameL(fs, KGbaCredentialsFileName, fullPath);
    EnsurePathL(fs, fullPath );

    GBA_TRACE_DEBUG(fullPath);
    TInt err = folder.FindByDir( fullPath, KNullDesC );
  
    if (  err == KErrNotFound || err == KErrNone || err == KErrPathNotFound )  
        {
    
        CDictionaryFileStore* pStore = CDictionaryFileStore::OpenLC(fs,fullPath,KUidGBACredRoot);   
        
        //Save IMPI
        RDictionaryWriteStream writer;
        CleanupClosePushL(writer);
        writer.AssignL(*pStore, KUidIMPI);
        writer.WriteInt32L(iIdentity->Size());
        writer.WriteL(*iIdentity);
        writer.CommitL();
        CleanupStack::PopAndDestroy( &writer );
       
        //GBA_U doesn't need to save ks and rand.
        if ( !iGBAUAvailable )
            {
            GBA_TRACE_DEBUG(("It is GBA_ME, save Ks and Rand"));
            //Save ks
            RDictionaryWriteStream writer1;
            CleanupClosePushL(writer1);
            writer1.AssignL( *pStore, KUidKs );
            writer1.WriteInt32L(iMasterKey->Size());
            writer1.WriteL(*iMasterKey);
            writer1.CommitL();
            CleanupStack::PopAndDestroy( &writer1 );
          
            //Save Rand
            RDictionaryWriteStream writer2;
            CleanupClosePushL(writer2);
            writer2.AssignL(*pStore,KUidRand );
            writer2.WriteInt32L(iRand->Size());
            writer2.WriteL(*iRand);
            writer2.CommitL();
            CleanupStack::PopAndDestroy( &writer2 );
            }
        else
            {
            GBA_TRACE_DEBUG(("It is GBA_U, remove Ks and Rand if there are"));    
            pStore->RemoveL(KUidKs);
            pStore->RemoveL(KUidRand);
            }    
        //Save B-TID
        RDictionaryWriteStream writer3;
        CleanupClosePushL(writer3);
        writer3.AssignL(*pStore,KUidBTID );
        writer3.WriteInt32L(iBTID->Size());
        writer3.WriteL(*iBTID);
        writer3.CommitL();
        CleanupStack::PopAndDestroy( &writer3 );
      
        //Save key lifetime
        RDictionaryWriteStream writer4;
        CleanupClosePushL(writer4);
        writer4.AssignL(*pStore,KUidkeylifetime );
        TPtrC8 ptrkeylifetime((TUint8*)&iLifetime,sizeof(TTime));
        writer4.WriteL(ptrkeylifetime); 
        writer4.CommitL();
        CleanupStack::PopAndDestroy( &writer4 );
      
        //Save gba run type
        RDictionaryWriteStream writer5;
        CleanupClosePushL(writer5);
        writer5.AssignL(*pStore,KUidGBARunType);
        writer5.WriteInt8L(iGBARunType);
        writer5.CommitL();
        CleanupStack::PopAndDestroy( &writer5 );
      
        pStore->CommitL();
        CleanupStack::PopAndDestroy( pStore );
        CleanupStack::PopAndDestroy( &fs );     
        }
    else
        {
        CleanupStack::PopAndDestroy( &fs );
        User::LeaveIfError( err );    
        } 
    }

// -----------------------------------------------------------------------------
// C3GPPBootstrap::CheckGBAUAvailability()
// Check the GBA availability from store, if no record there, check from 
// smart card directly.
// -----------------------------------------------------------------------------
TBool C3GPPBootstrap::CheckGBAUAvailabilityL( TBool aIsfromGBAClient )
    {       
    TBool GBAUAvailability = EFalse;
    //Read the record from store
    TInt result = LoadGBAUAvailabililtyFromStoreL( aIsfromGBAClient, GBAUAvailability );
    
    //The store GBA type is GBA_U or GBA_ME
    if ( result != KErrNotFound && result != KErrGeneral )
        {
        //return the cached GBAU availabilty, since smart card is not changed
        return GBAUAvailability;
        }
    else if ( result == KErrGeneral )
        {
        //impi is different
        //delete the whole store
        RFs fs;
        User::LeaveIfError( fs.Connect() );
        CleanupClosePushL(fs);
        TFileName fullPath;
        MakePrivateFilenameL(fs, KGbaCredentialsFileName, fullPath);
        fs.Delete( fullPath );
        CleanupStack::PopAndDestroy( &fs );
        }
    else
        {
        //The first time query    
        } 
    // There is no record on GBA_U availability or impis are different   
    // It only happens on the first time when GBA server starts
    // or after smart card is removed.
    
    //retrieve the GBA availability from smart card
    iSmartCardInterface->QueryGBAUAvailabilityL( GBAUAvailability );
    
    SaveGBAUAvailabilityToStoreL( GBAUAvailability );
    return GBAUAvailability;   
    }


// -----------------------------------------------------------------------------
// C3GPPBootstrap::LoadGBAUAvailabililtyFromStoreL()
// -----------------------------------------------------------------------------
TInt C3GPPBootstrap::LoadGBAUAvailabililtyFromStoreL( TBool& aIsfromGBAClient, TBool& aGBAUAvail )
    { 
    GBA_TRACE_DEBUG(("Loading the GBA-U avail from store"));
    TInt cleanupstack = 0;
    RFs fs;
    User::LeaveIfError( fs.Connect() );
    CleanupClosePushL(fs);
    cleanupstack++;
    TFindFile folder( fs );
    
    
    TFileName fullPath;
    MakePrivateFilenameL(fs, KGbaCredentialsFileName, fullPath);
    GBA_TRACE_DEBUG(fullPath);
    TInt err = folder.FindByDir( fullPath, KNullDesC );
  
    // the store file is not available  
    if (  err != KErrNone )
        {
        GBA_TRACE_DEBUG(("No store available"));
        CleanupStack::PopAndDestroy(cleanupstack); 
        
        //get impi here, save to store later
        if ( aIsfromGBAClient )
            {
            //retrieve the impi from smart card
            TPtr8 idPtr = iIdentity->Des();
            idPtr.Zero();
            TRAPD(error,iSmartCardInterface->QueryIdentityL(idPtr)); 
    
            if( error != KErrNone )
                {
                GBA_TRACE_DEBUG((" Can't get IMPI from smart card"));
                User::LeaveIfError( error );
                }
        
            GBA_TRACE_DEBUG((" got IMPI"));    
            }
        return KErrNotFound;
      }
    else
       {
       GBA_TRACE_DEBUG(("Found store "));
       CDictionaryFileStore* pStore = CDictionaryFileStore::OpenLC(fs,KGbaCredentialsFileName,KUidGBACredRoot);    
       cleanupstack++;
       TInt impiLength = 0;
       HBufC8* cachedimpi = NULL;
       TInt8 GBAUAvail = 0;
       
       //Read GBA-U avail
       if ( pStore->IsPresentL( KUidGBAUAvail ) )
           {
           GBA_TRACE_DEBUG(("GBAU Avail is present "));
           RDictionaryReadStream reader;
           CleanupClosePushL(reader);
           reader.OpenL(*pStore,KUidGBAUAvail); 
           GBAUAvail = reader.ReadInt8L();
           CleanupStack::PopAndDestroy( &reader );
           }
            
       //Read IMPI
       if ( pStore->IsPresentL( KUidIMPI ) )
          {
          GBA_TRACE_DEBUG(("IMPI is present "));
          RDictionaryReadStream reader1;
          CleanupClosePushL(reader1);
          cleanupstack++; 
          reader1.OpenL(*pStore,KUidIMPI);
          impiLength = reader1.ReadInt32L();
        
          cachedimpi = HBufC8::NewLC(impiLength);
          cleanupstack++;
          TPtr8 ptrcachedimpi = cachedimpi->Des();
      
          reader1.ReadL(ptrcachedimpi,impiLength);
          ptrcachedimpi.SetLength(impiLength);
          GBA_TRACE_DEBUG(("IMPI = ")); 
          GBA_TRACE_DEBUG(ptrcachedimpi);

          if ( aIsfromGBAClient )
              {
              //retrieve the impi from smart card
              TPtr8 idPtr = iIdentity->Des();
              idPtr.Zero();
              TRAPD(error,iSmartCardInterface->QueryIdentityL(idPtr)); 
    
              if( error != KErrNone )
                  {
                  GBA_TRACE_DEBUG((" Can't get IMPI from smart card"));
                  User::LeaveIfError( error );
                  }
        
              GBA_TRACE_DEBUG((" got IMPI"));    
              }

        
          if( *iIdentity == *cachedimpi )
              {
              GBA_TRACE_DEBUG(("IMPI are the same"));    
              //the impi are the same, return the cached gbau availability
              CleanupStack::PopAndDestroy(cleanupstack);
              aGBAUAvail = (TBool)GBAUAvail;
              return KErrNone;
              }
          else
              {
              GBA_TRACE_DEBUG(("IMPIs are different"));    
              //the impi are different, return KErrGeneral
              iSmartCardInterface->NotifyCardChangeL();
              CleanupStack::PopAndDestroy(cleanupstack); 
              return KErrGeneral;    
              }
           }
        else
           {
           GBA_TRACE_DEBUG(("no impi present"));    
           return KErrGeneral;   
           }  
        }
    }

// -----------------------------------------------------------------------------
// C3GPPBootstrap::SaveGBAUAvailabilityToStoreL()
// -----------------------------------------------------------------------------
//
void C3GPPBootstrap::SaveGBAUAvailabilityToStoreL( TBool& aGBAUAvail )
    {
    GBA_TRACE_DEBUG(("Save GBA-U avail into dictionary store"));
  
    RFs fs;
    User::LeaveIfError(fs.Connect());
    CleanupClosePushL(fs);
    TFindFile folder( fs );
    
    TFileName fullPath;
    MakePrivateFilenameL(fs, KGbaCredentialsFileName, fullPath);
    EnsurePathL(fs, fullPath );
    GBA_TRACE_DEBUG(fullPath);
    TInt err = folder.FindByDir( fullPath, KNullDesC );
  
    if (  err == KErrNotFound || err == KErrNone || err == KErrPathNotFound )  
        {
    
        CDictionaryFileStore* pStore = CDictionaryFileStore::OpenLC(fs,fullPath,KUidGBACredRoot);   
      
        //Save IMPI
        RDictionaryWriteStream writer;
        CleanupClosePushL(writer);
        writer.AssignL(*pStore, KUidIMPI);
        writer.WriteInt32L(iIdentity->Size());
        writer.WriteL(*iIdentity);
        writer.CommitL();
        CleanupStack::PopAndDestroy( &writer );    
        //Save GBA-U avail
        RDictionaryWriteStream writer1;
        CleanupClosePushL(writer1);
        writer1.AssignL(*pStore,KUidGBAUAvail );
        writer1.WriteInt8L((TInt8)aGBAUAvail);
        writer1.CommitL();
        CleanupStack::PopAndDestroy( &writer1 );
      
        pStore->CommitL();
        CleanupStack::PopAndDestroy(pStore);
        CleanupStack::PopAndDestroy(&fs);
        GBA_TRACE_DEBUG(("Save GBA-U avail successfully"));    
        }
    else
        {
        GBA_TRACE_DEBUG(("Save GBA-U avail failed"));
        CleanupStack::PopAndDestroy(&fs);
        User::LeaveIfError( err );    
        }
    }

// -----------------------------------------------------------------------------
// C3GPPBootstrap::IsStillValid()
// -----------------------------------------------------------------------------
//
TBool C3GPPBootstrap::IsStillValid( TTime* aLifetime )
    {
    TTime nowTime;
    nowTime.UniversalTime();
    GBA_TRACE_DEBUG(("Current Time:"));
    GBA_TRACE_TIME( nowTime );
    
    GBA_TRACE_DEBUG(("Expiry Time:"));
    GBA_TRACE_TIME( *aLifetime );
    
    if( *aLifetime > nowTime )
        {
        GBA_TRACE_DEBUG(("key still valid"));
        return ETrue;
        }
    else
        {
        GBA_TRACE_DEBUG(("key expired"));
        return EFalse;
        }
    }

// -----------------------------------------------------------------------------
// C3GPPBootstrap::ConvertStringToTTime()
// -----------------------------------------------------------------------------
//
TBool C3GPPBootstrap::ConvertStringToTTime(TDesC8& aLifetimeBuf, TTime* aLifetime)
{
  GBA_TRACE_BEGIN();
  TInt aTimeVariable[KVariableIndex6] = 
  {
          0,0,0,0,0,0
  }; // { year,month,day,hour,minute,second }
  
  // assuming the lifetime is given in ISO 8601 format
  // YYYY-MM-DD or YYYYMMDD (we don't allow YYYYMM or YYYY format, although this isn't specified in the standard)
  // (year could have a + before it if key is valid beyond year 9999, but we hope that someone will rewrite this within next 8000 years)
  // there might be a T between date and time we just ignore it
  // hours 
  // hh:mm:ss or hhmmss
  // hh:mm or hhmm
  // hh

  TInt pos = 0;
  TInt len = KVariableIndex4;
  for(TInt variableIndex = 0; variableIndex < KVariableIndex6; variableIndex++)
  {
    // if next value isn't a digit we're done
    if(!TChar(aLifetimeBuf[pos]).IsDigit())
      break;
        
    if(pos + len < aLifetimeBuf.Length())
    {
    
      TLex8 lex(aLifetimeBuf.Mid(pos,len));
      if(KErrNone  != lex.Val(aTimeVariable[variableIndex]))
      {
        GBA_TRACE_DEBUG(("failed"));
        GBA_TRACE_DEBUG(aLifetimeBuf.Mid(pos,len));
        return EFalse;
      }
      pos += len;
      

      // remove possible separators
      if(aLifetimeBuf[pos] == '-' || aLifetimeBuf[pos] == ':')
        pos += 1;
      // there can be spaces after month
      if( variableIndex == KVariableIndex2 )
        while(pos < aLifetimeBuf.Length() && 
        (TChar(aLifetimeBuf[pos]).IsSpace() || aLifetimeBuf[pos] == 'T'))
            pos++;
      
    }
    else
    { 
      // if we don't get second it doesn't matter
      if(variableIndex >= KVariableIndex5)
        break; 
      return EFalse;
    }
    len = KVariableIndex2; // year is the exception 
  }
  // Symbian months and days start from 0, UTC months from 1
  aTimeVariable[1] = aTimeVariable[1] - 1;
  aTimeVariable[2] = aTimeVariable[2] - 1;

  TBuf<KBufferSize255> aDBBuf;
  aDBBuf.Format(KTimeFormat, aTimeVariable[KVariableIndex0],aTimeVariable[KVariableIndex1],aTimeVariable[KVariableIndex2],
                          aTimeVariable[KVariableIndex3],aTimeVariable[KVariableIndex4],aTimeVariable[KVariableIndex5]);
  GBA_TRACE_DEBUG(aDBBuf);

  // time should always be in UTC so no need to check the timezone
  TDateTime dt;

  TRAPD(error,dt.Set(
    aTimeVariable[KVariableIndex0],
    (TMonth)(aTimeVariable[KVariableIndex1]), 
    aTimeVariable[KVariableIndex2],
    aTimeVariable[KVariableIndex3],
    aTimeVariable[KVariableIndex4],
    aTimeVariable[KVariableIndex5],
    0
    ));

  if(error != KErrNone)
  {
    aDBBuf.Format(KErrorMessage,error);
    GBA_TRACE_DEBUG(aDBBuf);
    return EFalse;
  }

  *aLifetime = dt;
  
  GBA_TRACE_END();
  return ETrue;
}


// ---------------------------------------------------------------------------
// C3GPPBootstrap::CreateImplementationL()
// ---------------------------------------------------------------------------
//
MUICCInterface* C3GPPBootstrap::RequestUICCInterfaceL()
    {
    GBA_TRACE_BEGIN();
    TAny* ptr = REComSession::CreateImplementationL(iImplementationUID, iDtorIDKey);
    MUICCInterface* ptyped = static_cast<MUICCInterface*>(ptr);
    GBA_TRACE_END();
    return ptyped;
    }


// ---------------------------------------------------------------------------
// C3GPPBootstrap::IsPluginExistL()
// ---------------------------------------------------------------------------
//
TBool C3GPPBootstrap::IsPluginExistL()
    {
    GBA_TRACE_BEGIN();
    RImplInfoPtrArray array; 
    // Note that a special cleanup function is required to reset and destroy
    // all items in the array, and then close it.
    TCleanupItem cleanup(ResetAndDestroyArray, &array);
    CleanupStack::PushL(cleanup);  

    REComSession::ListImplementationsL( KGBAUICCInterfaceUID, array );
    
    if( array.Count())
        {
        CleanupStack::PopAndDestroy(&array); //array, results in a call to ResetAndDestroyArray
        GBA_TRACE_END();
        return ETrue;
        }
    else
        {
        GBA_TRACE_END();
        CleanupStack::PopAndDestroy(&array); //array, results in a call to ResetAndDestroyArray
        return EFalse;
        }
    }


// CleanupEComArray function is used for cleanup support of locally declared arrays
void ResetAndDestroyArray(TAny* aArray)
    {
    GBA_TRACE_BEGIN();
    (static_cast<RImplInfoPtrArray*> (aArray))->ResetAndDestroy();
    (static_cast<RImplInfoPtrArray*> (aArray))->Close();
    GBA_TRACE_END();
    }


// ---------------------------------------------------------------------------
// C3GPPBootstrap::InterfaceIs2G()
// ---------------------------------------------------------------------------
//
TBool C3GPPBootstrap::InterfaceIs2G() 
    {
    return iSmartCardInterface->InterfaceIs2G();
    }
    
    
// ---------------------------------------------------------------------------
// C3GPPBootstrap::MakePrivateFilenameL()
// ---------------------------------------------------------------------------
//
void C3GPPBootstrap::MakePrivateFilenameL(RFs& aFs, const TDesC& aLeafName, 
                                     TDes& aNameOut)
    {
    aNameOut.Copy(KGBAStoreStandardDrive);
    // Get private path
    TBuf<KStringLength> privatePath;
    aFs.PrivatePath(privatePath);
    aNameOut.Append(privatePath);
    aNameOut.Append(aLeafName);
    }
    
      
// ---------------------------------------------------------------------------
// C3GPPBootstrap::EnsurePathL()
// ---------------------------------------------------------------------------
//      
void C3GPPBootstrap::EnsurePathL( RFs& aFs, const TDesC& aFile )
    {
    TInt err = aFs.MkDirAll(aFile);
    if (err != KErrNone && err != KErrAlreadyExists)
        {
        User::Leave(err);
        }
    }   
   
//EOF