diff -r 000000000000 -r 164170e6151a gba/gbaserver/src/dataretriever.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/gba/gbaserver/src/dataretriever.cpp Tue Jan 26 15:20:08 2010 +0200 @@ -0,0 +1,1358 @@ +/* +* Copyright (c) 2007 Nokia Corporation and/or its subsidiary(-ies). +* All rights reserved. +* This component and the accompanying materials are made available +* under the terms of "Eclipse Public License v1.0" +* which accompanies this distribution, and is available +* at the URL "http://www.eclipse.org/legal/epl-v10.html". +* +* Initial Contributors: +* Nokia Corporation - initial contribution. +* +* Contributors: +* +* Description: Implementation of bootstrap and data retriever +* +*/ + + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "dataretriever.h" +#include "GbaCommon.h" +#include "GBALogger.h" +#include "bootstrap.h" + +_LIT8(KUserAgent,"S60 GBA 1.0"); +_LIT8(KAccept,"*/*"); +_LIT8(KNCVal_2, ":00000001:"); +_LIT8(Kfopaque,""); +_LIT8(Kfalgo,"AKAv1-MD5"); +_LIT8(Kalgorithm,"algorithm"); +_LIT8(formatStr, "%02x"); +_LIT8(KAuthInt,"auth-int"); +_LIT8(KAuts,"auts"); +_LIT8(KHTTPAuthInfo,"Authentication-Info"); +_LIT8(KMD5HashofEmpty,"d41d8cd98f00b204e9800998ecf8427e"); +_LIT8(KClose, "Close"); +_LIT(KColon, ":"); + + +//Constants +const TInt KNumber3 = 3; +const TInt KNumber5 = 5; +const TInt KNumber8 = 8; +const TInt KNumber32 = 32; +const TInt KNumber33 = 33; +const TInt KNumber34 = 34; +// Length of a digest hash when represented in hex +const TInt KHashLength = 32; +// Length of a digest hash before converting to hex. +const TInt KRawHashLength = 16; +const TInt KMaxRequestBuffer = 255; +const TInt KAlgLength = 40; + +// --------------------------------------------------------------------------- +// CDataRetriever::NewL() +// --------------------------------------------------------------------------- +// +CDataRetriever* CDataRetriever::NewL( MBootstrapCallBack* aBootstrapCallBack ) + { + CDataRetriever* self = NewLC( aBootstrapCallBack ); + CleanupStack::Pop( self ); + return self; + } + + +// --------------------------------------------------------------------------- +// CDataRetriever::NewLC() +// --------------------------------------------------------------------------- +// +CDataRetriever* CDataRetriever::NewLC( MBootstrapCallBack* aBootstrapCallBack ) + { + CDataRetriever* self = new (ELeave) CDataRetriever( aBootstrapCallBack ) ; + CleanupStack::PushL( self ); + self->ConstructL(); + return self; + } + + +// --------------------------------------------------------------------------- +// CDataRetriever::CDataRetriever() +// --------------------------------------------------------------------------- +// +CDataRetriever::CDataRetriever( MBootstrapCallBack* aBootstrapCallBack ) + : iBootstrapCallBack( aBootstrapCallBack ) + { + } + + +// --------------------------------------------------------------------------- +// CDataRetriever::ConstructL() +// --------------------------------------------------------------------------- +// +void CDataRetriever::ConstructL() + { + iHttpHandler = C3GPPBootstrapHttpHandler::NewL( this, iBootstrapCallBack ); + iInternalState = EReadyForRequest; + iCmManagerExt.OpenL(); + } + + +// --------------------------------------------------------------------------- +// CDataRetriever::~CDataRetriever() +// --------------------------------------------------------------------------- +// +CDataRetriever::~CDataRetriever() + { + GBA_TRACE_DEBUG(("CDataRetriever::~CDataRetriever")); + + delete iHttpHandler; + iHTTPTransaction.Close(); + iHTTPSession.Close(); + iConnection.Close(); + iSockServ.Close(); + iCmManagerExt.Close(); + + if ( iInternalState == EMakeRequestCalled ) + { + GBA_TRACE_DEBUG(("CDataRetriever::~CDataRetriever EMakeRequestCalled")); + User::RequestComplete(iCallerRequestStatus, KErrCancel); + } + + GBA_TRACE_DEBUG(("CDataRetriever::~CDataRetriever End")); + } + +// --------------------------------------------------------------------------- +// CDataRetriever::EventRequestCompletedL() +// --------------------------------------------------------------------------- +// +void CDataRetriever::EventRequestCompletedL(TInt aErrorCode) + { + GBA_TRACE_DEBUG(("CDataRetriever::EventRequestCompletedL enter")); + + if ( iInternalState == EMakeRequestCalled ) + { + GBA_TRACE_DEBUG(("CDataRetriever::EventRequestCompletedL EMakeRequestCalled")); + + TRAPD( err, iBootstrapCallBack->CompleteBootStrappingL( aErrorCode ) ); + if( err == KErrNone ) + User::RequestComplete(iCallerRequestStatus,aErrorCode); + else + User::RequestComplete(iCallerRequestStatus, err); + // Get Ready for new request + iHttpHandler->Reset(); + iHTTPTransaction.Close(); + iHTTPSession.Close(); + iConnection.Close(); + iSockServ.Close(); + iInternalState = EReadyForRequest; + } + } + + +// --------------------------------------------------------------------------- +// CDataRetriever::CancelRequest() +// --------------------------------------------------------------------------- +// +void CDataRetriever::CancelRequest() + { + GBA_TRACE_DEBUG(("CDataRetriever::CancelRequest")); + if ( iInternalState == EMakeRequestCalled ) + { + iInternalState = EReadyForRequest; + iHttpHandler->Reset(); + iHTTPTransaction.Close(); + iHTTPSession.Close(); + iConnection.Close(); + iSockServ.Close(); + User::RequestComplete( iCallerRequestStatus, KErrCancel ); + } + } + + +// --------------------------------------------------------------------------- +// CDataRetriever::MakeRequestL() +// --------------------------------------------------------------------------- +// +void CDataRetriever::MakeRequestL( + TRequestStatus* aRequestStatus, + const TDesC8& aIdentity, + const TDesC8& aRealm, + const TDesC8& aBsfUri, + const TDesC8& aReferrerNAFUri, + const TInt& aIAPID ) + { + GBA_TRACE_BEGIN(); + + if ( iInternalState != EReadyForRequest ) + { + User::LeaveIfError( KErrInUse ); + } + + iCallerRequestStatus = aRequestStatus; + + SetupSessionL( aIAPID ); + + // Add headers appropriate to all methods + TUriParser8 URIParse; + + User::LeaveIfError( URIParse.Parse( aBsfUri ) ); + + iHTTPTransaction = iHTTPSession.OpenTransactionL( URIParse, *iHttpHandler ); + RHTTPHeaders hdr = iHTTPTransaction.Request().GetHeaderCollection(); + + GBA_TRACE_DEBUG(URIParse.Extract(EUriHost) ); + + SetHeaderL(hdr,HTTP::EHost, URIParse.Extract(EUriHost) ); + SetHeaderL(hdr,HTTP::EUserAgent, KUserAgent); + SetHeaderL(hdr,HTTP::EAccept, KAccept); + SetHeaderL(hdr,HTTP::EReferer, aReferrerNAFUri); + + SetHeaderL(hdr, HTTP::EConnection, KClose); + + TBuf8 bufAuth; + bufAuth.Copy(_L8("Digest username=\"")); + bufAuth.Append(aIdentity); + bufAuth.Append(_L8("\", realm=\"")); + + bufAuth.Append(aRealm); + bufAuth.Append(_L8("\", nonce=\"\", uri=\"/\", response=\"\"")); + + GBA_TRACE_DEBUG(bufAuth); + SetHeaderL(hdr,HTTP::EAuthorization,bufAuth); + + iHTTPTransaction.SubmitL(); + iInternalState = EMakeRequestCalled; + GBA_TRACE_END(); + } + +// --------------------------------------------------------------------------- +// CDataRetriever::SetHeaderL() +// --------------------------------------------------------------------------- +// +void CDataRetriever::SetHeaderL(RHTTPHeaders aHeaders, TInt aHdrField, const TDesC8& aHdrValue) + { + RStringF valStr = iHTTPSession.StringPool().OpenFStringL(aHdrValue); + THTTPHdrVal val(valStr); + aHeaders.SetFieldL(iHTTPSession.StringPool().StringF(aHdrField,RHTTPSession::GetTable()), val); + valStr.Close(); + } + +// --------------------------------------------------------------------------- +// CDataRetriever::SetupSessionL() +// Establish a connection for bootstrapping +// --------------------------------------------------------------------------- +// +void CDataRetriever::SetupSessionL( const TInt& aIAPID ) + { + GBA_TRACE_DEBUG(("CDataRetriever::SetupSession")); + // check that sockserver is available + + User::LeaveIfError(iSockServ.Connect() ); + GBA_TRACE_DEBUG(("Socket server connected")); + + // check that connection is possible + User::LeaveIfError(iConnection.Open(iSockServ) ); + GBA_TRACE_DEBUG(("Connection opened")); + + if ( !ValidateGivenIAPIDL( aIAPID ) ) + { + GBA_TRACE_DEBUG(("No valid iapid from user")); + TConnSnapPref snapPref; + TUint32 snapid = GetInternetDestIDL(); + GBA_TRACE_DEBUG_NUM(("the chosen snap id is %d"), snapid ); + snapPref.SetSnap( snapid ); + TInt err = iConnection.Start( snapPref ); + + if ( err != KErrNone ) + { + GBA_TRACE_DEBUG_NUM(("internet nap error is %d"), err ); + TCommDbConnPref connPref; + connPref.SetDialogPreference( ECommDbDialogPrefPrompt ); + User::LeaveIfError( iConnection.Start( connPref ) ); + } + } + else + { + GBA_TRACE_DEBUG(("User gives valid iapid go with it")); + //given iapid is valid, go with it + TCommDbConnPref connPref; + connPref.SetDirection( ECommDbConnectionDirectionOutgoing ); + + //No dialog present + connPref.SetDialogPreference( ECommDbDialogPrefDoNotPrompt ); + connPref.SetIapId( aIAPID ); + + User::LeaveIfError( iConnection.Start( connPref ) ); + } + + GBA_TRACE_DEBUG(("Access point selection done!")); + + GBA_TRACE_DEBUG(("CDataRetriever::SetupSession, connect choosen is done ")); + + iHTTPSession.OpenL(); + + //GBA Http filter gets loaded into to http session when session is opened + //Remove GBA http filter from http session iHTTPSession + //Reason: Ub interface should not have the User-Agent string "3gpp-gba" + RStringF filterName = iHTTPSession.StringPool().OpenFStringL( KHTTPFilterGBAName ); + CleanupClosePushL( filterName ); + iHTTPSession.FilterCollection().RemoveFilter( filterName ); + CleanupStack::PopAndDestroy( &filterName ); + + GBA_TRACE_DEBUG(("Session opened")); + + //Set selected access point. + RStringPool strPool = iHTTPSession.StringPool(); + RHTTPConnectionInfo httpconnInfo = iHTTPSession.ConnectionInfo(); + + httpconnInfo.SetPropertyL ( strPool.StringF(HTTP::EHttpSocketServ, + RHTTPSession::GetTable() ), THTTPHdrVal (iSockServ.Handle()) ); + + TInt connPtr = REINTERPRET_CAST(TInt, &iConnection); + + httpconnInfo.SetPropertyL ( strPool.StringF(HTTP::EHttpSocketConnection, + RHTTPSession::GetTable() ), THTTPHdrVal (connPtr) ); + + //if 2G interface and cert is untrusted, surpress the warning dialog + if ( iBootstrapCallBack->InterfaceIs2G() ) + { + //surpress the warning dialog + httpconnInfo.SetPropertyL ( strPool.StringF(HTTP::ESecureDialog, + RHTTPSession::GetTable() ),strPool.StringF(HTTP::EDialogNoPrompt, + RHTTPSession::GetTable() ) ); + } + + GBA_TRACE_DEBUG(("SetupSession done")); + } + + +// --------------------------------------------------------------------------- +// CDataRetriever::ValidateGivenIAPIDL() +// --------------------------------------------------------------------------- +// +TBool CDataRetriever::ValidateGivenIAPIDL( const TInt& aIAPID ) + { + using namespace CMManager; + GBA_TRACE_DEBUG((" start valid iapid given by user")); + //aIAPID == -1 selected default accesspoint + if ( aIAPID == -1 ) + { + return EFalse; + } + else + { + TInt CleanupCounter = 0; + + RArray destIdArray; + CleanupClosePushL( destIdArray ); + CleanupCounter++; + iCmManagerExt.AllDestinationsL( destIdArray ); + + for ( TInt i = 0; i< destIdArray.Count(); i++ ) + { + RCmDestinationExt dest = iCmManagerExt.DestinationL( destIdArray[i] ); + CleanupClosePushL( dest ); + CleanupCounter++; + + for ( TInt j=0; j < dest.ConnectionMethodCount(); j++ ) + { + + TUint32 iapId = dest. ConnectionMethodL(j).GetIntAttributeL( ECmIapId ); + + if ( iapId == aIAPID ) + { + GBA_TRACE_DEBUG((" IAPID matches !!")); + CleanupStack::PopAndDestroy( CleanupCounter ); + return ETrue; + } + } + + CleanupStack::PopAndDestroy( &dest ); //dest + CleanupCounter--; // dest + } + GBA_TRACE_DEBUG((" search is over no matching IAPID!!")); + CleanupStack::PopAndDestroy( CleanupCounter ); + return EFalse; + } + } + +// --------------------------------------------------------------------------- +// CDataRetriever::QueryResponseValueL() +// --------------------------------------------------------------------------- +// +HBufC8* CDataRetriever::QueryResponseValueL() + { + return iHttpHandler->GetResponse(); + } + +// --------------------------------------------------------------------------- +// CDataRetriever::GetInternetDestIDL() +// --------------------------------------------------------------------------- +// +TUint32 CDataRetriever::GetInternetDestIDL() + { + using namespace CMManager; + GBA_TRACE_DEBUG((" Get the Dest ID of Internet")); + + TInt CleanupCounter = 0; + + RArray destIdArray; + CleanupClosePushL( destIdArray ); + CleanupCounter++; + iCmManagerExt.AllDestinationsL( destIdArray ); + + for ( TInt i = 0; i< destIdArray.Count(); i++ ) + { + RCmDestinationExt dest = iCmManagerExt.DestinationL( destIdArray[i] ); + CleanupClosePushL( dest ); + CleanupCounter++; + + if ( dest.MetadataL( ESnapMetadataInternet ) ) + { + GBA_TRACE_DEBUG_NUM((" found the internet dest id = %d"), destIdArray[i] ); + + TUint32 desID = destIdArray[i]; + CleanupStack::PopAndDestroy( CleanupCounter ); + return desID; + } + + CleanupStack::PopAndDestroy( &dest ); + CleanupCounter--; // dest + } + GBA_TRACE_DEBUG(("not found the internet dest id") ); + CleanupStack::PopAndDestroy( CleanupCounter ); + return NULL; + } + + +// C3GPPBootstrapHttpHandler +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::ConstructL() +// ----------------------------------------------------------------------------- +// +void C3GPPBootstrapHttpHandler::ConstructL() + { + iResponse=HBufC8::NewL(KMaxBootstrapRespLen); + iMD5Calculator = CMD5::NewL(); + iSucceeded=EFalse; + } + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::C3GPPBootstrapHttpHandler() +// ----------------------------------------------------------------------------- +// +C3GPPBootstrapHttpHandler::C3GPPBootstrapHttpHandler( MHttpRequestEvents* aEventSink, M3GPPAuthenticationCallback* aDataRetrieverCallBack ) + : iEventSink ( aEventSink ), iDataRetrieverCallBack ( aDataRetrieverCallBack ) + { + } + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::~C3GPPBootstrapHttpHandler() +// ----------------------------------------------------------------------------- +// +C3GPPBootstrapHttpHandler::~C3GPPBootstrapHttpHandler() + { + GBA_TRACE_DEBUG(("C3GPPBootstrapHttpHandler::~C3GPPBootstrapHttpHandler()")); + Reset(); + delete iResponse; + delete iMD5Calculator; + GBA_TRACE_DEBUG(("C3GPPBootstrapHttpHandler::~C3GPPBootstrapHttpHandler() end")); + } + + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::Reset() +// ----------------------------------------------------------------------------- +// +void C3GPPBootstrapHttpHandler::Reset() + { + // close strings in string pool if they were opened + iUsername.Close(); + iPassword.Close(); + iNonce.Close(); + iCnonce.Close(); + iUri.Close(); + iRealm.Close(); + iMethod.Close(); + } + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::NewLC() +// ----------------------------------------------------------------------------- +// +C3GPPBootstrapHttpHandler* C3GPPBootstrapHttpHandler::NewLC( MHttpRequestEvents* aEventSink, + M3GPPAuthenticationCallback* aDataRetrieverCallBack ) + { + C3GPPBootstrapHttpHandler* me = new(ELeave)C3GPPBootstrapHttpHandler( aEventSink, aDataRetrieverCallBack ); + CleanupStack::PushL(me); + me->ConstructL(); + return me; + } + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::NewL() +// ----------------------------------------------------------------------------- +// +C3GPPBootstrapHttpHandler* C3GPPBootstrapHttpHandler::NewL( MHttpRequestEvents* aEventSink , + M3GPPAuthenticationCallback* aDataRetrieverCallBack ) + { + C3GPPBootstrapHttpHandler* me = NewLC(aEventSink, aDataRetrieverCallBack ); + CleanupStack::Pop(me); + return me; + } + + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::MHFRunL() +// ----------------------------------------------------------------------------- +// +void C3GPPBootstrapHttpHandler::MHFRunL( RHTTPTransaction aTransaction, const THTTPEvent& aEvent ) + { + GBA_TRACE_DEBUG_NUM(("MHFRunL received event %d"), aEvent.iStatus ); + + switch (aEvent.iStatus) + { + case THTTPEvent::EGotResponseHeaders: + { + // HTTP response headers have been received. + // We can determine now if there is going to be a response body to save. + GBA_TRACE_DEBUG(("THTTPEvent::EGotResponseHeaders")); + RHTTPResponse resp = aTransaction.Response(); + TInt status = resp.StatusCode(); + + RStringF statusStr = resp.StatusText(); + + // 401 = we received a authorization challenge + if ( status == HTTPStatus::EUnauthorized ) + { + // resubmit the transaction and hope for the best + TInt result = HandleAuthorizationChallengeL(aTransaction, aEvent); + if( result == KErrNone ) + { + aTransaction.Cancel(); + aTransaction.SubmitL(); + } + else + { + aTransaction.Cancel(); + iEventSink->EventRequestCompletedL( result ); + } + //a new request with password is sent. + return; + } + TInt responseBodySize = 0; + + // 200 received, succeeded with body + if ( resp.HasBody() && ( status == HTTPStatus::EOk ) ) + { + MHTTPDataSupplier *respbody = resp.Body(); + if ( respbody ) + { + responseBodySize = respbody->OverallDataSize(); + GBA_TRACE_DEBUG_NUM(("Response body size is %d"), responseBodySize ); + iSucceeded = ETrue; + } + } + //Reallocate iResponse buffer size if the response size is greater than KMaxBootstrapRespLen + if( responseBodySize > KMaxBootstrapRespLen ) + iResponse = iResponse->ReAllocL( responseBodySize ); + // we take this opportunity to reset our own buffers + TPtr8 ptrResp(iResponse->Des()); + + ptrResp.Zero(); + } + break; + + case THTTPEvent::EGotResponseBodyData: + { + GBA_TRACE_DEBUG(("THTTPEvent::EGotResponseBodyData")); + // Get the body data supplier + iRespBody = aTransaction.Response().Body(); + + // Some (more) body data has been received (in the HTTP response) + // Append to the output file if we're saving responses + TPtr8 ptrResp(iResponse->Des()); + + TPtrC8 bodyData; + TBool lastChunk = EFalse; + + while ( !lastChunk ) + { + GBA_TRACE_DEBUG(("THTTPEvent::EGotResponseBodyData in loop")); + lastChunk = iRespBody->GetNextDataPart( bodyData ); + + //Issue with formatting string with a special character + //GBA_TRACE_DEBUG( bodyData ); + if ( bodyData.Length() <= ( ptrResp.MaxLength() - ptrResp.Length() ) ) + { + ptrResp.Append( bodyData ); + } + else + { + break; + } + } + + GBA_TRACE_DEBUG_NUM(("Response body received size is %d"), iResponse->Length() ); + // Done with that bit of body data + iRespBody->ReleaseData(); + } + break; + + case THTTPEvent::EResponseComplete: + { + GBA_TRACE_DEBUG(("THTTPEvent::EResponseComplete")); + // The transaction's response is complete + } + break; + + case THTTPEvent::ESucceeded: + { + GBA_TRACE_DEBUG(("THTTPEvent::ESucceeded || KErrDisconnected")); + if ( iSucceeded ) + { + // verify authrsp + User::LeaveIfError(CheckRspAuthL(aTransaction)); + + //Set it back + iSucceeded=EFalse; + + GBA_TRACE_DEBUG(("THTTPEvent::ESucceeded || KErrDisconnected 1")); + iEventSink->EventRequestCompletedL(KErrNone); + } + else + { + iEventSink->EventRequestCompletedL( KErrDisconnected ); + GBA_TRACE_DEBUG(("Connection was closed")); + } + } + break; + + case THTTPEvent::EFailed: + { + GBA_TRACE_DEBUG(("THTTPEvent::EFailed")); + RHTTPResponse resp = aTransaction.Response(); + TInt status = resp.StatusCode(); + GBA_TRACE_DEBUG_NUM( ("http StatusCode : %d "), status ); + iEventSink->EventRequestCompletedL( KErrUnknown ); + } + break; + + //The transaction is being cancelled. An outgoing event. + case THTTPEvent::ECancel: + { + GBA_TRACE_DEBUG(("THTTPEvent::ECancel")); + aTransaction.Cancel(); + } + break; + + // this warning can come when going through proxies + case THTTPEvent::ERedirectedTemporarily: + break; + + default: + { + GBA_TRACE_DEBUG_NUM(("Failed with HTTP event event: %d "),aEvent.iStatus ); + if( aEvent.iStatus < 0 ) + { + // close off the transaction if it's an error + aTransaction.Cancel(); + iEventSink->EventRequestCompletedL( aEvent.iStatus ); + } + } + break; + } + } + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::MHFRunError() +// ----------------------------------------------------------------------------- +// +TInt C3GPPBootstrapHttpHandler::MHFRunError(TInt aError, RHTTPTransaction /*aTransaction*/, const THTTPEvent& aEvent) + { + GBA_TRACE_DEBUG_NUM(("MHFRunError called with error code = %d"), aError); + GBA_TRACE_DEBUG_NUM(("MHFRunError called with http event = %d"),aEvent.iStatus ); + // tell caller that there was an error + TRAPD(err, iEventSink->EventRequestCompletedL(aError)); + return err; + } + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::HandleAuthorizationChallengeL() +// ----------------------------------------------------------------------------- +// +TInt C3GPPBootstrapHttpHandler::HandleAuthorizationChallengeL( RHTTPTransaction aTransaction, const THTTPEvent& /*aEvent*/ ) + { + GBA_TRACE_BEGIN(); + TInt pushCount = 0; + RStringPool stringPool = aTransaction.Session().StringPool(); + RStringF wwwAuthHeader = stringPool.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable()); + RHTTPHeaders headers(aTransaction.Response().GetHeaderCollection()); + + //find header which has digest algorithm and qop is auth-int + TInt headerPart = FindHeaderPartToUseL( aTransaction ); + + if ( headerPart == KErrNotFound ) + { + return KErrArgument; + } + + THTTPHdrVal authTypeParam; + TInt error = headers.GetField( wwwAuthHeader, headerPart, authTypeParam ); + + // If anything goes wrong, just stop. This will have the effect of + // returning the error response from the server to the client. + if ( error != KErrNone ) + { + return error; + } + + TBool haveUserPW = EFalse; + RString realm; + RString username; + RString password; + RString nonce; + RString algorithm; + RString resync; + + // Get realm value from response header + THTTPHdrVal realmVal; + error = headers.GetParam( wwwAuthHeader, + stringPool.StringF( HTTP::ERealm, RHTTPSession::GetTable() ), realmVal, headerPart ) ; + if ( error != KErrNone ) + { + return error; + } + + realm = realmVal.Str(); + GBA_TRACE_DEBUG(("Realm:")); + GBA_TRACE_DEBUG(realm.DesC()); + + THTTPHdrVal nonceVal; + //Get nonce value from response header + // contain the RAND and AUTH + error = headers.GetParam( stringPool.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable()), + stringPool.StringF(HTTP::ENonce,RHTTPSession::GetTable()), + nonceVal, + headerPart); + if ( error != KErrNone ) + { + return error; + } + + nonce=nonceVal.Str(); + GBA_TRACE_DEBUG(("Nonce:")); + GBA_TRACE_DEBUG(nonce.DesC()); + + //Fetch algorithm type + THTTPHdrVal algVal; + error = headers.GetParam( stringPool.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable()), + stringPool.StringF(HTTP::EAlgorithm,RHTTPSession::GetTable()), + algVal, + headerPart); + if ( error != KErrNone ) + { + return error; + } + + algorithm=algVal.Str(); + GBA_TRACE_DEBUG(("Algorithm:")); + GBA_TRACE_DEBUG(algorithm.DesC()); + + // If the SQN is out of range, Resync is required + TBool resyncrequired = EFalse; + + //Get password from smart card + //The smart card will first authenticate the nonce value + RStringF authType = authTypeParam.StrF(); + + TRAP( error, haveUserPW = iDataRetrieverCallBack->GetCredentialsL( aTransaction.Request().URI(), + realm, nonce, algorithm, username, password, resync, resyncrequired ) ) ; + + if ( error != KErrNone ) + { + GBA_TRACE_DEBUG_NUM(("Get Gredentails failed with error %d"), error ); + return error; + } + + if ( haveUserPW || resyncrequired ) + { + CleanupClosePushL(username); + pushCount++; + CleanupClosePushL(password); + pushCount++; + //Resync required + if( resyncrequired ) + { + CleanupClosePushL(resync); + pushCount++; + } + + GBA_TRACE_DEBUG(("HandleAuthorizationChallengeL: received following credentials")); + GBA_TRACE_DEBUG(("Realm:")); + GBA_TRACE_DEBUG(realm.DesC()); + GBA_TRACE_DEBUG(("Username:")); + GBA_TRACE_DEBUG(username.DesC()); + GBA_TRACE_DEBUG(("Password:")); + GBA_TRACE_DEBUG_BINARY(password.DesC()); + GBA_TRACE_DEBUG(("Resync:")); + GBA_TRACE_DEBUG_BINARY(resync.DesC()); + + } + else //No password and no resync required + { + CleanupStack::PopAndDestroy( pushCount ); + return KErrNotFound; + } + + // Encode the Username/Password + switch ( authType.Index( RHTTPSession::GetTable() ) ) + { + case HTTP::EDigest: + { + THTTPHdrVal requestUri; + RHTTPTransactionPropertySet propSet = aTransaction.PropertySet(); + propSet.Property( stringPool.StringF(HTTP::EUri,RHTTPSession::GetTable()), requestUri ); + //save rsp auth calcuation + //Save the string handle for rsp auth checking + //Close the previous handle, then set new one + iUsername.Close(); + iUsername = username.Copy(); + iPassword.Close(); + iPassword = password.Copy(); + iRealm.Close(); + iRealm = realm.Copy(); + iNonce.Close(); + iNonce = nonce.Copy(); + iUri.Close(); + iUri = requestUri.Str().Copy(); + + TRAP ( error, EncodeDigestAuthL( username, password, aTransaction, headerPart, requestUri ) ); + GBA_TRACE_DEBUG(("After Encode Digest AuthL")); + if ( error != KErrNone ) + { + GBA_TRACE_DEBUG_NUM(("After Encode Digest AuthL error %d"), error ); + CleanupStack::PopAndDestroy( pushCount ); + return error; + } + } + break; + default: + { + CleanupStack::PopAndDestroy( pushCount ); + return KErrArgument; + } + + } + GBA_TRACE_DEBUG(("After Encode Digest AuthL 1")); + // Resubmit the request to the server + // add resyncronization header to the request if it is available + if ( resyncrequired ) + { + THTTPHdrVal hdrVal; + RStringF unStr = stringPool.OpenFStringL(KAuts); + CleanupClosePushL(unStr); + pushCount++; + hdrVal.SetStr(resync); + RHTTPHeaders requestHeaders(aTransaction.Request().GetHeaderCollection()); + requestHeaders.SetFieldL( stringPool.StringF(HTTP::EAuthorization,RHTTPSession::GetTable()), + THTTPHdrVal(stringPool.StringF(HTTP::EDigest,RHTTPSession::GetTable())), + unStr, + hdrVal ); + } + GBA_TRACE_DEBUG(("After Encode Digest AuthL 2")); + CleanupStack::PopAndDestroy( pushCount ); + GBA_TRACE_DEBUG(("After Encode Digest AuthL 3")); + return KErrNone; + } + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::FindHeaderPartToUseL() +// ----------------------------------------------------------------------------- +// +TInt C3GPPBootstrapHttpHandler::FindHeaderPartToUseL( RHTTPTransaction aTransaction ) const + { + //We only pick up the first digest authentication fields: + + RStringPool stringPool = aTransaction.Session().StringPool(); + + RStringF wwwAuthenticate = stringPool.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable()); + RStringF realm = stringPool.StringF(HTTP::ERealm,RHTTPSession::GetTable()); + RStringF nonce = stringPool.StringF(HTTP::ENonce,RHTTPSession::GetTable()); + RStringF qop = stringPool.StringF(HTTP::EQop,RHTTPSession::GetTable()); + + RHTTPHeaders headers = aTransaction.Response().GetHeaderCollection(); + const TInt parts = headers.FieldPartsL( wwwAuthenticate ); + + for ( TInt i = 0; i < parts; i++ ) + { + THTTPHdrVal fieldVal;// The name of the current field. + THTTPHdrVal hdrVal;//A scratch hdrVal + headers.GetField(wwwAuthenticate, i, fieldVal); + switch ( fieldVal.StrF().Index(RHTTPSession::GetTable() ) ) + { + case HTTP::EDigest: + { + // It is Digest, let us check realm, nonce, qop then + if ( headers.GetParam(wwwAuthenticate, realm, hdrVal, i ) == KErrNone + && + headers.GetParam(wwwAuthenticate, nonce, hdrVal, i ) == KErrNone) + { + // We've got a realm and a nonce. If there's a qop, we + // need to check it's acceptable. + if ( headers.GetParam(wwwAuthenticate, qop, hdrVal, i ) == KErrNone + && + FindAuth( hdrVal.Str().DesC() ) ) + { + // the header has qop and it is auth-int. + // we found it + return i; + } + + } + } + break; + + default: + //Ingore if it is not Digest + break; + } + } + return KErrNotFound; +} + + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::EncodeDigestAuthL() +// ----------------------------------------------------------------------------- +// +void C3GPPBootstrapHttpHandler::EncodeDigestAuthL( const RString& aUsername, + const RString& aPW, + RHTTPTransaction& aTransaction, + TInt aHeaderPart, + const THTTPHdrVal& aRequestUri ) + { + GBA_TRACE_BEGIN(); + TInt pushCount = 0; + + RStringPool stringPool = aTransaction.Session().StringPool(); + + GBA_TRACE_DEBUG(("Username:")); + GBA_TRACE_DEBUG(aUsername.DesC()); + + GBA_TRACE_DEBUG(("Passwd:")); + GBA_TRACE_DEBUG_BINARY(aPW.DesC()); + + TBuf8 hash; + TBuf8 cnonce; + //Nonce + THTTPHdrVal nonce; + RHTTPHeaders headers = aTransaction.Response().GetHeaderCollection(); + TInt error = headers.GetParam(stringPool.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable()), + stringPool.StringF(HTTP::ENonce,RHTTPSession::GetTable()), nonce, + aHeaderPart); + + if ( error != KErrNone ) + { + User::LeaveIfError( error ); + } + + //realm + THTTPHdrVal realm; + error = headers.GetParam(stringPool.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable()), + stringPool.StringF(HTTP::ERealm,RHTTPSession::GetTable()), realm, + aHeaderPart); + + if ( error != KErrNone ) + { + User::LeaveIfError( error ); + } + + //qop + THTTPHdrVal qop; + error = headers.GetParam(stringPool.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable()), + stringPool.StringF(HTTP::EQop,RHTTPSession::GetTable()), qop, + aHeaderPart); + + if ( error != KErrNone ) + { + User::LeaveIfError( error ); + } + + GenerateCNonce( cnonce ); + + GBA_TRACE_DEBUG(("cnonce:")); + GBA_TRACE_DEBUG_BINARY( cnonce ); + + RString cnonceString = stringPool.OpenStringL(cnonce); + CleanupClosePushL(cnonceString); + pushCount++; + + // stored for auth calculations + iCnonce.Close(); + iCnonce = cnonceString.Copy(); + + // stored for auth calculations + iMethod.Close(); + iMethod = aTransaction.Request().Method().Copy(); + + DigestCalcL( KMD5HashofEmpty, hash ); + + GBA_TRACE_DEBUG(("hash:")); + GBA_TRACE_DEBUG_BINARY( hash ); + + // OK. hash now contains the digest response. Set up the header. + RHTTPHeaders requestHeaders(aTransaction.Request().GetHeaderCollection()); + RHTTPHeaders responseHeaders(aTransaction.Response().GetHeaderCollection()); + + requestHeaders.RemoveField(stringPool.StringF(HTTP::EAuthorization,RHTTPSession::GetTable())); + + //Copy useranme + THTTPHdrVal hdrVal; + hdrVal.SetStr(aUsername); + + //Set the username to request header + requestHeaders.SetFieldL(stringPool.StringF(HTTP::EAuthorization,RHTTPSession::GetTable()), + THTTPHdrVal(stringPool.StringF(HTTP::EDigest,RHTTPSession::GetTable())), + stringPool.StringF(HTTP::EUsername,RHTTPSession::GetTable()), + hdrVal); + + // copy Realm from response headers + responseHeaders.GetParam(stringPool.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable()), + stringPool.StringF(HTTP::ERealm,RHTTPSession::GetTable()), + hdrVal, + aHeaderPart); + + // Set the Realm to request header + requestHeaders.SetFieldL(stringPool.StringF(HTTP::EAuthorization,RHTTPSession::GetTable()), + THTTPHdrVal(stringPool.StringF(HTTP::EDigest,RHTTPSession::GetTable())), + stringPool.StringF(HTTP::ERealm,RHTTPSession::GetTable()), + hdrVal); + + // copy nonce from response headers + responseHeaders.GetParam(stringPool.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable()), + stringPool.StringF(HTTP::ENonce,RHTTPSession::GetTable()), + hdrVal, + aHeaderPart); + + // set nonce to request header + requestHeaders.SetFieldL(stringPool.StringF(HTTP::EAuthorization,RHTTPSession::GetTable()), + THTTPHdrVal(stringPool.StringF(HTTP::EDigest,RHTTPSession::GetTable())), + stringPool.StringF(HTTP::ENonce,RHTTPSession::GetTable()), + hdrVal); + + // Set uri to request header. + // the uri has already been fetched from http property setting + requestHeaders.SetFieldL(stringPool.StringF(HTTP::EAuthorization,RHTTPSession::GetTable()), + THTTPHdrVal(stringPool.StringF(HTTP::EDigest,RHTTPSession::GetTable())), + stringPool.StringF(HTTP::EUri,RHTTPSession::GetTable()), + aRequestUri); + + // Qop with quotation marks + // copy qop from response headers + responseHeaders.GetParam(stringPool.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable()), + stringPool.StringF(HTTP::EQop,RHTTPSession::GetTable()), + hdrVal, + aHeaderPart); + + // Set Qop to request header + requestHeaders.SetFieldL(stringPool.StringF(HTTP::EAuthorization,RHTTPSession::GetTable()), + THTTPHdrVal(stringPool.StringF(HTTP::EDigest,RHTTPSession::GetTable())), + stringPool.StringF(HTTP::EQop,RHTTPSession::GetTable()), + hdrVal); + + //Set Nc + hdrVal.SetStrF(stringPool.StringF(HTTP::E00000001,RHTTPSession::GetTable())); + requestHeaders.SetFieldL(stringPool.StringF(HTTP::EAuthorization,RHTTPSession::GetTable()), + THTTPHdrVal(stringPool.StringF(HTTP::EDigest,RHTTPSession::GetTable())), + stringPool.StringF(HTTP::ENc,RHTTPSession::GetTable()), + hdrVal); + + // Set Cnonce to request header. + hdrVal.SetStr(cnonceString); + requestHeaders.SetFieldL(stringPool.StringF(HTTP::EAuthorization,RHTTPSession::GetTable()), + THTTPHdrVal(stringPool.StringF(HTTP::EDigest,RHTTPSession::GetTable())), + stringPool.StringF(HTTP::ECnonce,RHTTPSession::GetTable()), + hdrVal); + + // Set response to request header. + RString hashStr = stringPool.OpenStringL(hash); + CleanupClosePushL(hashStr); + hdrVal.SetStr(hashStr); + requestHeaders.SetFieldL(stringPool.StringF(HTTP::EAuthorization,RHTTPSession::GetTable()), + THTTPHdrVal(stringPool.StringF(HTTP::EDigest,RHTTPSession::GetTable())), + stringPool.StringF(HTTP::EResponse,RHTTPSession::GetTable()), + hdrVal); + CleanupStack::PopAndDestroy(&hashStr); + + // Get Opaque from response header. + error = responseHeaders.GetParam(stringPool.StringF(HTTP::EWWWAuthenticate,RHTTPSession::GetTable()), + stringPool.StringF(HTTP::EOpaque,RHTTPSession::GetTable()), + hdrVal, aHeaderPart); + + // Set Opaque + if ( error != KErrNotFound ) + { + GBA_TRACE_DEBUG((" found the opaque value and copy it")); + requestHeaders.SetFieldL(stringPool.StringF(HTTP::EAuthorization,RHTTPSession::GetTable()), + THTTPHdrVal(stringPool.StringF(HTTP::EDigest,RHTTPSession::GetTable())), + stringPool.StringF(HTTP::EOpaque,RHTTPSession::GetTable()), + hdrVal); + } + else + { + GBA_TRACE_DEBUG((" No opaque value send empty one")); + RString opaque = stringPool.OpenStringL(Kfopaque); + GBA_TRACE_DEBUG((" No opaque value send empty one 1")); + CleanupClosePushL(opaque); + pushCount++; + hdrVal.SetStr(opaque); + GBA_TRACE_DEBUG((" No opaque value send empty one 2")); + requestHeaders.SetFieldL(stringPool.StringF(HTTP::EAuthorization,RHTTPSession::GetTable()), + THTTPHdrVal(stringPool.StringF(HTTP::EDigest,RHTTPSession::GetTable())), + stringPool.StringF(HTTP::EOpaque,RHTTPSession::GetTable()), + hdrVal); + } + GBA_TRACE_DEBUG((" No opaque value send empty one 3")); + // Set algorithm. + TBuf8 algbuf; + algbuf.Copy(_L8(", ")); + algbuf.Append(Kalgorithm); + algbuf.Append(_L8("=")); + algbuf.Append(Kfalgo); + + GBA_TRACE_DEBUG((" No opaque value send empty one 5")); + + RStringF valStr = stringPool.OpenFStringL(algbuf); + THTTPHdrVal val(valStr); + requestHeaders.SetFieldL(stringPool.StringF(HTTP::EAuthorization,RHTTPSession::GetTable()), val); + valStr.Close(); + + GBA_TRACE_DEBUG((" No opaque value send empty one 4")); + + CleanupStack::PopAndDestroy(pushCount); + GBA_TRACE_DEBUG((" No opaque value send empty one 6")); + } + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::FindAuth() +// ----------------------------------------------------------------------------- +// +TBool C3GPPBootstrapHttpHandler::FindAuth(const TDesC8& aQop) const + { + GBA_TRACE_BEGIN(); + if ( aQop == KAuthInt ) + { + GBA_TRACE_DEBUG((" qop is equal to auth-int")); + return ETrue; + } + else + { + GBA_TRACE_DEBUG((" qop is NOT equal to auth-int")); + GBA_TRACE_DEBUG(("")); + return EFalse; + } + } + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::HA1L() +// ----------------------------------------------------------------------------- +// +void C3GPPBootstrapHttpHandler::HAOneL(const RString& aUsername,const RString& aPW, + const RString& aRealm, TDes8& aResult) + { + HBufC8* a1 = HBufC8::NewMaxLC(aUsername.DesC().Length() + + aPW.DesC().Length() + + 1 + + aRealm.DesC().Length() + 1 + ); + TPtr8 a1Mod = a1->Des(); + a1Mod.Zero(); + + a1Mod.Append(aUsername.DesC()); + a1Mod.Append(':'); + a1Mod.Append(aRealm.DesC()); + a1Mod.Append(':'); + a1Mod.Append(aPW.DesC().Ptr(),aPW.DesC().Length()); + + GBA_TRACE_DEBUG(a1Mod); + Hash(*a1, aResult); + GBA_TRACE_DEBUG(("after hash")); + CleanupStack::PopAndDestroy(a1); + } + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::HAtwoL() +// ----------------------------------------------------------------------------- +// +void C3GPPBootstrapHttpHandler::HATwoL(const RStringF& aMethod, + const RString& aRequestUri, + const TDesC8& aHentity, + TDes8& aResult) + { + // In the auth qop, a2 is Method:digest-uri-value:empty body hash + // Allocate enough space for the method, the URI and the colon, empty content-hash and colon. + TPtrC8 requestUri = aRequestUri.DesC(); + TPtrC8 method = aMethod.DesC(); + HBufC8* a2 = HBufC8::NewMaxLC( requestUri.Length() + method.Length() + KNumber34 ); + TPtr8 a2Mod = a2->Des(); + a2Mod.Zero(); + a2Mod.Append(method); + a2Mod.Append(':'); + + a2Mod.Append( requestUri ); + GBA_TRACE_DEBUG( requestUri ); + // since for this method is always auth-int we always add hentity + a2Mod.Append(':'); + a2Mod.Append(aHentity); + GBA_TRACE_DEBUG(a2Mod); + + Hash(*a2, aResult); + + GBA_TRACE_DEBUG_BINARY(aResult); + CleanupStack::PopAndDestroy(a2); + + GBA_TRACE_DEBUG(("Exit HATwoL")); + } + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::Hash() +// ----------------------------------------------------------------------------- +// +void C3GPPBootstrapHttpHandler::Hash(const TDesC8& aMessage, TDes8& aHash) + { + GBA_TRACE_DEBUG(("hash")); + // Calculate the 128 bit (16 byte) hash + iMD5Calculator->Reset(); + TPtrC8 hash = iMD5Calculator->Hash(aMessage); + GBA_TRACE_DEBUG(("after hash")); + // Now print it as a 32 byte hex number + aHash.Zero(); + for ( TInt ii = 0; ii < KRawHashLength; ii++ ) + { + TBuf8<2> scratch; + scratch.Zero(); + scratch.Format(formatStr, hash[ii]); + aHash.Append(scratch); + } + } + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::GenerateCNonce() +// ----------------------------------------------------------------------------- +// +void C3GPPBootstrapHttpHandler::GenerateCNonce(TDes8& aNonce) + { + // The purpose of the client nonce is to protect aextst 'chosen + // plaintext' attacks where a hostile server tricks the client + // into supplying a password using a specific server nonce that + // allows an (as yet undiscovered) flaw in MD5 to recover the + // password. As such the only important thing about client nonces + // is that they change and aren't predictable. See section 4.9 of + // RFC2616 + + TTime time; + time.UniversalTime(); + TInt64 randomNumber = Math::Rand(iSeed); + randomNumber <<= KNumber32; + randomNumber += Math::Rand(iSeed); + TBuf8 key; + key.Zero(); + key.AppendNum(time.Int64(), EHex); + key.Append(KColon); + key.AppendNum(randomNumber, EHex); + + Hash(key, aNonce); + } + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::CheckRspAuthL() +// ----------------------------------------------------------------------------- +// +TInt C3GPPBootstrapHttpHandler::CheckRspAuthL(RHTTPTransaction aTransaction) + { + RStringF wwwAuthInfoHeader = aTransaction.Session().StringPool().OpenFStringL(KHTTPAuthInfo); + RHTTPHeaders headers(aTransaction.Response().GetHeaderCollection()); + + THTTPHdrVal rspAuthVal; + + TInt retVal = headers.FieldPartsL(wwwAuthInfoHeader); + + TInt error = headers.GetField(wwwAuthInfoHeader, 0, rspAuthVal); + + if(error != KErrNone) + { + wwwAuthInfoHeader.Close(); + return error; + } + wwwAuthInfoHeader.Close(); + return KErrNone; + } + + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::DigestCalcL() +// ----------------------------------------------------------------------------- +// +void C3GPPBootstrapHttpHandler::DigestCalcL( + const TDesC8& aHentity, + TDes8& aResult ) + { + TInt stringToHashLength = iNonce.DesC().Length() + + KNumber8 + // auth-int length + KNumber3 * KHashLength + KNumber8 + iPassword.DesC().Length() + KNumber5; + HBufC8* stringToHash = HBufC8::NewMaxLC(stringToHashLength); + TPtr8 stringMod = stringToHash->Des(); + stringMod.Zero(); + HAOneL(iUsername, iPassword, iRealm, stringMod); + stringMod.Append(':'); + stringMod.Append(iNonce.DesC()); + stringMod.Append(KNCVal_2); + stringMod.Append(iCnonce.DesC()); + stringMod.Append(':'); + stringMod.Append(KAuthInt); + stringMod.Append(':'); + TBuf8 hash; + HATwoL(iMethod, iUri, aHentity,hash); + GBA_TRACE_DEBUG_BINARY(stringMod); + stringMod.Append(hash); + GBA_TRACE_DEBUG(stringMod); + Hash(*stringToHash, aResult); + CleanupStack::PopAndDestroy(stringToHash); + }; + +// ----------------------------------------------------------------------------- +// C3GPPBootstrapHttpHandler::GetResponse() +// ----------------------------------------------------------------------------- +// + HBufC8* C3GPPBootstrapHttpHandler::GetResponse() + { + return iResponse->Alloc(); + }; + +//EOF