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