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