--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/realtimenetprots/sipfw/SIP/SIPSec/DigestPlugin/src/CSIPSecCredentials.cpp Tue Feb 02 01:03:15 2010 +0200
@@ -0,0 +1,453 @@
+// 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 : CSIPSecCredentials.cpp
+// Part of : SIPDigestPlugin
+// Version : SIP/6.0
+//
+
+
+
+#include "CSIPSecCredentials.h"
+#include "CSIPSecChallenge.h"
+#include "MSIPSecAlgorithm.h"
+#include "sipsecdigestcontext.h"
+#include "CSIPSecUserRecord.h"
+#include "MSIPSecUser.h"
+#include "SipLogs.h"
+#include "siprequest.h"
+#include "uricontainer.h"
+#include "sipauthorizationheader.h"
+#include "sipproxyauthorizationheader.h"
+#include "sipauthenticateheaderbase.h"
+#include "sipauthenticationinfoheader.h"
+#include "sipstrings.h"
+#include "sipstrconsts.h"
+
+
+// ============================ MEMBER FUNCTIONS ===============================
+
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::NewL
+// -----------------------------------------------------------------------------
+//
+CSIPSecCredentials*
+CSIPSecCredentials::NewL( CSIPSecChallenge* aChallenge,
+ CSIPSecDigest& aMechanism,
+ TSIPSecPluginCtxResponse& aContext )
+ {
+ __ASSERT_ALWAYS( aChallenge, User::Leave( KErrArgument ) );
+
+ const MSIPSecUser* sipSecUser = aChallenge->Owner();
+ if ( !sipSecUser )
+ {
+ sipSecUser = &aContext.SIPSecUser();
+ }
+
+ CSIPSecCredentials* self = new ( ELeave ) CSIPSecCredentials( aMechanism,
+ *sipSecUser );
+ CleanupStack::PushL( self );
+ self->ConstructL( aChallenge, aContext );
+ CleanupStack::Pop( self );
+ return self;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::CSIPSecCredentials
+// -----------------------------------------------------------------------------
+//
+CSIPSecCredentials::CSIPSecCredentials( CSIPSecDigest& aMechanism,
+ const MSIPSecUser& aUser ) :
+ CSIPSecDigestCacheEntry( aUser ),
+ iMechanism( aMechanism )
+ {
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecChallenge::~CSIPSecCredentials
+// -----------------------------------------------------------------------------
+//
+CSIPSecCredentials::~CSIPSecCredentials()
+ {
+ delete iChallenge;
+ delete iAuthorizationHeader;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::ConstructL
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::ConstructL( CSIPSecChallenge* aChallenge,
+ TSIPSecPluginCtxResponse& aContext )
+ {
+ __ASSERT_ALWAYS( aChallenge, User::Leave( KErrArgument ) );
+
+ CSIPSecDigestCacheEntry::ConstructL( ChallengeType( *aChallenge,
+ &aContext ),
+ aContext.RemoteTarget() );
+ CreateContentL( *aChallenge );
+ TSIPSecDigestCtxSetup ctx( *this, aContext.TransactionId(), &aContext );
+ aChallenge->PopulateCredentialsL( ctx );
+
+ // Take ownership of aChallenge when leave can't occur any more
+ iChallenge = aChallenge;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::UpdateL
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::UpdateL( CSIPSecUserRecord& aUserCredentials )
+ {
+ // If user credentials update is for this entry
+ if ( HoldsUserData( aUserCredentials ) && !UserData().IsUpdating() )
+ {
+ TSIPSecDigestCtxSetup ctx( *this, aUserCredentials.TransactionId() );
+ TBool askCredentials( EFalse );
+
+ // As credentials were obtained, DigestUpdateL must not indicate "wait".
+ __ASSERT_ALWAYS( !DigestUpdateL( ctx, askCredentials ),
+ User::Leave( KErrGeneral ) );
+ __ASSERT_ALWAYS( !askCredentials, User::Leave( KErrGeneral ) );
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::UpdateL
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::UpdateL( TSIPSecPluginCtxRequest& aContext )
+ {
+ __SIP_LOG( "SIPSecCred:UpdateL(ctx)" )
+
+ if ( UserData().IsValid() )
+ {
+ __SIP_LOG( "user data is valid" )
+
+ TSIPSecDigestCtxProcess ctx( *this, &aContext );
+ UpdateContentL( ctx );
+
+ iChallenge->Algorithm().ProcessRequestL( ctx );
+
+ // Add a (Proxy-)Authorization header
+ aContext.SIPRequest().AddHeaderL( Content() );
+ }
+
+ __SIP_LOG( "SIPSecCred:UpdateL(ctx) end" )
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::HandleL
+// Called for each matching cache entry. They store the new nonce.
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::HandleL( TSIPSecPluginCtxInfo& aAuthenticationInfo )
+ {
+ RStringF cnonce = SIPStrings::StringF( SipStrConsts::ECNonce );
+ RStringF nc = SIPStrings::StringF( SipStrConsts::ENonceCount );
+ RStringF qop = SIPStrings::StringF( SipStrConsts::EQop );
+ CSIPAuthenticationInfoHeader& authInfo =
+ aAuthenticationInfo.AuthenticationInfoHeader();
+
+ if ( Content().ParamValue( qop ) == authInfo.Value( qop ) &&
+ Content().DesParamValue( cnonce ) == authInfo.DesValue( cnonce ) &&
+ Content().ParamValue( nc ) == authInfo.Value( nc ) )
+ {
+ const TDesC8& responseAuth = authInfo.DesValue( SIPStrings::StringF(
+ SipStrConsts::EResponseAuth ) );
+ if ( responseAuth.Length() > 0 )
+ {
+ TBuf8< KSIPSecDigestHashHexSize > response;
+ TSIPSecDigestAuthInfoContext ctx( *this,
+ response,
+ &aAuthenticationInfo );
+ // Process the response auth
+ iChallenge->Algorithm().ProcessRequestL( ctx );
+
+ if ( responseAuth.Compare( response ) != 0 )
+ {
+ User::Leave( KErrPermissionDenied );
+ }
+ }
+
+ const TDesC8& nextNonce = authInfo.DesValue(
+ SIPStrings::StringF( SipStrConsts::ENextNonce ) );
+ if ( nextNonce.Length() > 0 )
+ {
+ RStringF nonce = SIPStrings::StringF( SipStrConsts::ENonce );
+ Content().SetDesParamL( nonce, nextNonce );
+ iChallenge->Content().SetDesParamL( nonce, nextNonce );
+ SetNonceCountL( 0 );
+ }
+ }
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::HandleL
+// Process Security-Verify header
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::HandleL( TSIPSecPluginCtxVerify& aSecurityVerifyCtx )
+ {
+ HBufC8* requestURI =
+ aSecurityVerifyCtx.SIPRequest().RequestURI()->ToTextL();
+ CleanupStack::PushL( requestURI );
+
+ TSIPSecDigestVerifyContext ctx( *this, *requestURI, &aSecurityVerifyCtx );
+ iChallenge->Algorithm().ProcessRequestL( ctx );
+
+ CleanupStack::PopAndDestroy( requestURI );
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::DigestUpdateL
+// Generate CNonce if it doesn't exist.
+// -----------------------------------------------------------------------------
+//
+TBool CSIPSecCredentials::DigestUpdateL( TSIPSecDigestCtxSetup& aContext,
+ TBool& aAskCredentials )
+ {
+ UpdateContentL( aContext );
+
+ if ( iChallenge->HasQop() &&
+ !Content().HasParam( SIPStrings::StringF( SipStrConsts::ECNonce ) ) )
+ {
+ iChallenge->Algorithm().GenerateCNonceL( aContext );
+ }
+ return iChallenge->Algorithm().ProcessResponseL( aContext,
+ aAskCredentials );
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::ChallengeType
+// -----------------------------------------------------------------------------
+//
+CSIPSecDigest::TChallengeType
+CSIPSecCredentials::ChallengeType( const CSIPSecChallenge& aChallenge,
+ const TSIPSecPluginContext* aContext ) const
+ {
+ CSIPSecDigest::TChallengeType type = aChallenge.Type();
+ TBool ignoreOutboundProxy( aContext &&
+ aContext->OutboundProxy().Length() == 0 );
+
+ if ( type == CSIPSecDigest::EProxy &&
+ !ignoreOutboundProxy &&
+ iUserCredentials &&
+ iUserCredentials->OutboundProxy().Length() > 0 )
+ {
+ type = CSIPSecDigest::EOutboundProxy;
+ }
+
+ return type;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::Type
+// -----------------------------------------------------------------------------
+//
+CSIPSecDigest::TChallengeType CSIPSecCredentials::Type() const
+ {
+ return ChallengeType( *iChallenge );
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::Type
+// -----------------------------------------------------------------------------
+//
+CSIPSecDigest::TChallengeType CSIPSecCredentials::Type(
+ const TSIPSecPluginContext& aContext ) const
+ {
+ return ChallengeType( *iChallenge, &aContext );
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::DoesMatch
+// aChallenge::Owner() is always NULL at this phase.
+// -----------------------------------------------------------------------------
+//
+TBool CSIPSecCredentials::DoesMatch( const CSIPSecChallenge& aChallenge,
+ const MSIPSecUser& aUser,
+ TRegistrationId aRegistrationId ) const
+ {
+ return aChallenge.Type() == iChallenge->Type() &&
+ ( aChallenge.Realm().Compare( iChallenge->Realm() ) == 0 ) &&
+ iUserCredentials &&
+ iUserCredentials->CompareUser( aUser, aRegistrationId );
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::ChallengeReceived
+// If "stale=true", retry with new nonce. Username and password are valid.
+// Otherwise ask username and password. PopulateCredentialsL later copies nonce
+// to CSIPSecCredentials::iAuthorizationHeader.
+// -----------------------------------------------------------------------------
+//
+TBool CSIPSecCredentials::ChallengeReceived( CSIPSecChallenge& aNewChallenge )
+ {
+ RStringF stale = SIPStrings::StringF( SipStrConsts::EStale );
+
+ TBool hasStale = aNewChallenge.Content().HasParam( stale );
+ _LIT8( KSIPSecStaleTrue, "true" );
+ TBool isStale = hasStale &&
+ aNewChallenge.Content().ParamValue( stale ).DesC().CompareF(
+ KSIPSecStaleTrue ) == 0;
+ TBool hasAuts =
+ Content().HasParam( SIPStrings::StringF( SipStrConsts::EAuts ) );
+ TBool isAKA = aNewChallenge.Algorithm().AlgorithmName() ==
+ SIPStrings::StringF( SipStrConsts::EAKAv1MD5 );
+
+ if ( !isStale || hasAuts || isAKA )
+ {
+ // Credentials are wrong
+ UserData().Invalidate( CSIPSecUserRecord::ENoState );
+
+ RStringF nonce = SIPStrings::StringF( SipStrConsts::ENonce );
+ if ( aNewChallenge.Content().DesParamValue( nonce ) !=
+ Content().DesParamValue( nonce ) )
+ {
+ // Server gave a new nonce, clear old username and password so even
+ // if application gives same username and password, the request is
+ // sent. As nonce is different, the result will be different.
+ UserData().ClearUsernameAndPassword();
+ }
+ }
+
+ aNewChallenge.SetOwner( &iUser );
+
+ // Remove unless SIPSec user asked the response and waits credentials
+ TBool remove = iUser.PassOnlyRealmsToUser() || !UserData().IsUpdating();
+
+ __SIP_INT_LOG1( "SIPSecCred:ChallRecv remove", remove )
+ return remove;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::Mechanism
+// -----------------------------------------------------------------------------
+//
+CSIPSecDigest& CSIPSecCredentials::Mechanism() const
+ {
+ return iMechanism;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::Content
+// -----------------------------------------------------------------------------
+//
+CSIPAuthorizationHeaderBase& CSIPSecCredentials::Content()
+ {
+ return *iAuthorizationHeader;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::Challenge
+// -----------------------------------------------------------------------------
+//
+CSIPSecChallenge& CSIPSecCredentials::Challenge()
+ {
+ return *iChallenge;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::CreateContentL
+// Delete old AuthorizationHeader when can't leave, so it retains its old value
+// in case of leave. Otherwise crashes e.g. in CSIPSecCredentials::Content that
+// expects iAuthorizationHeader to exist.
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::CreateContentL( CSIPSecChallenge& aChallenge )
+ {
+ TBool hasType = aChallenge.Type() == CSIPSecDigest::EEndPoint ||
+ aChallenge.Type() == CSIPSecDigest::EProxy;
+ __ASSERT_ALWAYS( hasType, User::Leave( KErrArgument ) );
+
+ // Create a new authorization header
+ CSIPAuthorizationHeaderBase* authorization( NULL );
+ RStringF digest = SIPStrings::Pool().OpenFStringL( KSIPSecDigestScheme );
+ CleanupClosePushL( digest );
+
+ if ( aChallenge.Type() == CSIPSecDigest::EEndPoint )
+ {
+ authorization = CSIPAuthorizationHeader::NewL( digest );
+ }
+ else
+ {
+ authorization = CSIPProxyAuthorizationHeader::NewL( digest );
+ }
+
+ CleanupStack::PopAndDestroy(); // digest
+ CleanupStack::PushL( authorization );
+
+ if ( aChallenge.HasQop() )
+ {
+ RStringF qop =
+ SIPStrings::Pool().OpenFStringL( aChallenge.QopDescriptor() );
+ CleanupClosePushL( qop );
+ authorization->SetParamL( SIPStrings::StringF( SipStrConsts::EQop ),
+ qop );
+ CleanupStack::PopAndDestroy(); // qop
+ }
+
+ CleanupStack::Pop( authorization );
+ delete iAuthorizationHeader;
+ iAuthorizationHeader = authorization;
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::UpdateContentL
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::UpdateContentL( TSIPSecDigestCtxSetup& aContext )
+ {
+ aContext.SetDesParamValueL( SipStrConsts::EUserName,
+ aContext.UserData().UserName() );
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::SetNonceCountL
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::SetNonceCountL( TUint aNonceCount )
+ {
+ iNonceCount = aNonceCount;
+
+ const TInt KNonceCountLength = 8;
+ TBuf8< KNonceCountLength > ncDescr;
+ ncDescr.NumFixedWidth( iNonceCount, EHex, KNonceCountLength );
+
+ TSIPSecDigestContext::SetParamValueL( Content(),
+ SipStrConsts::ENonceCount,
+ ncDescr );
+ }
+
+// -----------------------------------------------------------------------------
+// CSIPSecCredentials::UpdateContentL
+// Increment nonce count and set Request-URI.
+// -----------------------------------------------------------------------------
+//
+void CSIPSecCredentials::UpdateContentL( TSIPSecDigestCtxProcess& aContext )
+ {
+ if ( iChallenge->HasQop() )
+ {
+ SetNonceCountL( iNonceCount + 1 );
+ }
+
+ TSIPSecPluginCtxRequest& parent =
+ static_cast<TSIPSecPluginCtxRequest&>( aContext.Parent() );
+ HBufC8* requestURI = parent.SIPRequest().RequestURI()->ToTextL();
+ CleanupStack::PushL( requestURI );
+
+ aContext.SetParamValueL( SipStrConsts::EUri, *requestURI );
+ CleanupStack::PopAndDestroy( requestURI );
+ }