vpnengine/ikev1lib/src/ikev1trans.cpp
changeset 0 33413c0669b9
child 22 9f4e37332ce5
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/ikev1lib/src/ikev1trans.cpp	Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,1148 @@
+/*
+* Copyright (c) 2005-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: IKE transaction exchange implementation.
+*
+*/
+
+/**-------------------------------------------------------------------
+ *
+ * Class CTransNegotiation
+ * This class is used to handle ISAKMP Transaction exchange messages.
+ * Transaction exchange has been defined in the IETF draft which specifies
+ * The ISAKMP Configuration Method <draft-dukes-ike-mode-cfg-01.txt>.
+ * This same two message configuration transaction is also used in IETF draft
+ * Extended Authentication within IKE (XAUTH) <draft-beaulieu-ike-xauth-02.txt>.
+ * CTransNegotiation class implements these IETF drafts, too.
+ *
+ *--------------------------------------------------------------------*/
+
+#include "ikev1trans.h"
+#include "ikedebug.h"
+#include "ikev1pluginsession.h"
+#include "ikev1negotiation.h"
+#include "ikev1payload.h"
+#include "ikev1timeout.h"
+#include "ikev1crack.h"
+#include "ikev1isakmpstream.h"
+#include "ikev1crypto.h"
+
+const TUint8  XAUTH_VID_DATA[8] = {0x09, 0x00, 0x26, 0x89, 0xdf, 0xd6, 0xb7, 0x12};
+const TUint8  CISCO_UNITY_VID_DATA[16] = {0x12, 0xf5, 0xf2, 0x8c, 0x45, 0x71, 0x68, 0xa9,
+                                          0x70, 0x2d, 0x9f, 0xe2, 0x74, 0xcc, 0x01, 0x00};
+                                          
+                                          
+CTransNegotiation::CTransNegotiation( TInt aGranularity,
+                                      TBool aUseXauth,
+                                      TBool aUseCfgMode, 
+                                      CIkev1PluginSession* aPluginSession,
+                                      CIkev1Negotiation* aNegotiation,
+                                      MIkeDebug& aDebug ) 
+    :CArrayFixFlat<TTransExchange*>(aGranularity),
+     iPluginSession(aPluginSession),
+     iNegotiation(aNegotiation),
+     iUseXauth(aUseXauth),
+     iUseCfgMode(aUseCfgMode),
+     iDebug(aDebug)
+{
+}
+                                          
+                                          
+/**-------------------------------------------------------------------
+ *
+ * Method New()
+ * Creates an instance of CTransNegotiation class if either 
+ * usage of XAUTH or CFG-MODE has been requested.
+ *
+ *--------------------------------------------------------------------*/
+CTransNegotiation* CTransNegotiation::NewL(TBool aUseXauth, TBool aUseCfgMode,
+                                           CIkev1PluginSession* aPluginSession, 
+                                           CIkev1Negotiation* aNegotiation,
+                                           MIkeDebug& aDebug )
+{    
+    CTransNegotiation* Neg = new (ELeave) CTransNegotiation( 1,
+                                                             aUseXauth,
+                                                             aUseCfgMode,
+                                                             aPluginSession,
+                                                             aNegotiation,
+                                                             aDebug );
+    CleanupStack::PushL(Neg);
+    Neg->ConstructL();
+    CleanupStack::Pop(Neg);
+    return Neg;        
+}
+/**-------------------------------------------------------------------
+ *
+ * Deconstruct method
+ *
+ *--------------------------------------------------------------------*/
+CTransNegotiation::~CTransNegotiation()
+{
+    DEBUG_LOG(_L("Transaction exchange object deleted"));  
+        
+    delete iInternalAddr;
+    delete iDialog;
+    delete iDialogInfo;
+	delete iUserName; 	
+            
+    for ( TInt i = 0; i < Count(); i++ )
+    {
+        delete At(i);
+    }
+}
+
+/**-------------------------------------------------------------------
+ *
+ * Method ConstructL()
+ * -- Links CKmdEngine- and CNegotiation object pointers to CTransNegotiation
+ * -- If only CONFIG-MODE requested, start corresponding transaction exchange.
+ *
+ *--------------------------------------------------------------------*/
+void CTransNegotiation::ConstructL()
+{
+    if ( !iPluginSession || !iNegotiation || (!iUseXauth && !iUseCfgMode)) 
+    {
+        User::Leave(KErrArgument);   
+    }
+       
+    DEBUG_LOG(_L("Transaction exchange object constructed"));  
+    if ( !iUseXauth ) 
+    {
+       iXauthCompleted = ETrue;
+       iNegotiation->iTimer->Cancel();  // Stop retransmission timer   
+    }
+    else 
+    {
+       if ( !iUseCfgMode ) 
+           iCfgModeCompleted = ETrue;
+       DEBUG_LOG(_L("Starting to Wait XAUTH request"));  
+    }    
+}
+
+/**-------------------------------------------------------------------
+ *
+ * Method GetAuthMethod()
+ * This static method converts the authentication method value from
+ * "normal" IKE attribute value (specified in RFC2409) to the attribute
+ * value indicate XAUTH usage after IKE phase 1. This conversion is done
+ * into the opposite direction when call parameter (aAuthMethod) have
+ * already value indicating Xauth usage.
+ *
+ *--------------------------------------------------------------------*/
+TUint16 CTransNegotiation::GetAuthMethod(TUint16 aAuthMethod, TBool aXauthUsed, TInt aRole)
+{
+    if ( aXauthUsed ) {
+       if ( aAuthMethod >= XAUTHInitPreShared && aAuthMethod <= XAUTHRespRSARevisedEncr) {
+          aAuthMethod -= XAUTHMethodBase;
+          aAuthMethod = (TUint16)((aAuthMethod >> XAUTHScaler) | XAUTHScaler);
+       }
+       else {
+          if ( aAuthMethod >= PRE_SHARED && aAuthMethod <= RSA_REV_ENCR ) {
+             aAuthMethod = (TUint16)((aAuthMethod << XAUTHScaler) + XAUTHMethodBase);
+             if ( aRole == INITIATOR )
+                aAuthMethod -= XAUTHScaler;
+          }
+       }       
+    }
+    return aAuthMethod;
+}   
+
+/**-------------------------------------------------------------------
+ *
+ * Method BuildXauthVendorId()
+ * This method builds a XAUTH related Vendor ID payload and adds it into 
+ * the IKE message. The vendor id is specified in the draft
+ * <draft-beaulieu-ike-xauth-02.txt> and its content is the following:
+ * ["0x09002689DFD6B712"])
+ * Both ISAKMP mode-cfg and extended authentication (XAUTH) can be
+ * implemented in some VPN SGWs according to the older mode-cfg and
+ * xauth drafts:
+ * <draft-ietf-ipsec-isakmp-mode-cfg-04.txt> and
+ * <draft-ietf-ipsec-isakmp-xauth-04.txt>
+ *
+ *--------------------------------------------------------------------*/
+void CTransNegotiation::BuildXauthVendorId(TIkev1IsakmpStream &aMsg)
+{
+    TInetAddr DummyAddr;
+    
+    aMsg.IsakmpVendorId(IETF_NATT_VENDOR_ID,
+                        NULL, NULL, DummyAddr, // These parameters has no relevance with IETF_NATT_VID_DATA
+                        (TUint8*)XAUTH_VID_DATA, sizeof(XAUTH_VID_DATA));
+	
+	aMsg.IsakmpVendorId(IETF_NATT_VENDOR_ID,
+						NULL, NULL, DummyAddr, // These parameters has no relevance with IETF_NATT_VID_DATA
+						(TUint8*)CISCO_UNITY_VID_DATA,
+						sizeof(CISCO_UNITY_VID_DATA));
+}
+
+/**-------------------------------------------------------------------
+ *
+ * Method GetIV()
+ * Get IV for transaction exchange specified with message id parameter:
+ * Find corresponding exchange structure and copy IV to caller
+ * If no exchange found, return EFALSE status to indicate error.    
+ *
+ *--------------------------------------------------------------------*/
+TBool CTransNegotiation::GetIV(TUint32 aMsgId, TDes8& aIV)
+{
+    TBool status = ETrue;
+    TTransExchange *exchange = FindExchange(aMsgId);
+    if ( exchange )
+         aIV.Copy(exchange->iIV);
+    else status = EFalse;
+
+    return status;
+}   
+
+/**-------------------------------------------------------------------
+ *
+ * Method SetIV()
+ * Set IV for transaction exchange specified with message id parameter:
+ * Find corresponding exchange structure and store specified IV to
+ * exchange structure
+ * If no exchange found, return EFALSE status to indicate error.    
+ *
+ *--------------------------------------------------------------------*/
+TBool CTransNegotiation::SetIV(TUint32 aMsgId, TDes8& aIV)
+{
+    TBool status = ETrue;
+    TTransExchange *exchange = FindExchange(aMsgId);
+    if ( exchange )
+         exchange->iIV.Copy(aIV);
+    else status = EFalse;
+
+    return status;
+}   
+
+/**-------------------------------------------------------------------
+ *
+ * Method ProcessUserResponseL()
+ * ProcessUserResponseL() builds a XAUTH reply message from authentication
+ * credentials linked into the current CAuthDialogInfo object.
+ *
+ *--------------------------------------------------------------------*/
+TInt CTransNegotiation::ProcessUserResponseL(CAuthDialogInfo *aDialogInfo )
+{
+    //
+    // Find a transaction exchange structure for current message 
+    //
+    TInt lth = 0;
+    iCurrExchange = FindExchange(aDialogInfo->GetMsgId());
+    
+    if ( iCurrExchange && iRequestFlags ) {
+       //
+       // Allocate a buffer for Attribute payload.
+       // Calculate first required buffer length
+       //
+       if ( aDialogInfo->iUsername )    
+          lth += (aDialogInfo->iUsername->Length() + 4);
+       if ( aDialogInfo->iSecret )  
+          lth += (aDialogInfo->iSecret->Length() + 4);
+       
+       HBufC8 *attributes = HBufC8::NewL(lth + 4);
+       CleanupStack::PushL(attributes);
+       TPtr8 attr_ptr(attributes->Des());
+	   TUint16 AttrType;
+       
+       if ( iRequestFlags & (1 << (ATTR_PASSWORD - ATTR_XAUTH_TYPE)) ) {
+          //
+          // Add Xauth type attribute. Value is taken from current exchange structure
+          //
+		  if ( iUseOlderPIXXauth )
+			   AttrType = ATTR_PIX_XAUTH_TYPE;
+          else AttrType = ATTR_XAUTH_TYPE;						 
+          AddAttributeData(attr_ptr, AttrType, 2, (TUint8*)&iCurrExchange->iXauthType);
+       }
+       
+       if ( aDialogInfo->iUsername ) {
+          //
+          // Add user name attribute. 
+          //
+	      if ( iUseOlderPIXXauth )
+			   AttrType = ATTR_PIX_USER_NAME;
+		  else AttrType = ATTR_USER_NAME;						 
+		  
+          AddAttributeData(attr_ptr, AttrType, aDialogInfo->iUsername->Length(),
+                           (TUint8*)aDialogInfo->iUsername->Ptr());
+          //
+	      // Take a copy of user name buffer in dialog info. This user name
+	      // is cached into user name file if current CRACK negotiation is
+	      // succeeded
+	      //
+		  delete iUserName; // Delete old user name buffer for sure
+  	      iUserName = HBufC8::New(aDialogInfo->iUsername->Length() + 16); // 16 bytes space for padding
+		  if ( iUserName ) {
+		     iUserName->Des().Copy(aDialogInfo->iUsername->Des()); 
+		  } 	   
+       }
+
+       if ( aDialogInfo->iSecret ) {
+          //
+          // Add either password, passcode or next pin attribute.
+          // Check from iRequestFlags which one was requested by the gateway
+          //
+	      if ( iUseOlderPIXXauth )
+			   AttrType = ATTR_PIX_PASSWORD; // default;
+		  else AttrType = ATTR_PASSWORD; // default
+
+          switch ( iRequestFlags ) {
+
+              case (1 << (ATTR_PASSCODE - ATTR_XAUTH_TYPE)):
+				  if ( iUseOlderPIXXauth )
+					   AttrType = ATTR_PIX_PASSCODE;
+				  else AttrType = ATTR_PASSCODE;
+                  break;
+
+              case (1 << (ATTR_NEXT_PIN - ATTR_XAUTH_TYPE)):
+                  AttrType = ATTR_NEXT_PIN;
+                  break;
+
+              default:
+                  break;
+                   
+          }   
+          AddAttributeData(attr_ptr, AttrType, aDialogInfo->iSecret->Length(),
+                          (TUint8*)aDialogInfo->iSecret->Ptr());           
+       }
+       
+       BuildAndSendMessageL(attr_ptr, ISAKMP_CFG_REPLY);
+       
+       CleanupStack::PopAndDestroy(); //attributes 
+       
+       iRequestFlags = 0;
+
+    }
+    
+    delete iDialog;  // delete dialog object
+    delete aDialogInfo;  // release dialog info object  
+    iDialog = NULL;
+    iDialogInfo = NULL;  
+     
+    return TRANSACTION_CONTINUE;
+}   
+
+/**-------------------------------------------------------------------
+ *
+ * Method TransactionFailedL()
+ * TransactionFailedL() is called when a notificatio/delete payload 
+ * has been received in the middle of a transaction exchange.
+ *
+ *--------------------------------------------------------------------*/
+TInt CTransNegotiation::TransactionFailedL(const TNotificationISAKMP *aNotifPayload)
+{
+
+    (void)aNotifPayload;
+    iNegotiation->iTimer->Cancel();   //Cancel timer because authentication failed
+    DEBUG_LOG(_L("Transaction exchange stopped by the gateway!"));
+    // 
+    // Dialog object shall be delete in Dialog->RunL when dialog completed
+    //
+    CIkev1Dialog* Dialog  = CIkev1Dialog::NewL(iPluginSession, iPluginSession->DialogAnchor(), iDebug);
+    Dialog->ShowErrorDialogL(TVpnNoteDialog::EKmdAuthenticationFailed, NULL, NULL);
+    
+    return TRANSACTION_FAILED;
+}
+
+/**-------------------------------------------------------------------
+ *
+ * Method ExecuteL()
+ * Processes a received ISAKMP transaction exchange message.
+ * The received message MUST be an encrypted transaction exchange message
+ * otherwise it is silently discarded.
+ * Current TTransExchange structure is found, IV value calculated and
+ * ISAKMP message decrypted.
+ * TransactionExchangeL() method returns to the caller the following status codes:
+ * (Corresponding CRACK status codes  defined in ike_crack.h)
+ * -- TRANSACTION_SUCCESS (0) =
+ *    Transaction exchange(s) has been succesfully completed.
+ *    Normal operation can continue and CTransNegotiation object can be deleted.
+ * -- TRANSACTION_CONTINUE (1) =
+ *    Received message succesfully processed.
+ *    Transaction exchange(s) shall still continue. 
+ * -- TRANSACTION_IGNORE   (2) =
+ *    Received message ignored. Transaction exchange(s) shall still continue. 
+ * -- TRANSACTION_FAILED   (4) =
+ *    Transaction exchange(s) has been failed (either CONFIG-MODE or XAUTH).
+ *    Current CNegotiation object as well as CTransNegotiation object can
+ *    be deleted. (= corresponding ISAKMP phase 1 negotiation shall be deleted).
+ *
+ *--------------------------------------------------------------------*/
+#ifdef _DEBUG
+TInt CTransNegotiation::ExecuteL( const ThdrISAKMP& aHdr,
+                                  const TInetAddr& aSrcAddr,
+                                  TInt aLocalPort )
+#else
+TInt CTransNegotiation::ExecuteL( const ThdrISAKMP& aHdr,
+                                  const TInetAddr& /*aSrcAddr*/,
+                                  TInt /*aLocalPort*/ )
+#endif
+{
+    DEBUG_LOG(_L("Received message (encr)."));
+    
+    TLastIKEMsg msg_info(aHdr); //For retransmitted IKE msg detection
+    if ( iLastTransMsgInfo.IsReTransmit(msg_info) ) {
+       DEBUG_LOG(_L("Retransmitted Transaction message received, silently discarded !"));
+       return TRANSACTION_IGNORE;              
+    }
+    TUint32 status = TRANSACTION_IGNORE; // default
+    TUint32 msg_id;
+    TBuf8<IV_LTH> tmp_IV;   //Temporal IV. Used to update the real one if the msg OK    
+    const ThdrISAKMP *hdr = NULL;
+    TUint8 *msg = NULL;
+    msg_id = aHdr.GetMessageId();   //Saves the ID to compute IV and hash
+    
+    if (aHdr.GetFlags() & ISAKMP_HDR_EFLAG) //if encrypted
+    {
+        msg = new (ELeave) TUint8[aHdr.GetLength()];    //to place the new msg
+		CleanupStack::PushL(msg);
+		
+        Mem::Copy(msg, (TUint8 *)&aHdr, sizeof(aHdr));  //The header is not encrypted
+
+#ifdef _DEBUG        
+        DEBUG_LOG(_L("Message ID recv:"));        
+        TUint32 swap_id = ByteOrder::Swap32(msg_id);
+        DEBUG_LOG_ARRAY((TUint8 *)&swap_id, sizeof(msg_id));
+        DEBUG_LOG(_L("Transaction IV:"));
+#endif // _DEBUG        
+        //
+        // Find a transaction exchange structure for current message 
+        //
+        iCurrExchange = FindExchange(msg_id);
+        if ( !iCurrExchange )
+           iCurrExchange = AddExchangeL(msg_id, RESPONDER); // Add a new transaction exchange
+        //
+        // Adjust IV value for transaction exchange.
+        // There is now two situations:
+        // 1) There already exists an IV in exchange structure
+        //    (received message is a reply for an earlier sent request)
+        // 2) There is no IV in exchange structure
+        //    (received message is a new request/set message from peer)
+        //    A new IV is built from CNegotiation.iLastIV and current message ID
+        //
+        if ( iCurrExchange->iIV.Length() == 0 ) {
+           iCurrExchange->iIV.Copy(iNegotiation->iLastIV);          
+           iNegotiation->ComputeIVL(iCurrExchange->iIV, msg_id);        
+        }
+        tmp_IV.Copy(iCurrExchange->iIV); // Make a copy of current IV                       
+
+        DEBUG_LOG(_L("Decrypting..."));
+
+        DecryptL((TUint8 *)aHdr.Next(),&msg[sizeof(aHdr)], (aHdr.GetLength()-sizeof(aHdr)),
+                 iCurrExchange->iIV, iNegotiation->iSKEYID_e,
+                 iNegotiation->iChosenProposal_I.iAttrList->iEncrAlg);
+        hdr = (ThdrISAKMP *)msg;  //decrypted msg
+
+#ifdef _DEBUG   
+        const TPtrC8 ikeMsgPtr( (TUint8*)hdr,(TUint16)hdr->GetLength() );
+        TInetAddr dstAddr;
+        iPluginSession->GetLocalAddress( dstAddr );
+        dstAddr.SetPort( aLocalPort );
+        TRACE_MSG_IKEV1( ikeMsgPtr, aSrcAddr, dstAddr );                        
+#endif // _DEBUG                        
+        
+        status = TransactionExchangeL(*hdr);
+
+        if ( status == TRANSACTION_IGNORE ) {
+           //
+           // Current message ignored, restore saved IV to exchange structure
+           //   
+           iCurrExchange->iIV.Copy(tmp_IV);
+        }
+    }
+    else
+        hdr = &aHdr;
+
+    if (msg)    //If used erase it (when encryption)
+        CleanupStack::PopAndDestroy();
+	
+    if ( status == TRANSACTION_CONTINUE )
+       msg_info.Store(iLastTransMsgInfo); // store new last received IKE message info
+    
+    return status;
+}
+
+/**-------------------------------------------------------------------
+ *
+ * Method TransactionExchangeL()
+ * The ISAKMP transaction exchange message MUST be the following format:
+ * HDR*, HASH, ATTR
+ * Where the HASH payload contains the prf output, using SKEYID_a as
+ * the key, and the M-ID (ISAKMP header Message ID) unique to this
+ * exchange concatenated with all of the payloads after the HASH
+ * payload. In other words, the hash for the above exchange is:
+ * HASH = prf( SKEYID_a, M-ID | ATTR )
+ * Multiple ATTR payloads MAY NOT be present in the Transaction Exchange.
+ *
+ *--------------------------------------------------------------------*/
+TInt CTransNegotiation::TransactionExchangeL(const ThdrISAKMP &aHdr)
+{
+    TUint32 status;
+	iNegotiation->iLengthLeft = aHdr.GetLength(); //Used to check the size in the payload are OK
+	
+	CIkev1Payloads* payload = CIkev1Payloads::NewL(aHdr, *iNegotiation, iDebug);
+	if (!payload)
+	{	
+		return TRANSACTION_FAILED;    
+	}
+	CleanupStack::PushL(payload);
+
+	if ( payload->iHash && payload->iAttr )
+	{
+	   // 
+	   // Check if the hash value is OK. 
+	   // 
+	   if (!iNegotiation->VerifyInformationalHashL(payload->iHash, payload->iAttr,
+		                                           iCurrExchange->iMessageId))
+	   {	   
+	      DEBUG_LOG(_L("AUTHENTICATION_FAILED (Transaction hash)"));
+		  CleanupStack::PopAndDestroy();  //payload					  
+		  return TRANSACTION_FAILED;                    
+   	   }
+	   status = ProcessAttributesL(payload->iAttr);
+	   CleanupStack::PopAndDestroy();  //payload
+	   return status;
+	}
+	CleanupStack::PopAndDestroy();  //payload    	
+   	DEBUG_LOG(_L("Erroneous Transaction Exchange message received"));		
+	return TRANSACTION_FAILED;    
+}
+
+/**-------------------------------------------------------------------
+ *
+ * Method ProcessAttributesL()
+ * ProcessAttributesL() method parses the data attributes in received
+ * attribute payload. If the iRole data member of current exchange structure
+ * contains value INITIATOR, attribute payload is a CONFIG-MODE Reply
+ * which should contain CONFIG-MODE attributes.
+ * If the iRole data member of current exchange structure
+ * contains value RESPONDER, attribute payload is either a XAUTH Request or Set.
+ * These primitives should contain XAUTH attributes.
+ *
+ *--------------------------------------------------------------------*/
+TInt CTransNegotiation::ProcessAttributesL(const TAttributeISAKMP *aAttr)
+{
+    TInt length = (TInt)aAttr->GetLength();
+    if ( STATIC_CAST(TUint, length) < sizeof(TAttributeISAKMP) ) {
+       return TRANSACTION_FAILED; 
+    }
+
+    TInt status;
+    TUint8  cfg_msg_type = aAttr->CfgMsgType(); 
+    TUint16 identifier   = aAttr->Identifier();
+    
+    if ( iCurrExchange->iRole == INITIATOR ) {
+       //
+       // Config mode transaction. The current message should be a reply.
+       // Identifier value must also match to value in current exchange structure.
+       //
+       if ( cfg_msg_type != ISAKMP_CFG_REPLY ) {
+//          ||
+//          ( iCurrExchange->iIdentifier != identifier ) ) { 
+          return TRANSACTION_FAILED; 
+       }       
+       status = ProcessCfgModeAttrsL(aAttr->AttrData(), aAttr->AttrDataLen());
+    }
+    else {
+       //
+       // XAUTH mode transaction. The current message should be either request
+       // or set.
+       //
+       if ( (cfg_msg_type != ISAKMP_CFG_REQUEST) && (cfg_msg_type != ISAKMP_CFG_SET) ) {
+          return TRANSACTION_FAILED; 
+       }
+       iCurrExchange->iIdentifier = identifier;
+       if ( cfg_msg_type == ISAKMP_CFG_REQUEST ) 
+            status = ProcessXauthRequestL(aAttr->AttrData(), aAttr->AttrDataLen());
+       else status = ProcessXauthStatusL(aAttr->AttrData(), aAttr->AttrDataLen());    
+    }
+
+    return CheckTransactionStatusL(status);
+    
+}   
+
+/**-------------------------------------------------------------------
+ *
+ * Method ProcessCfgModeAttrs()
+ * ProcessCfgModeAttrs parses  CONFIG-MODE reply message attributes 
+ * received from gateway. In this phase the following attributes are used:
+ * -- INTERNAL_IP4_ADDRESS  = Client virtual IPv4 address in secure network
+ * -- INTERNAL_IP6_ADDRESS  = Client virtual IPv6 address in secure network
+ * -- INTERNAL_IP4_DNS      = DNS address(es) in secure network
+ *
+ * All other attributes are silently discarded
+ *
+ *--------------------------------------------------------------------*/
+TInt CTransNegotiation::ProcessCfgModeAttrsL(TDataISAKMP* aAttr, TInt aLth)
+{
+    
+    TBool   ia_received = EFalse;
+    TUint32  ipv4_addr; 
+    TIp6Addr ipv6_addr;    //IPV6 raw address
+    TInetAddr *dns_addr;
+    
+    delete iInternalAddr;  // delete old CInternalAddress for sure
+    iInternalAddr = NULL;
+    CInternalAddress *InternalAddr = new (ELeave)CInternalAddress(1);   
+    CleanupStack::PushL(InternalAddr);
+    
+    while ( aLth > 0 ) {
+        
+        aLth = aLth - aAttr->Size();
+        if ( aLth < 0 ) {
+           DEBUG_LOG(_L("CONFIG-MODE REPLY ERROR (Length mismatch in the attibutes)"));
+           CleanupStack::PopAndDestroy(); // InternalAddr
+           return TRANSACTION_FAILED;
+        }
+        switch ( aAttr->Type() ) {
+
+           case ATTR_INTERNAL_IP4_ADDR:
+                //
+                // A Virtual IPv4 address received.
+                // Store value to CInternalAddress object
+                // 
+                if ( !aAttr->IsBasic() && (aAttr->Length() == 4) ) {
+                   if ( !ia_received ) {
+                      ia_received = ETrue;                    
+                      ipv4_addr = GET32(aAttr->VarValue()); 
+                      InternalAddr->iClientIntAddr.SetAddress(ipv4_addr);
+                   }   
+                }
+                break;
+
+           case ATTR_INTERNAL_IP6_ADDR:
+                //
+                // A Virtual IPv6 address received.
+                // Store value to CInternalAddress object
+                // 
+                if ( !aAttr->IsBasic() && (aAttr->Length() == 16) ) {
+                   if ( !ia_received ) {
+                      ia_received = ETrue;
+                      Mem::Copy(&ipv6_addr.u.iAddr8, aAttr->VarValue(), sizeof(ipv6_addr.u.iAddr8));
+                      InternalAddr->iClientIntAddr.SetAddress(ipv6_addr);
+                   }   
+                }
+                break;
+
+           case ATTR_INTERNAL_IP4_DNS:
+                //
+                // Internal DNS address received.
+                // Add value to CInternalAddress object
+                // 
+                if ( !aAttr->IsBasic() && (aAttr->Length() == 4) ) {
+                   ipv4_addr = GET32(aAttr->VarValue());
+                   dns_addr  = new(ELeave)TInetAddr;
+                   CleanupStack::PushL(dns_addr);                  
+                   dns_addr->SetAddress(ipv4_addr);
+                   InternalAddr->AppendL(dns_addr);
+                   CleanupStack::Pop();  // dns_addr
+                }
+                break;
+            
+           default:
+                break;
+        }
+        
+        aAttr = aAttr->Next();
+    }
+    
+    CleanupStack::Pop(); // InternalAddr
+    iInternalAddr = InternalAddr;   
+
+    iCfgModeCompleted = ETrue;
+
+    DEBUG_LOG(_L("CONFIG-MODE completed, reply received!"));       
+    
+    return TRANSACTION_SUCCESS;
+}
+
+/**-------------------------------------------------------------------
+ *
+ * Method ProcessXauthRequest()
+ * ProcessXauthRequest parses XAUTH request message attributes 
+ * received from gateway. 
+ *
+ *--------------------------------------------------------------------*/
+TInt CTransNegotiation::ProcessXauthRequestL(TDataISAKMP* aAttr, TInt aLth)
+{
+    TInt     status        = TRANSACTION_CONTINUE;
+    TUint16  xauth_type    = ATTR_XAUTH_GENERIC;
+    TUint32  request_flags = 0;
+    TPtr8    challenge(NULL, 0);
+	TUint16  attr_type;
+	
+    while ( aLth > 0 ) {
+        
+        aLth = aLth - aAttr->Size();
+        if ( aLth < 0 ) {
+           DEBUG_LOG(_L("XAUTH REQUEST ERROR (Length mismatch in the attibutes)"));
+           return TRANSACTION_FAILED;
+        }
+		attr_type = aAttr->Type();
+		//
+		// Check does the VPN gateway support older XAUTH draft version
+		// draft-ietf-ipsec-isakmp-xauth-04.txt.
+		// The check is based on attribute type values. In the older
+		// draft attribute values are defined in range (13-20) and in the newer
+		// "de-facto" draft-beaulieu-ike-xauth-02.txt the same
+		// attribute values are in "private use" range (16520-16529)
+		//
+		if ( attr_type < ATTR_XAUTH_TYPE )
+			iUseOlderPIXXauth = ETrue;	
+ 
+        switch ( attr_type ) {
+
+           case ATTR_XAUTH_TYPE:
+		   case ATTR_PIX_XAUTH_TYPE:			   
+                //
+                // Extended authentication type requested
+                //
+                if ( aAttr->IsBasic() ) { // Basic attribute
+                   request_flags |= (1 << (ATTR_XAUTH_TYPE - ATTR_XAUTH_TYPE));                 
+                   iCurrExchange->iXauthType = aAttr->Value();
+                }
+                break;
+
+           case ATTR_USER_NAME:
+           case ATTR_PASSWORD:                         
+           case ATTR_PASSCODE:
+		   case ATTR_PIX_USER_NAME:
+		   case ATTR_PIX_PASSWORD:
+		   case ATTR_PIX_PASSCODE:
+                //
+                // Handles the following attribute values:
+                // -- User name
+                // -- Password
+                // -- Passcode
+                // Set a corresponding bit request flags. Parameter contents has
+                // no meaning in request
+                // 
+                if ( !aAttr->IsBasic() ) {  // Variable length
+				   if ( attr_type < ATTR_USER_NAME )
+					    request_flags |= (1 << (attr_type - ATTR_PIX_XAUTH_TYPE)); 					   
+                   else request_flags |= (1 << (attr_type - ATTR_XAUTH_TYPE)); 
+                }
+                break;
+
+           case ATTR_MESSAGE:
+		   case ATTR_PIX_MESSAGE:
+                //
+                // Message data attribute (NOT USED IN THIS PHASE)
+                // 
+                break;
+
+           case ATTR_CHALLENGE:
+		   case ATTR_PIX_CHALLENGE:
+                //
+                // Challenge data attribute
+                //
+                if ( !aAttr->IsBasic() && aAttr->Length() ) {
+                   request_flags |= (1 << (ATTR_CHALLENGE - ATTR_XAUTH_TYPE));
+                   challenge.Set(aAttr->VarValue(), aAttr->Length(), aAttr->Length());    
+                }
+                break;
+
+           case ATTR_DOMAIN:
+		   case ATTR_STATUS:
+		   case ATTR_PIX_DOMAIN:			   
+		   case ATTR_PIX_STATUS:
+                //
+                // Domain and status attributes (NOT USED IN THIS PHASE)
+                // 
+                break;
+
+           case ATTR_NEXT_PIN:                          
+                if ( !aAttr->IsBasic() ) {  // Variable length
+                   request_flags |= (1 << (ATTR_NEXT_PIN - ATTR_XAUTH_TYPE)); 
+                }
+                break;
+
+           case ATTR_ANSWER:
+                //
+                // Answer data attribute (NOT USED IN THIS PHASE)
+                // 
+                break;
+            
+           default:
+                break;
+        }
+        
+        aAttr = aAttr->Next();
+    }
+
+    //
+    // Check if there already exist a authentication credentials request active
+    // (= iRequestFlags are not zero). If there is ignore current message.
+    //
+    if ( iRequestFlags == 0 ) {
+       iRequestFlags = request_flags;
+    }    
+    else {
+       request_flags = 0;
+       status        = TRANSACTION_IGNORE;
+    }   
+    //
+    // Examine request_flags and show appropriate dialog to get requested
+    // authentication credentials from user
+    //
+    switch ( request_flags & ~(1 << (ATTR_XAUTH_TYPE - ATTR_XAUTH_TYPE)) ) {
+
+        case ( (1 << (ATTR_USER_NAME - ATTR_XAUTH_TYPE)) | (1 << (ATTR_PASSWORD - ATTR_XAUTH_TYPE))):
+            //
+            //  User name/Password authentication required
+            //
+			iDialog     = CIkev1Dialog::NewL(iPluginSession, iPluginSession->DialogAnchor(), iDebug);			
+            iDialogInfo = new(ELeave) CAuthDialogInfo(iPluginSession, XAUTH_DIALOG_ID, iNegotiation->SAId(), iCurrExchange->iMessageId);
+            iDialog->GetAsyncUNPWDialogL(iDialogInfo, (MIkeDialogComplete*)this);          
+            break;
+
+        case ( (1 << (ATTR_USER_NAME - ATTR_XAUTH_TYPE)) | (1 << (ATTR_PASSCODE - ATTR_XAUTH_TYPE))):
+            //
+            //  User name/Secure ID authentication required
+            //
+            iDialog     = CIkev1Dialog::NewL(iPluginSession, iPluginSession->DialogAnchor(), iDebug);
+            iDialogInfo = new(ELeave) CAuthDialogInfo(iPluginSession, XAUTH_DIALOG_ID, iNegotiation->SAId(), iCurrExchange->iMessageId);
+            iDialog->GetAsyncSecureidDialogL(iDialogInfo, (MIkeDialogComplete*)this);          
+            break;
+
+        case ( (1 << (ATTR_USER_NAME - ATTR_XAUTH_TYPE)) | (1 << (ATTR_NEXT_PIN - ATTR_XAUTH_TYPE))):
+            //
+            //  User name/Secure ID next pin required
+            //
+			iDialog     = CIkev1Dialog::NewL(iPluginSession, iPluginSession->DialogAnchor(), iDebug);			
+			iDialogInfo = new(ELeave) CAuthDialogInfo(iPluginSession, XAUTH_DIALOG_ID, iNegotiation->SAId(), iCurrExchange->iMessageId);
+            iDialog->GetAsyncSecureNextPinDialogL(iDialogInfo, (MIkeDialogComplete*)this);
+            break;
+
+        case ( (1 << (ATTR_CHALLENGE - ATTR_XAUTH_TYPE)) ):
+            //
+            //  User Challenge response dialog
+            //
+            if ( xauth_type == ATTR_XAUTH_RADIUS_CHAP )
+			{
+				iDialog     = CIkev1Dialog::NewL(iPluginSession, iPluginSession->DialogAnchor(), iDebug);			
+				iDialogInfo = new(ELeave) CAuthDialogInfo(iPluginSession, XAUTH_DIALOG_ID, iNegotiation->SAId(), iCurrExchange->iMessageId);
+                iDialog->GetAsyncRespDialog(challenge, iDialogInfo, (MIkeDialogComplete*)this);
+            }   
+            break;
+
+        default:
+            break;
+
+    }   
+    
+    return status;
+
+}
+
+/**-------------------------------------------------------------------
+ *
+ * Method ProcessXauthStatus()
+ * ProcessXauthStatus parses XAUTH Set message attributes received from gateway.
+ * Only Status attribute has any relevance in Set message.
+ *
+ *--------------------------------------------------------------------*/
+TInt CTransNegotiation::ProcessXauthStatusL(TDataISAKMP* aAttr, TInt aLth)
+{
+    TBuf8<16> attributes;    
+    TInt      status = TRANSACTION_CONTINUE;
+    TInt16    attr_status;
+    
+    while ( aLth > 0 ) {
+        
+        aLth = aLth - aAttr->Size();
+        if ( aLth < 0 ) {
+           DEBUG_LOG(_L("XAUTH SET ERROR (Length mismatch in the attibutes)"));
+           return TRANSACTION_FAILED;
+        }
+
+        switch ( aAttr->Type() ) {
+
+           case ATTR_STATUS:
+		   case ATTR_PIX_STATUS:			   
+                //
+                // Status code from gateway
+                // 
+                if ( aAttr->IsBasic() ) { // Basic attribute
+                   attr_status = aAttr->Value();    
+                   if ( attr_status == ATTR_STATUS_OK )
+                        status = TRANSACTION_SUCCESS;
+                   else status = TRANSACTION_FAILED;   
+                }
+                break;
+            
+           default:
+                break;
+        }
+        
+        aAttr = aAttr->Next();
+    }
+    
+    if ( status != TRANSACTION_CONTINUE ) {
+       //
+       // Send Transaction exchange ACK
+       //
+	   TUint16 AttrType;
+	   if ( iUseOlderPIXXauth )
+		    AttrType = ATTR_PIX_STATUS;
+	   else AttrType = ATTR_STATUS;
+	   
+       AddAttributeData(attributes, AttrType, 2, (TUint8*)&attr_status);
+       BuildAndSendMessageL(attributes, ISAKMP_CFG_ACK);
+       if ( status == TRANSACTION_SUCCESS ) {
+          DEBUG_LOG(_L("XAUTH authentication succeeded!"));
+          iXauthCompleted = ETrue;
+		  if ( iUserName ) {
+		     //
+    		 // Cache user name into user name file
+			 //
+		     CIkev1Dialog* Dialog = CIkev1Dialog::NewL(iPluginSession, iPluginSession->DialogAnchor(), iDebug);
+             CleanupStack::PushL(Dialog);
+			 TInt err(KErrNone);
+			 TRAP(err, Dialog->StoreUserNameL(iUserName->Des()));
+#ifdef _DEBUG			 
+			 if (err == KErrNone)
+			     DEBUG_LOG(_L("User Name caching succeeded"));
+			 else DEBUG_LOG(_L("User Name caching failed"));
+#endif // _DEBUG			 
+			 CleanupStack::PopAndDestroy();					 
+		  }	   
+       }            
+       else {
+          DEBUG_LOG(_L("XAUTH authentication failed!"));
+	   // Dialog object shall be delete in Dialog->RunL when dialog completed				  
+          CIkev1Dialog* Dialog  = CIkev1Dialog::NewL(iPluginSession, iPluginSession->DialogAnchor(), iDebug);		  
+          Dialog->ShowErrorDialogL(TVpnNoteDialog::EKmdAuthenticationFailed, NULL, NULL);
+       }
+    }
+    
+    return status;
+}
+
+/**--------------------------------------------------------------------------------
+ *
+ * Method CheckTransactionStatusL()
+ * CheckTransactionStatus is after an incoming ISAKMP transaction exchange message
+ * has been processed. This method decides the actions shall be taken next:
+ * -- If current status (= call parameter) is continue, ignore or failed
+ *    ==> Same status is returned
+ * -- If current status is success and XAUTH completed.     
+ *    ==> CONFIG MODE actions are started (= Config mode request is transmitted)
+ * -- If current status is success and CONFIG MODE completed.     
+ *    ==> XAUTH actions are started. (= We shall just wait for XAUTH request)
+ * -- If current status is success and both CONFIG-MODE and XAUTH completed
+ *    ==> TRANSACTION_SUCCESS status is returned
+ *
+ *--------------------------------------------------------------------*/
+TInt CTransNegotiation::CheckTransactionStatusL(TInt aStatus)
+{
+    if ( aStatus == TRANSACTION_SUCCESS || aStatus == TRANSACTION_CONTINUE ) {
+       //
+       // Stop retransmission timer 
+       //
+       iNegotiation->iTimer->Cancel();
+       
+       if ( aStatus == TRANSACTION_SUCCESS ) {
+          if ( iXauthCompleted ) {
+             if ( !iCfgModeCompleted ) {
+                aStatus = BuildConfigRequestL();
+             }    
+          }
+          else {
+             if ( !iXauthCompleted ) {
+                aStatus = TRANSACTION_CONTINUE;
+             }    
+          }    
+       }
+    }
+    
+    return aStatus;
+}   
+
+/**-------------------------------------------------------------------
+ *
+ * Method BuildConfigRequestL()
+ * BuildConfigRequestL() builds the CONFIG-MODE request message. 
+ * In this phase requests the following parameters from gateway:
+ * -- Client virtual IP in secure network = INTERNAL_IP4_ADDRESS, INTERNAL_IP4_NETMASK
+ *                                         (INTERNAL_IP6_ADDRESS, INTERNAL_IP6_NETMASK)
+ * -- DNS address(es) in secure network   = INTERNAL_IP4_DNS  
+ *
+ *--------------------------------------------------------------------*/
+TInt CTransNegotiation::BuildConfigRequestL()
+{
+
+    TBuf8<16> attributes;
+    
+    TUint32  message_id = iNegotiation->RandomMessageId();
+
+    iCurrExchange = AddExchangeL(message_id, INITIATOR); //Add a new transaction exchange
+    iCurrExchange->iIdentifier = GetIdentifier();
+    
+    iCurrExchange->iIV.Copy(iNegotiation->iLastIV);      // Calculate base IV for ..
+    iNegotiation->ComputeIVL(iCurrExchange->iIV, message_id); // transaction message
+
+    AddAttributeData(attributes, ATTR_INTERNAL_IP4_ADDR, 0, NULL);
+    AddAttributeData(attributes, ATTR_INTERNAL_IP4_DNS, 0, NULL);
+	
+    BuildAndSendMessageL(attributes, ISAKMP_CFG_REQUEST);
+    DEBUG_LOG(_L("CONFIG-MODE started, request xmitted!")); 
+
+    return TRANSACTION_CONTINUE;
+
+    
+}
+
+/**-------------------------------------------------------------------
+ *
+ * Method AddAttributeData()
+ * AddAttributeData() method adds one attribute data to an attribute buffer
+ *
+ *--------------------------------------------------------------------*/
+void CTransNegotiation::AddAttributeData(TDes8& aAttrBfr, TInt aType, TInt aLth, TUint8* aData)
+{
+    TDataISAKMP attr;
+    if ( aType == ATTR_STATUS     || aType == ATTR_XAUTH_TYPE ||
+		 aType == ATTR_PIX_STATUS || aType == ATTR_PIX_XAUTH_TYPE) {
+       //
+       // Add a basic length attribute
+       //
+       attr.SetBasic(ETrue);
+       attr.SetType((TUint16)aType);
+       if ( aData ) 
+          attr.SetValue(*(TUint16*)aData);
+       aAttrBfr.Append((TUint8 *)&attr, sizeof(attr));
+    }
+    else {
+       //
+       // Add a variable length attribute
+       //
+       attr.SetBasic(EFalse);
+       attr.SetType((TUint16)aType);
+       attr.SetLength((TUint16)(aLth));
+       aAttrBfr.Append((TUint8 *)&attr, sizeof(attr));
+       if ( aLth ) 
+          aAttrBfr.Append(aData, aLth);       
+    }   
+}
+
+/**-------------------------------------------------------------------
+ *
+ * Method BuildAndSendMessageL()
+ * BuildAndSendMessage() method builds ISAKMP transaction exchange message
+ * and transmits it using CNegotiation class send() method.
+ * The payload format of a transaction exchange message is the following:
+ * HDR*, HASH, ATTR
+ * Where the HASH payload contains the prf output, using SKEYID_a as
+ * the key, and the M-ID (ISAKMP header Message ID) unique to this
+ * exchange concatenated with all of the payloads after the HASH
+ * payload. In other words, the hash for the above exchange is:
+ * HASH = prf( SKEYID_a, M-ID | ATTR )
+ *
+ *--------------------------------------------------------------------*/
+void CTransNegotiation::BuildAndSendMessageL(TDesC8& aAttrBfr, TUint8 aMsgType)
+{
+	TIkev1IsakmpStream* msg = iNegotiation->SaveIkeMsgBfr( new (ELeave) TIkev1IsakmpStream(iDebug) );
+	
+    TUint32 saved_msg_id     = iNegotiation->iMessageId;
+    TUint8  saved_exchange   = iNegotiation->iExchange;
+    iNegotiation->iMessageId = iCurrExchange->iMessageId; // used in method Isakmp_INIT()
+    iNegotiation->iExchange  = ISAKMP_EXCHANGE_TRANSACT;  // used in method Isakmp_INIT()
+    
+    msg->IsakmpInit(iNegotiation);
+    msg->IsakmpHashL();
+    msg->IsakmpAttributes(aMsgType, iCurrExchange->iIdentifier, aAttrBfr);  
+    msg->IsakmpHashContL();
+    
+    iNegotiation->SendL(*msg);
+
+    iNegotiation->iMessageId = saved_msg_id;
+    iNegotiation->iExchange  = saved_exchange;
+    
+}
+
+/**-------------------------------------------------------------------
+ *
+ * Method FindExchange()
+ * FindExchange() method finds a exchange strcuture for a specified message id 
+ *
+ *--------------------------------------------------------------------*/
+TTransExchange* CTransNegotiation::FindExchange(TUint32 aMsgId)
+{
+    TTransExchange *exchange;
+    TInt i = 0;
+
+    while ( i < Count() )
+    {
+        exchange = At(i);
+        if ( exchange->iMessageId == aMsgId )
+           return exchange;
+        i ++;
+    }   
+
+    return NULL;
+}
+
+/**-------------------------------------------------------------------
+ *
+ * Method AddExchangeL()
+ * AddExchangeL() method allocates a new exchange structure and adds it
+ * to exchange array. 
+ *
+ *--------------------------------------------------------------------*/
+TTransExchange* CTransNegotiation::AddExchangeL(TUint32 aMsgId, TUint8 aRole )
+{
+    
+    TTransExchange *exchange =  new(ELeave)TTransExchange;
+    exchange->iMessageId     = aMsgId;
+    exchange->iRole          = aRole;
+    exchange->iIV.SetLength(0);
+    AppendL(exchange);
+    
+    return exchange;
+}
+
+//
+// The implementation for class MIkeDialogComplete virtual function
+//
+TInt CTransNegotiation::DialogCompleteL(CIkev1Dialog* /*aDialog*/, TAny* aUserInfo,
+								        HBufC8* aUsername, HBufC8* aSecret, HBufC8* aDomain)
+{
+/*---------------------------------------------------------------------------
+ *  
+ *  A response received from client user (through asynchronous dialog)
+ *  This method is introduced as a TUserCallback for CGetIKEPassword dialog
+ *  object is created. When the dialog is completed this callback function
+ *  is called to deliver Credentials data for CHRE payload attributes.
+ *  Store credential buffers to CAuthDialogInfo object and call engine
+ *  entry  
+ *  
+ *-------------------------------------------------------------------------*/
+	TUint32 obj_id = 1;
+	CAuthDialogInfo* info = (CAuthDialogInfo*)aUserInfo;
+	DEBUG_LOG1(_L("CIKECRACKNegotiation::DialogCompleteL(), aUserInfo =  %x"), aUserInfo);
+
+	if ( info )
+	{
+		obj_id = info->GetObjId();
+		DEBUG_LOG1(_L("Preparing to call AuthDialogCompletedL(), ObjId = %x"), obj_id);
+		if ( obj_id == XAUTH_DIALOG_ID )
+		{
+			info->iUsername = aUsername;
+			info->iSecret   = aSecret;
+			info->iDomain   = aDomain;
+			obj_id = info->PluginSession()->AuthDialogCompletedL(info);
+		}   
+	}
+
+	return obj_id;
+}