--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/omaprovisioning/provisioning/ProvisioningEngine/Src/CWPPushMessage.cpp Thu Dec 17 09:07:52 2009 +0200
@@ -0,0 +1,1237 @@
+/*
+* 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