|
1 /* |
|
2 * Copyright (c) 2003-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: IKEv2 Proposal handling. |
|
15 * |
|
16 */ |
|
17 |
|
18 |
|
19 #include <e32math.h> |
|
20 #include <in_sock.h> |
|
21 #include "ikedebug.h" |
|
22 #include "ikev2proposal.h" |
|
23 #include "ikev2SAdata.h" |
|
24 #include "ikev2payloads.h" |
|
25 #include "ikemsgrec.h" |
|
26 #include "ikev2const.h" |
|
27 #include "ikev2plugin.h" |
|
28 #include "ikepolparser.h" |
|
29 #include "ikev2identity.h" |
|
30 #include "ikev2ipsecsadata.h" |
|
31 #include "ikev2Negotiation.h" |
|
32 #include <networking/pfkeyv2.h> |
|
33 |
|
34 HBufC8* Ikev2Proposal::FromPolicyToProposaL(TIkev2SAData& aIkeSaData, |
|
35 const TDesC8& aRekeySpi, |
|
36 TInt aDHGroupGuess, |
|
37 TBool aRekey) |
|
38 { |
|
39 // |
|
40 // Build IKE SA proposal from IKE policy data |
|
41 // Because proposal information is presented as "IKEv1" |
|
42 // proposals in policy these are presented as sequence of |
|
43 // proposals. All these transforms contains 4 different type transform |
|
44 // payloads. |
|
45 // |
|
46 TProposalData* PropList = aIkeSaData.iIkeData->iPropList; |
|
47 |
|
48 if ( !aRekey ) |
|
49 { |
|
50 aIkeSaData.iEAPType = aIkeSaData.iIkeData->iEAPProtocol; |
|
51 } |
|
52 |
|
53 if (!PropList) |
|
54 { |
|
55 User::LeaveIfNull(PropList); |
|
56 } |
|
57 |
|
58 HBufC8* saData = HBufC8::NewL(512); //512 should be enough for all Proposals |
|
59 |
|
60 TUint8 PropNum = 1; |
|
61 TUint16 SaLth = 0; |
|
62 TUint16 PropLth; |
|
63 TUint16 TranLth; |
|
64 TUint16 PRF; |
|
65 TUint16 DHGroup; |
|
66 |
|
67 TProposalIkev2* Proposal = TProposalIkev2::Cast(saData->Ptr()); |
|
68 TProposalIkev2* Next = Proposal; |
|
69 TTransformIkev2* Transform; |
|
70 TDataAttributes* Attributes; |
|
71 |
|
72 while ( PropList ) |
|
73 { |
|
74 |
|
75 Proposal = Next; |
|
76 TPayloadIkev2::Cast(Proposal)->Init(); // Initialize Payload general header |
|
77 TPayloadIkev2::Cast(Proposal)->SetNextPayload(IKEV2_PAYLOAD_PROP); |
|
78 Proposal->SetNum(PropNum); |
|
79 Proposal->SetProtocol(IKEV2_PROTOCOL); |
|
80 if ( aRekey ) |
|
81 { |
|
82 Proposal->SetSPISize(IKEV2_SPI_SIZE); |
|
83 Mem::Copy(Proposal->SPI(), aRekeySpi.Ptr(), IKEV2_SPI_SIZE); |
|
84 } |
|
85 else Proposal->SetSPISize(0); |
|
86 Proposal->SetNumTrans(4); |
|
87 PropLth = (TUint16)Proposal->PropHdrLth(); |
|
88 |
|
89 Transform = Proposal->TransformPl(); |
|
90 TPayloadIkev2::Cast(Transform)->Init(); // Initialize Payload general header |
|
91 TPayloadIkev2::Cast(Transform)->SetNextPayload(IKEV2_PAYLOAD_TRANS); |
|
92 Transform->SetType(IKEV2_ENCR); // Encryption Algorithm transform (1) |
|
93 Transform->SetReserved(); |
|
94 TranLth = (TUint16)Transform->Size(); |
|
95 |
|
96 switch ( PropList->iEncrAlg ) |
|
97 { |
|
98 case IKE_PARSER_DES_CBC: |
|
99 Transform->SetID(ENCR_DES); |
|
100 break; |
|
101 case IKE_PARSER_DES3_CBC: |
|
102 Transform->SetID(ENCR_3DES); |
|
103 break; |
|
104 case IKE_PARSER_AES_CBC: |
|
105 Transform->SetID(ENCR_AES_CBC); |
|
106 // |
|
107 // Add key length attribute to transform data |
|
108 // |
|
109 Transform->SetID(ENCR_AES_CBC); |
|
110 Attributes = Transform->Attributes(); |
|
111 Attributes->SetType(IKEV2_ENCR_KEY_LTH); |
|
112 Attributes->SetBasic(); |
|
113 if (PropList->iEncrKeyLth) |
|
114 Attributes->SetValue((TUint16)PropList->iEncrKeyLth); |
|
115 else Attributes->SetValue(128); //default AES key size |
|
116 TranLth = (TUint16)(TranLth + Attributes->Size()); |
|
117 break; |
|
118 default: |
|
119 Transform->SetID(ENCR_3DES); // Use 3DES as default |
|
120 break; |
|
121 } |
|
122 TPayloadIkev2::Cast(Transform)->SetLength(TranLth); |
|
123 PropLth = (TUint16)(PropLth + TranLth); |
|
124 |
|
125 Transform = (TTransformIkev2*)TPayloadIkev2::Cast(Transform)->Next(); |
|
126 TPayloadIkev2::Cast(Transform)->Init(); // Initialize Payload general header |
|
127 TPayloadIkev2::Cast(Transform)->SetNextPayload(IKEV2_PAYLOAD_TRANS); |
|
128 Transform->SetType(IKEV2_INTEG); // Integrity Algorithm (3) |
|
129 Transform->SetReserved(); |
|
130 TranLth = (TUint16)Transform->Size(); |
|
131 |
|
132 switch ( PropList->iHashAlg ) |
|
133 { |
|
134 case IKE_PARSER_MD5: |
|
135 Transform->SetID(AUTH_HMAC_MD5_96); |
|
136 PRF = IKE_PARSER_MD5; |
|
137 break; |
|
138 case IKE_PARSER_SHA1: |
|
139 Transform->SetID(AUTH_HMAC_SHA1_96); |
|
140 PRF = IKE_PARSER_SHA1; |
|
141 break; |
|
142 default: |
|
143 Transform->SetID(AUTH_HMAC_SHA1_96); |
|
144 PRF = IKE_PARSER_SHA1; |
|
145 break; |
|
146 } |
|
147 TPayloadIkev2::Cast(Transform)->SetLength(TranLth); |
|
148 PropLth = (TUint16)(PropLth + TranLth); |
|
149 |
|
150 Transform = (TTransformIkev2*)TPayloadIkev2::Cast(Transform)->Next(); |
|
151 TPayloadIkev2::Cast(Transform)->Init(); // Initialize Payload general header |
|
152 TPayloadIkev2::Cast(Transform)->SetNextPayload(IKEV2_PAYLOAD_TRANS); |
|
153 Transform->SetType(IKEV2_PRF); // Pseudo-random Function (2) |
|
154 Transform->SetReserved(); |
|
155 TranLth = (TUint16)Transform->Size(); |
|
156 |
|
157 if ( PropList->iPRF ) |
|
158 PRF = PropList->iPRF; |
|
159 switch ( PRF ) |
|
160 { |
|
161 case IKE_PARSER_MD5: |
|
162 Transform->SetID(PRF_HMAC_MD5); |
|
163 break; |
|
164 case IKE_PARSER_SHA1: |
|
165 Transform->SetID(PRF_HMAC_SHA1); |
|
166 break; |
|
167 default: |
|
168 Transform->SetID(AUTH_HMAC_SHA1_96); |
|
169 break; |
|
170 } |
|
171 TPayloadIkev2::Cast(Transform)->SetLength(TranLth); |
|
172 PropLth = (TUint16)(PropLth + TranLth); |
|
173 |
|
174 |
|
175 Transform = (TTransformIkev2*)TPayloadIkev2::Cast(Transform)->Next(); |
|
176 TPayloadIkev2::Cast(Transform)->Init(); // Initialize Payload general header |
|
177 TPayloadIkev2::Cast(Transform)->SetNextPayload(IKEV2_PAYLOAD_NONE); |
|
178 Transform->SetType(IKEV2_DH); // Diffie-Hellman Group (4) |
|
179 Transform->SetReserved(); |
|
180 TranLth = (TUint16)Transform->Size(); |
|
181 |
|
182 |
|
183 DHGroup = (PropList->iGroupDesc == 0) ? aIkeSaData.iIkeData->iGroupDesc_II : |
|
184 PropList->iGroupDesc; |
|
185 |
|
186 DHGroup = Ikev2Proposal::GetDHGroup(DHGroup); |
|
187 Transform->SetID(DHGroup); |
|
188 TPayloadIkev2::Cast(Transform)->SetLength(TranLth); |
|
189 |
|
190 if ( PropNum == aDHGroupGuess) |
|
191 { |
|
192 if (aIkeSaData.iDHGroup == 0) |
|
193 aIkeSaData.iDHGroup = DHGroup; // Preferred group for initial KE payload |
|
194 switch ( PropList->iAuthMeth ) |
|
195 { |
|
196 case IKE_PARSER_DSS_SIG: |
|
197 aIkeSaData.iAuthMethod = DSS_DIGITAL_SIGN; |
|
198 break; |
|
199 |
|
200 case IKE_PARSER_RSA_SIG: |
|
201 case IKE_PARSER_RSA_REV_ENCR: |
|
202 aIkeSaData.iAuthMethod = RSA_DIGITAL_SIGN; |
|
203 break; |
|
204 |
|
205 default: |
|
206 aIkeSaData.iAuthMethod = PRESHARED_KEY; |
|
207 break; |
|
208 |
|
209 } |
|
210 } |
|
211 |
|
212 if ( aIkeSaData.iLifetime == 0 ) |
|
213 aIkeSaData.iLifetime = PropList->iLifetimeSec; // Init lifetime |
|
214 else if ( PropList->iLifetimeSec && (aIkeSaData.iLifetime > PropList->iLifetimeSec) ) |
|
215 aIkeSaData.iLifetime = PropList->iLifetimeSec; // Take shorter time |
|
216 |
|
217 PropLth = (TUint16)(PropLth + TranLth); |
|
218 SaLth = (TUint16)(SaLth + PropLth); |
|
219 TPayloadIkev2::Cast(Proposal)->SetLength(PropLth); |
|
220 |
|
221 PropNum ++; |
|
222 Next = (TProposalIkev2*)TPayloadIkev2::Cast(Proposal)->Next(); |
|
223 PropList = PropList->iNext; |
|
224 } |
|
225 |
|
226 if ( aIkeSaData.iLifetime == 0 ) |
|
227 aIkeSaData.iLifetime = IKEV2_DEF_LIFETIME; |
|
228 TPayloadIkev2::Cast(Proposal)->SetNextPayload(IKEV2_PAYLOAD_NONE); |
|
229 |
|
230 saData->Des().SetLength(SaLth); |
|
231 |
|
232 return saData; |
|
233 |
|
234 } |
|
235 |
|
236 HBufC8* Ikev2Proposal::GetPSKFromPolicyL(CIkeData* aHostData) |
|
237 { |
|
238 ASSERT(aHostData); |
|
239 // |
|
240 // Get Preshared Key from IKE policy and return in to caller in |
|
241 // HBufc8. |
|
242 // |
|
243 HBufC8 *PSK = NULL; |
|
244 if ( aHostData->iPresharedKey.iFormat == STRING_KEY ) |
|
245 { |
|
246 PSK = HBufC8::NewL(aHostData->iPresharedKey.iKey.Length()); |
|
247 PSK->Des().Copy(aHostData->iPresharedKey.iKey); |
|
248 } |
|
249 else if ( aHostData->iPresharedKey.iFormat == HEX_KEY ) |
|
250 { |
|
251 PSK = HBufC8::NewL(aHostData->iPresharedKey.iKey.Length() / 2); |
|
252 |
|
253 |
|
254 for(TInt i = 0; i < aHostData->iPresharedKey.iKey.Length(); i += 2) |
|
255 { |
|
256 TPtrC hexByte(aHostData->iPresharedKey.iKey.Mid(i, 2)); |
|
257 TLex lex(hexByte); |
|
258 TUint8 value; |
|
259 User::LeaveIfError(lex.Val(value, EHex)); |
|
260 |
|
261 PSK->Des().Append(&value, 1); |
|
262 } |
|
263 |
|
264 } |
|
265 |
|
266 return PSK; |
|
267 } |
|
268 |
|
269 TUint16 Ikev2Proposal::GetDHGroup(TInt aDHGroup) |
|
270 { |
|
271 // |
|
272 // Map DH group Enum value used in IKE policy to the real DH group |
|
273 // transform type value used in IKEv2 negotiation |
|
274 // If aDHGroup parameter is not defined mapping is done to |
|
275 // iGroupDesc_II data member value in CIkeData |
|
276 // |
|
277 TUint16 DHTransId = 0; |
|
278 switch ( aDHGroup ) |
|
279 { |
|
280 case IKE_PARSER_MODP_768: |
|
281 DHTransId = DH_GROUP_768; |
|
282 break; |
|
283 case IKE_PARSER_MODP_1024: |
|
284 DHTransId = DH_GROUP_1024; |
|
285 break; |
|
286 case IKE_PARSER_MODP_1536: |
|
287 DHTransId = DH_GROUP_1536; |
|
288 break; |
|
289 case IKE_PARSER_MODP_2048: |
|
290 DHTransId = DH_GROUP_2048; |
|
291 break; |
|
292 default: |
|
293 break; |
|
294 } |
|
295 |
|
296 return DHTransId; |
|
297 } |
|
298 |
|
299 HBufC8* Ikev2Proposal::BuildSaResponseL(TProposalIkev2* aAcceptedProp, CIkev2Payloads* aAcceptedTrans) |
|
300 { |
|
301 ASSERT(aAcceptedProp && aAcceptedTrans); |
|
302 HBufC8* SaRespBfr = HBufC8::NewL(256); //256 should be enough response |
|
303 |
|
304 // |
|
305 // Build SA response payload based on Transform payloads which are |
|
306 // marked to be "SELECTED" in request proposal |
|
307 // |
|
308 TProposalIkev2* Proposal = TProposalIkev2::Cast(const_cast<TUint8*>(SaRespBfr->Ptr())); |
|
309 TUint16 PropLth = (TUint16)aAcceptedProp->PropHdrLth(); |
|
310 Mem::Copy((TUint8*)Proposal, (TUint8*)aAcceptedProp, PropLth); |
|
311 |
|
312 TTransformIkev2* Transform = Proposal->TransformPl(); |
|
313 TTransformIkev2* LastTrans = Transform; |
|
314 TTransformIkev2* AccTransform; |
|
315 TUint8 NbrOfTransforms = 0; |
|
316 TInt TranCount = aAcceptedTrans->iTrans->Count(); |
|
317 for ( TInt i = 0; i < TranCount; ++i ) |
|
318 { |
|
319 AccTransform = (TTransformIkev2*)aAcceptedTrans->iTrans->At(i); |
|
320 if ( AccTransform->IsSelected() ) |
|
321 { |
|
322 NbrOfTransforms ++; |
|
323 Mem::Copy((TUint8*)Transform, (TUint8*)AccTransform, TPayloadIkev2::Cast(AccTransform)->GetLength()); |
|
324 Transform->NotSelected(); // Reset selected bit ! |
|
325 PropLth = (TUint16)(PropLth + TPayloadIkev2::Cast(AccTransform)->GetLength()); |
|
326 TPayloadIkev2::Cast(Transform)->SetNextPayload(IKEV2_PAYLOAD_TRANS); |
|
327 LastTrans = Transform; |
|
328 Transform = (TTransformIkev2*)TPayloadIkev2::Cast(Transform)->Next(); |
|
329 } |
|
330 } |
|
331 TPayloadIkev2::Cast(LastTrans)->SetNextPayload(IKEV2_PAYLOAD_NONE); |
|
332 TPayloadIkev2::Cast(Proposal)->SetNextPayload(IKEV2_PAYLOAD_NONE); |
|
333 TPayloadIkev2::Cast(Proposal)->SetLength(PropLth); |
|
334 Proposal->SetNumTrans(NbrOfTransforms); |
|
335 SaRespBfr->Des().SetLength(PropLth); |
|
336 |
|
337 return SaRespBfr; |
|
338 } |
|
339 |
|
340 |
|
341 TBool Ikev2Proposal::GetSelectedProposalData(TIkev2SAData& aIkev2SaData, |
|
342 TIkeV2IpsecSAData& aChildSaData, |
|
343 const CIkev2Payloads& aAcceptedProp, |
|
344 const TProposalIkev2& aProp) |
|
345 { |
|
346 // |
|
347 // Get IKE SA algorithm information from Transform payload which are |
|
348 // marked to be "SELECTED" |
|
349 // |
|
350 TTransformIkev2* Transform; |
|
351 TDataAttributes* Attribute; |
|
352 TUint16 EncrAlg; |
|
353 TInt KeyLth; |
|
354 TUint8 ExistingTypes = 0; |
|
355 TUint8 RequiredTypes; |
|
356 TUint8 Protocol = aProp.GetProtocol(); |
|
357 switch ( Protocol ) |
|
358 { |
|
359 case IKEV2_IPSEC_AH: |
|
360 { |
|
361 RequiredTypes = (1 << IKEV2_INTEG); |
|
362 aChildSaData.iSaType = SADB_SATYPE_AH; |
|
363 TUint32 spi = 0; |
|
364 aProp.GetIpsecSPI(&spi); |
|
365 aChildSaData.iSPI_Out = TPtrC8(reinterpret_cast<TUint8*>(&spi), sizeof(spi)); |
|
366 } |
|
367 break; |
|
368 case IKEV2_IPSEC_ESP: |
|
369 { |
|
370 RequiredTypes = (1 << IKEV2_ENCR); |
|
371 aChildSaData.iSaType = SADB_SATYPE_ESP; |
|
372 TUint32 spi = 0; |
|
373 aProp.GetIpsecSPI(&spi); |
|
374 aChildSaData.iSPI_Out = TPtrC8(reinterpret_cast<TUint8*>(&spi), sizeof(spi)); |
|
375 } |
|
376 break; |
|
377 default: //IKEV2_PROTOCOL: |
|
378 RequiredTypes = ((1 << IKEV2_ENCR) | (1 << IKEV2_PRF) | (1 << IKEV2_INTEG) | (1 << IKEV2_DH)); |
|
379 break; |
|
380 } |
|
381 |
|
382 TInt TranCount = aAcceptedProp.iTrans->Count(); |
|
383 |
|
384 for ( TInt i = 0; i < TranCount; ++i ) |
|
385 { |
|
386 Transform = (TTransformIkev2*)aAcceptedProp.iTrans->At(i); |
|
387 if ( Transform->IsSelected() ) |
|
388 { |
|
389 Transform->NotSelected(); // Reset private "selected" bit |
|
390 switch ( Transform->GetType() ) |
|
391 { |
|
392 case IKEV2_ENCR: |
|
393 ExistingTypes |= (1 << IKEV2_ENCR); |
|
394 EncrAlg = Transform->GetID(); |
|
395 if ( Protocol == IKEV2_PROTOCOL ) |
|
396 aIkev2SaData.iEncrAlg = EncrAlg; |
|
397 else aChildSaData.iEncrAlg = EncrAlg; |
|
398 if ( EncrAlg == ENCR_AES_CBC ) |
|
399 { |
|
400 // |
|
401 // Get encryption key length from attributes |
|
402 // (or use default key length 128 bit) |
|
403 // |
|
404 if ( TPayloadIkev2::Cast(Transform)->GetLength() > Transform->Size() ) |
|
405 { |
|
406 Attribute = Transform->Attributes(); |
|
407 KeyLth = (Attribute->GetValue() >> 3); // byte length |
|
408 } |
|
409 else KeyLth = 16; // default: 16 bytes = 128 bits |
|
410 if ( Protocol == IKEV2_PROTOCOL ) |
|
411 aIkev2SaData.iCipherKeyLth = KeyLth; |
|
412 else aChildSaData.iCipherKeyLth = KeyLth; |
|
413 } |
|
414 break; |
|
415 |
|
416 case IKEV2_PRF: |
|
417 ExistingTypes |= (1 << IKEV2_PRF); |
|
418 if ( Protocol == IKEV2_PROTOCOL ) |
|
419 aIkev2SaData.iPRFAlg = Transform->GetID(); |
|
420 break; |
|
421 |
|
422 case IKEV2_INTEG: |
|
423 ExistingTypes |= (1 << IKEV2_INTEG); |
|
424 if ( Protocol == IKEV2_PROTOCOL ) |
|
425 aIkev2SaData.iIntegAlg = Transform->GetID(); |
|
426 else aChildSaData.iIntegAlg = Transform->GetID(); |
|
427 break; |
|
428 |
|
429 case IKEV2_DH: |
|
430 ExistingTypes |= (1 << IKEV2_DH); |
|
431 if ( Protocol == IKEV2_PROTOCOL ) |
|
432 aIkev2SaData.iDHGroup = Transform->GetID(); |
|
433 break; |
|
434 |
|
435 case IKEV2_ESN: |
|
436 ExistingTypes |= (1 << IKEV2_ESN); |
|
437 if ( Protocol != IKEV2_PROTOCOL ) |
|
438 aChildSaData.iESN = (TUint8)Transform->GetID(); |
|
439 break; |
|
440 |
|
441 default: |
|
442 break; |
|
443 |
|
444 } |
|
445 } |
|
446 |
|
447 } |
|
448 |
|
449 return ((RequiredTypes & ExistingTypes) == RequiredTypes); |
|
450 } |
|
451 |
|
452 TBool Ikev2Proposal::VerifySaResponseL(TIkev2SAData& aIkeSaData, |
|
453 TIkeV2IpsecSAData& aIpsecSaData, |
|
454 const TDesC8& aReferenceSaData, |
|
455 const CIkev2Payloads& aRespProp) |
|
456 { |
|
457 // |
|
458 // Verify content of an IKE SA response to proposed IKE SA transform |
|
459 // list. The IKE SA proposal selected by peer MUST contain one |
|
460 // proposal and transform selected from our SA proposal |
|
461 // |
|
462 if ( aRespProp.iProps->Count() != 1 ) |
|
463 return EFalse; |
|
464 |
|
465 TBool Status = EFalse; |
|
466 TPtrC8 unprocessedReferenceSaData(aReferenceSaData); |
|
467 |
|
468 while(!Status && unprocessedReferenceSaData.Length() > 0) |
|
469 { |
|
470 TPayloadIkev2* referenceProposal = TPayloadIkev2::Cast(unprocessedReferenceSaData.Ptr()); |
|
471 CIkev2Payloads* OwnProp = CIkev2Payloads::NewL(referenceProposal, IKEV2_PAYLOAD_PROP, aIkeSaData); |
|
472 CleanupStack::PushL(OwnProp); |
|
473 |
|
474 //Something is seriously wrong, if we can't parse our own reference data |
|
475 __ASSERT_DEBUG(OwnProp->Status() == KErrNone, User::Invariant()); |
|
476 |
|
477 TProposalIkev2* Prop = (TProposalIkev2*)aRespProp.iProps->At(0); |
|
478 Status = Ikev2Proposal::VerifyProposaL(OwnProp, Prop, aIkeSaData); |
|
479 if ( Status ) |
|
480 { |
|
481 Status = Ikev2Proposal::GetSelectedProposalData(aIkeSaData, aIpsecSaData, aRespProp, *Prop); |
|
482 } |
|
483 CleanupStack::PopAndDestroy(OwnProp); |
|
484 unprocessedReferenceSaData.Set(unprocessedReferenceSaData.Mid(referenceProposal->GetLength())); |
|
485 } |
|
486 |
|
487 return Status; |
|
488 } |
|
489 |
|
490 TBool Ikev2Proposal::VerifySaRequestAndGetProposedSaBufferL(TIkev2SAData& aIkeSaData, |
|
491 TIkeV2IpsecSAData& aIpsecSaData, |
|
492 const TDesC8& aReferenceSaData, |
|
493 const CIkev2Payloads& aProposed, |
|
494 HBufC8*& aProposedSaBuffer) |
|
495 { |
|
496 __ASSERT_DEBUG(aReferenceSaData.Length() > 0, User::Invariant()); |
|
497 |
|
498 |
|
499 // |
|
500 // Verify content of an IKE SA request against a reference |
|
501 // proposals built according to the local policy. |
|
502 // |
|
503 if ( !aProposed.iSa ) |
|
504 return EFalse; |
|
505 |
|
506 TBool Status = EFalse; |
|
507 TPtrC8 unprocessedReferenceSaData(aReferenceSaData); |
|
508 while (!Status && unprocessedReferenceSaData.Length() > 0) |
|
509 { |
|
510 TPayloadIkev2* referenceSa = TPayloadIkev2::Cast(unprocessedReferenceSaData.Ptr()); |
|
511 unprocessedReferenceSaData.Set(unprocessedReferenceSaData.Mid(referenceSa->GetLength())); |
|
512 CIkev2Payloads* OwnProp = CIkev2Payloads::NewL(referenceSa, IKEV2_PAYLOAD_PROP, aIkeSaData); |
|
513 //If we can't parse our own reference proposal something is seriously wrong. |
|
514 __ASSERT_DEBUG(OwnProp->Status() == KErrNone, User::Invariant()); |
|
515 CleanupStack::PushL(OwnProp); |
|
516 |
|
517 |
|
518 CIkev2Payloads* PeerProp = CIkev2Payloads::NewL((TPayloadIkev2*)aProposed.iSa, IKEV2_PAYLOAD_SA, aIkeSaData); |
|
519 CleanupStack::PushL(PeerProp); |
|
520 Status = (PeerProp->Status() == KErrNone); |
|
521 if ( Status ) |
|
522 { |
|
523 Status = EFalse; |
|
524 TInt PropCount = PeerProp->iProps->Count(); |
|
525 for ( TInt i = 0; i < PropCount; ++i ) |
|
526 { |
|
527 TProposalIkev2* Prop = (TProposalIkev2*)PeerProp->iProps->At(i); |
|
528 Status = Ikev2Proposal::VerifyProposaL(OwnProp, Prop, aIkeSaData); |
|
529 if ( Status ) |
|
530 { |
|
531 // |
|
532 // Build SA response payload and pick up algorithm |
|
533 // information into negotiation object |
|
534 // |
|
535 |
|
536 HBufC8* SaRespBfr = NULL; |
|
537 TRAPD(err, SaRespBfr = Ikev2Proposal::BuildSaResponseL(Prop, PeerProp)); |
|
538 if (err == KErrNone) |
|
539 { |
|
540 aProposedSaBuffer = SaRespBfr; |
|
541 Status = Ikev2Proposal::GetSelectedProposalData(aIkeSaData, aIpsecSaData, *PeerProp, *Prop); |
|
542 } |
|
543 else |
|
544 { |
|
545 Status = EFalse; |
|
546 } |
|
547 break; |
|
548 } |
|
549 } |
|
550 } |
|
551 CleanupStack::PopAndDestroy(PeerProp); |
|
552 CleanupStack::PopAndDestroy(OwnProp); |
|
553 } |
|
554 return Status; |
|
555 } |
|
556 |
|
557 TBool Ikev2Proposal::IkeSaRekey(CIkev2Payloads* aIkeMsg) |
|
558 { |
|
559 ASSERT(aIkeMsg); |
|
560 // |
|
561 // Check is the current IKE message an IKE SA rekey request |
|
562 // Should be format: HDR(A,B), SK { SA, Ni, KEi } |
|
563 // where proposal protcol should be IKEV2_PROTOCOL |
|
564 // |
|
565 TBool Status = EFalse; |
|
566 if ( aIkeMsg->iProps->Count() && !aIkeMsg->iTsI && !aIkeMsg->iTsR ) |
|
567 { |
|
568 TProposalIkev2* Prop = (TProposalIkev2*)aIkeMsg->iProps->At(0); |
|
569 Status = (Prop->GetProtocol() == IKEV2_PROTOCOL); |
|
570 } |
|
571 return Status; |
|
572 } |
|
573 |
|
574 TBool Ikev2Proposal::GetRekeySpi(CIkev2Payloads* aIkeMsg, TIkeSPI& aSPI) |
|
575 { |
|
576 ASSERT(aIkeMsg); |
|
577 // |
|
578 // Get remote ends IKE SPI from the first Proposal of IKE message |
|
579 // |
|
580 TBool Status = EFalse; |
|
581 if ( aIkeMsg->iProps->Count() ) |
|
582 { |
|
583 TProposalIkev2* Proposal = (TProposalIkev2*)aIkeMsg->iProps->At(0); |
|
584 if ( Proposal->GetSPISize() == IKEV2_SPI_SIZE ) |
|
585 { |
|
586 Mem::Copy( (TUint8*)aSPI.Ptr(), Proposal->SPI(), IKEV2_SPI_SIZE); |
|
587 Status = ETrue; |
|
588 } |
|
589 } |
|
590 return Status; |
|
591 } |
|
592 |
|
593 void Ikev2Proposal::ChangeSpiInProposal(HBufC8* aSaBfr, TIkeSPI& aSPI) |
|
594 { |
|
595 ASSERT(aSaBfr); |
|
596 TProposalIkev2* Proposal = TProposalIkev2::Cast(aSaBfr->Ptr()); |
|
597 Mem::Copy(Proposal->SPI(), (TUint8*)aSPI.Ptr(), IKEV2_SPI_SIZE); |
|
598 } |
|
599 |
|
600 TBool Ikev2Proposal::VerifyProposaL(CIkev2Payloads* aReference, TProposalIkev2* aProposal, TIkev2SAData& aIkev2SaData) |
|
601 { |
|
602 // |
|
603 // Find a matching proposal for "candidate" from reference payload |
|
604 // chain. This implementation does not support the AND of sequental |
|
605 // proposals (for example proposal which defines (ESP and AH)) |
|
606 // |
|
607 if ( !aProposal || !aReference || (aReference->iProps->Count() == 0) ) |
|
608 return EFalse; |
|
609 |
|
610 CIkev2Payloads* Prop = CIkev2Payloads::NewL(TPayloadIkev2::Cast(aProposal), IKEV2_PAYLOAD_PROP, aIkev2SaData); |
|
611 CleanupStack::PushL(Prop); |
|
612 TBool Status = ( Prop->Status() == KErrNone ); |
|
613 if ( Status ) |
|
614 { |
|
615 |
|
616 Status = EFalse; |
|
617 TInt PropCount = aReference->iProps->Count(); |
|
618 TProposalIkev2* RefProp; |
|
619 |
|
620 for ( TInt i = 0; i < PropCount; ++i ) |
|
621 { |
|
622 RefProp = (TProposalIkev2*)aReference->iProps->At(i); |
|
623 if ( !aReference->ParsePayloadL(TPayloadIkev2::Cast(RefProp), IKEV2_PAYLOAD_PROP ))// Transforms from Proposal |
|
624 break; |
|
625 if ( aReference->iTrans->Count() == 0 ) |
|
626 break; |
|
627 if ( RefProp->GetProtocol() != aProposal->GetProtocol() ) |
|
628 continue; |
|
629 // |
|
630 // Compare transforms within proposals |
|
631 // |
|
632 Status = Ikev2Proposal::CompareTransforms(aReference->iTrans, Prop->iTrans); |
|
633 if ( Status ) |
|
634 break; // Match found |
|
635 } |
|
636 } |
|
637 CleanupStack::PopAndDestroy(Prop); |
|
638 |
|
639 return Status; |
|
640 } |
|
641 |
|
642 TBool Ikev2Proposal::CompareTransforms(CArrayFixFlat<TTransformIkev2*>* aRefTrans, |
|
643 CArrayFixFlat<TTransformIkev2*>* aTrans) |
|
644 { |
|
645 ASSERT(aTrans && aRefTrans); |
|
646 // |
|
647 // "Select" matching transforms from transform list (aTrans). |
|
648 // Transforms from aTrans array is marked "SELECTED" if there is a |
|
649 // matching transform in aRefTrans array for existing transform |
|
650 // types. |
|
651 // |
|
652 TUint8 TransType; |
|
653 TTransformIkev2* Trans; |
|
654 TTransformIkev2* RefTrans; |
|
655 TDataAttributes* Attribute; |
|
656 |
|
657 TInt TranCount2; |
|
658 TUint16 Lth; |
|
659 TUint8 ExistingTypes = 0; |
|
660 TUint8 MatchingTypes = 0; |
|
661 TInt TranCount = aTrans->Count(); |
|
662 TInt i; |
|
663 |
|
664 for ( i = 0; i < TranCount; ++i ) |
|
665 { |
|
666 Trans = aTrans->At(i); |
|
667 TransType = Trans->GetType(); |
|
668 if ( (TransType < IKEV2_ENCR ) || (TransType > IKEV2_ESN) ) |
|
669 break; // Unknown transform type (error) |
|
670 |
|
671 ExistingTypes |= (1 << TransType); |
|
672 TranCount2 = aRefTrans->Count(); |
|
673 |
|
674 for ( TInt j = 0; j < TranCount2; ++j ) |
|
675 { |
|
676 RefTrans = aRefTrans->At(j); |
|
677 |
|
678 if ( (TransType != RefTrans->GetType()) || (Trans->GetID() != RefTrans->GetID()) ) |
|
679 continue; |
|
680 // |
|
681 // Matching transform type and ID. Check is there any |
|
682 // attributes in transform (in this phase only IKEV2_ENCR |
|
683 // transform type can contain an attribute AES key length) |
|
684 // |
|
685 Lth = TPayloadIkev2::Cast(Trans)->GetLength(); |
|
686 if ( Lth >= Trans->Size() ) |
|
687 { |
|
688 if (( TransType == IKEV2_ENCR ) && (Trans->GetID() == ENCR_AES_CBC) ) |
|
689 { |
|
690 TUint16 KeyLth = 128; |
|
691 TUint16 RefKeyLth = 128; |
|
692 if ( Lth > Trans->Size() ) |
|
693 { |
|
694 Attribute = Trans->Attributes(); |
|
695 Lth = (TUint16)(Lth - Trans->Size()); |
|
696 if ( (Lth == Attribute->Size()) && Attribute->IsBasic() && (Attribute->GetType() == IKEV2_ENCR_KEY_LTH) ) |
|
697 KeyLth = Attribute->GetValue(); |
|
698 } |
|
699 if ( TPayloadIkev2::Cast(RefTrans)->GetLength() > Trans->Size() ) |
|
700 { |
|
701 Attribute = RefTrans->Attributes(); |
|
702 RefKeyLth = Attribute->GetValue(); |
|
703 } |
|
704 if ( KeyLth != RefKeyLth ) |
|
705 continue; // Not matching attribute |
|
706 } |
|
707 } |
|
708 // |
|
709 // Mark current transform "SELECTED" |
|
710 // |
|
711 if ( (MatchingTypes & (1 << TransType) ) == 0 ) |
|
712 { |
|
713 Trans->Selected(); |
|
714 MatchingTypes |= (1 << TransType); |
|
715 } |
|
716 break; |
|
717 } |
|
718 } |
|
719 |
|
720 TBool Status = (ExistingTypes == MatchingTypes); |
|
721 if ( !Status ) |
|
722 { |
|
723 // |
|
724 // No match ! Reset "SELECTED" indicator from transforms |
|
725 // |
|
726 i = 0; |
|
727 while ( i < TranCount ) |
|
728 { |
|
729 Trans = (TTransformIkev2*)aTrans->At(i); |
|
730 Trans->NotSelected(); |
|
731 i ++; |
|
732 } |
|
733 } |
|
734 |
|
735 return Status; |
|
736 |
|
737 } |
|
738 |
|
739 CIkeV2Identity* Ikev2Proposal::GetRemoteIdentityL(CIkeData* aHostData) |
|
740 { |
|
741 ASSERT(aHostData); |
|
742 CIkeV2Identity* identity = NULL; |
|
743 |
|
744 if ( aHostData->iRemoteIdentity ) |
|
745 { |
|
746 TPtrC16 idData = aHostData->iRemoteIdentity->GetData(); |
|
747 TUint8 idType = aHostData->iRemoteIdType; |
|
748 if ( (idType == ID_IPV4_ADDR) || (idType == ID_IPV6_ADDR) ) |
|
749 { |
|
750 // |
|
751 // If configured remote id type is either IPv4- or IPv6 address |
|
752 // convert ASCII format address data into hexa octet string IP |
|
753 // address format: IPv4 address shall be represented as four |
|
754 // octet string and Ipv6 address as 16 octet string |
|
755 // |
|
756 TInetAddr ipAddr; |
|
757 if ( ipAddr.Input(idData) == KErrNone ) |
|
758 { |
|
759 if ( idType == ID_IPV4_ADDR ) |
|
760 { |
|
761 TUint32 ipv4 = ByteOrder::Swap32(ipAddr.Address()); |
|
762 TPtrC8 ipv4Ptr(reinterpret_cast<TUint8*>(&ipv4), sizeof(ipv4)); |
|
763 identity = CIkeV2Identity::NewL(idType, ipv4Ptr); |
|
764 } |
|
765 else |
|
766 { |
|
767 TPtrC8 IPv6Ptr(&ipAddr.Ip6Address().u.iAddr8[0], 16); |
|
768 identity = CIkeV2Identity::NewL(idType, IPv6Ptr); |
|
769 } |
|
770 } |
|
771 } |
|
772 else |
|
773 { |
|
774 if ( (idType != ID_FQDN) && (idType != ID_RFC822_ADDR) ) |
|
775 { |
|
776 idType = ID_FQDN; // Default |
|
777 } |
|
778 |
|
779 HBufC8* id = HBufC8::NewLC(idData.Length()); |
|
780 TPtr8 idPtr(id->Des()); |
|
781 idPtr.Copy(idData); |
|
782 identity = CIkeV2Identity::NewL(idType, *id); |
|
783 CleanupStack::PopAndDestroy(id); |
|
784 } |
|
785 } |
|
786 |
|
787 return identity; |
|
788 } |