--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/ikev2lib/src/ikev2proposal.cpp Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,788 @@
+/*
+* Copyright (c) 2003-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 Proposal handling.
+*
+*/
+
+
+#include <e32math.h>
+#include <in_sock.h>
+#include "ikedebug.h"
+#include "ikev2proposal.h"
+#include "ikev2SAdata.h"
+#include "ikev2payloads.h"
+#include "ikemsgrec.h"
+#include "ikev2const.h"
+#include "ikev2plugin.h"
+#include "ikepolparser.h"
+#include "ikev2identity.h"
+#include "ikev2ipsecsadata.h"
+#include "ikev2Negotiation.h"
+#include <networking/pfkeyv2.h>
+
+HBufC8* Ikev2Proposal::FromPolicyToProposaL(TIkev2SAData& aIkeSaData,
+ const TDesC8& aRekeySpi,
+ TInt aDHGroupGuess,
+ TBool aRekey)
+{
+ //
+ // Build IKE SA proposal from IKE policy data
+ // Because proposal information is presented as "IKEv1"
+ // proposals in policy these are presented as sequence of
+ // proposals. All these transforms contains 4 different type transform
+ // payloads.
+ //
+ TProposalData* PropList = aIkeSaData.iIkeData->iPropList;
+
+ if ( !aRekey )
+ {
+ aIkeSaData.iEAPType = aIkeSaData.iIkeData->iEAPProtocol;
+ }
+
+ if (!PropList)
+ {
+ User::LeaveIfNull(PropList);
+ }
+
+ HBufC8* saData = HBufC8::NewL(512); //512 should be enough for all Proposals
+
+ TUint8 PropNum = 1;
+ TUint16 SaLth = 0;
+ TUint16 PropLth;
+ TUint16 TranLth;
+ TUint16 PRF;
+ TUint16 DHGroup;
+
+ TProposalIkev2* Proposal = TProposalIkev2::Cast(saData->Ptr());
+ TProposalIkev2* Next = Proposal;
+ TTransformIkev2* Transform;
+ TDataAttributes* Attributes;
+
+ while ( PropList )
+ {
+
+ Proposal = Next;
+ TPayloadIkev2::Cast(Proposal)->Init(); // Initialize Payload general header
+ TPayloadIkev2::Cast(Proposal)->SetNextPayload(IKEV2_PAYLOAD_PROP);
+ Proposal->SetNum(PropNum);
+ Proposal->SetProtocol(IKEV2_PROTOCOL);
+ if ( aRekey )
+ {
+ Proposal->SetSPISize(IKEV2_SPI_SIZE);
+ Mem::Copy(Proposal->SPI(), aRekeySpi.Ptr(), IKEV2_SPI_SIZE);
+ }
+ else Proposal->SetSPISize(0);
+ Proposal->SetNumTrans(4);
+ PropLth = (TUint16)Proposal->PropHdrLth();
+
+ Transform = Proposal->TransformPl();
+ TPayloadIkev2::Cast(Transform)->Init(); // Initialize Payload general header
+ TPayloadIkev2::Cast(Transform)->SetNextPayload(IKEV2_PAYLOAD_TRANS);
+ Transform->SetType(IKEV2_ENCR); // Encryption Algorithm transform (1)
+ Transform->SetReserved();
+ TranLth = (TUint16)Transform->Size();
+
+ switch ( PropList->iEncrAlg )
+ {
+ case IKE_PARSER_DES_CBC:
+ Transform->SetID(ENCR_DES);
+ break;
+ case IKE_PARSER_DES3_CBC:
+ Transform->SetID(ENCR_3DES);
+ break;
+ case IKE_PARSER_AES_CBC:
+ Transform->SetID(ENCR_AES_CBC);
+ //
+ // Add key length attribute to transform data
+ //
+ Transform->SetID(ENCR_AES_CBC);
+ Attributes = Transform->Attributes();
+ Attributes->SetType(IKEV2_ENCR_KEY_LTH);
+ Attributes->SetBasic();
+ if (PropList->iEncrKeyLth)
+ Attributes->SetValue((TUint16)PropList->iEncrKeyLth);
+ else Attributes->SetValue(128); //default AES key size
+ TranLth = (TUint16)(TranLth + Attributes->Size());
+ break;
+ default:
+ Transform->SetID(ENCR_3DES); // Use 3DES as default
+ break;
+ }
+ TPayloadIkev2::Cast(Transform)->SetLength(TranLth);
+ PropLth = (TUint16)(PropLth + TranLth);
+
+ Transform = (TTransformIkev2*)TPayloadIkev2::Cast(Transform)->Next();
+ TPayloadIkev2::Cast(Transform)->Init(); // Initialize Payload general header
+ TPayloadIkev2::Cast(Transform)->SetNextPayload(IKEV2_PAYLOAD_TRANS);
+ Transform->SetType(IKEV2_INTEG); // Integrity Algorithm (3)
+ Transform->SetReserved();
+ TranLth = (TUint16)Transform->Size();
+
+ switch ( PropList->iHashAlg )
+ {
+ case IKE_PARSER_MD5:
+ Transform->SetID(AUTH_HMAC_MD5_96);
+ PRF = IKE_PARSER_MD5;
+ break;
+ case IKE_PARSER_SHA1:
+ Transform->SetID(AUTH_HMAC_SHA1_96);
+ PRF = IKE_PARSER_SHA1;
+ break;
+ default:
+ Transform->SetID(AUTH_HMAC_SHA1_96);
+ PRF = IKE_PARSER_SHA1;
+ break;
+ }
+ TPayloadIkev2::Cast(Transform)->SetLength(TranLth);
+ PropLth = (TUint16)(PropLth + TranLth);
+
+ Transform = (TTransformIkev2*)TPayloadIkev2::Cast(Transform)->Next();
+ TPayloadIkev2::Cast(Transform)->Init(); // Initialize Payload general header
+ TPayloadIkev2::Cast(Transform)->SetNextPayload(IKEV2_PAYLOAD_TRANS);
+ Transform->SetType(IKEV2_PRF); // Pseudo-random Function (2)
+ Transform->SetReserved();
+ TranLth = (TUint16)Transform->Size();
+
+ if ( PropList->iPRF )
+ PRF = PropList->iPRF;
+ switch ( PRF )
+ {
+ case IKE_PARSER_MD5:
+ Transform->SetID(PRF_HMAC_MD5);
+ break;
+ case IKE_PARSER_SHA1:
+ Transform->SetID(PRF_HMAC_SHA1);
+ break;
+ default:
+ Transform->SetID(AUTH_HMAC_SHA1_96);
+ break;
+ }
+ TPayloadIkev2::Cast(Transform)->SetLength(TranLth);
+ PropLth = (TUint16)(PropLth + TranLth);
+
+
+ Transform = (TTransformIkev2*)TPayloadIkev2::Cast(Transform)->Next();
+ TPayloadIkev2::Cast(Transform)->Init(); // Initialize Payload general header
+ TPayloadIkev2::Cast(Transform)->SetNextPayload(IKEV2_PAYLOAD_NONE);
+ Transform->SetType(IKEV2_DH); // Diffie-Hellman Group (4)
+ Transform->SetReserved();
+ TranLth = (TUint16)Transform->Size();
+
+
+ DHGroup = (PropList->iGroupDesc == 0) ? aIkeSaData.iIkeData->iGroupDesc_II :
+ PropList->iGroupDesc;
+
+ DHGroup = Ikev2Proposal::GetDHGroup(DHGroup);
+ Transform->SetID(DHGroup);
+ TPayloadIkev2::Cast(Transform)->SetLength(TranLth);
+
+ if ( PropNum == aDHGroupGuess)
+ {
+ if (aIkeSaData.iDHGroup == 0)
+ aIkeSaData.iDHGroup = DHGroup; // Preferred group for initial KE payload
+ switch ( PropList->iAuthMeth )
+ {
+ case IKE_PARSER_DSS_SIG:
+ aIkeSaData.iAuthMethod = DSS_DIGITAL_SIGN;
+ break;
+
+ case IKE_PARSER_RSA_SIG:
+ case IKE_PARSER_RSA_REV_ENCR:
+ aIkeSaData.iAuthMethod = RSA_DIGITAL_SIGN;
+ break;
+
+ default:
+ aIkeSaData.iAuthMethod = PRESHARED_KEY;
+ break;
+
+ }
+ }
+
+ if ( aIkeSaData.iLifetime == 0 )
+ aIkeSaData.iLifetime = PropList->iLifetimeSec; // Init lifetime
+ else if ( PropList->iLifetimeSec && (aIkeSaData.iLifetime > PropList->iLifetimeSec) )
+ aIkeSaData.iLifetime = PropList->iLifetimeSec; // Take shorter time
+
+ PropLth = (TUint16)(PropLth + TranLth);
+ SaLth = (TUint16)(SaLth + PropLth);
+ TPayloadIkev2::Cast(Proposal)->SetLength(PropLth);
+
+ PropNum ++;
+ Next = (TProposalIkev2*)TPayloadIkev2::Cast(Proposal)->Next();
+ PropList = PropList->iNext;
+ }
+
+ if ( aIkeSaData.iLifetime == 0 )
+ aIkeSaData.iLifetime = IKEV2_DEF_LIFETIME;
+ TPayloadIkev2::Cast(Proposal)->SetNextPayload(IKEV2_PAYLOAD_NONE);
+
+ saData->Des().SetLength(SaLth);
+
+ return saData;
+
+}
+
+HBufC8* Ikev2Proposal::GetPSKFromPolicyL(CIkeData* aHostData)
+{
+ ASSERT(aHostData);
+ //
+ // Get Preshared Key from IKE policy and return in to caller in
+ // HBufc8.
+ //
+ HBufC8 *PSK = NULL;
+ if ( aHostData->iPresharedKey.iFormat == STRING_KEY )
+ {
+ PSK = HBufC8::NewL(aHostData->iPresharedKey.iKey.Length());
+ PSK->Des().Copy(aHostData->iPresharedKey.iKey);
+ }
+ else if ( aHostData->iPresharedKey.iFormat == HEX_KEY )
+ {
+ PSK = HBufC8::NewL(aHostData->iPresharedKey.iKey.Length() / 2);
+
+
+ for(TInt i = 0; i < aHostData->iPresharedKey.iKey.Length(); i += 2)
+ {
+ TPtrC hexByte(aHostData->iPresharedKey.iKey.Mid(i, 2));
+ TLex lex(hexByte);
+ TUint8 value;
+ User::LeaveIfError(lex.Val(value, EHex));
+
+ PSK->Des().Append(&value, 1);
+ }
+
+ }
+
+ return PSK;
+}
+
+TUint16 Ikev2Proposal::GetDHGroup(TInt aDHGroup)
+{
+ //
+ // Map DH group Enum value used in IKE policy to the real DH group
+ // transform type value used in IKEv2 negotiation
+ // If aDHGroup parameter is not defined mapping is done to
+ // iGroupDesc_II data member value in CIkeData
+ //
+ TUint16 DHTransId = 0;
+ switch ( aDHGroup )
+ {
+ case IKE_PARSER_MODP_768:
+ DHTransId = DH_GROUP_768;
+ break;
+ case IKE_PARSER_MODP_1024:
+ DHTransId = DH_GROUP_1024;
+ break;
+ case IKE_PARSER_MODP_1536:
+ DHTransId = DH_GROUP_1536;
+ break;
+ case IKE_PARSER_MODP_2048:
+ DHTransId = DH_GROUP_2048;
+ break;
+ default:
+ break;
+ }
+
+ return DHTransId;
+}
+
+HBufC8* Ikev2Proposal::BuildSaResponseL(TProposalIkev2* aAcceptedProp, CIkev2Payloads* aAcceptedTrans)
+{
+ ASSERT(aAcceptedProp && aAcceptedTrans);
+ HBufC8* SaRespBfr = HBufC8::NewL(256); //256 should be enough response
+
+ //
+ // Build SA response payload based on Transform payloads which are
+ // marked to be "SELECTED" in request proposal
+ //
+ TProposalIkev2* Proposal = TProposalIkev2::Cast(const_cast<TUint8*>(SaRespBfr->Ptr()));
+ TUint16 PropLth = (TUint16)aAcceptedProp->PropHdrLth();
+ Mem::Copy((TUint8*)Proposal, (TUint8*)aAcceptedProp, PropLth);
+
+ TTransformIkev2* Transform = Proposal->TransformPl();
+ TTransformIkev2* LastTrans = Transform;
+ TTransformIkev2* AccTransform;
+ TUint8 NbrOfTransforms = 0;
+ TInt TranCount = aAcceptedTrans->iTrans->Count();
+ for ( TInt i = 0; i < TranCount; ++i )
+ {
+ AccTransform = (TTransformIkev2*)aAcceptedTrans->iTrans->At(i);
+ if ( AccTransform->IsSelected() )
+ {
+ NbrOfTransforms ++;
+ Mem::Copy((TUint8*)Transform, (TUint8*)AccTransform, TPayloadIkev2::Cast(AccTransform)->GetLength());
+ Transform->NotSelected(); // Reset selected bit !
+ PropLth = (TUint16)(PropLth + TPayloadIkev2::Cast(AccTransform)->GetLength());
+ TPayloadIkev2::Cast(Transform)->SetNextPayload(IKEV2_PAYLOAD_TRANS);
+ LastTrans = Transform;
+ Transform = (TTransformIkev2*)TPayloadIkev2::Cast(Transform)->Next();
+ }
+ }
+ TPayloadIkev2::Cast(LastTrans)->SetNextPayload(IKEV2_PAYLOAD_NONE);
+ TPayloadIkev2::Cast(Proposal)->SetNextPayload(IKEV2_PAYLOAD_NONE);
+ TPayloadIkev2::Cast(Proposal)->SetLength(PropLth);
+ Proposal->SetNumTrans(NbrOfTransforms);
+ SaRespBfr->Des().SetLength(PropLth);
+
+ return SaRespBfr;
+}
+
+
+TBool Ikev2Proposal::GetSelectedProposalData(TIkev2SAData& aIkev2SaData,
+ TIkeV2IpsecSAData& aChildSaData,
+ const CIkev2Payloads& aAcceptedProp,
+ const TProposalIkev2& aProp)
+{
+ //
+ // Get IKE SA algorithm information from Transform payload which are
+ // marked to be "SELECTED"
+ //
+ TTransformIkev2* Transform;
+ TDataAttributes* Attribute;
+ TUint16 EncrAlg;
+ TInt KeyLth;
+ TUint8 ExistingTypes = 0;
+ TUint8 RequiredTypes;
+ TUint8 Protocol = aProp.GetProtocol();
+ switch ( Protocol )
+ {
+ case IKEV2_IPSEC_AH:
+ {
+ RequiredTypes = (1 << IKEV2_INTEG);
+ aChildSaData.iSaType = SADB_SATYPE_AH;
+ TUint32 spi = 0;
+ aProp.GetIpsecSPI(&spi);
+ aChildSaData.iSPI_Out = TPtrC8(reinterpret_cast<TUint8*>(&spi), sizeof(spi));
+ }
+ break;
+ case IKEV2_IPSEC_ESP:
+ {
+ RequiredTypes = (1 << IKEV2_ENCR);
+ aChildSaData.iSaType = SADB_SATYPE_ESP;
+ TUint32 spi = 0;
+ aProp.GetIpsecSPI(&spi);
+ aChildSaData.iSPI_Out = TPtrC8(reinterpret_cast<TUint8*>(&spi), sizeof(spi));
+ }
+ break;
+ default: //IKEV2_PROTOCOL:
+ RequiredTypes = ((1 << IKEV2_ENCR) | (1 << IKEV2_PRF) | (1 << IKEV2_INTEG) | (1 << IKEV2_DH));
+ break;
+ }
+
+ TInt TranCount = aAcceptedProp.iTrans->Count();
+
+ for ( TInt i = 0; i < TranCount; ++i )
+ {
+ Transform = (TTransformIkev2*)aAcceptedProp.iTrans->At(i);
+ if ( Transform->IsSelected() )
+ {
+ Transform->NotSelected(); // Reset private "selected" bit
+ switch ( Transform->GetType() )
+ {
+ case IKEV2_ENCR:
+ ExistingTypes |= (1 << IKEV2_ENCR);
+ EncrAlg = Transform->GetID();
+ if ( Protocol == IKEV2_PROTOCOL )
+ aIkev2SaData.iEncrAlg = EncrAlg;
+ else aChildSaData.iEncrAlg = EncrAlg;
+ if ( EncrAlg == ENCR_AES_CBC )
+ {
+ //
+ // Get encryption key length from attributes
+ // (or use default key length 128 bit)
+ //
+ if ( TPayloadIkev2::Cast(Transform)->GetLength() > Transform->Size() )
+ {
+ Attribute = Transform->Attributes();
+ KeyLth = (Attribute->GetValue() >> 3); // byte length
+ }
+ else KeyLth = 16; // default: 16 bytes = 128 bits
+ if ( Protocol == IKEV2_PROTOCOL )
+ aIkev2SaData.iCipherKeyLth = KeyLth;
+ else aChildSaData.iCipherKeyLth = KeyLth;
+ }
+ break;
+
+ case IKEV2_PRF:
+ ExistingTypes |= (1 << IKEV2_PRF);
+ if ( Protocol == IKEV2_PROTOCOL )
+ aIkev2SaData.iPRFAlg = Transform->GetID();
+ break;
+
+ case IKEV2_INTEG:
+ ExistingTypes |= (1 << IKEV2_INTEG);
+ if ( Protocol == IKEV2_PROTOCOL )
+ aIkev2SaData.iIntegAlg = Transform->GetID();
+ else aChildSaData.iIntegAlg = Transform->GetID();
+ break;
+
+ case IKEV2_DH:
+ ExistingTypes |= (1 << IKEV2_DH);
+ if ( Protocol == IKEV2_PROTOCOL )
+ aIkev2SaData.iDHGroup = Transform->GetID();
+ break;
+
+ case IKEV2_ESN:
+ ExistingTypes |= (1 << IKEV2_ESN);
+ if ( Protocol != IKEV2_PROTOCOL )
+ aChildSaData.iESN = (TUint8)Transform->GetID();
+ break;
+
+ default:
+ break;
+
+ }
+ }
+
+ }
+
+ return ((RequiredTypes & ExistingTypes) == RequiredTypes);
+}
+
+TBool Ikev2Proposal::VerifySaResponseL(TIkev2SAData& aIkeSaData,
+ TIkeV2IpsecSAData& aIpsecSaData,
+ const TDesC8& aReferenceSaData,
+ const CIkev2Payloads& aRespProp)
+{
+ //
+ // Verify content of an IKE SA response to proposed IKE SA transform
+ // list. The IKE SA proposal selected by peer MUST contain one
+ // proposal and transform selected from our SA proposal
+ //
+ if ( aRespProp.iProps->Count() != 1 )
+ return EFalse;
+
+ TBool Status = EFalse;
+ TPtrC8 unprocessedReferenceSaData(aReferenceSaData);
+
+ while(!Status && unprocessedReferenceSaData.Length() > 0)
+ {
+ TPayloadIkev2* referenceProposal = TPayloadIkev2::Cast(unprocessedReferenceSaData.Ptr());
+ CIkev2Payloads* OwnProp = CIkev2Payloads::NewL(referenceProposal, IKEV2_PAYLOAD_PROP, aIkeSaData);
+ CleanupStack::PushL(OwnProp);
+
+ //Something is seriously wrong, if we can't parse our own reference data
+ __ASSERT_DEBUG(OwnProp->Status() == KErrNone, User::Invariant());
+
+ TProposalIkev2* Prop = (TProposalIkev2*)aRespProp.iProps->At(0);
+ Status = Ikev2Proposal::VerifyProposaL(OwnProp, Prop, aIkeSaData);
+ if ( Status )
+ {
+ Status = Ikev2Proposal::GetSelectedProposalData(aIkeSaData, aIpsecSaData, aRespProp, *Prop);
+ }
+ CleanupStack::PopAndDestroy(OwnProp);
+ unprocessedReferenceSaData.Set(unprocessedReferenceSaData.Mid(referenceProposal->GetLength()));
+ }
+
+ return Status;
+}
+
+TBool Ikev2Proposal::VerifySaRequestAndGetProposedSaBufferL(TIkev2SAData& aIkeSaData,
+ TIkeV2IpsecSAData& aIpsecSaData,
+ const TDesC8& aReferenceSaData,
+ const CIkev2Payloads& aProposed,
+ HBufC8*& aProposedSaBuffer)
+{
+ __ASSERT_DEBUG(aReferenceSaData.Length() > 0, User::Invariant());
+
+
+ //
+ // Verify content of an IKE SA request against a reference
+ // proposals built according to the local policy.
+ //
+ if ( !aProposed.iSa )
+ return EFalse;
+
+ TBool Status = EFalse;
+ TPtrC8 unprocessedReferenceSaData(aReferenceSaData);
+ while (!Status && unprocessedReferenceSaData.Length() > 0)
+ {
+ TPayloadIkev2* referenceSa = TPayloadIkev2::Cast(unprocessedReferenceSaData.Ptr());
+ unprocessedReferenceSaData.Set(unprocessedReferenceSaData.Mid(referenceSa->GetLength()));
+ CIkev2Payloads* OwnProp = CIkev2Payloads::NewL(referenceSa, IKEV2_PAYLOAD_PROP, aIkeSaData);
+ //If we can't parse our own reference proposal something is seriously wrong.
+ __ASSERT_DEBUG(OwnProp->Status() == KErrNone, User::Invariant());
+ CleanupStack::PushL(OwnProp);
+
+
+ CIkev2Payloads* PeerProp = CIkev2Payloads::NewL((TPayloadIkev2*)aProposed.iSa, IKEV2_PAYLOAD_SA, aIkeSaData);
+ CleanupStack::PushL(PeerProp);
+ Status = (PeerProp->Status() == KErrNone);
+ if ( Status )
+ {
+ Status = EFalse;
+ TInt PropCount = PeerProp->iProps->Count();
+ for ( TInt i = 0; i < PropCount; ++i )
+ {
+ TProposalIkev2* Prop = (TProposalIkev2*)PeerProp->iProps->At(i);
+ Status = Ikev2Proposal::VerifyProposaL(OwnProp, Prop, aIkeSaData);
+ if ( Status )
+ {
+ //
+ // Build SA response payload and pick up algorithm
+ // information into negotiation object
+ //
+
+ HBufC8* SaRespBfr = NULL;
+ TRAPD(err, SaRespBfr = Ikev2Proposal::BuildSaResponseL(Prop, PeerProp));
+ if (err == KErrNone)
+ {
+ aProposedSaBuffer = SaRespBfr;
+ Status = Ikev2Proposal::GetSelectedProposalData(aIkeSaData, aIpsecSaData, *PeerProp, *Prop);
+ }
+ else
+ {
+ Status = EFalse;
+ }
+ break;
+ }
+ }
+ }
+ CleanupStack::PopAndDestroy(PeerProp);
+ CleanupStack::PopAndDestroy(OwnProp);
+ }
+ return Status;
+}
+
+TBool Ikev2Proposal::IkeSaRekey(CIkev2Payloads* aIkeMsg)
+{
+ ASSERT(aIkeMsg);
+ //
+ // Check is the current IKE message an IKE SA rekey request
+ // Should be format: HDR(A,B), SK { SA, Ni, KEi }
+ // where proposal protcol should be IKEV2_PROTOCOL
+ //
+ TBool Status = EFalse;
+ if ( aIkeMsg->iProps->Count() && !aIkeMsg->iTsI && !aIkeMsg->iTsR )
+ {
+ TProposalIkev2* Prop = (TProposalIkev2*)aIkeMsg->iProps->At(0);
+ Status = (Prop->GetProtocol() == IKEV2_PROTOCOL);
+ }
+ return Status;
+}
+
+TBool Ikev2Proposal::GetRekeySpi(CIkev2Payloads* aIkeMsg, TIkeSPI& aSPI)
+{
+ ASSERT(aIkeMsg);
+ //
+ // Get remote ends IKE SPI from the first Proposal of IKE message
+ //
+ TBool Status = EFalse;
+ if ( aIkeMsg->iProps->Count() )
+ {
+ TProposalIkev2* Proposal = (TProposalIkev2*)aIkeMsg->iProps->At(0);
+ if ( Proposal->GetSPISize() == IKEV2_SPI_SIZE )
+ {
+ Mem::Copy( (TUint8*)aSPI.Ptr(), Proposal->SPI(), IKEV2_SPI_SIZE);
+ Status = ETrue;
+ }
+ }
+ return Status;
+}
+
+void Ikev2Proposal::ChangeSpiInProposal(HBufC8* aSaBfr, TIkeSPI& aSPI)
+{
+ ASSERT(aSaBfr);
+ TProposalIkev2* Proposal = TProposalIkev2::Cast(aSaBfr->Ptr());
+ Mem::Copy(Proposal->SPI(), (TUint8*)aSPI.Ptr(), IKEV2_SPI_SIZE);
+}
+
+TBool Ikev2Proposal::VerifyProposaL(CIkev2Payloads* aReference, TProposalIkev2* aProposal, TIkev2SAData& aIkev2SaData)
+{
+ //
+ // Find a matching proposal for "candidate" from reference payload
+ // chain. This implementation does not support the AND of sequental
+ // proposals (for example proposal which defines (ESP and AH))
+ //
+ if ( !aProposal || !aReference || (aReference->iProps->Count() == 0) )
+ return EFalse;
+
+ CIkev2Payloads* Prop = CIkev2Payloads::NewL(TPayloadIkev2::Cast(aProposal), IKEV2_PAYLOAD_PROP, aIkev2SaData);
+ CleanupStack::PushL(Prop);
+ TBool Status = ( Prop->Status() == KErrNone );
+ if ( Status )
+ {
+
+ Status = EFalse;
+ TInt PropCount = aReference->iProps->Count();
+ TProposalIkev2* RefProp;
+
+ for ( TInt i = 0; i < PropCount; ++i )
+ {
+ RefProp = (TProposalIkev2*)aReference->iProps->At(i);
+ if ( !aReference->ParsePayloadL(TPayloadIkev2::Cast(RefProp), IKEV2_PAYLOAD_PROP ))// Transforms from Proposal
+ break;
+ if ( aReference->iTrans->Count() == 0 )
+ break;
+ if ( RefProp->GetProtocol() != aProposal->GetProtocol() )
+ continue;
+ //
+ // Compare transforms within proposals
+ //
+ Status = Ikev2Proposal::CompareTransforms(aReference->iTrans, Prop->iTrans);
+ if ( Status )
+ break; // Match found
+ }
+ }
+ CleanupStack::PopAndDestroy(Prop);
+
+ return Status;
+}
+
+TBool Ikev2Proposal::CompareTransforms(CArrayFixFlat<TTransformIkev2*>* aRefTrans,
+ CArrayFixFlat<TTransformIkev2*>* aTrans)
+{
+ ASSERT(aTrans && aRefTrans);
+ //
+ // "Select" matching transforms from transform list (aTrans).
+ // Transforms from aTrans array is marked "SELECTED" if there is a
+ // matching transform in aRefTrans array for existing transform
+ // types.
+ //
+ TUint8 TransType;
+ TTransformIkev2* Trans;
+ TTransformIkev2* RefTrans;
+ TDataAttributes* Attribute;
+
+ TInt TranCount2;
+ TUint16 Lth;
+ TUint8 ExistingTypes = 0;
+ TUint8 MatchingTypes = 0;
+ TInt TranCount = aTrans->Count();
+ TInt i;
+
+ for ( i = 0; i < TranCount; ++i )
+ {
+ Trans = aTrans->At(i);
+ TransType = Trans->GetType();
+ if ( (TransType < IKEV2_ENCR ) || (TransType > IKEV2_ESN) )
+ break; // Unknown transform type (error)
+
+ ExistingTypes |= (1 << TransType);
+ TranCount2 = aRefTrans->Count();
+
+ for ( TInt j = 0; j < TranCount2; ++j )
+ {
+ RefTrans = aRefTrans->At(j);
+
+ if ( (TransType != RefTrans->GetType()) || (Trans->GetID() != RefTrans->GetID()) )
+ continue;
+ //
+ // Matching transform type and ID. Check is there any
+ // attributes in transform (in this phase only IKEV2_ENCR
+ // transform type can contain an attribute AES key length)
+ //
+ Lth = TPayloadIkev2::Cast(Trans)->GetLength();
+ if ( Lth >= Trans->Size() )
+ {
+ if (( TransType == IKEV2_ENCR ) && (Trans->GetID() == ENCR_AES_CBC) )
+ {
+ TUint16 KeyLth = 128;
+ TUint16 RefKeyLth = 128;
+ if ( Lth > Trans->Size() )
+ {
+ Attribute = Trans->Attributes();
+ Lth = (TUint16)(Lth - Trans->Size());
+ if ( (Lth == Attribute->Size()) && Attribute->IsBasic() && (Attribute->GetType() == IKEV2_ENCR_KEY_LTH) )
+ KeyLth = Attribute->GetValue();
+ }
+ if ( TPayloadIkev2::Cast(RefTrans)->GetLength() > Trans->Size() )
+ {
+ Attribute = RefTrans->Attributes();
+ RefKeyLth = Attribute->GetValue();
+ }
+ if ( KeyLth != RefKeyLth )
+ continue; // Not matching attribute
+ }
+ }
+ //
+ // Mark current transform "SELECTED"
+ //
+ if ( (MatchingTypes & (1 << TransType) ) == 0 )
+ {
+ Trans->Selected();
+ MatchingTypes |= (1 << TransType);
+ }
+ break;
+ }
+ }
+
+ TBool Status = (ExistingTypes == MatchingTypes);
+ if ( !Status )
+ {
+ //
+ // No match ! Reset "SELECTED" indicator from transforms
+ //
+ i = 0;
+ while ( i < TranCount )
+ {
+ Trans = (TTransformIkev2*)aTrans->At(i);
+ Trans->NotSelected();
+ i ++;
+ }
+ }
+
+ return Status;
+
+}
+
+CIkeV2Identity* Ikev2Proposal::GetRemoteIdentityL(CIkeData* aHostData)
+{
+ ASSERT(aHostData);
+ CIkeV2Identity* identity = NULL;
+
+ if ( aHostData->iRemoteIdentity )
+ {
+ TPtrC16 idData = aHostData->iRemoteIdentity->GetData();
+ TUint8 idType = aHostData->iRemoteIdType;
+ if ( (idType == ID_IPV4_ADDR) || (idType == ID_IPV6_ADDR) )
+ {
+ //
+ // If configured remote id type is either IPv4- or IPv6 address
+ // convert ASCII format address data into hexa octet string IP
+ // address format: IPv4 address shall be represented as four
+ // octet string and Ipv6 address as 16 octet string
+ //
+ TInetAddr ipAddr;
+ if ( ipAddr.Input(idData) == KErrNone )
+ {
+ if ( idType == ID_IPV4_ADDR )
+ {
+ TUint32 ipv4 = ByteOrder::Swap32(ipAddr.Address());
+ TPtrC8 ipv4Ptr(reinterpret_cast<TUint8*>(&ipv4), sizeof(ipv4));
+ identity = CIkeV2Identity::NewL(idType, ipv4Ptr);
+ }
+ else
+ {
+ TPtrC8 IPv6Ptr(&ipAddr.Ip6Address().u.iAddr8[0], 16);
+ identity = CIkeV2Identity::NewL(idType, IPv6Ptr);
+ }
+ }
+ }
+ else
+ {
+ if ( (idType != ID_FQDN) && (idType != ID_RFC822_ADDR) )
+ {
+ idType = ID_FQDN; // Default
+ }
+
+ HBufC8* id = HBufC8::NewLC(idData.Length());
+ TPtr8 idPtr(id->Des());
+ idPtr.Copy(idData);
+ identity = CIkeV2Identity::NewL(idType, *id);
+ CleanupStack::PopAndDestroy(id);
+ }
+ }
+
+ return identity;
+}