diff -r 000000000000 -r 33413c0669b9 vpnengine/ikev2lib/src/ikev2proposal.cpp --- /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 +#include +#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 + +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(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(&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(&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* aRefTrans, + CArrayFixFlat* 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(&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; +}