/*
* Copyright (c) 2002 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: Helps in saving/loading a push message.
*
*/
// INCLUDE FILES
#include <e32base.h>
#include <msvstore.h>
#include <hash.h>
#include <chttpresponse.h>
#include <centralrepository.h>
#include "ProvisioningVariant.hrh"
#include "CWPPushMessage.h"
#include "ProvisioningDebug.h"
#include "ProvisioningUIDs.h"
#include "CWPEngine.pan"
#include "ProvisioningInternalCRKeys.h"
// CONSTANTS
/// Short integers must be masked with this to get real number
const TUint KShortIntegerMask = 0x7f;
/// In q-values if the number is above this number, there are more bytes.
const TUint KQValueContinuation = 0x80;
/// Quotes strings start with this constant.
const TUint KQuotedStringStart = 34;
/// Quotes strings start with this constant.
const TUint KQuotedTextStringStart = 127;
/// Maximum length of a long integer.
const TUint KMaxLongIntegerLength = 30;
/// Types of coding a value in a parameter
enum TParameterCodingType {
EQValue,
EWellKnownCharset,
EVersionValue,
EIntegerValue,
ETextString,
EFieldName,
EShortInteger,
EConstrainedEncoding,
EDeltaSecondsValue,
ENoValue,
ETextValue,
EDateValue
};
/// Well-known parameter assignments and their mappings to value types
/// (WAP-230-WSP-20010705-a, table 38)
const TParameterCodingType KParameterTypes[] =
{
EQValue,
EWellKnownCharset,
EVersionValue,
EIntegerValue,
ENoValue,
ETextString,
ETextString,
EFieldName,
EShortInteger,
EConstrainedEncoding,
ETextString,
ETextString,
ETextString,
ETextString,
EDeltaSecondsValue,
ETextString,
ENoValue,
EShortInteger,
ETextValue,
EDateValue,
EDateValue,
EDateValue,
EIntegerValue,
ETextValue,
ETextValue,
ETextValue,
ETextValue,
ETextValue,
ETextValue,
ETextValue
};
/// Date-values are seconds from this date
_LIT( KDateValueStart, "19700101:000000.000000" );
/// WSP constant for field SEC
const TInt KWSPHeaderSEC = 0x11;
/// WSP constant for field MAC
const TInt KWSPHeaderMAC = 0x12;
/// Number of BCD digits in byte
const TInt KNumDigitsInByte = 2;
/// Number of bits in half-byte
const TInt KNumBitsInNibble = 4;
/// Ascii code for zero
const TUint8 KZero = '0';
/// Padding half-byte
const TUint8 KPadNibble = 0xf;
/// First nibble
const TUint8 KFirstNibble = 0x1;
/// Parity bit number in first nibble
const TUint KParityBitNum = 3;
/// Content type code for OMA Provisioning messages
const TUint8 KContentType = 0xb6;
/// Provisioning message format version when stored in Messaging Store
const TInt KProvisioningMsgVersion = 1;
// ============================ MEMBER FUNCTIONS ===============================
// -----------------------------------------------------------------------------
// CWPPushMessage::CWPPushMessage
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CWPPushMessage::CWPPushMessage()
: iInitiator( KNullDesC8 ), iSEC( KSECNONE )
{
}
// -----------------------------------------------------------------------------
// CWPPushMessage::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CWPPushMessage::ConstructL()
{
iHeader = CHTTPResponse::NewL();
}
// -----------------------------------------------------------------------------
// CWPPushMessage::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CWPPushMessage* CWPPushMessage::NewL()
{
CWPPushMessage* self = NewLC();
CleanupStack::Pop();
return self;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
EXPORT_C CWPPushMessage* CWPPushMessage::NewLC()
{
CWPPushMessage* self = new( ELeave ) CWPPushMessage;
CleanupStack::PushL( self );
self->ConstructL();
return self;
}
// Destructor
CWPPushMessage::~CWPPushMessage()
{
delete iBody;
delete iHeader;
delete iOriginator;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::StoreL
// -----------------------------------------------------------------------------
//
EXPORT_C void CWPPushMessage::StoreL( CMsvStore& aStore ) const
{
TUid uid;
uid.iUid = KProvisioningMessageStreamUid;
aStore.Remove( uid );
RMsvWriteStream stream;
stream.AssignLC( aStore, uid );
ExternalizeL( stream );
CleanupStack::PopAndDestroy(); // stream
}
// -----------------------------------------------------------------------------
// CWPPushMessage::RestoreL
// -----------------------------------------------------------------------------
//
EXPORT_C void CWPPushMessage::RestoreL( CMsvStore& aStore )
{
RMsvReadStream stream;
stream.OpenLC( aStore, TUid::Uid( KProvisioningMessageStreamUid ) );
InternalizeL( stream );
CleanupStack::PopAndDestroy(); // stream
ParseHeaderL();
}
// -----------------------------------------------------------------------------
// CWPPushMessage::ExternalizeL
// -----------------------------------------------------------------------------
//
EXPORT_C void CWPPushMessage::ExternalizeL( RWriteStream& aStream ) const
{
// Save version
aStream.WriteInt32L( KProvisioningMsgVersion );
// Save the header
aStream.WriteInt32L( iHeader->Response().Length() );
aStream << iHeader->Response();
aStream.WriteInt8L( iAuthenticated );
aStream.WriteInt8L( iSaved );
// Save the body
aStream.WriteInt32L( iBody->Length() );
aStream << *iBody;
// The sender
if( iOriginator )
{
aStream.WriteInt32L( iOriginator->Length() );
aStream << *iOriginator;
}
else
{
aStream.WriteInt32L( KNullDesC8().Length() );
}
aStream.CommitL();
}
// -----------------------------------------------------------------------------
// CWPPushMessage::InternalizeL
// -----------------------------------------------------------------------------
//
EXPORT_C void CWPPushMessage::InternalizeL( RReadStream& aStream )
{
// Restore the header
TInt version( aStream.ReadInt32L() );
TInt length( aStream.ReadInt32L() );
HBufC8* header = HBufC8::NewLC( aStream, length );
iAuthenticated = aStream.ReadInt8L();
iSaved = aStream.ReadInt8L();
// Restore the body
length = aStream.ReadInt32L();
HBufC8* body = HBufC8::NewL( aStream, length );
// Store header and body
CleanupStack::Pop(); // header
Set( header, body );
if( version == KProvisioningMsgVersion )
{
length = aStream.ReadInt32L();
if( length > 0 )
{
delete iOriginator;
iOriginator = NULL;
iOriginator = HBufC8::NewL( aStream, length );
}
}
}
// -----------------------------------------------------------------------------
// CWPPushMessage::SetL
// -----------------------------------------------------------------------------
//
EXPORT_C void CWPPushMessage::SetL( const TDesC8& aHeader, const TDesC8& aBody )
{
HBufC8* header = aHeader.AllocLC();
HBufC8* body = aBody.AllocL();
CleanupStack::Pop(); // header
Set( header, body );
}
// -----------------------------------------------------------------------------
// CWPPushMessage::Set
// -----------------------------------------------------------------------------
//
EXPORT_C void CWPPushMessage::Set( HBufC8* aHeader, HBufC8* aBody )
{
__ASSERT_DEBUG( aHeader && aBody, Panic( EWPNullMessage ) );
iHeader->AddResponse( aHeader );
delete iBody;
iBody = aBody;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::SetOriginatorL
// -----------------------------------------------------------------------------
//
EXPORT_C void CWPPushMessage::SetOriginatorL( const TDesC8& aOrig )
{
HBufC8* orig = aOrig.AllocL();
delete iOriginator;
iOriginator = orig;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::Header
// -----------------------------------------------------------------------------
//
EXPORT_C const TDesC8& CWPPushMessage::Header() const
{
if( iHeader )
{
return iHeader->Response();
}
else
{
return KNullDesC8;
}
}
// -----------------------------------------------------------------------------
// CWPPushMessage::Body
// -----------------------------------------------------------------------------
//
EXPORT_C const TDesC8& CWPPushMessage::Body() const
{
if( iBody )
{
return *iBody;
}
else
{
return KNullDesC8;
}
}
// -----------------------------------------------------------------------------
// CWPPushMessage::Originator
// -----------------------------------------------------------------------------
//
EXPORT_C const TDesC8& CWPPushMessage::Originator() const
{
if( iOriginator )
{
return *iOriginator;
}
else
{
return KNullDesC8;
}
}
// -----------------------------------------------------------------------------
// CWPPushMessage::SetAuthenticated
// -----------------------------------------------------------------------------
//
EXPORT_C void CWPPushMessage::SetAuthenticated( TBool aAuthenticated )
{
iAuthenticated = aAuthenticated;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::Authenticated
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CWPPushMessage::Authenticated() const
{
return iAuthenticated;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::SetSaved
// -----------------------------------------------------------------------------
//
EXPORT_C void CWPPushMessage::SetSaved( TBool aSaved )
{
iSaved = aSaved;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::Saved
// -----------------------------------------------------------------------------
//
EXPORT_C TBool CWPPushMessage::Saved() const
{
return iSaved;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::InitiatorURI
// -----------------------------------------------------------------------------
//
EXPORT_C const TDesC8& CWPPushMessage::InitiatorURI() const
{
return iInitiator;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::MAC
// -----------------------------------------------------------------------------
//
EXPORT_C const TDesC8& CWPPushMessage::MAC() const
{
return iMAC;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::SEC
// -----------------------------------------------------------------------------
//
EXPORT_C TUint CWPPushMessage::SEC() const
{
return iSEC;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::PushFlag
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CWPPushMessage::PushFlag() const
{
return iPushFlag;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::ParseHeader
// -----------------------------------------------------------------------------
//
EXPORT_C void CWPPushMessage::ParseHeaderL()
{
// CHTTPResponse panicks if it is used for parsing a zero-length
// descriptor.
if( iHeader->Response().Length() > 0 )
{
// We use lexer for safety.
TLex8 contentType( ContentTypeHeader( *iHeader ) );
if( !contentType.Eos() )
{
ParseContentType( contentType );
}
TLex8 initiatorURI( InitiatorURIHeader( *iHeader ) );
if( !initiatorURI.Eos() )
{
ParseInitiatorURI( initiatorURI );
}
TLex8 pushFlag( PushFlagHeader( *iHeader ) );
if( !pushFlag.Eos() )
{
ParsePushFlag( pushFlag );
}
}
}
// -----------------------------------------------------------------------------
// CWPPushMessage::ParseInitiatorURI
// -----------------------------------------------------------------------------
//
void CWPPushMessage::ParseInitiatorURI( TLex8& aPointer )
{
iInitiator.Set( GetTextString( aPointer ) );
}
// -----------------------------------------------------------------------------
// CWPPushMessage::ParsePushFlag
// -----------------------------------------------------------------------------
//
void CWPPushMessage::ParsePushFlag( TLex8& aPointer )
{
TInt64 pushFlag( GetIntegerValue( aPointer ) );
iPushFlag = I64LOW(pushFlag);
}
// -----------------------------------------------------------------------------
// CWPPushMessage::ParseContentType
// -----------------------------------------------------------------------------
//
void CWPPushMessage::ParseContentType( TLex8& aPointer )
{
// Go through the whole content type header.
while( !aPointer.Eos() )
{
// Each parameter might be well-known (integer) or unknown (text)
if( IsIntegerValue( aPointer ) )
{
// For well-known parameters, the token is an integer value
TUint paramToken( I64LOW( GetIntegerValue( aPointer ) ) );
// These are filled with results from parsing.
TInt resultInteger( 0 );
TPtrC8 resultString;
// Make sure paramToken fits into KParameterTypes table
if( paramToken
< sizeof(KParameterTypes)/sizeof(TParameterCodingType))
{
// Get the coding and use it to determine how we should decode
// the next parameter value. We actually ignore all results
// except short integer (SEC) and text-value (MAC), but the
// rest of the parameters have to be parsed anyway.
TParameterCodingType coding( KParameterTypes[paramToken] );
switch( coding )
{
case EQValue:
GetQValue( aPointer );
break;
case EWellKnownCharset:
GetWellKnownCharset( aPointer );
break;
case EVersionValue:
GetVersionValue( aPointer );
break;
case EIntegerValue:
GetIntegerValue( aPointer );
break;
case ETextString:
GetTextString( aPointer );
break;
case EFieldName:
GetFieldName( aPointer );
break;
case EShortInteger:
resultInteger = GetShortInteger( aPointer );
break;
case EConstrainedEncoding:
GetConstrainedEncoding( aPointer );
break;
case EDeltaSecondsValue:
GetDeltaSecondsValue( aPointer );
break;
case ENoValue:
GetNoValue( aPointer );
break;
case ETextValue:
resultString.Set( GetTextValue( aPointer ) );
break;
case EDateValue:
GetDateValue( aPointer );
break;
default:
break;
}
// We have a result. We're actually only interested in
// SEC and MAC parameters, so we save them here.
switch( paramToken )
{
case KWSPHeaderSEC:
iSEC = resultInteger;
break;
case KWSPHeaderMAC:
iMAC.Set( resultString );
break;
default:
break;
}
}
}
else
{
// Unknown parameter. Its name is in text, and the value
// might be an integer or text.
GetTokenText( aPointer );
if( IsIntegerValue( aPointer ) )
{
GetIntegerValue( aPointer );
}
else
{
GetTextValue( aPointer );
}
}
}
}
// -----------------------------------------------------------------------------
// CWPPushMessage::GetQValue
// -----------------------------------------------------------------------------
//
TUint CWPPushMessage::GetQValue( TLex8& aPointer ) const
{
// q-value is an integer. It is coded as 7 bits per byte.
// The highest bit determines if the number continues.
TUint result( 0 );
TBool lastDigit( EFalse );
while( !aPointer.Eos() && !lastDigit )
{
TInt one( aPointer.Get() );
result = (result << 7) || (one & ~KQValueContinuation);
if( (one & KQValueContinuation) == 0 )
{
lastDigit = ETrue;
}
}
return result;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::GetDateValue
// -----------------------------------------------------------------------------
//
TTime CWPPushMessage::GetDateValue( TLex8& aPointer ) const
{
// Date-value is a long integer and represents seconds
// since KDateValueStart.
TInt64 result( GetLongInteger( aPointer ) );
TTime start( KDateValueStart );
TTimeIntervalSeconds delta;
delta = I64LOW(result);
start += delta;
return start;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::GetNoValue
// -----------------------------------------------------------------------------
//
void CWPPushMessage::GetNoValue( TLex8& aPointer ) const
{
// We're not checking anything here. No value is no value.
aPointer.Get();
}
// -----------------------------------------------------------------------------
// CWPPushMessage::GetDeltaSecondsValue
// -----------------------------------------------------------------------------
//
TInt64 CWPPushMessage::GetDeltaSecondsValue( TLex8& aPointer ) const
{
return GetIntegerValue( aPointer );
}
// -----------------------------------------------------------------------------
// CWPPushMessage::GetConstrainedEncoding
// -----------------------------------------------------------------------------
//
TUint CWPPushMessage::GetConstrainedEncoding( TLex8& aPointer ) const
{
// Constrained encoding can be extension media or short integer
TUint result( 0 );
if( !aPointer.Eos() )
{
TUint first( aPointer.Peek() );
if( first > KShortIntegerMask )
{
result = GetShortInteger( aPointer );
}
else
{
// Just skip the text version
GetTokenText( aPointer );
}
}
return result;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::GetFieldName
// -----------------------------------------------------------------------------
//
TUint CWPPushMessage::GetFieldName( TLex8& aPointer ) const
{
// Field name can be a short integer or text.
TUint result( 0 );
if( !aPointer.Eos() )
{
TUint first( aPointer.Peek() );
if( first > KShortIntegerMask )
{
result = GetShortInteger( aPointer );
}
else
{
// Only well-known fields are read
GetTokenText( aPointer );
}
}
return result;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::GetTokenText
// -----------------------------------------------------------------------------
//
TPtrC8 CWPPushMessage::GetTokenText( TLex8& aPointer ) const
{
// Token text is just characters with an end-of-string marker.
aPointer.Mark();
while( !aPointer.Eos() && aPointer.Get() != EKeyNull )
{
// Do nothing
}
return aPointer.MarkedToken();
}
// -----------------------------------------------------------------------------
// CWPPushMessage::GetIntegerValue
// -----------------------------------------------------------------------------
//
TInt64 CWPPushMessage::GetIntegerValue( TLex8& aPointer ) const
{
// Integer value can be a short integer or a long integer.
// Short integer is always >KShortIntegerMask.
TInt64 result( 0 );
if( !aPointer.Eos() )
{
TUint first( aPointer.Peek() );
if( first > KShortIntegerMask )
{
result = GetShortInteger( aPointer );
}
else
{
result = GetLongInteger( aPointer );
}
}
return result;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::IsIntegerValue
// -----------------------------------------------------------------------------
//
TBool CWPPushMessage::IsIntegerValue( TLex8& aPointer ) const
{
// Integer values either are above KShortIntegerMask or
// their first byte is <=KMaxLongIntegerLength.
TBool result( EFalse );
if( !aPointer.Eos() )
{
TUint first( aPointer.Peek() );
if( first > KShortIntegerMask || first <= KMaxLongIntegerLength )
{
result = ETrue;
}
}
return result;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::GetLongInteger
// -----------------------------------------------------------------------------
//
TInt64 CWPPushMessage::GetLongInteger( TLex8& aPointer ) const
{
// Long integer has length as first byte.
TInt64 result( 0 );
TInt length( aPointer.Get() );
for( TInt i( 0 ); i < length; i++ )
{
result = (result << 8) + TInt( aPointer.Get() );
}
return result;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::GetTextValue
// -----------------------------------------------------------------------------
//
TPtrC8 CWPPushMessage::GetTextValue( TLex8& aPointer ) const
{
// Text-value can be quoted, so skip that first.
if( aPointer.Peek() == KQuotedStringStart )
{
aPointer.Inc();
}
aPointer.Mark();
// It is null-terminated
while( aPointer.Get() != EKeyNull )
{
// Do nothing
}
// We don't want to have NULL in the resulting descriptor, so
// back that out.
TPtrC8 result( aPointer.MarkedToken() );
result.Set( result.Left( Max( 0, result.Length()-1 ) ) );
return result;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::GetWellKnownCharset
// -----------------------------------------------------------------------------
//
TInt64 CWPPushMessage::GetWellKnownCharset( TLex8& aPointer ) const
{
return GetIntegerValue( aPointer );
}
// -----------------------------------------------------------------------------
// CWPPushMessage::GetVersionValue
// -----------------------------------------------------------------------------
//
TUint CWPPushMessage::GetVersionValue( TLex8& aPointer ) const
{
// Version-value is a short integer or text. Handle that.
TUint result( 0 );
if( !aPointer.Eos() )
{
TUint first( aPointer.Peek() );
if( first > KShortIntegerMask )
{
result = GetShortInteger( aPointer );
}
else
{
GetTextString( aPointer );
}
}
return result;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::GetShortInteger
// -----------------------------------------------------------------------------
//
TUint CWPPushMessage::GetShortInteger( TLex8& aPointer ) const
{
return aPointer.Get() & KShortIntegerMask;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::GetTextString
// -----------------------------------------------------------------------------
//
TPtrC8 CWPPushMessage::GetTextString( TLex8& aPointer ) const
{
// Text-string can be quoted.
if( aPointer.Peek() == KQuotedTextStringStart )
{
aPointer.Inc();
}
aPointer.Mark();
while( aPointer.Get() != EKeyNull )
{
// Nothing
}
// We don't want to have NULL in the resulting descriptor, so
// back that out.
aPointer.UnGet();
TPtrC8 result( aPointer.MarkedToken() );
aPointer.Inc();
return result;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::ContentTypeHeader
// -----------------------------------------------------------------------------
//
TPtrC8 CWPPushMessage::ContentTypeHeader( CHTTPResponse& aResponse ) const
{
// We use CHTTPResponse to find first the content-type header.
TPtrC8 contentType( KNullDesC8 );
TPtrC8 result( KNullDesC8 );
if( aResponse.FindBinaryDescField( EHttpContentType, contentType )
&& contentType.Length() > 0 )
{
result.Set( contentType );
if( result[0] == KContentType )
{
result.Set( result.Mid(1) );
}
}
return result;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::InitiatorURIHeader
// -----------------------------------------------------------------------------
//
TPtrC8 CWPPushMessage::InitiatorURIHeader( CHTTPResponse& aResponse ) const
{
// We use CHTTPResponse to find first the content-type header.
TPtrC8 initiatorURI( KNullDesC8 );
TPtrC8 result( KNullDesC8 );
if( aResponse.FindBinaryDescField( EHttpXWapInitiatorURI, initiatorURI )
&& initiatorURI.Length() > 0 )
{
result.Set( initiatorURI );
}
return result;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::PushFlagHeader
// -----------------------------------------------------------------------------
//
TPtrC8 CWPPushMessage::PushFlagHeader( CHTTPResponse& aResponse ) const
{
// We use CHTTPResponse to find first the content-type header.
TPtrC8 pushFlag( KNullDesC8 );
TPtrC8 result( KNullDesC8 );
if( aResponse.FindBinaryDescField( EHttpPushFlag, pushFlag )
&& pushFlag.Length() > 0 )
{
result.Set( pushFlag );
}
return result;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::AuthenticateL
// The method first checks if there is security information in the message
// with aMessage.SEC(). If yes, the authentication code described in OMA
// Provisioning Bootstrap specification is calculated and compared to the
// one in message header. If the codes match, authentication has been
// performed succesfully.
// -----------------------------------------------------------------------------
//
EXPORT_C TInt CWPPushMessage::AuthenticateL( const TDesC& aIMSI,
const TDesC& aPIN )
{
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL:" ) );
TInt result( KWPAuthResultAuthenticated );
// Retrieve the MAC from message
ParseHeaderL();
// The HMAC is in ASCII HEX format. Convert to binary.
HBufC8* headerMac = PackLC( MAC() );
// Create space for key
HBufC8* key = HBufC8::NewLC( Max( 1, aIMSI.Length() + aPIN.Length() ) );
TPtr8 keyPtr( key->Des() );
// Check if only NETWPIN authentication is allowed, from central repository.
TInt value( 0 );
CRepository* repository = CRepository::NewLC( KOMAProvAuthenticationLV );
User::LeaveIfError( repository->Get( KOMAProvAuthenticationLVFlag, value ) );
CleanupStack::PopAndDestroy(); // repository
// We support only security type NETWPIN
switch( SEC() )
{
case KSECNETWPIN:
{
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: KSECNETWPIN" ) );
// Get the key to be used in HMAC calculation
ConvertIMSIL( aIMSI, keyPtr );
break;
}
case KSECUSERPIN:
{
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: KSECUSERPIN" ) );
if (EAuthNETWPINOnly != value)
{
if( aPIN.Length() == 0 )
{
result = KWPAuthResultPinRequired;
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: KWPAuthResultPinRequired" ) );
}
keyPtr.Copy( aPIN );
}
else
{
result = KWPAuthResultAuthenticationFailed;
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: KWPAuthResultAuthenticationFailed" ) );
}
break;
}
case KSECUSERNETWPIN:
{
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: KSECUSERNETWPIN" ) );
if (EAuthNETWPINOnly != value)
{
if( aPIN.Length() == 0 )
{
result = KWPAuthResultPinRequired;
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: KWPAuthResultPinRequired" ) );
}
ConvertIMSIL( aIMSI, keyPtr );
keyPtr.Append( aPIN );
}
else
{
result = KWPAuthResultAuthenticationFailed;
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: KWPAuthResultAuthenticationFailed" ) );
}
break;
}
case KSECUSERPINMAC:
{
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: KSECUSERPINMAC" ) );
if (EAuthNETWPINOnly != value)
{
if( aPIN.Length() == 0 )
{
result = KWPAuthResultPinRequired;
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: KWPAuthResultPinRequired" ) );
}
keyPtr.Copy( aPIN );
}
else
{
result = KWPAuthResultAuthenticationFailed;
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: KWPAuthResultAuthenticationFailed" ) );
}
break;
}
default:
{
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: default" ) );
if (EAuthNETWPINOnly == value || EAuthNoSecurity == value )
{
result = KWPAuthResultAuthenticationFailed;
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: KWPAuthResultAuthenticationFailed" ) );
}
else
{
result = KWPAuthResultNoAuthentication;
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: KWPAuthResultNoAuthentication" ) );
}
break;
}
}
if( result == KWPAuthResultAuthenticated )
{
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: KWPAuthResultAuthenticated" ) );
CMessageDigest* digest = CSHA1::NewL();
CleanupStack::PushL( digest );
if( SEC() == KSECUSERPINMAC )
{
// key C is a concatenation of pin K and digest m
TPtrC8 K( key->Left( key->Length()/2 ) );
TPtrC8 m( key->Right( key->Length()/2 ) );
// M' = HMAC-SHA(K, A)
CHMAC* hmac = CHMAC::NewL( K, digest );
CleanupStack::Pop( digest );
CleanupStack::PushL( hmac );
TPtrC8 MM( hmac->Hash( Body() ) );
// Create m' (renamed to mm)
HBufC8* mm = HBufC8::NewLC( m.Length() );
TPtr8 ptr( mm->Des() );
for( TInt i( 0 ); i < m.Length(); i++ )
{
ptr.Append( (MM[i]%10)+KZero );
}
// Compare the MACs and mark the message as authenticated
if( *mm != m )
{
result = KWPAuthResultAuthenticationFailed;
}
CleanupStack::PopAndDestroy(); // mm
}
else
{
FLOG( _L( "[Provisioning] CWPPushMessage::AuthenticateL: not KWPAuthResultAuthenticated" ) );
// Create the HMAC from body
CHMAC* hmac = CHMAC::NewL( *key, digest );
CleanupStack::Pop( digest );
CleanupStack::PushL( hmac );
// Compare the MACs and mark the message as authenticated
if( headerMac->Length() == 0
|| hmac->Hash( Body() ) != *headerMac )
{
result = KWPAuthResultAuthenticationFailed;
}
}
CleanupStack::PopAndDestroy(); // hmac
}
CleanupStack::PopAndDestroy( 2 ); // key, headerMac
return result;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::PackL
// -----------------------------------------------------------------------------
//
HBufC8* CWPPushMessage::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;
}
// -----------------------------------------------------------------------------
// CWPPushMessage::ConvertIMSIL
// -----------------------------------------------------------------------------
//
void CWPPushMessage::ConvertIMSIL( const TDesC& aIMSI, TPtr8& aKey ) const
{
TUint8 parity( TUint8((aIMSI.Length() % 2) << KParityBitNum) );
if( aIMSI.Length() == 0 )
{
aKey.Append( (KPadNibble<<KNumBitsInNibble) + KFirstNibble + parity );
return;
}
// First byte contains just a header and one digit
TInt first( aIMSI[0] - KZero );
aKey.Append( (first<<KNumBitsInNibble) | KFirstNibble | parity );
// Use semi-octet or BCD packing of IMSI. It means that one byte contains
// two decimal numbers, each in its own nibble.
for( TInt i( 1 ); i < aIMSI.Length(); i += KNumDigitsInByte )
{
first = aIMSI[i] - KZero;
TInt second( 0 );
if( aIMSI.Length() == i+1 )
{
second = KPadNibble;
}
else
{
second = aIMSI[i+1] - KZero;
}
aKey.Append( (second<<KNumBitsInNibble) + first );
}
}
// End of File