realtimenetprots/sipfw/SIP/SIPSec/DigestPlugin/src/CSIPSecDigestPlugin.cpp
changeset 0 307788aac0a8
equal deleted inserted replaced
-1:000000000000 0:307788aac0a8
       
     1 // Copyright (c) 2008-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     2 // All rights reserved.
       
     3 // This component and the accompanying materials are made available
       
     4 // under the terms of "Eclipse Public License v1.0"
       
     5 // which accompanies this distribution, and is available
       
     6 // at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     7 //
       
     8 // Initial Contributors:
       
     9 // Nokia Corporation - initial contribution.
       
    10 //
       
    11 // Contributors:
       
    12 //
       
    13 // Description:
       
    14 // Name          : CSIPSecDigestPlugin.cpp
       
    15 // Part of       : SIPDigestPlugin
       
    16 // Version       : SIP/6.0
       
    17 //
       
    18 
       
    19 
       
    20 
       
    21 #include "SipLogs.h"
       
    22 #include "siprequest.h"
       
    23 #include "sipresponse.h"
       
    24 #include "sipauthorizationheader.h"
       
    25 #include "sipauthenticationinfoheader.h"
       
    26 #include "sipsecurityclientheader.h"
       
    27 #include "sipsecurityserverheader.h"
       
    28 #include "sipsecurityverifyheader.h"
       
    29 #include "sipstrings.h"
       
    30 #include "sipstrconsts.h"
       
    31 #include "SipSecUtils.h"
       
    32 #include "tsipsecmechanisminitparams.h"
       
    33 #include "CSIPSecDigestPlugin.h"
       
    34 #include "sipsecdigestcontext.h"
       
    35 #include "sipsecdigestcache.h"
       
    36 #include "CSIPSecUserRecord.h"
       
    37 #include "sipprivatecrkeys.h"
       
    38 #include <centralrepository.h>
       
    39 
       
    40 
       
    41 // ============================ MEMBER FUNCTIONS ===============================
       
    42 
       
    43 // -----------------------------------------------------------------------------
       
    44 // CSIPSecDigestPlugin::NewL
       
    45 // -----------------------------------------------------------------------------
       
    46 //
       
    47 CSIPSecDigestPlugin* CSIPSecDigestPlugin::NewL( TAny* aInitParams ) 
       
    48     {
       
    49     __ASSERT_ALWAYS( aInitParams, User::Leave( KErrArgument ) );
       
    50     				 
       
    51     TSIPSecMechanismInitParams* initParams =
       
    52     	static_cast<TSIPSecMechanismInitParams*>( aInitParams );
       
    53 	CSIPSecDigestPlugin* self =
       
    54 		new ( ELeave ) CSIPSecDigestPlugin( initParams->iEngineContext );
       
    55 	CleanupStack::PushL( self );
       
    56 	self->ConstructL( initParams->iTimer );
       
    57 	CleanupStack::Pop( self );
       
    58 	return self;
       
    59     }
       
    60 
       
    61 // -----------------------------------------------------------------------------
       
    62 // CSIPSecDigestPlugin::ConstructL
       
    63 // -----------------------------------------------------------------------------
       
    64 //
       
    65 void CSIPSecDigestPlugin::ConstructL( MTimerManager& aTimerMgr )
       
    66     {
       
    67     iDigestMechanism = CSIPSecDigest::NewL();
       
    68 	iCache = CSIPSecDigestCache::NewL( aTimerMgr );
       
    69 
       
    70 	CRepository* repository = CRepository::NewLC( KCRUidSIP );
       
    71 	TInt emptyResponseAfterSqnFailure( 0 );
       
    72 	if ( repository->Get(KSIPSendEmptyResponseParameterAfterSqnFailure,
       
    73 		 				 emptyResponseAfterSqnFailure ) == KErrNone &&
       
    74 		 emptyResponseAfterSqnFailure )
       
    75 		{
       
    76 		iSendEmptyResponseParameterAfterSqnFailure = ETrue;
       
    77 		}
       
    78 	CleanupStack::PopAndDestroy( repository );
       
    79     }
       
    80 
       
    81 // -----------------------------------------------------------------------------
       
    82 // CSIPSecDigestPlugin::CSIPSecDigestPlugin
       
    83 // -----------------------------------------------------------------------------
       
    84 //
       
    85 CSIPSecDigestPlugin::CSIPSecDigestPlugin( MSIPSecEngineContext& aEngineContext )
       
    86   : iEngineContext( aEngineContext )
       
    87     {
       
    88     }
       
    89 
       
    90 // -----------------------------------------------------------------------------
       
    91 // CSIPSecDigestPlugin::~CSIPSecDigestPlugin
       
    92 // -----------------------------------------------------------------------------
       
    93 //
       
    94 CSIPSecDigestPlugin::~CSIPSecDigestPlugin()
       
    95     {
       
    96     delete iDigestMechanism;
       
    97     delete iCache;
       
    98     }
       
    99 
       
   100 // -----------------------------------------------------------------------------
       
   101 // CSIPSecDigestPlugin::Name
       
   102 // -----------------------------------------------------------------------------
       
   103 //
       
   104 const TDesC8& CSIPSecDigestPlugin::Name() const
       
   105     {
       
   106     return iDigestMechanism->Name();
       
   107     }
       
   108 
       
   109 // -----------------------------------------------------------------------------
       
   110 // CSIPSecDigestPlugin::InitializeSecurityClientL
       
   111 // -----------------------------------------------------------------------------
       
   112 //
       
   113 void CSIPSecDigestPlugin::InitializeSecurityClientL(
       
   114 	CSIPSecurityClientHeader& aSecurityClient )
       
   115     {
       
   116     aSecurityClient.SetMechanismNameL( Name() );
       
   117     }
       
   118 
       
   119 // -----------------------------------------------------------------------------
       
   120 // CSIPSecDigestPlugin::ProcessSecurityVerifyL
       
   121 // Find Security-Server and Security-Verify with a matching mechanism, and
       
   122 // process them.
       
   123 // A2 is computed from all Sec-Server headers, e.g.
       
   124 // "Security-Server:ipsec-ike;q=0.1,tls;q=0.2". I.e. "Security-Server" followed
       
   125 // by all mechanisms and parameters. Resulting digest-verify parameter is put to
       
   126 // the Security-Verify header that has "digest" mechanism.
       
   127 // -----------------------------------------------------------------------------
       
   128 //
       
   129 void CSIPSecDigestPlugin::ProcessSecurityVerifyL(
       
   130 	TSIPTransportParams& /*aTransportParams*/,
       
   131 	CSIPRequest& aRequest,
       
   132 	TInetAddr& /*aNextHop*/,
       
   133 	const CUri8& aRemoteTarget,
       
   134 	const TDesC8& aOutboundProxy,
       
   135 	MSIPSecUser* aUser,
       
   136 	TRegistrationId aRegistrationId,
       
   137 	RPointerArray<CSIPSecurityServerHeader>& aSecurityServer,        
       
   138 	RPointerArray<CSIPSecurityVerifyHeader>& aSecurityVerify )
       
   139     {
       
   140     __ASSERT_ALWAYS( aUser, User::Leave( KErrArgument ) );
       
   141 
       
   142 	CSIPSecurityServerHeader* secServer = NULL;
       
   143 	for ( TInt i = 0; i < aSecurityServer.Count() && !secServer; ++i )
       
   144 		{
       
   145 		if ( aSecurityServer[ i ]->MechanismName().CompareF( Name() ) == 0 )
       
   146             {
       
   147             secServer = aSecurityServer[ i ];
       
   148             }
       
   149 		}
       
   150 	__ASSERT_ALWAYS( secServer, User::Leave( KErrArgument ) );
       
   151 
       
   152 	CSIPSecurityVerifyHeader* secVerify = NULL;
       
   153 	for ( TInt j = 0; j < aSecurityVerify.Count() && !secVerify; ++j )
       
   154 		{
       
   155 		if ( aSecurityVerify[ j ]->MechanismName().CompareF( Name() ) == 0 )
       
   156             {
       
   157             secVerify = aSecurityVerify[ j ];
       
   158             }        
       
   159 		}
       
   160 	__ASSERT_ALWAYS( secVerify, User::Leave( KErrArgument ) );
       
   161 
       
   162     iDigestMechanism->InitializeL( *secServer );
       
   163     TSIPSecPluginCtxVerify secVerifyContext( *this, aRemoteTarget,
       
   164     										 aOutboundProxy, aRequest,
       
   165                                              *secVerify, aSecurityServer, 
       
   166                                              *aUser, aRegistrationId );
       
   167     TSIPSecDigestCacheIterator cacheIter( secVerifyContext );
       
   168     iCache->InitializeIterator( cacheIter );
       
   169 
       
   170     CSIPSecDigestCacheEntry* entry = NULL;
       
   171 	while ( ( entry = cacheIter.Next() ) != NULL )
       
   172 		{
       
   173 		if ( entry->Match( secVerifyContext ) )
       
   174 		    {
       
   175 		    entry->HandleL( secVerifyContext );
       
   176     		return;
       
   177 		    }
       
   178 		}
       
   179     }
       
   180 
       
   181 // -----------------------------------------------------------------------------
       
   182 // CSIPSecDigestPlugin::AddSecurityParamsL
       
   183 // Nothing is done for ACK.
       
   184 // -----------------------------------------------------------------------------
       
   185 //
       
   186 void CSIPSecDigestPlugin::AddSecurityParamsL(
       
   187 	TSIPTransportParams& /*aTransportParams*/,
       
   188 	CSIPRequest& aRequest,
       
   189 	TRegistrationId aRegistrationId,
       
   190 	TTransactionId aTransactionId,
       
   191 	TInetAddr& /*aNextHop*/,
       
   192 	const CUri8& aRemoteTarget,
       
   193 	const TDesC8& aOutboundProxy,
       
   194 	MSIPSecUser* aUser )
       
   195 	{
       
   196 	__ASSERT_ALWAYS( aUser, User::Leave( KErrArgument ) );	
       
   197 
       
   198 	if ( SipSecUtils::Match( SipStrConsts::EAck, aRequest.Method() ) )
       
   199 		{
       
   200 		return;
       
   201 		}
       
   202 
       
   203 	TSIPSecPluginCtxRequest requestContext( *this,
       
   204 											aRemoteTarget,
       
   205 											aOutboundProxy,
       
   206 											aRequest,
       
   207 											*aUser,
       
   208 											aRegistrationId,
       
   209 											aTransactionId );
       
   210 	TSIPSecDigestCacheIterator cacheIter( requestContext );
       
   211 	iCache->InitializeIterator( cacheIter );
       
   212 
       
   213     // Cleanup
       
   214     CSIPAuthorizationHeader* nonDigestHeader = PrepareRequestL( aRequest );
       
   215 
       
   216 	CSIPSecDigestCacheEntry* entry = NULL;
       
   217 	while ( ( entry = cacheIter.Next() ) != NULL )
       
   218 		{
       
   219 		if ( nonDigestHeader &&
       
   220 		     entry->Type( requestContext ) == CSIPSecDigest::EEndPoint )
       
   221 		    {
       
   222 		    User::LeaveIfError( aRequest.RemoveHeader( nonDigestHeader ) );
       
   223 		    delete nonDigestHeader;
       
   224 		    nonDigestHeader = NULL;
       
   225 		    }
       
   226 
       
   227 		entry->UpdateL( requestContext );
       
   228 		}
       
   229 	}
       
   230 
       
   231 // -----------------------------------------------------------------------------
       
   232 // CSIPSecDigestPlugin::PrepareRequestL
       
   233 // Remove all Proxy-Authorization headers. Remove Authorization headers
       
   234 // selectively, based on response value.
       
   235 // -----------------------------------------------------------------------------
       
   236 //
       
   237 CSIPAuthorizationHeader*
       
   238 CSIPSecDigestPlugin::PrepareRequestL( CSIPRequest& aRequest ) const
       
   239     {
       
   240     aRequest.DeleteHeaders(
       
   241     	SIPStrings::StringF( SipStrConsts::EProxyAuthorizationHeader ) );
       
   242 
       
   243     const RStringF auth =
       
   244     	SIPStrings::StringF( SipStrConsts::EAuthorizationHeader );
       
   245 
       
   246 	CSIPAuthorizationHeader* nonDigestHeader = NULL;
       
   247     if ( aRequest.HeaderCount( auth ) > 0 )
       
   248         {
       
   249     	TSglQueIter<CSIPHeaderBase> authHeaders = aRequest.Headers( auth );
       
   250 
       
   251         CSIPAuthorizationHeader* header = NULL;
       
   252         while ( ( header =
       
   253                   static_cast<CSIPAuthorizationHeader*>( authHeaders++ ) )
       
   254                   != NULL )
       
   255             {
       
   256             if ( header->DesParamValue( SIPStrings::StringF(
       
   257             	SipStrConsts::EResponse ) ).Length() == 0 )
       
   258                 {
       
   259                 nonDigestHeader = header;
       
   260                 }
       
   261             else
       
   262                 {
       
   263                 // This is created by digest plugin -> can be deleted now
       
   264     		    User::LeaveIfError( aRequest.RemoveHeader( header ) );
       
   265     		    delete header;
       
   266     		    header = NULL;
       
   267                 }
       
   268             }
       
   269         }
       
   270 
       
   271     return nonDigestHeader;
       
   272     }    
       
   273 
       
   274 // -----------------------------------------------------------------------------
       
   275 // CSIPSecDigestPlugin::ResponseReceivedL
       
   276 // If 2xx, try to update with authentication info.
       
   277 // -----------------------------------------------------------------------------
       
   278 //
       
   279 TBool CSIPSecDigestPlugin::ResponseReceivedL(
       
   280 	TSIPTransportParams& /*aTransportParams*/,
       
   281 	CSIPResponse& aResponse,
       
   282 	CSIPRequest& aRequest,
       
   283 	TRegistrationId aRegistrationId,
       
   284 	TTransactionId aTransactionId,
       
   285 	TInetAddr& /*aNextHop*/,
       
   286 	const CUri8& aRemoteTarget,
       
   287 	const TDesC8& aOutboundProxy,
       
   288 	MSIPSecUser* aUser,
       
   289 	MSIPSecSecurityMechanismObserver& aObserver )
       
   290     {
       
   291     __ASSERT_ALWAYS( aUser, User::Leave( KErrArgument ) );
       
   292 
       
   293 	User::LeaveIfError( iCache->CountResponses( aResponse,
       
   294 		aRequest,
       
   295 		aTransactionId,
       
   296 		iDigestMechanism->Algorithm() ) );
       
   297 
       
   298     if ( aResponse.ResponseCode() == 401 || // WWW Authorization
       
   299          aResponse.ResponseCode() == 407 || // Proxy Authorization
       
   300          aResponse.ResponseCode() == 494 )  // Security Agreement
       
   301    		{
       
   302         TSIPSecPluginCtxResponse respContext( *this,
       
   303     										  aRemoteTarget,
       
   304     										  aOutboundProxy,
       
   305     										  aResponse,
       
   306 										      *iCache,
       
   307 										      aObserver,
       
   308 										      *aUser,
       
   309 										      aRegistrationId,
       
   310 										      aTransactionId );
       
   311 		return iDigestMechanism->UpdateCacheL( respContext );
       
   312         }
       
   313 
       
   314 	CSIPAuthenticationInfoHeader* authInfo( NULL );
       
   315     if ( ( aResponse.Type() == CSIPResponse::E2XX ) &&
       
   316          ( authInfo = AuthenticationInfo( aResponse ) ) != NULL )
       
   317         {
       
   318         TSIPSecPluginCtxInfo authInfoCtx( *this,
       
   319         								  aRemoteTarget,
       
   320         								  aOutboundProxy,
       
   321         								  aResponse,
       
   322         								  *authInfo,
       
   323 									      *iCache,
       
   324 									      aObserver,
       
   325 									      *aUser,
       
   326 									      aRegistrationId );
       
   327     	TSIPSecDigestCacheIterator cacheIterator( authInfoCtx );
       
   328     	iCache->InitializeIterator( cacheIterator );
       
   329 		CSIPSecDigestCacheEntry* entry( NULL );
       
   330 
       
   331 		while ( ( entry = cacheIterator.Next() ) != NULL )
       
   332 			{
       
   333 			// Let each matching cache entry handle the Authentication-Info
       
   334 			entry->HandleL( authInfoCtx );
       
   335 			}
       
   336         }
       
   337     return EFalse;
       
   338     }
       
   339 
       
   340 // -----------------------------------------------------------------------------
       
   341 // CSIPSecDigestPlugin::IsServerInitiatedSecAgreeAllowed
       
   342 // -----------------------------------------------------------------------------
       
   343 //
       
   344 TBool CSIPSecDigestPlugin::IsServerInitiatedSecAgreeAllowed() const
       
   345 	{
       
   346 	return ETrue;
       
   347 	}
       
   348 
       
   349 // -----------------------------------------------------------------------------
       
   350 // CSIPSecDigestPlugin::ParametersUpdatedL
       
   351 // -----------------------------------------------------------------------------
       
   352 //
       
   353 TBool CSIPSecDigestPlugin::ParametersUpdatedL( MSIPSecUser* /*aUser*/ )
       
   354 	{
       
   355 	return EFalse;
       
   356 	}
       
   357 
       
   358 // -----------------------------------------------------------------------------
       
   359 // CSIPSecDigestPlugin::CancelPendingOperations
       
   360 // -----------------------------------------------------------------------------
       
   361 //
       
   362 void CSIPSecDigestPlugin::CancelPendingOperations(
       
   363 	MSIPSecSecurityMechanismObserver* aObserver )
       
   364     {
       
   365 	iCache->CancelPendingOperations( aObserver );
       
   366     }
       
   367 
       
   368 // -----------------------------------------------------------------------------
       
   369 // CSIPSecDigestPlugin::ClearCache
       
   370 // -----------------------------------------------------------------------------
       
   371 //
       
   372 void CSIPSecDigestPlugin::ClearCache( MSIPSecUser* aUser )
       
   373     {
       
   374     if ( aUser )
       
   375     	{
       
   376     	iCache->ClearCache( *aUser );	
       
   377     	}
       
   378 	iCache->CleanObservers();
       
   379     }
       
   380 
       
   381 // -----------------------------------------------------------------------------
       
   382 // CSIPSecDigestPlugin::SetCredentialsL
       
   383 // Cache can have just one record for a realm and transaction id pair.
       
   384 // SIPSec users with PassOnlyRealmsToUser == ETrue set aTransactionId to value
       
   385 // KEmptyTransactionId. Correct operation is not guaranteed if several of them
       
   386 // use the same realm.
       
   387 //
       
   388 // This function will eventually be removed and clients start to use
       
   389 // SetCredentialsL( const MSIPSecUser& .. ) instead.
       
   390 // -----------------------------------------------------------------------------
       
   391 //
       
   392 void CSIPSecDigestPlugin::SetCredentialsL( TTransactionId aTransactionId,
       
   393                                            const TDesC8& aRealm,
       
   394                                            const TDesC8& aOutboundProxy, 
       
   395                                            const TDesC8& aUserName,
       
   396                                            const TDesC8& aPassword )
       
   397 	{
       
   398 	__ASSERT_ALWAYS( aRealm.Length() > 0, User::Leave( KErrArgument ) );
       
   399 
       
   400 	CSIPSecUserRecord* record = iCache->SearchRecord( aRealm, aTransactionId );
       
   401 	__ASSERT_ALWAYS( record != NULL, User::Leave( KErrNotFound ) );
       
   402 
       
   403 	SetCredentialsToRecordL( *record, aOutboundProxy, aUserName, aPassword );
       
   404 	}
       
   405 
       
   406 // -----------------------------------------------------------------------------
       
   407 // CSIPSecDigestPlugin::SetCredentialsL
       
   408 // -----------------------------------------------------------------------------
       
   409 //
       
   410 void CSIPSecDigestPlugin::SetCredentialsL( const MSIPSecUser& aUser,
       
   411                                            const TDesC8& aRealm,
       
   412                                            const TDesC8& aOutboundProxy, 
       
   413                                            const TDesC8& aUserName,
       
   414                                            const TDesC8& aPassword )
       
   415 	{
       
   416 	__ASSERT_ALWAYS( aRealm.Length() > 0, User::Leave( KErrArgument ) );	
       
   417 
       
   418 	CSIPSecUserRecord* record = iCache->SearchRecord( aRealm, aUser );
       
   419 	__ASSERT_ALWAYS( record != NULL, User::Leave( KErrNotFound ) );
       
   420 
       
   421 	SetCredentialsToRecordL( *record, aOutboundProxy, aUserName, aPassword );
       
   422 	}
       
   423 
       
   424 // -----------------------------------------------------------------------------
       
   425 // CSIPSecDigestPlugin::SetCredentialsToRecordL
       
   426 // -----------------------------------------------------------------------------
       
   427 //
       
   428 void CSIPSecDigestPlugin::SetCredentialsToRecordL( CSIPSecUserRecord& aRecord,
       
   429 												   const TDesC8& aOutboundProxy,
       
   430                                            		   const TDesC8& aUserName,
       
   431                                            		   const TDesC8& aPassword )
       
   432 	{
       
   433 	TBool valid = aRecord.SetUserCredentialsL( aUserName, aPassword );
       
   434 	if ( valid )
       
   435 	    {
       
   436 		aRecord.SetOutboundProxyL( aOutboundProxy );
       
   437 
       
   438     	TSIPSecDigestCacheIterator cacheIterator;
       
   439     	iCache->InitializeIterator( cacheIterator );
       
   440 
       
   441 		CSIPSecDigestCacheEntry* entry( NULL );
       
   442 		while ( ( entry = cacheIterator.Next() ) != NULL )
       
   443 			{
       
   444 			entry->UpdateL( aRecord );
       
   445 			}
       
   446 	    }
       
   447 
       
   448 	aRecord.Updated();
       
   449 
       
   450 	if ( !valid )
       
   451 		{
       
   452 		iCache->ClearCache( aRecord, EFalse );
       
   453 		}
       
   454 
       
   455     iCache->CleanObservers();
       
   456 	}
       
   457 
       
   458 // -----------------------------------------------------------------------------
       
   459 // CSIPSecDigestPlugin::IgnoreChallenge
       
   460 // If aTransactionId is KEmptyTransactionId removes cache entries with
       
   461 // PassOnlyRealmsToUser == ETrue.
       
   462 // -----------------------------------------------------------------------------
       
   463 //
       
   464 TInt CSIPSecDigestPlugin::IgnoreChallenge( TTransactionId aTransactionId,
       
   465                                            const TDesC8& aRealm,
       
   466                                            const MSIPSecUser* aTrustedUser )
       
   467 	{
       
   468 	return iCache->Cancel( aTransactionId, aRealm, aTrustedUser );
       
   469     }
       
   470 
       
   471 // -----------------------------------------------------------------------------
       
   472 // CSIPSecDigestPlugin::RemoveCredentials
       
   473 // Only remove cache entries for which PassOnlyRealmsToUser == ETrue.
       
   474 // -----------------------------------------------------------------------------
       
   475 //
       
   476 TInt CSIPSecDigestPlugin::RemoveCredentials( const TDesC8& aRealm )    
       
   477     {
       
   478     return iCache->Remove( aRealm );
       
   479     }
       
   480 
       
   481 // -----------------------------------------------------------------------------
       
   482 // CSIPSecDigestPlugin::EngineContext
       
   483 // -----------------------------------------------------------------------------
       
   484 //
       
   485 MSIPSecEngineContext& CSIPSecDigestPlugin::EngineContext()
       
   486     {
       
   487     return iEngineContext;
       
   488     }
       
   489 
       
   490 // -----------------------------------------------------------------------------
       
   491 // CSIPSecDigestPlugin::EmptyResponseAfterSqnFailure
       
   492 // -----------------------------------------------------------------------------
       
   493 //
       
   494 TBool CSIPSecDigestPlugin::EmptyResponseAfterSqnFailure() const
       
   495 	{
       
   496 	return iSendEmptyResponseParameterAfterSqnFailure;
       
   497 	}
       
   498 
       
   499 // -----------------------------------------------------------------------------
       
   500 // CSIPSecDigestPlugin::AuthenticationInfo
       
   501 // -----------------------------------------------------------------------------
       
   502 //
       
   503 CSIPAuthenticationInfoHeader*
       
   504 CSIPSecDigestPlugin::AuthenticationInfo( CSIPResponse& aResponse ) const
       
   505     {
       
   506     CSIPAuthenticationInfoHeader* header( NULL );
       
   507 
       
   508     if ( aResponse.Type() == CSIPResponse::E2XX )
       
   509         {
       
   510         const RStringF authInfo =
       
   511     		SIPStrings::StringF( SipStrConsts::EAuthenticationInfoHeader );
       
   512 	    TInt count = aResponse.HeaderCount( authInfo );
       
   513 	    if ( count > 0 )
       
   514 	        {
       
   515 	    	TSglQueIter< CSIPHeaderBase > headers =
       
   516 	    		aResponse.Headers( authInfo );
       
   517     		for ( TInt i = 0; i < count; i++ )
       
   518                 {
       
   519                 header =
       
   520                 	static_cast< CSIPAuthenticationInfoHeader* >( headers++ );
       
   521                 }
       
   522 	        }
       
   523         }
       
   524 
       
   525     return header;
       
   526     }