realtimenetprots/sipfw/SIP/SIPSec/DigestPlugin/src/CSIPSecDigestPlugin.cpp
changeset 0 307788aac0a8
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/SIPSec/DigestPlugin/src/CSIPSecDigestPlugin.cpp	Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,526 @@
+// 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          : CSIPSecDigestPlugin.cpp
+// Part of       : SIPDigestPlugin
+// Version       : SIP/6.0
+//
+
+
+
+#include "SipLogs.h"
+#include "siprequest.h"
+#include "sipresponse.h"
+#include "sipauthorizationheader.h"
+#include "sipauthenticationinfoheader.h"
+#include "sipsecurityclientheader.h"
+#include "sipsecurityserverheader.h"
+#include "sipsecurityverifyheader.h"
+#include "sipstrings.h"
+#include "sipstrconsts.h"
+#include "SipSecUtils.h"
+#include "tsipsecmechanisminitparams.h"
+#include "CSIPSecDigestPlugin.h"
+#include "sipsecdigestcontext.h"
+#include "sipsecdigestcache.h"
+#include "CSIPSecUserRecord.h"
+#include "sipprivatecrkeys.h"
+#include <centralrepository.h>
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::NewL
+// -----------------------------------------------------------------------------
+//
+CSIPSecDigestPlugin* CSIPSecDigestPlugin::NewL( TAny* aInitParams ) 
+    {
+    __ASSERT_ALWAYS( aInitParams, User::Leave( KErrArgument ) );
+    				 
+    TSIPSecMechanismInitParams* initParams =
+    	static_cast<TSIPSecMechanismInitParams*>( aInitParams );
+	CSIPSecDigestPlugin* self =
+		new ( ELeave ) CSIPSecDigestPlugin( initParams->iEngineContext );
+	CleanupStack::PushL( self );
+	self->ConstructL( initParams->iTimer );
+	CleanupStack::Pop( self );
+	return self;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CSIPSecDigestPlugin::ConstructL( MTimerManager& aTimerMgr )
+    {
+    iDigestMechanism = CSIPSecDigest::NewL();
+	iCache = CSIPSecDigestCache::NewL( aTimerMgr );
+
+	CRepository* repository = CRepository::NewLC( KCRUidSIP );
+	TInt emptyResponseAfterSqnFailure( 0 );
+	if ( repository->Get(KSIPSendEmptyResponseParameterAfterSqnFailure,
+		 				 emptyResponseAfterSqnFailure ) == KErrNone &&
+		 emptyResponseAfterSqnFailure )
+		{
+		iSendEmptyResponseParameterAfterSqnFailure = ETrue;
+		}
+	CleanupStack::PopAndDestroy( repository );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::CSIPSecDigestPlugin
+// -----------------------------------------------------------------------------
+//
+CSIPSecDigestPlugin::CSIPSecDigestPlugin( MSIPSecEngineContext& aEngineContext )
+  : iEngineContext( aEngineContext )
+    {
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::~CSIPSecDigestPlugin
+// -----------------------------------------------------------------------------
+//
+CSIPSecDigestPlugin::~CSIPSecDigestPlugin()
+    {
+    delete iDigestMechanism;
+    delete iCache;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::Name
+// -----------------------------------------------------------------------------
+//
+const TDesC8& CSIPSecDigestPlugin::Name() const
+    {
+    return iDigestMechanism->Name();
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::InitializeSecurityClientL
+// -----------------------------------------------------------------------------
+//
+void CSIPSecDigestPlugin::InitializeSecurityClientL(
+	CSIPSecurityClientHeader& aSecurityClient )
+    {
+    aSecurityClient.SetMechanismNameL( Name() );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::ProcessSecurityVerifyL
+// Find Security-Server and Security-Verify with a matching mechanism, and
+// process them.
+// A2 is computed from all Sec-Server headers, e.g.
+// "Security-Server:ipsec-ike;q=0.1,tls;q=0.2". I.e. "Security-Server" followed
+// by all mechanisms and parameters. Resulting digest-verify parameter is put to
+// the Security-Verify header that has "digest" mechanism.
+// -----------------------------------------------------------------------------
+//
+void CSIPSecDigestPlugin::ProcessSecurityVerifyL(
+	TSIPTransportParams& /*aTransportParams*/,
+	CSIPRequest& aRequest,
+	TInetAddr& /*aNextHop*/,
+	const CUri8& aRemoteTarget,
+	const TDesC8& aOutboundProxy,
+	MSIPSecUser* aUser,
+	TRegistrationId aRegistrationId,
+	RPointerArray<CSIPSecurityServerHeader>& aSecurityServer,        
+	RPointerArray<CSIPSecurityVerifyHeader>& aSecurityVerify )
+    {
+    __ASSERT_ALWAYS( aUser, User::Leave( KErrArgument ) );
+
+	CSIPSecurityServerHeader* secServer = NULL;
+	for ( TInt i = 0; i < aSecurityServer.Count() && !secServer; ++i )
+		{
+		if ( aSecurityServer[ i ]->MechanismName().CompareF( Name() ) == 0 )
+            {
+            secServer = aSecurityServer[ i ];
+            }
+		}
+	__ASSERT_ALWAYS( secServer, User::Leave( KErrArgument ) );
+
+	CSIPSecurityVerifyHeader* secVerify = NULL;
+	for ( TInt j = 0; j < aSecurityVerify.Count() && !secVerify; ++j )
+		{
+		if ( aSecurityVerify[ j ]->MechanismName().CompareF( Name() ) == 0 )
+            {
+            secVerify = aSecurityVerify[ j ];
+            }        
+		}
+	__ASSERT_ALWAYS( secVerify, User::Leave( KErrArgument ) );
+
+    iDigestMechanism->InitializeL( *secServer );
+    TSIPSecPluginCtxVerify secVerifyContext( *this, aRemoteTarget,
+    										 aOutboundProxy, aRequest,
+                                             *secVerify, aSecurityServer, 
+                                             *aUser, aRegistrationId );
+    TSIPSecDigestCacheIterator cacheIter( secVerifyContext );
+    iCache->InitializeIterator( cacheIter );
+
+    CSIPSecDigestCacheEntry* entry = NULL;
+	while ( ( entry = cacheIter.Next() ) != NULL )
+		{
+		if ( entry->Match( secVerifyContext ) )
+		    {
+		    entry->HandleL( secVerifyContext );
+    		return;
+		    }
+		}
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::AddSecurityParamsL
+// Nothing is done for ACK.
+// -----------------------------------------------------------------------------
+//
+void CSIPSecDigestPlugin::AddSecurityParamsL(
+	TSIPTransportParams& /*aTransportParams*/,
+	CSIPRequest& aRequest,
+	TRegistrationId aRegistrationId,
+	TTransactionId aTransactionId,
+	TInetAddr& /*aNextHop*/,
+	const CUri8& aRemoteTarget,
+	const TDesC8& aOutboundProxy,
+	MSIPSecUser* aUser )
+	{
+	__ASSERT_ALWAYS( aUser, User::Leave( KErrArgument ) );	
+
+	if ( SipSecUtils::Match( SipStrConsts::EAck, aRequest.Method() ) )
+		{
+		return;
+		}
+
+	TSIPSecPluginCtxRequest requestContext( *this,
+											aRemoteTarget,
+											aOutboundProxy,
+											aRequest,
+											*aUser,
+											aRegistrationId,
+											aTransactionId );
+	TSIPSecDigestCacheIterator cacheIter( requestContext );
+	iCache->InitializeIterator( cacheIter );
+
+    // Cleanup
+    CSIPAuthorizationHeader* nonDigestHeader = PrepareRequestL( aRequest );
+
+	CSIPSecDigestCacheEntry* entry = NULL;
+	while ( ( entry = cacheIter.Next() ) != NULL )
+		{
+		if ( nonDigestHeader &&
+		     entry->Type( requestContext ) == CSIPSecDigest::EEndPoint )
+		    {
+		    User::LeaveIfError( aRequest.RemoveHeader( nonDigestHeader ) );
+		    delete nonDigestHeader;
+		    nonDigestHeader = NULL;
+		    }
+
+		entry->UpdateL( requestContext );
+		}
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::PrepareRequestL
+// Remove all Proxy-Authorization headers. Remove Authorization headers
+// selectively, based on response value.
+// -----------------------------------------------------------------------------
+//
+CSIPAuthorizationHeader*
+CSIPSecDigestPlugin::PrepareRequestL( CSIPRequest& aRequest ) const
+    {
+    aRequest.DeleteHeaders(
+    	SIPStrings::StringF( SipStrConsts::EProxyAuthorizationHeader ) );
+
+    const RStringF auth =
+    	SIPStrings::StringF( SipStrConsts::EAuthorizationHeader );
+
+	CSIPAuthorizationHeader* nonDigestHeader = NULL;
+    if ( aRequest.HeaderCount( auth ) > 0 )
+        {
+    	TSglQueIter<CSIPHeaderBase> authHeaders = aRequest.Headers( auth );
+
+        CSIPAuthorizationHeader* header = NULL;
+        while ( ( header =
+                  static_cast<CSIPAuthorizationHeader*>( authHeaders++ ) )
+                  != NULL )
+            {
+            if ( header->DesParamValue( SIPStrings::StringF(
+            	SipStrConsts::EResponse ) ).Length() == 0 )
+                {
+                nonDigestHeader = header;
+                }
+            else
+                {
+                // This is created by digest plugin -> can be deleted now
+    		    User::LeaveIfError( aRequest.RemoveHeader( header ) );
+    		    delete header;
+    		    header = NULL;
+                }
+            }
+        }
+
+    return nonDigestHeader;
+    }    
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::ResponseReceivedL
+// If 2xx, try to update with authentication info.
+// -----------------------------------------------------------------------------
+//
+TBool CSIPSecDigestPlugin::ResponseReceivedL(
+	TSIPTransportParams& /*aTransportParams*/,
+	CSIPResponse& aResponse,
+	CSIPRequest& aRequest,
+	TRegistrationId aRegistrationId,
+	TTransactionId aTransactionId,
+	TInetAddr& /*aNextHop*/,
+	const CUri8& aRemoteTarget,
+	const TDesC8& aOutboundProxy,
+	MSIPSecUser* aUser,
+	MSIPSecSecurityMechanismObserver& aObserver )
+    {
+    __ASSERT_ALWAYS( aUser, User::Leave( KErrArgument ) );
+
+	User::LeaveIfError( iCache->CountResponses( aResponse,
+		aRequest,
+		aTransactionId,
+		iDigestMechanism->Algorithm() ) );
+
+    if ( aResponse.ResponseCode() == 401 || // WWW Authorization
+         aResponse.ResponseCode() == 407 || // Proxy Authorization
+         aResponse.ResponseCode() == 494 )  // Security Agreement
+   		{
+        TSIPSecPluginCtxResponse respContext( *this,
+    										  aRemoteTarget,
+    										  aOutboundProxy,
+    										  aResponse,
+										      *iCache,
+										      aObserver,
+										      *aUser,
+										      aRegistrationId,
+										      aTransactionId );
+		return iDigestMechanism->UpdateCacheL( respContext );
+        }
+
+	CSIPAuthenticationInfoHeader* authInfo( NULL );
+    if ( ( aResponse.Type() == CSIPResponse::E2XX ) &&
+         ( authInfo = AuthenticationInfo( aResponse ) ) != NULL )
+        {
+        TSIPSecPluginCtxInfo authInfoCtx( *this,
+        								  aRemoteTarget,
+        								  aOutboundProxy,
+        								  aResponse,
+        								  *authInfo,
+									      *iCache,
+									      aObserver,
+									      *aUser,
+									      aRegistrationId );
+    	TSIPSecDigestCacheIterator cacheIterator( authInfoCtx );
+    	iCache->InitializeIterator( cacheIterator );
+		CSIPSecDigestCacheEntry* entry( NULL );
+
+		while ( ( entry = cacheIterator.Next() ) != NULL )
+			{
+			// Let each matching cache entry handle the Authentication-Info
+			entry->HandleL( authInfoCtx );
+			}
+        }
+    return EFalse;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::IsServerInitiatedSecAgreeAllowed
+// -----------------------------------------------------------------------------
+//
+TBool CSIPSecDigestPlugin::IsServerInitiatedSecAgreeAllowed() const
+	{
+	return ETrue;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::ParametersUpdatedL
+// -----------------------------------------------------------------------------
+//
+TBool CSIPSecDigestPlugin::ParametersUpdatedL( MSIPSecUser* /*aUser*/ )
+	{
+	return EFalse;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::CancelPendingOperations
+// -----------------------------------------------------------------------------
+//
+void CSIPSecDigestPlugin::CancelPendingOperations(
+	MSIPSecSecurityMechanismObserver* aObserver )
+    {
+	iCache->CancelPendingOperations( aObserver );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::ClearCache
+// -----------------------------------------------------------------------------
+//
+void CSIPSecDigestPlugin::ClearCache( MSIPSecUser* aUser )
+    {
+    if ( aUser )
+    	{
+    	iCache->ClearCache( *aUser );	
+    	}
+	iCache->CleanObservers();
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::SetCredentialsL
+// Cache can have just one record for a realm and transaction id pair.
+// SIPSec users with PassOnlyRealmsToUser == ETrue set aTransactionId to value
+// KEmptyTransactionId. Correct operation is not guaranteed if several of them
+// use the same realm.
+//
+// This function will eventually be removed and clients start to use
+// SetCredentialsL( const MSIPSecUser& .. ) instead.
+// -----------------------------------------------------------------------------
+//
+void CSIPSecDigestPlugin::SetCredentialsL( TTransactionId aTransactionId,
+                                           const TDesC8& aRealm,
+                                           const TDesC8& aOutboundProxy, 
+                                           const TDesC8& aUserName,
+                                           const TDesC8& aPassword )
+	{
+	__ASSERT_ALWAYS( aRealm.Length() > 0, User::Leave( KErrArgument ) );
+
+	CSIPSecUserRecord* record = iCache->SearchRecord( aRealm, aTransactionId );
+	__ASSERT_ALWAYS( record != NULL, User::Leave( KErrNotFound ) );
+
+	SetCredentialsToRecordL( *record, aOutboundProxy, aUserName, aPassword );
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::SetCredentialsL
+// -----------------------------------------------------------------------------
+//
+void CSIPSecDigestPlugin::SetCredentialsL( const MSIPSecUser& aUser,
+                                           const TDesC8& aRealm,
+                                           const TDesC8& aOutboundProxy, 
+                                           const TDesC8& aUserName,
+                                           const TDesC8& aPassword )
+	{
+	__ASSERT_ALWAYS( aRealm.Length() > 0, User::Leave( KErrArgument ) );	
+
+	CSIPSecUserRecord* record = iCache->SearchRecord( aRealm, aUser );
+	__ASSERT_ALWAYS( record != NULL, User::Leave( KErrNotFound ) );
+
+	SetCredentialsToRecordL( *record, aOutboundProxy, aUserName, aPassword );
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::SetCredentialsToRecordL
+// -----------------------------------------------------------------------------
+//
+void CSIPSecDigestPlugin::SetCredentialsToRecordL( CSIPSecUserRecord& aRecord,
+												   const TDesC8& aOutboundProxy,
+                                           		   const TDesC8& aUserName,
+                                           		   const TDesC8& aPassword )
+	{
+	TBool valid = aRecord.SetUserCredentialsL( aUserName, aPassword );
+	if ( valid )
+	    {
+		aRecord.SetOutboundProxyL( aOutboundProxy );
+
+    	TSIPSecDigestCacheIterator cacheIterator;
+    	iCache->InitializeIterator( cacheIterator );
+
+		CSIPSecDigestCacheEntry* entry( NULL );
+		while ( ( entry = cacheIterator.Next() ) != NULL )
+			{
+			entry->UpdateL( aRecord );
+			}
+	    }
+
+	aRecord.Updated();
+
+	if ( !valid )
+		{
+		iCache->ClearCache( aRecord, EFalse );
+		}
+
+    iCache->CleanObservers();
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::IgnoreChallenge
+// If aTransactionId is KEmptyTransactionId removes cache entries with
+// PassOnlyRealmsToUser == ETrue.
+// -----------------------------------------------------------------------------
+//
+TInt CSIPSecDigestPlugin::IgnoreChallenge( TTransactionId aTransactionId,
+                                           const TDesC8& aRealm,
+                                           const MSIPSecUser* aTrustedUser )
+	{
+	return iCache->Cancel( aTransactionId, aRealm, aTrustedUser );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::RemoveCredentials
+// Only remove cache entries for which PassOnlyRealmsToUser == ETrue.
+// -----------------------------------------------------------------------------
+//
+TInt CSIPSecDigestPlugin::RemoveCredentials( const TDesC8& aRealm )    
+    {
+    return iCache->Remove( aRealm );
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::EngineContext
+// -----------------------------------------------------------------------------
+//
+MSIPSecEngineContext& CSIPSecDigestPlugin::EngineContext()
+    {
+    return iEngineContext;
+    }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::EmptyResponseAfterSqnFailure
+// -----------------------------------------------------------------------------
+//
+TBool CSIPSecDigestPlugin::EmptyResponseAfterSqnFailure() const
+	{
+	return iSendEmptyResponseParameterAfterSqnFailure;
+	}
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestPlugin::AuthenticationInfo
+// -----------------------------------------------------------------------------
+//
+CSIPAuthenticationInfoHeader*
+CSIPSecDigestPlugin::AuthenticationInfo( CSIPResponse& aResponse ) const
+    {
+    CSIPAuthenticationInfoHeader* header( NULL );
+
+    if ( aResponse.Type() == CSIPResponse::E2XX )
+        {
+        const RStringF authInfo =
+    		SIPStrings::StringF( SipStrConsts::EAuthenticationInfoHeader );
+	    TInt count = aResponse.HeaderCount( authInfo );
+	    if ( count > 0 )
+	        {
+	    	TSglQueIter< CSIPHeaderBase > headers =
+	    		aResponse.Headers( authInfo );
+    		for ( TInt i = 0; i < count; i++ )
+                {
+                header =
+                	static_cast< CSIPAuthenticationInfoHeader* >( headers++ );
+                }
+	        }
+        }
+
+    return header;
+    }