pnpmobileservices/pnpms/PnP/NHwrParser/HttpProvContent.cpp
author Dremov Kirill (Nokia-D-MSW/Tampere) <kirill.dremov@nokia.com>
Thu, 17 Dec 2009 08:40:12 +0200
changeset 0 3ce708148e4d
permissions -rw-r--r--
Revision: 200949 Kit: 200951

/*
* Copyright (c) 2004 Nokia Corporation and/or its subsidiary(-ies). 
* All rights reserved.
* This component and the accompanying materials are made available
* under the terms of "Eclipse Public License v1.0"
* which accompanies this distribution, and is available
* at the URL "http://www.eclipse.org/legal/epl-v10.html".
*
* Initial Contributors:
* Nokia Corporation - initial contribution.
*
* Contributors:
*
* Description: Implementation of PnPMS components
*
*/



// INCLUDE FILES
#include <hash.h>

#include "HttpProvContent.h"
#include "HttpProvContentType.h"
#include "NHwrParserLogger.h"
#include "HttpProvHeaders.h"
#include "PnpUtilImpl.h"

// CONSTANTS

// 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;


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

// -----------------------------------------------------------------------------
// CHttpProvContent::CHttpProvContent
// C++ default constructor can NOT contain any code, that
// might leave.
// -----------------------------------------------------------------------------
//
CHttpProvContent::CHttpProvContent() : iAuthenticated( EFalse)
    {
    }

// -----------------------------------------------------------------------------
// CHttpProvContent::ConstructL
// Symbian 2nd phase constructor can leave.
// -----------------------------------------------------------------------------
//
void CHttpProvContent::ConstructL( const TPtrC8 aContent )
    {
    iContent.Set( aContent );
    }

// -----------------------------------------------------------------------------
// CHttpProvContent::NewL
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CHttpProvContent* CHttpProvContent::NewL(const TPtrC8 aContent)
    {
    LOGSTRING( "CHttpProvContent::NewL()" );
    CHttpProvContent* self = NewLC(aContent);
    CleanupStack::Pop();
    return self;
    }

// -----------------------------------------------------------------------------
// CHttpProvContent::NewLC
// Two-phased constructor.
// -----------------------------------------------------------------------------
//
CHttpProvContent* CHttpProvContent::NewLC(const TPtrC8 aContent)
    {
    LOGSTRING( "CHttpProvContent::NewLC()" );
    CHttpProvContent* self = new(ELeave) CHttpProvContent; 
    CleanupStack::PushL(self);
    self->ConstructL(aContent);
    return self;
    }

// Destructor
CHttpProvContent::~CHttpProvContent()
    {
    LOGSTRING( "~CHttpProvContent - done" );
    }

// -----------------------------------------------------------------------------
// CHttpProvContent::AuthenticateL
// -----------------------------------------------------------------------------
//
TInt CHttpProvContent::AuthenticateL( const CHttpProvHeaders& aHeaders, CHttpProvContentType& aContentType )
    {
    LOGSTRING( "CHttpProvContent::AuthenticateL" );

    TInt result( KHttpProvAuthResultAuthenticated );

    CPnpUtilImpl* pnpUtil = CPnpUtilImpl::NewLC();

    TInt token = 0;
    TBuf8<4> tokenbuf;    // Token cannot be more the 4 characters long
    tokenbuf.Zero();

    RMobilePhone::TMobilePhoneSubscriberId imsi;
    //    util->Imsi(imsi);
    //    RDebug::Print(imsi);
    
    // Create space for key
    HBufC8* key = HBufC8::NewLC( Max( 1, imsi.MaxLength() + tokenbuf.MaxLength() ) );
    TPtr8 keyPtr( key->Des() );

    LOGSTRING2( "Content type SEC: %i", aContentType.SEC() );

    // We support only security type NETWPIN
    switch( aContentType.SEC() )
        {
        case KSECUSERPIN:
            {
            LOGSTRING("KSECUSERPIN");
            // Get token saved by ConfManager    
            TInt err = pnpUtil->GetTokenValue( token );
            tokenbuf.AppendNum(token);
            if( err != KErrNone )
                {
                result = KHttpProvAuthResultTokenExpired;
                }
            else if( tokenbuf.Length() == 0 )
                {
                result = KHttpProvAuthResultPinRequired;
                }

            keyPtr.Copy( tokenbuf );
            if( result == KHttpProvAuthResultAuthenticated )
                AuthenticateSenderL( *key, aContentType, result );
            break;
            }

        case KSECUSERNETWPIN:
            {
            LOGSTRING("KSECUSERNETWPIN");
            // Get token saved by ConfManager    
            TInt err = pnpUtil->GetTokenValue( token );
            tokenbuf.AppendNum(token);
            if( err != KErrNone )
                {
                result = KHttpProvAuthResultTokenExpired;
                }
            else if( tokenbuf.Length() == 0 )
                {
                result = KHttpProvAuthResultPinRequired;
                }

            ConvertIMSIL( imsi, keyPtr );
            keyPtr.Append( tokenbuf );

            if( result == KHttpProvAuthResultAuthenticated )
                AuthenticateSenderL( *key, aContentType, result );
            break;
            }

        case KSECUSERPINMAC:
            {
            LOGSTRING("KSECUSERPINMAC");
            // Get token saved by ConfManager    
            TInt err = pnpUtil->GetTokenValue( token );
            tokenbuf.AppendNum(token);
            if( err != KErrNone )
                {
                result = KHttpProvAuthResultTokenExpired;
                }
            else if( tokenbuf.Length() == 0 )
                {
                result = KHttpProvAuthResultPinRequired;
                }

            keyPtr.Copy( tokenbuf );

            if( result == KHttpProvAuthResultAuthenticated )
                AuthenticateSenderL( *key, aContentType, result );
            break;
            }
        case KSECPKA:
            {
            LOGSTRING("KSECPKA");
            LOGSTRING( "Get nonce" );
            TBuf8<KNonceLength> nonce;
            pnpUtil->GetNonceL( nonce );

            LOGSTRING( "Verify signature" );
            // Verify digest (Hash value of "nonce:data") and signature of the sender
            if( !pnpUtil->VerifySignatureL(
                    aHeaders.GetParamValL( KDigestValue ),
                    aHeaders.GetParamValL( KSignatureValue ),
                    iContent,
                    nonce ) )
                {
                LOGSTRING("Signature verify failed");
                result = KHttpProvAuthResultAuthenticationFailed;
                }
            else
                {
                LOGSTRING("Signature verified");
                }
            break;
            }
        default:
            {
            LOGSTRING("No authentication");
            result = KHttpProvAuthResultNoAuthentication;
            }
        }


    CleanupStack::PopAndDestroy( key ); // key, headerMac

    CleanupStack::PopAndDestroy( pnpUtil );

    LOGSTRING2( "CHttpProvContent::AuthenticateL - done: %i", result );
    
    return result;
    }

void CHttpProvContent::AuthenticateSenderL( const TDesC8& aKey, CHttpProvContentType& aContentType, TInt& aResult )
    {
    LOGSTRING( "CHttpProvContent::AuthenticateSenderL" );
    // The HMAC is in ASCII HEX format. Convert to binary.
    TPtrC8 mac;
    aContentType.MACL(mac);
    LOGSTRING( "mac:" );
    LOGTEXT( mac );
    HBufC8* headerMac = PackLC( mac );
    CMessageDigest* digest = CSHA1::NewL();
    CleanupStack::PushL( digest );

    if( aContentType.SEC() == KSECUSERPINMAC )
        {
        // key C is a concatenation of pin K and digest m
        TPtrC8 K( aKey.Left( aKey.Length()/2 ) );
        TPtrC8 m( aKey.Right( aKey.Length()/2 ) );

        // M' = HMAC-SHA(K, A)
        CHMAC* hmac = CHMAC::NewL( K, digest );
        // Ownership of digest is transferred to hmac created above
        CleanupStack::Pop( digest );
        CleanupStack::PushL( hmac );
        TPtrC8 MM( hmac->Hash( iContent ) );

        // 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 )
            {
            aResult = KHttpProvAuthResultAuthenticationFailed;
            }
        CleanupStack::PopAndDestroy( mm );
        CleanupStack::PopAndDestroy( hmac );
        }
    else
        {
        // Create the HMAC from body
        CHMAC* hmac = CHMAC::NewL( aKey, digest );
        LOGTEXT( aKey );
        // Ownership of digest is transferred to hmac created above
        CleanupStack::Pop( digest );
        CleanupStack::PushL( hmac );

        // Compare the MACs and mark the message as authenticated
        TPtrC8 temp = hmac->Hash( iContent );
        if( headerMac->Length() == 0 
            || temp != *headerMac )
            {
            LOGSTRING( "KHttpProvAuthResultAuthenticationFailed" );
            aResult = KHttpProvAuthResultAuthenticationFailed;
            }
        CleanupStack::PopAndDestroy( hmac );
        }
    CleanupStack::PopAndDestroy( headerMac );
    }

// -----------------------------------------------------------------------------
// CHttpProvContent::PackLC
// -----------------------------------------------------------------------------
//
HBufC8* CHttpProvContent::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;
    }

// -----------------------------------------------------------------------------
// CHttpProvContent::ConvertIMSIL
// -----------------------------------------------------------------------------
//
void CHttpProvContent::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 )
        {
        TInt 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