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