diff -r 000000000000 -r 307788aac0a8 realtimenetprots/sipfw/SIP/SIPSec/DigestPlugin/src/CSIPSecDigestPlugin.cpp --- /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 + + +// ============================ MEMBER FUNCTIONS =============================== + +// ----------------------------------------------------------------------------- +// CSIPSecDigestPlugin::NewL +// ----------------------------------------------------------------------------- +// +CSIPSecDigestPlugin* CSIPSecDigestPlugin::NewL( TAny* aInitParams ) + { + __ASSERT_ALWAYS( aInitParams, User::Leave( KErrArgument ) ); + + TSIPSecMechanismInitParams* initParams = + static_cast( 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& aSecurityServer, + RPointerArray& 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 authHeaders = aRequest.Headers( auth ); + + CSIPAuthorizationHeader* header = NULL; + while ( ( header = + static_cast( 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; + }