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
22UINT16 mIkev2EncryptAlgorithmList[IKEV2_SUPPORT_ENCRYPT_ALGORITHM_NUM] = {
23  IKEV2_TRANSFORM_ID_ENCR_3DES,
24  IKEV2_TRANSFORM_ID_ENCR_AES_CBC,
25};
26
27UINT16 mIkev2PrfAlgorithmList[IKEV2_SUPPORT_PRF_ALGORITHM_NUM] = {
28  IKEV2_TRANSFORM_ID_PRF_HMAC_SHA1,
29};
30
31UINT16 mIkev2DhGroupAlgorithmList[IKEV2_SUPPORT_DH_ALGORITHM_NUM] = {
32  IKEV2_TRANSFORM_ID_DH_1024MODP,
33  IKEV2_TRANSFORM_ID_DH_2048MODP,
34};
35
36UINT16 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**/
49IKEV2_SA_SESSION *
50Ikev2SaSessionAlloc (
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**/
121VOID
122Ikev2SaSessionReg (
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**/
212IKEV2_SA_SESSION *
213Ikev2SaSessionLookup (
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**/
247VOID
248Ikev2SaSessionInsert (
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**/
267IKEV2_SA_SESSION *
268Ikev2SaSessionRemove (
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**/
301EFI_STATUS
302Ikev2SaSessionOnDeleting (
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**/
316VOID
317Ikev2SaSessionCommonFree (
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**/
342VOID
343Ikev2SessionCommonRefresh (
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**/
366VOID
367Ikev2SaSessionFree (
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**/
482VOID
483Ikev2SaSessionIncreaseMessageId (
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**/
506IKEV2_CHILD_SA_SESSION *
507Ikev2ChildSaSessionAlloc (
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**/
577VOID
578Ikev2ChildSaSessionReg (
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**/
671IKEV2_CHILD_SA_SESSION *
672Ikev2ChildSaSessionLookupByMid (
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**/
702IKEV2_CHILD_SA_SESSION *
703Ikev2ChildSaSessionLookupBySpi (
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**/
729VOID
730Ikev2ChildSaSessionInsert (
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**/
749IKEV2_CHILD_SA_SESSION *
750Ikev2ChildSaSessionRemove (
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**/
787EFI_STATUS
788Ikev2ChildSaSessionOnDeleting (
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**/
801VOID
802Ikev2ChildSaSessionFree (
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**/
875EFI_STATUS
876Ikev2ChildSaSilentDelete (
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**/
1037VOID
1038Ikev2DhBufferFree (
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**/
1069IKEV2_CREATE_CHILD_REQUEST_TYPE
1070Ikev2ChildExchangeRequestType(
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**/
1126EFI_STATUS
1127Ikev2ChildSaAssociateSpdEntry (
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**/
1148UINT32
1149Ikev2ChildExchangeRekeySpi (
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**/
1169BOOLEAN
1170Ikev2ValidateHeader (
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**/
1239IKEV2_SA_DATA *
1240Ikev2InitializeSaData (
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**/
1438VOID
1439Ikev2StoreSaData (
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**/
1565VOID
1566EFIAPI
1567Ikev2LifetimeNotify (
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**/
1626VOID
1627EFIAPI
1628Ikev2ResendNotify (
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**/
1771EFI_STATUS
1772Ikev2ChildSaSessionSpdSelectorCreate (
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**/
1837IKEV2_CHILD_SA_SESSION *
1838Ikev2ChildSaSessionCreate (
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**/
1938EFI_STATUS
1939Ikev2MatchSpdEntry (
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**/
2029BOOLEAN
2030Ikev2IsSupportAlg (
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**/
2089VOID
2090Ikev2ParseProposalData (
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**/
2204BOOLEAN
2205Ikev2SaParseSaPayload (
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**/
2414BOOLEAN
2415Ikev2ChildSaParseSaPayload (
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**/
2634EFI_STATUS
2635Ikev2SaGenerateKey (
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
2782Exit:
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