diff -r 000000000000 -r 33413c0669b9 vpnengine/ikev2lib/src/ikev2message.cpp --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/vpnengine/ikev2lib/src/ikev2message.cpp Thu Dec 17 09:14:51 2009 +0200 @@ -0,0 +1,1293 @@ +/* +* Copyright (c) 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: +* +*/ + +#include +#include +#include + +#include "ikev2message.h" +#include "ikev2const.h" +#include "ikecalist.h" +#include "ikecaelem.h" +#include "ikev2trafficselector.h" +#include "ikecrypto.h" +#include "ikev2identity.h" +#include "ikemsgheader.h" +#include "ikedebug.h" + +static const TUint8 KMessageIdFieldOffset = 20; + +static const TUint KIkePayloadGenericHeaderLength = 4; +static const TUint8 KLengthFieldOffset = 2; + +static const TUint32 KSha1Length = 20; +static const TUint32 KCertReqHeaderLength = 5; +static const TUint32 KCertHeaderLength = 5; +static const TUint32 KSaHeaderLength = 4; +static const TUint32 KKeHeaderLength = 8; +static const TUint32 KNonceHeaderLength = 4; +static const TUint32 KAuthHeaderLength = 8; +static const TUint32 KNotifyHeaderLength = 8; +static const TUint32 KConfigurationHeaderLength = 8; +static const TUint32 KVendorIdHeaderLength = 4; +static const TUint32 KDeleteHeaderLength = 8; +static const TUint32 KEapHeaderLength = 4; +static const TUint32 KTsHeaderLength = 8; +static const TUint32 KEncryptedHeaderLength = 4; + +_LIT8(KNonEspMarker, "\0\0\0\0"); + +CIkeV2Payload::CIkeV2Payload(TUint8 aPayloadType) +:iPayloadType(aPayloadType) + { + } + + +CIkeV2Payload::~CIkeV2Payload() + { + delete iPayloadData; + } + +TUint8 CIkeV2Payload::PayloadType() const + { + return iPayloadType; + } + + +TUint8 CIkeV2Payload::NextPayload() const + { + __ASSERT_DEBUG(iPayloadData->Length() >= KIkePayloadGenericHeaderLength, + User::Invariant()); + + return (*iPayloadData)[0]; + } + + +void CIkeV2Payload::SetNextPayload(TUint8 aNextPayload) + { + __ASSERT_DEBUG(iPayloadData->Length() >= KIkePayloadGenericHeaderLength, + User::Invariant()); + + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr[0] = aNextPayload; + } + + +TUint16 CIkeV2Payload::PayloadLength() const + { + __ASSERT_DEBUG(iPayloadData->Length() >= KIkePayloadGenericHeaderLength, + User::Invariant()); + + return BigEndian::Get16(iPayloadData->Ptr() + KLengthFieldOffset); + } + + +void CIkeV2Payload::SetPayloadLength(TUint16 aLength) + { + __ASSERT_DEBUG(iPayloadData->Length() >= KIkePayloadGenericHeaderLength, + User::Invariant()); + const TUint KLengthPosition = 2; + + BigEndian::Put16(reinterpret_cast(&aLength), aLength); + TPtrC8 length(reinterpret_cast(&aLength), sizeof(aLength)); + + TPtr8 lengthPtr(iPayloadData->Des().MidTPtr(KLengthPosition, + length.Length())); + lengthPtr = length; + } + +TPtrC8 CIkeV2Payload::PayloadData() const + { + return TPtrC8(*iPayloadData); + } + + +CIkevV2CertReqPayload* CIkevV2CertReqPayload::NewL(const CIkeCaList& aCaList) + { + CIkevV2CertReqPayload* self = new (ELeave) CIkevV2CertReqPayload; + CleanupStack::PushL(self); + self->ConstructL(aCaList); + CleanupStack::Pop(self); + + return self; + } + + + +CIkevV2CertReqPayload::CIkevV2CertReqPayload() +:CIkeV2Payload(IKEV2_PAYLOAD_CR) + { + } + + +void CIkevV2CertReqPayload::ConstructL(const CIkeCaList& aCaList) + { + __ASSERT_DEBUG(aCaList.Count() > 0, User::Invariant()); + TUint16 length = (aCaList.Count() * KSha1Length) + KCertReqHeaderLength; + + iPayloadData = HBufC8::NewL(length); + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength); + payloadDataPtr.FillZ(); + + SetPayloadLength(length); + + TUint8 encoding = X509_CERTIFICATE_SIGN; + TPtrC8 encodingPtr(&encoding, sizeof(encoding)); + payloadDataPtr.Append(encodingPtr); + + for (TUint i = 0; i < aCaList.Count(); ++i) + { + payloadDataPtr.Append(aCaList[i]->KeyHash()); + } + + __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant()); + } + + +CIkevV2CertPayload* CIkevV2CertPayload::NewL(const TDesC8& aCertData) + { + CIkevV2CertPayload* self = new (ELeave) CIkevV2CertPayload; + CleanupStack::PushL(self); + self->ConstructL(aCertData); + CleanupStack::Pop(self); + + return self; + } + + +CIkevV2CertPayload::CIkevV2CertPayload() +:CIkeV2Payload(IKEV2_PAYLOAD_CERT) + { + + } + + +void CIkevV2CertPayload::ConstructL(const TDesC8& aCertData) + { + TUint16 length = aCertData.Length() + KCertHeaderLength; + + iPayloadData = HBufC8::NewL(length); + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength); + payloadDataPtr.FillZ(); + + SetPayloadLength(length); + + TUint8 encoding = X509_CERTIFICATE_SIGN; + TPtrC8 encodingPtr(&encoding, sizeof(encoding)); + payloadDataPtr.Append(encodingPtr); + payloadDataPtr.Append(aCertData); + + __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant()); + } + + +CIkevV2SaPayload* CIkevV2SaPayload::NewL(const TDesC8& aSaData) + { + CIkevV2SaPayload* self = new (ELeave) CIkevV2SaPayload; + CleanupStack::PushL(self); + self->ConstructL(aSaData); + CleanupStack::Pop(self); + + return self; + } + + +CIkevV2SaPayload::CIkevV2SaPayload() +:CIkeV2Payload(IKEV2_PAYLOAD_SA) + { + } + + +void CIkevV2SaPayload::ConstructL(const TDesC8& aSaData) + { + TUint16 length = aSaData.Length() + KSaHeaderLength; + + iPayloadData = HBufC8::NewL(length); + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength); + payloadDataPtr.FillZ(); + + SetPayloadLength(length); + + payloadDataPtr.Append(aSaData); + + __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant()); + } + + +CIkevV2KePayload* CIkevV2KePayload::NewL(TUint16 aDHGroup, const TDesC8& aKeData) + { + CIkevV2KePayload* self = new (ELeave) CIkevV2KePayload; + CleanupStack::PushL(self); + self->ConstructL(aDHGroup, aKeData); + CleanupStack::Pop(self); + + return self; + } + + +CIkevV2KePayload::CIkevV2KePayload() +:CIkeV2Payload(IKEV2_PAYLOAD_KE) + { + } + +void CIkevV2KePayload::ConstructL(TUint16 aDHGroup, const TDesC8& aKeData) + { + static const TUint8 KReservedFieldLength = 2; + + TUint16 length = aKeData.Length() + KKeHeaderLength; + + iPayloadData = HBufC8::NewL(length); + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength); + payloadDataPtr.FillZ(); + + SetPayloadLength(length); + + BigEndian::Put16(reinterpret_cast(&aDHGroup), aDHGroup); + TPtrC8 dhGroupPtr(reinterpret_cast(&aDHGroup), sizeof(aDHGroup)); + payloadDataPtr.Append(dhGroupPtr); + + //Leave reserved bytes zero + payloadDataPtr.SetLength(payloadDataPtr.Length() + KReservedFieldLength); + TPtr8 reservedBytes = payloadDataPtr.RightTPtr(KReservedFieldLength); + reservedBytes.FillZ(); + + payloadDataPtr.Append(aKeData); + + __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant()); + } + + +CIkevV2NoncePayload* CIkevV2NoncePayload::NewL(const TDesC8& aNonceData) + { + CIkevV2NoncePayload* self = new (ELeave) CIkevV2NoncePayload; + CleanupStack::PushL(self); + self->ConstructL(aNonceData); + CleanupStack::Pop(self); + + return self; + } + + +CIkevV2NoncePayload::CIkevV2NoncePayload() +:CIkeV2Payload(IKEV2_PAYLOAD_NONCE) + { + } + + +void CIkevV2NoncePayload::ConstructL(const TDesC8& aNonceData) + { + TUint16 length = aNonceData.Length() + KNonceHeaderLength; + + iPayloadData = HBufC8::NewL(length); + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength); + payloadDataPtr.FillZ(); + + SetPayloadLength(length); + + payloadDataPtr.Append(aNonceData); + + __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant()); + } + + +CIkevV2IdPayload::CIkevV2IdPayload(TUint8 aPayloadType) +:CIkeV2Payload(aPayloadType) + { + } + +void CIkevV2IdPayload::ConstructL(const CIkeV2Identity& aIdentity) + { + TPtrC8 idPayloadData = aIdentity.PayloadData(); + TUint32 length = idPayloadData.Length() + KIkePayloadGenericHeaderLength; + + iPayloadData = HBufC8::NewL(length); + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength); + payloadDataPtr.FillZ(); + + SetPayloadLength(length); + + payloadDataPtr.Append(idPayloadData); + + __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant()); + } + + +CIkevV2IdiPayload* CIkevV2IdiPayload::NewL(const CIkeV2Identity& aIdentity) + { + CIkevV2IdiPayload* self = new (ELeave) CIkevV2IdiPayload; + CleanupStack::PushL(self); + self->ConstructL(aIdentity); + CleanupStack::Pop(self); + return self; + } + + +CIkevV2IdiPayload::CIkevV2IdiPayload() +:CIkevV2IdPayload(IKEV2_PAYLOAD_ID_I) + { + } + + +CIkevV2IdrPayload* CIkevV2IdrPayload::NewL(const CIkeV2Identity& aIdentity) + { + CIkevV2IdrPayload* self = new (ELeave) CIkevV2IdrPayload; + CleanupStack::PushL(self); + self->ConstructL(aIdentity); + CleanupStack::Pop(self); + return self; + } + + +CIkevV2IdrPayload::CIkevV2IdrPayload() +:CIkevV2IdPayload(IKEV2_PAYLOAD_ID_R) + { + } + + +CIkeV2AuthPayload* CIkeV2AuthPayload::NewL(TUint8 aAuthMethod, const TDesC8& aAuthData) + { + CIkeV2AuthPayload* self = new (ELeave) CIkeV2AuthPayload; + CleanupStack::PushL(self); + self->ConstructL(aAuthMethod, aAuthData); + CleanupStack::Pop(self); + + return self; + } + + +CIkeV2AuthPayload::CIkeV2AuthPayload() +:CIkeV2Payload(IKEV2_PAYLOAD_AUTH) + { + } + + +void CIkeV2AuthPayload::ConstructL(TUint8 aAuthMethod, const TDesC8& aAuthData) + { + static const TUint8 KReservedFieldLength = 3; + + TUint32 length = aAuthData.Length() + KAuthHeaderLength; + + iPayloadData = HBufC8::NewL(length); + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength); + payloadDataPtr.FillZ(); + + SetPayloadLength(length); + + TPtrC8 authTypePtr(&aAuthMethod, sizeof(aAuthMethod)); + payloadDataPtr.Append(authTypePtr); + //Leave reserved bytes zero + payloadDataPtr.SetLength(payloadDataPtr.Length() + KReservedFieldLength); + TPtr8 reservedField = payloadDataPtr.RightTPtr(KReservedFieldLength); + reservedField.FillZ(); + + payloadDataPtr.Append(aAuthData); + + __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant()); + } + + +CIkeV2NotifyPayload* CIkeV2NotifyPayload::NewL(TUint8 aProtocolId, + const TDesC8& aSpi, + TUint16 aNotifyType, + const TDesC8& aNotifyData) + { + CIkeV2NotifyPayload* self = new (ELeave) CIkeV2NotifyPayload; + CleanupStack::PushL(self); + self->ConstructL(aProtocolId, aSpi, aNotifyType, aNotifyData); + CleanupStack::Pop(self); + + return self; + } + + +CIkeV2NotifyPayload::CIkeV2NotifyPayload() +:CIkeV2Payload(IKEV2_PAYLOAD_NOTIF) + { + } + + +void CIkeV2NotifyPayload::ConstructL(TUint8 aProtocolId, + const TDesC8& aSpi, + TUint16 aNotifyType, + const TDesC8& aNotifyData) + { + TUint32 length = aSpi.Length() + aNotifyData.Length() + KNotifyHeaderLength; + + iPayloadData = HBufC8::NewL(length); + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength); + payloadDataPtr.FillZ(); + + SetPayloadLength(length); + + TPtrC8 protocolIdPtr(&aProtocolId, sizeof(aProtocolId)); + TUint8 spiSize = aSpi.Length(); + TPtrC8 spiSizePtr(&spiSize, sizeof(spiSize)); + + BigEndian::Put16(reinterpret_cast(&aNotifyType), aNotifyType); + TPtrC8 notifyTypePtr(reinterpret_cast(&aNotifyType), sizeof(aNotifyType)); + + + payloadDataPtr.Append(protocolIdPtr); + payloadDataPtr.Append(spiSizePtr); + payloadDataPtr.Append(notifyTypePtr); + payloadDataPtr.Append(aSpi); + payloadDataPtr.Append(aNotifyData); + + __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant()); + } + + +CIkeV2ConfigurationPayload* CIkeV2ConfigurationPayload::NewL(TUint8 aCfgType, + const TDesC8& aConfigurationData) + { + CIkeV2ConfigurationPayload* self = new (ELeave) CIkeV2ConfigurationPayload; + CleanupStack::PushL(self); + self->ConstructL(aCfgType, aConfigurationData); + CleanupStack::Pop(self); + + return self; + } + + +CIkeV2ConfigurationPayload::CIkeV2ConfigurationPayload() +: CIkeV2Payload(IKEV2_PAYLOAD_CONFIG) + { + } + + +void CIkeV2ConfigurationPayload::ConstructL(TUint8 aCfgType, + const TDesC8& aConfigurationData) + { + static const TUint8 KReservedFieldLength = 3; + + TUint32 length = aConfigurationData.Length() + KConfigurationHeaderLength; + + iPayloadData = HBufC8::NewL(length); + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength); + payloadDataPtr.FillZ(); + + SetPayloadLength(length); + + TPtrC8 cfgTypePtr(reinterpret_cast(&aCfgType), sizeof(aCfgType)); + payloadDataPtr.Append(cfgTypePtr); + + //Leave reserved bytes zero + payloadDataPtr.SetLength(payloadDataPtr.Length() + KReservedFieldLength); + TPtr8 reservedField = payloadDataPtr.RightTPtr(KReservedFieldLength); + reservedField.FillZ(); + + payloadDataPtr.Append(aConfigurationData); + + __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant()); + } + + +CIkeV2VendorIdPayload* CIkeV2VendorIdPayload::NewL(const TDesC8& aVendorIdData) + { + CIkeV2VendorIdPayload* self = new (ELeave) CIkeV2VendorIdPayload; + CleanupStack::PushL(self); + self->ConstructL(aVendorIdData); + CleanupStack::Pop(self); + + return self; + } + + +CIkeV2VendorIdPayload::CIkeV2VendorIdPayload() +:CIkeV2Payload(IKEV2_PAYLOAD_VID) + { + } + + +void CIkeV2VendorIdPayload::ConstructL(const TDesC8& aVendorIdData) + { + TUint32 length = aVendorIdData.Length() + KVendorIdHeaderLength; + + iPayloadData = HBufC8::NewL(length); + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength); + payloadDataPtr.FillZ(); + + SetPayloadLength(length); + + payloadDataPtr.Append(aVendorIdData); + + __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant()); + } + + +CIkeV2DeletePayload* CIkeV2DeletePayload::NewL(TUint8 aProtocolId, + const CDesC8Array& aSpiList) + { + CIkeV2DeletePayload* self = new (ELeave) CIkeV2DeletePayload; + CleanupStack::PushL(self); + self->ConstructL(aProtocolId, aSpiList); + CleanupStack::Pop(self); + + return self; + } + + +CIkeV2DeletePayload::CIkeV2DeletePayload() +:CIkeV2Payload(IKEV2_PAYLOAD_DELETE) + { + } + + +void CIkeV2DeletePayload::ConstructL(TUint8 aProtocolId, const CDesC8Array& aSpiList) + { + TUint16 spiCount = aSpiList.Count(); + TUint8 spiLength = (spiCount > 0) ? aSpiList[0].Length() : 0; + TUint32 length = KDeleteHeaderLength + (spiCount * spiLength); + + iPayloadData = HBufC8::NewL(length); + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength); + payloadDataPtr.FillZ(); + + SetPayloadLength(length); + + TPtrC8 protocolIdPtr(&aProtocolId, sizeof(aProtocolId)); + TPtrC8 spiLengthPtr(&spiLength, sizeof(spiLength)); + + BigEndian::Put16(reinterpret_cast(&spiCount), spiCount); + TPtrC8 spiCountPtr(reinterpret_cast(&spiCount), sizeof(spiCount)); + + payloadDataPtr.Append(protocolIdPtr); + payloadDataPtr.Append(spiLengthPtr); + payloadDataPtr.Append(spiCountPtr); + + for (TInt i = 0; i < aSpiList.Count(); ++i) + { + const TDesC8& spi = aSpiList[i]; + __ASSERT_DEBUG(spi.Length() == spiLength, User::Invariant()); + payloadDataPtr.Append(spi); + } + + __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant()); + } + + +CIkeV2EapPayload* CIkeV2EapPayload::NewL(const TDesC8& aEapData) + { + CIkeV2EapPayload* self = new (ELeave) CIkeV2EapPayload; + CleanupStack::PushL(self); + self->ConstructL(aEapData); + CleanupStack::Pop(self); + + return self; + } + + +CIkeV2EapPayload::CIkeV2EapPayload() +:CIkeV2Payload(IKEV2_PAYLOAD_EAP) + { + } + + +void CIkeV2EapPayload::ConstructL(const TDesC8& aEapData) + { + TUint32 length = aEapData.Length() + KEapHeaderLength; + + iPayloadData = HBufC8::NewL(length); + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength); + payloadDataPtr.FillZ(); + SetPayloadLength(length); + + payloadDataPtr.Append(aEapData); + + __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant()); + } + + + +CIkeV2TsPayload::CIkeV2TsPayload(TUint aPayloadType) +:CIkeV2Payload(aPayloadType) + { + } + + +void CIkeV2TsPayload::ConstructL(const CArrayFix& aTsList) + { + //selector format: + // 1 2 3 + // 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! TS Type !IP Protocol ID*| Selector Length | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // | Start Port* | End Port* | + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ! + // ~ Starting Address* ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + // ! ! + // ~ Ending Address* ~ + // ! ! + // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + const TUint16 KIpv4SelectorLength = 2*4 + 2*4; //fixed selector header + 2*IPv4 address length + const TUint16 KIpv6SelectorLength = 2*4 + 2*16;//fixed selector header + 2*IPv6 address length + + TUint8 tsCount = aTsList.Count(); + __ASSERT_DEBUG(tsCount > 0, User::Invariant()); + + + TUint32 length = KTsHeaderLength; + + TUint i; + for (i = 0; i < aTsList.Count(); ++i) + { + if (aTsList[i].Type() == TS_IPV4_ADDR_RANGE) + { + length += KIpv4SelectorLength; //fixed selector header + 2*IPv4 address length + } + else + { + __ASSERT_DEBUG(aTsList[i].Type() == TS_IPV6_ADDR_RANGE, User::Invariant()); + length += KIpv6SelectorLength; //fixed selector header + 2*IPv6 address length + } + } + + iPayloadData = HBufC8::NewL(length); + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength); + payloadDataPtr.FillZ(); + + SetPayloadLength(length); + + const TPtrC8 tsCountPtr(&tsCount, sizeof(tsCount)); + payloadDataPtr.Append(tsCountPtr); + + _LIT(KReservedField, "\0\0\0"); + payloadDataPtr.Append(KReservedField); + + for (i = 0; i < aTsList.Count(); ++i) + { + TBuf8 selector; + selector.Zero(); + const TIkeV2TrafficSelector& selectorData = aTsList[i]; + TUint8 type = selectorData.Type(); + selector.Append(&type, sizeof(type)); + + TUint8 protocol = selectorData.ProtocolId(); + selector.Append(&protocol, sizeof(protocol)); + + TUint16 selectorLength = 0; + if (selectorData.Type() == TS_IPV4_ADDR_RANGE) + { + BigEndian::Put16(reinterpret_cast(&selectorLength), KIpv4SelectorLength); + } + else + { + BigEndian::Put16(reinterpret_cast(&selectorLength), KIpv6SelectorLength); + } + selector.Append(reinterpret_cast(&selectorLength), sizeof(selectorLength)); + + TInetAddr startAddress = selectorData.StartingAddress(); + TInetAddr endAddress = selectorData.EndingAddress(); + + TUint16 startPort = startAddress.Port(); + TUint16 endPort = endAddress.Port(); + + BigEndian::Put16(reinterpret_cast(&startPort), startPort); + BigEndian::Put16(reinterpret_cast(&endPort), endPort); + + selector.Append(reinterpret_cast(&startPort), sizeof(startPort)); + selector.Append(reinterpret_cast(&endPort), sizeof(endPort)); + + if (selectorData.Type() == TS_IPV4_ADDR_RANGE) + { + TUint32 start = 0; + TUint32 end = 0; + BigEndian::Put32(reinterpret_cast(&start), startAddress.Address()); + BigEndian::Put32(reinterpret_cast(&end), endAddress.Address()); + + selector.Append(reinterpret_cast(&start), sizeof(start)); + selector.Append(reinterpret_cast(&end), sizeof(end)); + } + else + { + TPtrC8 start(&startAddress.Ip6Address().u.iAddr8[0], 16); + TPtrC8 end(&endAddress.Ip6Address().u.iAddr8[0], 16); + selector.Append(start); + selector.Append(end); + } + payloadDataPtr.Append(selector); + } + + __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant()); + } + + +CIkeV2TsiPayload* CIkeV2TsiPayload::NewL(const CArrayFix& aTsList) + { + CIkeV2TsiPayload* self = new (ELeave) CIkeV2TsiPayload(); + CleanupStack::PushL(self); + self->ConstructL(aTsList); + CleanupStack::Pop(self); + + return self; + } + + +CIkeV2TsiPayload::CIkeV2TsiPayload() +:CIkeV2TsPayload(IKEV2_PAYLOAD_TS_I) + { + + } + + +CIkeV2TsrPayload* CIkeV2TsrPayload::NewL(const CArrayFix& aTsList) + { + CIkeV2TsrPayload* self = new (ELeave) CIkeV2TsrPayload(); + CleanupStack::PushL(self); + self->ConstructL(aTsList); + CleanupStack::Pop(self); + + return self; + } + + +CIkeV2TsrPayload::CIkeV2TsrPayload() +:CIkeV2TsPayload(IKEV2_PAYLOAD_TS_R) + { + } + + +CIkeV2EncryptedPayload* CIkeV2EncryptedPayload::NewL(TUint aBlockSize) + { + CIkeV2EncryptedPayload* self = new (ELeave) CIkeV2EncryptedPayload; + CleanupStack::PushL(self); + self->ConstructL(aBlockSize); + CleanupStack::Pop(self); + + return self; + } + + +CIkeV2EncryptedPayload::CIkeV2EncryptedPayload() +:CIkeV2TsPayload(IKEV2_PAYLOAD_ENCR) + { + } + + +void CIkeV2EncryptedPayload::ConstructL(TUint aBlockSize) + { + TUint32 length = aBlockSize + KEncryptedHeaderLength; + + iPayloadData = HBufC8::NewL(length); + TPtr8 payloadDataPtr(iPayloadData->Des()); + payloadDataPtr.SetLength(KIkePayloadGenericHeaderLength); + payloadDataPtr.FillZ(); + + SetPayloadLength(length); + payloadDataPtr.SetLength(length); + + TPtr8 Iv = payloadDataPtr.MidTPtr(KEncryptedHeaderLength); + Iv.SetLength(aBlockSize); + TRandom::RandomL(Iv); + + iBlockSize = aBlockSize; + + __ASSERT_DEBUG(PayloadLength() == iPayloadData->Length(), User::Invariant()); + } + +TUint CIkeV2EncryptedPayload::BlockSize() const + { + return iBlockSize; + } + +TPtrC8 CIkeV2EncryptedPayload::InitializationVector() const + { + return iPayloadData->Right(iBlockSize); + } + +void CIkeV2EncryptedPayload::SetContentLength(TUint16 aLength) + { + //Set the payload length to be: header + Iv + content + SetPayloadLength(aLength + iPayloadData->Length()); + } + +static const TUint KDefaultMessageSize = 4096; +static const TUint32 KIkeV2MsgHeaderLength = 28; +static const TUint8 KIkeV2Version = 2 << 4; + +CIkeV2Message* CIkeV2Message::NewL(const TDesC8& aInitiatorSpi, + const TDesC8& aResponderSpi, + TUint8 aExchangeType, + TBool aIntiator, + TBool aResponse, + TUint32 aMessageId, + MIkeDebug& aDebug) + { + CIkeV2Message* self = new (ELeave)CIkeV2Message(aDebug); + CleanupStack::PushL(self); + self->ConstructL(aInitiatorSpi, + aResponderSpi, + aExchangeType, + aIntiator, + aResponse, + aMessageId); + CleanupStack::Pop(self); + + return self; + } + + +CIkeV2Message::CIkeV2Message(MIkeDebug& aDebug) +:iDebug(aDebug), iModified(ETrue) + { + } + + +void CIkeV2Message::ConstructL(const TDesC8& aInitiatorSpi, + const TDesC8& aResponderSpi, + TUint8 aExchangeType, + TBool aIntiator, + TBool aResponse, + TUint32 aMessageId) + { + __ASSERT_DEBUG(aInitiatorSpi.Length() == 8, User::Invariant()); + __ASSERT_DEBUG(aResponderSpi.Length() == 8, User::Invariant()); + + iIkeV2MessageHeader = HBufC8::NewL(KDefaultMessageSize); + TPtr8 messageDataPtr = iIkeV2MessageHeader->Des(); + + + const TPtrC8 versionPtr(&KIkeV2Version, sizeof(TUint8)); + const TPtrC8 exchangeTypePtr(&aExchangeType, sizeof(TUint8)); + + TUint8 flags = (aIntiator) ? IKEV2_INITIATOR : 0; + flags |= (aResponse) ? IKEV2_RESPONSE_MSG : 0; + + + const TPtrC8 flagsPtr(&flags, sizeof(flags)); + BigEndian::Put32(reinterpret_cast(&aMessageId), aMessageId); + const TPtrC8 messageIdPtr(reinterpret_cast(&aMessageId), sizeof(TUint32)); + + TUint32 length; + BigEndian::Put32(reinterpret_cast(&length), KIkeV2MsgHeaderLength); + const TPtrC8 lengthPtr(reinterpret_cast(&length), sizeof(TUint32)); + + //Add SPIs + messageDataPtr.Append(aInitiatorSpi); + messageDataPtr.Append(aResponderSpi); + + //Left next payload as zero + TUint8 nextPayload = 0; + TPtrC8 nextPayloadPtr(&nextPayload, sizeof(nextPayload)); + messageDataPtr.Append(nextPayloadPtr); + + messageDataPtr.Append(versionPtr); + messageDataPtr.Append(exchangeTypePtr); + messageDataPtr.Append(flagsPtr); + messageDataPtr.Append(messageIdPtr); + messageDataPtr.Append(lengthPtr); + + __ASSERT_DEBUG(iIkeV2MessageHeader->Length() == KIkeV2MsgHeaderLength, User::Invariant()); + } + + +CIkeV2Message::~CIkeV2Message() + { + delete iIkeV2Datagram; + delete iIkeV2MessageHeader; + iPayloads.ResetAndDestroy(); + iPayloads.Close(); + } + + +TPtrC8 CIkeV2Message::InitiatorSpi()const + { + TUint KInitiatorSpiPosition = 0; + TUint KSpiLength = 8; + + return iIkeV2MessageHeader->Mid(KInitiatorSpiPosition, KSpiLength); + } + + +TPtrC8 CIkeV2Message::ResponderSpi() const + { + TUint KResponderSpiPosition = 8; + TUint KSpiLength = 8; + + return iIkeV2MessageHeader->Mid(KResponderSpiPosition, KSpiLength); + } + + +TUint8 CIkeV2Message::Flags() const + { + TUint KFlagsPosition = 19; + return (*iIkeV2MessageHeader)[KFlagsPosition]; + } + + +TUint32 CIkeV2Message::MessageId() const + { + __ASSERT_DEBUG(iIkeV2MessageHeader->Length() >= KIkeV2MsgHeaderLength, User::Invariant()); + const TUint8* messageIdPtr = iIkeV2MessageHeader->Ptr() + KMessageIdFieldOffset; + return BigEndian::Get32(messageIdPtr); + + } + + +void CIkeV2Message::AppendCertReqPayloadL(const CIkeCaList& aCaList) + { + __ASSERT_DEBUG(aCaList.Count() > 0, User::Invariant()); + + CIkevV2CertReqPayload* certReqPayload = CIkevV2CertReqPayload::NewL(aCaList); + AppendPayloadL(certReqPayload); + } + + +void CIkeV2Message::AppendCertPayloadL(const TDesC8& aCertificateData) + { + CIkevV2CertPayload* certPayload = CIkevV2CertPayload::NewL(aCertificateData); + AppendPayloadL(certPayload); + } + + +void CIkeV2Message::AppendSaPayloadL(const TDesC8& aSaData) + { + CIkevV2SaPayload* saPayload = CIkevV2SaPayload::NewL(aSaData); + AppendPayloadL(saPayload); + } + + +void CIkeV2Message::AppendKePayloadL(TUint16 aDHGroup, const TDesC8& aKeData) + { + CIkevV2KePayload* kePayload = CIkevV2KePayload::NewL(aDHGroup, aKeData); + AppendPayloadL(kePayload); + } + + +void CIkeV2Message::AppendNoncePayloadL(const TDesC8& aNonceData) + { + CIkevV2NoncePayload* noncePayload = CIkevV2NoncePayload::NewL(aNonceData); + AppendPayloadL(noncePayload); + } + + +void CIkeV2Message::AppendIdiPayloadL(const CIkeV2Identity& aIdentity) + { + CIkevV2IdiPayload* idiPayload = CIkevV2IdiPayload::NewL(aIdentity); + AppendPayloadL(idiPayload); + } + + +void CIkeV2Message::AppendIdrPayloadL(const CIkeV2Identity& aIdentity) + { + CIkevV2IdrPayload* idrPayload = CIkevV2IdrPayload::NewL(aIdentity); + AppendPayloadL(idrPayload); + } + +void CIkeV2Message::AppendAuthPayloadL(TUint8 aAuthMethod, const TDesC8& aAuthData) + { + CIkeV2AuthPayload* authPayload = CIkeV2AuthPayload::NewL(aAuthMethod, aAuthData); + AppendPayloadL(authPayload); + } + + +void CIkeV2Message::AppendNotifyPayloadL(TUint8 aProtocolId, + const TDesC8& aSpi, + TUint16 aNotifyType, + const TDesC8& aNotifyData) + { + CIkeV2NotifyPayload* notifyPayload = CIkeV2NotifyPayload::NewL(aProtocolId, aSpi, + aNotifyType, aNotifyData); + AppendPayloadL(notifyPayload); + } + +void CIkeV2Message::PrependCookieNotifyPayloadL(const TDesC8& aCookieData) + { + _LIT8(KZeroDesc, ""); + CIkeV2NotifyPayload* notifyPayload = CIkeV2NotifyPayload::NewL(0, KZeroDesc, + COOKIE, aCookieData); + + delete iIkeV2Datagram; + iIkeV2Datagram = NULL; + iModified = ETrue; + + if (iPayloads.Count() > 0) + { + notifyPayload->SetNextPayload(iPayloads[0]->PayloadType()); + } + + TInt err = iPayloads.Insert(notifyPayload, 0); + if (err != KErrNone) + { + delete notifyPayload; + User::Leave(err); + } + + SetNextPayload(notifyPayload->PayloadType()); + } + + +void CIkeV2Message::AppendConfigurationPayloadL(TUint8 aCfgType, + const TDesC8& aConfigurationData) + { + CIkeV2ConfigurationPayload* configPayload = + CIkeV2ConfigurationPayload::NewL(aCfgType, aConfigurationData); + AppendPayloadL(configPayload); + } + + +void CIkeV2Message::AppendVendorIdPayloadL(const TDesC8& aVendorIdData) + { + CIkeV2VendorIdPayload* vendorIdPayload = CIkeV2VendorIdPayload::NewL(aVendorIdData); + AppendPayloadL(vendorIdPayload); + } + +void CIkeV2Message::AppendDeletePayloadL(TUint8 aProtocolId, const CDesC8Array& aSpiList) + { + CIkeV2DeletePayload* deletePayload = CIkeV2DeletePayload::NewL(aProtocolId, aSpiList); + AppendPayloadL(deletePayload); + } + + +void CIkeV2Message::AppendEapPayloadL(const TDesC8& aEapData) + { + CIkeV2EapPayload* eapPayload = CIkeV2EapPayload::NewL(aEapData); + AppendPayloadL(eapPayload); + } + + +void CIkeV2Message::AppendTsiPayloadL(const CArrayFix& aTsList) + { + CIkeV2TsiPayload* tsPayload = CIkeV2TsiPayload::NewL(aTsList); + AppendPayloadL(tsPayload); + } + + +void CIkeV2Message::AppendTsrPayloadL(const CArrayFix& aTsList) + { + CIkeV2TsrPayload* tsPayload = CIkeV2TsrPayload::NewL(aTsList); + AppendPayloadL(tsPayload); + } + + +void CIkeV2Message::AppendEncryptedPayloadL(TUint aBlockSize) + { + __ASSERT_DEBUG(iPayloads.Count() == 0, User::Invariant()); + CIkeV2EncryptedPayload* encryptedPayload = CIkeV2EncryptedPayload::NewL(aBlockSize); + AppendPayloadL(encryptedPayload); + } + +void CIkeV2Message::PrepareIkeMessageDatagramL(TUint16 aEncryptionAlgorith, + const TDesC8& aEncryptionKey, + TUint16 aIntegrityAlgorithm, + const TDesC8& aIntegrityKey, +#ifdef _DEBUG + const TInetAddr& aSourceAddress, +#else + const TInetAddr& /*aSourceAddress*/, +#endif + const TInetAddr& aDestinationAddress) + { + __ASSERT_DEBUG(iPayloads.Count() > 0, User::Invariant()); + + if (iModified) + { + __ASSERT_DEBUG(iIkeV2Datagram == NULL, User::Invariant()); + + if (iPayloads[0]->PayloadType() == IKEV2_PAYLOAD_ENCR) + { + //Datagram is should be encrypted + //Calculate the length of the padding + CIkeV2EncryptedPayload* encryptedPayload = static_cast(iPayloads[0]); + TUint encryptedDataLength = 0; + for(TInt i = 1; i < iPayloads.Count(); ++i) + { + encryptedDataLength += iPayloads[i]->PayloadLength(); + } + + //If the data length is multiple of the blocksize, we add full block length + //of padding. Otherwise we just add padding enough to fill the block. + TUint8 paddingLength = encryptedPayload->BlockSize() - + encryptedDataLength % encryptedPayload->BlockSize(); + //The last octet of the padding tells the length of the padding. + //we just use that value to fill the entire padding. + TInt integrityCheckSumLength = 0; + IkeCrypto::AlgorithmInfo(IKEV2_INTEG, aIntegrityAlgorithm, &integrityCheckSumLength); + + + //The length of the whole datagram: + TUint32 datagramLength = iIkeV2MessageHeader->Length() + + encryptedPayload->PayloadLength() + + encryptedDataLength + + paddingLength + + integrityCheckSumLength; + + //Update header fields + SetLength(datagramLength); + encryptedPayload->SetContentLength((TUint16)(encryptedDataLength + + paddingLength + + integrityCheckSumLength)); + + //Allocate buffer, which has space for the whole datagram. (+ Non ESP marker) + HBufC8* datagram = HBufC8::NewLC(datagramLength + KNonEspMarker().Length()); + TPtr8 datagramPtr = datagram->Des(); + + datagramPtr = *iIkeV2MessageHeader; + datagramPtr.Append(encryptedPayload->PayloadData()); + + //buffer for data, which is encrypted + HBufC8* encryptionSource = HBufC8::NewLC(encryptedDataLength + + paddingLength); + TPtr8 encryptionSourcePtr = encryptionSource->Des(); + + for (TInt i = 1; i < iPayloads.Count(); ++i) + { + const CIkeV2Payload* pl = iPayloads[i]; + __ASSERT_DEBUG(pl->PayloadData().Length() == pl->PayloadLength(), User::Invariant()); + + encryptionSourcePtr.Append(pl->PayloadData()); + datagramPtr.Append(pl->PayloadData()); //This is because we want to trace the datagram + } + + + //Last byte of the padding has to be the length of the padding. + //We fillup the whole padding with this same number + TUint8 paddingValue = paddingLength - 1; + for (TInt i = 0; i < paddingLength; ++i) + { + encryptionSourcePtr.Append(&paddingValue, 1); + datagramPtr.Append(&paddingValue, 1); + } + + + datagramPtr.SetLength(datagram->Length() + integrityCheckSumLength); + TRACE_MSG(*datagram, aSourceAddress, aDestinationAddress, + (CIkePcapTrace::TEncryptionType)aEncryptionAlgorith); + datagramPtr.SetLength(datagram->Length() - integrityCheckSumLength); + + //Extracts the data, which is encrypted. + //(Excludes IKE hdr, Encrypted payload hdr and Iv) + TPtr8 encryptionBuffer = datagramPtr.MidTPtr(iIkeV2MessageHeader->Length() + + KEncryptedHeaderLength + + encryptedPayload->BlockSize()); + __ASSERT_DEBUG(encryptionBuffer.Length() == encryptionSource->Length(), User::Invariant()); + encryptionBuffer.SetLength(0); + IkeCrypto::EncryptL(*encryptionSource, encryptionBuffer, + encryptedPayload->InitializationVector(), + aEncryptionKey, aEncryptionAlgorith); + + CleanupStack::PopAndDestroy(encryptionSource); + + //Extracts the space for the checksum from the end of the buffer + TUint lengthWithoutItegrityCheckSum = datagramPtr.Length(); + datagramPtr.SetLength(lengthWithoutItegrityCheckSum + integrityCheckSumLength); + TPtr8 checksum = datagramPtr.MidTPtr(lengthWithoutItegrityCheckSum); + + //Extracts the source for the integrity checksum calculation + TPtrC8 integrityCheckSumSource = datagram->Left(lengthWithoutItegrityCheckSum); + IkeCrypto::IntegHMACL(integrityCheckSumSource, checksum, aIntegrityKey, aIntegrityAlgorithm); + + CleanupStack::Pop(datagram); + iIkeV2Datagram = datagram; + } + else + { + //calculate the length of unencrypted datagram + TUint datagramLength = iIkeV2MessageHeader->Length(); + for (TInt i = 0; i < iPayloads.Count(); ++i) + { + datagramLength += iPayloads[i]->PayloadLength(); + } + SetLength(datagramLength); + + iIkeV2Datagram = HBufC8::NewL(datagramLength + KNonEspMarker().Length()); + TPtr8 ikeV2DatargramPtr = iIkeV2Datagram->Des(); + ikeV2DatargramPtr.Append(*iIkeV2MessageHeader); + + for (TInt i = 0; i < iPayloads.Count(); ++i) + { + ikeV2DatargramPtr.Append(iPayloads[i]->PayloadData()); + } + TRACE_MSG(*iIkeV2Datagram, aSourceAddress, aDestinationAddress, + (CIkePcapTrace::TEncryptionType)aEncryptionAlgorith); + + } + + if (aDestinationAddress.Port() == FLOATED_IKE_PORT) + { + //insert non esp marker + iIkeV2Datagram->Des().Insert(0, KNonEspMarker); + } + iModified = EFalse; + } + + __ASSERT_DEBUG(!iModified && iIkeV2Datagram != NULL, User::Invariant()); + } + + +TPtrC8 CIkeV2Message::IkeMessageDatagram() const + { + __ASSERT_DEBUG(!iModified && iIkeV2Datagram != NULL, User::Invariant()); + return *iIkeV2Datagram; + } + + +void CIkeV2Message::AppendPayloadL(CIkeV2Payload* aPayload) + { + TInt err = iPayloads.Append(aPayload); + if (err != KErrNone) + { + delete aPayload; + User::Leave(err); + } + + if (iPayloads.Count() > 1) + { + iPayloads[iPayloads.Count() - 2]->SetNextPayload(aPayload->PayloadType()); + } + else + { + SetNextPayload(aPayload->PayloadType()); + } + + delete iIkeV2Datagram; + iIkeV2Datagram = NULL; + iModified = ETrue; + } + +void CIkeV2Message::SetLength(TUint32 aDatagramLength) + { + static const TUint KLengthFieldPosition = 6*4; + BigEndian::Put32(reinterpret_cast(&aDatagramLength), aDatagramLength); + TPtr8 lengthField = iIkeV2MessageHeader->Des().MidTPtr(KLengthFieldPosition, sizeof(aDatagramLength)); + lengthField = TPtrC8(reinterpret_cast(&aDatagramLength), sizeof(aDatagramLength)); + } + + +void CIkeV2Message::SetNextPayload(TUint8 aNextPayload) + { + const TUint KNextPayloadPosition = 16; + TPtr8 ikeHeaderPtr = iIkeV2MessageHeader->Des(); + ikeHeaderPtr[KNextPayloadPosition] = aNextPayload; + }