realtimenetprots/sipfw/SIP/SIPSec/DigestPlugin/src/CSIPSecCredentials.cpp
changeset 0 307788aac0a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/SIPSec/DigestPlugin/src/CSIPSecCredentials.cpp	Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,453 @@
+// Copyright (c) 2008-2009 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:
+// Name          : CSIPSecCredentials.cpp
+// Part of       : SIPDigestPlugin
+// Version       : SIP/6.0
+//
+
+
+
+#include "CSIPSecCredentials.h"
+#include "CSIPSecChallenge.h"
+#include "MSIPSecAlgorithm.h"
+#include "sipsecdigestcontext.h"
+#include "CSIPSecUserRecord.h"
+#include "MSIPSecUser.h"
+#include "SipLogs.h"
+#include "siprequest.h"
+#include "uricontainer.h"
+#include "sipauthorizationheader.h"
+#include "sipproxyauthorizationheader.h"
+#include "sipauthenticateheaderbase.h"
+#include "sipauthenticationinfoheader.h"
+#include "sipstrings.h"
+#include "sipstrconsts.h"
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::NewL
+// -----------------------------------------------------------------------------
+//
+CSIPSecCredentials*
+CSIPSecCredentials::NewL( CSIPSecChallenge* aChallenge, 
+                          CSIPSecDigest& aMechanism,
+			              TSIPSecPluginCtxResponse& aContext )
+    {
+	__ASSERT_ALWAYS( aChallenge, User::Leave( KErrArgument ) );
+
+	const MSIPSecUser* sipSecUser = aChallenge->Owner();
+	if ( !sipSecUser )
+        {
+        sipSecUser = &aContext.SIPSecUser();
+        }
+
+    CSIPSecCredentials* self = new ( ELeave ) CSIPSecCredentials( aMechanism,											 					  
+																  *sipSecUser );
+	CleanupStack::PushL( self );
+	self->ConstructL( aChallenge, aContext );
+	CleanupStack::Pop( self );
+	return self;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::CSIPSecCredentials
+// -----------------------------------------------------------------------------
+//
+CSIPSecCredentials::CSIPSecCredentials( CSIPSecDigest& aMechanism,
+										const MSIPSecUser& aUser ) :
+    CSIPSecDigestCacheEntry( aUser ),
+    iMechanism( aMechanism )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecChallenge::~CSIPSecCredentials
+// -----------------------------------------------------------------------------
+//
+CSIPSecCredentials::~CSIPSecCredentials()
+    {
+    delete iChallenge;
+    delete iAuthorizationHeader;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::ConstructL( CSIPSecChallenge* aChallenge,
+									 TSIPSecPluginCtxResponse& aContext )
+    {
+    __ASSERT_ALWAYS( aChallenge, User::Leave( KErrArgument ) );
+
+    CSIPSecDigestCacheEntry::ConstructL( ChallengeType( *aChallenge,
+    													&aContext ),
+										 aContext.RemoteTarget() );
+    CreateContentL( *aChallenge );
+	TSIPSecDigestCtxSetup ctx( *this, aContext.TransactionId(), &aContext );
+    aChallenge->PopulateCredentialsL( ctx );
+
+	// Take ownership of aChallenge when leave can't occur any more
+	iChallenge = aChallenge;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::UpdateL
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::UpdateL( CSIPSecUserRecord& aUserCredentials )
+    {
+    // If user credentials update is for this entry
+    if ( HoldsUserData( aUserCredentials ) && !UserData().IsUpdating() )
+        {
+        TSIPSecDigestCtxSetup ctx( *this, aUserCredentials.TransactionId() );
+		TBool askCredentials( EFalse );
+
+        // As credentials were obtained, DigestUpdateL must not indicate "wait".        
+        __ASSERT_ALWAYS( !DigestUpdateL( ctx, askCredentials ),
+        				 User::Leave( KErrGeneral ) );
+		__ASSERT_ALWAYS( !askCredentials, User::Leave( KErrGeneral ) );
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::UpdateL
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::UpdateL( TSIPSecPluginCtxRequest& aContext )
+    {
+	__SIP_LOG( "SIPSecCred:UpdateL(ctx)" )
+
+	if ( UserData().IsValid() )
+		{
+		__SIP_LOG( "user data is valid" )
+
+		TSIPSecDigestCtxProcess ctx( *this, &aContext );
+	    UpdateContentL( ctx );
+
+	    iChallenge->Algorithm().ProcessRequestL( ctx );
+
+	    // Add a (Proxy-)Authorization header
+		aContext.SIPRequest().AddHeaderL( Content() );
+		}
+
+	__SIP_LOG( "SIPSecCred:UpdateL(ctx) end" )
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::HandleL
+// Called for each matching cache entry. They store the new nonce.
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::HandleL( TSIPSecPluginCtxInfo& aAuthenticationInfo )
+    {
+    RStringF cnonce = SIPStrings::StringF( SipStrConsts::ECNonce );
+    RStringF nc 	= SIPStrings::StringF( SipStrConsts::ENonceCount );
+    RStringF qop 	= SIPStrings::StringF( SipStrConsts::EQop );
+    CSIPAuthenticationInfoHeader& authInfo =
+    	aAuthenticationInfo.AuthenticationInfoHeader();
+
+    if ( Content().ParamValue( qop ) 	   == authInfo.Value( qop ) &&
+    	 Content().DesParamValue( cnonce ) == authInfo.DesValue( cnonce ) &&
+    	 Content().ParamValue( nc )        == authInfo.Value( nc ) )
+        {
+		const TDesC8& responseAuth = authInfo.DesValue( SIPStrings::StringF(
+			SipStrConsts::EResponseAuth ) );
+        if ( responseAuth.Length() > 0 )
+            {
+            TBuf8< KSIPSecDigestHashHexSize > response;
+            TSIPSecDigestAuthInfoContext ctx( *this,
+            								  response,
+            								  &aAuthenticationInfo );
+            // Process the response auth
+            iChallenge->Algorithm().ProcessRequestL( ctx );
+
+            if ( responseAuth.Compare( response ) != 0 )
+                {
+                User::Leave( KErrPermissionDenied );
+                }
+            }
+
+        const TDesC8& nextNonce = authInfo.DesValue(
+        	SIPStrings::StringF( SipStrConsts::ENextNonce ) );
+        if ( nextNonce.Length() > 0 )
+            {
+		    RStringF nonce = SIPStrings::StringF( SipStrConsts::ENonce );			              	    
+            Content().SetDesParamL( nonce, nextNonce );
+            iChallenge->Content().SetDesParamL( nonce, nextNonce );
+            SetNonceCountL( 0 );
+            }
+        }
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::HandleL
+// Process Security-Verify header
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::HandleL( TSIPSecPluginCtxVerify& aSecurityVerifyCtx )
+    {
+    HBufC8* requestURI =
+    	aSecurityVerifyCtx.SIPRequest().RequestURI()->ToTextL();
+    CleanupStack::PushL( requestURI );
+
+	TSIPSecDigestVerifyContext ctx( *this, *requestURI, &aSecurityVerifyCtx );
+    iChallenge->Algorithm().ProcessRequestL( ctx );
+
+    CleanupStack::PopAndDestroy( requestURI );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::DigestUpdateL
+// Generate CNonce if it doesn't exist.
+// -----------------------------------------------------------------------------
+//
+TBool CSIPSecCredentials::DigestUpdateL( TSIPSecDigestCtxSetup& aContext,
+										 TBool& aAskCredentials )
+    {
+    UpdateContentL( aContext );
+
+	if ( iChallenge->HasQop() &&
+    	 !Content().HasParam( SIPStrings::StringF( SipStrConsts::ECNonce ) ) )
+        {
+        iChallenge->Algorithm().GenerateCNonceL( aContext );
+        }
+    return iChallenge->Algorithm().ProcessResponseL( aContext,
+    												 aAskCredentials );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::ChallengeType
+// -----------------------------------------------------------------------------
+//
+CSIPSecDigest::TChallengeType
+CSIPSecCredentials::ChallengeType( const CSIPSecChallenge& aChallenge,
+    							   const TSIPSecPluginContext* aContext ) const
+    {
+    CSIPSecDigest::TChallengeType type = aChallenge.Type();
+    TBool ignoreOutboundProxy( aContext &&
+                               aContext->OutboundProxy().Length() == 0 );
+
+    if ( type == CSIPSecDigest::EProxy &&
+         !ignoreOutboundProxy &&
+    	 iUserCredentials &&
+    	 iUserCredentials->OutboundProxy().Length() > 0 )
+        {
+        type = CSIPSecDigest::EOutboundProxy;
+        }
+
+    return type;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::Type
+// -----------------------------------------------------------------------------
+//
+CSIPSecDigest::TChallengeType CSIPSecCredentials::Type() const
+    {    
+    return ChallengeType( *iChallenge );
+    }
+    
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::Type
+// -----------------------------------------------------------------------------
+//
+CSIPSecDigest::TChallengeType CSIPSecCredentials::Type(
+    const TSIPSecPluginContext& aContext ) const
+    {    
+    return ChallengeType( *iChallenge, &aContext );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::DoesMatch
+// aChallenge::Owner() is always NULL at this phase.
+// -----------------------------------------------------------------------------
+//
+TBool CSIPSecCredentials::DoesMatch( const CSIPSecChallenge& aChallenge,
+									 const MSIPSecUser& aUser,
+									 TRegistrationId aRegistrationId ) const
+	{
+	return aChallenge.Type() == iChallenge->Type() &&
+		   ( aChallenge.Realm().Compare( iChallenge->Realm() ) == 0 ) &&
+		   iUserCredentials &&
+		   iUserCredentials->CompareUser( aUser, aRegistrationId );
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::ChallengeReceived
+// If "stale=true", retry with new nonce. Username and password are valid.
+// Otherwise ask username and password. PopulateCredentialsL later copies nonce
+// to CSIPSecCredentials::iAuthorizationHeader.
+// -----------------------------------------------------------------------------
+//
+TBool CSIPSecCredentials::ChallengeReceived( CSIPSecChallenge& aNewChallenge )
+    {
+	RStringF stale = SIPStrings::StringF( SipStrConsts::EStale );	
+
+    TBool hasStale = aNewChallenge.Content().HasParam( stale );    
+	_LIT8( KSIPSecStaleTrue, "true" );
+    TBool isStale = hasStale &&
+		aNewChallenge.Content().ParamValue( stale ).DesC().CompareF(
+			KSIPSecStaleTrue ) == 0;
+    TBool hasAuts =
+    	Content().HasParam( SIPStrings::StringF( SipStrConsts::EAuts ) );
+	TBool isAKA = aNewChallenge.Algorithm().AlgorithmName() ==
+		 				SIPStrings::StringF( SipStrConsts::EAKAv1MD5 );
+
+    if ( !isStale || hasAuts || isAKA )
+        {
+        // Credentials are wrong
+        UserData().Invalidate( CSIPSecUserRecord::ENoState );
+
+		RStringF nonce = SIPStrings::StringF( SipStrConsts::ENonce );
+        if ( aNewChallenge.Content().DesParamValue( nonce ) !=
+        	 Content().DesParamValue( nonce ) )
+        	{
+        	// Server gave a new nonce, clear old username and password so even
+        	// if application gives same username and password, the request is
+        	// sent. As nonce is different, the result will be different.
+        	UserData().ClearUsernameAndPassword();
+        	}
+        }
+
+    aNewChallenge.SetOwner( &iUser );
+
+	// Remove unless SIPSec user asked the response and waits credentials
+	TBool remove = iUser.PassOnlyRealmsToUser() || !UserData().IsUpdating();
+
+	__SIP_INT_LOG1( "SIPSecCred:ChallRecv remove", remove )
+	return remove;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::Mechanism
+// -----------------------------------------------------------------------------
+//
+CSIPSecDigest& CSIPSecCredentials::Mechanism() const
+    {
+    return iMechanism;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::Content
+// -----------------------------------------------------------------------------
+//
+CSIPAuthorizationHeaderBase& CSIPSecCredentials::Content()
+    {
+    return *iAuthorizationHeader;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::Challenge
+// -----------------------------------------------------------------------------
+//
+CSIPSecChallenge& CSIPSecCredentials::Challenge()
+    {
+    return *iChallenge;
+    }
+    
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::CreateContentL
+// Delete old AuthorizationHeader when can't leave, so it retains its old value
+// in case of leave. Otherwise crashes e.g. in CSIPSecCredentials::Content that
+// expects iAuthorizationHeader to exist.
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::CreateContentL( CSIPSecChallenge& aChallenge )
+    {
+	TBool hasType = aChallenge.Type() == CSIPSecDigest::EEndPoint || 
+                    aChallenge.Type() == CSIPSecDigest::EProxy;
+    __ASSERT_ALWAYS( hasType, User::Leave( KErrArgument ) );
+
+    // Create a new authorization header
+    CSIPAuthorizationHeaderBase* authorization( NULL );
+	RStringF digest = SIPStrings::Pool().OpenFStringL( KSIPSecDigestScheme );
+	CleanupClosePushL( digest );
+
+    if ( aChallenge.Type() == CSIPSecDigest::EEndPoint )
+        {
+        authorization = CSIPAuthorizationHeader::NewL( digest );
+        }
+    else
+        {
+        authorization = CSIPProxyAuthorizationHeader::NewL( digest );
+        }
+
+    CleanupStack::PopAndDestroy(); // digest
+    CleanupStack::PushL( authorization );
+
+	if ( aChallenge.HasQop() )
+		{
+		RStringF qop =
+			SIPStrings::Pool().OpenFStringL( aChallenge.QopDescriptor() );
+		CleanupClosePushL( qop );
+		authorization->SetParamL( SIPStrings::StringF( SipStrConsts::EQop ),
+													   qop );
+        CleanupStack::PopAndDestroy(); // qop
+		}
+
+	CleanupStack::Pop( authorization );
+	delete iAuthorizationHeader;
+    iAuthorizationHeader = authorization;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::UpdateContentL
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::UpdateContentL( TSIPSecDigestCtxSetup& aContext )
+    {
+    aContext.SetDesParamValueL( SipStrConsts::EUserName,
+    						 	aContext.UserData().UserName() );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::SetNonceCountL
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::SetNonceCountL( TUint aNonceCount )
+    {
+    iNonceCount = aNonceCount;
+
+    const TInt KNonceCountLength = 8;
+	TBuf8< KNonceCountLength > ncDescr;
+	ncDescr.NumFixedWidth( iNonceCount, EHex, KNonceCountLength );
+
+    TSIPSecDigestContext::SetParamValueL( Content(),
+    									  SipStrConsts::ENonceCount,
+    									  ncDescr );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::UpdateContentL
+// Increment nonce count and set Request-URI.
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::UpdateContentL( TSIPSecDigestCtxProcess& aContext )
+    {
+    if ( iChallenge->HasQop() )
+        {
+        SetNonceCountL( iNonceCount + 1 );
+        }
+
+    TSIPSecPluginCtxRequest& parent =
+    	static_cast<TSIPSecPluginCtxRequest&>( aContext.Parent() );
+    HBufC8* requestURI = parent.SIPRequest().RequestURI()->ToTextL();
+    CleanupStack::PushL( requestURI );
+
+    aContext.SetParamValueL( SipStrConsts::EUri, *requestURI );
+    CleanupStack::PopAndDestroy( requestURI );
+    }