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