--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/SIPSec/DigestPlugin/src/sipsecdigestcache.cpp Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,888 @@
+// 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 : sipsecdigestcache.cpp
+// Part of : SIPSec
+// Version : SIP/6.0
+//
+
+
+
+#include "SipLogs.h"
+#include "siperr.h"
+#include "SipAssert.h"
+#include "sipsecdigestcache.h"
+#include "CSIPSecDigestCacheEntry.h"
+#include "CSIPSecDigestObserver.h"
+#include "CSIPSecUserRecord.h"
+#include "CSIPSecSIMRecord.h"
+#include "CSIPSecCredentials.h"
+#include "CSIPSecChallengeAKA.h"
+#include "RSIPSecChallengeResolver.h"
+#include "MSIPSecUser.h"
+#include "sipstrings.h"
+#include "sipstrconsts.h"
+#include "siprequest.h"
+#include "sipresponse.h"
+#include "sipsecdigestcontext.h"
+#include "sipauthenticateheaderbase.h"
+
+
+const TInt TSIPSecDigestCacheEntryIterator::iSIPSecOffset =
+ _FOFF( TSIPSecDigestCacheEntryIterator, iLink );
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::NewL
+// ----------------------------------------------------------------------------
+//
+CSIPSecDigestCache* CSIPSecDigestCache::NewL( MTimerManager& aTimerManager )
+ {
+ CSIPSecDigestCache* self = NewLC( aTimerManager );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::NewLC
+// ----------------------------------------------------------------------------
+//
+CSIPSecDigestCache* CSIPSecDigestCache::NewLC( MTimerManager& aTimerManager )
+ {
+ CSIPSecDigestCache* self =
+ new ( ELeave ) CSIPSecDigestCache( aTimerManager );
+ CleanupStack::PushL( self );
+ return self;
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache
+// ----------------------------------------------------------------------------
+//
+CSIPSecDigestCache::CSIPSecDigestCache( MTimerManager& aTimerManager ) :
+ iProxyList( CSIPSecDigestCacheEntry::iSIPSecOffset ),
+ iProxyListIter( iProxyList ),
+ iEndpointList( CSIPSecDigestCacheEntry::iSIPSecOffset ),
+ iEndpointListIter( iEndpointList ),
+ iCredentialsList( CSIPSecUserRecord::iSIPSecOffset ),
+ iCredentialsListIter( iCredentialsList ),
+#ifdef CPPUNIT_TEST
+ // Use granularity 1 to make each append operation to allocate memory.
+ iDigestObservers( 1 ),
+#endif
+ iTimerManager( aTimerManager )
+ {
+ }
+
+// ----------------------------------------------------------------------------
+// ~CSIPSecDigestCache
+// ----------------------------------------------------------------------------
+//
+CSIPSecDigestCache::~CSIPSecDigestCache()
+ {
+ RemoveAllEntries();
+ RemoveAllCredentials();
+ iDigestObservers.ResetAndDestroy();
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::InitializeIterator
+// ----------------------------------------------------------------------------
+//
+void
+CSIPSecDigestCache::InitializeIterator( TSIPSecDigestCacheIterator& aIterator )
+ {
+ iProxyListIter.SetToFirst();
+ iEndpointListIter.SetToFirst();
+
+ aIterator.iList.Reset();
+ aIterator.iList.AddLast( iProxyListIter );
+ aIterator.iList.AddLast( iEndpointListIter );
+ aIterator.iListIterator.SetToFirst();
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::AddEntry
+// ----------------------------------------------------------------------------
+//
+void CSIPSecDigestCache::AddEntry( CSIPSecDigestCacheEntry* aCacheEntry )
+ {
+ __SIP_ASSERT_RETURN( aCacheEntry, KErrArgument );
+ __SIP_ASSERT_RETURN( !IsEntryInCache( *aCacheEntry ), KErrAlreadyExists );
+
+ SelectCache( *aCacheEntry ).AddLast( *aCacheEntry );
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::RemoveEntry
+// ----------------------------------------------------------------------------
+//
+void CSIPSecDigestCache::RemoveEntry( CSIPSecDigestCacheEntry& aCacheEntry )
+ {
+ __SIP_ASSERT_RETURN( IsEntryInCache( aCacheEntry ), KErrNotFound );
+
+ aCacheEntry.UserData().CredentialsDetach();
+ SelectCache( aCacheEntry ).Remove( aCacheEntry );
+ delete &aCacheEntry;
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::RemoveCacheEntry
+// ----------------------------------------------------------------------------
+//
+TBool CSIPSecDigestCache::RemoveCacheEntry( CSIPSecDigestCacheEntry& aEntry,
+ const MSIPSecUser& aUser )
+ {
+ CSIPSecUserRecord& record = aEntry.UserData();
+ RemoveEntry( aEntry );
+ if ( record.CredentialsAttached() )
+ {
+ ChangeRecordUserIfNeeded( record, aUser );
+ return EFalse;
+ }
+
+ __SIP_LOG( "SIPSecDigestCache:RemoveCacheEntry record not used" )
+ __SIP_ASSERT_RETURN_VALUE( IsCredentialsInList( record ), KErrNotFound );
+ iCredentialsList.Remove( record );
+ delete &record;
+ return ETrue;
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::IsEntryInCache
+// ----------------------------------------------------------------------------
+//
+TBool CSIPSecDigestCache::IsEntryInCache( CSIPSecDigestCacheEntry& aCacheEntry )
+ {
+ TSIPSecDigestCacheEntryIterator entryIterator =
+ TSIPSecDigestCacheEntryIterator( SelectCache( aCacheEntry ) );
+
+ CSIPSecDigestCacheEntry* entry( NULL );
+ TBool found( EFalse );
+ while ( !found && ( entry = entryIterator.Next() ) != NULL )
+ {
+ found = ( entry == &aCacheEntry );
+ }
+ return found;
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::SelectCache
+// ----------------------------------------------------------------------------
+//
+TSglQue< CSIPSecDigestCacheEntry >&
+CSIPSecDigestCache::SelectCache( const CSIPSecDigestCacheEntry& aCacheEntry )
+ {
+ if ( aCacheEntry.Type() == CSIPSecDigest::EEndPoint )
+ {
+ return iEndpointList;
+ }
+ return iProxyList;
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::AddUserCredentials
+// ----------------------------------------------------------------------------
+//
+void CSIPSecDigestCache::AddUserCredentials( CSIPSecUserRecord* aCredentials )
+ {
+ __SIP_ASSERT_RETURN( aCredentials, KErrArgument );
+ __SIP_ASSERT_RETURN( !IsCredentialsInList( *aCredentials ),
+ KErrAlreadyExists );
+ iCredentialsList.AddLast( *aCredentials );
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::SearchRecordForResponse
+// Cache can have only one entry with matching MSIPSecUser and realm.
+// ----------------------------------------------------------------------------
+//
+CSIPSecUserRecord*
+CSIPSecDigestCache::SearchRecordForResponse( const TDesC8& aRealm,
+ const MSIPSecUser& aUser,
+ TRegistrationId aRegistrationId )
+ {
+ __ASSERT_ALWAYS( aRealm.Length() > 0,
+ User::Panic( _L( "DigestCache:SearchRecForResp" ), KErrArgument ) );
+
+ CSIPSecUserRecord* record( NULL );
+ iCredentialsListIter.SetToFirst();
+ while ( ( record = iCredentialsListIter++ ) != NULL )
+ {
+ if ( record->IsSameRealm( aRealm ) &&
+ record->CompareUser( aUser, aRegistrationId ) )
+ {
+ return record;
+ }
+ }
+
+ return NULL;
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::SearchRecord
+// ----------------------------------------------------------------------------
+//
+CSIPSecUserRecord*
+CSIPSecDigestCache::SearchRecord( const TDesC8& aRealm,
+ TTransactionId aTransactionId )
+ {
+ __ASSERT_ALWAYS( aRealm.Length() > 0,
+ User::Panic( _L( "DigestCache:SearchRec(id)" ), KErrArgument ) );
+
+ CSIPSecUserRecord* record( NULL );
+ iCredentialsListIter.SetToFirst();
+ while ( ( record = iCredentialsListIter++ ) != NULL )
+ {
+ if ( record->IsSameRealm( aRealm ) &&
+ record->TransactionIdPassedToClient() == aTransactionId )
+ {
+ return record;
+ }
+ }
+
+ return NULL;
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::SearchRecord
+// ----------------------------------------------------------------------------
+//
+CSIPSecUserRecord* CSIPSecDigestCache::SearchRecord( const TDesC8& aRealm,
+ const MSIPSecUser& aUser )
+ {
+ __ASSERT_ALWAYS( aRealm.Length() > 0,
+ User::Panic( _L( "DigestCache:SearchRec(user)" ), KErrArgument ) );
+
+ CSIPSecUserRecord* record( NULL );
+ iCredentialsListIter.SetToFirst();
+ while ( ( record = iCredentialsListIter++ ) != NULL )
+ {
+ if ( record->IsSameRealm( aRealm ) && &aUser == &record->SIPSecUser() )
+ {
+ return record;
+ }
+ }
+
+ return NULL;
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::RemoveAllEntries
+// ----------------------------------------------------------------------------
+//
+void CSIPSecDigestCache::RemoveAllEntries()
+ {
+ RemoveAllEntriesFromList( iProxyList );
+ RemoveAllEntriesFromList( iEndpointList );
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::RemoveAllEntriesFromList
+// ----------------------------------------------------------------------------
+//
+void CSIPSecDigestCache::RemoveAllEntriesFromList(
+ TSglQue<CSIPSecDigestCacheEntry>& aList )
+ {
+ if ( !aList.IsEmpty() )
+ {
+ CSIPSecDigestCacheEntry* entry( NULL );
+ TSIPSecDigestCacheEntryIterator entryIterator =
+ TSIPSecDigestCacheEntryIterator( aList );
+
+ while ( ( entry = entryIterator.Next() ) != NULL )
+ {
+ aList.Remove( *entry );
+ delete entry;
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::RemoveAllCredentials
+// ----------------------------------------------------------------------------
+//
+void CSIPSecDigestCache::RemoveAllCredentials()
+ {
+ if ( !iCredentialsList.IsEmpty() )
+ {
+ CSIPSecUserRecord* record( NULL );
+ iCredentialsListIter.SetToFirst();
+ while ( ( record = iCredentialsListIter++ ) != NULL )
+ {
+ iCredentialsList.Remove( *record );
+ delete record;
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::IsCredentialsInList
+// ----------------------------------------------------------------------------
+//
+TBool CSIPSecDigestCache::IsCredentialsInList(
+ const CSIPSecUserRecord& aCredentials )
+ {
+ if ( !iCredentialsList.IsEmpty() )
+ {
+ CSIPSecUserRecord* record( NULL );
+ iCredentialsListIter.SetToFirst();
+ while ( ( record = iCredentialsListIter++ ) != NULL )
+ {
+ if ( record == &aCredentials )
+ {
+ return ETrue;
+ }
+ }
+ }
+ return EFalse;
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::ClearCache
+// ----------------------------------------------------------------------------
+//
+void CSIPSecDigestCache::ClearCache( const MSIPSecUser& aUser )
+ {
+ RemoveUsedEntry( iProxyList, aUser );
+ RemoveUsedEntry( iEndpointList, aUser );
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::RemoveUsedEntry
+// ----------------------------------------------------------------------------
+//
+void
+CSIPSecDigestCache::RemoveUsedEntry( TSglQue< CSIPSecDigestCacheEntry >& aList,
+ const MSIPSecUser& aUser )
+ {
+ if ( !aList.IsEmpty() )
+ {
+ CSIPSecDigestCacheEntry* entry( NULL );
+ TSIPSecDigestCacheEntryIterator entryIter =
+ TSIPSecDigestCacheEntryIterator( aList );
+
+ while ( ( entry = entryIter.Next() ) != NULL )
+ {
+ // When removing cache items, do NOT compare trusted user
+ if ( &entry->SIPSecUser() == &aUser )
+ {
+ RemoveCacheEntry( *entry, aUser );
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::ClearCache
+// ----------------------------------------------------------------------------
+//
+void CSIPSecDigestCache::ClearCache( CSIPSecUserRecord& aCredentials,
+ TBool aAKAOnly )
+ {
+ RemoveMatchingEntry( iProxyList, aCredentials, aAKAOnly );
+ RemoveMatchingEntry( iEndpointList, aCredentials, aAKAOnly );
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::RemoveMatchingEntry
+// ----------------------------------------------------------------------------
+//
+void CSIPSecDigestCache::RemoveMatchingEntry(
+ TSglQue< CSIPSecDigestCacheEntry >& aList,
+ CSIPSecUserRecord& aCredentials,
+ TBool aAKAOnly )
+ {
+ if ( !aList.IsEmpty() )
+ {
+ CSIPSecDigestCacheEntry* entry( NULL );
+ TSIPSecDigestCacheEntryIterator entryIter =
+ TSIPSecDigestCacheEntryIterator( aList );
+
+ while ( ( entry = entryIter.Next() ) != NULL )
+ {
+ if ( entry->HoldsUserData( aCredentials ) &&
+ ( !aAKAOnly ||
+ ( static_cast< CSIPSecCredentials* >( entry )->Challenge().
+ Algorithm().AlgorithmName() ==
+ CSIPSecChallengeAKA::SupportedAlgorithm() ) ) )
+ {
+ if ( RemoveCacheEntry( *entry, entry->SIPSecUser() ) )
+ {
+ // Removed aCredentials, nothing refers to it, so exit loop
+ return;
+ }
+ }
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::ClearAKAEntriesWithOldRealm
+// ----------------------------------------------------------------------------
+//
+void CSIPSecDigestCache::ClearAKAEntriesWithOldRealm( const TDesC8& aRealm )
+ {
+ CSIPSecUserRecord* record( NULL );
+ iCredentialsListIter.SetToFirst();
+ while ( ( record = iCredentialsListIter++ ) != NULL )
+ {
+ if ( !record->IsSameRealm( aRealm ) )
+ {
+ ClearCache( *record, ETrue );
+ }
+ }
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::RegisterObserverL
+// Check if aObserver has a matching CSIPSecDigestObserver. If not, create
+// CSIPSecDigestObserver for it. Each SIP response has its own aObserver.
+// ----------------------------------------------------------------------------
+//
+CSIPSecDigestObserver* CSIPSecDigestCache::RegisterObserverL(
+ MSIPSecSecurityMechanismObserver& aObserver,
+ CSIPSecUserRecord& aUserData )
+ {
+ CSIPSecDigestObserver* observer( NULL );
+ TInt i( 0 );
+ while ( !observer && i < iDigestObservers.Count() )
+ {
+ observer = iDigestObservers[ i++ ];
+ observer = observer->HasObserver( aObserver ) ? observer : NULL;
+ }
+
+ if ( !observer )
+ {
+ observer = aUserData.CreateObserverL( aObserver );
+ CleanupStack::PushL( observer );
+ iDigestObservers.AppendL( observer );
+ CleanupStack::Pop( observer );
+ }
+
+ return observer;
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::CancelPendingOperations
+// ----------------------------------------------------------------------------
+//
+void CSIPSecDigestCache::CancelPendingOperations(
+ MSIPSecSecurityMechanismObserver* aObserver )
+ {
+ CSIPSecUserRecord* record( NULL );
+ iCredentialsListIter.SetToFirst();
+ while ( ( record = iCredentialsListIter++ ) != NULL )
+ {
+ record->CancelPendingOperations( aObserver );
+ }
+
+ CleanObservers();
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::Cancel
+// ----------------------------------------------------------------------------
+//
+TInt CSIPSecDigestCache::Cancel( TTransactionId aTransactionId,
+ const TDesC8& aRealm,
+ const MSIPSecUser* aTrustedUser )
+ {
+ if ( aRealm.Length() == 0 )
+ {
+ return KErrArgument;
+ }
+
+ TInt status( KErrNotFound );
+ CSIPSecUserRecord* record( NULL );
+ iCredentialsListIter.SetToFirst();
+ while ( ( record = iCredentialsListIter++ ) != NULL )
+ {
+ if ( record->IsSameRealm( aRealm ) &&
+ ( record->TransactionIdPassedToClient() == aTransactionId ||
+ &record->SIPSecUser() == aTrustedUser ) )
+ {
+ status = KErrNone; // At least one found
+ record->CancelPendingOperations( NULL /* cancel all */ );
+ }
+ }
+
+ CleanObservers();
+ return status;
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::Remove
+// ----------------------------------------------------------------------------
+//
+TInt CSIPSecDigestCache::Remove( const TDesC8& aRealm )
+ {
+ if ( aRealm.Length() == 0 )
+ {
+ return KErrArgument;
+ }
+
+ TInt status( KErrNotFound );
+ CSIPSecUserRecord* record( NULL );
+ iCredentialsListIter.SetToFirst();
+ while ( ( record = iCredentialsListIter++ ) != NULL )
+ {
+ if ( record->IsSameRealm( aRealm ) )
+ {
+ status = KErrNone; // At least one found
+ // Remove entries pointing to record, then remove record.
+ ClearCache( *record, EFalse );
+ }
+ }
+
+ CleanObservers();
+ return status;
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::CountResponses
+// There can be just one record per realm/transaction id pair, as many SIPSec
+// users can't have the same transaction id. Cache has just one IMS record.
+// Compare the real transaction ids, regardless of the value returned by
+// MSIPSecUser::PassOnlyRealmsToUser().
+// ----------------------------------------------------------------------------
+//
+TInt CSIPSecDigestCache::CountResponses( CSIPResponse& aResponse,
+ CSIPRequest& aRequest,
+ TTransactionId aTransactionId,
+ RStringF aDefaultAlgorithm )
+ {
+ TInt status( KErrNone );
+
+ RStringF alg;
+ RStringF dummyQop;
+ RSIPSecChallengeResolver::GetDigestParamsFromSecurityServer( aResponse,
+ alg,
+ dummyQop );
+ CSIPSecUserRecord* record( NULL );
+ iCredentialsListIter.SetToFirst();
+ while ( ( record = iCredentialsListIter++ ) != NULL )
+ {
+ if ( record->Type() == CSIPSecUserRecord::EIMS &&
+ record->TransactionId() == aTransactionId )
+ {
+ TBool match( EFalse );
+ if ( !HandleChallenges( aResponse,
+ alg,
+ aDefaultAlgorithm,
+ record->Realm(),
+ match ) )
+ {
+ __SIP_ASSERT_RETURN_VALUE( !match, KErrAlreadyExists );
+ match = HandleAuthorizations( aRequest,
+ alg,
+ aDefaultAlgorithm,
+ record->Realm() );
+ }
+ if ( match &&
+ static_cast< CSIPSecSIMRecord* >( record )->
+ UpdateMessageCounter( aResponse.ResponseCode() ) )
+ {
+ status = KErrSIPForbidden;
+ }
+ }
+ }
+ return status;
+ }
+
+// ----------------------------------------------------------------------------
+// CSIPSecDigestCache::CleanObservers
+// ----------------------------------------------------------------------------
+//
+void CSIPSecDigestCache::CleanObservers()
+ {
+ TInt i( 0 );
+ while ( i < iDigestObservers.Count() )
+ {
+ CSIPSecDigestObserver* observer = iDigestObservers[ i ];
+ if ( observer->IsCompleted() )
+ {
+ iDigestObservers.Remove( i );
+ delete observer;
+ }
+ else
+ {
+ ++i;
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestCache::HandleChallenges
+// -----------------------------------------------------------------------------
+//
+TBool CSIPSecDigestCache::HandleChallenges( CSIPResponse& aResponse,
+ RStringF aAlgorithm,
+ RStringF aDefaultAlgorithm,
+ const TDesC8& aRealm,
+ TBool& aMatch ) const
+ {
+ TBool proxyChallenges( EFalse );
+ TBool endpointChallenges( EFalse );
+
+ aMatch = HandleAuthHeaders( aResponse,
+ aAlgorithm,
+ aDefaultAlgorithm,
+ SIPStrings::StringF( SipStrConsts::EProxyAuthenticateHeader ),
+ aRealm,
+ ETrue,
+ proxyChallenges ) ||
+ HandleAuthHeaders( aResponse,
+ aAlgorithm,
+ aDefaultAlgorithm,
+ SIPStrings::StringF( SipStrConsts::EWWWAuthenticateHeader ),
+ aRealm,
+ ETrue,
+ endpointChallenges );
+ return proxyChallenges || endpointChallenges;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestCache::HandleAuthorizations
+// -----------------------------------------------------------------------------
+//
+TBool CSIPSecDigestCache::HandleAuthorizations( CSIPRequest& aRequest,
+ RStringF aAlgorithm,
+ RStringF aDefaultAlgorithm,
+ const TDesC8& aRealm ) const
+ {
+ TBool dummy( EFalse );
+ return HandleAuthHeaders( aRequest,
+ aAlgorithm,
+ aDefaultAlgorithm,
+ SIPStrings::StringF( SipStrConsts::EAuthorizationHeader ),
+ aRealm,
+ EFalse,
+ dummy ) ||
+ HandleAuthHeaders( aRequest,
+ aAlgorithm,
+ aDefaultAlgorithm,
+ SIPStrings::StringF( SipStrConsts::EProxyAuthorizationHeader ),
+ aRealm,
+ EFalse,
+ dummy );
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestCache::HandleAuthHeaders
+// -----------------------------------------------------------------------------
+//
+TBool CSIPSecDigestCache::HandleAuthHeaders( CSIPMessage& aMessage,
+ RStringF aAlgorithm,
+ RStringF aDefaultAlgorithm,
+ RStringF aHeaderName,
+ const TDesC8& aRealm,
+ TBool aCheckChallenges,
+ TBool& aChallengeFound ) const
+ {
+ aChallengeFound = EFalse;
+ TBool match( EFalse );
+
+ if ( aMessage.HeaderCount( aHeaderName ) > 0 )
+ {
+ TSglQueIter< CSIPHeaderBase > headers = aMessage.Headers( aHeaderName );
+ while ( headers && !match )
+ {
+ CSIPAuthHeaderBase* authHeader =
+ static_cast< CSIPAuthHeaderBase* >( headers++ );
+ if ( !aCheckChallenges ||
+ RSIPSecChallengeResolver::IsValidDigestChallenge(
+ *authHeader ) )
+ {
+ aChallengeFound = ETrue;
+ match = CompareAKARealm( *authHeader,
+ aRealm,
+ aAlgorithm,
+ aDefaultAlgorithm );
+ }
+ }
+ }
+ return match;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestCache::CompareAKARealm
+// aAlgorithm may change in this function, but caller's algorithm must not.
+// -----------------------------------------------------------------------------
+//
+TBool CSIPSecDigestCache::CompareAKARealm( CSIPAuthHeaderBase& aHeader,
+ const TDesC8& aCachedRealm,
+ RStringF aAlgorithm,
+ RStringF aDefaultAlgorithm ) const
+ {
+ RSIPSecChallengeResolver::SelectAlgorithm( aHeader,
+ aDefaultAlgorithm,
+ aAlgorithm );
+ return ( TSIPSecDigestContext::GetDesParam( aHeader,
+ SipStrConsts::ERealm ).Compare( aCachedRealm ) == 0 ) &&
+ ( aAlgorithm == SIPStrings::StringF( SipStrConsts::EAKAv1MD5 ) );
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecDigestCache::ChangeRecordUserIfNeeded
+// If none of the entries in iProxyList or iEndpointList that point to aRecord,
+// have the same SIPSec user as the aRecord, change aRecord's SIPSec user to be
+// any of the referring entries' SIPSec user.
+// -----------------------------------------------------------------------------
+//
+void CSIPSecDigestCache::ChangeRecordUserIfNeeded( CSIPSecUserRecord& aRecord,
+ const MSIPSecUser& aUser )
+ {
+ // Do not compare trusted user
+ if ( &aRecord.User() == &aUser )
+ {
+ // Loop both proxy and endpoint caches.
+ // iProxyListIter and iEndpointListIter are already used by the code
+ // that calls ChangeRecordUserIfNeeded(), so use new iterators.
+ TSIPSecDigestCacheEntryIterator proxyListIter( iProxyList );
+ TSIPSecDigestCacheEntryIterator endpointListIter( iEndpointList );
+ TSIPSecDigestCacheIterator cacheIterator;
+ // Initialize iterators
+ proxyListIter.SetToFirst();
+ endpointListIter.SetToFirst();
+ cacheIterator.iList.Reset();
+ cacheIterator.iList.AddLast( proxyListIter );
+ cacheIterator.iList.AddLast( endpointListIter );
+ cacheIterator.iListIterator.SetToFirst();
+
+ const MSIPSecUser* sipSecUser( NULL );
+ CSIPSecDigestCacheEntry* entry( NULL );
+ while ( ( entry = cacheIterator.Next() ) != NULL )
+ {
+ if ( entry->HoldsUserData( aRecord ) )
+ {
+ if ( &entry->SIPSecUser() == &aUser )
+ {
+ return; // Same SIPSec user, no action needed
+ }
+ else
+ {
+ sipSecUser = &entry->SIPSecUser();
+ }
+ }
+ }
+
+ // Original SIPSec user no longer uses aRecord.
+ // Change SIPSec user to one of those still using it.
+ __ASSERT_DEBUG( sipSecUser != NULL,
+ User::Panic( _L( "DigestCache:ChangeRecUser" ),
+ KErrNotFound ) );
+ if ( sipSecUser )
+ {
+ aRecord.SetUser( *sipSecUser );
+ }
+ }
+ }
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// ----------------------------------------------------------------------------
+// TSIPSecDigestCacheEntryIterator::TSIPSecDigestCacheEntryIterator
+// ----------------------------------------------------------------------------
+//
+TSIPSecDigestCacheEntryIterator::TSIPSecDigestCacheEntryIterator(
+ TSglQue<CSIPSecDigestCacheEntry>& aList ) :
+ TSglQueIter<CSIPSecDigestCacheEntry>( aList ),
+ iLink()
+ {
+ SetToFirst();
+ }
+
+// ----------------------------------------------------------------------------
+// TSIPSecDigestCacheEntryIterator::Next
+// Return the next matching entry in the cache.
+// ----------------------------------------------------------------------------
+//
+CSIPSecDigestCacheEntry*
+TSIPSecDigestCacheEntryIterator::Next( TSIPSecPluginContext& aContext )
+ {
+ CSIPSecDigestCacheEntry* entry( NULL );
+
+ while ( ( entry = Next() ) != NULL )
+ {
+ if ( entry->Match( aContext ) )
+ {
+ return entry;
+ }
+ }
+
+ return NULL;
+ }
+
+// ----------------------------------------------------------------------------
+// TSIPSecDigestCacheEntryIterator::Next
+// ----------------------------------------------------------------------------
+//
+CSIPSecDigestCacheEntry* TSIPSecDigestCacheEntryIterator::Next()
+ {
+ return ( *this )++;
+ }
+
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+// ----------------------------------------------------------------------------
+// TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator
+// ----------------------------------------------------------------------------
+//
+TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator() :
+ iList( TSIPSecDigestCacheEntryIterator::iSIPSecOffset ),
+ iListIterator( TSglQueIter<TSIPSecDigestCacheEntryIterator>( iList ) ),
+ iContext( NULL )
+ {
+ }
+
+// ----------------------------------------------------------------------------
+// TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator
+// ----------------------------------------------------------------------------
+//
+TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator(
+ TSIPSecPluginContext& aContext ) :
+ iList( TSIPSecDigestCacheEntryIterator::iSIPSecOffset ),
+ iListIterator( TSglQueIter<TSIPSecDigestCacheEntryIterator>( iList ) ),
+ iContext( &aContext )
+ {
+ }
+
+// ----------------------------------------------------------------------------
+// TSIPSecDigestCacheIterator::TSIPSecDigestCacheIterator
+// ----------------------------------------------------------------------------
+//
+CSIPSecDigestCacheEntry* TSIPSecDigestCacheIterator::Next()
+ {
+ TSIPSecDigestCacheEntryIterator* iter( NULL );
+ CSIPSecDigestCacheEntry* entry( NULL );
+
+ // Loop until an entry is found or both lists have been traversed
+ while ( !entry && ( iter = iListIterator ) != NULL )
+ {
+ // Get next entry from current list
+ entry = iContext ? iter->Next( *iContext ) : iter->Next();
+
+ // If the current list has been exhausted, move to next list
+ if ( !entry )
+ {
+ iter = ( iListIterator )++;
+ }
+ }
+
+ return entry;
+ }