--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/vpnengine/ikev2lib/src/ikemsgrec.cpp Thu Dec 17 09:14:51 2009 +0200
@@ -0,0 +1,452 @@
+/*
+* 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: Received IKE message handling rules.
+*
+*/
+
+#include "ikev2SAdata.h"
+#include "ikemsgrec.h"
+#include "ikecrypto.h"
+//
+// CIkev2Payloads
+//
+
+CIkev2Payloads::CIkev2Payloads(const TIkev2SAData& aIkeV2SaData)
+:iIkeV2SaData(aIkeV2SaData)
+{
+}
+
+CIkev2Payloads::~CIkev2Payloads()
+{
+ delete iProps;
+ delete iTrans;
+ delete iCerts;
+ delete iCertReqs;
+ delete iNotifs;
+ delete iDeletes;
+ delete iVids;
+ delete iGenPlds;
+}
+
+CIkev2Payloads* CIkev2Payloads::NewL(const ThdrISAKMP &aHdr, const TIkev2SAData& aIkeV2SaData)
+{
+ CIkev2Payloads* Payloads = new (ELeave) CIkev2Payloads(aIkeV2SaData);
+ CleanupStack::PushL(Payloads);
+
+ Payloads->ConstructL();
+
+ Payloads->iIkeMsg = (ThdrISAKMP*)&aHdr; // Save pointer to IKE message data
+ TInt Lth = aHdr.GetLength() - ThdrISAKMP::Size();
+ Payloads->ParsePayloadsL(TPayloadIkev2::Cast(aHdr.Next()), Lth, aHdr.GetPayload(), IKEV2_PAYLOAD_NONE);
+
+ CleanupStack::Pop(Payloads);
+
+ return Payloads;
+}
+
+CIkev2Payloads* CIkev2Payloads::NewL(TPayloadIkev2* aPayload, TUint8 aPayloadType, TIkev2SAData& aIkeV2SaData)
+{
+ User::LeaveIfNull((TAny*)aPayload);
+ CIkev2Payloads* Payloads = new (ELeave) CIkev2Payloads(aIkeV2SaData);
+ CleanupStack::PushL(Payloads);
+
+ Payloads->ConstructL();
+
+ Payloads->ParsePayloadsL(aPayload, aPayload->GetLength(), aPayloadType, aPayloadType);
+
+ CleanupStack::Pop(Payloads);
+
+ return Payloads;
+}
+
+TBool CIkev2Payloads::ParsePayloadL(TPayloadIkev2* aPayload, TUint16 aPlType)
+{
+ User::LeaveIfNull((TAny*)aPayload);
+
+ if ( aPlType == IKEV2_PAYLOAD_SA )
+ iProps->Reset();
+ else if ( aPlType == IKEV2_PAYLOAD_PROP )
+ iTrans->Reset();
+ if ( ParsePayloadsL(aPayload, aPayload->GetLength(), aPlType, aPlType) != 0 )
+ return EFalse;
+ else return ETrue;
+}
+
+void CIkev2Payloads::ConstructL()
+{
+ iProps = new (ELeave) CArrayFixFlat<TProposalIkev2 *>(4);
+ iTrans = new (ELeave) CArrayFixFlat<TTransformIkev2 *>(4);
+ iCerts = new (ELeave) CArrayFixFlat<TCertPayloadIkev2 *>(4);
+ iCertReqs = new (ELeave) CArrayFixFlat<TCReqPayloadIkev2 *>(2);
+ iNotifs = new (ELeave) CArrayFixFlat<TNotifPayloadIkev2 *>(2);
+ iDeletes = new (ELeave) CArrayFixFlat<TDeletePlIkev2 *>(2);
+ iVids = new (ELeave) CArrayFixFlat<TVendorPlIkev2 *>(2);
+ iGenPlds = new (ELeave) CArrayFixFlat<TPayloadIkev2 *>(2);
+}
+
+
+TInt CIkev2Payloads::ParsePayloadsL(TPayloadIkev2* aPayload, TInt aLength, TUint16 aPlType, TUint16 aRefPlType )
+{
+ ASSERT(aPayload);
+ TBool Critical;
+ TInt PlLth;
+ TInt RefLth;
+
+ while ( aPlType != IKEV2_PAYLOAD_NONE )
+ {
+ PlLth = aPayload->GetLength();
+ RefLth = TPayloadIkev2::Size();
+
+ if ( ( aLength < TPayloadIkev2::Size() ) || (aLength < PlLth) )
+ {
+ if ( aLength && ( aRefPlType != IKEV2_PAYLOAD_SA ))
+ SetStatus(INVALID_SYNTAX); // Payload length mismatch !!
+ return aLength;
+ }
+
+ if ( (aRefPlType != IKEV2_PAYLOAD_NONE) && (aRefPlType != aPlType) )
+ {
+ SetStatus(INVALID_SYNTAX); // Illegal payload type !!
+ return aLength;
+ }
+
+ Critical = aPayload->GetCritical();
+
+ switch ( aPlType )
+ {
+ case IKEV2_PAYLOAD_PROP:
+ iProps->AppendL(TProposalIkev2::Cast(aPayload));
+ //
+ // Parse Transform payloads within a Proposal payload
+ // (recursively)
+ //
+ ParsePayloadsL(TPayloadIkev2::Cast(TProposalIkev2::Cast(aPayload)->TransformPl()),
+ (PlLth - TProposalIkev2::Cast(aPayload)->PropHdrLth()),
+ IKEV2_PAYLOAD_TRANS, IKEV2_PAYLOAD_TRANS);
+ if ( Status() )
+ return aLength;
+ break;
+
+ case IKEV2_PAYLOAD_TRANS:
+ RefLth = TTransformIkev2::Cast(aPayload)->Size();
+ iTrans->AppendL(TTransformIkev2::Cast(aPayload));
+ break;
+
+ case IKEV2_PAYLOAD_SA: //also includes proposal and transform
+ if ( !iSa ) // Only one SA payload (The first)
+ {
+ iSa = aPayload;
+ //
+ // Parse Proposal payloads within a SA payload
+ // (recursively)
+ //
+ ParsePayloadsL(TPayloadIkev2::Cast(aPayload->PayloadData()), aPayload->PlDataLen(),
+ IKEV2_PAYLOAD_PROP, IKEV2_PAYLOAD_PROP);
+ if ( Status() )
+ return aLength;
+ }
+ break;
+
+ case IKEV2_PAYLOAD_KE:
+ RefLth = TKEPayloadIkev2::Size();
+ if ( !iKe ) // Only one KE payload (The first)
+ {
+ iKe = TKEPayloadIkev2::Cast(aPayload);
+ }
+ break;
+
+ case IKEV2_PAYLOAD_ID_I:
+ if ( !Encrypted() )
+ {
+ SetStatus(INVALID_SYNTAX); // ID payload MUST be encrypted
+ return aLength;
+ }
+ RefLth = TIDPayloadIkev2::Size();
+ if ( !iIdI ) // Only one Initiator ID payload (The first)
+ {
+ iIdI = TIDPayloadIkev2::Cast(aPayload);
+ }
+ break;
+
+ case IKEV2_PAYLOAD_ID_R:
+ if ( !Encrypted() )
+ {
+ SetStatus(INVALID_SYNTAX); // ID payload MUST be encrypted
+ return aLength;
+ }
+ RefLth = TIDPayloadIkev2::Size();
+ if ( !iIdR ) // Only one Responder ID payload (The first)
+ {
+ iIdR = TIDPayloadIkev2::Cast(aPayload);
+ }
+ break;
+
+ case IKEV2_PAYLOAD_CERT:
+ RefLth = TCertPayloadIkev2::Size();
+ iCerts->AppendL(TCertPayloadIkev2::Cast(aPayload));
+ break;
+
+ case IKEV2_PAYLOAD_CR:
+ RefLth = TCReqPayloadIkev2::Size();
+ iCertReqs->AppendL(TCReqPayloadIkev2::Cast(aPayload));
+ break;
+
+ case IKEV2_PAYLOAD_AUTH:
+ if ( !Encrypted() )
+ {
+ SetStatus(INVALID_SYNTAX); // Auth payload MUST be encrypted
+ return aLength;
+ }
+ RefLth = TAuthPayloadIkev2::Size();
+ if ( !iAuth ) // Only one Authentication payload (The first)
+ {
+ iAuth = TAuthPayloadIkev2::Cast(aPayload);
+ }
+ break;
+
+ case IKEV2_PAYLOAD_NONCE:
+ if ( !iNonce )
+ { // Only one SA payload (The first)
+ iNonce = aPayload;
+ }
+ break;
+
+ case IKEV2_PAYLOAD_NOTIF:
+ RefLth = TNotifPayloadIkev2::Size();
+ iNotifs->AppendL(TNotifPayloadIkev2::Cast(aPayload));
+ break;
+
+ case IKEV2_PAYLOAD_DELETE:
+ RefLth = TDeletePlIkev2::Size();
+ iDeletes->AppendL(TDeletePlIkev2::Cast(aPayload));
+ break;
+
+ case IKEV2_PAYLOAD_VID:
+ iVids->AppendL(aPayload);
+ break;
+
+ case IKEV2_PAYLOAD_TS_I:
+ if ( !Encrypted() )
+ {
+ SetStatus(INVALID_SYNTAX); // ID payload MUST be encrypted
+ return aLength;
+ }
+ RefLth = TTSPayloadIkev2::Size();
+ if ( !iTsI ) // Only one Initiator ID payload (The first)
+ {
+ iTsI = TTSPayloadIkev2::Cast(aPayload);
+ }
+ break;
+
+ case IKEV2_PAYLOAD_TS_R:
+ if ( !Encrypted() )
+ {
+ SetStatus(INVALID_SYNTAX); // ID payload MUST be encrypted
+ return aLength;
+ }
+ RefLth = TTSPayloadIkev2::Size();
+ if ( !iTsR ) // Only one Initiator ID payload (The first)
+ {
+ iTsR = TTSPayloadIkev2::Cast(aPayload);
+ }
+ break;
+
+ case IKEV2_PAYLOAD_ENCR:
+ if ( !iEncr ) // Only one Initiator ID payload (The first)
+ {
+ DecryptEncrPayloadL(aPayload);
+ iEncr = aPayload;
+ }
+ else SetStatus(INVALID_SYNTAX); // Only ONE encrypted payload per message
+ if ( Status() )
+ return aLength;
+ break;
+
+ case IKEV2_PAYLOAD_CONFIG:
+ if ( !Encrypted() )
+ {
+ SetStatus(INVALID_SYNTAX); // ID payload MUST be encrypted
+ return aLength;
+ }
+ RefLth = TCPPayloadIkev2::Size();
+ if ( !iCp ) // Only one Config payload (The first)
+ {
+ iCp = TCPPayloadIkev2::Cast(aPayload);
+ }
+ break;
+
+ case IKEV2_PAYLOAD_EAP:
+ if ( !Encrypted() )
+ {
+ SetStatus(INVALID_SYNTAX); // ID payload MUST be encrypted
+ return aLength;
+ }
+ if ( !iEap ) // Only one Config payload (The first)
+ {
+ iEap = aPayload;
+ }
+ break;
+
+ //
+ // Unknown payload detected. If Critical bit is not set
+ //
+ //
+ default:
+ if ( Critical )
+ {
+ SetStatus(UNSUPPORTED_CRITICAL_PAYLOAD);
+ return aLength;
+ }
+ else iGenPlds->AppendL(aPayload);
+ break;
+
+ }
+
+ if ( PlLth < RefLth )
+ {
+ SetStatus(INVALID_SYNTAX); // Length mismatch
+ return aLength;
+ }
+
+ aLength -= PlLth;
+ aPlType = aPayload->GetNextPayload();
+ aPayload = aPayload->Next();
+ }
+
+ if ( aLength )
+ SetStatus(INVALID_SYNTAX); // Length mismatch
+
+ return aLength;
+}
+
+void CIkev2Payloads::DecryptEncrPayloadL(TPayloadIkev2* aPayload)
+{
+ ASSERT(aPayload);
+ //
+ // Process Encrypted Payload
+ // 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
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Next Payload !C! RESERVED ! Payload Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Initialization Vector !
+ // ! (length is block size for encryption algorithm) !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! Encrypted IKE Payloads !
+ // + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ! ! Padding (0-255 octets) !
+ // +-+-+-+-+-+-+-+-+ +-+-+-+-+-+-+-+-+
+ // ! ! Pad Length !
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ // ~ Integrity Checksum Data ~
+ // +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
+ //
+ // Save integrity checksum from encrypted payload tail the
+ // integrity checksum length is defined by used integrity algorithm
+ //
+ TInt CheksumLth = iIkeV2SaData.iIntChkSumLth;
+ TInt CbcLth = iIkeV2SaData.iCipherBlkLth;
+ TInt EmbeddedLth = aPayload->GetLength();
+ if ( EmbeddedLth < (CheksumLth + CbcLth) )
+ {
+ SetStatus(INVALID_SYNTAX);
+ return;
+ }
+ TUint8* MsgChecksum = (TUint8*)aPayload + EmbeddedLth - CheksumLth;
+ TBuf8<IKEV2_KEY_MATERIAL_SIZE> CheckSum;
+ //
+ // Decrypt encryption payload content and payload tail the
+ // integrity checksum length is defined by used integrity algorithm
+ //
+
+ TInt EntireLth = iIkeMsg->GetLength() - iIkeV2SaData.iIntChkSumLth;
+ TInt EncryptedDataLength = aPayload->GetLength() - (iIkeV2SaData.iIntChkSumLth + iIkeV2SaData.iCipherBlkLth + TPayloadIkev2::Size());
+ TUint8* IvPtr = aPayload->PayloadData();
+ TUint8* EncryptedData = IvPtr + iIkeV2SaData.iCipherBlkLth;
+
+ TPtrC8 entireDataPtr((TUint8*)iIkeMsg, EntireLth);
+ if ( iIkeV2SaData.iInitiator )
+ {
+ IkeCrypto::IntegHMACL(entireDataPtr, CheckSum, iIkeV2SaData.iSK_ar, iIkeV2SaData.iIntegAlg);
+ IkeCrypto::DecryptL(EncryptedData, EncryptedData, EncryptedDataLength, IvPtr, iIkeV2SaData.iSK_er, iIkeV2SaData.iEncrAlg);
+ }
+ else
+ {
+ IkeCrypto::IntegHMACL(entireDataPtr, CheckSum, iIkeV2SaData.iSK_ai, iIkeV2SaData.iIntegAlg);
+ IkeCrypto::DecryptL(EncryptedData, EncryptedData, EncryptedDataLength, IvPtr, iIkeV2SaData.iSK_ei, iIkeV2SaData.iEncrAlg);
+ }
+
+
+ //
+ // Check that integrity cheksum is correct
+ //
+ if ( Mem::Compare(MsgChecksum, CheksumLth ,CheckSum.Ptr(), CheksumLth) != 0 )
+ {
+ SetStatus(INVALID_SYNTAX); // Length mismatch
+ return;
+ }
+ //
+ // Process embedded payloads inside the encrypted payload
+ // - Bypass IV in the begin of encrypted payload data
+ // - Assure that padded "embedded" payloads have length which
+ // equals with multiple of CBC block length
+ // - Ignore padding bytes from that length
+ //
+ EmbeddedLth -= (CheksumLth + CbcLth + TPayloadIkev2::Size());
+ if ( EmbeddedLth % CbcLth )
+ {
+ SetStatus(INVALID_SYNTAX);
+ return;
+ }
+ MsgChecksum --; // Move pointer to padding length
+ if ( EmbeddedLth < (TInt)*MsgChecksum )
+ {
+ SetStatus(INVALID_SYNTAX);
+ return;
+ }
+ EmbeddedLth -= (TInt)*MsgChecksum;
+ EmbeddedLth --; // Pad Length itself
+ TPayloadIkev2* EmbeddedPl = TPayloadIkev2::Cast(aPayload->PayloadData() + CbcLth);
+
+ iEncrypted = ETrue; // Set encrypted indicator
+
+ ParsePayloadsL(EmbeddedPl, EmbeddedLth,
+ aPayload->GetNextPayload(), IKEV2_PAYLOAD_NONE);
+
+}
+
+ThdrISAKMP* CIkev2Payloads::GetIkeMsg()
+{
+ return iIkeMsg;
+}
+
+
+TInt CIkev2Payloads::Status()
+{
+ return iStatus;
+}
+
+
+void CIkev2Payloads::SetStatus(TInt aStatus)
+{
+ if ( iStatus == 0) iStatus = aStatus;
+}
+
+
+TBool CIkev2Payloads::Encrypted()
+{
+ return iEncrypted;
+}
+
+