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