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