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