diff -r 000000000000 -r 72b543305e3a email/imap4mtm/imapsession/src/cimapauthhelpers.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/email/imap4mtm/imapsession/src/cimapauthhelpers.cpp Thu Dec 17 08:44:11 2009 +0200 @@ -0,0 +1,518 @@ +// 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: +// IMAPAUTHHELPERS.CPP +// +// + +#include "cimapauthhelpers.h" +#include "cimaputils.h" // forward declarations for utility fns +#include "cimaplogger.h" +#include "moutputstream.h" +#include "cimapsessionconsts.h" +#include + + +// IMAP LOGIN command +_LIT8(KCommandAuthenticateCrammd5, "%d AUTHENTICATE CRAM-MD5\r\n"); +_LIT8(KCommandAuthenticatePlain, "%d AUTHENTICATE PLAIN "); +_LIT8(KCommandAuthenticateLogin, "%d AUTHENTICATE LOGIN\r\n"); +_LIT8(KImapAuthBase64StringUsername,"username*"); // To match a folded 'username:' or 'username' +_LIT8(KImapAuthBase64StringPassword,"password*"); // To match a folded 'password:' or 'password' + +const TInt KMaxLengthOfPlainMessageComponent = 255; +const TInt KMd5BlockLength = 64; + +#define BASE64LEN(x) ((x*4)/3) // Every 3 bytes will be turned into 4 bytes + +const TInt KPreambleLength = 18; //"AUTH LOGIN\r\nPLAIN " +const TInt KMaxLengthOfPlainMessage= KPreambleLength + 1/*NUL*/ + KMaxLengthOfPlainMessageComponent/*Username*/ + 1/*NUL*/ + KMaxLengthOfPlainMessageComponent/*Password*/ + 2/* /r/n */; +const TInt KMaxLengthOfPlainMessageBase64= BASE64LEN(KMaxLengthOfPlainMessage); + + + + /** +Class constructor + +@param aImapSettings Settings for IMAP service +@param aSelectedFolderData Imap Folder Info +@param aLogId logging info +*/ + CImapAuthMechanismHelper::CImapAuthMechanismHelper(const CImapSettings& aSettings,CImapFolderInfo* aSelectedFolderData, TInt aLogId) : CImapCommandEx(aSelectedFolderData, aLogId),iSettings(aSettings){} + + +/** +Static factory constructor. Part of two phased construction. + +@param aImapSettings Settings for the Imap service +@param aSelectedFolderData Imap Folder Info +@param aLogId logging info +@return The constructed CImapAuthPlainMechanismHelper object +*/ +CImapAuthPlainMechanismHelper* CImapAuthPlainMechanismHelper::NewL(const CImapSettings& aSettings,CImapFolderInfo* aSelectedFolderData, TInt aLogId) + { + CImapAuthPlainMechanismHelper* self= new (ELeave) CImapAuthPlainMechanismHelper(aSettings,aSelectedFolderData,aLogId); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + + +/** +Class constructor + +@param aImapSettings Settings for IMAP service +@param aSelectedFolderData Imap Folder Info +@param aLogId logging info +*/ +CImapAuthPlainMechanismHelper::CImapAuthPlainMechanismHelper(const CImapSettings& aSettings,CImapFolderInfo* aSelectedFolderData, TInt aLogId) : CImapAuthMechanismHelper(aSettings,aSelectedFolderData, aLogId){} + +/** +Non-trival constructor. Part of two phased construction. +*/ +void CImapAuthPlainMechanismHelper::ConstructL(){} + + +/** +Formats and sends the IMAP AUTHENTICATE PLAIN command. +@param aTagId Command sequence id which will be send along with the IMAP command. +@param aStream A wrapper for the outbound stream of a connected socket, using which +the command will be send to the server +*/ +void CImapAuthPlainMechanismHelper::SendMessageL(TInt aTagId, MOutputStream& aStream) + { + iTagId = aTagId; + iStream = &aStream; + + iNextClientMessage.Zero(); + + // send Authenticate PLAIN command + TInt bufLength = KCommandAuthenticatePlain().Length(); + bufLength += TagLength(aTagId); + iNextClientMessage.Format(KCommandAuthenticatePlain, aTagId); + + // Build up the un-encoded authorisation string in parts + HBufC8* authString = HBufC8::NewMaxLC(KMaxLengthOfPlainMessage); + TPtr8 authStringPtr = authString->Des(); + + TBuf8<1> nul; + nul.SetLength(1); + nul[0] = 0; + + //Add Null to begining of auth string + authStringPtr = nul; + + //Get LoginName from central repository and append to auth string + TPtrC8 loginName = iSettings.LoginName(); + TInt length= Min(loginName.Length(),KMaxLengthOfPlainMessageComponent); + authStringPtr.Append(loginName.Left(length)); + + authStringPtr.Append(nul); // Separator between login and password + + //Get Password from central repository and append to auth string + length= Min(iSettings.Password().Length(), KMaxLengthOfPlainMessageComponent); + authStringPtr.Append(iSettings.Password().Left(length)); + + // Auth string is now built, + HBufC8* encodedBuf = HBufC8::NewMaxLC(KMaxLengthOfPlainMessageBase64); + TPtr8 encodedBufPtr = encodedBuf->Des(); + + //Encode string + iEncoder.Encode(authStringPtr,encodedBufPtr); + + // Now build the message + iNextClientMessage.Append(encodedBufPtr); + iNextClientMessage.Append(KImapTxtCrlf); + + //send the command to the server + aStream.SendDataReq(iNextClientMessage); + + CleanupStack::PopAndDestroy(2,authString); + } + + +/** +Respond upon reciept of a continuation response from server. +*/ +void CImapAuthPlainMechanismHelper::ParseContinuationResponseL(){} + +/** +Static factory constructor. Part of two phased construction. + +@param aImapSettings Settings for the Imap service +@param aSelectedFolderData Imap Folder Info +@param aLogId logging info +@return The constructed CImapAuthLoginMechanismHelper object +*/ +CImapAuthLoginMechanismHelper* CImapAuthLoginMechanismHelper::NewL(const CImapSettings& aSettings,CImapFolderInfo* aSelectedFolderData, TInt aLogId) + { + CImapAuthLoginMechanismHelper* self= new (ELeave) CImapAuthLoginMechanismHelper(aSettings,aSelectedFolderData,aLogId); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +/** +Class constructor + +@param aImapSettings Settings for IMAP service +@param aSelectedFolderData Imap Folder Info +@param aLogId logging info +*/ +CImapAuthLoginMechanismHelper::CImapAuthLoginMechanismHelper(const CImapSettings& aSettings,CImapFolderInfo* aSelectedFolderData, TInt aLogId) : CImapAuthMechanismHelper(aSettings,aSelectedFolderData, aLogId){} + +/** +Class destructor +*/ +CImapAuthLoginMechanismHelper::~CImapAuthLoginMechanismHelper() + { + delete iBase64LoginName; + delete iBase64Password; + } + +/** +Non-trival constructor. Part of two phased construction. +Creates Base64 Username and Password +*/ +void CImapAuthLoginMechanismHelper::ConstructL() + { + //Get LoginName from central repository + TInt len=(((iSettings.LoginName().Length()/3)+1)*4)+2; // length of LoginName in base 64 + 2 for CRLF + iBase64LoginName=HBufC8::NewL(len); + TPtr8 authString(iBase64LoginName->Des()); + + //Encode LoginName + iEncoder.Encode(iSettings.LoginName(),authString); + //Append CRLF to authstring + authString.Append(KImapTxtCrlf); + + //Get Password from central repository + len=(((iSettings.Password().Length()/3)+1)*4)+2; // length of Password in base 64 + 2 for CRLF + iBase64Password=HBufC8::NewL(len); + authString.Set(iBase64Password->Des()); + + //Encode Password Name + iEncoder.Encode(iSettings.Password(),authString); + //Append CRLF to authstring + authString.Append(KImapTxtCrlf); + } + + +/** +Formats and sends the IMAP AUTHENTICATE LOGIN command. +@param aTagId Command sequence id which will be send along with the IMAP command. +@param aStream A wrapper for the outbound stream of a connected socket, using which +the command will be send to the server +*/ +void CImapAuthLoginMechanismHelper::SendMessageL(TInt aTagId, MOutputStream& aStream) + { + + iTagId = aTagId; + iStream = &aStream; + + TInt bufLength = KCommandAuthenticateLogin().Length(); + + //Add tagId to buffer + bufLength += TagLength(aTagId); + + // Create Authenticate LOGIN command message + iOutputBuffer = HBufC8::NewL(bufLength); + iOutputBuffer->Des().Format(KCommandAuthenticateLogin, aTagId); + + //send the command to the server + aStream.SendDataReq(*iOutputBuffer); + } + +/** +Sends the Encoded Username message using Login, upon reciept of a continuation response from server. +The next line Encoded Password message will be sent upon reciept of a continuation response from server, indicating that the first line has been succesfully sent. +*/ + +void CImapAuthLoginMechanismHelper::ParseContinuationResponseL() + { + + iNextClientMessage.Zero(); + + //Get next part of the response from server + TPtrC8 part = GetNextPart(); + + HBufC8* decodedMessage = NULL; + + decodedMessage = HBufC8::NewLC(KImMailMaxBufferSize); + if (decodedMessage) + { + TPtr8 decodedMessagePtr = decodedMessage->Des(); + + //Decode Server response + iEncoder.Decode(part, decodedMessagePtr); + } + + switch (iState) + { + case ESendingLoginName: + if (decodedMessage) + { + // Match against 'username*' + if (decodedMessage->Des().MatchF(KImapAuthBase64StringUsername) == KErrNotFound) + { + User::Leave(KErrNotSupported); + } + //Initialise encoder + iEncoder.Initialise(); + + //Copy Base64 LoginName to buffer + iNextClientMessage=*iBase64LoginName; + + //Change state to ESendingPassword + iState = ESendingPassword; + } + else + { + User::Leave(KErrNotSupported); + } + break; + case ESendingPassword: + if (decodedMessage) + { + // Match against 'password*' + if (decodedMessage->Des().MatchF(KImapAuthBase64StringPassword) == KErrNotFound) + { + User::Leave(KErrNotSupported); + } + + //Copy Base64 Password to buffer + iNextClientMessage=*iBase64Password; + } + else + { + User::Leave(KErrNotSupported); + } + break; + default: + User::Leave(KErrNotSupported); + break; + } + + if (decodedMessage) + { + CleanupStack::PopAndDestroy(decodedMessage); + } + + //send the command to the server + iStream->SendDataReq(iNextClientMessage); + } + +/** +Static factory constructor. Part of two phased construction. + +@param aImapSettings Settings for the Imap service +@param aSelectedFolderData Imap Folder Info +@param aLogId logging info +@return The constructed CImapAuthCramMd5MechanismHelper object +*/ +CImapAuthCramMd5MechanismHelper* CImapAuthCramMd5MechanismHelper::NewL(const CImapSettings& aSettings,CImapFolderInfo* aSelectedFolderData, TInt aLogId) + { + CImapAuthCramMd5MechanismHelper* self= new (ELeave) CImapAuthCramMd5MechanismHelper(aSettings,aSelectedFolderData,aLogId); + CleanupStack::PushL(self); + self->ConstructL(); + CleanupStack::Pop(); + return self; + } + +/** +Class constructor + +@param aImapSettings Settings for IMAP service +@param aSelectedFolderData Imap Folder Info +@param aLogId logging info +*/ +CImapAuthCramMd5MechanismHelper::CImapAuthCramMd5MechanismHelper(const CImapSettings& aSettings,CImapFolderInfo* aSelectedFolderData, TInt aLogId) :CImapAuthMechanismHelper(aSettings,aSelectedFolderData, aLogId){} + +/** +Non-trival constructor. Part of two phased construction. +Constructs md5 +*/ +void CImapAuthCramMd5MechanismHelper::ConstructL() + { + //Create Md5 + iMd5Hash = CMD5::NewL(); + } + +CImapAuthCramMd5MechanismHelper::~CImapAuthCramMd5MechanismHelper() + { + //Delete Md5 object + delete iMd5Hash; + } + +/** +Formats and sends the IMAP AUTHENTICATE CRAM-MD5 command. +@param aTagId Command sequence id which will be send along with the IMAP command. +@param aStream A wrapper for the outbound stream of a connected socket, using which +the command will be send to the server +*/ +void CImapAuthCramMd5MechanismHelper::SendMessageL(TInt aTagId, MOutputStream& aStream) + { + + iTagId = aTagId; + iStream = &aStream; + + TInt bufLength = KCommandAuthenticateCrammd5().Length(); + + //Add tagId to buffer + bufLength += TagLength(aTagId); + + // Create Authenticate CRAM-MD5 command message + iOutputBuffer = HBufC8::NewL(bufLength); + iOutputBuffer->Des().Format(KCommandAuthenticateCrammd5, aTagId); + + //send the command to the server + aStream.SendDataReq(*iOutputBuffer); + } + + +/**Creates Shared secret Key between client and server +@param aPassword +*/ +TPtr8 CImapAuthCramMd5MechanismHelper::FormSharedSecret(TPtr8 aPassword) + { + TPtr8 secret = aPassword; + + if (aPassword.Length() <= KMd5BlockLength) + { + //pad up to 64 bytes with zeros + secret.SetLength(64); + TInt origLen = aPassword.Length(); + TInt lengthToFill = KMd5BlockLength-aPassword.Length(); + for (TInt i = 0; iReset(); + + //Hash Md5 + secret = (iMd5Hash->Hash(aPassword)); + } + + return secret; + } + + +/** +Sends the Encoded Username and password message using CRAM-MD5, upon reciept of a continuation response from server. +*/ +void CImapAuthCramMd5MechanismHelper::ParseContinuationResponseL() + { + + //Sets the length of the data to zero. + iNextClientMessage.Zero(); + + //Get next part of the response from server + TPtrC8 part = GetNextPart(); + __LOG_FORMAT((iLogId, "CImapCommand::ParseBlockL(): [%S] %d octets", &part, part.Length())); + + //Create Cram-md5 Base64 message + HBufC8* authbuffer = HBufC8::NewMaxLC(KImMailMaxBufferSize); + TPtr8 authbufferptr = authbuffer->Des(); + HBufC8* authbuffer2 = HBufC8::NewMaxLC(KImMailMaxBufferSize); + TPtr8 authbufferptr2 = authbuffer2->Des(); + HBufC8* authbuffer3 = HBufC8::NewMaxLC(KImMailMaxBufferSize); + TPtr8 authbufferptr3 = authbuffer3->Des(); + + //copy server response to buffer + authbufferptr = part; + + //Decode Server response,timestamp info now in authbufferptr2 + iEncoder.Decode(authbufferptr,authbufferptr2); + + //Sets the length of the data to zero. + authbufferptr.Zero(); + authbufferptr3.Zero(); + + //Get Password from Central repository + authbufferptr = iSettings.Password(); + + //Create Shared secrete key + authbufferptr3 = FormSharedSecret(authbufferptr); + + //Sets the length of the data to zero. + authbufferptr.Zero(); + + // authbufferptr and authbufferptr3 contain the shared secret null padded to 64 bytes. + authbufferptr = authbufferptr3; + TInt i=0; + for (i=0; iReset(); ; + + //Hash Md5 ; + authbufferptr2 = iMd5Hash->Hash(authbufferptr); + + authbufferptr3.Append(authbufferptr2); + authbufferptr.Zero(); + + //Reset Md5 + iMd5Hash->Reset(); + + //Hash Md5 + authbufferptr = iMd5Hash->Hash(authbufferptr3); + + // MD5 algorithm ALWAYS returns 16 bytes of data - which will be converted into + // 32 characters; each byte represented by a 2 character hex representation, + // eg 255="ff" + + TBuf<32> hexHash; + for (i=0;i<16;i++) + { + hexHash.AppendNumFixedWidth(authbufferptr[i],EHex,2); + } + + authbufferptr3.Zero(); + + //Get LoginName from Central repository + authbufferptr3.Append(iSettings.LoginName()); + + //Add Space to authbufferptr3 + authbufferptr3.Append(_L8(" ")); + + //Append hexHash authbufferptr3 + authbufferptr3.Append(hexHash); + + //Encode Cram-md5 message + iEncoder.Encode(authbufferptr3, iNextClientMessage); + + //Append CRLF to iNextClientMessage + iNextClientMessage.Append(KImapTxtCrlf); + + CleanupStack::PopAndDestroy(3); // authbufferptr3 ,authbufferptr2, authbufferptr + + //send the command to the server + iStream->SendDataReq(iNextClientMessage); + } +