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