vpnengine/ikev1lib/src/ikev1infonegotiation.cpp
changeset 0 33413c0669b9
equal deleted inserted replaced
-1:000000000000 0:33413c0669b9
       
     1 /*
       
     2 * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies).
       
     3 * All rights reserved.
       
     4 * This component and the accompanying materials are made available
       
     5 * under the terms of "Eclipse Public License v1.0"
       
     6 * which accompanies this distribution, and is available
       
     7 * at the URL "http://www.eclipse.org/legal/epl-v10.html".
       
     8 *
       
     9 * Initial Contributors:
       
    10 * Nokia Corporation - initial contribution.
       
    11 *
       
    12 * Contributors:
       
    13 *
       
    14 * Description:   CIkev1InfoNegotiation class
       
    15 *
       
    16 */
       
    17 
       
    18 #include <vpnlogmessages.rsg>
       
    19 
       
    20 #include "ikev1infonegotiation.h"
       
    21 #include "ikev1negotiation.h"
       
    22 #include "ikev1SAdata.h"
       
    23 #include "ikev1isakmpct.h"
       
    24 #include "ikedebug.h"
       
    25 #include "ikev1pluginsession.h"
       
    26 #include "ikev1negotiation.h"
       
    27 #include "ikev1crypto.h"
       
    28 #include "ikev1payload.h"
       
    29 #include "ikev1crack.h"
       
    30 #include "ikev1trans.h"
       
    31 #include "kmdapi.h"
       
    32 #include "kmdeventloggerif.h"
       
    33 
       
    34 
       
    35 CIkev1InfoNegotiation::CIkev1InfoNegotiation( CIkev1PluginSession& aPluginSession,
       
    36                                               CIkev1Negotiation& aNegotiation,
       
    37                                               MIkeDebug& aDebug )
       
    38  : iPluginSession( aPluginSession ),
       
    39    iNegotiation( aNegotiation ),
       
    40    iDebug( aDebug )
       
    41 {        
       
    42 }
       
    43 
       
    44 #ifdef _DEBUG
       
    45 void CIkev1InfoNegotiation::ExecuteL( const ThdrISAKMP& aHdr,
       
    46                                       const TInetAddr& aSrcAddr,
       
    47                                       TInt aLocalPort )
       
    48 #else
       
    49 void CIkev1InfoNegotiation::ExecuteL( const ThdrISAKMP& aHdr,
       
    50                                       const TInetAddr& /*aSrcAddr*/,
       
    51                                       TInt /*aLocalPort*/ )
       
    52 #endif
       
    53 {
       
    54     const ThdrISAKMP *hdr = NULL;
       
    55     TUint8 *msg=NULL;
       
    56     TBuf8<IKEV1_MAX_IV_SIZE> tmp_IV;    //Temporal IV. Used to update the real one if the msg OK
       
    57 
       
    58     iMessageId = aHdr.GetMessageId();   //Saves the ID to compute IV and hash
       
    59     if (aHdr.GetFlags() & ISAKMP_HDR_EFLAG) //if encrypted
       
    60     {
       
    61         DEBUG_LOG(_L("Received message (encr)."));
       
    62         msg = new (ELeave) TUint8[aHdr.GetLength()];    //to place the new msg
       
    63 		CleanupStack::PushL(msg);
       
    64 		
       
    65         Mem::Copy(msg,(TUint8 *)&aHdr, sizeof(aHdr));   //The header is not encrypted
       
    66 
       
    67         DEBUG_LOG(_L("Message ID recv:"));
       
    68 #ifdef _DEBUG        
       
    69         TUint32 swap_id = ByteOrder::Swap32(iMessageId);
       
    70         DEBUG_LOG_ARRAY((TUint8 *)&swap_id, sizeof(iMessageId));
       
    71         DEBUG_LOG(_L("Notif IV:"));
       
    72 #endif // _DEBUG        
       
    73         //Notify and Phase II requires a recomputing of IV
       
    74 
       
    75         if (iNegotiation.iLastIV.Length() != 0)
       
    76             tmp_IV.Copy(iNegotiation.iLastIV);
       
    77         else    //iLastIV not yet computed so current iIV is used
       
    78             tmp_IV.Copy(iNegotiation.iIV);
       
    79         iNegotiation.ComputeIVL(tmp_IV, iMessageId);
       
    80 
       
    81         DEBUG_LOG(_L("Decrypting..."));
       
    82 
       
    83         DecryptL((TUint8 *)aHdr.Next(),&msg[sizeof(aHdr)], aHdr.GetLength()-sizeof(aHdr), tmp_IV, iNegotiation.iSKEYID_e, iNegotiation.iChosenProposal_I.iAttrList->iEncrAlg);
       
    84         hdr=(ThdrISAKMP *)msg;  //decrypted msg
       
    85     }
       
    86     else
       
    87         hdr = &aHdr;
       
    88 
       
    89     DEBUG_LOG(_L("Received message."));
       
    90 #ifdef _DEBUG
       
    91     const TPtrC8 ikeMsgPtr( (TUint8*)hdr,(TUint16)hdr->GetLength() );
       
    92     TInetAddr localAddr;
       
    93     iPluginSession.GetLocalAddress( localAddr );
       
    94     localAddr.SetPort( aLocalPort );
       
    95     TRACE_MSG_IKEV1( ikeMsgPtr, aSrcAddr, localAddr );
       
    96 #endif // _DEBUG    
       
    97     InfoExchangeL(*hdr);
       
    98     if (msg)    //If used erase it (when encryption)
       
    99    	   CleanupStack::PopAndDestroy();
       
   100 }
       
   101 
       
   102 MKmdEventLoggerIf& CIkev1InfoNegotiation::EventLogger()
       
   103 {
       
   104     return iPluginSession.EventLogger();
       
   105 }
       
   106 
       
   107 //No phase dependant. May inform of an error or general status info
       
   108 void CIkev1InfoNegotiation::InfoExchangeL(const ThdrISAKMP &aHdr)
       
   109 {
       
   110 	iNegotiation.iLengthLeft = aHdr.GetLength();  //Used to check the size in the payload are OK
       
   111 	
       
   112 	CIkev1Payloads* payload = CIkev1Payloads::NewL(aHdr, iNegotiation, iDebug);
       
   113 	if (!payload)
       
   114 		return;
       
   115 	CleanupStack::PushL(payload);
       
   116 
       
   117 	TInt i;			
       
   118 	TBool notif_ok = EFalse;    
       
   119     //If the message contains a hash
       
   120     if ( payload->iHash )
       
   121     {
       
   122         if ( payload->iNotifs->Count() )
       
   123         {
       
   124             //Checks if the hash value is OK. Here because need the notification payload
       
   125             if (!iNegotiation.VerifyInformationalHashL(payload->iHash, payload->iNotifs->At(0), iMessageId))
       
   126             {
       
   127                 DEBUG_LOG(_L("AUTHENTICATION_FAILED (Informational hash)"));
       
   128                 iNegotiation.SendNotifyL(AUTHENTICATION_FAILED);
       
   129             }
       
   130             else    //Hash OK
       
   131 			{
       
   132 				i = 0;
       
   133 				while ( i < payload->iNotifs->Count() )
       
   134 				{	
       
   135                     notif_ok = ProcessNotificationL(payload->iNotifs->At(i), ETrue);
       
   136 					if ( !notif_ok )
       
   137 					   break;	
       
   138 					i ++;
       
   139 				}	
       
   140 			}	
       
   141         }
       
   142         else if ( payload->iDeletes->Count() )
       
   143         {
       
   144             if (!iNegotiation.VerifyInformationalHashL(payload->iHash, payload->iDeletes->At(0), iMessageId))
       
   145             {
       
   146                 DEBUG_LOG(_L("AUTHENTICATION_FAILED (Informational hash)"));
       
   147                 iNegotiation.SendNotifyL(AUTHENTICATION_FAILED);
       
   148             }
       
   149             else
       
   150             {   //Hash OK
       
   151                 if ( !iNegotiation.iAutoLogin && iNegotiation.iCRACKneg )
       
   152                    iNegotiation.iCRACKneg->CrackAuthenticationFailedL(NULL);
       
   153                 if ( !iNegotiation.iAutoLogin && iNegotiation.iTransactionNeg )
       
   154                    iNegotiation.iTransactionNeg->TransactionFailedL(NULL);
       
   155 				i = 0;
       
   156 				while ( i < payload->iDeletes->Count() )
       
   157 				{	
       
   158 					notif_ok = ProcessDeleteL(payload->iDeletes->At(0));
       
   159 					if (!notif_ok)
       
   160 					   break;	
       
   161 					i ++;
       
   162 				}	
       
   163             }   
       
   164         }
       
   165         else
       
   166         {
       
   167             DEBUG_LOG(_L("PAYLOAD_MALFORMED (no hash or delete payload)"));
       
   168             iNegotiation.SendNotifyL(PAYLOAD_MALFORMED);
       
   169         }
       
   170     }
       
   171     else    //No hash sent  
       
   172     {
       
   173         if (aHdr.GetFlags() & ISAKMP_HDR_EFLAG) //if encrypted
       
   174         {
       
   175             DEBUG_LOG(_L("PAYLOAD_MALFORMED (Hash required)"));
       
   176             iNegotiation.SendNotifyL(PAYLOAD_MALFORMED);
       
   177         }
       
   178         else    //Not encrypted so not hash required
       
   179         {
       
   180 			i = 0;
       
   181 			while ( i < payload->iNotifs->Count() )
       
   182 			{	
       
   183 				notif_ok = ProcessNotificationL(payload->iNotifs->At(i), EFalse);
       
   184 				if ( !notif_ok )
       
   185 					break;	
       
   186 				i ++;
       
   187 			}	
       
   188         }
       
   189     }
       
   190     
       
   191     if ( notif_ok ) {
       
   192 	   const TNotificationISAKMP* notif = NULL;	
       
   193 	   if (	payload->iNotifs->Count() )
       
   194 		   notif = payload->iNotifs->At(0); 
       
   195        if ( iNegotiation.iCRACKneg ) {
       
   196 		  if ( !iNegotiation.iAutoLogin )
       
   197              iNegotiation.iCRACKneg->CrackAuthenticationFailedL(notif);
       
   198 		  iNegotiation.SetErrorStatus(KKmdIkeAuthFailedErr);
       
   199 		  iNegotiation.AcquireSAErrorResponse(KKmdIkeAuthFailedErr);
       
   200 	   }	 
       
   201        if ( iNegotiation.iTransactionNeg ) {
       
   202 	      if ( !iNegotiation.iAutoLogin )		   
       
   203              iNegotiation.iTransactionNeg->TransactionFailedL(notif);
       
   204 		  iNegotiation.SetErrorStatus(KKmdIkeAuthFailedErr);		  
       
   205 		  iNegotiation.AcquireSAErrorResponse(KKmdIkeAuthFailedErr);
       
   206 	   }	  
       
   207     }   
       
   208 
       
   209 	CleanupStack::PopAndDestroy();  //payload
       
   210 	
       
   211 }
       
   212 
       
   213 
       
   214 //Handles Notification Payload
       
   215 TBool CIkev1InfoNegotiation::ProcessNotificationL(const TPayloadISAKMP *aPayload, TBool aEncrypted)
       
   216 {
       
   217 #ifdef _DEBUG
       
   218     TBuf<80> str;
       
   219 #endif // _DEBUG    
       
   220     TNotificationISAKMP *notif = TNotificationISAKMP::Ptr(aPayload);
       
   221     if (!iNegotiation.CheckDOI(notif->GetDOI()))
       
   222     {
       
   223         DEBUG_LOG(_L("DOI_NOT_SUPPORTED in NOT Payload Message."));
       
   224         return EFalse;
       
   225     }
       
   226 	TBool   Status;
       
   227 	TUint16 MsgType = notif->GetMsgType();
       
   228 	
       
   229 	if ( (MsgType == DPD_R_U_THERE || MsgType == DPD_R_U_THERE_ACK) && aEncrypted )
       
   230 	{
       
   231 	   return ProcessDPDNotifyL(notif);	
       
   232 	}
       
   233 	
       
   234 	if ( MsgType <= UNEQUAL_PAYLOAD_LENGTHS )
       
   235 	{	
       
   236 #ifdef _DEBUG	
       
   237         str.Copy(_L("Error/Status Type: "));
       
   238 #endif // _DEBUG        
       
   239         Status = ETrue;
       
   240 		iNegotiation.SetNotifyStatus(MsgType);		
       
   241 		
       
   242 	    LOG_KMD_EVENT( MKmdEventLoggerIf::KLogError,
       
   243 	                   R_VPN_MSG_VPN_GW_ERR_RESP_RECEIVED,
       
   244 	                   MsgType, 
       
   245 	                   iPluginSession.VpnIapId(),
       
   246 	                   &(iNegotiation.iRemoteAddr) );
       
   247 	}
       
   248 	else
       
   249 	{
       
   250 #ifdef _DEBUG	
       
   251 		str.Copy(_L("Unexpected info notification: "));
       
   252 #endif // _DEBUG		
       
   253 		Status = EFalse;  	
       
   254 	}
       
   255 #ifdef _DEBUG	
       
   256 	str.Append(CIkev1Negotiation::TextNotifyType(MsgType));
       
   257 	DEBUG_LOG(str);
       
   258 #endif // _DEBUG	
       
   259     return Status;	
       
   260 }
       
   261 
       
   262 //
       
   263 // Process DPD R-U_THERE / R-U-THERE-ACK
       
   264 // When a R-U-THERE notify received it processes as follows:
       
   265 // -- Find an ISAKMP SA with SPI in notify message
       
   266 // -- Pass DPD notify message for further processing into 
       
   267 //    CIkev1Negotiation::NotifyMessageReceived() via iNegotiation reference 
       
   268 //
       
   269 TBool CIkev1InfoNegotiation::ProcessDPDNotifyL(TNotificationISAKMP* aNotify)
       
   270 {
       
   271 
       
   272     if ( aNotify->GetSPISize() == (2 * ISAKMP_COOKIE_SIZE) && (aNotify->GetNotifDataSize() == 4)) 
       
   273 	{
       
   274 	   TCookie cookie_I, cookie_R;
       
   275 	   cookie_I.Copy(aNotify->GetSPI(), ISAKMP_COOKIE_SIZE);
       
   276 	   cookie_R.Copy((aNotify->GetSPI() + ISAKMP_COOKIE_SIZE), ISAKMP_COOKIE_SIZE);
       
   277 	   
       
   278 	   TIkev1SAData* Sa = iPluginSession.FindIkev1SAData(cookie_I, cookie_R);
       
   279 	   if ( !Sa )
       
   280 	   {	   
       
   281 		  Sa = iPluginSession.FindIkev1SAData(cookie_R, cookie_I);
       
   282 #ifdef _DEBUG		  
       
   283 		  if (Sa) DEBUG_LOG(_L("ISAKMP SA found for DPD notify message with CKY_R+CKY_I"));
       
   284 #endif // _DEBUG		  
       
   285 	   }	  
       
   286 	   if ( Sa && Sa->iDPDSupported )
       
   287 	   {
       
   288 		   TUint32 Sequence = GET32(aNotify->GetNotifData());
       
   289 		   iNegotiation.DpdNotifyMessageReceivedL(Sa, aNotify->GetMsgType(), Sequence);
       
   290 	   }
       
   291 #ifdef _DEBUG	   
       
   292 	   else DEBUG_LOG(_L("No ISAKMP SA found for DPD notify message"));
       
   293 #endif // _DEBUG	   
       
   294 	}
       
   295 #ifdef _DEBUG    
       
   296 	else DEBUG_LOG(_L("Illegal SPI- or notify data length in DPD message"));
       
   297 #endif // _DEBUG	
       
   298   		
       
   299 	return EFalse;
       
   300 }
       
   301 
       
   302 //Handles Delete Payload
       
   303 TBool CIkev1InfoNegotiation::ProcessDeleteL(const TPayloadISAKMP *aPayload)
       
   304 {
       
   305 TDeleteISAKMP *delete_payload = TDeleteISAKMP::Ptr(aPayload);
       
   306 
       
   307 #ifdef _DEBUG
       
   308     TBuf<1200> msg;    
       
   309     DEBUG_LOG(_L("Delete Payload received!!!"));
       
   310     delete_payload->String(msg);
       
   311     DEBUG_LOG(msg);
       
   312 #endif // _DEBUG    
       
   313     if (!iNegotiation.CheckDOI(delete_payload->DOI()))
       
   314     {
       
   315         DEBUG_LOG(_L("DOI_NOT_SUPPORTED in delete payload"));
       
   316         return EFalse;
       
   317     }
       
   318     
       
   319     TUint8 protocol = delete_payload->Protocol();
       
   320     TUint32 spi;
       
   321     TInetAddr remote_addr(iNegotiation.iRemoteAddr);
       
   322     remote_addr.SetPort(KInetPortAny);
       
   323 
       
   324     TInt err = KErrNone;
       
   325     if ( protocol == PROTO_ISAKMP )
       
   326 	{	
       
   327         iPluginSession.DeleteISAKMPSAsL( delete_payload, iNegotiation );
       
   328 	}	
       
   329     else    //IPSEC AH or ESP (others will be discarded by the kernel)
       
   330     {
       
   331         if (delete_payload->SPISize() != sizeof(TUint32))
       
   332         {
       
   333             DEBUG_LOG(_L("Bad SPI Size for a IPsec SA. (SA Not deleted)"));
       
   334         }
       
   335 		TIpsecSPI IpsecSpi;
       
   336         for (TInt i=0; i < delete_payload->NumSPI(); i++)   //Shouldn't be more than one
       
   337         {
       
   338             Mem::Copy((TUint8*)&spi, delete_payload->SPI(i),sizeof(TUint32));
       
   339             if (err == KErrNone)
       
   340 			{	
       
   341                 //The right one is the Outbound(Local->Remote) one to avoid sending when deleted at the other side
       
   342                 //The opposite if sending a Delete
       
   343 				IpsecSpi.iSrcAddr  = iNegotiation.iLocalAddr;
       
   344 				IpsecSpi.iDstAddr  = remote_addr;
       
   345 				IpsecSpi.iSPI      = spi;
       
   346 				IpsecSpi.iProtocol = protocol;
       
   347 				IpsecSpi.iInbound  = EFalse;
       
   348 				if (iPluginSession.DeleteIpsecSpi(iNegotiation.SAId(), spi, EFalse))
       
   349 				    {
       
   350 				    DEBUG_LOG(_L("Deleting IPsec SA"));
       
   351                     iPluginSession.DeleteIpsecSA(IpsecSpi.iSPI, IpsecSpi.iSrcAddr, IpsecSpi.iDstAddr, 
       
   352                                                      IpsecSpi.iProtocol);
       
   353 				    }
       
   354 			}	
       
   355             else
       
   356             {
       
   357                 DEBUG_LOG1(_L("IPsec SA with SPI=%x not deleted"), ByteOrder::Swap32(spi));
       
   358             }
       
   359         }
       
   360     }
       
   361 
       
   362 	return ETrue;
       
   363 }