omaprovisioning/pnputil/src/PnpUtilImpl.cpp
changeset 0 b497e44ab2fc
child 2 5594fba90824
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/omaprovisioning/pnputil/src/PnpUtilImpl.cpp	Thu Dec 17 09:07:52 2009 +0200
@@ -0,0 +1,1066 @@
+/*
+* Copyright (c) 2004-2006 Nokia Corporation and/or its subsidiary(-ies). 
+* All rights reserved.
+* This component and the accompanying materials are made available
+* under the terms of "Eclipse Public License v1.0"
+* which accompanies this distribution, and is available
+* at the URL "http://www.eclipse.org/legal/epl-v10.html".
+*
+* Initial Contributors:
+* Nokia Corporation - initial contribution.
+*
+* Contributors:
+*
+* Description:  PnpUtil implementation
+*
+*/
+
+
+
+// INCLUDE FILES
+#include <e32std.h>
+#include <e32math.h>
+#include <mmtsy_names.h>
+#include <asymmetric.h>         // For RInteger
+#include <3des.h>               // For C3DES
+#include <centralrepository.h>  // link against centralrepository.lib
+
+#include "PnpUtilImpl.h"
+#include "PnpUtilLogger.h"
+#include "PnpUtilPrivateCRKeys.h" // Central repository keys
+
+
+// CONSTANTS
+
+const TInt KMaxModulusLength = 300;
+const TInt KMaxPublicExponentLength = 10;
+
+_LIT8(K3DesKey, "111111111111111111111111");
+
+// Default token validity time
+const TInt KTokenValidityTime = 600;
+const TInt KTokenLength = 4;
+// C3DESEncryptor and C3DESDecryptor require the buffer to be more than 4 characters
+// (8 characters seems to be enough)
+const TInt KTokenLengthDuringStorage = 8;
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CPnpUtilImpl::ConstructL()
+    {
+    LOGSTRING( "Enter to CPnpUtilImpl::ConstructL()" );
+
+    User::LeaveIfError( iServer.Connect() );
+    LOGSTRING( "CPnpUtilImpl::ConstructL() 2" );
+    User::LeaveIfError( iServer.LoadPhoneModule( KMmTsyModuleName ) );
+    LOGSTRING( "CPnpUtilImpl::ConstructL() 3" );
+    User::LeaveIfError( iPhone.Open( iServer, KMmTsyPhoneName ) );
+    LOGSTRING( "CPnpUtilImpl::ConstructL() 4" );
+    User::LeaveIfError( iPhone.Initialise() );
+
+    LOGSTRING( "CPnpUtilImpl::ConstructL() 5" );
+
+    iRepository = CRepository::NewL( KCRUidPnpUtil );
+
+#ifndef __WINS__ // calling C3DESEncryptor::NewL crashes emulator
+    iEncryptor = C3DESEncryptor::NewL( K3DesKey );
+    iDecryptor = C3DESDecryptor::NewL( K3DesKey );
+#endif 
+
+    LOGSTRING( "Exit from CPnpUtilImpl::ConstructL()" );
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::NewLC
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CPnpUtilImpl* CPnpUtilImpl::NewLC()
+    {
+    LOGSTRING("CPnpUtilImpl::NewLC");
+    CPnpUtilImpl* self = new (ELeave) CPnpUtilImpl();
+    CleanupStack::PushL( self );
+    self->ConstructL();
+    return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::CPnpUtilImpl
+// -----------------------------------------------------------------------------
+//
+CPnpUtilImpl::CPnpUtilImpl()
+    {
+    LOGSTRING("CPnpUtilImpl()");
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::~CPnpUtilImpl
+// -----------------------------------------------------------------------------
+//
+EXPORT_C CPnpUtilImpl::~CPnpUtilImpl()
+    {
+    LOGSTRING( "~CPnpUtilImpl" );
+    delete iRepository;
+    iPhone.Close();
+    iServer.Close();
+#ifndef __WINS__
+    delete iEncryptor;
+    delete iDecryptor;
+#endif
+    LOGSTRING( "~CPnpUtilImpl - done" );
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::Version
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CPnpUtilImpl::Version( TDes& aVersion )
+    {
+    LOGSTRING( "CPnpUtilImpl::Version" );
+
+    // There is now a separate dll for HDC so there is no need to
+    // read the version string from a database, we may use
+    // a hard-coded value instead.
+
+    _LIT( KTempVersion, "NPnP-MSS60-1.01" );
+   
+    // Max length is KMaxVersionStringLength
+    if( KTempVersion().Length() > aVersion.MaxLength() )
+        {
+        return KErrArgument;
+        }
+    aVersion.Copy( KTempVersion );
+    return KErrNone;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::CreateNewToken
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CPnpUtilImpl::CreateNewToken(TUint32 aTimeout, TInt& aToken)
+    {
+    LOGSTRING("CPnpUtilImpl::CreateNewToken");
+    TInt value(0);
+    // Get current time
+    TTime t;
+    t.HomeTime();
+    TInt64 time = t.Int64();
+
+    // Create timeout
+    if( aTimeout > 9999 )
+        {
+        LOGSTRING("too long timeout - KErrArgument");
+        return KErrArgument;
+        }
+
+    // Deadline = currenttime + (atimeout * 1000000)
+    TInt64 deadline = time + TInt64((TInt)aTimeout) * TInt64(1000000);
+    TBuf<21> num;    // 20 is max length for 64 bit integer (radix 10)
+    num.AppendNum(deadline);
+    LOGSTRING("WriteDeadline");
+    LOGTEXT(num);
+
+    // Store deadline
+    TInt result = iRepository->Set( KPnPUtilDeadline, num );
+    if( result != KErrNone )
+        {
+        LOGSTRING2("Storing deadline failed: %i", result);
+        return result;
+        }
+    
+    value = Math::Rand(time);
+    value %= (9999 - 1001);
+    value += 1001;
+
+    LOGSTRING2( "New Token: %i", value );
+
+    // KTokenLength is too small for the buffer length because C3DESEncryptor/C3DESDecryptor
+    // cannot handle small buffers
+    TBuf8<KTokenLengthDuringStorage> tokenBuf;
+    tokenBuf.AppendNum( value );
+    tokenBuf.AppendNum( 1234 );
+    // Encrypt
+#ifndef __WINS__
+    iEncryptor->Transform( tokenBuf );
+#endif
+
+    // Save token
+    result = iRepository->Set( KPnPUtilToken, tokenBuf );
+
+    aToken = value;
+
+    LOGSTRING("CPnpUtilImpl::CreateNewToken - done");
+    return result;
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::GetTokenValidityTime
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CPnpUtilImpl::GetTokenValidityTime()
+    {
+    LOGSTRING("CPnpUtilImpl::GetTokenValidityTime");
+    return KTokenValidityTime;
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::GetTokenValue
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CPnpUtilImpl::GetTokenValue(TInt& aToken)
+    {
+    LOGSTRING("Enter CPnpUtilImpl::GetTokenValue");
+
+    // Check deadline
+    TBuf<21> num;
+    LOGSTRING("ReadDeadline");
+
+    TInt result = iRepository->Get( KPnPUtilDeadline, num );
+    if( result != KErrNone )    
+        {
+        return KErrCorrupt;
+        }
+
+    LOGTEXT(num);
+    TLex l(num);
+    TInt64 deadline(0);
+    if( l.Val(deadline)!= KErrNone )
+        {
+        return KErrCorrupt;
+        }
+    // Check validity time
+    TTime t;
+    t.HomeTime();
+    if( t > deadline )
+        {
+        TTimeIntervalSeconds seconds(0);
+        t.SecondsFrom( deadline, seconds );
+        LOGSTRING2( "Token validity expired: %is ago", seconds.Int() );
+        return KErrTimedOut;
+        }
+
+    LOGSTRING("Token not expired");
+
+    // Get token
+    // KTokenLength is too small for the buffer length because C3DESEncryptor/C3DESDecryptor
+    // cannot handle small buffers
+    TBuf8<KTokenLengthDuringStorage> tokenBuf;
+    result = iRepository->Get( KPnPUtilToken, tokenBuf );
+
+    if( result != KErrNone )
+        {
+        LOGSTRING2( "Error %i when trying to read token value", result );
+        return result;
+        }
+
+    LOGSTRING("Tokenbuf:");
+    LOGTEXT( tokenBuf );
+
+#ifndef __WINS__
+    iDecryptor->Transform( tokenBuf );
+#endif
+
+    TInt token(0);
+    TLex8 parser( tokenBuf.Left( KTokenLength ) );
+    parser.Val( token );
+
+    if( token < 1 || token > 9999)
+        {
+        return KErrCorrupt;
+        }
+
+    LOGSTRING("Token OK");
+    LOGSTRING2("Token: %i", token);
+ 
+    aToken = token;
+
+    return KErrNone;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::CreateNewNonceL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CPnpUtilImpl::CreateNewNonceL( const TUint /*aTimeOut*/, TDes8& aNonce )
+    {
+    LOGSTRING("CPnpUtilImpl::CreateNewNonceL");
+    if( aNonce.MaxLength() < KNonceLength )
+        {
+        User::Leave( KErrArgument );
+        }
+
+    TBuf8<KNonceLength> buffer;
+
+    TTime time;
+    time.HomeTime();
+    TInt64 seed = time.Int64();
+    for( TInt i(0); i < KNonceLength; i++ )
+        {
+        TChar character( RandomCharacter( seed ) );
+        buffer.Append( character );
+        }
+
+    LOGSTRING("New Nonce:");
+    LOGTEXT( buffer );
+    aNonce.Copy( buffer );
+
+    // Encrypt
+#ifndef __WINS__
+    iEncryptor->Transform( buffer );
+#endif
+
+    // Save the nonce
+    User::LeaveIfError( iRepository->Set( KPnPUtilNonce, buffer ) );
+
+    LOGSTRING("CPnpUtilImpl::CreateNewNonceL - done");
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::GetNonceValidityTimeL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CPnpUtilImpl::GetNonceValidityTimeL()
+    {
+    // Not used
+    User::Leave( KErrNotSupported );
+    return KErrNone;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::GetNonceL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CPnpUtilImpl::GetNonceL( TDes8& aNonce )
+    {
+    LOGSTRING("CPnpUtilImpl::GetNonceL");
+
+    if( aNonce.MaxLength() < KNonceLength )
+        {
+        User::Leave( KErrArgument );
+        }
+    TBuf8<KNonceLength> buffer;
+    
+    User::LeaveIfError( iRepository->Get( KPnPUtilNonce, buffer) );
+
+    // Decrypt
+#ifndef __WINS__
+    if( buffer.Length() > 0 )
+    	{
+    	LOGTEXT( buffer );
+    	iDecryptor->Transform( buffer );
+    	}
+#endif
+
+    LOGSTRING("Nonce:");
+    LOGTEXT( buffer );
+    aNonce.Copy( buffer );
+
+    LOGSTRING("CPnpUtilImpl::GetNonceL - done");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::RandomCharacter
+// -----------------------------------------------------------------------------
+//
+TUint CPnpUtilImpl::RandomCharacter( TInt64& aSeed )
+    {
+    // Create random number value for token
+    TInt value = Math::Rand( aSeed );
+    if( value < 0 )
+        {
+        value = -value;
+        }
+    value %= 61; // [0,61]
+    value += 48; // [48,109]
+    // split the range to ranges [48,57],[65,90] and [97,122]
+    // that is: the ascii codes for numbers from 0 to 9,
+    // capital alphabets from A to Z and alphabets from a to z
+    if( value > 57 )
+        {
+        value += 8; // [65,90]
+        if( value > 90 )
+            {
+            value += 6; // [97,122]
+            }
+        }
+    return value;
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::GetKeyInfoL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CPnpUtilImpl::GetKeyInfoL( TDes8& aKeyInfo )
+    {
+    LOGSTRING("CPnpUtilImpl::GetKeyInfoL");
+    if( aKeyInfo.MaxLength() < KMaxKeyInfoLength )
+        {
+        User::Leave( KErrArgument );
+        }
+    // read keyinfo from cenrep
+    TBuf<KMaxKeyInfoLength> buffer;
+    User::LeaveIfError( iRepository->Get( KPnPUtilKeyInfo, buffer) );
+    aKeyInfo.Copy( buffer );
+    LOGSTRING("CPnpUtilImpl::GetKeyInfoL - done");
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::VerifySignatureL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool CPnpUtilImpl::VerifySignatureL(
+        const TDesC8& aDigestValue, const TDesC8& aSignatureValue,
+        const TDesC8& aData, const TDesC8& aNonce )
+    {
+    LOGSTRING( "CPnpUtilImpl::VerifySignatureL" );
+    LOGTEXT( aDigestValue );
+
+    HBufC8* sendersDigest = DecodeBase64LC( aDigestValue );
+    LOGSTRING( "senders digest:" );
+    LogAsASCIIHexL( *sendersDigest );
+
+    HBufC8* sendersSignature = DecodeBase64LC( aSignatureValue );
+    LOGSTRING( "senders signature:" );
+    LogAsASCIIHexL( *sendersSignature );
+    
+
+    // Read Modulus and PublicExponent from Cenrep
+    LOGSTRING( "Read Modulus and PublicExponent from Cenrep" );
+    TBuf<KMaxModulusLength> bufferMod;
+    TBuf<KMaxPublicExponentLength> bufferExp;
+    User::LeaveIfError( iRepository->Get( KPnPUtilModulus, bufferMod) );
+    User::LeaveIfError( iRepository->Get( KPnPUtilPublicExponent, bufferExp) );
+    
+    TBuf8<KMaxModulusLength> bufferMod8;
+    TBuf8<KMaxPublicExponentLength> bufferExp8;
+    bufferMod8.Copy( bufferMod );
+    bufferExp8.Copy( bufferExp );
+
+    LOGSTRING( "Pack modulus and exponent" );
+    // Look for (lousy/faulty) documentation for RInteger from the 2.1 SDK
+    HBufC8* modulusBuf = PackLC( bufferMod8 );
+    HBufC8* exponentBuf = PackLC( bufferExp8 );
+
+    RInteger modulus = RInteger::NewL( *modulusBuf );
+    RInteger exponent = RInteger::NewL( *exponentBuf );
+
+    CRSAPublicKey* publicKey = CRSAPublicKey::NewLC( modulus, exponent );
+    CRSAPKCS1v15Verifier* rsaVerifier = CRSAPKCS1v15Verifier::NewLC( *publicKey );
+
+    RInteger rsaSignatureInteger = RInteger::NewL( *sendersSignature );
+    CRSASignature* signature = CRSASignature::NewLC( rsaSignatureInteger );
+
+    // Verify the digest against the signature
+    TBool verified = rsaVerifier->VerifyL( *sendersDigest, *signature );
+
+    // These are not needed anymore, destroy
+    CleanupStack::PopAndDestroy( signature );
+    CleanupStack::PopAndDestroy( rsaVerifier );
+    CleanupStack::PopAndDestroy( publicKey );
+    CleanupStack::PopAndDestroy( exponentBuf );
+    CleanupStack::PopAndDestroy( modulusBuf );
+    CleanupStack::PopAndDestroy( sendersSignature );
+
+    
+    if( verified ) // Signature was verified
+        {
+        LOGSTRING( "Signature Verified" );
+
+        // ...Yep, verify also digest
+        verified = VerifyDigestL( *sendersDigest, aData, aNonce );
+        if( verified )
+            {
+            LOGSTRING( "Digest Verified" );
+            }
+        else
+            {
+            LOGSTRING( "Digest NOT verified" );
+            }
+        }
+    else
+        {
+        // ...Nope, do not check the digest, verify already failed anyways
+        LOGSTRING( "Signature NOT verified" );
+        }
+
+    CleanupStack::PopAndDestroy( sendersDigest );
+
+    LOGSTRING( "CPnpUtilImpl::VerifySignatureL - done" );
+    return verified;
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::VerifyDigestL
+// -----------------------------------------------------------------------------
+//
+TBool CPnpUtilImpl::VerifyDigestL(
+        const TDesC8& aSendersDigest, const TDesC8& aData, const TDesC8& aNonce )
+    {
+    LOGSTRING( "VerifyDigestL" );
+    LOGTEXT( aData );
+    LOGTEXT( aNonce );
+
+    CSHA1* sha1 = CSHA1::NewL();
+    CleanupStack::PushL( sha1 );
+
+    HBufC8* dataToBeHashed = HBufC8::NewLC( aData.Length() + aNonce.Length() + 1 );
+    TPtr8 dataToBeHashedPtr = dataToBeHashed->Des();
+    _LIT8( KColon, ":" );
+    dataToBeHashedPtr.Append( aNonce );
+    dataToBeHashedPtr.Append( KColon );
+    dataToBeHashedPtr.Append( aData );
+
+    LOGSTRING( "nonce:data" );
+    LogAsASCIIHexL( *dataToBeHashed );
+
+    TPtrC8 hash = sha1->Final( *dataToBeHashed );
+    LOGSTRING( "computed hash:" );
+    LOGTEXT( hash );
+    LogAsASCIIHexL( hash );
+
+    LOGSTRING( "senders hash:" );
+    LogAsASCIIHexL( aSendersDigest );
+    TBool verified( EFalse );
+    if( hash.Compare( aSendersDigest ) == 0 )
+        {
+        verified = ETrue;
+        }
+    CleanupStack::PopAndDestroy( dataToBeHashed );
+    CleanupStack::PopAndDestroy( sha1 );
+    return verified;
+    }
+
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::LogAsASCIIHexL
+// -----------------------------------------------------------------------------
+//
+void CPnpUtilImpl::LogAsASCIIHexL( const TDesC8& aDesc )
+    {
+    HBufC8* asciiHexBuf = HBufC8::NewLC( aDesc.Length() * 2 );
+    TPtr8 asciiHexBufPtr = asciiHexBuf->Des();
+    TBuf8<2> asciiHex;
+    // binary to ascii (hex)
+    _LIT8( KAsciiHexFormat, "%02X" );
+    TUint8 val;
+    for( TInt i=0; i<aDesc.Length(); i++ )
+        {
+        val = aDesc[i];
+        asciiHex.Format( KAsciiHexFormat, val );
+        asciiHexBufPtr.Append( asciiHex );
+        }
+
+#ifdef _DEBUG
+    for( TInt j(0); j < asciiHexBufPtr.Length(); j += 128 )
+        {
+        TPtrC8 logText = asciiHexBufPtr.Mid(j); // print in 128 byte chunks
+        LOGTEXT( logText );
+        }
+#endif
+
+    CleanupStack::PopAndDestroy( asciiHexBuf );
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::DecodeBase64LC
+// -----------------------------------------------------------------------------
+//
+HBufC8* CPnpUtilImpl::DecodeBase64LC( const TDesC8& aBase64EncodedDesc )
+    {
+    TInt lenght = aBase64EncodedDesc.Length();
+    HBufC8* decoded = HBufC8::NewLC( lenght );
+    TPtr8 decodedPtr = decoded->Des();
+
+    if( lenght % 4 != 0 )
+        {
+        User::Leave( KErrCorrupt );
+        }
+
+    for( TInt i(0); i < lenght - 1; i++ )
+        {
+        // The last two character may be zero characters ('=')
+        if( aBase64EncodedDesc[i] == '=' )
+        {
+            if( i < lenght - 2 || aBase64EncodedDesc[i+1] != '=' )
+                {
+                User::Leave( KErrCorrupt );
+                }
+            return decoded;
+        }
+        else if( aBase64EncodedDesc[i+1] == '=' )
+        {
+            if( i < lenght - 2 )
+                {
+                User::Leave( KErrCorrupt );
+                }
+            return decoded;
+        }
+
+        TChar character( DecodeCharL( aBase64EncodedDesc[i] ) );
+        TChar nextCharacter( DecodeCharL( aBase64EncodedDesc[i + 1] ) );
+
+        switch( i % 4 )
+            {
+            case 0:
+                {
+                TChar shiftedChar(
+                    ( character << 2 ) |                    // bits 0 to 5 of the first character
+                    ( ( nextCharacter & 0x30 ) >> 4 ) );    // bits 4 to 5 of the second character
+                decodedPtr.Append( shiftedChar );
+                }
+                break;
+            case 1:
+                {
+                TChar shiftedChar(
+                    ( character << 4 ) |                    // 0 to 3
+                    ( ( nextCharacter & 0x3C ) >> 2 ) );    // 2 to 5
+                decodedPtr.Append( shiftedChar );
+                }
+                break;
+            case 2:
+                {
+                TChar shiftedChar(
+                    ( ( character & 0x03 ) << 6 ) |            // bits 0 to 1
+                    ( nextCharacter & 0x3F ) );                // bits 0 to 5
+                decodedPtr.Append( shiftedChar );
+                }
+                break;
+            default: /* case 3, skip */
+                break;
+            }
+        }
+    return decoded;
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::DecodeCharL
+// -----------------------------------------------------------------------------
+//
+TChar CPnpUtilImpl::DecodeCharL( const TChar aCharacter )
+    {
+    TChar decodedChar('A');
+
+    if( aCharacter >= 'A' && aCharacter <= 'Z' )
+        {
+        decodedChar = aCharacter - 'A';
+        }
+    else if( aCharacter >= 'a' && aCharacter <= 'z' )
+        {
+        decodedChar = aCharacter - 'a' + 26;
+        }
+    else if( aCharacter >= '0' && aCharacter <= '9' )
+        {
+        decodedChar = aCharacter - '0' + 52;
+        }
+    else if( aCharacter == '+' )
+        {
+        decodedChar = 62;
+        }
+    else if( aCharacter == '/' )
+        {
+        decodedChar = 63;
+        }
+    else if( aCharacter != '=' )
+        {
+        User::Leave( KErrCorrupt );
+        }
+    return decodedChar;
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::PackLC
+// -----------------------------------------------------------------------------
+//
+HBufC8* CPnpUtilImpl::PackLC( const TDesC8& aHex ) const
+    {
+    HBufC8* bin = HBufC8::NewLC( aHex.Length() / 2 );
+    TPtr8 binPtr( bin->Des() );
+    for( TInt i(0); i < aHex.Length() / 2; i++ )
+        {
+        TLex8 lex( aHex.Mid( i * 2, 2 ) );
+        TUint8 byte(0);
+        User::LeaveIfError( lex.Val( byte, EHex ) );
+        binPtr.Append( TUint8( byte ) );
+        }
+    return bin;
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::Imsi
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CPnpUtilImpl::ImsiL(RMobilePhone::TMobilePhoneSubscriberId& aImsi) const
+    {
+    // Get IMSI
+    TRequestStatus status;
+    iPhone.GetSubscriberId( status, aImsi );
+    User::WaitForRequest( status );
+    User::LeaveIfError( status.Int() );
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::FetchHomeNetworkInfoL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CPnpUtilImpl::FetchHomeNetworkInfoL()
+    {
+    LOGSTRING( "FetchHomeNetworkInfoL");
+
+    // Get home (sim) MCC&MNC info
+    RMobilePhone::TMobilePhoneNetworkInfoV1 info;
+    RMobilePhone::TMobilePhoneNetworkInfoV1Pckg infoPckg( info );
+#ifndef __WINS__
+    TRequestStatus status( KRequestPending );
+    iPhone.GetHomeNetwork( status, infoPckg );
+    User::WaitForRequest( status );
+    User::LeaveIfError( status.Int() );
+#else
+    info.iCountryCode.Copy( _L("244") );
+    info.iNetworkId.Copy( _L("05") );
+#endif
+
+    RMobilePhone::TMobilePhoneNetworkIdentity formattedMnc;
+    FormatMncCodeL( info.iCountryCode, info.iNetworkId, formattedMnc );
+    SetHomeMncL( formattedMnc );
+    SetHomeMccL( info.iCountryCode );
+
+    LOGSTRING( "FetchHomeNetworkInfoL - done");
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::FetchNetworkInfoL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CPnpUtilImpl::FetchNetworkInfoL()
+    {
+    LOGSTRING( "FetchNetworkInfoL");
+
+    // Get current (network) MCC&MNC info
+    TRequestStatus status;
+    LOGSTRING( "FetchNetworkInfoL 1");
+    RMobilePhone::TMobilePhoneNetworkInfoV1 info;
+    RMobilePhone::TMobilePhoneNetworkInfoV1Pckg infoPckg( info );
+    LOGSTRING( "FetchNetworkInfoL 2");
+    status = KErrNone;
+    LOGSTRING( "FetchNetworkInfoL 3");
+
+    iPhone.GetCurrentNetwork( status, infoPckg );
+
+    LOGSTRING( "FetchNetworkInfoL 4");
+    User::WaitForRequest( status );
+    LOGSTRING( "FetchNetworkInfoL 5");
+    User::LeaveIfError( status.Int() );
+    LOGSTRING( "FetchNetworkInfoL 6");
+
+    RMobilePhone::TMobilePhoneNetworkIdentity formattedMnc;
+    FormatMncCodeL( info.iCountryCode, info.iNetworkId, formattedMnc );
+    LOGSTRING( "FetchNetworkInfoL 7");
+    SetNetworkMncL( formattedMnc );
+    LOGSTRING( "FetchNetworkInfoL 8");
+    SetNetworkMccL( info.iCountryCode );
+
+    LOGSTRING( "FetchNetworkInfoL - done");
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::HomeMccL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C const RMobilePhone::TMobilePhoneNetworkCountryCode CPnpUtilImpl::HomeMccL() const
+    {
+    RMobilePhone::TMobilePhoneNetworkIdentity mcc;
+    User::LeaveIfError( iRepository->Get( KPnPUtilHomeMcc, mcc ) );
+    LOGSTRING2( "HomeMccL %S", &mcc );
+
+    return mcc;
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::SetHomeMccL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CPnpUtilImpl::SetHomeMccL( const RMobilePhone::TMobilePhoneNetworkCountryCode aMcc )
+    {
+    LOGSTRING2( "SetHomeMccL %S", &aMcc );
+    User::LeaveIfError( iRepository->Set( KPnPUtilHomeMcc, aMcc ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::HomeMncL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C const RMobilePhone::TMobilePhoneNetworkIdentity CPnpUtilImpl::HomeMncL() const
+    {
+    RMobilePhone::TMobilePhoneNetworkIdentity mnc;
+    User::LeaveIfError( iRepository->Get( KPnPUtilHomeMnc, mnc ) );
+    LOGSTRING2( "HomeMncL %S", &mnc );
+    return mnc;    
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::SetHomeMncL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CPnpUtilImpl::SetHomeMncL( const RMobilePhone::TMobilePhoneNetworkIdentity aMnc )
+    {
+    LOGSTRING2( "SetHomeMncL %S", &aMnc );
+    User::LeaveIfError( iRepository->Set( KPnPUtilHomeMnc, aMnc ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::NetworkMccL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C const RMobilePhone::TMobilePhoneNetworkCountryCode CPnpUtilImpl::NetworkMccL() const
+    {
+    RMobilePhone::TMobilePhoneNetworkIdentity mcc;
+    User::LeaveIfError( iRepository->Get( KPnPUtilNetworkMcc, mcc ) );
+    LOGSTRING2( "NetworkMccL %S", &mcc );
+    return mcc;
+    }
+
+EXPORT_C void CPnpUtilImpl::SetNetworkMccL( const RMobilePhone::TMobilePhoneNetworkCountryCode aMcc )
+    {
+    LOGSTRING2( "SetNetworkMccL %S", &aMcc );
+    User::LeaveIfError( iRepository->Set( KPnPUtilNetworkMcc, aMcc ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::NetworkMncL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C const RMobilePhone::TMobilePhoneNetworkIdentity CPnpUtilImpl::NetworkMncL() const
+    {
+    RMobilePhone::TMobilePhoneNetworkIdentity mnc;
+    User::LeaveIfError( iRepository->Get( KPnPUtilNetworkMnc, mnc ) );
+    LOGSTRING2( "NetworkMncL %S", &mnc );
+    return mnc;    
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::NetworkMncL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CPnpUtilImpl::SetNetworkMncL( const RMobilePhone::TMobilePhoneNetworkIdentity aMnc )
+    {
+    LOGSTRING2( "SetNetworkMncL %S", &aMnc );
+    User::LeaveIfError( iRepository->Set( KPnPUtilNetworkMnc, aMnc ) );
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::RegisteredInHomeNetworkL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TBool CPnpUtilImpl::RegisteredInHomeNetworkL()
+    {
+    // Get registeration status
+    TRequestStatus status;
+    RMobilePhone::TMobilePhoneRegistrationStatus regstatus;
+    iPhone.GetNetworkRegistrationStatus(status, regstatus);
+    User::WaitForRequest( status );
+    User::LeaveIfError( status.Int() );
+    return (regstatus == RMobilePhone::ERegisteredOnHomeNetwork);
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::OperatorLongNameL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CPnpUtilImpl::OperatorLongName(RMobilePhone::TMobilePhoneNetworkLongName& aName)
+    {
+    // Get home (sim) MCC&MNC info
+    TRequestStatus status;
+    RMobilePhone::TMobilePhoneNetworkInfoV1 info;
+    RMobilePhone::TMobilePhoneNetworkInfoV1Pckg infoPckg( info );
+    status = KErrNone;
+    iPhone.GetHomeNetwork( status, infoPckg );
+    User::WaitForRequest( status );
+    aName.Zero();
+    aName.Append( info.iLongName ); 
+    return status.Int();
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::StoreAccessPoint
+// -----------------------------------------------------------------------------
+//
+EXPORT_C TInt CPnpUtilImpl::StoreAccessPoint(TUint32 /*aAP*/)
+    {
+    // Not used
+    return KErrNotSupported;
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::FetchAccessPoint
+// -----------------------------------------------------------------------------
+//
+TInt CPnpUtilImpl::FetchAccessPoint(TUint32& /*aAP*/)
+    {
+    // Not used
+    return KErrNotSupported;
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::FormatMncCodeL
+// -----------------------------------------------------------------------------
+//
+EXPORT_C void CPnpUtilImpl::FormatMncCodeL(
+    const RMobilePhone::TMobilePhoneNetworkCountryCode aMcc,
+    const RMobilePhone::TMobilePhoneNetworkIdentity aUnformattedMnc,
+    RMobilePhone::TMobilePhoneNetworkIdentity& aFormattedMnc ) const
+    {
+    LOGSTRING("FormatMncCodeL");
+    LOGTEXT( aMcc );
+    LOGTEXT( aUnformattedMnc );
+
+    RMobilePhone::TMobilePhoneNetworkIdentity formattedMnc;
+
+    // Check that codes only contain valid characters
+    TInt mncValue(0);
+    TInt mccValue(0);
+
+    TLex mncParser( aUnformattedMnc );
+    TInt err = mncParser.Val( mncValue );
+    if( err != KErrNone )
+        {
+        User::Leave( KErrCorrupt );
+        }
+
+    TLex mccParser( aMcc );
+    err = mccParser.Val( mccValue );
+    if( err != KErrNone )
+        {
+        User::Leave( KErrCorrupt );
+        }
+
+    // In N7610 the MNC given by RMobilePhone::GetHomeNetwork is
+    // always three digits
+    // But for example in N6630 the MNC seems to be correctly formatted
+
+    // The initial value is the given MNC:
+    formattedMnc.Copy( aUnformattedMnc );
+
+    // Reformat only if needed
+    if( aUnformattedMnc.Length() == 3 )
+        {
+        // Assume two digits, exceptions follow
+        formattedMnc.Copy( aUnformattedMnc.Left(2) );
+
+        if( aMcc.Compare( _L("302") ) == 0 ||
+            aMcc.Compare( _L("346") ) == 0 ||
+            aMcc.Compare( _L("348") ) == 0 ||
+            aMcc.Compare( _L("356") ) == 0 ||
+            aMcc.Compare( _L("365") ) == 0 ||
+            aMcc.Compare( _L("376") ) == 0 ||
+            aMcc.Compare( _L("467") ) == 0 ||
+            aMcc.Compare( _L("732") ) == 0 )
+            {
+            // MNC should be three digits
+            formattedMnc.Copy( aUnformattedMnc );
+            }
+        else if( aMcc.Compare( _L("310") ) == 0 )
+            {
+            // MNC is always three digits in this case
+            // For example: 000, 011, 110, 020, 200, ...
+            formattedMnc.Copy( aUnformattedMnc );
+            }
+        else if( aMcc.Compare( _L("311") ) == 0 )
+            {
+            // 3 digit (USA) some exceptions
+
+            // See previous case for comments
+            formattedMnc.Copy( aUnformattedMnc );
+            }
+
+        else if( aMcc.Compare( _L("338") ) == 0 )
+            {
+            // 2 digit, but 3 digit if 180 (JAM)
+            if( aUnformattedMnc.Compare( _L("180") ) == 0 )
+                {
+                formattedMnc.Copy( aUnformattedMnc );
+                }
+            }
+        else if( aMcc.Compare( _L("342") ) == 0 )
+            {
+            // 2 digit, but 3 digit if larger than 51
+            if( mncValue >= 510 )
+                {
+                formattedMnc.Copy( aUnformattedMnc );
+                }
+            }
+        else if( aMcc.Compare( _L("344") ) == 0 )
+            {
+            // 2 digit, but 3 digit if larger than 31
+            if( mncValue >= 310 )
+                {
+                formattedMnc.Copy( aUnformattedMnc );
+                }
+            }
+        else if( aMcc.Compare( _L("352") ) == 0 )
+            {
+            // 2 digit, but 3 digit if smaller than 29
+            if( mncValue < 300 )
+                {
+                formattedMnc.Copy( aUnformattedMnc );
+                }
+            }
+        else if( aMcc.Compare( _L("358") ) == 0 )
+            {
+            // 2 digit, but 3 digit if smaller than 20
+            if( mncValue < 300 )
+                {
+                formattedMnc.Copy( aUnformattedMnc );
+                }
+            }
+        else if( aMcc.Compare( _L("360") ) == 0 )
+            {
+            // 2 digit, but 3 digit if 110
+            if( aUnformattedMnc.Compare( _L("110") ) == 0 )
+                {
+                formattedMnc.Copy( aUnformattedMnc  );
+                }
+            }
+        else if( aMcc.Compare( _L("362") ) == 0 )
+            {
+            // 2 digit, but 3 digit if larger than 92
+            if( mncValue >= 920 )
+                {
+                formattedMnc.Copy( aUnformattedMnc );
+                }
+            }
+        else if( aMcc.Compare( _L("366") ) == 0 )
+            {
+            // 2 digit, but 3 digit if 110
+            if( aUnformattedMnc.Compare( _L("110") ) == 0 )
+                {
+                formattedMnc.Copy( aUnformattedMnc );
+                }
+            }
+        else if( aMcc.Compare( _L("722") ) == 0 )
+            {
+            // 2 digit, but 3 digit if 310
+            if( aUnformattedMnc.Compare( _L("310") ) == 0 )
+                {
+                formattedMnc.Copy( aUnformattedMnc );
+                }
+            }
+        }
+    aFormattedMnc.Copy( formattedMnc );
+    }
+
+// -----------------------------------------------------------------------------
+// CPnpUtilImpl::RESERVED_FUNC
+// -----------------------------------------------------------------------------
+//
+void CPnpUtilImpl::RESERVED_FUNC()
+    {
+    LOGSTRING("RESERVED_FUNC")
+    }
+
+//  End of File