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