]> git.proxmox.com Git - mirror_edk2.git/blame - NetworkPkg/IpSecDxe/Ikev2/Utility.c
NetworkPkg: IpSecDxe: remove set but unused variables
[mirror_edk2.git] / NetworkPkg / IpSecDxe / Ikev2 / Utility.c
CommitLineData
9166f840 1/** @file\r
2 The Common operations used by IKE Exchange Process.\r
3\r
e8837edd 4 (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>\r
5dd08a46 5 Copyright (c) 2010 - 2015, Intel Corporation. All rights reserved.<BR>\r
9166f840 6\r
7 This program and the accompanying materials\r
8 are licensed and made available under the terms and conditions of the BSD License\r
9 which accompanies this distribution. The full text of the license may be found at\r
10 http://opensource.org/licenses/bsd-license.php.\r
11\r
12 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
13 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
14\r
15**/\r
16\r
17#include "Utility.h"\r
18#include "IpSecDebug.h"\r
19#include "IkeService.h"\r
20#include "IpSecConfigImpl.h"\r
21\r
22UINT16 mIkev2EncryptAlgorithmList[IKEV2_SUPPORT_ENCRYPT_ALGORITHM_NUM] = {\r
23 IKEV2_TRANSFORM_ID_ENCR_3DES,\r
24 IKEV2_TRANSFORM_ID_ENCR_AES_CBC, \r
25};\r
26\r
27UINT16 mIkev2PrfAlgorithmList[IKEV2_SUPPORT_PRF_ALGORITHM_NUM] = {\r
28 IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1,\r
29};\r
30\r
31UINT16 mIkev2DhGroupAlgorithmList[IKEV2_SUPPORT_DH_ALGORITHM_NUM] = {\r
32 IKEV2_TRANSFORM_ID_DH_1024MODP,\r
33 IKEV2_TRANSFORM_ID_DH_2048MODP,\r
34};\r
35\r
36UINT16 mIkev2AuthAlgorithmList[IKEV2_SUPPORT_AUTH_ALGORITHM_NUM] = {\r
37 IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96,\r
38};\r
39\r
40/**\r
41 Allocate buffer for IKEV2_SA_SESSION and initialize it.\r
42\r
43 @param[in] Private Pointer to IPSEC_PRIVATE_DATA.\r
44 @param[in] UdpService Pointer to IKE_UDP_SERVICE related to this IKE SA Session.\r
45\r
46 @return Pointer to IKEV2_SA_SESSION or NULL.\r
47\r
48**/\r
49IKEV2_SA_SESSION *\r
50Ikev2SaSessionAlloc (\r
51 IN IPSEC_PRIVATE_DATA *Private,\r
52 IN IKE_UDP_SERVICE *UdpService\r
53 )\r
54{\r
55 EFI_STATUS Status;\r
56 IKEV2_SESSION_COMMON *SessionCommon;\r
57 IKEV2_SA_SESSION *IkeSaSession;\r
58\r
59 IkeSaSession = AllocateZeroPool (sizeof (IKEV2_SA_SESSION));\r
60 ASSERT (IkeSaSession != NULL);\r
61\r
62 //\r
63 // Initialize the fields of IkeSaSession and its SessionCommon.\r
64 //\r
65 IkeSaSession->NCookie = NULL;\r
66 IkeSaSession->Signature = IKEV2_SA_SESSION_SIGNATURE;\r
67 IkeSaSession->InitiatorCookie = IkeGenerateCookie ();\r
68 IkeSaSession->ResponderCookie = 0;\r
69 //\r
70 // BUGBUG: Message ID starts from 2 is to match the OpenSwan requirement, but it \r
71 // might not match the IPv6 Logo. In its test specification, it mentions that\r
72 // the Message ID should start from zero after the IKE_SA_INIT exchange.\r
73 //\r
74 IkeSaSession->MessageId = 2;\r
75 SessionCommon = &IkeSaSession->SessionCommon;\r
76 SessionCommon->UdpService = UdpService;\r
77 SessionCommon->Private = Private;\r
78 SessionCommon->IkeSessionType = IkeSessionTypeIkeSa;\r
79 SessionCommon->IkeVer = 2;\r
80 SessionCommon->AfterEncodePayload = NULL;\r
81 SessionCommon->BeforeDecodePayload = NULL;\r
82\r
83 //\r
84 // Create a resend notfiy event for retry.\r
85 //\r
86 Status = gBS->CreateEvent (\r
87 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
88 TPL_CALLBACK,\r
89 Ikev2ResendNotify,\r
90 SessionCommon,\r
91 &SessionCommon->TimeoutEvent\r
92 );\r
93\r
94 if (EFI_ERROR (Status)) {\r
95 FreePool (IkeSaSession);\r
96 return NULL;\r
97 }\r
98\r
99 //\r
100 // Initialize the lists in IkeSaSession.\r
101 //\r
102 InitializeListHead (&IkeSaSession->ChildSaSessionList);\r
103 InitializeListHead (&IkeSaSession->ChildSaEstablishSessionList);\r
104 InitializeListHead (&IkeSaSession->InfoMIDList);\r
105 InitializeListHead (&IkeSaSession->DeleteSaList);\r
106\r
107 return IkeSaSession;\r
108}\r
109\r
110/**\r
111 Register the established IKEv2 SA into Private->Ikev2EstablishedList. If there is\r
112 IKEV2_SA_SESSION with same remote peer IP, remove the old one then register the\r
113 new one.\r
114\r
115 @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be registered.\r
116 @param[in] Private Pointer to IPSEC_PRAVATE_DATA.\r
117\r
118**/\r
119VOID\r
120Ikev2SaSessionReg (\r
121 IN IKEV2_SA_SESSION *IkeSaSession,\r
122 IN IPSEC_PRIVATE_DATA *Private\r
123 )\r
124{\r
125 IKEV2_SESSION_COMMON *SessionCommon;\r
126 IKEV2_SA_SESSION *OldIkeSaSession;\r
127 EFI_STATUS Status;\r
128 UINT64 Lifetime;\r
129\r
130 //\r
131 // Keep IKE SA exclusive to remote ip address.\r
132 //\r
133 SessionCommon = &IkeSaSession->SessionCommon;\r
134 OldIkeSaSession = Ikev2SaSessionRemove (&Private->Ikev2EstablishedList, &SessionCommon->RemotePeerIp);\r
135 if (OldIkeSaSession != NULL) {\r
136 //\r
137 // TODO: It should delete all child SAs if rekey the IKE SA.\r
138 //\r
139 Ikev2SaSessionFree (OldIkeSaSession);\r
140 }\r
141\r
142 //\r
143 // Cleanup the fields of SessionCommon for processing.\r
144 // \r
145 Ikev2SessionCommonRefresh (SessionCommon);\r
146\r
147 //\r
148 // Insert the ready IKE SA session into established list.\r
149 //\r
150 Ikev2SaSessionInsert (&Private->Ikev2EstablishedList, IkeSaSession, &SessionCommon->RemotePeerIp);\r
151\r
152 //\r
153 // Create a notfiy event for the IKE SA life time counting.\r
154 //\r
155 Status = gBS->CreateEvent (\r
156 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
157 TPL_CALLBACK,\r
158 Ikev2LifetimeNotify,\r
159 SessionCommon,\r
160 &SessionCommon->TimeoutEvent\r
161 );\r
162 if (EFI_ERROR(Status)){\r
163 //\r
164 // If TimerEvent creation failed, the SA will be alive untill user disable it or \r
165 // receiving a Delete Payload from peer. \r
166 //\r
167 return;\r
168 }\r
169\r
170 //\r
171 // Start to count the lifetime of the IKE SA.\r
172 //\r
173 if (IkeSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime == 0) {\r
174 Lifetime = IKE_SA_DEFAULT_LIFETIME;\r
175 } else {\r
176 Lifetime = IkeSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime;\r
177 }\r
178 \r
179 Status = gBS->SetTimer (\r
180 SessionCommon->TimeoutEvent,\r
181 TimerRelative,\r
182 MultU64x32(Lifetime, 10000000) // ms->100ns\r
183 );\r
184 if (EFI_ERROR(Status)){\r
185 //\r
186 // If SetTimer failed, the SA will be alive untill user disable it or \r
187 // receiving a Delete Payload from peer. \r
188 //\r
189 return ;\r
190 }\r
191\r
192 DEBUG ((\r
193 DEBUG_INFO,\r
194 "\n------IkeSa established and start to count down %d seconds lifetime\n",\r
195 Lifetime\r
196 ));\r
197\r
198 return ;\r
199}\r
200\r
201/**\r
202 Find a IKEV2_SA_SESSION by the remote peer IP.\r
203\r
204 @param[in] SaSessionList SaSession List to be searched.\r
205 @param[in] RemotePeerIp Pointer to specified IP address.\r
206\r
207 @return Pointer to IKEV2_SA_SESSION if find one or NULL.\r
208\r
209**/\r
210IKEV2_SA_SESSION *\r
211Ikev2SaSessionLookup (\r
212 IN LIST_ENTRY *SaSessionList,\r
213 IN EFI_IP_ADDRESS *RemotePeerIp\r
214 )\r
215{\r
216 LIST_ENTRY *Entry;\r
217 IKEV2_SA_SESSION *IkeSaSession;\r
218\r
219 NET_LIST_FOR_EACH (Entry, SaSessionList) {\r
220 IkeSaSession = IKEV2_SA_SESSION_BY_SESSION (Entry);\r
221\r
222 if (CompareMem (\r
223 &IkeSaSession->SessionCommon.RemotePeerIp,\r
224 RemotePeerIp,\r
225 sizeof (EFI_IP_ADDRESS)\r
226 ) == 0) {\r
227\r
228 return IkeSaSession;\r
229 }\r
230 }\r
231\r
232 return NULL;\r
233}\r
234\r
235/**\r
236 Insert a IKE_SA_SESSION into IkeSaSession list. The IkeSaSession list is either\r
237 Private->Ikev2SaSession list or Private->Ikev2EstablishedList list.\r
238\r
239 @param[in] SaSessionList Pointer to list to be inserted into.\r
240 @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be inserted. \r
241 @param[in] RemotePeerIp Pointer to EFI_IP_ADDRESSS to indicate the \r
242 unique IKEV2_SA_SESSION.\r
243\r
244**/\r
245VOID\r
246Ikev2SaSessionInsert (\r
247 IN LIST_ENTRY *SaSessionList,\r
248 IN IKEV2_SA_SESSION *IkeSaSession,\r
249 IN EFI_IP_ADDRESS *RemotePeerIp\r
250 )\r
251{\r
252 Ikev2SaSessionRemove (SaSessionList, RemotePeerIp);\r
253 InsertTailList (SaSessionList, &IkeSaSession->BySessionTable);\r
254}\r
255\r
256/**\r
257 Remove the SA Session by Remote Peer IP.\r
258\r
259 @param[in] SaSessionList Pointer to list to be searched.\r
260 @param[in] RemotePeerIp Pointer to EFI_IP_ADDRESS to use for SA Session search.\r
261\r
262 @retval Pointer to IKEV2_SA_SESSION with the specified remote IP address or NULL. \r
263\r
264**/\r
265IKEV2_SA_SESSION *\r
266Ikev2SaSessionRemove (\r
267 IN LIST_ENTRY *SaSessionList,\r
268 IN EFI_IP_ADDRESS *RemotePeerIp\r
269 )\r
270{\r
271 LIST_ENTRY *Entry;\r
272 IKEV2_SA_SESSION *IkeSaSession;\r
273\r
274 NET_LIST_FOR_EACH (Entry, SaSessionList) {\r
275 IkeSaSession = IKEV2_SA_SESSION_BY_SESSION (Entry);\r
276\r
277 if (CompareMem (\r
278 &IkeSaSession->SessionCommon.RemotePeerIp,\r
279 RemotePeerIp,\r
280 sizeof (EFI_IP_ADDRESS)\r
281 ) == 0) {\r
282\r
283 RemoveEntryList (Entry);\r
284 return IkeSaSession;\r
285 }\r
286 }\r
287\r
288 return NULL;\r
289}\r
290\r
291/**\r
292 Marking a SA session as on deleting.\r
293\r
294 @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION.\r
295\r
296 @retval EFI_SUCCESS Find the related SA session and marked it.\r
297\r
298**/\r
299EFI_STATUS\r
300Ikev2SaSessionOnDeleting (\r
301 IN IKEV2_SA_SESSION *IkeSaSession\r
302 )\r
303{\r
304 return EFI_SUCCESS;\r
305}\r
306\r
307/**\r
308 Free specified Seession Common. The session common would belong to a IKE SA or \r
309 a Child SA.\r
310\r
311 @param[in] SessionCommon Pointer to a Session Common.\r
312\r
313**/\r
314VOID\r
315Ikev2SaSessionCommonFree (\r
316 IN IKEV2_SESSION_COMMON *SessionCommon\r
317 )\r
318{\r
319\r
320 ASSERT (SessionCommon != NULL);\r
321\r
322 if (SessionCommon->LastSentPacket != NULL) {\r
323 IkePacketFree (SessionCommon->LastSentPacket);\r
324 }\r
325\r
326 if (SessionCommon->SaParams != NULL) {\r
327 FreePool (SessionCommon->SaParams);\r
328 }\r
329 if (SessionCommon->TimeoutEvent != NULL) {\r
330 gBS->CloseEvent (SessionCommon->TimeoutEvent);\r
331 }\r
332}\r
333\r
334/**\r
335 After IKE/Child SA is estiblished, close the time event and free sent packet.\r
336\r
337 @param[in] SessionCommon Pointer to a Session Common.\r
338\r
339**/\r
340VOID\r
341Ikev2SessionCommonRefresh (\r
342 IN IKEV2_SESSION_COMMON *SessionCommon\r
343 )\r
344{\r
345 ASSERT (SessionCommon != NULL);\r
346\r
347 gBS->CloseEvent (SessionCommon->TimeoutEvent);\r
348 SessionCommon->TimeoutEvent = NULL;\r
349 SessionCommon->TimeoutInterval = 0;\r
350 SessionCommon->RetryCount = 0;\r
351 if (SessionCommon->LastSentPacket != NULL) {\r
352 IkePacketFree (SessionCommon->LastSentPacket);\r
353 SessionCommon->LastSentPacket = NULL;\r
354 }\r
355\r
356 return ;\r
357}\r
358/**\r
359 Free specified IKEV2 SA Session. \r
360\r
361 @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION to be freed.\r
362\r
363**/\r
364VOID\r
365Ikev2SaSessionFree (\r
366 IN IKEV2_SA_SESSION *IkeSaSession\r
367 )\r
368{\r
369 IKEV2_SESSION_KEYS *IkeKeys;\r
370 LIST_ENTRY *Entry;\r
371 IKEV2_CHILD_SA_SESSION *ChildSa;\r
372 IKEV2_DH_BUFFER *DhBuffer;\r
373\r
374 ASSERT (IkeSaSession != NULL);\r
375 \r
376 //\r
377 // Delete Common Session\r
378 //\r
379 Ikev2SaSessionCommonFree (&IkeSaSession->SessionCommon);\r
380\r
381 //\r
382 // Delete ChildSaEstablish List and SAD\r
383 //\r
384 for (Entry = IkeSaSession->ChildSaEstablishSessionList.ForwardLink;\r
385 Entry != &IkeSaSession->ChildSaEstablishSessionList;\r
386 ) {\r
387\r
388 ChildSa = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);\r
389 Entry = Entry->ForwardLink;\r
390 Ikev2ChildSaSilentDelete (ChildSa->IkeSaSession, ChildSa->LocalPeerSpi);\r
391\r
392 }\r
393\r
394 //\r
395 // Delete ChildSaSessionList\r
396 //\r
397 for ( Entry = IkeSaSession->ChildSaSessionList.ForwardLink;\r
398 Entry != &IkeSaSession->ChildSaSessionList;\r
399 ){\r
400 ChildSa = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);\r
401 Entry = Entry->ForwardLink;\r
402 RemoveEntryList (Entry->BackLink);\r
403 Ikev2ChildSaSessionFree (ChildSa);\r
404 }\r
405\r
406 //\r
407 // Delete DhBuffer and Keys\r
408 //\r
409 if (IkeSaSession->IkeKeys != NULL) {\r
410 IkeKeys = IkeSaSession->IkeKeys;\r
411 DhBuffer = IkeKeys->DhBuffer;\r
412\r
413 //\r
414 // Delete DhBuffer\r
415 //\r
416 Ikev2DhBufferFree (DhBuffer);\r
417\r
418 //\r
419 // Delete Keys\r
420 // \r
421 if (IkeKeys->SkAiKey != NULL) {\r
422 FreePool (IkeKeys->SkAiKey);\r
423 }\r
424 if (IkeKeys->SkArKey != NULL) {\r
425 FreePool (IkeKeys->SkArKey);\r
426 }\r
427 if (IkeKeys->SkdKey != NULL) {\r
428 FreePool (IkeKeys->SkdKey);\r
429 }\r
430 if (IkeKeys->SkEiKey != NULL) {\r
431 FreePool (IkeKeys->SkEiKey);\r
432 }\r
433 if (IkeKeys->SkErKey != NULL) {\r
434 FreePool (IkeKeys->SkErKey);\r
435 }\r
436 if (IkeKeys->SkPiKey != NULL) {\r
437 FreePool (IkeKeys->SkPiKey);\r
438 }\r
439 if (IkeKeys->SkPrKey != NULL) {\r
440 FreePool (IkeKeys->SkPrKey);\r
441 }\r
442 FreePool (IkeKeys);\r
443 }\r
444\r
445 if (IkeSaSession->SaData != NULL) {\r
446 FreePool (IkeSaSession->SaData);\r
447 }\r
448\r
449 if (IkeSaSession->NiBlock != NULL) {\r
450 FreePool (IkeSaSession->NiBlock);\r
451 }\r
452\r
453 if (IkeSaSession->NrBlock != NULL) {\r
454 FreePool (IkeSaSession->NrBlock);\r
455 }\r
456\r
457 if (IkeSaSession->NCookie != NULL) {\r
458 FreePool (IkeSaSession->NCookie);\r
459 }\r
460\r
461 if (IkeSaSession->InitPacket != NULL) {\r
462 FreePool (IkeSaSession->InitPacket);\r
463 }\r
464\r
465 if (IkeSaSession->RespPacket != NULL) {\r
466 FreePool (IkeSaSession->RespPacket);\r
467 }\r
468\r
469 FreePool (IkeSaSession);\r
470\r
471 return ;\r
472}\r
473\r
474/**\r
475 Increase the MessageID in IkeSaSession.\r
476\r
477 @param[in] IkeSaSession Pointer to a specified IKEV2_SA_SESSION.\r
478\r
479**/\r
480VOID\r
481Ikev2SaSessionIncreaseMessageId (\r
482 IN IKEV2_SA_SESSION *IkeSaSession\r
483 )\r
484{\r
485 if (IkeSaSession->MessageId < 0xffffffff) {\r
486 IkeSaSession->MessageId ++;\r
487 } else {\r
488 //\r
489 // TODO: Trigger Rekey process.\r
490 //\r
491 }\r
492}\r
493\r
494/**\r
495 Allocate memory for IKEV2 Child SA Session.\r
496 \r
497 @param[in] UdpService Pointer to IKE_UDP_SERVICE.\r
498 @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to this Child SA \r
499 Session.\r
500\r
501 @retval Pointer of a new created IKEV2 Child SA Session or NULL.\r
502\r
503**/\r
504IKEV2_CHILD_SA_SESSION *\r
505Ikev2ChildSaSessionAlloc (\r
506 IN IKE_UDP_SERVICE *UdpService,\r
507 IN IKEV2_SA_SESSION *IkeSaSession\r
508 )\r
509{\r
510 EFI_STATUS Status;\r
511 IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
512 IKEV2_SESSION_COMMON *ChildSaCommon;\r
513 IKEV2_SESSION_COMMON *SaCommon;\r
514\r
515 ChildSaSession = AllocateZeroPool (sizeof (IKEV2_CHILD_SA_SESSION));\r
516 if (ChildSaSession == NULL) {\r
517 return NULL;\r
518 }\r
519\r
520 //\r
521 // Initialize the fields of ChildSaSession and its SessionCommon.\r
522 //\r
523 ChildSaSession->Signature = IKEV2_CHILD_SA_SESSION_SIGNATURE;\r
524 ChildSaSession->IkeSaSession = IkeSaSession;\r
525 ChildSaSession->MessageId = IkeSaSession->MessageId;\r
526 ChildSaSession->LocalPeerSpi = IkeGenerateSpi ();\r
527 ChildSaCommon = &ChildSaSession->SessionCommon;\r
528 ChildSaCommon->UdpService = UdpService;\r
529 ChildSaCommon->Private = IkeSaSession->SessionCommon.Private;\r
530 ChildSaCommon->IkeSessionType = IkeSessionTypeChildSa;\r
531 ChildSaCommon->IkeVer = 2;\r
532 ChildSaCommon->AfterEncodePayload = Ikev2ChildSaAfterEncodePayload;\r
533 ChildSaCommon->BeforeDecodePayload = Ikev2ChildSaBeforeDecodePayload;\r
534 SaCommon = &ChildSaSession->IkeSaSession->SessionCommon;\r
535\r
536 //\r
537 // Create a resend notfiy event for retry.\r
538 //\r
539 Status = gBS->CreateEvent (\r
540 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
541 TPL_CALLBACK,\r
542 Ikev2ResendNotify,\r
543 ChildSaCommon,\r
544 &ChildSaCommon->TimeoutEvent\r
545 );\r
546 if (EFI_ERROR (Status)) {\r
547 FreePool (ChildSaSession);\r
548 return NULL;\r
549 }\r
550\r
551 CopyMem (&ChildSaCommon->LocalPeerIp, &SaCommon->LocalPeerIp, sizeof (EFI_IP_ADDRESS));\r
552 CopyMem (&ChildSaCommon->RemotePeerIp, &SaCommon->RemotePeerIp, sizeof (EFI_IP_ADDRESS));\r
553\r
554 return ChildSaSession;\r
555}\r
556\r
557/**\r
558 Register a established IKEv2 Child SA into IkeSaSession->ChildSaEstablishSessionList. \r
559 If the there is IKEV2_CHILD_SA_SESSION with same remote peer IP, remove the old one \r
560 then register the new one.\r
561\r
562 @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION to be registered.\r
563 @param[in] Private Pointer to IPSEC_PRAVATE_DATA.\r
564\r
565**/\r
566VOID\r
567Ikev2ChildSaSessionReg (\r
568 IN IKEV2_CHILD_SA_SESSION *ChildSaSession,\r
569 IN IPSEC_PRIVATE_DATA *Private\r
570 )\r
571{\r
572 IKEV2_SESSION_COMMON *SessionCommon;\r
573 IKEV2_CHILD_SA_SESSION *OldChildSaSession;\r
574 IKEV2_SA_SESSION *IkeSaSession;\r
9166f840 575 EFI_STATUS Status;\r
576 UINT64 Lifetime;\r
577\r
578 //\r
579 // Keep the IKE SA exclusive.\r
580 //\r
581 SessionCommon = &ChildSaSession->SessionCommon;\r
582 IkeSaSession = ChildSaSession->IkeSaSession;\r
583 OldChildSaSession = Ikev2ChildSaSessionRemove (\r
584 &IkeSaSession->ChildSaEstablishSessionList,\r
585 ChildSaSession->LocalPeerSpi,\r
586 IKEV2_ESTABLISHED_CHILDSA_LIST\r
587 );\r
588 if (OldChildSaSession != NULL) {\r
589 //\r
590 // Free the old one.\r
591 //\r
592 Ikev2ChildSaSessionFree (OldChildSaSession);\r
593 }\r
594\r
595 //\r
596 // Store the ready child SA into SAD.\r
597 //\r
598 Ikev2StoreSaData (ChildSaSession);\r
599\r
600 //\r
601 // Cleanup the fields of SessionCommon for processing.\r
602 // \r
603 Ikev2SessionCommonRefresh (SessionCommon);\r
604 \r
605 //\r
606 // Insert the ready child SA session into established list.\r
607 //\r
608 Ikev2ChildSaSessionInsert (&IkeSaSession->ChildSaEstablishSessionList, ChildSaSession);\r
609\r
610 //\r
611 // Create a Notify event for the IKE SA life time counting.\r
612 //\r
613 Status = gBS->CreateEvent (\r
614 EVT_TIMER | EVT_NOTIFY_SIGNAL,\r
615 TPL_CALLBACK,\r
616 Ikev2LifetimeNotify,\r
617 SessionCommon,\r
618 &SessionCommon->TimeoutEvent\r
619 );\r
620 if (EFI_ERROR(Status)){\r
621 return ;\r
622 }\r
623\r
624 //\r
625 // Start to count the lifetime of the IKE SA.\r
626 //\r
9166f840 627 if (ChildSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime != 0){\r
628 Lifetime = ChildSaSession->Spd->Data->ProcessingPolicy->SaLifetime.HardLifetime;\r
629 } else {\r
630 Lifetime = CHILD_SA_DEFAULT_LIFETIME;\r
631 }\r
632\r
633 Status = gBS->SetTimer (\r
634 SessionCommon->TimeoutEvent,\r
635 TimerRelative,\r
636 MultU64x32(Lifetime, 10000000) // ms->100ns\r
637 );\r
638 if (EFI_ERROR(Status)){\r
639 return ;\r
640 }\r
641\r
642 DEBUG ((\r
643 DEBUG_INFO,\r
644 "\n------ChildSa established and start to count down %d seconds lifetime\n",\r
645 Lifetime\r
646 ));\r
647\r
648 return ;\r
649}\r
650\r
651/**\r
652 Find the ChildSaSession by it's MessagId.\r
653\r
654 @param[in] SaSessionList Pointer to a ChildSaSession List.\r
655 @param[in] Mid The messageId used to search ChildSaSession.\r
656\r
657 @return Pointer to IKEV2_CHILD_SA_SESSION or NULL.\r
658\r
659**/\r
660IKEV2_CHILD_SA_SESSION *\r
661Ikev2ChildSaSessionLookupByMid (\r
662 IN LIST_ENTRY *SaSessionList,\r
663 IN UINT32 Mid\r
664 )\r
665{\r
666 LIST_ENTRY *Entry;\r
667 IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
44de1013 668\r
9166f840 669 NET_LIST_FOR_EACH (Entry, SaSessionList) {\r
670 ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);\r
44de1013 671\r
9166f840 672 if (ChildSaSession->MessageId == Mid) {\r
44de1013
HT
673 return ChildSaSession;\r
674 }\r
9166f840 675 }\r
676 return NULL;\r
677}\r
678\r
679/**\r
680 This function find the Child SA by the specified SPI.\r
44de1013
HT
681\r
682 This functin find a ChildSA session by searching the ChildSaSessionlist of\r
9166f840 683 the input IKEV2_SA_SESSION by specified MessageID.\r
44de1013 684 \r
9166f840 685 @param[in] SaSessionList Pointer to List to be searched.\r
686 @param[in] Spi Specified SPI.\r
44de1013 687\r
9166f840 688 @return Pointer to IKEV2_CHILD_SA_SESSION or NULL.\r
689\r
690**/\r
691IKEV2_CHILD_SA_SESSION *\r
692Ikev2ChildSaSessionLookupBySpi (\r
693 IN LIST_ENTRY *SaSessionList,\r
694 IN UINT32 Spi\r
695 )\r
696{\r
697 LIST_ENTRY *Entry;\r
698 IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
44de1013 699\r
9166f840 700 NET_LIST_FOR_EACH (Entry, SaSessionList) {\r
701 ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);\r
44de1013 702\r
9166f840 703 if (ChildSaSession->RemotePeerSpi == Spi || ChildSaSession->LocalPeerSpi == Spi) {\r
44de1013
HT
704 return ChildSaSession;\r
705 }\r
706 }\r
9166f840 707\r
708 return NULL;\r
709}\r
710\r
711/**\r
712 Insert a Child SA Session into the specified ChildSa list.\r
713\r
714 @param[in] SaSessionList Pointer to list to be inserted in.\r
715 @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION to be inserted.\r
716\r
717**/\r
718VOID\r
719Ikev2ChildSaSessionInsert (\r
720 IN LIST_ENTRY *SaSessionList,\r
721 IN IKEV2_CHILD_SA_SESSION *ChildSaSession\r
722 )\r
723{\r
724 InsertTailList (SaSessionList, &ChildSaSession->ByIkeSa);\r
725}\r
726\r
727/**\r
728 Remove the IKEV2_CHILD_SA_SESSION from IkeSaSessionList.\r
729 \r
730 @param[in] SaSessionList The SA Session List to be iterated.\r
731 @param[in] Spi Spi used to identified the IKEV2_CHILD_SA_SESSION.\r
732 @param[in] ListType The type of the List to indicate whether it is a \r
733 Established. \r
734\r
735 @return The point to IKEV2_CHILD_SA_SESSION or NULL.\r
736 \r
737**/\r
738IKEV2_CHILD_SA_SESSION *\r
739Ikev2ChildSaSessionRemove (\r
740 IN LIST_ENTRY *SaSessionList,\r
741 IN UINT32 Spi, \r
742 IN UINT8 ListType\r
743 )\r
744{\r
745 LIST_ENTRY *Entry;\r
746 LIST_ENTRY *NextEntry;\r
747 IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
748\r
749 NET_LIST_FOR_EACH_SAFE (Entry, NextEntry, SaSessionList) {\r
750 \r
751 if (ListType == IKEV2_ESTABLISHED_CHILDSA_LIST || ListType == IKEV2_ESTABLISHING_CHILDSA_LIST) {\r
752 ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (Entry);\r
753 } else if (ListType == IKEV2_DELET_CHILDSA_LIST) {\r
754 ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_DEL_SA (Entry);\r
755 } else {\r
756 return NULL;\r
757 }\r
758\r
759 if (ChildSaSession->RemotePeerSpi == Spi || ChildSaSession->LocalPeerSpi == Spi) {\r
760 RemoveEntryList (Entry);\r
761 return ChildSaSession;\r
762 }\r
763 }\r
764\r
765 return NULL;\r
766}\r
767\r
768/**\r
769 Mark a specified Child SA Session as on deleting.\r
770\r
771 @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION.\r
772\r
773 @retval EFI_SUCCESS Operation is successful.\r
774\r
775**/\r
776EFI_STATUS\r
777Ikev2ChildSaSessionOnDeleting (\r
778 IN IKEV2_CHILD_SA_SESSION *ChildSaSession\r
779 )\r
780{\r
781 return EFI_SUCCESS;\r
782}\r
783\r
784/**\r
785 Free the memory located for the specified IKEV2_CHILD_SA_SESSION. \r
786\r
787 @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION.\r
788\r
789**/\r
790VOID\r
791Ikev2ChildSaSessionFree (\r
792 IN IKEV2_CHILD_SA_SESSION *ChildSaSession\r
793 )\r
794{\r
795 IKEV2_SESSION_COMMON *SessionCommon;\r
796\r
797 SessionCommon = &ChildSaSession->SessionCommon;\r
798 if (ChildSaSession->SaData != NULL) {\r
799 FreePool (ChildSaSession->SaData);\r
800 }\r
801\r
802 if (ChildSaSession->NiBlock != NULL) {\r
803 FreePool (ChildSaSession->NiBlock);\r
804 }\r
805\r
806 if (ChildSaSession->NrBlock != NULL) {\r
807 FreePool (ChildSaSession->NrBlock);\r
808 }\r
809\r
810 if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey != NULL) {\r
811 FreePool (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.AuthKey);\r
812 }\r
813\r
814 if (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey != NULL) {\r
815 FreePool (ChildSaSession->ChildKeymats.LocalPeerInfo.EspAlgoInfo.EncKey);\r
816 }\r
817\r
818 if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey != NULL) {\r
819 FreePool (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.AuthKey);\r
820 }\r
821\r
822 if (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey != NULL) {\r
823 FreePool (ChildSaSession->ChildKeymats.RemotePeerInfo.EspAlgoInfo.EncKey);\r
824 }\r
825\r
826 //\r
827 // Delete DhBuffer\r
828 //\r
829 Ikev2DhBufferFree (ChildSaSession->DhBuffer);\r
830\r
831 //\r
832 // Delete SpdSelector\r
833 //\r
834 if (ChildSaSession->SpdSelector != NULL) {\r
835 if (ChildSaSession->SpdSelector->LocalAddress != NULL) {\r
836 FreePool (ChildSaSession->SpdSelector->LocalAddress);\r
837 }\r
838 if (ChildSaSession->SpdSelector->RemoteAddress != NULL) {\r
839 FreePool (ChildSaSession->SpdSelector->RemoteAddress);\r
840 }\r
841 FreePool (ChildSaSession->SpdSelector);\r
842 }\r
843 Ikev2SaSessionCommonFree (SessionCommon);\r
844 FreePool (ChildSaSession);\r
845\r
846 return ;\r
847}\r
848\r
849/**\r
850 Delete the specified established Child SA.\r
851\r
852 This function delete the Child SA directly and don't send the Information Packet to\r
853 remote peer.\r
854\r
855 @param[in] IkeSaSession Pointer to a IKE SA Session used to be searched for.\r
856 @param[in] Spi SPI used to find the Child SA.\r
857\r
858 @retval EFI_NOT_FOUND Pointer of IKE SA Session is NULL.\r
859 @retval EFI_NOT_FOUND There is no specified Child SA related with the input\r
860 SPI under this IKE SA Session.\r
861 @retval EFI_SUCCESS Delete the Child SA successfully.\r
862\r
863**/\r
864EFI_STATUS\r
865Ikev2ChildSaSilentDelete (\r
866 IN IKEV2_SA_SESSION *IkeSaSession,\r
867 IN UINT32 Spi\r
868 )\r
869{\r
870 EFI_STATUS Status;\r
871 EFI_IPSEC_CONFIG_SELECTOR *Selector;\r
872 UINTN SelectorSize;\r
873 BOOLEAN IsLocalFound;\r
874 BOOLEAN IsRemoteFound;\r
875 UINT32 LocalSpi;\r
876 UINT32 RemoteSpi;\r
877 IKEV2_CHILD_SA_SESSION *ChildSession;\r
878 EFI_IPSEC_CONFIG_SELECTOR *LocalSelector;\r
879 EFI_IPSEC_CONFIG_SELECTOR *RemoteSelector;\r
9166f840 880 IPSEC_PRIVATE_DATA *Private;\r
881\r
882 if (IkeSaSession == NULL) {\r
883 return EFI_NOT_FOUND;\r
884 }\r
885\r
886 IsLocalFound = FALSE;\r
887 IsRemoteFound = FALSE;\r
888 ChildSession = NULL;\r
889 LocalSelector = NULL;\r
890 RemoteSelector = NULL;\r
9166f840 891\r
5dd08a46 892 Private = IkeSaSession->SessionCommon.Private;\r
9166f840 893\r
894 //\r
895 // Remove the Established SA from ChildSaEstablishlist.\r
896 //\r
897 ChildSession = Ikev2ChildSaSessionRemove(\r
898 &(IkeSaSession->ChildSaEstablishSessionList),\r
899 Spi, \r
900 IKEV2_ESTABLISHED_CHILDSA_LIST\r
901 );\r
902 if (ChildSession == NULL) {\r
903 return EFI_NOT_FOUND;\r
904 }\r
905\r
906 LocalSpi = ChildSession->LocalPeerSpi;\r
907 RemoteSpi = ChildSession->RemotePeerSpi;\r
908 \r
909 SelectorSize = sizeof (EFI_IPSEC_CONFIG_SELECTOR);\r
910 Selector = AllocateZeroPool (SelectorSize);\r
911 ASSERT (Selector != NULL);\r
912\r
913 \r
914\r
915 while (1) {\r
916 Status = EfiIpSecConfigGetNextSelector (\r
917 &Private->IpSecConfig,\r
918 IPsecConfigDataTypeSad,\r
919 &SelectorSize,\r
920 Selector\r
921 );\r
922 if (Status == EFI_BUFFER_TOO_SMALL) {\r
923 FreePool (Selector);\r
924\r
925 Selector = AllocateZeroPool (SelectorSize);\r
393a3169 926 ASSERT (Selector != NULL);\r
9166f840 927 Status = EfiIpSecConfigGetNextSelector (\r
928 &Private->IpSecConfig,\r
929 IPsecConfigDataTypeSad,\r
930 &SelectorSize,\r
931 Selector\r
932 );\r
933 }\r
934\r
935 if (EFI_ERROR (Status)) {\r
936 break;\r
937 }\r
938\r
939 if (Selector->SaId.Spi == RemoteSpi) {\r
940 //\r
941 // SPI is unique. There is only one SAD whose SPI is\r
942 // same with RemoteSpi.\r
943 //\r
944 IsRemoteFound = TRUE;\r
945 RemoteSelector = AllocateZeroPool (SelectorSize);\r
02a758cb 946 ASSERT (RemoteSelector != NULL);\r
9166f840 947 CopyMem (RemoteSelector, Selector, SelectorSize);\r
948 }\r
949\r
950 if (Selector->SaId.Spi == LocalSpi) {\r
951 //\r
952 // SPI is unique. There is only one SAD whose SPI is\r
953 // same with LocalSpi.\r
954 //\r
955 IsLocalFound = TRUE;\r
956 LocalSelector = AllocateZeroPool (SelectorSize);\r
02a758cb 957 ASSERT (LocalSelector != NULL);\r
9166f840 958 CopyMem (LocalSelector, Selector, SelectorSize);\r
959 }\r
960 }\r
961 //\r
962 // Delete SA from the Variable.\r
963 //\r
964 if (IsLocalFound) {\r
965 Status = EfiIpSecConfigSetData (\r
966 &Private->IpSecConfig,\r
967 IPsecConfigDataTypeSad,\r
968 LocalSelector,\r
969 NULL,\r
970 NULL\r
971 );\r
972 }\r
973\r
974 if (IsRemoteFound) {\r
975 Status = EfiIpSecConfigSetData (\r
976 &Private->IpSecConfig,\r
977 IPsecConfigDataTypeSad,\r
978 RemoteSelector,\r
979 NULL,\r
980 NULL\r
981 );\r
982\r
983 }\r
984\r
985 DEBUG (\r
986 (DEBUG_INFO,\r
987 "\n------IKEV2 deleted ChildSa(local spi, remote spi):(0x%x, 0x%x)------\n",\r
988 LocalSpi,\r
989 RemoteSpi)\r
990 );\r
991 Ikev2ChildSaSessionFree (ChildSession);\r
992\r
993 if (RemoteSelector != NULL) {\r
994 FreePool (RemoteSelector);\r
995 }\r
996\r
997 if (LocalSelector != NULL) {\r
998 FreePool (LocalSelector);\r
999 }\r
1000\r
1001 if (Selector != NULL) {\r
1002 FreePool (Selector);\r
1003 }\r
1004\r
1005 return Status;\r
1006}\r
1007\r
1008/**\r
1009 Free the specified DhBuffer.\r
1010\r
1011 @param[in] DhBuffer Pointer to IKEV2_DH_BUFFER to be freed.\r
1012 \r
1013**/\r
1014VOID\r
1015Ikev2DhBufferFree (\r
1016 IKEV2_DH_BUFFER *DhBuffer\r
1017) \r
1018{\r
1019 if (DhBuffer != NULL) {\r
1020 if (DhBuffer->GxBuffer != NULL) {\r
1021 FreePool (DhBuffer->GxBuffer);\r
1022 }\r
1023 if (DhBuffer->GyBuffer != NULL) {\r
1024 FreePool (DhBuffer->GyBuffer);\r
1025 }\r
1026 if (DhBuffer->GxyBuffer != NULL) {\r
1027 FreePool (DhBuffer->GxyBuffer);\r
1028 }\r
1029 if (DhBuffer->DhContext != NULL) {\r
1030 IpSecCryptoIoFreeDh (&DhBuffer->DhContext);\r
1031 }\r
1032 FreePool (DhBuffer);\r
1033 }\r
1034}\r
1035\r
1036/**\r
1037 This function is to parse a request IKE packet and return its request type.\r
1038 The request type is one of IKE CHILD SA creation, IKE SA rekeying and \r
1039 IKE CHILD SA rekeying.\r
1040\r
1041 @param[in] IkePacket IKE packet to be prased.\r
1042\r
1043 return the type of the IKE packet.\r
1044\r
1045**/\r
1046IKEV2_CREATE_CHILD_REQUEST_TYPE\r
1047Ikev2ChildExchangeRequestType(\r
1048 IN IKE_PACKET *IkePacket\r
1049 )\r
1050{\r
1051 BOOLEAN Flag;\r
1052 LIST_ENTRY *Entry;\r
1053 IKE_PAYLOAD *IkePayload;\r
1054\r
1055 Flag = FALSE;\r
1056\r
1057 NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {\r
1058 IkePayload = IKE_PAYLOAD_BY_PACKET (Entry);\r
1059 if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_TS_INIT) {\r
1060 //\r
1061 // Packet with Ts Payload means it is for either CHILD_SA_CREATE or CHILD_SA_REKEY.\r
1062 //\r
1063 Flag = TRUE;\r
1064 }\r
1065 if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_NOTIFY) { \r
1066 if (((IKEV2_NOTIFY*)IkePayload)->MessageType == IKEV2_NOTIFICATION_REKEY_SA) {\r
1067 //\r
1068 // If notify payload with REKEY_SA message type, the IkePacket is for \r
1069 // rekeying Child SA.\r
1070 //\r
1071 return IkeRequestTypeRekeyChildSa;\r
1072 }\r
1073 }\r
1074 };\r
1075\r
1076 if (!Flag){\r
1077 //\r
1078 // The Create Child Exchange is for IKE SA rekeying.\r
1079 //\r
1080 return IkeRequestTypeRekeyIkeSa;\r
1081 } else {\r
1082 //\r
1083 // If the Notify payloaad with transport mode message type, the IkePacket is \r
1084 // for create Child SA.\r
1085 //\r
1086 return IkeRequestTypeCreateChildSa;\r
1087 }\r
1088}\r
1089\r
1090/**\r
1091 Associate a SPD selector to the Child SA Session.\r
1092\r
1093 This function is called when the Child SA is not the first child SA of its \r
1094 IKE SA. It associate a SPD to this Child SA.\r
1095\r
1096 @param[in, out] ChildSaSession Pointer to the Child SA Session to be associated to \r
1097 a SPD selector.\r
1098\r
1099 @retval EFI_SUCCESS Associate one SPD selector to this Child SA Session successfully.\r
1100 @retval EFI_NOT_FOUND Can't find the related SPD selector.\r
1101\r
1102**/\r
1103EFI_STATUS\r
1104Ikev2ChildSaAssociateSpdEntry (\r
1105 IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession\r
1106 )\r
1107{\r
1108 IpSecVisitConfigData (IPsecConfigDataTypeSpd, Ikev2MatchSpdEntry, ChildSaSession);\r
1109 if (ChildSaSession->Spd != NULL) {\r
1110 return EFI_SUCCESS;\r
1111 } else {\r
1112 return EFI_NOT_FOUND;\r
1113 }\r
1114}\r
1115\r
1116\r
1117/**\r
1118 This function finds the SPI from Create Child SA Exchange Packet.\r
1119 \r
1120 @param[in] IkePacket Pointer to IKE_PACKET to be searched.\r
1121\r
1122 @retval SPI number or 0 if it is not supported.\r
1123\r
1124**/\r
1125UINT32\r
1126Ikev2ChildExchangeRekeySpi (\r
1127 IN IKE_PACKET *IkePacket\r
1128 )\r
1129{\r
1130 //\r
1131 // Not support yet.\r
1132 // \r
1133 return 0;\r
1134}\r
1135\r
1136/**\r
1137 Validate the IKE header of received IKE packet.\r
1138\r
1139 @param[in] IkeSaSession Pointer to IKEV2_SA_SESSION related to this IKE packet.\r
1140 @param[in] IkeHdr Pointer to IKE header of received IKE packet.\r
1141\r
1142 @retval TRUE If the IKE header is valid.\r
1143 @retval FALSE If the IKE header is invalid.\r
1144\r
1145**/\r
1146BOOLEAN\r
1147Ikev2ValidateHeader (\r
1148 IN IKEV2_SA_SESSION *IkeSaSession,\r
1149 IN IKE_HEADER *IkeHdr\r
1150 )\r
1151{\r
1152\r
1153 IKEV2_SESSION_STATE State;\r
1154\r
1155 State = IkeSaSession->SessionCommon.State;\r
1156 if (State == IkeStateInit) {\r
1157 //\r
1158 // For the IKE Initial Exchange, the MessagId should be zero.\r
1159 //\r
1160 if (IkeHdr->MessageId != 0) {\r
1161 return FALSE;\r
1162 }\r
1163 } else {\r
1164 if (State == IkeStateAuth) {\r
1165 if (IkeHdr->MessageId != 1) {\r
1166 return FALSE;\r
1167 }\r
1168 }\r
1169 if (IkeHdr->InitiatorCookie != IkeSaSession->InitiatorCookie ||\r
1170 IkeHdr->ResponderCookie != IkeSaSession->ResponderCookie\r
1171 ) {\r
1172 //\r
1173 // TODO: send notification INVALID-COOKIE\r
1174 //\r
1175 return FALSE;\r
1176 }\r
1177 }\r
1178\r
1179 //\r
1180 // Information Exchagne and Create Child Exchange can be started from each part.\r
1181 //\r
1182 if (IkeHdr->ExchangeType != IKEV2_EXCHANGE_TYPE_INFO && \r
1183 IkeHdr->ExchangeType != IKEV2_EXCHANGE_TYPE_CREATE_CHILD\r
1184 ) {\r
1185 if (IkeSaSession->SessionCommon.IsInitiator) {\r
1186 if (IkeHdr->InitiatorCookie != IkeSaSession->InitiatorCookie) {\r
1187 //\r
1188 // TODO: send notification INVALID-COOKIE\r
1189 //\r
1190 return FALSE;\r
1191 }\r
1192 if (IkeHdr->Flags != IKE_HEADER_FLAGS_RESPOND) {\r
1193 return FALSE;\r
1194 }\r
1195 } else {\r
1196 if (IkeHdr->Flags != IKE_HEADER_FLAGS_INIT) {\r
1197 return FALSE;\r
1198 }\r
1199 }\r
1200 }\r
1201\r
1202 return TRUE;\r
1203}\r
1204\r
1205/**\r
1206 Create and intialize IKEV2_SA_DATA for speicifed IKEV2_SESSION_COMMON.\r
1207\r
1208 This function will be only called by the initiator. The responder's IKEV2_SA_DATA\r
1209 will be generated during parsed the initiator packet.\r
1210\r
1211 @param[in] SessionCommon Pointer to IKEV2_SESSION_COMMON related to.\r
1212\r
1213 @retval a Pointer to a new IKEV2_SA_DATA or NULL.\r
1214\r
1215**/\r
1216IKEV2_SA_DATA *\r
1217Ikev2InitializeSaData (\r
1218 IN IKEV2_SESSION_COMMON *SessionCommon\r
1219 )\r
1220{\r
1221 IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
1222 IKEV2_SA_DATA *SaData;\r
1223 IKEV2_PROPOSAL_DATA *ProposalData;\r
1224 IKEV2_TRANSFORM_DATA *TransformData;\r
1225 IKE_SA_ATTRIBUTE *Attribute;\r
1226\r
1227 ASSERT (SessionCommon != NULL);\r
1228 //\r
1229 // TODO: Remove the hard code of the support Alogrithm. Those data should be\r
1230 // get from the SPD/PAD data.\r
1231 //\r
1232 if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
1233 SaData = AllocateZeroPool (\r
1234 sizeof (IKEV2_SA_DATA) +\r
1235 sizeof (IKEV2_PROPOSAL_DATA) * 2 +\r
1236 sizeof (IKEV2_TRANSFORM_DATA) * 4 * 2\r
1237 );\r
1238 } else {\r
1239 SaData = AllocateZeroPool (\r
1240 sizeof (IKEV2_SA_DATA) +\r
1241 sizeof (IKEV2_PROPOSAL_DATA) * 2 +\r
1242 sizeof (IKEV2_TRANSFORM_DATA) * 3 * 2\r
1243 );\r
1244 }\r
1245 if (SaData == NULL) {\r
1246 return NULL;\r
1247 }\r
1248\r
1249 //\r
1250 // First proposal payload: 3DES + SHA1 + DH\r
1251 //\r
1252 SaData->NumProposals = 2;\r
1253 ProposalData = (IKEV2_PROPOSAL_DATA *) (SaData + 1);\r
1254 ProposalData->ProposalIndex = 1;\r
1255\r
1256 //\r
1257 // If SA data for IKE_SA_INIT exchage, contains 4 transforms. If SA data for \r
1258 // IKE_AUTH exchange contains 3 transforms.\r
1259 //\r
1260 if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
1261 ProposalData->NumTransforms = 4;\r
1262 } else {\r
1263 ProposalData->NumTransforms = 3;\r
1264 }\r
1265\r
1266\r
1267 if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
1268 ProposalData->ProtocolId = IPSEC_PROTO_ISAKMP;\r
1269 } else {\r
1270 ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);\r
1271 ProposalData->ProtocolId = IPSEC_PROTO_IPSEC_ESP;\r
1272 ProposalData->Spi = AllocateZeroPool (sizeof (ChildSaSession->LocalPeerSpi));\r
1273 ASSERT (ProposalData->Spi != NULL);\r
1274 CopyMem (\r
1275 ProposalData->Spi,\r
1276 &ChildSaSession->LocalPeerSpi,\r
1277 sizeof(ChildSaSession->LocalPeerSpi)\r
1278 );\r
1279 }\r
1280\r
1281 //\r
1282 // Set transform attribute for Encryption Algorithm - 3DES\r
1283 //\r
1284 TransformData = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1);\r
1285 TransformData->TransformIndex = 0;\r
1286 TransformData->TransformType = IKEV2_TRANSFORM_TYPE_ENCR;\r
1287 TransformData->TransformId = IKEV2_TRANSFORM_ID_ENCR_3DES;\r
1288\r
1289 //\r
1290 // Set transform attribute for Integrity Algorithm - SHA1_96\r
1291 //\r
1292 TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
1293 TransformData->TransformIndex = 1;\r
1294 TransformData->TransformType = IKEV2_TRANSFORM_TYPE_INTEG;\r
1295 TransformData->TransformId = IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96;\r
1296\r
1297 if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
1298 //\r
1299 // Set transform attribute for Pseduo-Random Function - HAMC_SHA1\r
1300 //\r
1301 TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
1302 TransformData->TransformIndex = 2;\r
1303 TransformData->TransformType = IKEV2_TRANSFORM_TYPE_PRF;\r
1304 TransformData->TransformId = IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1;\r
1305 }\r
1306\r
1307 if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
1308 //\r
1309 // Set transform attribute for DH Group - DH 1024\r
1310 //\r
1311 TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
1312 TransformData->TransformIndex = 3;\r
1313 TransformData->TransformType = IKEV2_TRANSFORM_TYPE_DH;\r
1314 TransformData->TransformId = IKEV2_TRANSFORM_ID_DH_1024MODP;\r
1315 } else {\r
1316 //\r
1317 // Transform type for Extended Sequence Numbers. Currently not support Extended\r
1318 // Sequence Number.\r
1319 //\r
1320 TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
1321 TransformData->TransformIndex = 2;\r
1322 TransformData->TransformType = IKEV2_TRANSFORM_TYPE_ESN;\r
1323 TransformData->TransformId = 0;\r
1324 }\r
1325\r
1326 //\r
1327 // Second proposal payload: 3DES + SHA1 + DH\r
1328 //\r
1329 ProposalData = (IKEV2_PROPOSAL_DATA *) (TransformData + 1);\r
1330 ProposalData->ProposalIndex = 2;\r
1331\r
1332 if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
1333 ProposalData->ProtocolId = IPSEC_PROTO_ISAKMP;\r
1334 ProposalData->NumTransforms = 4;\r
1335 } else {\r
1336\r
1337 ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);\r
1338 ProposalData->ProtocolId = IPSEC_PROTO_IPSEC_ESP;\r
1339 ProposalData->NumTransforms = 3;\r
1340 ProposalData->Spi = AllocateZeroPool (sizeof (ChildSaSession->LocalPeerSpi));\r
1341 ASSERT (ProposalData->Spi != NULL);\r
1342 CopyMem (\r
1343 ProposalData->Spi,\r
1344 &ChildSaSession->LocalPeerSpi,\r
1345 sizeof(ChildSaSession->LocalPeerSpi)\r
1346 );\r
1347 }\r
1348\r
1349 //\r
1350 // Set transform attribute for Encryption Algorithm - AES-CBC\r
1351 //\r
1352 TransformData = (IKEV2_TRANSFORM_DATA *) (ProposalData + 1);\r
1353 TransformData->TransformIndex = 0;\r
1354 TransformData->TransformType = IKEV2_TRANSFORM_TYPE_ENCR;\r
1355 TransformData->TransformId = IKEV2_TRANSFORM_ID_ENCR_AES_CBC;\r
1356 Attribute = &TransformData->Attribute;\r
1357 Attribute->AttrType = IKEV2_ATTRIBUTE_TYPE_KEYLEN;\r
1358 Attribute->Attr.AttrLength = (UINT16) (8 * IpSecGetEncryptKeyLength (IKEV2_TRANSFORM_ID_ENCR_AES_CBC));\r
1359\r
1360 //\r
1361 // Set transform attribute for Integrity Algorithm - SHA1_96\r
1362 //\r
1363 TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
1364 TransformData->TransformIndex = 1;\r
1365 TransformData->TransformType = IKEV2_TRANSFORM_TYPE_INTEG;\r
1366 TransformData->TransformId = IKEV2_TRANSFORM_ID_AUTH_HMAC_SHA1_96;\r
1367\r
1368 if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
1369 //\r
1370 // Set transform attribute for Pseduo-Random Function - HAMC_SHA1\r
1371 //\r
1372 TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
1373 TransformData->TransformIndex = 2;\r
1374 TransformData->TransformType = IKEV2_TRANSFORM_TYPE_PRF;\r
1375 TransformData->TransformId = IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1;\r
1376 }\r
1377\r
1378 if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
1379 //\r
1380 // Set transform attrbiute for DH Group - DH-1024\r
1381 //\r
1382 TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
1383 TransformData->TransformIndex = 3;\r
1384 TransformData->TransformType = IKEV2_TRANSFORM_TYPE_DH;\r
1385 TransformData->TransformId = IKEV2_TRANSFORM_ID_DH_1024MODP;\r
1386 } else {\r
1387 //\r
1388 // Transform type for Extended Sequence Numbers. Currently not support Extended\r
1389 // Sequence Number.\r
1390 //\r
1391 TransformData = (IKEV2_TRANSFORM_DATA *) (TransformData + 1);\r
1392 TransformData->TransformIndex = 2;\r
1393 TransformData->TransformType = IKEV2_TRANSFORM_TYPE_ESN;\r
1394 TransformData->TransformId = 0;\r
1395 }\r
1396\r
1397 return SaData;\r
1398}\r
1399\r
1400/**\r
1401 Store the SA into SAD.\r
1402\r
1403 @param[in] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION.\r
1404\r
1405**/\r
1406VOID\r
1407Ikev2StoreSaData (\r
1408 IN IKEV2_CHILD_SA_SESSION *ChildSaSession\r
1409 )\r
1410{\r
1411 EFI_STATUS Status;\r
1412 EFI_IPSEC_SA_ID SaId;\r
1413 EFI_IPSEC_SA_DATA2 SaData;\r
1414 IKEV2_SESSION_COMMON *SessionCommon;\r
1415 IPSEC_PRIVATE_DATA *Private;\r
1416 UINT32 TempAddressCount;\r
1417 EFI_IP_ADDRESS_INFO *TempAddressInfo;\r
1418\r
1419 SessionCommon = &ChildSaSession->SessionCommon;\r
1420 Private = SessionCommon->Private;\r
1421\r
1422 ZeroMem (&SaId, sizeof (EFI_IPSEC_SA_ID));\r
1423 ZeroMem (&SaData, sizeof (EFI_IPSEC_SA_DATA2));\r
1424\r
1425 //\r
1426 // Create a SpdSelector. In this implementation, one SPD represents\r
1427 // 2 direction traffic, so in here, there needs to reverse the local address \r
1428 // and remote address for Remote Peer's SA, then reverse again for the locate\r
1429 // SA. \r
1430 //\r
1431 TempAddressCount = ChildSaSession->SpdSelector->LocalAddressCount;\r
1432 TempAddressInfo = ChildSaSession->SpdSelector->LocalAddress;\r
1433\r
1434 ChildSaSession->SpdSelector->LocalAddressCount = ChildSaSession->SpdSelector->RemoteAddressCount;\r
1435 ChildSaSession->SpdSelector->LocalAddress = ChildSaSession->SpdSelector->RemoteAddress;\r
1436\r
1437 ChildSaSession->SpdSelector->RemoteAddress = TempAddressInfo;\r
1438 ChildSaSession->SpdSelector->RemoteAddressCount= TempAddressCount;\r
1439\r
1440 //\r
1441 // Set the SaId and SaData.\r
1442 //\r
1443 SaId.Spi = ChildSaSession->LocalPeerSpi;\r
1444 SaId.Proto = EfiIPsecESP;\r
1445 SaData.AntiReplayWindows = 16;\r
1446 SaData.SNCount = 0;\r
1447 SaData.Mode = ChildSaSession->Spd->Data->ProcessingPolicy->Mode;\r
1448\r
1449 //\r
1450 // If it is tunnel mode, should add the TunnelDest and TunnelSource for SaData.\r
1451 //\r
1452 if (SaData.Mode == EfiIPsecTunnel) {\r
1453 CopyMem (\r
1454 &SaData.TunnelSourceAddress, \r
1455 &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress,\r
1456 sizeof (EFI_IP_ADDRESS)\r
1457 );\r
1458 CopyMem (\r
1459 &SaData.TunnelDestinationAddress,\r
1460 &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->LocalTunnelAddress,\r
1461 sizeof (EFI_IP_ADDRESS)\r
1462 );\r
1463 }\r
1464\r
1465 CopyMem (&SaId.DestAddress, &ChildSaSession->SessionCommon.LocalPeerIp, sizeof (EFI_IP_ADDRESS));\r
1466 CopyMem (&SaData.AlgoInfo, &ChildSaSession->ChildKeymats.LocalPeerInfo, sizeof (EFI_IPSEC_ALGO_INFO));\r
1467 SaData.SpdSelector = ChildSaSession->SpdSelector;\r
1468\r
1469 //\r
1470 // Store the remote SA into SAD.\r
1471 //\r
1472 Status = EfiIpSecConfigSetData (\r
1473 &Private->IpSecConfig,\r
1474 IPsecConfigDataTypeSad,\r
1475 (EFI_IPSEC_CONFIG_SELECTOR *) &SaId,\r
1476 &SaData,\r
1477 NULL\r
1478 );\r
1479 ASSERT_EFI_ERROR (Status);\r
1480\r
1481 //\r
1482 // Store the local SA into SAD.\r
1483 // \r
1484 ChildSaSession->SpdSelector->RemoteAddressCount = ChildSaSession->SpdSelector->LocalAddressCount;\r
1485 ChildSaSession->SpdSelector->RemoteAddress = ChildSaSession->SpdSelector->LocalAddress;\r
1486\r
1487 ChildSaSession->SpdSelector->LocalAddress = TempAddressInfo;\r
1488 ChildSaSession->SpdSelector->LocalAddressCount = TempAddressCount;\r
1489 \r
1490 SaId.Spi = ChildSaSession->RemotePeerSpi;\r
1491\r
1492 CopyMem (&SaId.DestAddress, &ChildSaSession->SessionCommon.RemotePeerIp, sizeof (EFI_IP_ADDRESS));\r
1493 CopyMem (&SaData.AlgoInfo, &ChildSaSession->ChildKeymats.RemotePeerInfo, sizeof (EFI_IPSEC_ALGO_INFO));\r
1494 SaData.SpdSelector = ChildSaSession->SpdSelector;\r
1495\r
1496 //\r
1497 // If it is tunnel mode, should add the TunnelDest and TunnelSource for SaData.\r
1498 //\r
1499 if (SaData.Mode == EfiIPsecTunnel) {\r
1500 CopyMem (\r
1501 &SaData.TunnelSourceAddress,\r
1502 &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->LocalTunnelAddress,\r
1503 sizeof (EFI_IP_ADDRESS)\r
1504 );\r
1505 CopyMem (\r
1506 &SaData.TunnelDestinationAddress,\r
1507 &ChildSaSession->Spd->Data->ProcessingPolicy->TunnelOption->RemoteTunnelAddress,\r
1508 sizeof (EFI_IP_ADDRESS)\r
1509 );\r
1510 }\r
1511\r
1512 Status = EfiIpSecConfigSetData (\r
1513 &Private->IpSecConfig,\r
1514 IPsecConfigDataTypeSad,\r
1515 (EFI_IPSEC_CONFIG_SELECTOR *) &SaId,\r
1516 &SaData,\r
1517 NULL\r
1518 );\r
1519\r
1520 ASSERT_EFI_ERROR (Status);\r
1521}\r
1522\r
1523/**\r
1524 Call back function of the IKE life time is over.\r
1525\r
1526 This function will mark the related IKE SA Session as deleting and trigger a \r
1527 Information negotiation.\r
1528\r
1529 @param[in] Event The signaled Event.\r
1530 @param[in] Context Pointer to data passed by caller.\r
1531 \r
1532**/\r
1533VOID\r
1534EFIAPI\r
1535Ikev2LifetimeNotify (\r
1536 IN EFI_EVENT Event,\r
1537 IN VOID *Context\r
1538 )\r
1539{\r
1540 IKEV2_SA_SESSION *IkeSaSession;\r
1541 IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
1542 IKEV2_SESSION_COMMON *SessionCommon;\r
1543\r
1544 ASSERT (Context != NULL);\r
1545 SessionCommon = (IKEV2_SESSION_COMMON *) Context;\r
1546\r
1547 if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
1548 IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);\r
1549 DEBUG ((\r
1550 DEBUG_INFO,\r
1551 "\n---IkeSa Lifetime is out(cookie_i, cookie_r):(0x%lx, 0x%lx)---\n",\r
1552 IkeSaSession->InitiatorCookie,\r
1553 IkeSaSession->ResponderCookie\r
1554 ));\r
1555\r
1556 //\r
1557 // Change the IKE SA Session's State to IKE_STATE_SA_DELETING.\r
1558 //\r
1559 IKEV2_DUMP_STATE (IkeSaSession->SessionCommon.State, IkeStateSaDeleting);\r
1560 IkeSaSession->SessionCommon.State = IkeStateSaDeleting;\r
1561\r
1562 } else {\r
1563 ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);\r
1564 IkeSaSession = ChildSaSession->IkeSaSession;\r
1565\r
1566 //\r
1567 // Link the timeout child SA to the DeleteSaList.\r
1568 //\r
1569 InsertTailList (&IkeSaSession->DeleteSaList, &ChildSaSession->ByDelete);\r
1570\r
1571 //\r
1572 // Change the Child SA Session's State to IKE_STATE_SA_DELETING.\r
1573 // \r
1574 DEBUG ((\r
1575 DEBUG_INFO,\r
1576 "\n------ChildSa Lifetime is out(SPI):(0x%x)------\n",\r
1577 ChildSaSession->LocalPeerSpi\r
1578 ));\r
1579 }\r
1580\r
1581 //\r
1582 // TODO: Send the delete info packet or delete silently\r
1583 //\r
1584 mIkev2Exchange.NegotiateInfo ((UINT8 *) IkeSaSession, NULL);\r
1585}\r
1586\r
1587/**\r
1588 This function will be called if the TimeOut Event is signaled.\r
1589\r
1590 @param[in] Event The signaled Event.\r
1591 @param[in] Context The data passed by caller.\r
1592\r
1593**/\r
1594VOID\r
1595EFIAPI\r
1596Ikev2ResendNotify (\r
1597 IN EFI_EVENT Event,\r
1598 IN VOID *Context\r
1599 )\r
1600{\r
1601 IPSEC_PRIVATE_DATA *Private;\r
1602 IKEV2_SA_SESSION *IkeSaSession;\r
1603 IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
1604 IKEV2_SESSION_COMMON *SessionCommon;\r
1605 LIST_ENTRY *ChildSaEntry;\r
1606 UINT8 Value;\r
1607 EFI_STATUS Status;\r
1608\r
1609 ASSERT (Context != NULL); \r
1610 IkeSaSession = NULL;\r
1611 ChildSaSession = NULL;\r
1612 SessionCommon = (IKEV2_SESSION_COMMON *) Context;\r
1613 Private = SessionCommon->Private;\r
1614\r
1615 //\r
1616 // Remove the SA session from the processing list if exceed the max retry.\r
1617 //\r
1618 if (SessionCommon->RetryCount > IKE_MAX_RETRY) {\r
1619 if (SessionCommon->IkeSessionType == IkeSessionTypeIkeSa) {\r
1620 IkeSaSession = IKEV2_SA_SESSION_FROM_COMMON (SessionCommon);\r
1621 if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting) {\r
1622\r
1623 //\r
1624 // If the IkeSaSession is initiator, delete all its Child SAs before removing IKE SA.\r
1625 // If the IkesaSession is responder, all ChildSa has been remove in Ikev2HandleInfo();\r
1626 //\r
1627 for (ChildSaEntry = IkeSaSession->ChildSaEstablishSessionList.ForwardLink;\r
1628 ChildSaEntry != &IkeSaSession->ChildSaEstablishSessionList;\r
1629 ) {\r
1630 ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (ChildSaEntry);\r
1631 //\r
1632 // Move to next ChildSa Entry.\r
1633 //\r
1634 ChildSaEntry = ChildSaEntry->ForwardLink;\r
1635 //\r
1636 // Delete LocalSpi & RemoteSpi and remove the ChildSaSession from the\r
1637 // EstablishedChildSaList.\r
1638 //\r
1639 Ikev2ChildSaSilentDelete (IkeSaSession, ChildSaSession->LocalPeerSpi);\r
1640 }\r
1641\r
1642 //\r
1643 // If the IKE SA Delete Payload wasn't sent out successfully, Delete it from the EstablishedList.\r
1644 //\r
1645 Ikev2SaSessionRemove (&Private->Ikev2EstablishedList, &SessionCommon->RemotePeerIp);\r
1646\r
1647 if (Private != NULL && Private->IsIPsecDisabling) {\r
1648 //\r
1649 // After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in\r
1650 // IPsec status variable.\r
1651 //\r
1652 if (IsListEmpty (&Private->Ikev1EstablishedList) && IsListEmpty (&Private->Ikev2EstablishedList)) {\r
1653 Value = IPSEC_STATUS_DISABLED;\r
1654 Status = gRT->SetVariable (\r
1655 IPSECCONFIG_STATUS_NAME,\r
1656 &gEfiIpSecConfigProtocolGuid,\r
1657 EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,\r
1658 sizeof (Value),\r
1659 &Value\r
1660 );\r
1661 if (!EFI_ERROR (Status)) {\r
1662 //\r
1663 // Set the Disabled Flag in Private data.\r
1664 //\r
1665 Private->IpSec.DisabledFlag = TRUE;\r
1666 Private->IsIPsecDisabling = FALSE;\r
1667 }\r
1668 }\r
1669 }\r
1670 } else {\r
1671 Ikev2SaSessionRemove (&Private->Ikev2SessionList, &SessionCommon->RemotePeerIp);\r
1672 }\r
1673 Ikev2SaSessionFree (IkeSaSession);\r
1674\r
1675 } else {\r
1676\r
1677 //\r
1678 // If the packet sent by Child SA.\r
1679 //\r
1680 ChildSaSession = IKEV2_CHILD_SA_SESSION_FROM_COMMON (SessionCommon);\r
1681 IkeSaSession = ChildSaSession->IkeSaSession;\r
1682 if (ChildSaSession->SessionCommon.State == IkeStateSaDeleting) {\r
1683\r
1684 //\r
1685 // Established Child SA should be remove from the SAD entry and \r
1686 // DeleteList. The function of Ikev2DeleteChildSaSilent() will remove \r
1687 // the childSA from the IkeSaSession->ChildSaEstablishedList. So there \r
1688 // is no need to remove it here.\r
1689 //\r
1690 Ikev2ChildSaSilentDelete (IkeSaSession, ChildSaSession->LocalPeerSpi);\r
1691 Ikev2ChildSaSessionRemove (\r
1692 &IkeSaSession->DeleteSaList,\r
1693 ChildSaSession->LocalPeerSpi,\r
1694 IKEV2_DELET_CHILDSA_LIST\r
1695 );\r
1696 } else {\r
1697 Ikev2ChildSaSessionRemove (\r
1698 &IkeSaSession->ChildSaSessionList,\r
1699 ChildSaSession->LocalPeerSpi,\r
1700 IKEV2_ESTABLISHING_CHILDSA_LIST\r
1701 );\r
1702 }\r
1703\r
1704 Ikev2ChildSaSessionFree (ChildSaSession);\r
1705 }\r
1706 return ;\r
1707 }\r
1708\r
1709 //\r
1710 // Increase the retry count.\r
1711 //\r
1712 SessionCommon->RetryCount++;\r
1713 DEBUG ((DEBUG_INFO, ">>>Resending the last packet ...\n"));\r
1714\r
1715 //\r
1716 // Resend the last packet.\r
1717 //\r
1718 Ikev2SendIkePacket (\r
1719 SessionCommon->UdpService,\r
1720 (UINT8*)SessionCommon,\r
1721 SessionCommon->LastSentPacket,\r
1722 0\r
1723 );\r
1724}\r
1725\r
1726/**\r
1727 Copy ChildSaSession->Spd->Selector to ChildSaSession->SpdSelector.\r
1728\r
1729 ChildSaSession->SpdSelector stores the real Spdselector for its SA. Sometime,\r
1730 the SpdSelector in ChildSaSession is more accurated or the scope is smaller \r
1731 than the one in ChildSaSession->Spd, especially for the tunnel mode.\r
1732 \r
1733 @param[in, out] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION related to.\r
1734 \r
1735**/\r
1736VOID\r
1737Ikev2ChildSaSessionSpdSelectorCreate (\r
1738 IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession\r
1739 ) \r
1740{\r
1741 if (ChildSaSession->Spd != NULL && ChildSaSession->Spd->Selector != NULL) {\r
1742 if (ChildSaSession->SpdSelector == NULL) {\r
1743 ChildSaSession->SpdSelector = AllocateZeroPool (sizeof (EFI_IPSEC_SPD_SELECTOR));\r
1744 ASSERT (ChildSaSession->SpdSelector != NULL);\r
1745 }\r
1746 CopyMem (\r
1747 ChildSaSession->SpdSelector, \r
1748 ChildSaSession->Spd->Selector, \r
1749 sizeof (EFI_IPSEC_SPD_SELECTOR)\r
1750 );\r
1751 ChildSaSession->SpdSelector->RemoteAddress = AllocateCopyPool (\r
1752 ChildSaSession->Spd->Selector->RemoteAddressCount * \r
1753 sizeof (EFI_IP_ADDRESS_INFO), \r
1754 ChildSaSession->Spd->Selector->RemoteAddress\r
1755 );\r
1756 ChildSaSession->SpdSelector->LocalAddress = AllocateCopyPool (\r
1757 ChildSaSession->Spd->Selector->LocalAddressCount * \r
1758 sizeof (EFI_IP_ADDRESS_INFO), \r
1759 ChildSaSession->Spd->Selector->LocalAddress\r
1760 );\r
1761\r
1762 ASSERT (ChildSaSession->SpdSelector->LocalAddress != NULL);\r
1763 ASSERT (ChildSaSession->SpdSelector->RemoteAddress != NULL);\r
1764\r
1765 ChildSaSession->SpdSelector->RemoteAddressCount = ChildSaSession->Spd->Selector->RemoteAddressCount;\r
1766 ChildSaSession->SpdSelector->LocalAddressCount = ChildSaSession->Spd->Selector->LocalAddressCount; \r
1767 }\r
1768}\r
1769\r
1770/**\r
1771 Generate a ChildSa Session and insert it into related IkeSaSession.\r
1772\r
1773 @param[in] IkeSaSession Pointer to related IKEV2_SA_SESSION.\r
1774 @param[in] UdpService Pointer to related IKE_UDP_SERVICE.\r
1775\r
1776 @return pointer of IKEV2_CHILD_SA_SESSION.\r
1777\r
1778**/\r
1779IKEV2_CHILD_SA_SESSION *\r
1780Ikev2ChildSaSessionCreate (\r
1781 IN IKEV2_SA_SESSION *IkeSaSession,\r
1782 IN IKE_UDP_SERVICE *UdpService\r
1783 )\r
1784{\r
1785 IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
1786 IKEV2_SESSION_COMMON *ChildSaCommon;\r
1787\r
1788 //\r
1789 // Create a new ChildSaSession.Insert it into processing list and initiate the common parameters.\r
1790 //\r
1791 ChildSaSession = Ikev2ChildSaSessionAlloc (UdpService, IkeSaSession);\r
1792 ASSERT (ChildSaSession != NULL);\r
1793\r
1794 //\r
1795 // Set the specific parameters.\r
1796 // \r
1797 ChildSaSession->Spd = IkeSaSession->Spd;\r
1798 ChildSaCommon = &ChildSaSession->SessionCommon;\r
1799 ChildSaCommon->IsInitiator = IkeSaSession->SessionCommon.IsInitiator;\r
1800 if (IkeSaSession->SessionCommon.State == IkeStateAuth) {\r
1801 ChildSaCommon->State = IkeStateAuth;\r
1802 IKEV2_DUMP_STATE (ChildSaCommon->State, IkeStateAuth);\r
1803 } else {\r
1804 ChildSaCommon->State = IkeStateCreateChild;\r
1805 IKEV2_DUMP_STATE (ChildSaCommon->State, IkeStateCreateChild);\r
1806 }\r
1807\r
1808 //\r
1809 // If SPD->Selector is not NULL, copy it to the ChildSaSession->SpdSelector.\r
1810 // The ChildSaSession->SpdSelector might be changed after the traffic selector\r
1811 // negoniation and it will be copied into the SAData after ChildSA established.\r
1812 //\r
1813 Ikev2ChildSaSessionSpdSelectorCreate (ChildSaSession);\r
1814\r
1815 //\r
1816 // Copy first NiBlock and NrBlock to ChildSa Session\r
1817 //\r
1818 ChildSaSession->NiBlock = AllocateZeroPool (IkeSaSession->NiBlkSize);\r
1819 ASSERT (ChildSaSession->NiBlock != NULL);\r
1820 ChildSaSession->NiBlkSize = IkeSaSession->NiBlkSize;\r
1821 CopyMem (ChildSaSession->NiBlock, IkeSaSession->NiBlock, IkeSaSession->NiBlkSize);\r
1822\r
1823 ChildSaSession->NrBlock = AllocateZeroPool (IkeSaSession->NrBlkSize);\r
1824 ASSERT (ChildSaSession->NrBlock != NULL);\r
1825 ChildSaSession->NrBlkSize = IkeSaSession->NrBlkSize;\r
1826 CopyMem (ChildSaSession->NrBlock, IkeSaSession->NrBlock, IkeSaSession->NrBlkSize);\r
1827\r
1828 //\r
1829 // Only if the Create Child SA is called for the IKE_INIT Exchange and \r
1830 // IkeSaSession is initiator (Only Initiator's SPD is not NULL), Set the \r
1831 // Traffic Selectors related information here.\r
1832 //\r
1833 if (IkeSaSession->SessionCommon.State == IkeStateAuth && IkeSaSession->Spd != NULL) {\r
1834 ChildSaSession->ProtoId = IkeSaSession->Spd->Selector->NextLayerProtocol;\r
1835 ChildSaSession->LocalPort = IkeSaSession->Spd->Selector->LocalPort;\r
1836 ChildSaSession->RemotePort = IkeSaSession->Spd->Selector->RemotePort;\r
1837 }\r
1838\r
1839 //\r
1840 // Insert the new ChildSaSession into processing child SA list.\r
1841 //\r
1842 Ikev2ChildSaSessionInsert (&IkeSaSession->ChildSaSessionList, ChildSaSession);\r
1843 return ChildSaSession;\r
1844}\r
1845\r
1846/**\r
1847 Check if the SPD is related to the input Child SA Session.\r
1848\r
1849 This function is the subfunction of Ikev1AssociateSpdEntry(). It is the call\r
1850 back function of IpSecVisitConfigData(). \r
1851 \r
1852\r
1853 @param[in] Type Type of the input Config Selector.\r
1854 @param[in] Selector Pointer to the Configure Selector to be checked. \r
1855 @param[in] Data Pointer to the Configure Selector's Data passed \r
1856 from the caller.\r
1857 @param[in] SelectorSize The buffer size of Selector.\r
1858 @param[in] DataSize The buffer size of the Data.\r
1859 @param[in] Context The data passed from the caller. It is a Child\r
1860 SA Session in this context.\r
1861\r
1862 @retval EFI_SUCCESS The SPD Selector is not related to the Child SA Session. \r
1863 @retval EFI_ABORTED The SPD Selector is related to the Child SA session and \r
1864 set the ChildSaSession->Spd to point to this SPD Selector.\r
1865\r
1866**/\r
1867EFI_STATUS\r
1868Ikev2MatchSpdEntry (\r
1869 IN EFI_IPSEC_CONFIG_DATA_TYPE Type,\r
1870 IN EFI_IPSEC_CONFIG_SELECTOR *Selector,\r
1871 IN VOID *Data,\r
1872 IN UINTN SelectorSize,\r
1873 IN UINTN DataSize,\r
1874 IN VOID *Context\r
1875 )\r
1876{\r
1877 IKEV2_CHILD_SA_SESSION *ChildSaSession;\r
1878 EFI_IPSEC_SPD_SELECTOR *SpdSelector;\r
1879 EFI_IPSEC_SPD_DATA *SpdData;\r
1880 BOOLEAN IsMatch;\r
1881 UINT8 IpVersion;\r
1882\r
1883 ASSERT (Type == IPsecConfigDataTypeSpd);\r
1884 SpdData = (EFI_IPSEC_SPD_DATA *) Data;\r
1885 //\r
1886 // Bypass all non-protect SPD entry first\r
1887 //\r
1888 if (SpdData->Action != EfiIPsecActionProtect) {\r
1889 return EFI_SUCCESS;\r
1890 }\r
1891\r
1892 ChildSaSession = (IKEV2_CHILD_SA_SESSION *) Context;\r
1893 IpVersion = ChildSaSession->SessionCommon.UdpService->IpVersion;\r
1894 SpdSelector = (EFI_IPSEC_SPD_SELECTOR *) Selector; \r
1895 IsMatch = TRUE;\r
1896\r
1897 if (SpdSelector->NextLayerProtocol == EFI_IP_PROTO_UDP &&\r
1898 SpdSelector->LocalPort == IKE_DEFAULT_PORT &&\r
1899 SpdSelector->LocalPortRange == 0 &&\r
1900 SpdSelector->RemotePort == IKE_DEFAULT_PORT &&\r
1901 SpdSelector->RemotePortRange == 0\r
1902 ) {\r
1903 //\r
1904 // TODO: Skip IKE Policy here or set a SPD entry?\r
1905 //\r
1906 return EFI_SUCCESS;\r
1907 }\r
1908\r
1909 if (SpdSelector->NextLayerProtocol != EFI_IPSEC_ANY_PROTOCOL &&\r
1910 SpdSelector->NextLayerProtocol != ChildSaSession->ProtoId\r
1911 ) {\r
1912 IsMatch = FALSE;\r
1913 }\r
1914\r
1915 if (SpdSelector->LocalPort != EFI_IPSEC_ANY_PORT && SpdSelector->LocalPort != ChildSaSession->LocalPort) {\r
1916 IsMatch = FALSE;\r
1917 }\r
1918\r
1919 if (SpdSelector->RemotePort != EFI_IPSEC_ANY_PORT && SpdSelector->RemotePort != ChildSaSession->RemotePort) {\r
1920 IsMatch = FALSE;\r
1921 }\r
1922\r
1923 IsMatch = (BOOLEAN) (IsMatch && \r
1924 IpSecMatchIpAddress (\r
1925 IpVersion,\r
1926 &ChildSaSession->SessionCommon.LocalPeerIp,\r
1927 SpdSelector->LocalAddress,\r
1928 SpdSelector->LocalAddressCount\r
1929 ));\r
1930\r
1931 IsMatch = (BOOLEAN) (IsMatch && \r
1932 IpSecMatchIpAddress (\r
1933 IpVersion,\r
1934 &ChildSaSession->SessionCommon.RemotePeerIp,\r
1935 SpdSelector->RemoteAddress,\r
1936 SpdSelector->RemoteAddressCount\r
1937 ));\r
1938\r
1939 if (IsMatch) {\r
1940 ChildSaSession->Spd = IkeSearchSpdEntry (SpdSelector);\r
1941 return EFI_ABORTED;\r
1942 } else {\r
1943 return EFI_SUCCESS;\r
1944 }\r
1945}\r
1946\r
1947/**\r
1948 Check if the Algorithm ID is supported.\r
1949\r
1950 @param[in] AlgorithmId The specified Algorithm ID.\r
1951 @param[in] Type The type used to indicate the Algorithm is for Encrypt or\r
1952 Authentication.\r
1953\r
1954 @retval TRUE If the Algorithm ID is supported.\r
1955 @retval FALSE If the Algorithm ID is not supported.\r
1956\r
1957**/\r
1958BOOLEAN\r
1959Ikev2IsSupportAlg (\r
1960 IN UINT16 AlgorithmId,\r
1961 IN UINT8 Type\r
1962 )\r
1963{\r
1964 UINT8 Index;\r
1965 switch (Type) {\r
1966 case IKE_ENCRYPT_TYPE :\r
1967 for (Index = 0; Index < IKEV2_SUPPORT_ENCRYPT_ALGORITHM_NUM; Index++) {\r
1968 if (mIkev2EncryptAlgorithmList[Index] == AlgorithmId) {\r
1969 return TRUE;\r
1970 }\r
1971 }\r
1972 break;\r
1973\r
1974 case IKE_AUTH_TYPE :\r
1975 for (Index = 0; Index < IKEV2_SUPPORT_AUTH_ALGORITHM_NUM; Index++) {\r
1976 if (mIkev2AuthAlgorithmList[Index] == AlgorithmId) {\r
1977 return TRUE;\r
1978 }\r
1979 }\r
1980 break;\r
1981\r
1982 case IKE_DH_TYPE :\r
1983 for (Index = 0; Index < IKEV2_SUPPORT_DH_ALGORITHM_NUM; Index++) {\r
1984 if (mIkev2DhGroupAlgorithmList[Index] == AlgorithmId) {\r
1985 return TRUE;\r
1986 }\r
1987 }\r
1988 break;\r
1989\r
1990 case IKE_PRF_TYPE :\r
1991 for (Index = 0; Index < IKEV2_SUPPORT_PRF_ALGORITHM_NUM; Index++) {\r
1992 if (mIkev2PrfAlgorithmList[Index] == AlgorithmId) {\r
1993 return TRUE;\r
1994 }\r
1995 }\r
1996 }\r
1997 return FALSE;\r
1998}\r
1999\r
2000/**\r
2001 Get the preferred algorithm types from ProposalData.\r
2002\r
2003 @param[in] ProposalData Pointer to related IKEV2_PROPOSAL_DATA.\r
2004 @param[out] PreferEncryptAlgorithm Output of preferred encrypt algorithm.\r
2005 @param[out] PreferIntegrityAlgorithm Output of preferred integrity algorithm. \r
2006 @param[out] PreferPrfAlgorithm Output of preferred PRF algorithm. Only \r
2007 for IKE SA.\r
2008 @param[out] PreferDhGroup Output of preferred DH group. Only for \r
2009 IKE SA.\r
2010 @param[out] PreferEncryptKeylength Output of preferred encrypt key length \r
2011 in bytes.\r
2012 @param[out] IsSupportEsn Output of value about the Extented Sequence\r
2013 Number is support or not. Only for Child SA.\r
2014 @param[in] IsChildSa If it is ture, the ProposalData is for IKE\r
2015 SA. Otherwise the proposalData is for Child SA.\r
2016\r
2017**/\r
2018VOID\r
2019Ikev2ParseProposalData (\r
2020 IN IKEV2_PROPOSAL_DATA *ProposalData, \r
2021 OUT UINT16 *PreferEncryptAlgorithm,\r
2022 OUT UINT16 *PreferIntegrityAlgorithm,\r
2023 OUT UINT16 *PreferPrfAlgorithm,\r
2024 OUT UINT16 *PreferDhGroup,\r
2025 OUT UINTN *PreferEncryptKeylength,\r
2026 OUT BOOLEAN *IsSupportEsn,\r
2027 IN BOOLEAN IsChildSa\r
2028) \r
2029{\r
2030 IKEV2_TRANSFORM_DATA *TransformData;\r
2031 UINT8 TransformIndex;\r
2032\r
2033 //\r
2034 // Check input parameters.\r
2035 //\r
2036 if (ProposalData == NULL ||\r
2037 PreferEncryptAlgorithm == NULL || \r
2038 PreferIntegrityAlgorithm == NULL ||\r
2039 PreferEncryptKeylength == NULL\r
2040 ) {\r
2041 return;\r
2042 }\r
2043\r
2044 if (IsChildSa) {\r
2045 if (IsSupportEsn == NULL) {\r
2046 return;\r
2047 }\r
2048 } else {\r
2049 if (PreferPrfAlgorithm == NULL || PreferDhGroup == NULL) {\r
2050 return;\r
2051 }\r
2052 } \r
2053\r
2054 TransformData = (IKEV2_TRANSFORM_DATA *)(ProposalData + 1);\r
2055 for (TransformIndex = 0; TransformIndex < ProposalData->NumTransforms; TransformIndex++) {\r
2056 switch (TransformData->TransformType) { \r
2057 //\r
2058 // For IKE SA there are four algorithm types. Encryption Algorithm, Pseudo-random Function, \r
2059 // Integrity Algorithm, Diffie-Hellman Group. For Child SA, there are three algorithm types. \r
2060 // Encryption Algorithm, Integrity Algorithm, Extended Sequence Number.\r
2061 //\r
2062 case IKEV2_TRANSFORM_TYPE_ENCR:\r
2063 if (*PreferEncryptAlgorithm == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_ENCRYPT_TYPE)) {\r
2064 //\r
2065 // Check the attribute value. According to RFC, only Keylength is support.\r
2066 //\r
2067 if (TransformData->Attribute.AttrType == IKEV2_ATTRIBUTE_TYPE_KEYLEN) {\r
2068 //\r
2069 // If the Keylength is not support, continue to check the next one.\r
2070 //\r
2071 if (IpSecGetEncryptKeyLength ((UINT8)TransformData->TransformId) != (UINTN)(TransformData->Attribute.Attr.AttrValue >> 3)){\r
2072 break;\r
2073 } else {\r
2074 *PreferEncryptKeylength = TransformData->Attribute.Attr.AttrValue;\r
2075 }\r
2076 }\r
2077 *PreferEncryptAlgorithm = TransformData->TransformId;\r
2078 }\r
2079 break;\r
2080\r
2081 case IKEV2_TRANSFORM_TYPE_PRF :\r
2082 if (!IsChildSa) {\r
2083 if (*PreferPrfAlgorithm == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_PRF_TYPE)) {\r
2084 *PreferPrfAlgorithm = TransformData->TransformId;\r
2085 }\r
2086 } \r
2087 break;\r
2088\r
2089 case IKEV2_TRANSFORM_TYPE_INTEG :\r
2090 if (*PreferIntegrityAlgorithm == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_AUTH_TYPE)) {\r
2091 *PreferIntegrityAlgorithm = TransformData->TransformId;\r
2092 }\r
2093 break;\r
2094 \r
2095 case IKEV2_TRANSFORM_TYPE_DH :\r
2096 if (!IsChildSa) {\r
2097 if (*PreferDhGroup == 0 && Ikev2IsSupportAlg (TransformData->TransformId, IKE_DH_TYPE)) {\r
2098 *PreferDhGroup = TransformData->TransformId;\r
2099 }\r
2100 } \r
2101 break;\r
2102 \r
2103 case IKEV2_TRANSFORM_TYPE_ESN :\r
2104 if (IsChildSa) {\r
2105 if (TransformData->TransformId != 0) {\r
2106 *IsSupportEsn = TRUE;\r
2107 }\r
2108 } \r
2109 break;\r
2110\r
2111 default:\r
2112 break;\r
2113 }\r
2114 TransformData = (IKEV2_TRANSFORM_DATA *)(TransformData + 1);\r
2115 }\r
2116}\r
2117\r
2118/**\r
2119 Parse the received Initial Exchange Packet.\r
2120 \r
2121 This function parse the SA Payload and Key Payload to find out the cryptographic \r
2122 suite for the further IKE negotiation and fill it into the IKE SA Session's \r
2123 CommonSession->SaParams.\r
2124\r
2125 @param[in, out] IkeSaSession Pointer to related IKEV2_SA_SESSION.\r
2126 @param[in] SaPayload The received packet.\r
2127 @param[in] Type The received packet IKE header flag. \r
2128\r
2129 @retval TRUE If the SA proposal in Packet is acceptable.\r
2130 @retval FALSE If the SA proposal in Packet is not acceptable.\r
2131\r
2132**/\r
2133BOOLEAN\r
2134Ikev2SaParseSaPayload (\r
2135 IN OUT IKEV2_SA_SESSION *IkeSaSession,\r
2136 IN IKE_PAYLOAD *SaPayload,\r
2137 IN UINT8 Type\r
2138 )\r
2139{\r
2140 IKEV2_PROPOSAL_DATA *ProposalData;\r
2141 UINT8 ProposalIndex;\r
2142 UINT16 PreferEncryptAlgorithm;\r
2143 UINT16 PreferIntegrityAlgorithm;\r
2144 UINT16 PreferPrfAlgorithm;\r
2145 UINT16 PreferDhGroup;\r
2146 UINTN PreferEncryptKeylength;\r
2147 UINT16 EncryptAlgorithm;\r
2148 UINT16 IntegrityAlgorithm;\r
2149 UINT16 PrfAlgorithm;\r
2150 UINT16 DhGroup;\r
2151 UINTN EncryptKeylength;\r
2152 BOOLEAN IsMatch;\r
2153 UINTN SaDataSize;\r
2154\r
2155 PreferPrfAlgorithm = 0;\r
2156 PreferIntegrityAlgorithm = 0;\r
2157 PreferDhGroup = 0;\r
2158 PreferEncryptAlgorithm = 0;\r
2159 PreferEncryptKeylength = 0;\r
2160 PrfAlgorithm = 0;\r
2161 IntegrityAlgorithm = 0;\r
2162 DhGroup = 0;\r
2163 EncryptAlgorithm = 0;\r
2164 EncryptKeylength = 0;\r
2165 IsMatch = FALSE;\r
2166\r
2167 if (Type == IKE_HEADER_FLAGS_INIT) {\r
2168 ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *)SaPayload->PayloadBuf + 1);\r
2169 for (ProposalIndex = 0; ProposalIndex < ((IKEV2_SA_DATA *)SaPayload->PayloadBuf)->NumProposals; ProposalIndex++) {\r
2170 //\r
2171 // Iterate each proposal to find the perfered one.\r
2172 //\r
2173 if (ProposalData->ProtocolId == IPSEC_PROTO_ISAKMP && ProposalData->NumTransforms >= 4) {\r
2174 //\r
2175 // Get the preferred algorithms.\r
2176 //\r
2177 Ikev2ParseProposalData (\r
2178 ProposalData, \r
2179 &PreferEncryptAlgorithm,\r
2180 &PreferIntegrityAlgorithm,\r
2181 &PreferPrfAlgorithm,\r
2182 &PreferDhGroup,\r
2183 &PreferEncryptKeylength,\r
2184 NULL,\r
2185 FALSE\r
2186 );\r
2187\r
2188 if (PreferEncryptAlgorithm != 0 &&\r
2189 PreferIntegrityAlgorithm != 0 &&\r
2190 PreferPrfAlgorithm != 0 && \r
2191 PreferDhGroup != 0\r
2192 ) {\r
2193 //\r
2194 // Find the matched one. \r
2195 //\r
2196 IkeSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS));\r
2197 ASSERT (IkeSaSession->SessionCommon.SaParams != NULL);\r
2198 IkeSaSession->SessionCommon.SaParams->EncAlgId = PreferEncryptAlgorithm;\r
2199 IkeSaSession->SessionCommon.SaParams->EnckeyLen = PreferEncryptKeylength;\r
2200 IkeSaSession->SessionCommon.SaParams->DhGroup = PreferDhGroup;\r
2201 IkeSaSession->SessionCommon.SaParams->Prf = PreferPrfAlgorithm;\r
2202 IkeSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm;\r
2203 IkeSaSession->SessionCommon.PreferDhGroup = PreferDhGroup;\r
2204\r
2205 //\r
2206 // Save the matched one in IKEV2_SA_DATA for furthure calculation.\r
2207 //\r
2208 SaDataSize = sizeof (IKEV2_SA_DATA) +\r
2209 sizeof (IKEV2_PROPOSAL_DATA) +\r
2210 sizeof (IKEV2_TRANSFORM_DATA) * 4;\r
2211 IkeSaSession->SaData = AllocateZeroPool (SaDataSize);\r
2212 ASSERT (IkeSaSession->SaData != NULL);\r
2213\r
2214 IkeSaSession->SaData->NumProposals = 1;\r
2215\r
2216 //\r
2217 // BUGBUG: Suppose the matched proposal only has 4 transforms. If\r
2218 // The matched Proposal has more than 4 transforms means it contains\r
2219 // one than one transform with same type.\r
2220 //\r
2221 CopyMem (\r
2222 (IKEV2_PROPOSAL_DATA *) (IkeSaSession->SaData + 1), \r
2223 ProposalData, \r
2224 SaDataSize - sizeof (IKEV2_SA_DATA)\r
2225 );\r
2226\r
2227 ((IKEV2_PROPOSAL_DATA *) (IkeSaSession->SaData + 1))->ProposalIndex = 1;\r
2228 return TRUE;\r
2229 } else {\r
2230 PreferEncryptAlgorithm = 0;\r
2231 PreferIntegrityAlgorithm = 0;\r
2232 PreferPrfAlgorithm = 0;\r
2233 PreferDhGroup = 0;\r
2234 PreferEncryptKeylength = 0;\r
2235 }\r
2236 }\r
2237 //\r
2238 // Point to next Proposal.\r
2239 //\r
2240 ProposalData = (IKEV2_PROPOSAL_DATA*)((UINT8*)(ProposalData + 1) + \r
2241 ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA));\r
2242 }\r
2243 } else if (Type == IKE_HEADER_FLAGS_RESPOND) {\r
2244 //\r
2245 // First check the SA proposal's ProtoctolID and Transform Numbers. Since it is \r
2246 // the responded SA proposal, suppose it only has one proposal and the transform Numbers \r
2247 // is 4. \r
2248 //\r
2249 ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *) SaPayload->PayloadBuf + 1);\r
2250 if (ProposalData->ProtocolId != IPSEC_PROTO_ISAKMP || ProposalData->NumTransforms != 4) {\r
2251 return FALSE;\r
2252 }\r
2253 //\r
2254 // Get the preferred algorithms. \r
2255 //\r
2256 Ikev2ParseProposalData (\r
2257 ProposalData,\r
2258 &PreferEncryptAlgorithm,\r
2259 &PreferIntegrityAlgorithm,\r
2260 &PreferPrfAlgorithm,\r
2261 &PreferDhGroup,\r
2262 &PreferEncryptKeylength,\r
2263 NULL, \r
2264 FALSE\r
2265 );\r
2266 // \r
2267 // Check if the Sa proposal data from received packet is in the IkeSaSession->SaData.\r
2268 //\r
2269 ProposalData = (IKEV2_PROPOSAL_DATA *) (IkeSaSession->SaData + 1);\r
2270\r
2271 for (ProposalIndex = 0; ProposalIndex < IkeSaSession->SaData->NumProposals && (!IsMatch); ProposalIndex++) {\r
2272 Ikev2ParseProposalData (\r
2273 ProposalData, \r
2274 &EncryptAlgorithm,\r
2275 &IntegrityAlgorithm,\r
2276 &PrfAlgorithm,\r
2277 &DhGroup,\r
2278 &EncryptKeylength,\r
2279 NULL,\r
2280 FALSE\r
2281 );\r
2282 if (EncryptAlgorithm == PreferEncryptAlgorithm &&\r
2283 EncryptKeylength == PreferEncryptKeylength &&\r
2284 IntegrityAlgorithm == PreferIntegrityAlgorithm &&\r
2285 PrfAlgorithm == PreferPrfAlgorithm &&\r
2286 DhGroup == PreferDhGroup\r
2287 ) {\r
2288 IsMatch = TRUE;\r
2289 } else {\r
2290 EncryptAlgorithm = 0;\r
2291 IntegrityAlgorithm = 0;\r
2292 PrfAlgorithm = 0;\r
2293 DhGroup = 0;\r
2294 EncryptKeylength = 0; \r
2295 }\r
2296\r
2297 ProposalData = (IKEV2_PROPOSAL_DATA*)((UINT8*)(ProposalData + 1) + \r
2298 ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA)); \r
2299 }\r
2300\r
2301 if (IsMatch) {\r
2302 IkeSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS));\r
2303 ASSERT (IkeSaSession->SessionCommon.SaParams != NULL);\r
2304 IkeSaSession->SessionCommon.SaParams->EncAlgId = PreferEncryptAlgorithm;\r
2305 IkeSaSession->SessionCommon.SaParams->EnckeyLen = PreferEncryptKeylength;\r
2306 IkeSaSession->SessionCommon.SaParams->DhGroup = PreferDhGroup;\r
2307 IkeSaSession->SessionCommon.SaParams->Prf = PreferPrfAlgorithm;\r
2308 IkeSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm;\r
2309 IkeSaSession->SessionCommon.PreferDhGroup = PreferDhGroup;\r
2310 \r
2311 return TRUE;\r
2312 }\r
2313 }\r
2314 return FALSE;\r
2315}\r
2316\r
2317/**\r
2318 Parse the received Authentication Exchange Packet.\r
2319 \r
2320 This function parse the SA Payload and Key Payload to find out the cryptographic\r
2321 suite for the ESP and fill it into the Child SA Session's CommonSession->SaParams.\r
2322 \r
2323 @param[in, out] ChildSaSession Pointer to IKEV2_CHILD_SA_SESSION related to \r
2324 this Authentication Exchange.\r
2325 @param[in] SaPayload The received packet.\r
2326 @param[in] Type The IKE header's flag of received packet . \r
2327 \r
2328 @retval TRUE If the SA proposal in Packet is acceptable.\r
2329 @retval FALSE If the SA proposal in Packet is not acceptable.\r
2330\r
2331**/\r
2332BOOLEAN\r
2333Ikev2ChildSaParseSaPayload (\r
2334 IN OUT IKEV2_CHILD_SA_SESSION *ChildSaSession,\r
2335 IN IKE_PAYLOAD *SaPayload,\r
2336 IN UINT8 Type\r
2337 )\r
2338{\r
2339 IKEV2_PROPOSAL_DATA *ProposalData;\r
2340 UINT8 ProposalIndex;\r
2341 UINT16 PreferEncryptAlgorithm;\r
2342 UINT16 PreferIntegrityAlgorithm;\r
2343 UINTN PreferEncryptKeylength;\r
2344 BOOLEAN PreferIsSupportEsn;\r
2345 UINT16 EncryptAlgorithm;\r
2346 UINT16 IntegrityAlgorithm;\r
2347 UINTN EncryptKeylength;\r
2348 BOOLEAN IsSupportEsn;\r
2349 BOOLEAN IsMatch;\r
2350 UINTN SaDataSize;\r
2351\r
2352\r
2353 PreferIntegrityAlgorithm = 0;\r
2354 PreferEncryptAlgorithm = 0;\r
2355 PreferEncryptKeylength = 0;\r
2356 IntegrityAlgorithm = 0;\r
2357 EncryptAlgorithm = 0;\r
2358 EncryptKeylength = 0;\r
2359 IsMatch = TRUE;\r
2360 IsSupportEsn = FALSE;\r
2361 PreferIsSupportEsn = FALSE;\r
2362\r
2363 if (Type == IKE_HEADER_FLAGS_INIT) {\r
2364 ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *) SaPayload->PayloadBuf + 1);\r
2365 for (ProposalIndex = 0; ProposalIndex < ((IKEV2_SA_DATA *) SaPayload->PayloadBuf)->NumProposals; ProposalIndex++) {\r
2366 //\r
2367 // Iterate each proposal to find the preferred one.\r
2368 //\r
2369 if (ProposalData->ProtocolId == IPSEC_PROTO_IPSEC_ESP && ProposalData->NumTransforms >= 3) {\r
2370 //\r
2371 // Get the preferred algorithm.\r
2372 //\r
2373 Ikev2ParseProposalData (\r
2374 ProposalData,\r
2375 &PreferEncryptAlgorithm,\r
2376 &PreferIntegrityAlgorithm,\r
2377 NULL,\r
2378 NULL,\r
2379 &PreferEncryptKeylength,\r
2380 &IsSupportEsn,\r
2381 TRUE\r
2382 );\r
2383 //\r
2384 // Don't support the ESN now.\r
2385 //\r
2386 if (PreferEncryptAlgorithm != 0 && \r
2387 PreferIntegrityAlgorithm != 0 &&\r
2388 !IsSupportEsn\r
2389 ) {\r
2390 //\r
2391 // Find the matched one. \r
2392 //\r
2393 ChildSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS));\r
2394 ASSERT (ChildSaSession->SessionCommon.SaParams != NULL);\r
2395 ChildSaSession->SessionCommon.SaParams->EncAlgId = PreferEncryptAlgorithm;\r
2396 ChildSaSession->SessionCommon.SaParams->EnckeyLen = PreferEncryptKeylength;\r
2397 ChildSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm;\r
2398 CopyMem (&ChildSaSession->RemotePeerSpi, ProposalData->Spi, sizeof (ChildSaSession->RemotePeerSpi));\r
2399\r
2400 //\r
2401 // Save the matched one in IKEV2_SA_DATA for furthure calculation.\r
2402 //\r
2403 SaDataSize = sizeof (IKEV2_SA_DATA) +\r
2404 sizeof (IKEV2_PROPOSAL_DATA) +\r
2405 sizeof (IKEV2_TRANSFORM_DATA) * 4;\r
2406\r
2407 ChildSaSession->SaData = AllocateZeroPool (SaDataSize);\r
2408 ASSERT (ChildSaSession->SaData != NULL);\r
2409\r
2410 ChildSaSession->SaData->NumProposals = 1;\r
2411\r
2412 //\r
2413 // BUGBUG: Suppose there are 4 transforms in the matched proposal. If\r
2414 // the matched Proposal has more than 4 transforms that means there \r
2415 // are more than one transform with same type.\r
2416 //\r
2417 CopyMem (\r
2418 (IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1),\r
2419 ProposalData,\r
2420 SaDataSize - sizeof (IKEV2_SA_DATA)\r
2421 );\r
2422\r
2423 ((IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1))->ProposalIndex = 1;\r
2424\r
2425 ((IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1))->Spi = AllocateCopyPool (\r
2426 sizeof (ChildSaSession->LocalPeerSpi), \r
2427 &ChildSaSession->LocalPeerSpi\r
2428 );\r
2429 ASSERT (((IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1))->Spi != NULL);\r
2430 return TRUE;\r
2431\r
2432 } else {\r
2433 PreferEncryptAlgorithm = 0;\r
2434 PreferIntegrityAlgorithm = 0;\r
2435 IsSupportEsn = TRUE;\r
2436 }\r
2437 }\r
2438 //\r
2439 // Point to next Proposal\r
2440 //\r
2441 ProposalData = (IKEV2_PROPOSAL_DATA *)((UINT8 *)(ProposalData + 1) + \r
2442 ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA));\r
2443 }\r
2444 } else if (Type == IKE_HEADER_FLAGS_RESPOND) {\r
2445 //\r
2446 // First check the SA proposal's ProtoctolID and Transform Numbers. Since it is \r
2447 // the responded SA proposal, suppose it only has one proposal and the transform Numbers \r
2448 // is 3. \r
2449 //\r
2450 ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *)SaPayload->PayloadBuf + 1);\r
2451 if (ProposalData->ProtocolId != IPSEC_PROTO_IPSEC_ESP || ProposalData->NumTransforms != 3) {\r
2452 return FALSE;\r
2453 }\r
2454 //\r
2455 // Get the preferred algorithms.\r
2456 //\r
2457 Ikev2ParseProposalData (\r
2458 ProposalData,\r
2459 &PreferEncryptAlgorithm,\r
2460 &PreferIntegrityAlgorithm,\r
2461 NULL,\r
2462 NULL,\r
2463 &PreferEncryptKeylength,\r
2464 &PreferIsSupportEsn,\r
2465 TRUE\r
2466 );\r
2467\r
2468 ProposalData = (IKEV2_PROPOSAL_DATA *) (ChildSaSession->SaData + 1);\r
2469\r
2470 for (ProposalIndex = 0; ProposalIndex < ChildSaSession->SaData->NumProposals && (!IsMatch); ProposalIndex++) {\r
2471 Ikev2ParseProposalData (\r
2472 ProposalData, \r
2473 &EncryptAlgorithm,\r
2474 &IntegrityAlgorithm,\r
2475 NULL,\r
2476 NULL,\r
2477 &EncryptKeylength,\r
2478 &IsSupportEsn,\r
2479 TRUE\r
2480 );\r
2481 if (EncryptAlgorithm == PreferEncryptAlgorithm &&\r
2482 EncryptKeylength == PreferEncryptKeylength &&\r
2483 IntegrityAlgorithm == PreferIntegrityAlgorithm &&\r
2484 IsSupportEsn == PreferIsSupportEsn \r
2485 ) {\r
2486 IsMatch = TRUE;\r
2487 } else {\r
2488 PreferEncryptAlgorithm = 0;\r
2489 PreferIntegrityAlgorithm = 0;\r
2490 IsSupportEsn = TRUE;\r
2491 }\r
2492 ProposalData = (IKEV2_PROPOSAL_DATA*)((UINT8*)(ProposalData + 1) + \r
2493 ProposalData->NumTransforms * sizeof (IKEV2_TRANSFORM_DATA)); \r
2494 }\r
2495 \r
2496 ProposalData = (IKEV2_PROPOSAL_DATA *)((IKEV2_SA_DATA *)SaPayload->PayloadBuf + 1);\r
2497 if (IsMatch) {\r
2498 ChildSaSession->SessionCommon.SaParams = AllocateZeroPool (sizeof (IKEV2_SA_PARAMS));\r
2499 ASSERT (ChildSaSession->SessionCommon.SaParams != NULL);\r
2500 ChildSaSession->SessionCommon.SaParams->EncAlgId = PreferEncryptAlgorithm;\r
2501 ChildSaSession->SessionCommon.SaParams->EnckeyLen = PreferEncryptKeylength;\r
2502 ChildSaSession->SessionCommon.SaParams->IntegAlgId = PreferIntegrityAlgorithm;\r
2503 CopyMem (&ChildSaSession->RemotePeerSpi, ProposalData->Spi, sizeof (ChildSaSession->RemotePeerSpi));\r
2504\r
2505 return TRUE;\r
2506 }\r
2507 }\r
2508 return FALSE;\r
2509}\r
2510\r
2511/**\r
2512 Generate Key buffer from fragments.\r
2513\r
2514 If the digest length of specified HashAlgId is larger than or equal with the \r
2515 required output key length, derive the key directly. Otherwise, Key Material \r
2516 needs to be PRF-based concatenation according to 2.13 of RFC 4306: \r
2517 prf+ (K,S) = T1 | T2 | T3 | T4 | ..., T1 = prf (K, S | 0x01),\r
2518 T2 = prf (K, T1 | S | 0x02), T3 = prf (K, T2 | S | 0x03),T4 = prf (K, T3 | S | 0x04)\r
2519 then derive the key from this key material.\r
2520 \r
2521 @param[in] HashAlgId The Hash Algorithm ID used to generate key.\r
2522 @param[in] HashKey Pointer to a key buffer which contains hash key.\r
2523 @param[in] HashKeyLength The length of HashKey in bytes.\r
2524 @param[in, out] OutputKey Pointer to buffer which is used to receive the \r
2525 output key.\r
2526 @param[in] OutputKeyLength The length of OutPutKey buffer.\r
2527 @param[in] Fragments Pointer to the data to be used to generate key.\r
2528 @param[in] NumFragments The numbers of the Fragement.\r
2529\r
2530 @retval EFI_SUCCESS The operation complete successfully.\r
2531 @retval EFI_INVALID_PARAMETER If NumFragments is zero.\r
2532 @retval EFI_OUT_OF_RESOURCES If the required resource can't be allocated.\r
2533 @retval Others The operation is failed.\r
2534\r
2535**/\r
2536EFI_STATUS\r
2537Ikev2SaGenerateKey (\r
2538 IN UINT8 HashAlgId,\r
2539 IN UINT8 *HashKey,\r
2540 IN UINTN HashKeyLength,\r
2541 IN OUT UINT8 *OutputKey,\r
2542 IN UINTN OutputKeyLength,\r
2543 IN PRF_DATA_FRAGMENT *Fragments,\r
2544 IN UINTN NumFragments\r
2545 )\r
2546{\r
2547 EFI_STATUS Status;\r
2548 PRF_DATA_FRAGMENT LocalFragments[3];\r
2549 UINT8 *Digest;\r
2550 UINTN DigestSize;\r
2551 UINTN Round;\r
2552 UINTN Index;\r
2553 UINTN AuthKeyLength;\r
2554 UINTN FragmentsSize;\r
2555 UINT8 TailData;\r
2556\r
2557 Status = EFI_SUCCESS;\r
2558\r
2559 if (NumFragments == 0) {\r
2560 return EFI_INVALID_PARAMETER;\r
2561 }\r
2562\r
2563 LocalFragments[0].Data = NULL;\r
2564 LocalFragments[1].Data = NULL;\r
2565 LocalFragments[2].Data = NULL;\r
2566\r
2567 AuthKeyLength = IpSecGetHmacDigestLength (HashAlgId);\r
2568 DigestSize = AuthKeyLength;\r
2569 Digest = AllocateZeroPool (AuthKeyLength);\r
2570\r
2571 if (Digest == NULL) {\r
2572 return EFI_OUT_OF_RESOURCES;\r
2573 }\r
2574 //\r
2575 // If the required output key length is less than the digest size,\r
2576 // copy the digest into OutputKey.\r
2577 //\r
2578 if (OutputKeyLength <= DigestSize) {\r
2579 Status = IpSecCryptoIoHmac (\r
2580 HashAlgId,\r
2581 HashKey, \r
2582 HashKeyLength, \r
2583 (HASH_DATA_FRAGMENT *) Fragments, \r
2584 NumFragments, \r
2585 Digest, \r
2586 DigestSize\r
2587 );\r
2588 if (EFI_ERROR (Status)) {\r
2589 goto Exit;\r
2590 }\r
2591\r
2592 CopyMem (OutputKey, Digest, OutputKeyLength);\r
2593 goto Exit;\r
2594 }\r
2595\r
2596 //\r
2597 //Otherwise, Key Material need to be PRF-based concatenation according to 2.13\r
2598 //of RFC 4306: prf+ (K,S) = T1 | T2 | T3 | T4 | ..., T1 = prf (K, S | 0x01),\r
2599 //T2 = prf (K, T1 | S | 0x02), T3 = prf (K, T2 | S | 0x03),T4 = prf (K, T3 | S | 0x04)\r
2600 //then derive the key from this key material.\r
2601 //\r
2602 FragmentsSize = 0;\r
2603 for (Index = 0; Index < NumFragments; Index++) {\r
2604 FragmentsSize = FragmentsSize + Fragments[Index].DataSize;\r
2605 }\r
2606\r
2607 LocalFragments[1].Data = AllocateZeroPool (FragmentsSize);\r
2608 ASSERT (LocalFragments[1].Data != NULL);\r
2609 LocalFragments[1].DataSize = FragmentsSize;\r
2610\r
2611 //\r
2612 // Copy all input fragments into LocalFragments[1];\r
2613 //\r
2614 FragmentsSize = 0;\r
2615 for (Index = 0; Index < NumFragments; Index++) {\r
2616 CopyMem (\r
2617 LocalFragments[1].Data + FragmentsSize, \r
2618 Fragments[Index].Data,\r
2619 Fragments[Index].DataSize\r
2620 );\r
2621 FragmentsSize = FragmentsSize + Fragments[Index].DataSize;\r
2622 }\r
2623\r
2624 //\r
2625 // Prepare 0x01 as the first tail data.\r
2626 //\r
2627 TailData = 0x01;\r
2628 LocalFragments[2].Data = &TailData;\r
2629 LocalFragments[2].DataSize = sizeof (TailData);\r
2630 //\r
2631 // Allocate buffer for the first fragment\r
2632 //\r
2633 LocalFragments[0].Data = AllocateZeroPool (AuthKeyLength);\r
2634 ASSERT (LocalFragments[0].Data != NULL);\r
2635 LocalFragments[0].DataSize = AuthKeyLength;\r
2636\r
2637 Round = (OutputKeyLength - 1) / AuthKeyLength + 1;\r
2638 for (Index = 0; Index < Round; Index++) {\r
2639 Status = IpSecCryptoIoHmac (\r
2640 HashAlgId, \r
2641 HashKey, \r
2642 HashKeyLength, \r
2643 (HASH_DATA_FRAGMENT *)(Index == 0 ? &LocalFragments[1] : LocalFragments),\r
2644 Index == 0 ? 2 : 3, \r
2645 Digest,\r
2646 DigestSize\r
2647 );\r
2648 if (EFI_ERROR(Status)) {\r
2649 goto Exit;\r
2650 }\r
2651 CopyMem (\r
2652 LocalFragments[0].Data, \r
2653 Digest, \r
2654 DigestSize\r
2655 );\r
2656 if (OutputKeyLength > DigestSize * (Index + 1)) {\r
2657 CopyMem (\r
2658 OutputKey + Index * DigestSize, \r
2659 Digest, \r
2660 DigestSize\r
2661 );\r
2662 LocalFragments[0].DataSize = DigestSize;\r
2663 TailData ++;\r
2664 } else {\r
2665 // \r
2666 // The last round\r
2667 //\r
2668 CopyMem (\r
2669 OutputKey + Index * DigestSize, \r
2670 Digest, \r
2671 OutputKeyLength - Index * DigestSize\r
2672 );\r
2673 }\r
2674 }\r
2675\r
2676Exit:\r
2677 //\r
2678 // Only First and second Framgement Data need to be freed.\r
2679 //\r
2680 for (Index = 0 ; Index < 2; Index++) {\r
2681 if (LocalFragments[Index].Data != NULL) {\r
2682 FreePool (LocalFragments[Index].Data);\r
2683 }\r
2684 }\r
2685 if (Digest != NULL) {\r
2686 FreePool (Digest);\r
2687 }\r
2688 return Status;\r
2689}\r
2690\r