|
1 /* |
|
2 * Copyright (c) 2007-2009 Nokia Corporation and/or its subsidiary(-ies). |
|
3 * All rights reserved. |
|
4 * This component and the accompanying materials are made available |
|
5 * under the terms of "Eclipse Public License v1.0" |
|
6 * which accompanies this distribution, and is available |
|
7 * at the URL "http://www.eclipse.org/legal/epl-v10.html". |
|
8 * |
|
9 * Initial Contributors: |
|
10 * Nokia Corporation - initial contribution. |
|
11 * |
|
12 * Contributors: |
|
13 * |
|
14 * Description: CIkev1InfoNegotiation class |
|
15 * |
|
16 */ |
|
17 |
|
18 #include <vpnlogmessages.rsg> |
|
19 |
|
20 #include "ikev1infonegotiation.h" |
|
21 #include "ikev1negotiation.h" |
|
22 #include "ikev1SAdata.h" |
|
23 #include "ikev1isakmpct.h" |
|
24 #include "ikedebug.h" |
|
25 #include "ikev1pluginsession.h" |
|
26 #include "ikev1negotiation.h" |
|
27 #include "ikev1crypto.h" |
|
28 #include "ikev1payload.h" |
|
29 #include "ikev1crack.h" |
|
30 #include "ikev1trans.h" |
|
31 #include "kmdapi.h" |
|
32 #include "kmdeventloggerif.h" |
|
33 |
|
34 |
|
35 CIkev1InfoNegotiation::CIkev1InfoNegotiation( CIkev1PluginSession& aPluginSession, |
|
36 CIkev1Negotiation& aNegotiation, |
|
37 MIkeDebug& aDebug ) |
|
38 : iPluginSession( aPluginSession ), |
|
39 iNegotiation( aNegotiation ), |
|
40 iDebug( aDebug ) |
|
41 { |
|
42 } |
|
43 |
|
44 #ifdef _DEBUG |
|
45 void CIkev1InfoNegotiation::ExecuteL( const ThdrISAKMP& aHdr, |
|
46 const TInetAddr& aSrcAddr, |
|
47 TInt aLocalPort ) |
|
48 #else |
|
49 void CIkev1InfoNegotiation::ExecuteL( const ThdrISAKMP& aHdr, |
|
50 const TInetAddr& /*aSrcAddr*/, |
|
51 TInt /*aLocalPort*/ ) |
|
52 #endif |
|
53 { |
|
54 const ThdrISAKMP *hdr = NULL; |
|
55 TUint8 *msg=NULL; |
|
56 TBuf8<IKEV1_MAX_IV_SIZE> tmp_IV; //Temporal IV. Used to update the real one if the msg OK |
|
57 |
|
58 iMessageId = aHdr.GetMessageId(); //Saves the ID to compute IV and hash |
|
59 if (aHdr.GetFlags() & ISAKMP_HDR_EFLAG) //if encrypted |
|
60 { |
|
61 DEBUG_LOG(_L("Received message (encr).")); |
|
62 msg = new (ELeave) TUint8[aHdr.GetLength()]; //to place the new msg |
|
63 CleanupStack::PushL(msg); |
|
64 |
|
65 Mem::Copy(msg,(TUint8 *)&aHdr, sizeof(aHdr)); //The header is not encrypted |
|
66 |
|
67 DEBUG_LOG(_L("Message ID recv:")); |
|
68 #ifdef _DEBUG |
|
69 TUint32 swap_id = ByteOrder::Swap32(iMessageId); |
|
70 DEBUG_LOG_ARRAY((TUint8 *)&swap_id, sizeof(iMessageId)); |
|
71 DEBUG_LOG(_L("Notif IV:")); |
|
72 #endif // _DEBUG |
|
73 //Notify and Phase II requires a recomputing of IV |
|
74 |
|
75 if (iNegotiation.iLastIV.Length() != 0) |
|
76 tmp_IV.Copy(iNegotiation.iLastIV); |
|
77 else //iLastIV not yet computed so current iIV is used |
|
78 tmp_IV.Copy(iNegotiation.iIV); |
|
79 iNegotiation.ComputeIVL(tmp_IV, iMessageId); |
|
80 |
|
81 DEBUG_LOG(_L("Decrypting...")); |
|
82 |
|
83 DecryptL((TUint8 *)aHdr.Next(),&msg[sizeof(aHdr)], aHdr.GetLength()-sizeof(aHdr), tmp_IV, iNegotiation.iSKEYID_e, iNegotiation.iChosenProposal_I.iAttrList->iEncrAlg); |
|
84 hdr=(ThdrISAKMP *)msg; //decrypted msg |
|
85 } |
|
86 else |
|
87 hdr = &aHdr; |
|
88 |
|
89 DEBUG_LOG(_L("Received message.")); |
|
90 #ifdef _DEBUG |
|
91 const TPtrC8 ikeMsgPtr( (TUint8*)hdr,(TUint16)hdr->GetLength() ); |
|
92 TInetAddr localAddr; |
|
93 iPluginSession.GetLocalAddress( localAddr ); |
|
94 localAddr.SetPort( aLocalPort ); |
|
95 TRACE_MSG_IKEV1( ikeMsgPtr, aSrcAddr, localAddr ); |
|
96 #endif // _DEBUG |
|
97 InfoExchangeL(*hdr); |
|
98 if (msg) //If used erase it (when encryption) |
|
99 CleanupStack::PopAndDestroy(); |
|
100 } |
|
101 |
|
102 MKmdEventLoggerIf& CIkev1InfoNegotiation::EventLogger() |
|
103 { |
|
104 return iPluginSession.EventLogger(); |
|
105 } |
|
106 |
|
107 //No phase dependant. May inform of an error or general status info |
|
108 void CIkev1InfoNegotiation::InfoExchangeL(const ThdrISAKMP &aHdr) |
|
109 { |
|
110 iNegotiation.iLengthLeft = aHdr.GetLength(); //Used to check the size in the payload are OK |
|
111 |
|
112 CIkev1Payloads* payload = CIkev1Payloads::NewL(aHdr, iNegotiation, iDebug); |
|
113 if (!payload) |
|
114 return; |
|
115 CleanupStack::PushL(payload); |
|
116 |
|
117 TInt i; |
|
118 TBool notif_ok = EFalse; |
|
119 //If the message contains a hash |
|
120 if ( payload->iHash ) |
|
121 { |
|
122 if ( payload->iNotifs->Count() ) |
|
123 { |
|
124 //Checks if the hash value is OK. Here because need the notification payload |
|
125 if (!iNegotiation.VerifyInformationalHashL(payload->iHash, payload->iNotifs->At(0), iMessageId)) |
|
126 { |
|
127 DEBUG_LOG(_L("AUTHENTICATION_FAILED (Informational hash)")); |
|
128 iNegotiation.SendNotifyL(AUTHENTICATION_FAILED); |
|
129 } |
|
130 else //Hash OK |
|
131 { |
|
132 i = 0; |
|
133 while ( i < payload->iNotifs->Count() ) |
|
134 { |
|
135 notif_ok = ProcessNotificationL(payload->iNotifs->At(i), ETrue); |
|
136 if ( !notif_ok ) |
|
137 break; |
|
138 i ++; |
|
139 } |
|
140 } |
|
141 } |
|
142 else if ( payload->iDeletes->Count() ) |
|
143 { |
|
144 if (!iNegotiation.VerifyInformationalHashL(payload->iHash, payload->iDeletes->At(0), iMessageId)) |
|
145 { |
|
146 DEBUG_LOG(_L("AUTHENTICATION_FAILED (Informational hash)")); |
|
147 iNegotiation.SendNotifyL(AUTHENTICATION_FAILED); |
|
148 } |
|
149 else |
|
150 { //Hash OK |
|
151 if ( !iNegotiation.iAutoLogin && iNegotiation.iCRACKneg ) |
|
152 iNegotiation.iCRACKneg->CrackAuthenticationFailedL(NULL); |
|
153 if ( !iNegotiation.iAutoLogin && iNegotiation.iTransactionNeg ) |
|
154 iNegotiation.iTransactionNeg->TransactionFailedL(NULL); |
|
155 i = 0; |
|
156 while ( i < payload->iDeletes->Count() ) |
|
157 { |
|
158 notif_ok = ProcessDeleteL(payload->iDeletes->At(0)); |
|
159 if (!notif_ok) |
|
160 break; |
|
161 i ++; |
|
162 } |
|
163 } |
|
164 } |
|
165 else |
|
166 { |
|
167 DEBUG_LOG(_L("PAYLOAD_MALFORMED (no hash or delete payload)")); |
|
168 iNegotiation.SendNotifyL(PAYLOAD_MALFORMED); |
|
169 } |
|
170 } |
|
171 else //No hash sent |
|
172 { |
|
173 if (aHdr.GetFlags() & ISAKMP_HDR_EFLAG) //if encrypted |
|
174 { |
|
175 DEBUG_LOG(_L("PAYLOAD_MALFORMED (Hash required)")); |
|
176 iNegotiation.SendNotifyL(PAYLOAD_MALFORMED); |
|
177 } |
|
178 else //Not encrypted so not hash required |
|
179 { |
|
180 i = 0; |
|
181 while ( i < payload->iNotifs->Count() ) |
|
182 { |
|
183 notif_ok = ProcessNotificationL(payload->iNotifs->At(i), EFalse); |
|
184 if ( !notif_ok ) |
|
185 break; |
|
186 i ++; |
|
187 } |
|
188 } |
|
189 } |
|
190 |
|
191 if ( notif_ok ) { |
|
192 const TNotificationISAKMP* notif = NULL; |
|
193 if ( payload->iNotifs->Count() ) |
|
194 notif = payload->iNotifs->At(0); |
|
195 if ( iNegotiation.iCRACKneg ) { |
|
196 if ( !iNegotiation.iAutoLogin ) |
|
197 iNegotiation.iCRACKneg->CrackAuthenticationFailedL(notif); |
|
198 iNegotiation.SetErrorStatus(KKmdIkeAuthFailedErr); |
|
199 iNegotiation.AcquireSAErrorResponse(KKmdIkeAuthFailedErr); |
|
200 } |
|
201 if ( iNegotiation.iTransactionNeg ) { |
|
202 if ( !iNegotiation.iAutoLogin ) |
|
203 iNegotiation.iTransactionNeg->TransactionFailedL(notif); |
|
204 iNegotiation.SetErrorStatus(KKmdIkeAuthFailedErr); |
|
205 iNegotiation.AcquireSAErrorResponse(KKmdIkeAuthFailedErr); |
|
206 } |
|
207 } |
|
208 |
|
209 CleanupStack::PopAndDestroy(); //payload |
|
210 |
|
211 } |
|
212 |
|
213 |
|
214 //Handles Notification Payload |
|
215 TBool CIkev1InfoNegotiation::ProcessNotificationL(const TPayloadISAKMP *aPayload, TBool aEncrypted) |
|
216 { |
|
217 #ifdef _DEBUG |
|
218 TBuf<80> str; |
|
219 #endif // _DEBUG |
|
220 TNotificationISAKMP *notif = TNotificationISAKMP::Ptr(aPayload); |
|
221 if (!iNegotiation.CheckDOI(notif->GetDOI())) |
|
222 { |
|
223 DEBUG_LOG(_L("DOI_NOT_SUPPORTED in NOT Payload Message.")); |
|
224 return EFalse; |
|
225 } |
|
226 TBool Status; |
|
227 TUint16 MsgType = notif->GetMsgType(); |
|
228 |
|
229 if ( (MsgType == DPD_R_U_THERE || MsgType == DPD_R_U_THERE_ACK) && aEncrypted ) |
|
230 { |
|
231 return ProcessDPDNotifyL(notif); |
|
232 } |
|
233 |
|
234 if ( MsgType <= UNEQUAL_PAYLOAD_LENGTHS ) |
|
235 { |
|
236 #ifdef _DEBUG |
|
237 str.Copy(_L("Error/Status Type: ")); |
|
238 #endif // _DEBUG |
|
239 Status = ETrue; |
|
240 iNegotiation.SetNotifyStatus(MsgType); |
|
241 |
|
242 LOG_KMD_EVENT( MKmdEventLoggerIf::KLogError, |
|
243 R_VPN_MSG_VPN_GW_ERR_RESP_RECEIVED, |
|
244 MsgType, |
|
245 iPluginSession.VpnIapId(), |
|
246 &(iNegotiation.iRemoteAddr) ); |
|
247 } |
|
248 else |
|
249 { |
|
250 #ifdef _DEBUG |
|
251 str.Copy(_L("Unexpected info notification: ")); |
|
252 #endif // _DEBUG |
|
253 Status = EFalse; |
|
254 } |
|
255 #ifdef _DEBUG |
|
256 str.Append(CIkev1Negotiation::TextNotifyType(MsgType)); |
|
257 DEBUG_LOG(str); |
|
258 #endif // _DEBUG |
|
259 return Status; |
|
260 } |
|
261 |
|
262 // |
|
263 // Process DPD R-U_THERE / R-U-THERE-ACK |
|
264 // When a R-U-THERE notify received it processes as follows: |
|
265 // -- Find an ISAKMP SA with SPI in notify message |
|
266 // -- Pass DPD notify message for further processing into |
|
267 // CIkev1Negotiation::NotifyMessageReceived() via iNegotiation reference |
|
268 // |
|
269 TBool CIkev1InfoNegotiation::ProcessDPDNotifyL(TNotificationISAKMP* aNotify) |
|
270 { |
|
271 |
|
272 if ( aNotify->GetSPISize() == (2 * ISAKMP_COOKIE_SIZE) && (aNotify->GetNotifDataSize() == 4)) |
|
273 { |
|
274 TCookie cookie_I, cookie_R; |
|
275 cookie_I.Copy(aNotify->GetSPI(), ISAKMP_COOKIE_SIZE); |
|
276 cookie_R.Copy((aNotify->GetSPI() + ISAKMP_COOKIE_SIZE), ISAKMP_COOKIE_SIZE); |
|
277 |
|
278 TIkev1SAData* Sa = iPluginSession.FindIkev1SAData(cookie_I, cookie_R); |
|
279 if ( !Sa ) |
|
280 { |
|
281 Sa = iPluginSession.FindIkev1SAData(cookie_R, cookie_I); |
|
282 #ifdef _DEBUG |
|
283 if (Sa) DEBUG_LOG(_L("ISAKMP SA found for DPD notify message with CKY_R+CKY_I")); |
|
284 #endif // _DEBUG |
|
285 } |
|
286 if ( Sa && Sa->iDPDSupported ) |
|
287 { |
|
288 TUint32 Sequence = GET32(aNotify->GetNotifData()); |
|
289 iNegotiation.DpdNotifyMessageReceivedL(Sa, aNotify->GetMsgType(), Sequence); |
|
290 } |
|
291 #ifdef _DEBUG |
|
292 else DEBUG_LOG(_L("No ISAKMP SA found for DPD notify message")); |
|
293 #endif // _DEBUG |
|
294 } |
|
295 #ifdef _DEBUG |
|
296 else DEBUG_LOG(_L("Illegal SPI- or notify data length in DPD message")); |
|
297 #endif // _DEBUG |
|
298 |
|
299 return EFalse; |
|
300 } |
|
301 |
|
302 //Handles Delete Payload |
|
303 TBool CIkev1InfoNegotiation::ProcessDeleteL(const TPayloadISAKMP *aPayload) |
|
304 { |
|
305 TDeleteISAKMP *delete_payload = TDeleteISAKMP::Ptr(aPayload); |
|
306 |
|
307 #ifdef _DEBUG |
|
308 TBuf<1200> msg; |
|
309 DEBUG_LOG(_L("Delete Payload received!!!")); |
|
310 delete_payload->String(msg); |
|
311 DEBUG_LOG(msg); |
|
312 #endif // _DEBUG |
|
313 if (!iNegotiation.CheckDOI(delete_payload->DOI())) |
|
314 { |
|
315 DEBUG_LOG(_L("DOI_NOT_SUPPORTED in delete payload")); |
|
316 return EFalse; |
|
317 } |
|
318 |
|
319 TUint8 protocol = delete_payload->Protocol(); |
|
320 TUint32 spi; |
|
321 TInetAddr remote_addr(iNegotiation.iRemoteAddr); |
|
322 remote_addr.SetPort(KInetPortAny); |
|
323 |
|
324 TInt err = KErrNone; |
|
325 if ( protocol == PROTO_ISAKMP ) |
|
326 { |
|
327 iPluginSession.DeleteISAKMPSAsL( delete_payload, iNegotiation ); |
|
328 } |
|
329 else //IPSEC AH or ESP (others will be discarded by the kernel) |
|
330 { |
|
331 if (delete_payload->SPISize() != sizeof(TUint32)) |
|
332 { |
|
333 DEBUG_LOG(_L("Bad SPI Size for a IPsec SA. (SA Not deleted)")); |
|
334 } |
|
335 TIpsecSPI IpsecSpi; |
|
336 for (TInt i=0; i < delete_payload->NumSPI(); i++) //Shouldn't be more than one |
|
337 { |
|
338 Mem::Copy((TUint8*)&spi, delete_payload->SPI(i),sizeof(TUint32)); |
|
339 if (err == KErrNone) |
|
340 { |
|
341 //The right one is the Outbound(Local->Remote) one to avoid sending when deleted at the other side |
|
342 //The opposite if sending a Delete |
|
343 IpsecSpi.iSrcAddr = iNegotiation.iLocalAddr; |
|
344 IpsecSpi.iDstAddr = remote_addr; |
|
345 IpsecSpi.iSPI = spi; |
|
346 IpsecSpi.iProtocol = protocol; |
|
347 IpsecSpi.iInbound = EFalse; |
|
348 if (iPluginSession.DeleteIpsecSpi(iNegotiation.SAId(), spi, EFalse)) |
|
349 { |
|
350 DEBUG_LOG(_L("Deleting IPsec SA")); |
|
351 iPluginSession.DeleteIpsecSA(IpsecSpi.iSPI, IpsecSpi.iSrcAddr, IpsecSpi.iDstAddr, |
|
352 IpsecSpi.iProtocol); |
|
353 } |
|
354 } |
|
355 else |
|
356 { |
|
357 DEBUG_LOG1(_L("IPsec SA with SPI=%x not deleted"), ByteOrder::Swap32(spi)); |
|
358 } |
|
359 } |
|
360 } |
|
361 |
|
362 return ETrue; |
|
363 } |