realtimenetprots/sipfw/SIP/SIPSec/DigestPlugin/src/CSIPSecChallengeMD5.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          : CSIPSecChallengeMD5.cpp
       
    15 // Part of       : SIPSec/DigestPlugin
       
    16 // Version       : SIP/6.0
       
    17 //
       
    18 
       
    19 
       
    20 
       
    21 #include <hash.h>
       
    22 #include <e32math.h>
       
    23 #include "SipLogs.h"
       
    24 #include "CSIPSecChallengeMD5.h"
       
    25 #include "sipsecrequestdata.h"
       
    26 #include "CSIPSecUserRecord.h"
       
    27 #include "sipsecdigestcontext.h"
       
    28 #include "sipstrings.h"
       
    29 #include "sipstrconsts.h"
       
    30 
       
    31 
       
    32 // ============================ MEMBER FUNCTIONS ===============================
       
    33 
       
    34 // -----------------------------------------------------------------------------
       
    35 // CSIPSecChallengeMD5::CSIPSecChallengeMD5
       
    36 // -----------------------------------------------------------------------------
       
    37 //
       
    38 CSIPSecChallengeMD5::CSIPSecChallengeMD5( CSIPSecDigest::TChallengeType aType,
       
    39 										  CSIPSecRequestData::TQop aQop ) :
       
    40 	CSIPSecChallenge( aType, aQop )
       
    41     {
       
    42     }
       
    43 
       
    44 // -----------------------------------------------------------------------------
       
    45 // CSIPSecChallengeMD5::NewLC
       
    46 // -----------------------------------------------------------------------------
       
    47 //
       
    48 CSIPSecChallengeMD5*
       
    49 CSIPSecChallengeMD5::NewLC( CSIPSecDigest::TChallengeType aType,
       
    50                             CSIPAuthenticateHeaderBase& aAuthenticateHeader,
       
    51                             CSIPSecRequestData::TQop aQop )
       
    52     {
       
    53 	CSIPSecChallengeMD5* self = new( ELeave )CSIPSecChallengeMD5( aType, aQop );
       
    54 	CleanupStack::PushL( self );
       
    55 	self->ConstructL( aAuthenticateHeader );	
       
    56 	return self;
       
    57 	}
       
    58 
       
    59 // -----------------------------------------------------------------------------
       
    60 // CSIPSecChallengeMD5::~CSIPSecChallengeMD5
       
    61 // -----------------------------------------------------------------------------
       
    62 //
       
    63 CSIPSecChallengeMD5::~CSIPSecChallengeMD5()
       
    64     {
       
    65     }
       
    66 
       
    67 // -----------------------------------------------------------------------------
       
    68 // CSIPSecChallengeMD5::VerifyTypeL
       
    69 // -----------------------------------------------------------------------------
       
    70 //
       
    71 void CSIPSecChallengeMD5::VerifyTypeL( CSIPSecUserRecord::TType aType ) const
       
    72 	{
       
    73 	__ASSERT_ALWAYS( aType == CSIPSecUserRecord::EIETF,
       
    74         			 User::Leave( KErrPermissionDenied ) );
       
    75 	}
       
    76 
       
    77 // -----------------------------------------------------------------------------
       
    78 // CSIPSecChallengeMD5::CreateUserRecordL
       
    79 // -----------------------------------------------------------------------------
       
    80 //
       
    81 CSIPSecUserRecord*
       
    82 CSIPSecChallengeMD5::CreateUserRecordL( const TDesC8& aRealm,
       
    83 										const MSIPSecUser& aUser,
       
    84 										TRegistrationId aRegistrationId,
       
    85 									    TTransactionId aTransactionId,
       
    86 									    TUint /*aResponseCode*/ ) const
       
    87 	{
       
    88 	return CSIPSecUserRecord::NewL( aRealm,
       
    89 									aUser,
       
    90 									aRegistrationId,
       
    91 									aTransactionId );
       
    92 	}
       
    93 			
       
    94 // -----------------------------------------------------------------------------
       
    95 // CSIPSecChallengeMD5::SupportedAlgorithm
       
    96 // -----------------------------------------------------------------------------
       
    97 //
       
    98 RStringF CSIPSecChallengeMD5::SupportedAlgorithm()
       
    99     {    
       
   100     return SIPStrings::StringF( SipStrConsts::EMD5 );
       
   101     }
       
   102 
       
   103 // -----------------------------------------------------------------------------
       
   104 // CSIPSecChallengeMD5::AlgorithmName
       
   105 // -----------------------------------------------------------------------------
       
   106 //
       
   107 RStringF CSIPSecChallengeMD5::AlgorithmName() const
       
   108     {
       
   109     return CSIPSecChallengeMD5::SupportedAlgorithm();
       
   110     }
       
   111 
       
   112 // -----------------------------------------------------------------------------
       
   113 // CSIPSecChallengeMD5::ProcessResponseL
       
   114 // -----------------------------------------------------------------------------
       
   115 //
       
   116 TBool CSIPSecChallengeMD5::ProcessResponseL( TSIPSecDigestCtxSetup& aContext,
       
   117 									   		 TBool& aAskCredentials ) const
       
   118     {
       
   119     aAskCredentials = EFalse;
       
   120     if ( aContext.UserData().IsValid() )
       
   121         {
       
   122         if ( aContext.UserData().SecretData().Length() == 0 )
       
   123             {
       
   124             CalculateSecretDataA1L( aContext );
       
   125             }
       
   126         return EFalse;
       
   127         }
       
   128 
       
   129     aAskCredentials = aContext.RequestUserCredentialsL();
       
   130     return ETrue;
       
   131     }
       
   132 
       
   133 // -----------------------------------------------------------------------------
       
   134 // CSIPSecChallengeMD5::ProcessRequestL
       
   135 // -----------------------------------------------------------------------------
       
   136 //
       
   137 void
       
   138 CSIPSecChallengeMD5::ProcessRequestL( TSIPSecDigestCtxProcess& aContext ) const
       
   139     {
       
   140     __SIP_LOG( "SIPSecChallMD5:ProcessRequestL" )
       
   141 
       
   142     HBufC8* response = RequestDigestL( aContext );
       
   143     CleanupStack::PushL( response );
       
   144 
       
   145 	__SIP_LOG( "response computed" )
       
   146 
       
   147     aContext.SetResponseL( response->Des() );
       
   148     CleanupStack::PopAndDestroy( response );
       
   149     
       
   150     __SIP_LOG( "SIPSecChallMD5:ProcessRequestL ends" )
       
   151     }
       
   152 
       
   153 // -----------------------------------------------------------------------------
       
   154 // CSIPSecChallengeMD5::RequestDigestL
       
   155 // -----------------------------------------------------------------------------
       
   156 //
       
   157 HBufC8*
       
   158 CSIPSecChallengeMD5::RequestDigestL( TSIPSecDigestCtxProcess& aContext ) const
       
   159     {
       
   160     CMD5& messageDigest = aContext.Mechanism().MessageDigest();            
       
   161     HBufC8* a2buf = CalculateA2L( aContext );
       
   162     CleanupStack::PushL( a2buf );
       
   163 
       
   164     const TDesC8& secretData = aContext.UserData().SecretData();    
       
   165     const TDesC8& nonce 	 = aContext.Nonce();
       
   166     const TDesC8& nonceCount = aContext.NonceCount();    
       
   167     const TDesC8& cnonce 	 = aContext.CNonce();
       
   168     const TDesC8& a2 		 = a2buf->Des();        
       
   169 	const TDesC8& qop 		 = QopDescriptor();
       
   170 
       
   171 	const TInt KSeparatorCharacters = 2;
       
   172 	TInt dataSize = secretData.Length() +
       
   173 					nonce.Length() +
       
   174 					a2.Length() +
       
   175 					KSeparatorCharacters;
       
   176     if ( HasQop() )
       
   177         {
       
   178         const TInt KAdditionalSeparatorCharacters = 3;
       
   179 
       
   180         dataSize += nonceCount.Length();
       
   181         dataSize += cnonce.Length();
       
   182         dataSize += qop.Length();        
       
   183         dataSize += KAdditionalSeparatorCharacters;
       
   184         }
       
   185 
       
   186     // Create response for hashing
       
   187     HBufC8* data = HBufC8::NewLC( dataSize );
       
   188 
       
   189     if ( HasQop() )
       
   190         {
       
   191         _LIT8( KSIPSecResponsePattern, "%S:%S:%S:%S:%S:%S" );
       
   192         data->Des().AppendFormat( KSIPSecResponsePattern,
       
   193          					      &secretData,
       
   194          					      &nonce,
       
   195          					      &nonceCount,
       
   196          					      &cnonce,
       
   197          					      &qop,
       
   198          					      &a2 );
       
   199         }
       
   200     else
       
   201         {
       
   202         _LIT8( KSIPSecResponsePatternAssumed, "%S:%S:%S" );
       
   203         data->Des().AppendFormat( KSIPSecResponsePatternAssumed,
       
   204         						  &secretData,
       
   205         						  &nonce,
       
   206         						  &a2 );
       
   207         }
       
   208 
       
   209     // Create response hash
       
   210     HBufC8* response = HashL( messageDigest, data->Des() );
       
   211 
       
   212     CleanupStack::PopAndDestroy( data );
       
   213     CleanupStack::PopAndDestroy( a2buf );
       
   214 
       
   215     return response;        
       
   216     }
       
   217 
       
   218 // -----------------------------------------------------------------------------
       
   219 // CSIPSecChallengeMD5::GenerateCNonceL
       
   220 // -----------------------------------------------------------------------------
       
   221 //
       
   222 void
       
   223 CSIPSecChallengeMD5::GenerateCNonceL( TSIPSecDigestCtxSetup& aContext ) const
       
   224     {
       
   225 #ifdef CPPUNIT_TEST
       
   226 	// Use a known CNonce value in unit testing
       
   227 	_LIT8( KDummyCNonce, "0a4f113b" );
       
   228     aContext.SetCNonceL( KDummyCNonce );
       
   229 #else
       
   230     TTime time;
       
   231     time.HomeTime();
       
   232 
       
   233     TInt64 timeKey = time.Int64();
       
   234     CMD5& messageDigest = aContext.Mechanism().MessageDigest();
       
   235 
       
   236     // Append also some other data to keyBuf and increase size of KBufLength
       
   237 
       
   238     // Long enough to hold the decimal representation of TInt64
       
   239     const TInt KBufLength = 20;
       
   240     TBuf8< KBufLength > keyBuf;
       
   241 	keyBuf.AppendNum( static_cast< TInt64 >( Math::Rand( timeKey ) ) );
       
   242 
       
   243     HBufC8* cnonce = HashL( messageDigest, keyBuf );
       
   244     CleanupStack::PushL( cnonce );
       
   245 
       
   246     aContext.SetCNonceL( cnonce->Des() );
       
   247     CleanupStack::PopAndDestroy( cnonce );
       
   248 #endif
       
   249     }
       
   250 
       
   251 // -----------------------------------------------------------------------------
       
   252 // CSIPSecChallengeMD5::CalculateA2L
       
   253 // -----------------------------------------------------------------------------
       
   254 //
       
   255 HBufC8*
       
   256 CSIPSecChallengeMD5::CalculateA2L( TSIPSecDigestCtxProcess& aContext ) const
       
   257     {
       
   258     CMD5& messageDigest = aContext.Mechanism().MessageDigest();
       
   259     CSIPSecRequestData* requestData = aContext.RequestDataL( Qop() );
       
   260     CleanupStack::PushL( requestData );
       
   261 
       
   262     HBufC8* dataA2 = HBufC8::NewLC( requestData->Size() );
       
   263     
       
   264     while ( !requestData->EndOfData() )
       
   265         {
       
   266         RSIPSecRequestDataField field = requestData->NextL();
       
   267         CleanupClosePushL( field );
       
   268 
       
   269         if ( field.NeedsHashing() )
       
   270             {
       
   271             HBufC8* hashBuf = HashL( messageDigest, field.Value() );
       
   272             dataA2->Des().Append( hashBuf->Des() );
       
   273             delete hashBuf;
       
   274             }
       
   275         else
       
   276             {
       
   277             dataA2->Des().Append( field.Value() );
       
   278             }
       
   279 
       
   280         dataA2->Des().Append( requestData->Separator() );
       
   281 
       
   282         CleanupStack::PopAndDestroy(); // field
       
   283         }
       
   284 
       
   285     HBufC8* a2 = HashL( messageDigest, dataA2->Des() );
       
   286 
       
   287     CleanupStack::PopAndDestroy( dataA2 );
       
   288     CleanupStack::PopAndDestroy( requestData );
       
   289     return a2;
       
   290     }
       
   291 
       
   292 // -----------------------------------------------------------------------------
       
   293 // CSIPSecChallengeMD5::CalculateSecretDataA1L
       
   294 // -----------------------------------------------------------------------------
       
   295 //
       
   296 void CSIPSecChallengeMD5::CalculateSecretDataA1L(
       
   297 	TSIPSecDigestCtxSetup& aContext ) const
       
   298     {
       
   299     _LIT8( KSIPSecA1Pattern, "%S:%S:%S" );
       
   300 
       
   301     CMD5& messageDigest    = aContext.Mechanism().MessageDigest();
       
   302     const TDesC8& realm    = aContext.UserData().Realm();
       
   303     const TDesC8& username = aContext.UserData().UserName();
       
   304     const TDesC8& password = aContext.UserData().Password();
       
   305 
       
   306 	TInt dataSize = realm.Length() +
       
   307 					username.Length() +
       
   308          	        password.Length() +
       
   309          	        KSIPSecA1Pattern().Length();
       
   310     HBufC8* data = HBufC8::NewLC( dataSize );
       
   311     data->Des().AppendFormat( KSIPSecA1Pattern, &username, &realm, &password );
       
   312 
       
   313     HBufC8* secretData = HashL( messageDigest, data->Des() );
       
   314 
       
   315     CleanupStack::PopAndDestroy( data );
       
   316     aContext.UserData().SetSecretData( secretData );
       
   317     }
       
   318 
       
   319 // -----------------------------------------------------------------------------
       
   320 // CSIPSecChallengeMD5::HashL
       
   321 // -----------------------------------------------------------------------------
       
   322 //
       
   323 HBufC8* CSIPSecChallengeMD5::HashL( CMD5& aDigest, TPtrC8 aData ) const
       
   324     {
       
   325     const TInt KHexSize = 2;
       
   326     TPtrC8 hash = aDigest.Hash( aData );
       
   327     TInt hashSize = aDigest.HashSize();
       
   328     TInt bufLength = hashSize * KHexSize;
       
   329 
       
   330     HBufC8* buf = HBufC8::NewL( bufLength );
       
   331     TPtr8 ptr( buf->Des() );
       
   332     TBuf8< KHexSize > hexChar;
       
   333 
       
   334     for ( TInt i = 0; i < hashSize; i++ )
       
   335 		{
       
   336 		hexChar.NumFixedWidth( hash[ i ], EHex, KHexSize );
       
   337 		ptr.Append( hexChar );
       
   338 		}
       
   339 
       
   340     aDigest.Reset();
       
   341 	return buf;
       
   342     }