--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/ikev2lib/src/ikev2negotiation.cpp Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,4059 @@
+/*
+* 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: IKEv2/IPSEC SA negotiation
+*
+*/
+
+#include <random.h>
+#include <in_sock.h>
+
+#include "ikev2Negotiation.h"
+#include "ikedebug.h"
+#include "ikev2natt.h"
+#include "ikev2mobike.h"
+#include "ikev2proposal.h"
+#include "ikev2SAdata.h"
+#include "ikev2pluginsession.h"
+#include "ikev2pfkey.h"
+#include "ikev2config.h"
+#include "ikev2EapInterface.h"
+#include "ikev2payloads.h"
+#include "ikev2const.h"
+#include "ikemsgrec.h"
+#include "ipsecproposal.h"
+#include "ipsecselectors.h"
+#include "ikepolparser.h"
+#include "kmdapi.h"
+#include "ikecaelem.h"
+#include "ikecalist.h"
+#include "ikepkiutils.h"
+#include "vpnapidefs.h"
+#include "kmdeventloggerif.h"
+#include "ipsecsalist.h"
+#include "ikev2message.h"
+#include "ikev2identity.h"
+#include "ikev2acquire.h"
+#include "ikev2expire.h"
+#include "ikev2ipsecsarekeydata.h"
+#include "ikev2messagesendqueue.h"
+
+_LIT8(KIkev2PSKData, "Key Pad for IKEv2");
+_LIT8(KZeroDesc, "");
+
+CIkev2Negotiation* CIkev2Negotiation::NewL(CIkev2PluginSession& aIkeV2PlugInSession,
+ CPFKeySocketIf& aPfKeySocketIf,
+ MKmdEventLoggerIf& aEventLogger,
+ CIkev2MessageSendQueue& aMessageSendQue,
+ MIkeDebug& aDebug,
+ CIkeData* aIkeData,
+ TUint32 aVpnIapId,
+ TUint32 aSaId,
+ TInetAddr aPhysicalInterfaceAddress,
+ TInetAddr aRemoteAddress)
+ {
+
+ CIkev2Negotiation* self = new (ELeave) CIkev2Negotiation(aIkeV2PlugInSession, aPfKeySocketIf,
+ aEventLogger, aMessageSendQue,
+ aDebug, aSaId);
+ CleanupStack::PushL(self);
+ self->ConstructL();
+
+ self->iHdr.iIkeData = aIkeData;
+ self->iHdr.iVpnIapId = aVpnIapId;
+ self->iProcessEvents = ETrue;
+ self->iHdr.iRemoteAddr = aRemoteAddress;
+ self->iHdr.iRemoteAddr.SetPort(IKE_PORT);
+
+ //
+ // Get IP address information for IKE SA negotiation
+ // Remote address is taken from current IKE policy data (CIkeData)
+ // Local address is resolved via IKE policy using policy handle
+ //
+ if ( self->iHdr.iRemoteAddr.IsUnspecified() )
+ {
+ self->iHdr.iRemoteAddr = self->iHdr.iIkeData->iAddr;
+ self->iHdr.iRemoteAddr.SetPort(IKE_PORT);
+ }
+ self->iHdr.iDestinAddr = self->iHdr.iRemoteAddr;
+ self->iHdr.iLocalAddr = aPhysicalInterfaceAddress;
+ TInt Scope = self->iHdr.iRemoteAddr.Scope();
+ if ( Scope )
+ self->iHdr.iLocalAddr.SetScope(Scope); // Set local scope same with remote scope
+
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+CIkev2Negotiation* CIkev2Negotiation::NewL(CIkev2PluginSession& aIkeV2PlugInSession,
+ CPFKeySocketIf& aPfKeySocketIf,
+ MKmdEventLoggerIf& aEventLogger,
+ CIkev2MessageSendQueue& aMessageSendQue,
+ MIkeDebug& aDebug,
+ TIkev2SAData& aIkev2SAdata)
+ {
+ CIkev2Negotiation* self = new (ELeave) CIkev2Negotiation(aIkeV2PlugInSession, aPfKeySocketIf,
+ aEventLogger, aMessageSendQue,
+ aDebug, aIkev2SAdata.SaId());
+ CleanupStack::PushL(self);
+ self->ConstructL();
+
+ self->iHdr.Copy(aIkev2SAdata);
+ self->iState = KStateIkeSaCompleted;
+
+ CleanupStack::Pop(self);
+ return self;
+ }
+
+
+CIkev2Negotiation::CIkev2Negotiation(CIkev2PluginSession& aIkeV2PlugInSession, CPFKeySocketIf& aPfKeySocketIf,
+ MKmdEventLoggerIf& aEventLogger, CIkev2MessageSendQueue& aMessageSendQue,
+ MIkeDebug& aDebug, TUint32 aSaId)
+: iChild(aDebug), iIkeV2PlugInSession(aIkeV2PlugInSession), iPfKeySocketIf(aPfKeySocketIf),
+ iEventLogger(aEventLogger), iMessageSendQue(aMessageSendQue),iDebug(aDebug), iDHGroupGuess(1)
+ {
+ DEBUG_LOG1(_L("CIkev2Negotiation::CIkev2Negotiation: 0x%08x"), this);
+
+ iHdr.SetSaId(aSaId);
+ iHdr.iWindowSize = DEF_MSG_ID_WINDOW;
+ }
+
+
+void CIkev2Negotiation::ConstructL()
+ {
+ iTimer = CIkev2RetransmitTimer::NewL(*this);
+ iSpiRetriever = CIpsecSaSpiRetriever::NewL(*this, iPfKeySocketIf);
+
+ iIkeV2PlugInSession.LinkNegotiation(this); // <- takes ownership of this
+ iProcessEvents = ETrue;
+ }
+
+
+CIkev2Negotiation::~CIkev2Negotiation()
+ {
+
+ delete iSpiRetriever;
+ // Turn off event processing to prevent EAPVPNIF event
+ iProcessEvents = EFalse;
+ delete iTimer;
+
+ DEBUG_LOG1(_L("CIkev2Negotiation::~CIkev2Negotiation: 0x%08x"), this);
+ iIkeV2PlugInSession.RemoveNegotiation(this);
+
+ iHdr.CleanUp();
+
+ //
+ // Purge Acquire, Expire and Info message queues
+ //
+ CIkev2Acquire::PurgeQue(GetAcquireQue());
+ CIkev2Expire::PurgeQue(GetExpireQue());
+
+ delete iPeerCert;
+ delete iSavedSaInit;
+ delete iProposedSA;
+ delete iDHKeys;
+ delete iDHPublicPeer;
+ delete iNonce_I;
+ delete iNonce_R;
+ delete iAuthMsgInit;
+ delete iAuthMsgResp;
+ delete iRemoteIdentity;
+ delete iLocalIdentity;
+ delete iNatNotify;
+ delete iConfigMode;
+ delete iEapPlugin;
+ delete iPkiService;
+ delete iPresharedKey;
+ delete iChildSaRequest;
+ }
+
+void CIkev2Negotiation::StartIkeSANegotiationL()
+ {
+ __ASSERT_DEBUG(iChildSaRequest == NULL, User::Invariant());
+
+ //This method should be called only if we have IA in use.
+ //Otherwise the negotiation should start with ProcessAcquire
+ __ASSERT_DEBUG(iHdr.iIkeData->iUseInternalAddr, User::Invariant());
+
+ //
+ // This method is called when an IKE SA negotiation is started due
+ // a RKMD::Activate() request with policy that uses IA.
+ //
+ iHdr.iInitiator = ETrue;
+ LoadEapPluginL();
+
+ GetNonceDataL(ETrue);
+
+ CIkev2Acquire* Acquire = IpsecSelectors::BuildVirtualAcquireL(iIkeV2PlugInSession);
+ CleanupStack::PushL(Acquire);
+
+ if ( !InitPkiServiceL() )
+ {
+ //No PkiService Needed.
+ //Continue by requesting SPI for IPsecSA.
+ CIkev2Acquire::Link(Acquire, GetAcquireQue());
+ //
+ // Get SPI for inbound SA with PFKEY GETSPI primitive
+ //
+ GetIpsecSPI(Acquire);
+ }
+ else
+ {
+ iChildSaRequest = Acquire;
+ }
+ CleanupStack::Pop(Acquire);
+ }
+
+TBool CIkev2Negotiation::StartRespondingL(const ThdrISAKMP& aIkeMessage)
+ {
+ //
+ // This method is called when local end is going to ACT as a
+ // responder of an IKE SA negotiation.
+ // Initialize PKI service usage, if needed. Because PKI service
+ // initialisation is an asynchronous operation we must take a copy
+ // of incoming IKE message from where it is processed when PKI
+ // service initialisation is completed.
+ //
+ TBool Status( InitPkiServiceL() );
+ if ( Status )
+ {
+ TInt MsgLth = (TInt)aIkeMessage.GetLength();
+ delete iSavedSaInit;
+ iSavedSaInit = NULL;
+ iSavedSaInit = HBufC8::NewL(MsgLth);
+ iSavedSaInit->Des().Copy((TUint8*)&aIkeMessage, MsgLth);
+ }
+ return !Status;
+ }
+
+void CIkev2Negotiation::StartIkeSADeleteL()
+{
+ //
+ // This method is called when an IKE SA shall be deleted either due
+ // IKE SA timeout or due a RKMD::Deactivate() request
+ //
+ BuildDeleteRequestL(NULL);
+}
+
+
+void CIkev2Negotiation::IkeSaCompletedL()
+{
+
+ //
+ // This method is when an IKE SA negotiation has been succesfully
+ // completed.
+ // The following actions are taken:
+ // -- Get Virtual IP from iConfigMode object, if present and
+ // modify IKE SA lifetime if Virtual Ip expiration time is
+ // shorter than configured iKE SA lifetime
+ // -- Create a new IKE SA object, if not a rekeyd IKE SA
+ // -- If activation going, call IkeSaCompleted method in plug-in
+ //
+ TVPNAddress VirtualIp;
+ if ( iConfigMode )
+ {
+ VirtualIp = iConfigMode->VirtualIp();
+ iHdr.StoreVirtualIp(VirtualIp.iVPNIfAddr);
+ TUint32 ExpireTime = iConfigMode->ExpireTime();
+ if ( ExpireTime && (ExpireTime < iHdr.iLifetime) )
+ iHdr.iLifetime = ExpireTime;
+ }
+
+ if(!iIkeV2PlugInSession.FindIkev2SA(iHdr.SaId(), KSaStateNotDefined, KSaStateNotDefined))
+ {
+ iIkeV2PlugInSession.CreateIkev2SAL(iHdr);
+ }
+
+ iIkeV2PlugInSession.IkeSaCompleted(KErrNone, VirtualIp);
+
+ iEventLogger.LogEvent(MKmdEventLoggerIf::KLogInfo, R_VPN_MSG_VPN_GW_AUTH_OK, KErrNone,
+ iHdr.iVpnIapId, &iHdr.iRemoteAddr);
+ iEventLogger.LogEvent(MKmdEventLoggerIf::KLogInfo, R_VPN_MSG_ADDR_INFO_FOR_VPN_AP,
+ iHdr.iNATFlags, iHdr.iVpnIapId,
+ (!VirtualIp.iVPNIfAddr.IsUnspecified() ? &(VirtualIp.iVPNIfAddr) : NULL));
+
+ if ( iChildSaRequest )
+ {
+ IpsecSANegotiatedL();
+ }
+ if ( RequestsPending() )
+ {
+ ContinueIkeNegotiationL();
+ }
+ else
+ {
+ if ( !iHdr.iInitiator )
+ {
+ iIkeV2PlugInSession.StopResponding();
+ delete this; // Current negotiation can be deleted
+ }
+ else iStopped = ETrue;
+ }
+}
+
+void CIkev2Negotiation::IkeSaFailed(TInt Status)
+ {
+ //
+ // This method is when a IKE SA negotiation has failed
+ // The following actions are taken:
+ //
+
+ TVPNAddress dummyVirtualIp;
+
+ iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
+
+ if ( !iHdr.iInitiator )
+ iIkeV2PlugInSession.StopResponding();
+
+ if ( (iSendAttempt <= KMaxSendAttemps ) &&
+ ((iState == KStateIkeSaEapStarted) ||
+ (iState == KStateIkeSaEapGoing)))
+ iDeleteIkeSA = ETrue;
+ else iStopped = ETrue;
+
+ iEventLogger.LogEvent(MKmdEventLoggerIf::KLogError, R_VPN_MSG_REAL_IAP_ACT_FAILED, Status,
+ iHdr.iVpnIapId, &iHdr.iRemoteAddr);
+
+ iIkeV2PlugInSession.IkeSaCompleted(Status, dummyVirtualIp);
+ }
+
+void CIkev2Negotiation::IpsecSANegotiatedL()
+{
+ //
+ // This method is when an Ipsec SA negotiation has been succesfully
+ // completed.
+ // -- Update Ipsec SADB using PFKEY Update and Add primitives
+ // -- Find a new IKE SA object and queue Ipsec SA data into it
+ // -- Try to start a new exchange from queue, if there is nothing
+ // to start in queues mark current negotiation stopped
+ //
+ iChild.iSrcSpecific = iChildSaRequest->SrcSpecific();
+ Ikev2Pfkey::UpdateIpsecSaDataBaseL(iHdr, iChild, iIkeV2PlugInSession, *iChildSaRequest);
+
+ CIpsecSARekeyData* rekeyData =
+ CIpsecSARekeyData::NewL(iChildSaRequest->ReplayWindow(),
+ iChildSaRequest->HardLifetime(),
+ iChildSaRequest->SoftLifetime(),
+ iChildSaRequest->TS_i(),
+ iChildSaRequest->TS_r(),
+ *iChildSaRequest->LocalId(),
+ *iChildSaRequest->RemoteId());
+
+ iChild.PurgeKeyMaterial(); // Ipsec Keymaterial not saved into IKE SA
+ iChild.DeleteRekeyData();
+ iChild.iRekeyData = rekeyData;
+
+ iIkeV2PlugInSession.UpdateIkev2SAL(&iHdr, &iChild);
+
+ delete iChildSaRequest;
+ iChildSaRequest = NULL;
+
+ if ( RequestsPending() )
+ ContinueIkeNegotiationL();
+ else
+ { if ( iState == KStateIkeChildSAResponse )
+ delete this;
+ else iStopped = ETrue;
+ }
+}
+
+
+void CIkev2Negotiation::ProcessIkeMessageL(const ThdrISAKMP& aIkeMessage,
+ const TInetAddr& aRemote,
+ TUint16 aLocalPort)
+ {
+ //
+ // Start to process received IKE message by constructing a
+ // CIkev2Payloads object. CIkev2Payloads construction takes also
+ // care of the decryption of an Encrypted payload if present.
+ //
+ TBool Status( ETrue );
+
+ CIkev2Payloads* IkeMsg = CIkev2Payloads::NewL(aIkeMessage, iHdr);
+ CleanupStack::PushL(IkeMsg);
+
+ DEBUG_LOG2(_L("Process IKE message, SAID=%d, Msg ID=%d"),
+ iHdr.SaId(), aIkeMessage.GetMessageId());
+ if ( IkeMsg->Status() )
+ {
+ //
+ // An error occurred during IKE message parsing
+ //
+ SetNotifyCode(IkeMsg->Status());
+ DEBUG_LOG1(_L("Error in parsing of received IKE message: %d"), IkeMsg->Status());
+
+ if ( !iHdr.iInitiator && iState == KStateIdle )
+ {
+ iStopped = ETrue; // Negotiation object shall be released
+ }
+ else
+ {
+ CheckNotifyCodeL(IkeMsg);
+ }
+ CleanupStack::PopAndDestroy(IkeMsg); // IkeMsg
+ return;
+ }
+
+ if ( (iHdr.iNATFlags & (REMOTE_END_NAT + MOBIKE_USED)) &&
+ IkeMsg->Encrypted() )
+ {
+ //
+ // Received IKE message contains Encrypted payload. Save source
+ // IP as new destination IP to negotiation object
+ //
+ iHdr.iDestinAddr = aRemote;
+ iHdr.iDestinAddr.SetPort(FLOATED_IKE_PORT);
+ }
+
+ TPtrC8 ikeMsgDes((TUint8*)&aIkeMessage, aIkeMessage.GetLength());
+
+ TInetAddr localAddr(iHdr.iLocalAddr);
+ localAddr.SetPort(aLocalPort);
+ TRACE_MSG(ikeMsgDes, aRemote, localAddr,
+ (CIkePcapTrace::TEncryptionType)iHdr.iEncrAlg);
+
+ //
+ // Process received IKE message according to Exchange type
+ //
+ switch ( aIkeMessage.GetExchange() )
+ {
+ case IKE_SA_INIT:
+ DEBUG_LOG(_L("IKE_SA_INIT message received"));
+ Status = ProcessIkeSaInitL(IkeMsg, aRemote);
+ if ( !Status )
+ IkeSaFailed(KKmdIkeNegotFailed);
+ break;
+
+ case IKE_AUTH:
+ DEBUG_LOG(_L("IKE_AUTH message received"));
+ Status = ProcessIkeAuthL(IkeMsg);
+ if ( !Status )
+ IkeSaFailed(KKmdIkeAuthFailedErr);
+ break;
+
+ case CREATE_CHILD_SA:
+ DEBUG_LOG(_L("CREATE_CHILD_SA message received"));
+ Status = ProcessChildSaL(IkeMsg);
+ break;
+
+ case INFORMATIONAL:
+ DEBUG_LOG(_L("INFORMATION message received"));
+ Status = ProcessInfoMsgL(IkeMsg);
+ break;
+
+ default:
+ DEBUG_LOG(_L("UNKNOWN message received\n"));
+ Status = EFalse; // Negotiation object shall be released
+ break;
+ }
+
+ if ( !Status )
+ {
+ if ( iDeleteIkeSA )
+ {
+ //
+ // Used IKE SA shall be deleted due the fatal error occurred.
+ //
+ iDeleteIkeSA = EFalse;
+ iIkeV2PlugInSession.DeleteIkev2SA(iHdr.SaId());
+ BuildDeleteRequestL(NULL);
+ }
+ else
+ {
+ CheckNotifyCodeL(IkeMsg);
+ }
+ }
+ CleanupStack::PopAndDestroy(IkeMsg);
+}
+
+void CIkev2Negotiation::ProcessAcquireL(const TPfkeyMessage &aPfkeyMsg)
+ {
+ //
+ // Process received PFKEY Acquire primitive
+ // There is now the following possibilities:
+ // -- There already exists an IKE SA so new IPSEC SA is negotiated
+ // using IKE_CHILD_SA exchange
+ // -- The is no IKE SA yet.
+ // IPSEC SA can be negotiated concatenated during IKE_AUTH.
+ // If Virtual IP is specified, the CP payload is used to get
+ // that virtual IP address.
+ //
+ CIkev2Acquire* Acquire = CIkev2Acquire::NewL(aPfkeyMsg, iIkeV2PlugInSession.GetSAId(),
+ GetLocalAddr(),
+ Ikev2Proposal::GetDHGroup(iHdr.iIkeData->iGroupDesc_II), ImplicitChildSa());
+
+ if ( iState == KStateIdle )
+ {
+ CleanupStack::PushL(Acquire);
+ LoadEapPluginL();
+ iHdr.iInitiator = ETrue;
+ GetNonceDataL(ETrue); // For IKE SA
+ if ( iHdr.iIkeData->iUseInternalAddr )
+ {
+ CArrayFix<TIkeV2TrafficSelector>* TsI = new (ELeave) CArrayFixFlat<TIkeV2TrafficSelector>(1);
+ CleanupStack::PushL(TsI);
+
+ TInetAddr StartIp;
+ TInetAddr EndIp;
+ StartIp.SetAddress(KInetAddrNone); // 0.0.0.0
+ StartIp.SetPort(0);
+ EndIp.SetAddress(KInetAddrAll); // 255.255.255.255
+ EndIp.SetPort(0xffff);
+
+ TIkeV2TrafficSelector ts(StartIp, EndIp,
+ aPfkeyMsg.iDstAddr.iExt->sadb_address_proto);
+ TsI->AppendL(ts);
+ CleanupStack::Pop(TsI);
+ Acquire->ReplaceTS_i(TsI);
+ Acquire->SetVirtualIp();
+ }
+
+ if ( InitPkiServiceL() )
+ {
+ // Store Acquire to wait PKI service init
+ iChildSaRequest = Acquire;
+ CleanupStack::Pop(Acquire);
+ return;
+ }
+ CleanupStack::Pop(Acquire);
+ }
+ CIkev2Acquire::Link(Acquire, GetAcquireQue());
+ GetIpsecSPI(Acquire);
+ }
+
+
+void CIkev2Negotiation::ProcessExpireL(const TPfkeyMessage &aPfkeyMsg)
+ {
+ //
+ // Process received PFKEY Expire primitive
+ // Try to find first IPSEC SA data from the "parent" IKE SA and set
+ // inbound SA to zero in TIpsecSAData
+ //
+ TPtrC8 spi(reinterpret_cast<const TUint8*>(&aPfkeyMsg.iSa.iExt->sadb_sa_spi),
+ sizeof(aPfkeyMsg.iSa.iExt->sadb_sa_spi));
+
+ TIkeV2IpsecSAData* SaData =
+ iIkeV2PlugInSession.FindIpsecSAData(iHdr.SaId(), spi, ETrue);
+ if ( !SaData )
+ {
+ DEBUG_LOG(_L("PFKEY Expire received but no SA data found, stop negotiation"));
+
+ iStopped = ETrue;
+ return;
+ }
+ SaData->iSPI_In.Zero();
+ CIkev2Expire* Expire = CIkev2Expire::NewL(aPfkeyMsg);
+ CIkev2Expire::Link(Expire, GetExpireQue());
+
+ ContinueIkeNegotiationL();
+}
+
+void CIkev2Negotiation::StartIpsecSaRekeyingL(const TPfkeyMessage &aPfkeyMsg)
+{
+
+ TPtrC8 spi(reinterpret_cast<const TUint8*>(&aPfkeyMsg.iSa.iExt->sadb_sa_spi),
+ sizeof(aPfkeyMsg.iSa.iExt->sadb_sa_spi));
+ TIkeV2IpsecSAData* SaData =
+ iIkeV2PlugInSession.FindIpsecSAData(iHdr.SaId(), spi, ETrue);
+ if ( !SaData )
+ {
+ DEBUG_LOG(_L("No IPSec SA data found, stop rekeying"));
+ iStopped = ETrue;
+ return;
+ }
+
+ iStopped = ETrue;
+
+ CArrayFix<TIkeV2TrafficSelector>* tsIArray = SaData->iRekeyData->TsIL();
+ CleanupStack::PushL(tsIArray);
+
+ CArrayFix<TIkeV2TrafficSelector>* tsRArray = SaData->iRekeyData->TsRL();
+ CleanupStack::PushL(tsRArray);
+
+ __ASSERT_DEBUG(tsIArray->Count() > 0, User::Invariant());
+ __ASSERT_DEBUG(tsRArray->Count() > 0, User::Invariant());
+
+ TIkeV2TrafficSelector tsI = (*tsIArray)[0];
+ TIkeV2TrafficSelector tsR = (*tsRArray)[0];
+
+ CleanupStack::PopAndDestroy(tsRArray);
+ CleanupStack::PopAndDestroy(tsIArray);
+
+
+ TInetAddr localSelector;
+ TInetAddr localSelectorMask;
+
+ TInetAddr remoteSelector;
+ TInetAddr remoteSelectorMask;
+
+ if (iHdr.iInitiator)
+ {
+ localSelector = tsI.StartingAddress();
+ localSelectorMask = tsI.Mask();
+
+ remoteSelector = tsR.StartingAddress();
+ remoteSelectorMask = tsR.Mask();
+ }
+ else
+ {
+ localSelector = tsR.StartingAddress();
+ localSelectorMask = tsR.Mask();
+
+ remoteSelector = tsI.StartingAddress();
+ remoteSelectorMask = tsI.Mask();
+ }
+
+ CIpsecSaSpecList* SaList = iIkeV2PlugInSession.GetIPsecSaSpecListL(localSelector, localSelectorMask, //local address/port info
+ remoteSelector, remoteSelectorMask,
+ aPfkeyMsg.iDstAddr.iExt->sadb_address_proto);
+
+
+ CleanupStack::PushL(SaList);
+ __ASSERT_DEBUG(SaList != NULL, User::Invariant());
+ __ASSERT_DEBUG(SaList->Count() > 0, User::Invariant());
+ iStopped = EFalse;
+
+ const TIpsecSaSpec& saSpec = SaList->At(0);
+
+ CIkev2Acquire* Acquire = CIkev2Acquire::NewL(aPfkeyMsg, iIkeV2PlugInSession.GetSAId(), GetLocalAddr(),
+ Ikev2Proposal::GetDHGroup(iHdr.iIkeData->iGroupDesc_II), ImplicitChildSa(),
+ &saSpec, SaData->iRekeyData);
+ CleanupStack::PopAndDestroy(SaList); //SaList
+
+ Acquire->SetSPI_ToBeRekeyed(spi);
+
+ if ( iState == KStateIdle )
+ {
+ CleanupStack::PushL(Acquire);
+ LoadEapPluginL();
+ iHdr.iInitiator = ETrue;
+ GetNonceDataL(ETrue); // For IKE SA
+ if ( iHdr.iIkeData->iUseInternalAddr )
+ {
+ CArrayFix<TIkeV2TrafficSelector>* TsI = new (ELeave) CArrayFixFlat<TIkeV2TrafficSelector>(1);
+ CleanupStack::PushL(TsI);
+
+ TInetAddr StartIp;
+ TInetAddr EndIp;
+ StartIp.SetAddress(KInetAddrNone); // 0.0.0.0
+ StartIp.SetPort(0);
+ EndIp.SetAddress(KInetAddrAll); // 255.255.255.255
+ EndIp.SetPort(0xffff);
+
+ TIkeV2TrafficSelector ts(StartIp, EndIp,
+ aPfkeyMsg.iDstAddr.iExt->sadb_address_proto);
+ TsI->AppendL(ts);
+ Acquire->ReplaceTS_i(TsI);
+ CleanupStack::Pop(TsI);
+ Acquire->SetVirtualIp();
+ }
+
+ if ( InitPkiServiceL() )
+ {
+ iChildSaRequest = Acquire; // Store Acquire to wait PKI service init
+ CleanupStack::Pop(Acquire);
+ return;
+ }
+ CleanupStack::Pop(Acquire);
+ }
+ CIkev2Acquire::Link(Acquire, GetAcquireQue());
+ GetIpsecSPI(Acquire);
+}
+
+void CIkev2Negotiation::GetIpsecSPI(CIkev2Acquire* aAcquire)
+ {
+ ASSERT(aAcquire);
+ //
+ // Get SPI for inbound SA with PFKEY GETSPI primitive
+ //
+ TInetAddr DstAddr;
+ if ( aAcquire->SrcSpecific() )
+ DstAddr = iHdr.iLocalAddr;
+ else DstAddr.Init(0);
+ DstAddr.SetPort(0);
+ TInetAddr SrcAddr = iHdr.iRemoteAddr;
+ SrcAddr.SetPort(0);
+
+ iSpiRetriever->GetIpsecSaSpi(aAcquire->Id(),
+ aAcquire->IpsecProtocol(),
+ SrcAddr, DstAddr);
+ }
+
+
+void CIkev2Negotiation::IpsecSaSpiRetrieved(TUint32 aSpiRequestId,
+ TInt aStatus,
+ TUint32 aSpi)
+ {
+ if (aStatus == KErrNone)
+ {
+ TRAP(aStatus, IpsecSaSpiRetrievedL(aSpiRequestId, aSpi));
+ }
+
+ if (aStatus != KErrNone)
+ {
+ //Leave that we have not been able to handle
+ //above layers. We bail out and report error.
+ iIkeV2PlugInSession.DeleteIkev2SA(iHdr.SaId());
+ iIkeV2PlugInSession.IkeSaDeleted(aStatus);
+ delete this;
+ }
+ }
+
+void CIkev2Negotiation::CancelOperation()
+ {
+ if ( iTimer != NULL )
+ {
+ iTimer->Cancel();
+ }
+ if ( iSpiRetriever != NULL )
+ {
+ iSpiRetriever->Cancel();
+ }
+ }
+
+void CIkev2Negotiation::IpsecSaSpiRetrievedL(TUint32 aSpiRequestId, TUint32 aSpi)
+ {
+ DEBUG_LOG(_L("CIkev2Negotiation::SpiRetrievedL"));
+
+ //
+ // Ipsec SPI received. Find an Acquire object for received SPI and
+ // save SPI into found object.
+ //
+ CIkev2Acquire* Acquire = CIkev2Acquire::Find(aSpiRequestId, GetAcquireQue());
+ __ASSERT_DEBUG(Acquire, User::Invariant());
+
+ TPtrC8 spiPtr(reinterpret_cast<TUint8*>(&aSpi), sizeof(aSpi));
+ Acquire->SetSPI_In(spiPtr);
+ //
+ // Ipsec SPI received. Find an Acquire object for received SPI and
+ // save SPI into found object.
+ //
+ ContinueIkeNegotiationL();
+ }
+
+void CIkev2Negotiation::ContinueIkeNegotiationL()
+{
+ //
+ // This method takes actions according to current state (iState) of
+ // the negotiation.
+ //
+ CIkev2Acquire* Acquire;
+ CIkev2Expire* Expire;
+
+ switch ( iState )
+ {
+ case KStateIdle:
+ //
+ // Start IKE_SA_INIT exchange
+ //
+ StartIkeSaInitL();
+ break;
+
+ case KStateIkeSaAuthWaitSpi:
+ {
+ //
+ // Complete IKE_AUTH exchange (with concatenated Child SA)
+ //
+ iChildSaRequest = CIkev2Acquire::GetNext(GetAcquireQue(), ETrue);
+
+ DEBUG_LOG(_L("CIkev2Negotiation::ContinueIkeNegotiationL"));
+ DEBUG_LOG1(_L("iChildSaRequest is %d"), (TInt)iChildSaRequest);
+
+ SendIkeAuthMessageL();
+ }
+ break;
+
+ case KStateIkeSaCompleted:
+ //
+ // There is no activity going on this negotiation
+ // If there is something in request queues start process
+ // them in the following order:
+ // -- Check if there is something in info queue (NIY)
+ // -- Check if there is something in expire queue (NIY)
+ // -- Check if there is ready responses in acquire queue
+ // -- Check if there is ready request in acquire queue
+ //
+ Expire = CIkev2Expire::GetNext(GetExpireQue());
+ if ( Expire )
+ {
+ CleanupStack::PushL(Expire);
+ BuildDeleteRequestL(Expire);
+ CleanupStack::PopAndDestroy(Expire);
+ }
+ else
+ {
+ Acquire = CIkev2Acquire::GetNext(GetAcquireQue(), ETrue);
+ if ( Acquire )
+ {
+ BuildChildSAMessageL(Acquire, EFalse);
+ }
+ else
+ {
+ Acquire = CIkev2Acquire::GetNext(GetAcquireQue(), EFalse);
+ BuildChildSAMessageL(Acquire, ETrue);
+ }
+ }
+ break;
+
+ default:
+ break;
+ }
+}
+
+void CIkev2Negotiation::StartIkeSaInitL()
+ {
+ //
+ // Create Initiator SPI for the new IKE SA
+ //
+ CreateIkeSPI(iHdr.SpiI());
+
+ //
+ // Get required peer identity from policy (IDr)
+ //
+ iRemoteIdentity = Ikev2Proposal::GetRemoteIdentityL(iHdr.iIkeData);
+
+ __ASSERT_ALWAYS(iHdr.iInitiator, User::Invariant());
+ //
+ // Build and send the first IKE_SA_INIT message (request)
+ // HDR, SAi1, KEi, Ni, N[NAT_SRC], N[NAT_DST]
+ //
+ CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
+ iHdr.SpiR(),
+ IKE_SA_INIT,
+ iHdr.iInitiator,
+ EFalse,
+ iHdr.NextRequestId(),
+ iDebug);
+ CleanupStack::PushL(ikeMsg);
+
+ HBufC8* saBfr = Ikev2Proposal::FromPolicyToProposaL(iHdr, iSPI_Rekey, iDHGroupGuess);
+ CleanupStack::PushL(saBfr);
+ ikeMsg->AppendSaPayloadL(*saBfr);
+ CleanupStack::Pop(saBfr);
+ SetProposedSa(saBfr);
+
+ AppendKEPayloadL(*ikeMsg, iHdr.iDHGroup);
+ ikeMsg->AppendNoncePayloadL(*iNonce_I);
+ if ( !iHdr.iIkeData->iUseNatProbing )
+ {
+ delete iNatNotify;
+ iNatNotify = NULL;
+
+ TInetAddr LocalIp;
+ if ( iHdr.iIkeData->iUseMobIke )
+ LocalIp.SetAddress(KInetAddrNone);
+ else LocalIp = iHdr.iLocalAddr;
+ iNatNotify = CIkev2NatT::NewL(
+ LocalIp, iHdr.iRemoteAddr, IKE_PORT, ikeMsg->InitiatorSpi(), ikeMsg->ResponderSpi());
+
+ ikeMsg->AppendNotifyPayloadL(IKEV2_PROTOCOL, KZeroDesc, NAT_DETECTION_SOURCE_IP,
+ iNatNotify->SourceNofify());
+ ikeMsg->AppendNotifyPayloadL(IKEV2_PROTOCOL, KZeroDesc, NAT_DETECTION_DESTINATION_IP,
+ iNatNotify->DestinNofify());
+ }
+ CleanupStack::Pop(ikeMsg);
+
+ SendIkeMsgL(ikeMsg);
+ iState = KStateIkeSaInitRequest;
+ }
+
+void CIkev2Negotiation::SendIkeAuthMessageL()
+{
+ //
+ // Build and send IKE_AUTH message
+ // IKE_AUTH message sent by the initiator is the following:
+ // HDR(A,B), SK {IDi, [CERT] [CERTREQ], [IDr], [AUTH], [CP], [SAi2,
+ // TSi, TSr]}
+ // IKE_AUTH message sent by the responder is the following:
+ // HDR(A,B), SK {IDr, [CERT,] AUTH, [CP], [SAr2, TSi, TSr]}
+ // CERT and CERTREQ payloads are added into message on when needed.
+ // AUTH payload is missing from initiators message when EAP in use.
+ // IPSEC SA:s are not always negotiated within IKE_AUTH messages.
+ // In this sitution SAx2, TSi and TSr payloads shall be missing.
+ // CP payload is used the Virtual IP address (secure network DNS
+ // IP:s) for client Virtual IP interface.
+ // Initiators CP payload shall contain CFG_REQUEST and and
+ // responders CP payload CFG_REPLY.
+ // When CP payload is used IKE_AUTH message MUST always contain
+ // IPSEC SA negotiation payloads within.
+ // In case INITIAL_CONTACT is used, the first IKE_AUTH request on given
+ // IKE SA contains INITIAL_CONTACT Notification Payload that is added in
+ // the end of the IKE_AUTH message.
+ //
+
+ if ( !iLocalIdentity )
+ {
+ //
+ // Own identity does not exists yet. Do not build IKE_AUTH
+ // message now
+ //
+ iState = KStateIkeWaitingId;
+ return;
+ }
+
+ TUint32 MsgId = (iHdr.iInitiator) ? iHdr.NextRequestId() : iHdr.ExpectedRequestId();
+ CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
+ iHdr.SpiR(),
+ IKE_AUTH,
+ iHdr.iInitiator,
+ !iHdr.iInitiator, //Initiator sends only requests
+ MsgId,
+ iDebug);
+ CleanupStack::PushL(ikeMsg);
+
+ ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);
+
+ __ASSERT_DEBUG(iLocalIdentity != NULL, User::Invariant());
+ if (iHdr.iInitiator)
+ {
+ ikeMsg->AppendIdiPayloadL(*iLocalIdentity);
+ }
+ else
+ {
+ ikeMsg->AppendIdrPayloadL(*iLocalIdentity);
+ }
+
+ if ( iPkiService &&
+ iPkiService->UserCertificateData().Length() > 0)
+ {
+ ikeMsg->AppendCertPayloadL(iPkiService->UserCertificateData());
+ }
+
+ if ( iPkiService &&
+ iPkiService->I2CertificateData().Length() > 0)
+ {
+ ikeMsg->AppendCertPayloadL(iPkiService->I2CertificateData());
+ }
+
+ if ( iPkiService &&
+ iPkiService->I1CertificateData().Length() > 0)
+ {
+ ikeMsg->AppendCertPayloadL(iPkiService->I1CertificateData());
+ }
+
+ if ( iHdr.iInitiator && iHdr.iIkeData->iInitialContact )
+ {
+ ikeMsg->AppendNotifyPayloadL(IKEV2_PROT_NONE, KZeroDesc, INITIAL_CONTACT, KZeroDesc);
+ }
+
+
+ if ( iHdr.iInitiator && iPkiService != NULL && iPkiService->CaList().Count() > 0)
+ {
+ ikeMsg->AppendCertReqPayloadL(iPkiService->CaList());
+ }
+
+ if ( iHdr.iInitiator && iRemoteIdentity )
+ {
+ //
+ // Add IDr payload
+ //
+ ikeMsg->AppendIdrPayloadL(*iRemoteIdentity);
+ }
+ if ( !iEapPlugin )
+ {
+ HBufC8* authData = NULL;
+ if ( iHdr.iInitiator )
+ {
+ authData = SignAuthDataL(*iAuthMsgInit, (TUint8)iHdr.iAuthMethod);
+ }
+ else
+ {
+ authData = SignAuthDataL(*iAuthMsgResp, (TUint8)iHdr.iAuthMethod);
+ }
+ CleanupStack::PushL(authData);
+ ikeMsg->AppendAuthPayloadL(iHdr.iAuthMethod, *authData);
+ CleanupStack::PopAndDestroy(authData);
+ }
+ if ( iHdr.iIkeData->iUseMobIke )
+ {
+ //
+ // Add MOBIKE_SUPPORTED notify payload
+ //
+ ikeMsg->AppendNotifyPayloadL(IKEV2_PROT_NONE,
+ KZeroDesc,
+ MOBIKE_SUPPORTED,
+ KZeroDesc);
+ }
+
+
+ //
+ // Add Child SA and Traffic selector payloads into IKE_AUTH message
+ // if required
+ //
+ if ( iChildSaRequest )
+ {
+ iChild.iSPI_In = iChildSaRequest->SPI_In();
+ iChildSaRequest->AddIpsecSpiToSa(iChild.iSPI_In);
+ if ( iChildSaRequest->ForVirtualIp() )
+ {
+ //
+ // As Virtual Ip from peer SGW using Config Payload
+ // Build CP request data by constructing CIkev2Config Object
+ //
+ if ( !iConfigMode )
+ iConfigMode = CIkev2Config::NewL(iChildSaRequest);
+
+ ikeMsg->AppendConfigurationPayloadL(iConfigMode->CpType(), iConfigMode->Cp());
+ }
+ ikeMsg->AppendSaPayloadL(*iChildSaRequest->SA());
+
+ ikeMsg->AppendTsiPayloadL(iChildSaRequest->TS_i());
+ ikeMsg->AppendTsrPayloadL(iChildSaRequest->TS_r());
+ }
+
+ CleanupStack::Pop(ikeMsg);
+ SendIkeMsgL(ikeMsg);
+
+ if ( iHdr.iInitiator )
+ {
+ if ( iEapPlugin )
+ iState = KStateIkeSaEapStarted;
+ else iState = KStateIkeSaAuthRequest;
+ }
+ else
+ {
+ iState = KStateIkeSaCompleted;
+ IkeSaCompletedL();
+ }
+
+}
+
+void CIkev2Negotiation::SendKeepAliveMsgL()
+ {
+ CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
+ iHdr.SpiR(),
+ INFORMATIONAL,
+ iHdr.iInitiator,
+ EFalse,
+ iHdr.NextRequestId(),
+ iDebug);
+
+ ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);
+ SendIkeMsgL(ikeMsg);
+ iState = KStateIkeInfoRequest;
+
+ DEBUG_LOG(_L("CIkev2Negotiation::SendKeepAliveMsgL"));
+ }
+
+
+void CIkev2Negotiation::BuildChildSAMessageL(
+ CIkev2Acquire* aAcquire, TBool aInitiator)
+ {
+ ASSERT(aAcquire);
+ //
+ // Build and send CREATE_CHILD_SA message
+ // CREATE_CHILD_SA request message sent is the following:
+ // HDR(A,B), SK {[N], SA, Ni, [KEi], [TSi, TSr]}
+ // CREATE_CHILD_SA response message is the following:
+ // HDR(A,B), SK {SA, Nr, [KEi], [TSi, TSr]}
+ //
+ iChild.iSPI_In = aAcquire->SPI_In();
+ iChildSaRequest = aAcquire;
+ //TPayloadIkev2* PreviousPayload;
+ //TPayloadIkev2* EncrPayload;
+ GetNonceDataL(aInitiator);
+ aAcquire->AddIpsecSpiToSa(aAcquire->SPI_In());
+
+ TUint32 MsgId = (aInitiator) ? iHdr.NextRequestId() : iHdr.ExpectedRequestId();
+
+ CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
+ iHdr.SpiR(),
+ CREATE_CHILD_SA,
+ iHdr.iInitiator,
+ !aInitiator,
+ MsgId,
+ iDebug);
+
+ ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);
+
+ if (aInitiator && aAcquire->SPI_ToBeRekeyed().Length() > 0)
+ {
+ ikeMsg->AppendNotifyPayloadL(aAcquire->IpsecProtocol(),
+ aAcquire->SPI_ToBeRekeyed(),
+ REKEY_SA, KZeroDesc);
+ }
+ ikeMsg->AppendSaPayloadL(*aAcquire->SA());
+
+ if ( aInitiator )
+ {
+ ikeMsg->AppendNoncePayloadL(*iNonce_I);
+ }
+ else
+ {
+ ikeMsg->AppendNoncePayloadL(*iNonce_R);
+ }
+
+ delete iDHKeys; // Delete old DH object
+ iDHKeys = NULL;
+ if ( aAcquire->DHGroup() )
+ {
+ AppendKEPayloadL(*ikeMsg, aAcquire->DHGroup());
+ }
+ ikeMsg->AppendTsiPayloadL(aAcquire->TS_i());
+ ikeMsg->AppendTsrPayloadL(aAcquire->TS_r());
+
+ SendIkeMsgL(ikeMsg);
+
+ if ( aInitiator )
+ {
+ iState = KStateIkeChildSARequest;
+ }
+ else
+ {
+ if (iDHKeys && iDHPublicPeer)
+ {
+ HBufC8* g_ir = iDHKeys->ComputeAgreedKeyL(iDHPublicPeer->Des());
+ CleanupStack::PushL(g_ir);
+
+ iChild.GenerateIpsecKeysL(iHdr.iSK_d, *g_ir,
+ *iNonce_I, *iNonce_R, iHdr.iPRFAlg);
+
+ g_ir->Des().FillZ(); // Wipe out shared secret value from buffer
+ CleanupStack::PopAndDestroy(); //g_ir
+ }
+ else
+ {
+ iChild.GenerateIpsecKeysL(iHdr.iSK_d, KZeroDesc,
+ *iNonce_I, *iNonce_R, iHdr.iPRFAlg);
+ }
+
+ IpsecSANegotiatedL();
+ iState = KStateIkeChildSAResponse;
+ }
+}
+
+void CIkev2Negotiation::BuildDeleteRequestL(CIkev2Expire* aExpire)
+{
+ //
+ // Build and send INFORMATIONAL exchange message with delete payload
+ // HDR(A,B), SK {D}
+ // If CIkev2Expire object defined, build a Delete payload with Ipsec
+ // SPI and protocl stored into CIkev2Expire object. If no CIkev2Expire build
+ // Delete payload for IKE SA.
+ //
+ CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
+ iHdr.SpiR(),
+ INFORMATIONAL,
+ iHdr.iInitiator,
+ EFalse,
+ iHdr.NextRequestId(),
+ iDebug);
+
+ ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);
+
+ CDesC8Array* spiArray = new (ELeave) CDesC8ArrayFlat(2);
+ CleanupStack::PushL(spiArray);
+ if ( aExpire )
+ {
+ spiArray->AppendL(aExpire->SPI());
+ ikeMsg->AppendDeletePayloadL(aExpire->Protocol(), *spiArray);
+ }
+ else
+ {
+ ikeMsg->AppendDeletePayloadL(IKEV2_PROTOCOL, *spiArray);
+ }
+ CleanupStack::PopAndDestroy(spiArray);
+
+ SendIkeMsgL(ikeMsg);
+ DEBUG_LOG(_L("CIkev2Negotiation::BuildDeleteRequestL() Delete send OK"));
+
+ if ( aExpire )
+ {
+ iState = KStateChildDeleteRequest;
+ }
+ else
+ {
+ iState = KStateIkeDeleteRequest;
+ }
+}
+
+void CIkev2Negotiation::BuildIkeSaRekeyMsgL(TBool aRequest)
+{
+ //
+ // Build and send CHILD_SA exchange message which contains IKE SA
+ // rekey message (either request or response)
+ // HDR, SA, Nonce, KE
+ //
+ HBufC8* SaBfr;
+ HBufC8* Nonce;
+ TUint32 MsgId;
+
+ if ( aRequest )
+ {
+ // Get a new SA Id for rekeyed IKE SA
+ iSAid_Rekey = iIkeV2PlugInSession.GetSAId();
+ CreateIkeSPI(iSPI_Rekey, ETrue);
+ SaBfr = Ikev2Proposal::FromPolicyToProposaL(iHdr, iSPI_Rekey, iDHGroupGuess, ETrue);
+ SetProposedSa(SaBfr); // Save SA payload buffer
+ GetNonceDataL(ETrue);
+ Nonce = iNonce_I;
+ MsgId = iHdr.NextRequestId();
+ }
+ else
+ {
+ SaBfr = PeekProposedSa();
+ Ikev2Proposal::ChangeSpiInProposal(SaBfr, iSPI_Rekey);
+ GetNonceDataL(EFalse);
+ Nonce = iNonce_R;
+ MsgId = iHdr.ExpectedRequestId();
+ }
+
+ CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
+ iHdr.SpiR(),
+ CREATE_CHILD_SA,
+ iHdr.iInitiator,
+ !aRequest,
+ MsgId,
+ iDebug);
+
+ ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);
+ ikeMsg->AppendSaPayloadL(*SaBfr);
+ ikeMsg->AppendNoncePayloadL(*Nonce);
+ AppendKEPayloadL(*ikeMsg, iHdr.iDHGroup);
+
+ SendIkeMsgL(ikeMsg);
+
+ if ( aRequest )
+ {
+ iState = KStateIkeSARekeyRequest;
+ }
+}
+
+void CIkev2Negotiation::CheckNotifyCodeL(CIkev2Payloads* aIkeMsg)
+ {
+ ASSERT(aIkeMsg);
+ //
+ // Some error has occurred during incoming IKE message handling
+ // Build an error response with specified Notify message type
+ //
+ TInt MsgType( GetNotifyCode() );
+
+ if ( MsgType )
+ {
+ //
+ // Build and error response/request with Notify payload
+ // If received message with error condition is a request
+ // Notify payload is transmitted in the response IKE message
+ // of ongoing exchange (with erronous request message id)
+ // If received message with error conditions is a response
+ // an informational exchange is initiated with Notify payload
+ //
+ CIkeV2Message* XmitHdr = NULL;
+ TBool Response(aIkeMsg->GetIkeMsg()->GetFlags() & IKEV2_RESPONSE_MSG);
+ if ( Response )
+ {
+ iState = KStateIkeInfoRequest;
+ TUint32 MsgId = aIkeMsg->GetIkeMsg()->GetMessageId();
+ XmitHdr = CIkeV2Message::NewL(iHdr.SpiI(),
+ iHdr.SpiR(),
+ INFORMATIONAL,
+ iHdr.iInitiator,
+ EFalse,
+ MsgId,
+ iDebug);
+
+ }
+ else
+ {
+ XmitHdr = CIkeV2Message::NewL(iHdr.SpiI(),
+ iHdr.SpiR(),
+ aIkeMsg->GetIkeMsg()->GetExchange(),
+ iHdr.iInitiator,
+ ETrue,
+ iHdr.ExpectedRequestId(),
+ iDebug);
+ }
+
+ if (aIkeMsg->Encrypted())
+ {
+ XmitHdr->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);
+ }
+
+ TInt notifyDataLength = 0;
+ TUint8* notifyData = NotifyData(notifyDataLength);
+
+ if (notifyDataLength == 0)
+ {
+ XmitHdr->AppendNotifyPayloadL(IKEV2_PROT_NONE, KZeroDesc, MsgType, KZeroDesc);
+ }
+ else
+ {
+ TPtrC8 notifyDataPtrC(notifyData, notifyDataLength);
+ XmitHdr->AppendNotifyPayloadL(IKEV2_PROT_NONE, KZeroDesc, MsgType, notifyDataPtrC);
+ iNotifyDataLth = 0; //Reset notifydata
+ }
+
+ SendIkeMsgL(XmitHdr);
+
+ iEventLogger.LogEvent(MKmdEventLoggerIf::KLogError, R_VPN_MSG_SENT_ERROR_RESPONSE,
+ MsgType, iHdr.iVpnIapId, &iHdr.iRemoteAddr);
+ }
+ }
+
+
+void CIkev2Negotiation::GetNatStatus(TBool aSupported, const TInetAddr& aRemote)
+{
+ //
+ // Examine NAT discovery status (from iHdr.iNATFlags) and set
+ // floated port usage indicator, if required.
+ //
+ if ( aSupported )
+ {
+ if ( iHdr.iNATFlags & (REMOTE_END_NAT + LOCAL_END_NAT) )
+ {
+ if ( iHdr.iNATFlags & REMOTE_END_NAT )
+ {
+ //
+ // Remote end is behind NAT. Save current source IP to be
+ // used as further destination address.
+ // When remote and is behind NAT it is supposed that it
+ // must be pure mapping between public- and private IP
+ // addresses (remote NAPT is NOT supported)
+ //
+ DEBUG_LOG(_L("Remote end is behind NAT"));
+ iHdr.iDestinAddr = aRemote; // Remote end behind NAT, use current source IP as destin
+ }
+
+ if ( iHdr.iNATFlags & LOCAL_END_NAT )
+ {
+ DEBUG_LOG(_L("NAT discovery result: Local end is behind NAT"));
+ }
+ iHdr.iFloatedPort = ETrue;
+ iHdr.iDestinAddr.SetPort(FLOATED_IKE_PORT);
+ }
+ else
+ {
+ if ( iHdr.iMobikeUsed )
+ {
+ iHdr.iFloatedPort = ETrue;
+ iHdr.iDestinAddr.SetPort(FLOATED_IKE_PORT);
+ }
+ DEBUG_LOG(_L("NAT discovery result: There is no NAT between negotiating ends"));
+ }
+ }
+ else
+ {
+ DEBUG_LOG(_L("NAT discovery operation failed"));
+ }
+}
+
+void CIkev2Negotiation::CreateIkeSPI(TIkeSPI& aSPI, TBool aRekey)
+{
+ //
+ // Create IKE SPI for local end.
+ // The SPI value is created from the following "parameters" in
+ // IKEv2 negotiation object:
+ // - The first 4 octets of SPI value are the SAId (32 bit value)
+ // - The last 4 octets of SPI contains "pseudo random" value:
+ // X = (SAId + negotiation object pointer) >> (SAId & 3)
+ //
+ TUint32 SpiValue1;
+ TUint32 SpiValue2;
+ if ( aRekey )
+ SpiValue1 = iSAid_Rekey;
+ else SpiValue1 = iHdr.SaId();
+ Mem::Copy((TUint8*)&SpiValue2, (TUint8*)this, 4);
+ SpiValue2 = (SpiValue2 + SpiValue1) >> (SpiValue1 & 3);
+ PUT32(aSPI.Ptr(), SpiValue1);
+ PUT32((aSPI.Ptr() + 4), SpiValue2);
+ aSPI.SetLength(IKEV2_SPI_SIZE);
+}
+
+void CIkev2Negotiation::LoadEapPluginL()
+{
+ //
+ // If EAP configured in policy, construct EAP interface object to
+ // communicate EAP ECOM plug-in
+ // If consruction causes an error, stop negotiation request
+ //
+ iHdr.iEAPType = iHdr.iIkeData->iEAPProtocol;
+ if ( !iEapPlugin && iHdr.iEAPType )
+ {
+ iEapPlugin = CIkev2EapIf::NewL(*this, (TUint8)iHdr.iEAPType, iHdr.iIkeData, iDebug);
+ TInt Status = iEapPlugin->Status();
+ if ( Status != KErrNone )
+ {
+ iStopped = ETrue;
+ }
+ else iEapPlugin->QueryIdentity();
+ }
+}
+
+TBool CIkev2Negotiation::InitPkiServiceL()
+{
+ DEBUG_LOG(_L("-> CIkev2Negotiation::InitPkiServiceL"));
+ //
+ // If EAP configured in policy, construct EAP interface object to
+ // communicate EAP ECOM plug-in
+ // If consruction causes an error, return corresponding error code
+ // to stop negotiation request
+ //
+ TBool Status = EFalse;
+ if ( !iPkiService && Ikev2Proposal::PkiServiceNeeded(iHdr.iIkeData) )
+ {
+ iPkiService = CIkeV2PkiService::NewL(*this, iDebug);
+
+ if (iHdr.iIkeData->iCAList->Count() == 0)
+ {
+ User::Leave(KVpnErrInvalidCaCertFile);
+ }
+
+ iPkiService->InitIkeV2PkiService(iHdr.iIkeData);
+ iState = KStateIkeInitPkiService;
+ Status = ETrue;
+ }
+
+ DEBUG_LOG(_L("<- CIkev2Negotiation::InitPkiServiceL"));
+ return Status;
+}
+
+
+void CIkev2Negotiation::SendIkeMsgL(CIkeV2Message* aMsg)
+{
+ ASSERT(aMsg);
+
+ TPtrC8 encryptionKey;
+ TPtrC8 integrityKey;
+ if ( iHdr.iInitiator )
+ {
+ encryptionKey.Set(iHdr.iSK_ei);
+ integrityKey.Set(iHdr.iSK_ai);
+ }
+ else
+ {
+ encryptionKey.Set(iHdr.iSK_er);
+ integrityKey.Set(iHdr.iSK_ar);
+ }
+
+ TInetAddr sourceAddr(iHdr.iLocalAddr);
+ if (iHdr.iFloatedPort)
+ {
+ sourceAddr.SetPort(FLOATED_IKE_PORT);
+ }
+ else
+ {
+ sourceAddr.SetPort(IKE_PORT);
+ }
+ aMsg->PrepareIkeMessageDatagramL(iHdr.iEncrAlg, encryptionKey,
+ iHdr.iIntegAlg, integrityKey,
+ sourceAddr, iHdr.iDestinAddr);
+ iMessageSendQue.SendIkeMessageL(aMsg->IkeMessageDatagram(), iHdr.iFloatedPort);
+
+ if (aMsg->Flags() & IKEV2_RESPONSE_MSG )
+ {
+ iHdr.SaveRespMsg(aMsg);
+ iHdr.iRespRetryCount = 0;
+ }
+ else
+ {
+ iSendAttempt = 1;
+ iTimer->Cancel();
+ iTimer->IssueRequest(iSendAttempt); // Start retry timer
+
+ iHdr.SaveRequestMsg(aMsg);
+ }
+}
+
+void CIkev2Negotiation::RetransmitRequest()
+ {
+ TRAPD(err, DoRetransmitL(EFalse));
+ if ( err != KErrNone )
+ {
+ iIkeV2PlugInSession.IkeSaDeleted( err );
+ }
+ }
+
+void CIkev2Negotiation::DoRetransmitL(TBool aResponse)
+{
+ if ( aResponse )
+ {
+ //
+ // Peer has retransmitted a request, retransmit last response
+ // message saved.
+ //
+ if ( iHdr.iLastResponse && (iHdr.iRespRetryCount <= KMaxSendAttemps) )
+ {
+ iHdr.iRespRetryCount ++;
+ //iHdr.iLastResponse = NULL;
+ DEBUG_LOG3(_L("IKE response message rexmitted on SAId: %d , Retry: %d , State: %d"), iHdr.SaId(), iHdr.iRespRetryCount, iState );
+
+ iMessageSendQue.SendIkeMessageL(iHdr.iLastResponse->IkeMessageDatagram(),
+ iHdr.iFloatedPort);
+ }
+ else iStopped = ETrue;
+ }
+ else
+ {
+ //
+ // No response received to a transmitted IKE request message
+ // Retransmit message if retry count not exhausted
+ //
+ DEBUG_LOG(_L("No response received for transmitted IKE request."));
+
+ iSendAttempt++;
+ iMessageSendQue.CancelSend(iHdr.iLastRequest->IkeMessageDatagram());
+
+ if ( iSendAttempt <= KMaxSendAttemps )
+ {
+ DEBUG_LOG3(_L("IKE Message rexmitted on SAId: %d , State: %d , Retry: %d"),iHdr.SaId(), iState, iSendAttempt );
+ iMessageSendQue.SendIkeMessageL(iHdr.iLastRequest->IkeMessageDatagram(),
+ iHdr.iFloatedPort);
+ iTimer->IssueRequest(iSendAttempt); // Restart retry timer
+ }
+ else
+ {
+ DEBUG_LOG3(_L("Transmit retry count reached on SAId: %d , State: %d , retry: %d"),iHdr.SaId(), iState, iSendAttempt );
+ if ( iState < KStateIkeSaCompleted )
+ {
+ IkeSaFailed(KKmdIkeNegotFailed); // IKE SA negotiation going
+ }
+ else
+ {
+ iIkeV2PlugInSession.DeleteIkev2SA(iHdr.SaId());
+ iIkeV2PlugInSession.IkeSaDeleted(KKmdIkeNoResponseErr); //IKE SA deletion going
+ delete this;
+ }
+ }
+ }
+ }
+
+
+void CIkev2Negotiation::IkeV2PkiInitCompleteL(TInt aStatus)
+ {
+
+ DEBUG_LOG(_L("-> CIkev2Negotiation::IkeV2PkiInitCompleteL"));
+ //
+ // The implementation for class MPkiServiceComplete virtual function
+ // This method is called when a PKI service operation is
+ // completed.
+ //
+
+ __ASSERT_ALWAYS( iPkiService != NULL, User::Invariant());
+ __ASSERT_ALWAYS(iState == KStateIkeInitPkiService, User::Invariant());
+
+ switch(aStatus)
+ {
+ case KErrNone:
+ //
+ // PKI service object has been constructed
+ // Start IKE_SA_INIT exchange
+ //
+ iState = KStateIdle;
+ if ( iChildSaRequest )
+ {
+ CIkev2Acquire* Acquire = iChildSaRequest;
+ iChildSaRequest = NULL;
+ CIkev2Acquire::Link(Acquire, GetAcquireQue());
+ GetIpsecSPI(Acquire);
+ }
+ else if ( iSavedSaInit )
+ {
+ TPtr8 IkeMsg(iSavedSaInit->Des());
+ const ThdrISAKMP* IkeMessage = ThdrISAKMP::Ptr(IkeMsg);
+ ProcessIkeMessageL(*IkeMessage, iHdr.iRemoteAddr, IKE_PORT);
+ if ( Stopped() )
+ delete this;
+ }
+ break;
+ case KErrNotFound:
+ DEBUG_LOG(_L("IKEv2 CA certificate retrieve failed. Certificate not found"));
+ IkeSaFailed(KVpnErrInvalidCaCertFile);
+ break;
+ default:
+ {
+ DEBUG_LOG1(_L("IKEv2 CA certificate retrieve failed (%d)"), aStatus);
+ IkeSaFailed(aStatus);
+ }
+ break;
+ }
+
+ DEBUG_LOG(_L("<- CIkev2Negotiation::IkeV2PkiInitCompleteL"));
+ }
+
+
+void CIkev2Negotiation::SendEapDataL(HBufC8* aEapData)
+{
+ //
+ // Send an IKE containing an EAP payload (within Encrypted Payload)
+ // The entire EAP payload data is provided in aEapData buffer
+ //
+ CleanupStack::PushL(aEapData);
+ if ( iState == KStateIkeSaEapGoing )
+ {
+ __ASSERT_DEBUG(iHdr.iInitiator, User::Invariant());
+
+ CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(), iHdr.SpiR(),
+ IKE_AUTH,
+ iHdr.iInitiator,
+ EFalse,
+ iHdr.NextRequestId(),
+ iDebug);
+ CleanupStack::PushL(ikeMsg);
+ ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);
+ ikeMsg->AppendEapPayloadL(*aEapData);
+ CleanupStack::Pop(ikeMsg);
+ SendIkeMsgL(ikeMsg);
+ }
+ CleanupStack::PopAndDestroy(aEapData);
+}
+
+void CIkev2Negotiation::EapEventL(TInt aEvent)
+ {
+ // See whether the object is accepting any events
+ // (it is, by default, but will not take events during destruction phase)
+ if (!iProcessEvents)
+ {
+ return;
+ }
+ //
+ // An event idicated by the EAP plugin process event according to
+ // event type
+ //
+ switch ( aEvent )
+ {
+ case KEapEventSuccess:
+ if ( (iState == KStateIkeSaEapGoing) || (iState == KStateIkeSaEapStarted) )
+ {
+ //
+ // EAP auhtentication succeeded.
+ // Build IKE message HDR, SK {AUTH}
+ //
+ __ASSERT_DEBUG( iHdr.iInitiator, User::Invariant());
+
+ CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(), iHdr.SpiR(),
+ IKE_AUTH,
+ iHdr.iInitiator,
+ EFalse,
+ iHdr.NextRequestId(),
+ iDebug);
+ CleanupStack::PushL(ikeMsg);
+ ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);
+
+
+ HBufC8* authData = SignAuthDataL(*iAuthMsgInit, (TUint8)iHdr.iAuthMethod);
+ CleanupStack::PushL(authData);
+ ikeMsg->AppendAuthPayloadL(iHdr.iAuthMethod, *authData);
+ CleanupStack::PopAndDestroy(authData);
+
+ CleanupStack::Pop(ikeMsg);
+ SendIkeMsgL(ikeMsg);
+ iState = KStateIkeSaAuthRequest;
+ iEapCompleted = ETrue;
+ }
+ break;
+
+ case KEapEventGetIdentity:
+ GetOwnIdentityL(ETrue); // Gets the Identity from EAP plugin
+ if ( iState == KStateIkeWaitingId )
+ {
+ //
+ // Identity data provided by the EAP plug-in
+ // Complete local signed data and send the first
+ // IKE_AUTH message
+ //
+ AddIdToSignedDataL(ETrue, iAuthMsgInit, iLocalIdentity->PayloadData());
+ SendIkeAuthMessageL();
+ }
+ break;
+
+ case KEapEventGetPSK:
+ if ( iState == KStateIkeSaEapGoing )
+ {
+ //
+ // Preshared key provided by the EAP plug-in
+ // Get key data and link it into negotiation object
+ //
+ iPresharedKey = iEapPlugin->MSK();
+ }
+ break;
+
+ default: // = KEapEventFailed
+ //
+ // EAP authentication is failed. Stop negotiation
+ //
+ IkeSaFailed(KKmdIkeAuthFailedErr); // IKE SA negotiation going
+ break;
+ }
+ }
+
+TBool CIkev2Negotiation::ProcessIkeSaInitL(CIkev2Payloads* aIkeMsg, const TInetAddr& aRemote)
+{
+ ASSERT(aIkeMsg);
+ //
+ // Process IKE message of exchange type IKE_SA_INIT
+ //
+ ThdrISAKMP* IkeHdr = aIkeMsg->GetIkeMsg(); // IKE Message fixed header
+ TBool Response = IkeHdr->GetFlags() & IKEV2_RESPONSE_MSG;
+ TBool Initiator = IkeHdr->GetFlags() & IKEV2_INITIATOR;
+ TUint32 MsgId = IkeHdr->GetMessageId();
+
+ if ( iHdr.iInitiator )
+ {
+ if ( Initiator ) {
+ DEBUG_LOG1(_L("IKEv2 Message with Orig_Init-bit in wrong state: %d"), iState);
+ return ETrue;
+ }
+ if ( !Response )
+ {
+ DEBUG_LOG1(_L("IKEv2 Message is not response; state: %d"), iState);
+ return ETrue;
+ }
+ if ( MsgId != iHdr.ExpectedResponseId() )
+ {
+ DEBUG_LOG1(_L("Wrong message id in response; state: %d"), iState);
+ return ETrue;
+ }
+
+ if (iState == KStateIkeSaInitRequest)
+ {
+ //record responder SPI
+ aIkeMsg->GetIkeMsg()->GetSPI_R(iHdr.SpiR());
+
+ //
+ // Received message should be a response to a
+ // IKE_SA_INIT request transmitted.
+ //
+ if (IkeHdr->GetPayload() == IKEV2_PAYLOAD_NOTIF)
+ {
+ return ProcessNotifyPayloadsL(*aIkeMsg->iNotifs, EFalse, IKE_SA_INIT);
+ }
+ //
+ // Response message should be format:
+ // HDR(A,B), SAr1, KEr, Nr, [CERTREQ]
+ //
+ if ( !CheckPayloadsOrder(aIkeMsg, IKE_SA_INIT, ETrue) )
+ {
+ DEBUG_LOG1(_L("Erroneous IKE_SA_INIT response: %d"), iState);
+ return EFalse;
+ }
+ if ( !Ikev2Proposal::VerifySaResponseL(iHdr, iChild, *PeekProposedSa(), *aIkeMsg) )
+ {
+ DEBUG_LOG1(_L("Unaccepted SA content in IKE_SA_INIT response: %d"),iState);
+ return EFalse;
+ }
+ if ( aIkeMsg->iNonce->PlDataLen() < IKEV2_MIN_NONCE_SIZE )
+ {
+ DEBUG_LOG1(_L("Nonce data too short %d"), iState);
+ return EFalse;
+ }
+
+ if ( iNatNotify )
+ {
+ TBool Supported;
+ TInetAddr LocalIp;
+ if ( iHdr.iIkeData->iUseMobIke )
+ LocalIp.SetAddress(KInetAddrNone);
+ else LocalIp = iHdr.iLocalAddr;
+
+#ifdef _DEBUG
+ TBuf<80> debugBuf;
+ DEBUG_LOG(_L("Calculating NAT detection:"));
+ LocalIp.Output(debugBuf);
+ DEBUG_LOG2(_L("LocalIp %S:%d"), &debugBuf, IKE_PORT);
+ iHdr.iRemoteAddr.Output(debugBuf);
+ DEBUG_LOG2(_L("RemoteIp %S:%d"), &debugBuf, IKE_PORT);
+#endif
+
+ iHdr.iNATFlags = CIkev2NatT::CheckPeerNotifysL(*aIkeMsg->iNotifs, LocalIp, iHdr.iRemoteAddr, IKE_PORT,
+ iHdr.SpiI(), iHdr.SpiR(), Supported);
+ GetNatStatus(Supported, aRemote);
+ }
+
+ delete iNonce_R;
+ iNonce_R = NULL;
+
+ iNonce_R = HBufC8::NewL(aIkeMsg->iNonce->PlDataLen());
+ iNonce_R->Des().Copy(aIkeMsg->iNonce->PayloadData(), aIkeMsg->iNonce->PlDataLen());
+ if ( !ProcessKeyExchangeL((TKEPayloadIkev2*)aIkeMsg->iKe, iHdr.iDHGroup) )
+ {
+ return EFalse;
+ }
+
+ //
+ // IKE_SA_INIT request is completed enter IKE_AUTH
+ //
+ GenerateIkeKeysL();
+ TPtrC8 ikeHdrPtr((TUint8*)IkeHdr, IkeHdr->GetLength());
+ SaveSignedDataL(EFalse, ikeHdrPtr); // Save IKE_AUTH message 2
+
+ //We ignore possible cert req payloads and just work
+ //according our policy
+ if ( !iHdr.iEAPType &&
+ (iHdr.iAuthMethod == RSA_DIGITAL_SIGN || iHdr.iAuthMethod == DSS_DIGITAL_SIGN) )
+ {
+ SaveSignedDataL(ETrue, iHdr.iLastRequest->IkeMessageDatagram()); // Own identity not yet saved to signed data
+
+ GetOwnIdentityL(); // Get own Identity from Certificate (or policy)
+ AddIdToSignedDataL(ETrue, iAuthMsgInit, iLocalIdentity->PayloadData());
+ }
+ else
+ {
+ //
+ // Check if "implicit" Child SA exchange required
+ // by getting request CIkev2Acquire object from queue
+ //
+ GetOwnIdentityL();
+ SaveSignedDataL(ETrue, iHdr.iLastRequest->IkeMessageDatagram()); // Own identity saved to signed data
+ }
+ iChildSaRequest = CIkev2Acquire::GetNext(GetAcquireQue(), EFalse);
+ SendIkeAuthMessageL();
+ }
+ else
+ {
+ //
+ // Ignore received message silently
+ //
+ DEBUG_LOG1(_L("IKE_SA_INIT response received in state %d"), iState);
+ }
+ }
+ else {
+ if ( !Initiator )
+ {
+ DEBUG_LOG1(_L("IKEv2 Message without Orig_Init-bit in wrong, state: %d"), iState);
+ return ETrue;
+ }
+ if ( Response )
+ {
+ DEBUG_LOG1(_L("IKEv2 Message is not request, state: %d"), iState);
+ return ETrue;
+ }
+
+ switch ( iState )
+ {
+ case KStateIdle:
+ case KStateIkeSaInitResponse:
+ //Record Initiator SPI
+ aIkeMsg->GetIkeMsg()->GetSPI_I(iHdr.SpiI());
+ iHdr.SpiI().SetLength(IKEV2_SPI_SIZE);
+
+ //
+ // Received message should be an IKE_SA_INIT request
+ // Request message should be format:
+ // HDR(A,0), SAi1, KEi, Ni, [CERTREQ]
+ //
+ {
+ if ( !CheckPayloadsOrder(aIkeMsg, IKE_SA_INIT, EFalse) )
+ {
+ DEBUG_LOG1(_L("Erroneous IKE_SA_INIT request: %d"), iState);
+ return EFalse;
+ }
+ if ( MsgId != iHdr.ExpectedRequestId() ) {
+ if ( iHdr.iLastResponse != NULL &&
+ MsgId == iHdr.iLastResponse->MessageId() &&
+ iState == KStateIkeSaInitResponse )
+ {
+ //
+ // Retransmission of an earlier IKE_SA_INIT
+ // request. Retransmit current IKE_SA_INIT
+ // response (if retry count not exhausted)
+ //
+ DoRetransmitL(ETrue);
+ return ETrue;
+ }
+ else {
+ DEBUG_LOG1(_L("Wrong message id in request, state: %d"), iState);
+ return EFalse;
+ }
+ }
+ if ( iState == KStateIkeSaInitResponse )
+ return EFalse; // IKE_SA_INIT request retry with a new message ID
+ iIkeV2PlugInSession.StartResponding();
+
+ //
+ // Build a SA payload from current IKE policy and
+ // verify received IKE SA request with it
+ //
+ HBufC8* SaBfr = Ikev2Proposal::FromPolicyToProposaL(iHdr, iSPI_Rekey, iDHGroupGuess);
+ CleanupStack::PushL(SaBfr);
+ HBufC8* proposedSa = NULL;
+ TBool SaOk = Ikev2Proposal::VerifySaRequestAndGetProposedSaBufferL(iHdr, iChild,
+ *SaBfr, *aIkeMsg,
+ proposedSa);
+ CleanupStack::PopAndDestroy();
+ if ( !SaOk )
+ {
+ DEBUG_LOG1(_L("Unaccepted SA content in IKE_SA_INIT request: %d"),iState);
+ SetNotifyCode(NO_PROPOSAL_CHOSEN);
+ return EFalse;
+ }
+ SetProposedSa(proposedSa);
+ proposedSa = NULL;
+ if ( aIkeMsg->iNonce->PlDataLen() < IKEV2_MIN_NONCE_SIZE )
+ {
+ DEBUG_LOG1(_L("Nonce data too short %d"), iState);
+ return EFalse;
+ }
+
+ //Check peer NAT status
+ TBool useNatDetection = EFalse;
+ if ( !iHdr.iIkeData->iUseNatProbing )
+ {
+ TInetAddr LocalIp;
+ if ( iHdr.iIkeData->iUseMobIke )
+ LocalIp.SetAddress(KInetAddrNone);
+ else LocalIp = iHdr.iLocalAddr;
+ iHdr.iNATFlags = CIkev2NatT::CheckPeerNotifysL(*aIkeMsg->iNotifs, LocalIp,
+ iHdr.iRemoteAddr, IKE_PORT,
+ iHdr.SpiI(), iHdr.SpiR(), useNatDetection);
+ }
+
+ if ( !ProcessKeyExchangeL((TKEPayloadIkev2*)aIkeMsg->iKe, iHdr.iDHGroup) )
+ return EFalse;
+
+
+ //
+ // Create own SPI (responder)
+ //
+ CreateIkeSPI(iHdr.SpiR());
+ delete iNonce_I;
+ iNonce_I = NULL;
+ iNonce_I = HBufC8::NewL(aIkeMsg->iNonce->PlDataLen());
+ iNonce_I->Des().Copy(aIkeMsg->iNonce->PayloadData(), aIkeMsg->iNonce->PlDataLen());
+ GetNonceDataL(EFalse);
+
+ TPtrC8 ikeHdrPtr((TUint8*)IkeHdr, IkeHdr->GetLength());
+ SaveSignedDataL(EFalse, ikeHdrPtr); // Save IKE_AUTH message 2
+
+ //
+ // Build IKE_SA_INIT response message: HDR, SAr1, KEr, Nr, [CERTREQ]
+ //
+ __ASSERT_DEBUG(!iHdr.iInitiator, User::Invariant());
+ CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(), iHdr.SpiR(),
+ IKE_SA_INIT,
+ iHdr.iInitiator,
+ ETrue,
+ iHdr.ExpectedRequestId(),
+ iDebug);
+ CleanupStack::PushL(ikeMsg);
+
+ HBufC8* saBfr = Ikev2Proposal::FromPolicyToProposaL(iHdr, iSPI_Rekey, iDHGroupGuess);
+ CleanupStack::PushL(saBfr);
+ ikeMsg->AppendSaPayloadL(*saBfr);
+ CleanupStack::Pop(saBfr);
+ SetProposedSa(saBfr);
+
+ AppendKEPayloadL(*ikeMsg, iHdr.iDHGroup);
+ ikeMsg->AppendNoncePayloadL(*iNonce_R);
+
+ if ( iPkiService )
+ {
+ ikeMsg->AppendCertReqPayloadL(iPkiService->CaList());
+ }
+
+ if ( useNatDetection )
+ {
+ delete iNatNotify;
+ iNatNotify = NULL;
+
+ TInetAddr LocalIp;
+ if ( iHdr.iIkeData->iUseMobIke )
+ LocalIp.SetAddress(KInetAddrNone);
+ else LocalIp = iHdr.iLocalAddr;
+
+
+ iNatNotify = CIkev2NatT::NewL(LocalIp, iHdr.iRemoteAddr, IKE_PORT, ikeMsg->InitiatorSpi(), ikeMsg->ResponderSpi());
+ ikeMsg->AppendNotifyPayloadL(IKEV2_PROTOCOL, KZeroDesc, NAT_DETECTION_SOURCE_IP,
+ iNatNotify->SourceNofify());
+ ikeMsg->AppendNotifyPayloadL(IKEV2_PROTOCOL, KZeroDesc, NAT_DETECTION_DESTINATION_IP,
+ iNatNotify->DestinNofify());
+ }
+ GetNatStatus(useNatDetection, aRemote);
+ CleanupStack::Pop(ikeMsg);
+ SendIkeMsgL(ikeMsg);
+ GenerateIkeKeysL();
+
+ SaveSignedDataL(ETrue, ikeMsg->IkeMessageDatagram()); // Own identity is not yet saved to signed data
+ iState = KStateIkeSaInitResponse;
+ }
+ break;
+
+ default:
+ //
+ // Ignore received message silently
+ //
+ DEBUG_LOG1(_L("IKE_SA_INIT message received in state %d"), iState);
+ break;
+
+ }
+ }
+
+ return ETrue;
+}
+
+TBool CIkev2Negotiation::ProcessIkeAuthL(CIkev2Payloads* aIkeMsg)
+{
+ ASSERT(aIkeMsg);
+ //
+ // Process IKE message of exchange type IKE_AUTH
+ //
+ ThdrISAKMP* IkeHdr = aIkeMsg->GetIkeMsg(); // IKE Message fixed header
+ TBool Response = IkeHdr->GetFlags() & IKEV2_RESPONSE_MSG;
+ TBool Initiator = IkeHdr->GetFlags() & IKEV2_INITIATOR;
+ TUint32 MsgId = IkeHdr->GetMessageId();
+
+ if ( iHdr.iInitiator )
+ {
+ if ( Initiator )
+ {
+ DEBUG_LOG1(_L("IKEv2 Message with Orig_Init-bit in wrong state: %d"), iState);
+ return ETrue;
+ }
+ if ( !Response )
+ {
+ DEBUG_LOG1(_L("IKEv2 Message is not response; state: %d"), iState);
+ return ETrue;
+ }
+ if ( MsgId != iHdr.ExpectedResponseId() )
+ {
+ DEBUG_LOG1(_L("Wrong message id in response; state: %d"), iState);
+ return ETrue;
+ }
+
+ switch ( iState )
+ {
+ case KStateIkeSaAuthRequest:
+ DEBUG_LOG(_L("Handling IKE_AUTH response"));
+ //
+ // Received message should be a response to a
+ // IKE_AUTH request transmitted.
+ // Response message should be format:
+ // HDR(A,B), SK {IDr, [CERT,] AUTH, [CP], SAr2, TSi, TSr}
+ //
+ if ( aIkeMsg->iEncr )
+ {
+ ProcessNotifyPayloadsL(*aIkeMsg->iNotifs, EFalse, IKE_AUTH);
+ if ( iDeleteIkeSA )
+ {
+ DEBUG_LOG1(_L("Error Notify in IKE_AUTH response: %d"), iState);
+
+ //Because we are just in IKE_AUTH no IKE_SAs exists --> we don't
+ //want to delete one. So we set iDeleteIkeSA back to false.
+ iDeleteIkeSA = EFalse;
+
+ return EFalse;
+ }
+ }
+ if ( !CheckPayloadsOrder(aIkeMsg, IKE_AUTH, ETrue) )
+ {
+ DEBUG_LOG1(_L("Erroneous IKE_AUTH response: %d"), iState);
+ SetNotifyCode(INVALID_SYNTAX);
+
+ if ( iChildSaRequest && !iChildSARejected && !aIkeMsg->iSa )
+ {
+ iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
+ }
+
+ return EFalse;
+ }
+ DEBUG_LOG(_L("IKE_AUTH payload order check passed"));
+ TBool Status;
+ if ( iEapCompleted )
+ {
+ Status = AuthenticatePeerL(aIkeMsg->iAuth);
+ }
+ else
+ {
+ if ( iPkiService && !VerifyPeerCertificateL(aIkeMsg->iCerts, aIkeMsg->iIdR) )
+ {
+ SetNotifyCode(AUTHENTICATION_FAILED);
+ return EFalse;
+ }
+ Status = AddIdAndAuthenticatePeerL(aIkeMsg);
+ }
+ if ( !Status )
+ {
+ SetNotifyCode(AUTHENTICATION_FAILED);
+ return EFalse;
+ }
+ //
+ // If implicit Child SA negotiation requested,
+ // verify IPSEC SA- and Traffic selector payloads, too
+ //
+ if ( iChildSaRequest )
+ {
+ DEBUG_LOG(_L("Processing CHILD_SA creation"));
+ if ( !iChildSARejected )
+ {
+ if ( !Ikev2Proposal::VerifySaResponseL(iHdr, iChild, *iChildSaRequest->SA(), *aIkeMsg) )
+ {
+ DEBUG_LOG1(_L("Unaccepted SA payload content in IKE_AUTH response: %d"),iState);
+ SetNotifyCode(NO_PROPOSAL_CHOSEN);
+ iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
+ return EFalse;
+ }
+ DEBUG_LOG(_L("SA response verified"));
+ if ( !IpsecSelectors::VerifyTrafficSelectorsL(iChildSaRequest, (TTSPayloadIkev2*)aIkeMsg->iTsI, (TTSPayloadIkev2*)aIkeMsg->iTsR ) )
+ {
+ DEBUG_LOG1(_L("Unaccepted Traffic Selectors in IKE_AUTH response: %d"),iState);
+ SetNotifyCode(TS_UNACCEPTABLE);
+ iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
+ return EFalse;
+ }
+ DEBUG_LOG(_L("Traffic selectors verified"));
+ if ( aIkeMsg->iCp )
+ {
+ if ( iConfigMode )
+ {
+ iConfigMode->ProcessCpL(aIkeMsg->iCp);
+ }
+ else
+ {
+ DEBUG_LOG(_L("Unsolicited CP payload in IKE_AUTH response"));
+ }
+ }
+ iChildSaRequest->SetSPI_Out(iChild.iSPI_Out);
+ DEBUG_LOG(_L("Generating IPsec keys"));
+ iChild.GenerateIpsecKeysL(iHdr.iSK_d, KZeroDesc,
+ *iNonce_I, *iNonce_R, iHdr.iPRFAlg);
+ DEBUG_LOG(_L("IPsec keys generated"));
+ }
+ else
+ {
+ DEBUG_LOG1(_L("Implicit CHILD_SA rejected Notify in IKE_AUTH response: %d"), iState);
+ iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
+ }
+ }
+ //
+ // IKE_AUTH request is completed and IKE SA has been
+ // negotiated
+ //
+ IkeSaCompletedL();
+ break;
+
+ case KStateIkeSaEapStarted:
+ //
+ // Received message should be an IKE_AUTH response
+ // containing an EAP payload.
+ // The content of received IKE message shall be:
+ // HDR, SK {IDr, [CERT,] AUTH, EAP }
+ //
+ if ( !aIkeMsg->iEncr || !aIkeMsg->iIdR || !aIkeMsg->iAuth || !aIkeMsg->iEap )
+ {
+ DEBUG_LOG1(_L("Erroneous IKE_AUTH response: %d"), iState);
+ SetNotifyCode(INVALID_SYNTAX);
+ return EFalse;
+ }
+ if ( iPkiService && !VerifyPeerCertificateL(aIkeMsg->iCerts, aIkeMsg->iIdR) )
+ {
+ SetNotifyCode(AUTHENTICATION_FAILED);
+ return EFalse;
+ }
+ if ( !AddIdAndAuthenticatePeerL(aIkeMsg) )
+ {
+ SetNotifyCode(AUTHENTICATION_FAILED);
+ return EFalse;
+ }
+ iState = KStateIkeSaEapGoing;
+ iEapPlugin->EapDataInbound(aIkeMsg->iEap);
+ break;
+
+ case KStateIkeSaEapGoing:
+ //
+ // Received message should be an IKE_AUTH response
+ // containing an EAP payload.
+ // The content of received IKE message shall be:
+ // HDR, SK {EAP}
+ //
+ if ( !aIkeMsg->iEncr || !aIkeMsg->iEap )
+ {
+ DEBUG_LOG1(_L("Erroneous IKE_AUTH response: %d"), iState);
+ SetNotifyCode(INVALID_SYNTAX);
+ return EFalse;
+ }
+ iEapPlugin->EapDataInbound(aIkeMsg->iEap);
+ break;
+
+ default:
+ //
+ // Ignore received message silently
+ //
+ DEBUG_LOG1(_L("IKE_AUTH response received in state %d"), iState);
+ break;
+
+ }
+ }
+ else
+ {
+ if ( !Initiator )
+ {
+ DEBUG_LOG1(_L("IKEv2 Message without Orig_Init-bit in wrong, state: %d"), iState);
+ return ETrue;
+ }
+ if ( Response )
+ {
+ DEBUG_LOG1(_L("IKEv2 Message is not request, state: %d"), iState);
+ return ETrue;
+ }
+ switch ( iState )
+ {
+ case KStateIkeSaInitResponse:
+ case KStateIkeSaCompleted:
+ //
+ // Received message should be an IKE_AUTH request
+ // Request message should be format:
+ // HDR(A,B), SK {IDi, [CERT,] [CERTREQ,] [IDr,] AUTH, SAi2, TSi, TSr}
+ //
+ if ( !CheckPayloadsOrder(aIkeMsg, IKE_AUTH, EFalse) )
+ {
+ DEBUG_LOG1(_L("Erroneous IKE_AUTH request: %d"), iState);
+ SetNotifyCode(INVALID_SYNTAX);
+ return EFalse;
+ }
+ if ( MsgId != iHdr.ExpectedRequestId() ) {
+ if ( iHdr.iLastResponse != NULL &&
+ MsgId == iHdr.iLastResponse->MessageId() &&
+ iState == KStateIkeSaCompleted )
+ {
+ //
+ // Retransmission of an earlier IKE_SA_INIT
+ // request. Retransmit current IKE_SA_INIT
+ // response (if retry count not exhausted)
+ //
+ DoRetransmitL(ETrue);
+ return ETrue;
+ }
+ else {
+ DEBUG_LOG1(_L("Wrong message id in request, state: %d"), iState);
+ SetNotifyCode(INVALID_MESSAGE_ID);
+ StoreNotifyData32(MsgId);
+ return EFalse;
+ }
+ }
+ if ( iState == KStateIkeSaCompleted )
+ return EFalse; // IKE_AUTH request retry with a new message ID
+
+ //if ( aIkeMsg->iEncr )
+ //{
+ ProcessNotifyPayloadsL(*aIkeMsg->iNotifs, EFalse, IKE_AUTH);
+ if ( iDeleteIkeSA )
+ {
+ DEBUG_LOG1(_L("Error Notify in IKE_AUTH response: %d"), iState);
+ return EFalse;
+ }
+ //}
+
+ if ( iPkiService && !VerifyPeerCertificateL(aIkeMsg->iCerts, aIkeMsg->iIdI) )
+ {
+ DEBUG_LOG(_L("Peer certificate validation failed."));
+ SetNotifyCode(AUTHENTICATION_FAILED);
+ return EFalse;
+ }
+ if ( !AddIdAndAuthenticatePeerL(aIkeMsg) )
+ {
+ SetNotifyCode(AUTHENTICATION_FAILED);
+ return EFalse;
+ }
+ //
+ // Process "concatenated" Child SA- and Traffic
+ // Selector payloads if present
+ //
+ if ( aIkeMsg->iSa )
+ {
+ DEBUG_LOG(_L("IKE_AUTH request has SA and TS payload."));
+ CIkev2Acquire* Acquire = IpsecSelectors::GetIpsecPolicyL(iIkeV2PlugInSession, aIkeMsg);
+ if ( !Acquire )
+ {
+ DEBUG_LOG1(_L("Unaccepted Traffic Selectors in IKE_AUTH request: %d"),iState);
+ SetNotifyCode(TS_UNACCEPTABLE);
+ return EFalse;
+ }
+ CleanupStack::PushL(Acquire);
+ HBufC8* proposedSaBuffer = NULL;
+ if (!Ikev2Proposal::VerifySaRequestAndGetProposedSaBufferL(iHdr, iChild,
+ *Acquire->SA(), *aIkeMsg,
+ proposedSaBuffer))
+ {
+ CleanupStack::PopAndDestroy(Acquire);
+ DEBUG_LOG1(_L("Unaccepted SA content in IKE_AUTH request: %d"),iState);
+ SetNotifyCode(NO_PROPOSAL_CHOSEN);
+ return EFalse;
+ }
+ SetProposedSa(proposedSaBuffer);
+ proposedSaBuffer = NULL;
+ //
+ // Replace SA payload buffer in CIkev2Acquire with
+ // selected SA payload built in VerifySaRequestL
+ //
+ CleanupStack::Pop(Acquire);
+ Acquire->ReplaceSA(GetProposedSa());
+ Acquire->SetSPI_Out(iChild.iSPI_Out);
+ Acquire->SetResponse();
+ if ( iChild.iTransport )
+ {
+
+ Acquire->SetTransport();
+ }
+ CIkev2Acquire::Link(Acquire, GetAcquireQue());
+ DEBUG_LOG(_L("Acquire linked."));
+
+ if ( aIkeMsg->iCp )
+ {
+ //
+ // CP payload received as IKE SA responder
+ // Handle CP payload and return "dummy"
+ // virtual IP to initiator.
+ //
+ delete iConfigMode;
+ iConfigMode = NULL;
+ iConfigMode = CIkev2Config::NewL(Acquire, (TInetAddr*)&iHdr.iRemoteAddr);
+ iConfigMode->ProcessCpL(aIkeMsg->iCp);
+ Acquire->SetVirtualIp();
+ }
+ //
+ // Get SPI for new inbound SA
+ //
+ iChild.GenerateIpsecKeysL(iHdr.iSK_d, KZeroDesc,
+ *iNonce_I, *iNonce_R, iHdr.iPRFAlg);
+
+ if ( iPkiService && !iEapPlugin &&
+ aIkeMsg->iCertReqs &&
+ aIkeMsg->iCertReqs->Count() )
+ {
+ GetOwnIdentityL(); // Get own Identity from Certificate (or policy)
+ AddIdToSignedDataL(ETrue, iAuthMsgResp, iLocalIdentity->PayloadData());
+
+ CIkev2Acquire* Acquire = CIkev2Acquire::PeekFirst(GetAcquireQue());
+ if ( Acquire )
+ {
+ GetIpsecSPI(Acquire);
+ iState = KStateIkeSaAuthWaitSpi;
+ }
+ else
+ {
+ DEBUG_LOG(_L("CIkev2Acquire::PeekFirst returned NULL."));
+ DEBUG_LOG(_L("Sending IKE_AUTH response."));
+ SendIkeAuthMessageL();
+ }
+
+ }
+ else
+ {
+ GetOwnIdentityL();
+ AddIdToSignedDataL(ETrue, iAuthMsgResp, iLocalIdentity->PayloadData());
+ GetIpsecSPI(Acquire);
+ iState = KStateIkeSaAuthWaitSpi;
+ }
+ }
+ else
+ {
+ if ( iPkiService && !iEapPlugin &&
+ aIkeMsg->iCertReqs &&
+ aIkeMsg->iCertReqs->Count() )
+ {
+ GetOwnIdentityL(); // Get own Identity from Certificate (or policy)
+ AddIdToSignedDataL(ETrue, iAuthMsgResp, iLocalIdentity->PayloadData());
+
+ CIkev2Acquire* Acquire = CIkev2Acquire::PeekFirst(GetAcquireQue());
+ if ( Acquire )
+ {
+ GetIpsecSPI(Acquire);
+ iState = KStateIkeSaAuthWaitSpi;
+ }
+ else
+ {
+ SendIkeAuthMessageL();
+ }
+ }
+ else
+ {
+ //
+ // Build and send an IKE_AUTH response
+ //
+ GetOwnIdentityL();
+ AddIdToSignedDataL(ETrue, iAuthMsgResp, iLocalIdentity->PayloadData());
+ SendIkeAuthMessageL();
+ }
+ }
+ break;
+
+ default:
+ //
+ // Ignore received message silently
+ //
+ DEBUG_LOG1(_L("IKE_SA_INIT message received in state %d"), iState);
+ break;
+ }
+ }
+
+ return ETrue;
+}
+
+TBool CIkev2Negotiation::ProcessChildSaL(CIkev2Payloads* aIkeMsg)
+{
+ ASSERT(aIkeMsg);
+ //
+ // Process IKE message of exchange type CREATE_CHILD_SA
+ //
+ TUint16 PfsDHGroup;
+ ThdrISAKMP* IkeHdr = aIkeMsg->GetIkeMsg(); // IKE Message fixed header
+ TBool Response = IkeHdr->GetFlags() & IKEV2_RESPONSE_MSG;
+ TBool Initiator = IkeHdr->GetFlags() & IKEV2_INITIATOR;
+ TUint32 MsgId = IkeHdr->GetMessageId();
+
+ if ( iHdr.iInitiator )
+ {
+ if ( Initiator )
+ {
+ DEBUG_LOG1(_L("IKEv2 Message with Orig_Init-bit in wrong state: %d"), iState);
+ SetNotifyCode(INVALID_SYNTAX);
+ return EFalse;
+ }
+ }
+ else
+ {
+ if ( !Initiator )
+ {
+ DEBUG_LOG1(_L("IKEv2 Message without Orig_Init-bit in wrong state: %d"), iState);
+ SetNotifyCode(INVALID_SYNTAX);
+ return EFalse;
+ }
+ }
+
+ if ( Response )
+ {
+ //
+ // CREATE_CHILD_SA response message received
+ //
+ switch ( iState )
+ {
+ case KStateIkeChildSARequest:
+ //
+ // Received message should be a response to a
+ // CREATE_CHILD_SA request transmitted.
+ // Response message should be format:
+ // HDR(A,B), SK { SA, Nr, [KEr], [TSi, TSr]}
+ //
+ if ( MsgId != iHdr.ExpectedResponseId() )
+ {
+ DEBUG_LOG1(_L("Wrong message id in response; state: %d"), iState);
+
+ SetNotifyCode(INVALID_MESSAGE_ID);
+ StoreNotifyData32(MsgId);
+ return EFalse;
+ }
+ if ( aIkeMsg->iEncr )
+ {
+ ProcessNotifyPayloadsL(*aIkeMsg->iNotifs, EFalse, CREATE_CHILD_SA);
+ if ( iDeleteIkeSA )
+ {
+ DEBUG_LOG1(_L("Error Notify in CREATE_CHILD_SA response: %d"), iState);
+ return EFalse;
+ }
+ if ( iChildSARejected )
+ {
+ DEBUG_LOG1(_L("CHILD_SA rejected Notify in CREATE_CHILD_SA response: %d"), iState);
+ iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
+ iStopped = ETrue;
+ return EFalse;
+ }
+ }
+ if ( !CheckPayloadsOrder(aIkeMsg, CREATE_CHILD_SA, ETrue) )
+ {
+ DEBUG_LOG1(_L("Erroneous CREATE_CHILD_SA response: %d"), iState);
+ SetNotifyCode(INVALID_SYNTAX);
+ iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
+ return EFalse;
+ }
+ if ( aIkeMsg->iNonce->PlDataLen() < IKEV2_MIN_NONCE_SIZE )
+ {
+ DEBUG_LOG1(_L("Nonce data too short %d"), iState);
+ iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
+ iStopped = ETrue;
+ return EFalse;
+ }
+
+ if ( !Ikev2Proposal::VerifySaResponseL(iHdr, iChild, *iChildSaRequest->SA(), *aIkeMsg) )
+ {
+ DEBUG_LOG1(_L("Unaccepted SA content in CREATE_CHILD_SA response: %d"),iState);
+ SetNotifyCode(NO_PROPOSAL_CHOSEN);
+ iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
+ return EFalse;
+ }
+ if ( !IpsecSelectors::VerifyTrafficSelectorsL(iChildSaRequest, (TTSPayloadIkev2*)aIkeMsg->iTsI, (TTSPayloadIkev2*)aIkeMsg->iTsR ) )
+ {
+ DEBUG_LOG1(_L("Unaccepted Traffic Selectors in CREATE_CHILD_SA response: %d"),iState);
+ SetNotifyCode(TS_UNACCEPTABLE);
+ iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
+ return EFalse;
+ }
+ delete iNonce_R;
+ iNonce_R = NULL;
+ iNonce_R = HBufC8::NewL(aIkeMsg->iNonce->PlDataLen());
+ iNonce_R->Des().Copy(aIkeMsg->iNonce->PayloadData(), aIkeMsg->iNonce->PlDataLen());
+ PfsDHGroup = iChildSaRequest->DHGroup();
+ if ( PfsDHGroup )
+ {
+ if ( !ProcessKeyExchangeL((TKEPayloadIkev2*)aIkeMsg->iKe, PfsDHGroup) )
+ {
+ iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
+ return EFalse;
+ }
+ HBufC8* g_ir = iDHKeys->ComputeAgreedKeyL(iDHPublicPeer->Des());
+ CleanupStack::PushL(g_ir);
+
+ iChild.GenerateIpsecKeysL(iHdr.iSK_d, *g_ir,
+ *iNonce_I, *iNonce_R, iHdr.iPRFAlg);
+
+
+ g_ir->Des().FillZ(); // Wipe out shared secret value from buffer
+ CleanupStack::PopAndDestroy(); //g_ir
+
+ }
+ else if ( aIkeMsg->iKe )
+ {
+ DEBUG_LOG1(_L("Unsolicted Key Exchange payload present in CREATE_CHILD_SA response: %d"),iState);
+ SetNotifyCode(INVALID_KE_PAYLOAD);
+ iChildSaRequest = Ikev2Pfkey::DeleteInboundSPI(iHdr, iIkeV2PlugInSession, iChildSaRequest);
+ return EFalse;
+ }
+ else
+ {
+ iChild.GenerateIpsecKeysL(iHdr.iSK_d, KZeroDesc,
+ *iNonce_I, *iNonce_R, iHdr.iPRFAlg);
+
+ }
+ //
+ // CREATE_CHILD_SA request is completed Update
+ //
+ IpsecSANegotiatedL();
+ break;
+
+ case KStateIkeSARekeyRequest:
+ //
+ // Received message should be a response to a
+ // IKE SA rekey CHILD_SA request transmitted.
+ // Response message should be format:
+ // HDR(A,B), SK { SA, Nr, KEr }
+ //
+ if ( CheckPayloadsOrder(aIkeMsg, CREATE_CHILD_SA, ETrue) && aIkeMsg->iKe )
+ {
+ DEBUG_LOG1(_L("IKE SA rekey message received as CHILD_SA response: %d"), iState);
+ ProcessIkeSARekeyL(aIkeMsg);
+ }
+ else
+ {
+ DEBUG_LOG1(_L("Erroneous IKE SA rekey message received as CHILD_SA response: %d"),iState);
+ }
+ //iIkeV2PlugInSession.UpdateIkev2SAL(&iHdr, NULL, EFalse);
+ BuildDeleteRequestL(NULL); // Delete IKE SA rekeyed
+ iIkeV2PlugInSession.DeleteIkev2SA(iHdr.SaId());
+ break;
+
+ default:
+ //
+ // Ignore received message silently
+ //
+ DEBUG_LOG1(_L("CREATE_CHILD_SA response received in state %d"), iState);
+ break;
+
+ }
+ }
+ else
+ {
+ //
+ // CREATE_CHILD_SA request message received
+ //
+ if ( MsgId != iHdr.ExpectedRequestId() ) {
+ if ( iHdr.iLastResponse != NULL &&
+ MsgId == iHdr.iLastResponse->MessageId() )
+ {
+ //
+ // Retransmission of an earlier request.
+ // Retransmit current response
+ //
+ iState = KStateIkeChildSAResponse;
+ DoRetransmitL(ETrue);
+ return ETrue;
+ }
+ else {
+ DEBUG_LOG1(_L("Wrong message id in request, state: %d"), iState);
+ SetNotifyCode(INVALID_MESSAGE_ID);
+ StoreNotifyData32(MsgId);
+ return EFalse;
+ }
+ }
+
+ if ( iState >= KStateIkeSaCompleted )
+ {
+ //
+ // Received CREATE_CHILD_SA message can be one of the
+ // following:
+ // -- Create new Ipsec SA request:
+ // HDR(A,B), SK { SA, Nr, [KEi], [TSi, TSr]}
+ // -- Rekey Ipsec SA request:
+ // HDR(A,B), SK { N, SA, Ni, [KEi], [TSi, TSr]}
+ // -- Rekey IKE SA request:
+ // HDR(A,B), SK { SA, Ni, KEi}
+ //
+ if ( !CheckPayloadsOrder(aIkeMsg, CREATE_CHILD_SA, EFalse) )
+ {
+ DEBUG_LOG1(_L("Erroneous CREATE_CHILD_SA request: %d"), iState);
+ SetNotifyCode(INVALID_SYNTAX);
+ return EFalse;
+ }
+ //
+ // Check is the current request an IKE SA rekey by checking
+ // Proposal payload protocol value
+ //
+ if ( Ikev2Proposal::IkeSaRekey(aIkeMsg) )
+ {
+ TBool Status;
+ if ( iState == KStateIkeSARekeyRequest )
+ {
+ DEBUG_LOG1(_L("IKE SA Rekey collision for SAID: %d"), iHdr.SaId());
+ SetNotifyCode(NO_ADDITIONAL_SAS);
+ Status = EFalse;
+ }
+ else
+ {
+ DEBUG_LOG1(_L("IKE SA Rekey started by peer for SAID: %d"), iHdr.SaId());
+ iState = KStateIkeSARekeyResponse;
+ Status = ProcessIkeSARekeyL(aIkeMsg);
+ iIkeV2PlugInSession.UpdateIkev2SAL(&iHdr, NULL);
+ }
+ return Status;
+ }
+ if ( CIkev2Acquire::Responding(GetAcquireQue()) )
+ {
+ DEBUG_LOG1(_L("CREATE_CHILD_SA IKE SA request already pending: %d"), iState);
+ SetNotifyCode(NO_ADDITIONAL_SAS);
+ return EFalse;
+ }
+
+ //
+ // Get acceptable Ipsec policy for peer defined traffic
+ // selectors (and peer address)
+ //
+ CIkev2Acquire* Acquire = IpsecSelectors::GetIpsecPolicyL(iIkeV2PlugInSession, aIkeMsg,
+ iHdr.iIkeData->iGroupDesc_II);
+ if ( !Acquire )
+ {
+ DEBUG_LOG1(_L("Unaccepted Traffic Selectors in CREATE_CHILD_SA request: %d"),iState);
+ SetNotifyCode(TS_UNACCEPTABLE);
+ return EFalse;
+ }
+ CleanupStack::PushL(Acquire);
+ HBufC8* proposedSaBuffer = NULL;
+ if (!Ikev2Proposal::VerifySaRequestAndGetProposedSaBufferL(iHdr, iChild, *Acquire->SA(),
+ *aIkeMsg, proposedSaBuffer))
+ {
+ CleanupStack::PopAndDestroy(Acquire);
+ DEBUG_LOG1(_L("Unaccepted SA content in CREATE_CHILD_SA request: %d"),iState);
+ SetNotifyCode(NO_PROPOSAL_CHOSEN);
+ return EFalse;
+ }
+ this->SetProposedSa(proposedSaBuffer);
+ proposedSaBuffer = NULL;
+ delete iNonce_I;
+ iNonce_I = NULL;
+ iNonce_I = HBufC8::NewL(aIkeMsg->iNonce->PlDataLen());
+ iNonce_I->Des().Copy(aIkeMsg->iNonce->PayloadData(), aIkeMsg->iNonce->PlDataLen());
+ if ( aIkeMsg->iKe )
+ {
+ PfsDHGroup = Acquire->DHGroup();
+ if ( PfsDHGroup == 0 )
+ {
+ PfsDHGroup = Ikev2Proposal::GetDHGroup(iHdr.iIkeData->iGroupDesc_II);
+ Acquire->DHGroup(PfsDHGroup);
+ }
+ if ( !ProcessKeyExchangeL((TKEPayloadIkev2*)aIkeMsg->iKe, PfsDHGroup) )
+ {
+ CleanupStack::PopAndDestroy(Acquire);
+ return EFalse;
+ }
+ }
+ CleanupStack::Pop(Acquire);
+ Acquire->SetSPI_Out(iChild.iSPI_Out);
+ Acquire->SetResponse();
+ if ( iChild.iTransport )
+ Acquire->SetTransport();
+ CIkev2Acquire::Link(Acquire, GetAcquireQue());
+ //
+ // Get SPI for new inbound SA
+ //
+ GetIpsecSPI(Acquire);
+ }
+ else
+ {
+ //
+ // Ignore received message silently
+ //
+ DEBUG_LOG1(_L("CREATE_CHILD_SA request received in state %d"), iState);
+ }
+ }
+
+ return ETrue;
+}
+
+TBool CIkev2Negotiation::ProcessIkeSARekeyL(CIkev2Payloads* aIkeMsg)
+{
+ ASSERT(aIkeMsg);
+ //
+ // Process IKE SA rekey message (as IKE_CHILD_SA exchange)
+ // HDR(A,B), SK { SA, Nonce, KE}
+ //
+
+
+ if ( (iState == KStateIkeSARekeyRequest) || (iState == KStateIkeSARekeyResponse) )
+ {
+ //
+ // Received CREATE_CHILD_SA message for IKE SA rekey must
+ // look like the following: HDR(A,B), SK { SA, Ni, [KEi]}
+ // Allocate a new CIkev2Negotiation object for new IKE SA
+ //
+ //
+ CIkev2Negotiation* NewSA = new (ELeave) CIkev2Negotiation(iIkeV2PlugInSession, iPfKeySocketIf,
+ iEventLogger, iMessageSendQue, iDebug, 0);
+ CleanupStack::PushL(NewSA);
+
+ //Do not copy the previous sent request and response:
+ CIkeV2Message* lastResponse = iHdr.iLastResponse;
+ iHdr.iLastResponse = NULL;
+ CIkeV2Message* lastRequest = iHdr.iLastRequest;
+ iHdr.iLastRequest = NULL;
+ NewSA->iHdr.Copy(iHdr);
+ iHdr.iLastResponse = lastResponse;
+ iHdr.iLastRequest = lastRequest;
+
+
+ NewSA->iHdr.iWindowSize = 1;
+ NewSA->iHdr.iEncrAlg = 0;
+ NewSA->iHdr.iPRFAlg = 0;
+ NewSA->iHdr.iIntegAlg = 0;
+ NewSA->iHdr.iDHGroup = 0;
+ NewSA->iHdr.iAuthMethod = 0;
+ NewSA->iHdr.iCipherKeyLth = 0;
+ NewSA->iHdr.iCipherBlkLth = 0;
+ NewSA->iHdr.iIntChkSumLth = 0;
+
+ if ( iState == KStateIkeSARekeyRequest )
+ {
+ NewSA->iHdr.iInitiator = ETrue;
+ NewSA->iHdr.SetSaId(iSAid_Rekey);
+ NewSA->iHdr.SetSpiI(iSPI_Rekey);
+ NewSA->iNonce_I = iNonce_I; // Nonce was created in BuildIkeSaRekeyMsgL() earlier
+ NewSA->iDHKeys = iDHKeys; // DH keys object was created in BuildIkeSaRekeyMsgL() earlier
+ iNonce_I = NULL;
+ iDHKeys = NULL;
+ }
+ else
+ {
+ NewSA->iHdr.iInitiator = EFalse;
+ NewSA->iHdr.SetSaId(iIkeV2PlugInSession.GetSAId()); // Get a new SA Id
+ NewSA->CreateIkeSPI(NewSA->iHdr.SpiR());
+ }
+ //
+ // Build a SA payload from current IKE policy and
+ // verify received IKE SA request with it
+ //
+ HBufC8* SaBfr = Ikev2Proposal::FromPolicyToProposaL(NewSA->iHdr, NewSA->iSPI_Rekey, NewSA->iDHGroupGuess, ETrue);
+ CleanupStack::PushL(SaBfr);
+ HBufC8* proposedSaBuffer = NULL;
+ TBool SaOk = Ikev2Proposal::VerifySaRequestAndGetProposedSaBufferL(NewSA->iHdr, NewSA->iChild,
+ *SaBfr, *aIkeMsg, proposedSaBuffer);
+ CleanupStack::PopAndDestroy();
+ if ( iState == KStateIkeSARekeyRequest )
+ SaOk &= Ikev2Proposal::GetRekeySpi(aIkeMsg, NewSA->iHdr.SpiR());
+ else SaOk &= Ikev2Proposal::GetRekeySpi(aIkeMsg, NewSA->iHdr.SpiI());
+ if ( !SaOk )
+ {
+ DEBUG_LOG1(_L("Unaccepted SA content in IKE_SA Rekey request: %d"), iState);
+ SetNotifyCode(NO_PROPOSAL_CHOSEN);
+ CleanupStack::PopAndDestroy(NewSA);
+ return EFalse;
+ }
+ NewSA->SetProposedSa(proposedSaBuffer);
+ proposedSaBuffer = NULL;
+ if ( aIkeMsg->iNonce->PlDataLen() < IKEV2_MIN_NONCE_SIZE )
+ {
+ DEBUG_LOG1(_L("Nonce data too short in IKE_SA Rekey request %d"), iState);
+ SetNotifyCode(INVALID_SYNTAX);
+ CleanupStack::PopAndDestroy(NewSA);
+ return EFalse;
+ }
+ if ( iState == KStateIkeSARekeyRequest )
+ {
+ NewSA->iNonce_R = HBufC8::NewL(aIkeMsg->iNonce->PlDataLen());
+ NewSA->iNonce_R->Des().Copy(aIkeMsg->iNonce->PayloadData(), aIkeMsg->iNonce->PlDataLen());
+ }
+ else
+ {
+ NewSA->iNonce_I = HBufC8::NewL(aIkeMsg->iNonce->PlDataLen());
+ NewSA->iNonce_I->Des().Copy(aIkeMsg->iNonce->PayloadData(), aIkeMsg->iNonce->PlDataLen());
+ }
+
+ if ( !NewSA->ProcessKeyExchangeL((TKEPayloadIkev2*)aIkeMsg->iKe, NewSA->iHdr.iDHGroup) )
+ {
+ //If there was notify code set, copy it to current negotiation before destroying NewSa
+ if(NewSA->GetNotifyCode())
+ {
+ SetNotifyCode(NewSA->GetNotifyCode());
+ }
+ TInt dataLth(0);
+ TUint8* notifyData = NewSA->NotifyData(dataLth);
+ if(dataLth == 2)
+ {
+ StoreNotifyData16(GET16(notifyData));
+ }
+ else if(dataLth == 4)
+ {
+ StoreNotifyData32(GET32(notifyData));
+ }
+ CleanupStack::PopAndDestroy(NewSA);
+ return EFalse;
+ }
+
+ if ( iState == KStateIkeSARekeyResponse )
+ {
+ //
+ // Build IKE SA rekey response (CHILD_SA response):
+ // HDR, SAr, Nr, KEr
+ //
+ iDHKeys = NewSA->iDHKeys; // To calculate own DH value
+ iSPI_Rekey = NewSA->iHdr.SpiR();
+ SetProposedSa(NewSA->GetProposedSa());
+ BuildIkeSaRekeyMsgL(EFalse);
+ NewSA->iNonce_R = iNonce_R; // Nonce is created in BuildIkeSaRekeyMsgL()
+ iNonce_R = NULL;
+ iDHKeys = NULL;
+ }
+ //
+ // Generate key material for new IKE SA
+ //
+ NewSA->GenerateIkeKeysL(&iHdr);
+
+ //
+ // Create a new IKE SA and swap IPSec SA from rekeyed IKE SA
+ // to the new just created SA
+ //
+ iIkeV2PlugInSession.CreateIkev2SAL(NewSA->iHdr);
+ iIkeV2PlugInSession.InheritIpsecSas(NewSA->iHdr.SaId(), iHdr.SaId());
+
+ CleanupStack::PopAndDestroy(NewSA);
+ }
+
+ return ETrue;
+}
+
+TBool CIkev2Negotiation::ProcessInfoMsgL(CIkev2Payloads* aIkeMsg)
+{
+ ASSERT(aIkeMsg);
+ //
+ // Process IKE message of exchange type INFORMATIONAL
+ // HDR, SK {[N,] [D,] [CP,] ...}
+ // Only encyrpted and authenitcated are processed.
+ //
+ if ( !aIkeMsg->Encrypted() )
+ {
+ if ( iState == KStateIdle)
+ iStopped = ETrue;
+ return EFalse;
+ }
+ ThdrISAKMP* IkeHdr = aIkeMsg->GetIkeMsg(); // IKE Message fixed header
+ TBool Response = IkeHdr->GetFlags() & IKEV2_RESPONSE_MSG;
+ TUint32 MsgId = IkeHdr->GetMessageId();
+
+ if ( Response )
+ {
+ if ( (iState == KStateIkeInfoRequest) || (iState == KStateIkeDeleteRequest) )
+ {
+ //
+ // A response received to a transmitted Informational request
+ //
+ DEBUG_LOG(_L("Response received to a transmitted Informational request"));
+
+ if ( MsgId == iHdr.ExpectedResponseId() )
+ {
+ iIkeV2PlugInSession.UpdateIkev2SAL(&iHdr, NULL);
+ if ( iState == KStateIkeDeleteRequest )
+ {
+ iIkeV2PlugInSession.IkeSaDeleted(KErrNone); //IKE SA deletion going
+ }
+ else
+ {
+ if ( aIkeMsg->iNotifs->Count() )
+ {
+ ProcessNotifyPayloadsL(*aIkeMsg->iNotifs, EFalse, INFORMATIONAL);
+ }
+ }
+ iStopped = ETrue;
+ return EFalse;
+ }
+ }
+ else if ( iState == KStateChildDeleteRequest )
+ {
+ //
+ // A response received to a transmitted Child SA delete request
+ //
+ if ( aIkeMsg->iDeletes->Count() )
+ {
+ ProcessDeletePayloadsL(*aIkeMsg->iDeletes, EFalse);
+ }
+
+ //
+ // Update sequence numbers and IKE SA data
+ //
+ iIkeV2PlugInSession.UpdateIkev2SAL(&iHdr, NULL);
+ iStopped = ETrue;
+ return EFalse;
+ }
+ }
+ else
+ {
+ //
+ // A Informational request received. Process request according
+ // to payload content and send informational response.
+ //
+ DEBUG_LOG1(_L("INFORMATIONAL request received in state %d"), iState);
+ if ( MsgId == iHdr.ExpectedRequestId() )
+ {
+ TBool BuildResponse = ETrue;
+ if ( aIkeMsg->iDeletes->Count() )
+ {
+ BuildResponse = ProcessDeletePayloadsL(*aIkeMsg->iDeletes, ETrue);
+ }
+ if ( aIkeMsg->iNotifs->Count() )
+ {
+ BuildResponse = ProcessNotifyPayloadsL(*aIkeMsg->iNotifs, ETrue, INFORMATIONAL);
+ }
+ if ( BuildResponse )
+ {
+ CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
+ iHdr.SpiR(),
+ INFORMATIONAL,
+ iHdr.iInitiator,
+ ETrue,
+ iHdr.ExpectedRequestId(),
+ iDebug);
+ CleanupStack::PushL(ikeMsg);
+ ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);
+ CleanupStack::Pop(ikeMsg);
+ SendIkeMsgL(ikeMsg);
+ if ( (iState != KStateIkeInfoRequest) && (iState != KStateIkeDeleteRequest) && (iState != KStateIkeDeleteResponse) )
+ {
+ iState = KStateIkeInfoResponse;
+ iIkeV2PlugInSession.UpdateIkev2SAL(&iHdr, NULL);
+ }
+ }
+ }
+ }
+
+ return ETrue;
+}
+
+TBool CIkev2Negotiation::ProcessNotifyPayloadsL(const CArrayFixFlat<TNotifPayloadIkev2*>& aNotifys,
+ TBool aRequest, TInt aExchange)
+{
+ if ( Ikev2MobIke::ProcessNotifysL(this, aNotifys, aRequest, aExchange) )
+ {
+ return EFalse; // Notify payload(s) was processed by MOBIKE protocol
+ }
+
+ TInt MsgType;
+ TNotifPayloadIkev2* Payload;
+ TInt Count = aNotifys.Count();
+ TInt i = 0;
+
+ while ( i < Count )
+ {
+ Payload = aNotifys.At(i);
+ MsgType = (TInt)Payload->GetMsgType();
+ DEBUG_LOG1(_L("Received Notify payload message type %d"), MsgType);
+ //
+ // Process possible error type Notify messages
+ //
+ if (aExchange == IKE_SA_INIT)
+ {
+ switch ( MsgType )
+ {
+ case INVALID_SYNTAX:
+ //Fall through
+ case NO_PROPOSAL_CHOSEN:
+ return EFalse;
+ case INVALID_KE_PAYLOAD:
+ ProcessInvalidKePayloadNotifyL();
+ return ETrue;
+ case COOKIE:
+ return ProcessCookieL(aNotifys, aRequest);
+ default:
+ break;
+ }
+ }
+ else
+ {
+ switch ( MsgType )
+ {
+ case UNSUPPORTED_CRITICAL_PAYLOAD:
+ case INVALID_SYNTAX:
+ case INVALID_MESSAGE_ID:
+ case AUTHENTICATION_FAILED:
+ case INTERNAL_ADDRESS_FAILURE:
+ case FAILED_CP_REQUIRED:
+ //
+ // When some of these error types received IKE SA shall
+ // corresponding IKE SA shall be deleted
+ //
+ iDeleteIkeSA = ETrue;
+ break;
+
+ case NO_PROPOSAL_CHOSEN:
+ case SINGLE_PAIR_REQUIRED:
+ case NO_ADDITIONAL_SAS:
+ case TS_UNACCEPTABLE:
+ case INVALID_SELECTORS:
+ //
+ // When some of these error types received within
+ // IKE_AUTH or CREATE_CHILD_SA exchange (in response)
+ // Child SA request is interpreted to be failed
+ //
+ if ( ((aExchange == IKE_AUTH) || (aExchange == CREATE_CHILD_SA) ) && !aRequest )
+ iChildSARejected = ETrue;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ i++;
+ }
+
+ return ETrue;
+}
+
+TBool CIkev2Negotiation::ProcessCookieL(const CArrayFixFlat<TNotifPayloadIkev2*>& aNotifys, TBool aRequest)
+{
+
+ //
+ // Special handling for COOKIE Notify payload.
+ // The following actions are taken:
+ // - Assure that the first Notify payload in array is cookie
+ // - When the COOKIE is received in response (aRequest = EFalse)
+ // - Retransmit IKE_SA_INIT request again in format:
+ // HDR(A,0), N(COOKIE), SAi1, KEi, Ni, [Nat Notifies]
+ // - When the COOKIE is received in request (aRequest = ETrue)
+ // - Assure that COOKIE returned by the initiator is the we
+ // have earlier transmitted.
+ //
+ if ( aNotifys.Count() )
+ {
+ const TNotifPayloadIkev2* NotifyPayload = aNotifys.At(0);
+ if ( NotifyPayload->GetMsgType() == COOKIE && !aRequest)
+ {
+ //
+ // Local end COOKIE usage has not been implemented yet
+ //
+
+ //
+ // Init a new IKE message buffer and copy received COOKIE
+ // Notify to the first payload. Concatenate then all
+ // payloads from original IKE_SA_INIT request to this new
+ // IKE message (and set next payload field in Notify)
+ //
+ DEBUG_LOG1(_L("Cookie received, IKE_SA_INIT repeated: %d"), iState);
+ if ( iCookieReturned )
+ {
+ //
+ // One cookie already returned. Avoid cookie-loop
+ // by stopping ongoing IKE_SA_INIT exchange
+ //
+ DEBUG_LOG(_L("Cookie already returned once, IKE_SA_INIT exchange stopped"));
+ return EFalse;
+ }
+ CIkeV2Message* originalIkeSaInitRequest = iHdr.iLastRequest;
+ const TPtrC8 cookieData(NotifyPayload->NotifData(), NotifyPayload->NotifDataLength());
+ originalIkeSaInitRequest->PrependCookieNotifyPayloadL(cookieData);
+ iHdr.iLastRequest = NULL; //claims the ownership of the message
+
+ SendIkeMsgL(originalIkeSaInitRequest);
+ iTimer->Cancel(); // Reset transmit retry timer
+ iTimer->IssueRequest(iSendAttempt); // Start retry timer
+ iCookieReturned = ETrue;
+ return ETrue;
+ }
+ }
+ DEBUG_LOG1(_L("Cookie required, NO COOKIE Notify found: %d"), iState);
+
+ return EFalse;
+}
+
+
+
+TBool CIkev2Negotiation::ProcessDeletePayloadsL(const CArrayFixFlat<TDeletePlIkev2*>& aDeletes,
+ TBool aRequest)
+{
+ //
+ // Process delete payloads received.
+ //
+ CDesC8ArrayFlat* SpiList = NULL;
+ TUint8 Protocol = IKEV2_PROT_NONE;
+
+ for (TInt i = 0; i < aDeletes.Count(); ++i)
+ {
+ const TDeletePlIkev2* Payload = aDeletes.At(i);
+ Protocol = Payload->GetProtocolId();
+ switch ( Protocol )
+ {
+ case IKEV2_PROTOCOL:
+ //
+ // Deletion of current existing IKE SA. All IPSEC SA:s
+ // negotiated within IKE SA are deleted implicitly
+ //
+ iIkeV2PlugInSession.DeleteIkev2SA(iHdr.SaId());
+ delete SpiList;
+ SpiList = NULL;
+ i = aDeletes.Count(); // Stop outer while loop
+ iState = KStateIkeDeleteResponse; // Set next state here
+ break;
+
+ case IKEV2_IPSEC_AH:
+ case IKEV2_IPSEC_ESP:
+ if ( Payload->GetSPISize() == 4 )
+ {
+ //
+ // Delete Ipsec SPI:s from IKE SA (and IPSEC SADB)
+ // If Delete payload received within Info request
+ // build inbound SPI list of corresponding inbound
+ // SA:s
+ //
+ TUint SpiCount = (TInt)Payload->GetNbrOfSpis();
+ if ( TPayloadIkev2::Cast(Payload)->GetLength() ==
+ ( TDeletePlIkev2::Size() + 4*SpiCount) )
+ {
+ const TUint8* Spis = Payload->SPIs();
+ if ( aRequest && !SpiList )
+ {
+ SpiList = new (ELeave) CDesC8ArrayFlat(2);
+ CleanupStack::PushL(SpiList);
+ }
+ while ( SpiCount )
+ {
+ TPtrC8 Spi(Spis, 4);
+ if ( SpiList )
+ {
+ const TIkeV2IpsecSAData* IpsecSa =
+ iIkeV2PlugInSession.FindIpsecSAData(iHdr.SaId(), Spi, EFalse);
+ if ( IpsecSa && IpsecSa->iSPI_In.Length() > 0 )
+ {
+ SpiList->AppendL(IpsecSa->iSPI_In);
+ }
+ }
+ iIkeV2PlugInSession.DeleteIpsecSAData(iHdr.SaId(), Spi, EFalse);
+ Spis += 4;
+ SpiCount--;
+ }
+ }
+ }
+ break;
+ default:
+ break;
+ }
+ }
+
+ if ( SpiList )
+ {
+ //
+ // Build Informational exchange response with a
+ // Delete payload containing SPI:s of corresponding
+ // inbound SA:s.
+ //
+ CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
+ iHdr.SpiR(),
+ INFORMATIONAL,
+ iHdr.iInitiator,
+ ETrue,
+ iHdr.ExpectedRequestId(), iDebug);
+ CleanupStack::PushL(ikeMsg);
+ ikeMsg->AppendEncryptedPayloadL(iHdr.iCipherBlkLth);
+ ikeMsg->AppendDeletePayloadL(Protocol, *SpiList);
+ CleanupStack::Pop(ikeMsg);
+ SendIkeMsgL(ikeMsg);
+ CleanupStack::PopAndDestroy(SpiList);
+ iState = KStateIkeInfoResponse;
+ iIkeV2PlugInSession.UpdateIkev2SAL(&iHdr, NULL);
+ aRequest = EFalse;
+ }
+
+ return aRequest;
+}
+
+void CIkev2Negotiation::ProcessInvalidKePayloadNotifyL()
+{
+ // Build and send new IKE_SA_INIT message (request) with another DH group #
+ // HDR, SAi1, KEi, Ni, N[NAT_SRC], N[NAT_DST]
+ //
+ iDHGroupGuess++;
+ delete iDHKeys; // Delete old DH object
+ iDHKeys = NULL;
+ iHdr.iDHGroup = 0;
+
+ TUint32 lastRequestMsgId = 0;
+ if(iHdr.iLastRequest != NULL)
+ {
+ lastRequestMsgId = iHdr.iLastRequest->MessageId();
+ }
+
+ CIkeV2Message* ikeMsg = CIkeV2Message::NewL(iHdr.SpiI(),
+ iHdr.SpiR(),
+ IKE_SA_INIT,
+ iHdr.iInitiator,
+ EFalse,
+ lastRequestMsgId,
+ iDebug);
+ CleanupStack::PushL(ikeMsg);
+
+ HBufC8* saBfr = Ikev2Proposal::FromPolicyToProposaL(iHdr, iSPI_Rekey, iDHGroupGuess);
+ CleanupStack::PushL(saBfr);
+ ikeMsg->AppendSaPayloadL(*saBfr);
+ CleanupStack::Pop(saBfr);
+ SetProposedSa(saBfr);
+
+ AppendKEPayloadL(*ikeMsg, iHdr.iDHGroup);
+ ikeMsg->AppendNoncePayloadL(*iNonce_I);
+ if ( !iHdr.iIkeData->iUseNatProbing )
+ {
+ delete iNatNotify;
+ iNatNotify = NULL;
+
+ TInetAddr LocalIp;
+ if ( iHdr.iIkeData->iUseMobIke )
+ LocalIp.SetAddress(KInetAddrNone);
+ else LocalIp = iHdr.iLocalAddr;
+ iNatNotify = CIkev2NatT::NewL(
+ LocalIp, iHdr.iRemoteAddr, IKE_PORT, ikeMsg->InitiatorSpi(), ikeMsg->ResponderSpi());
+
+ ikeMsg->AppendNotifyPayloadL(IKEV2_PROTOCOL, KZeroDesc, NAT_DETECTION_SOURCE_IP,
+ iNatNotify->SourceNofify());
+ ikeMsg->AppendNotifyPayloadL(IKEV2_PROTOCOL, KZeroDesc, NAT_DETECTION_DESTINATION_IP,
+ iNatNotify->DestinNofify());
+ }
+
+ CleanupStack::Pop(ikeMsg);
+ SendIkeMsgL(ikeMsg);
+
+ iState = KStateIkeSaInitRequest;
+}
+
+
+
+void CIkev2Negotiation::GetNonceDataL(TBool aInitiator)
+{
+ //
+ // Get random data for local nonce
+ //
+ HBufC8* Nonce;
+ if ( aInitiator )
+ {
+ Nonce = HBufC8::NewL(IKEV2_DEF_NONCE_SIZE);
+ delete iNonce_I;
+ iNonce_I = Nonce;
+ }
+ else
+ {
+ Nonce = HBufC8::NewL(IKEV2_DEF_NONCE_SIZE);
+ delete iNonce_R;
+ iNonce_R = Nonce;
+ }
+ TPtr8 RandOctet(Nonce->Des());
+ RandOctet.SetLength(IKEV2_DEF_NONCE_SIZE);
+ TRandom::RandomL(RandOctet);
+}
+
+void CIkev2Negotiation::GetOwnIdentityL(TBool aEapIdResponse)
+{
+ if ( iLocalIdentity )
+ {
+ return; // We already have own identity data
+ }
+
+ //
+ // The own IKE identity data is built with the following system:
+ // -- If Own Certificate exist take try to get identity data from it
+ // If no Certificate or identity cannot be get from certificate
+ // -- If EAP used use identity speficied by the EAP plugin
+ // -- If EAP not used, get own identity data information from current IKE policy
+ // If no identity information found use local IP address as
+ // identity. Own IKE Identity information is stored in iLocalIdentity
+ // buffer (linked into negotiation object) in format of Identity
+ // payload (TIDPayloadIkev2)
+ //
+
+
+ HBufC8* IdBfr = NULL;
+ TUint8 IdType = ID_NOT_DEFINED;
+
+
+ //Try to get the identity from the user certificate
+ if ( iPkiService && iPkiService->UserCertificateData().Length() > 0 )
+ {
+ IdType = iHdr.iIkeData->iIdType;
+ IdBfr = IkePkiUtils::GetIdentityFromCertL(IdType, iPkiService->UserCertificateData());
+ if ( IdBfr != NULL)
+ {
+ if (IdType == ID_NOT_DEFINED)
+ {
+ IdType = ID_DER_ASN1_DN;
+ }
+ }
+ else
+ {
+ //We didn't get the ID data from the user certificate.
+ //Make sure that the type is set to not defined.
+ IdType = ID_NOT_DEFINED;
+ }
+ }
+
+ //If we didn't get the identity from the user certificate,
+ //try to get it from the EAP plugin.
+ if ( IdType == ID_NOT_DEFINED && iEapPlugin )
+ {
+ __ASSERT_DEBUG(IdBfr == NULL, User::Invariant());
+ //
+ // Try to get Own identity data from EAP Plug-in
+ //
+ IdBfr = iEapPlugin->Identity();
+ if ( IdBfr != NULL && IdBfr->Length() )
+ {
+ //
+ // Identity data provided by EAP plug-in. Define IKE Id type
+ // value according to Identity data content. If Id data
+ // contains realm (format username@realm) Id type
+ // ID_RFC822_ADDR is used. If no realm in ID use type ID_KEY_ID
+ //
+ TInt offset = IdBfr->Find(_L8("@"));
+ IdType = ( offset == KErrNotFound ) ? ID_KEY_ID : ID_RFC822_ADDR;
+ }
+ else
+ {
+ delete IdBfr;
+ IdBfr = NULL;
+ if ( !aEapIdResponse )
+ return; // Identity not yet available continue waiting
+ }
+ }
+
+ //If we don't have identity so far, try to get it from the
+ //policy:
+ if ( IdType == ID_NOT_DEFINED &&
+ iHdr.iIkeData->iIdType != ID_NOT_DEFINED &&
+ iHdr.iIkeData->iFQDN.Length() > 0)
+ {
+ __ASSERT_DEBUG(IdBfr == NULL, User::Invariant());
+ IdBfr = HBufC8::NewL(iHdr.iIkeData->iFQDN.Length());
+ IdBfr->Des().Copy(iHdr.iIkeData->iFQDN);
+ IdType = iHdr.iIkeData->iIdType;
+ }
+
+
+ //If we have not been able to get the identity so far, we are using the default
+ //identity, which is our own IP address.
+ if ( IdType == ID_NOT_DEFINED)
+ {
+ __ASSERT_DEBUG(IdBfr == NULL, User::Invariant());
+ if ( (iHdr.iLocalAddr.Family()== KAfInet) || iHdr.iLocalAddr.IsV4Mapped() )
+ {
+ TUint32 num = ByteOrder::Swap32(iHdr.iLocalAddr.Address());//Put in network order
+ IdBfr = HBufC8::NewL(sizeof(num));
+ IdBfr->Des().Append(reinterpret_cast<TUint8*>(&num), sizeof(num));
+ IdType = ID_IPV4_ADDR;
+ }
+ else
+ {
+ IdBfr = HBufC8::NewL(16);
+ const TUint8* pnum = &iHdr.iLocalAddr.Ip6Address().u.iAddr8[0]; //Address in a bytestream
+ IdBfr->Des().Append(pnum, 16);
+ IdType = ID_IPV6_ADDR;
+ }
+ }
+
+ __ASSERT_DEBUG((IdType != ID_NOT_DEFINED && IdBfr != NULL), User::Invariant());
+ CleanupStack::PushL(IdBfr);
+ iLocalIdentity = CIkeV2Identity::NewL(IdType, *IdBfr);
+ CleanupStack::PopAndDestroy(IdBfr);
+}
+
+
+void CIkev2Negotiation::GenerateIkeKeysL(TIkev2SAData* aRekeydSaData)
+{
+ //
+ // Generate IKE keying material. Start by calculating
+ // Diffie-Hellman secret.
+ //
+ User::LeaveIfNull(iDHPublicPeer);
+ if ( !iDHKeys )
+ {
+ iDHKeys = CDHKeys::CreateDHKeyL(iHdr.iDHGroup);
+ iDHKeys->XValueL(); // Calculate own DH public value
+ }
+ HBufC8* g_ir = iDHKeys->ComputeAgreedKeyL(iDHPublicPeer->Des());
+ CleanupStack::PushL(g_ir);
+ delete iDHKeys;
+ iDHKeys = NULL;
+
+ HBufC8* Ni_Nr;
+ HBufC8* SKEYSEED;
+ TUint16 prfAlg(0);
+
+ if ( aRekeydSaData )
+ {
+ //
+ // Calculate IKE keying material seed SKEYDSEED = prf(SK_d(old), [g^ir (new)] | Ni | Nr)
+ //
+ Ni_Nr = HBufC8::NewL(g_ir->Length() + iNonce_I->Length() + iNonce_R->Length());
+ CleanupStack::PushL(Ni_Nr);
+ Ni_Nr->Des().Copy(g_ir->Des());
+ Ni_Nr->Des().Append(iNonce_I->Des());
+ Ni_Nr->Des().Append(iNonce_R->Des());
+
+ prfAlg = aRekeydSaData->iPRFAlg;
+ SKEYSEED = IkeCrypto::PrfhmacL(*Ni_Nr, aRekeydSaData->iSK_d, prfAlg);
+ CleanupStack::PushL(SKEYSEED);
+ }
+ else
+ {
+ //
+ // Calculate IKE keying material seed SKEYDSEED = prf(Ni | Nr, g^ir)
+ //
+ Ni_Nr = HBufC8::NewL(iNonce_I->Length() + iNonce_R->Length());
+ CleanupStack::PushL(Ni_Nr);
+ Ni_Nr->Des().Copy(iNonce_I->Des());
+ Ni_Nr->Des().Append(iNonce_R->Des());
+
+ prfAlg = iHdr.iPRFAlg;
+ SKEYSEED = IkeCrypto::PrfhmacL(*g_ir, *Ni_Nr, prfAlg);
+ CleanupStack::PushL(SKEYSEED);
+ }
+
+ g_ir->Des().FillZ(); // Wipe out shared secret value from buffer
+
+ iHdr.GenerateIkeKeyDerivatesL(SKEYSEED->Des(),prfAlg, *iNonce_I, *iNonce_R);
+ SKEYSEED->Des().FillZ(); // Wipe out SKEYSEED value from buffer
+
+ CleanupStack::PopAndDestroy(3); //g_ir , Ni_Nr and SKEYSEED
+}
+
+
+void CIkev2Negotiation::SaveSignedDataL(TBool aLocal, const TDesC8& aIkeMsg)
+{
+ //
+ // Allocate buffer for signed octets needed for IKE SA
+ // authentication with AUTH payload.
+ // The signed octet contains the following data:
+ // Initiator:
+ // - IKE_SA_INIT message content (message number 1)
+ // concatenated with responder nonce data and value
+ // prf(SK_pi,IDi") where IDi" is initiator ID data without fixed
+ // payload header
+ //
+ // Responder:
+ // - IKE_SA_INIT message content (message number 2)
+ // concatenated with initiator nonce data and value
+ // prf(SK_pr,IDr") where IDr" is responder ID data without fixed
+ // payload header
+ //
+ TInt SignedLth = aIkeMsg.Length(); // Initial value
+ HBufC8* Nonce;
+ HBufC8** SignedBfrPtr;
+ if ( aLocal )
+ {
+ if ( iHdr.iInitiator )
+ {
+ SignedBfrPtr = &iAuthMsgInit;
+ Nonce = iNonce_R;
+ }
+ else {
+ SignedBfrPtr = &iAuthMsgResp;
+ Nonce = iNonce_I;
+ }
+ }
+ else
+ {
+ if ( iHdr.iInitiator )
+ {
+ SignedBfrPtr = &iAuthMsgResp;
+ Nonce = iNonce_I;
+ }
+ else
+ {
+ SignedBfrPtr = &iAuthMsgInit;
+ Nonce = iNonce_R;
+ }
+ }
+
+ SignedLth += Nonce->Length() + IkeCrypto::AlgorithmInfo(IKEV2_PRF, iHdr.iPRFAlg);
+ HBufC8* Signed = HBufC8::NewL(SignedLth);
+ Signed->Des().Copy(aIkeMsg);
+ Signed->Des().Append(Nonce->Des());
+
+ if ( aLocal && iLocalIdentity )
+ {
+ //
+ // Add value prf(SK_px,IDx") into local signed data buffer end
+ //
+ AddIdToSignedDataL(ETrue, Signed, iLocalIdentity->PayloadData());
+ }
+
+ delete *SignedBfrPtr;
+ *SignedBfrPtr = Signed;
+}
+
+
+void CIkev2Negotiation::AddIdToSignedDataL(TBool aLocal, HBufC8* aSigned, const TDesC8& aIdData)
+{
+ ASSERT(aSigned);
+ //
+ // Add value prf(SK_px,IDx") into signed data buffer end
+ //
+
+ HBufC8* signedIdData = NULL;;
+ if ( iHdr.iInitiator )
+ {
+ if ( aLocal )
+ {
+ signedIdData = IkeCrypto::PrfhmacL(aIdData, iHdr.iSK_pi, iHdr.iPRFAlg);
+ }
+ else
+ {
+ signedIdData = IkeCrypto::PrfhmacL(aIdData, iHdr.iSK_pr, iHdr.iPRFAlg);
+ }
+ }
+ else
+ {
+ if ( aLocal )
+ {
+ signedIdData = IkeCrypto::PrfhmacL(aIdData, iHdr.iSK_pr, iHdr.iPRFAlg);
+ }
+ else
+ {
+ signedIdData = IkeCrypto::PrfhmacL(aIdData, iHdr.iSK_pi, iHdr.iPRFAlg);
+ }
+ }
+ aSigned->Des().Append(*signedIdData);
+ delete signedIdData;
+}
+
+HBufC8* CIkev2Negotiation::SignAuthDataL(const TDesC8& aAuthData, TUint8 aAuthMethod)
+{
+ //
+ // Sign aMsgData according to authentication method parameter
+ //
+ HBufC8* signedAuthData = NULL;
+
+ if ( iPkiService &&
+ iPkiService->TrustedCaName().Length() > 0 &&
+ iPkiService->UserCertificateData().Length() > 0 )
+ {
+ //
+ // Message data <msg octets> is signed using private key
+ //
+ TPtrC8 TrustedCa(iPkiService->TrustedCaName());
+ signedAuthData = HBufC8::NewLC(320); // reserved for sign (aware for 2048 bits signatures)
+ TPtr8 signedAuthDataPtr(signedAuthData->Des());
+
+ iPkiService->Ikev2SignatureL(TrustedCa, iHdr.iIkeData->iOwnCert, aAuthData, signedAuthDataPtr, aAuthMethod);
+ CleanupStack::Pop(signedAuthData);
+ }
+ else
+ {
+ //
+ // Message data is signed using negotiated PRF function as
+ // follows:
+ // AUTH =
+ // prf(prf(Shared Secret,"Key Pad for IKEv2"), <msg octets>)
+ // If EAP method that creates a shared key as a side effect of
+ // authentication used, this shared key is used as Shared Secret
+ // Otherwise preshared key configured into policy is used as
+ // Shared secret.
+ //
+ if ( !iPresharedKey )
+ iPresharedKey = Ikev2Proposal::GetPSKFromPolicyL(iHdr.iIkeData);
+ //
+ // Calculate KEY = prf(Shared Secret,"Key Pad for IKEv2")
+ //
+ HBufC8* PskKey = IkeCrypto::PrfhmacL(KIkev2PSKData, *iPresharedKey, iHdr.iPRFAlg);
+ CleanupStack::PushL(PskKey);
+ //
+ // Calculate prf(KEY, <msg octets>)
+ //
+ signedAuthData = IkeCrypto::PrfhmacL(aAuthData, *PskKey, iHdr.iPRFAlg);
+ CleanupStack::PopAndDestroy(PskKey);
+ }
+ return signedAuthData;
+}
+
+TBool CIkev2Negotiation::AddIdAndAuthenticatePeerL(CIkev2Payloads* aIkeMsg)
+{
+ ASSERT(aIkeMsg);
+ //
+ // Verify that authentication payload of peer is correct
+ // To do this the signed data octets of peer must be filled with
+ // value: prf(SK_px,IDx")
+ // So the peer ID payload must be verified first.
+ //
+ HBufC8* Signed;
+ TIDPayloadIkev2* Id;
+ if ( iHdr.iInitiator )
+ {
+ Signed = iAuthMsgResp;
+ Id = (TIDPayloadIkev2*)aIkeMsg->iIdR;
+ }
+ else
+ {
+ Signed = iAuthMsgInit;
+ Id = (TIDPayloadIkev2*)aIkeMsg->iIdI;
+ }
+ if ( !Signed || !Id )
+ return EFalse;
+
+ if ( !iPeerIdInSignedData )
+ {
+ TUint16 IdLth = TPayloadIkev2::Cast(Id)->GetLength();
+ if ( IdLth < TIDPayloadIkev2::Size() )
+ {
+ DEBUG_LOG1(_L("Peer ID payload too short; Length %d"), IdLth);
+ return EFalse;
+ }
+ //
+ // Add value prf(SK_px,IDx") into peer signed data buffer end
+ //
+ TPayloadIkev2* idPayload = TPayloadIkev2::Cast(Id);
+ TPtrC8 idPtr(idPayload->PayloadData(), (idPayload->GetLength() - TPayloadIkev2::Size()));
+ AddIdToSignedDataL(EFalse, Signed, idPtr);
+ iPeerIdInSignedData = ETrue;
+ }
+
+ return AuthenticatePeerL(aIkeMsg->iAuth);
+
+}
+
+TBool CIkev2Negotiation::AuthenticatePeerL(TAuthPayloadIkev2* aAuth)
+{
+ //
+ // Authenticate peer tication payload of peer is correct
+ // To do this the signed data octets of peer must be filled with
+ // value: prf(SK_px,IDx")
+ // So the peer ID payload must be verified first.
+ //
+ HBufC8* Signed;
+ if ( iHdr.iInitiator )
+ Signed = iAuthMsgResp;
+ else Signed = iAuthMsgInit;
+
+ if ( !Signed || !aAuth )
+ return EFalse;
+
+ TUint16 AuthLth = TPayloadIkev2::Cast(aAuth)->GetLength();
+ if ( AuthLth < TAuthPayloadIkev2::Size() )
+ {
+ DEBUG_LOG1(_L("Peer Auth payload too short; Length %d"), AuthLth);
+ return EFalse;
+ }
+ AuthLth = (TUint16)(AuthLth - TAuthPayloadIkev2::Size());
+ TBool Status = EFalse;
+
+ if ( aAuth->GetAuthMethod() == PRESHARED_KEY )
+ {
+ DEBUG_LOG(_L("Authenticating SGW with PSK"));
+ //
+ // Pre shared key authentication is not accepted for peer if we
+ // have requested an certificate from peer (PKI authentication
+ // required)
+ //
+ if ( !iPkiAuthRequired )
+ {
+ HBufC8* AuthRef = SignAuthDataL(*Signed, PRESHARED_KEY);
+ CleanupStack::PushL(AuthRef);
+ if ( AuthRef->Length() == AuthLth )
+ {
+ Status = (Mem::Compare(AuthRef->Ptr(), AuthRef->Length(), aAuth->AuthData(), AuthLth ) == 0);
+ }
+ CleanupStack::PopAndDestroy(); // AuthRef
+ }
+ }
+ else
+ {
+ //
+ // Authentication based on PKI (private key signature)
+ //
+ if ( iPkiService && iPeerCert )
+ {
+ DEBUG_LOG(_L("Authenticating SGW with certs"));
+
+ TPtrC8 AuthData(Signed->Des());
+ TPtrC8 Signature(aAuth->AuthData(), AuthLth);
+ Status = IkePkiUtils::VerifyIkev2SignatureL(Signature, AuthData, *iPeerCert);
+ iPkiAuthRequired = EFalse;
+ }
+ }
+ if (Status)
+ {
+ DEBUG_LOG(_L("SGW authentication success"));
+ }
+ else
+ {
+ DEBUG_LOG(_L("SGW authentication failed"));
+ }
+
+ return Status;
+}
+
+
+TBool CIkev2Negotiation::VerifyPeerCertificateL(CArrayFixFlat<TCertPayloadIkev2*>* aCerts, TIDPayloadIkev2* aId )
+{
+ TBool Status = EFalse;
+
+ const CIkeCaList& trustedCaList = iPkiService->CaList();
+ CX509Certificate* PeerCert = IkePkiUtils::VerifyCertificateL(*aCerts, trustedCaList);
+
+ if ( PeerCert && aId )
+ {
+ CleanupStack::PushL(PeerCert);
+ TPtrC8 IdData(aId->IdData(), (TPayloadIkev2::Cast(aId)->GetLength() - TIDPayloadIkev2::Size()));
+ Status = IkePkiUtils::CertifyIdentityL(PeerCert, IdData, (TInt)aId->GetIdType());
+ if ( Status )
+ {
+ DEBUG_LOG(_L("IDr matches the SGW certificate"));
+ if (iRemoteIdentity && !iHdr.iIkeData->iSkipRemoteIdCheck ) //iRemoteIdentity if the REMOTE_IF from the policy
+ {
+ //TIDPayloadIkev2* peerIdentityPayload = TIDPayloadIkev2::Cast(iRemoteIdentity->Ptr());
+ if (iRemoteIdentity->IdType() == aId->GetIdType())
+ {
+ TPtrC8 idPtr(aId->IdData(),
+ TPayloadIkev2::Cast(aId)->GetLength() - TIDPayloadIkev2::Size());
+ TPtrC8 peerIdentityPtr(iRemoteIdentity->Identity());
+
+ //Check if we accept partial remote id
+ if (iHdr.iIkeData->iAcceptPartialRemoteId &&
+ iRemoteIdentity->IdType() == ID_FQDN &&
+ peerIdentityPtr.Length() > idPtr.Length())
+ {
+ DEBUG_LOG(_L("Using PARTIAL_REMOTE_ID_CHECK"));
+ peerIdentityPtr.Set(peerIdentityPtr.Right(idPtr.Length()));
+ }
+ if (idPtr.Compare(peerIdentityPtr) == 0)
+ {
+ DEBUG_LOG(_L("IDr matches the REMOTE_ID"));
+ Status = ETrue;
+ }
+ else
+ {
+ DEBUG_LOG(_L("IDr does not match the REMOTE_ID"));
+ Status = EFalse;
+ }
+ }
+ else
+ {
+ DEBUG_LOG(_L("IDr payload ID does not match REMOTE_ID_TYPE"));
+ Status = EFalse;
+ }
+ }
+ }
+ else
+ {
+ DEBUG_LOG(_L("IDr does not match the SGW certificate"));
+ }
+
+ if ( Status )
+ {
+ CleanupStack::Pop(PeerCert);
+ delete iPeerCert;
+ iPeerCert = PeerCert;
+ }
+ else CleanupStack::PopAndDestroy(PeerCert);
+ }
+ return Status;
+}
+
+
+TBool CIkev2Negotiation::ProcessKeyExchangeL(TKEPayloadIkev2* aKePayload, TUint16 aGroup)
+{
+ //
+ // Process key exchange payload received from peer
+ //
+ if ( !aKePayload )
+ {
+ DEBUG_LOG1(_L("Key Exchange payload not present, required Group %d"), aGroup);
+ SetNotifyCode(INVALID_KE_PAYLOAD);
+ StoreNotifyData16(aGroup);
+ return EFalse;
+ }
+ TUint16 PlLth = TPayloadIkev2::Cast(aKePayload)->GetLength();
+ if (( PlLth <= TKEPayloadIkev2::Size() ) || ( aKePayload->GetDHGroup() != aGroup ))
+ {
+ DEBUG_LOG1(_L("Peer Key Exchange DH group does not match, Group %d"), aKePayload->GetDHGroup());
+ SetNotifyCode(INVALID_KE_PAYLOAD);
+ StoreNotifyData16(aGroup);
+ return EFalse;
+ }
+ if ( !iDHKeys )
+ iDHKeys = CDHKeys::CreateDHKeyL(aGroup);
+ PlLth = (TUint16)(PlLth - TKEPayloadIkev2::Size());
+ if ( PlLth != iDHKeys->ModulusLength() )
+ {
+ DEBUG_LOG1(_L("Peer DH public value length does not match group, Length %d"), PlLth);
+ SetNotifyCode(INVALID_KE_PAYLOAD);
+ StoreNotifyData16(aGroup);
+ return EFalse;
+ }
+ delete iDHPublicPeer;
+ iDHPublicPeer = NULL;
+ iDHPublicPeer = HBufC8::NewL(PlLth);
+ iDHPublicPeer->Des().Copy(aKePayload->DHPublic(), PlLth);
+
+ return ETrue;
+}
+
+void CIkev2Negotiation::AppendKEPayloadL(CIkeV2Message& aIkeMsg, TUint16 aDHGroup)
+{
+ if ( !iDHKeys )
+ iDHKeys = CDHKeys::CreateDHKeyL(aDHGroup);
+
+ iDHKeys->XValueL(); // Calculate own DH public value
+ HBufC8* dHPublic = iDHKeys->GetPubKey(); //save the public key in a buffer to have easy access
+ User::LeaveIfNull(dHPublic);
+ CleanupStack::PushL(dHPublic);
+
+ TInt modulusLength = iDHKeys->ModulusLength();
+ HBufC8* kePayloadData = HBufC8::NewLC(modulusLength);
+ TPtr8 kePayloadDataPtr(kePayloadData->Des());
+
+ __ASSERT_DEBUG(modulusLength == dHPublic->Length(), User::Invariant());
+
+ kePayloadDataPtr.Append(*dHPublic);
+ kePayloadDataPtr.SetLength(modulusLength); //adds zero padding, if needed
+
+ aIkeMsg.AppendKePayloadL(aDHGroup, *kePayloadData);
+
+ CleanupStack::PopAndDestroy(kePayloadData);
+ CleanupStack::PopAndDestroy(dHPublic);
+}
+
+
+
+TBool CIkev2Negotiation::CheckPayloadsOrder(CIkev2Payloads* aIkeMsg, TUint8 aExchange, TBool aResponse)
+ {
+ switch ( aExchange )
+ {
+ case IKE_SA_INIT:
+ if(!aIkeMsg->iSa || !aIkeMsg->iKe || !aIkeMsg->iNonce) return EFalse;
+ if(aIkeMsg->iSa->GetNextPayload() != IKEV2_PAYLOAD_KE) return EFalse;
+ if(aIkeMsg->iKe->GetNextPayload() != IKEV2_PAYLOAD_NONCE) return EFalse;
+ break;
+
+ case IKE_AUTH:
+ if(!iEapPlugin)
+ {
+ if(!aIkeMsg->iEncr || !aIkeMsg->iAuth || !aIkeMsg->iSa || !aIkeMsg->iTsI || !aIkeMsg->iTsR)
+ {
+ DEBUG_LOG(_L("1"));
+ return EFalse;
+ }
+ if(aIkeMsg->iSa->GetNextPayload() != IKEV2_PAYLOAD_TS_I)
+ {
+ DEBUG_LOG(_L("2"));
+ return EFalse;
+ }
+ if(aIkeMsg->iTsI->GetNextPayload() != IKEV2_PAYLOAD_TS_R)
+ {
+ DEBUG_LOG(_L("3"));
+ return EFalse;
+ }
+
+ if(aResponse)
+ {
+ if(!aIkeMsg->iIdR)
+ {
+ DEBUG_LOG(_L("4"));
+ return EFalse;
+ }
+ if(!aIkeMsg->iCerts || aIkeMsg->iCerts->Count() == 0)
+ {
+ if(aIkeMsg->iIdR->GetNextPayload() != IKEV2_PAYLOAD_AUTH)
+ {
+ DEBUG_LOG(_L("5"));
+ return EFalse;
+ }
+ }
+ else
+ {
+ if(aIkeMsg->iIdR->GetNextPayload() != IKEV2_PAYLOAD_CERT)
+ {
+ DEBUG_LOG(_L("6"));
+ return EFalse;
+ }
+ TInt c = aIkeMsg->iCerts->Count();
+ if(aIkeMsg->iCerts->At(c-1)->GetNextPayload() != IKEV2_PAYLOAD_AUTH)
+ {
+ DEBUG_LOG(_L("7"));
+ return EFalse;
+ }
+ }
+ }
+ else
+ {
+ if(!aIkeMsg->iIdI)
+ {
+ DEBUG_LOG(_L("8"));
+ return EFalse;
+ }
+ if(aIkeMsg->iCerts && aIkeMsg->iCerts->Count() != 0)
+ {
+ if(aIkeMsg->iIdI->GetNextPayload() != IKEV2_PAYLOAD_CERT)
+ {
+ DEBUG_LOG(_L("9"));
+ return EFalse;
+ }
+ }
+ if(aIkeMsg->iCertReqs && aIkeMsg->iCertReqs->Count() != 0)
+ {
+ TInt c = aIkeMsg->iCertReqs->Count();
+ if(aIkeMsg->iIdR && aIkeMsg->iCertReqs->At(c-1)->GetNextPayload() != IKEV2_PAYLOAD_ID_R)
+ {
+ DEBUG_LOG(_L("10"));
+ return EFalse;
+ }
+ if(!aIkeMsg->iIdR && aIkeMsg->iCertReqs->At(c-1)->GetNextPayload() != IKEV2_PAYLOAD_AUTH)
+ {
+ DEBUG_LOG(_L("11"));
+ return EFalse;
+ }
+ }
+ if(aIkeMsg->iIdR && aIkeMsg->iIdR->GetNextPayload() != IKEV2_PAYLOAD_AUTH)
+ {
+ DEBUG_LOG(_L("12"));
+ return EFalse;
+ }
+ }
+ }
+ break;
+
+ case CREATE_CHILD_SA:
+ if(!aIkeMsg->iEncr || !aIkeMsg->iSa || !aIkeMsg->iNonce) return EFalse;
+ if(aIkeMsg->iSa->GetNextPayload() != IKEV2_PAYLOAD_NONCE) return EFalse;
+ if(aIkeMsg->iKe && aIkeMsg->iNonce->GetNextPayload() != IKEV2_PAYLOAD_KE) return EFalse;
+ if(aIkeMsg->iTsI)
+ {
+ if(aIkeMsg->iKe && aIkeMsg->iKe->GetNextPayload() != IKEV2_PAYLOAD_TS_I) return EFalse;
+ if(!aIkeMsg->iKe && aIkeMsg->iNonce->GetNextPayload() != IKEV2_PAYLOAD_TS_I) return EFalse;
+ if(aIkeMsg->iTsI->GetNextPayload() != IKEV2_PAYLOAD_TS_R) return EFalse;
+ }
+ break;
+
+ default:
+ break;
+ }
+ DEBUG_LOG(_L("13"));
+ return ETrue;
+ }
+
+
+TBool CIkev2Negotiation::Stopped()
+ {
+ return iStopped;
+ }
+
+
+TBool CIkev2Negotiation::ImplicitChildSa()
+ {
+ return (iState < KStateIkeSaCompleted);
+ }
+
+
+HBufC8* CIkev2Negotiation::PeekProposedSa()
+ {
+ return iProposedSA;
+ }
+
+
+HBufC8* CIkev2Negotiation::GetProposedSa()
+ {
+ HBufC8* Sa = iProposedSA;
+ iProposedSA = NULL;
+ return Sa;
+ }
+
+
+void CIkev2Negotiation::SetProposedSa(HBufC8* aSaPl)
+ {
+ delete iProposedSA;
+ iProposedSA = aSaPl;
+ }
+
+
+CIkev2Acquire** CIkev2Negotiation::GetAcquireQue()
+ {
+ return &iAcquireFirst;
+ }
+
+
+CIkev2Expire** CIkev2Negotiation::GetExpireQue()
+ {
+ return &iExpireFirst;
+ }
+
+
+TBool CIkev2Negotiation::RequestsPending()
+ {
+ return (iAcquireFirst || iExpireFirst);
+ }
+
+
+void CIkev2Negotiation::SetNotifyCode(TInt aMsgType)
+ {
+ if (iNotifyCode == 0)
+ iNotifyCode = aMsgType;
+ }
+
+
+TInt CIkev2Negotiation::GetNotifyCode()
+ {
+ return iNotifyCode;
+ }
+
+
+void CIkev2Negotiation::StoreNotifyData32(TUint32 aData)
+ {
+ PUT32(iNotifyData, aData);
+ iNotifyDataLth = 4;
+ }
+
+
+void CIkev2Negotiation::StoreNotifyData16(TUint16 aData)
+ {
+ PUT16(iNotifyData, aData);
+ iNotifyDataLth = 2;
+ }
+
+
+TUint8* CIkev2Negotiation::NotifyData(TInt& aDataLth)
+ {
+ aDataLth = iNotifyDataLth;
+ if ( iNotifyDataLth )
+ return iNotifyData;
+ else return NULL;
+ }
+
+
+TInetAddr CIkev2Negotiation::GetLocalAddr() const
+ {
+ if ( iHdr.iVirtualAddr.IsUnspecified() )
+ {
+ return iHdr.iLocalAddr;
+ }
+ else
+ {
+ return iHdr.iVirtualAddr;
+ }
+ }
+