Home | History | Annotate | Download | only in Ikev2
      1 /** @file
      2   The Implementations for Information Exchange.
      3 
      4   (C) Copyright 2015 Hewlett-Packard Development Company, L.P.<BR>
      5   Copyright (c) 2010, 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 "IpSecConfigImpl.h"
     20 
     21 /**
     22   Generate Information Packet.
     23 
     24   The information Packet may contain one Delete Payload, or Notify Payload, which
     25   dependes on the Context's parameters.
     26 
     27   @param[in]  SaSession   Pointer to IKE SA Session or Child SA Session which is
     28                           related to the information Exchange.
     29   @param[in]  Context     The Data passed from the caller. If the Context is not NULL
     30                           it should contain the information for Notification Data.
     31 
     32   @retval     Pointer of IKE_PACKET generated.
     33 
     34 **/
     35 IKE_PACKET *
     36 Ikev2InfoGenerator (
     37   IN UINT8                         *SaSession,
     38   IN VOID                          *Context
     39   )
     40 {
     41   IKEV2_SA_SESSION            *IkeSaSession;
     42   IKEV2_CHILD_SA_SESSION      *ChildSaSession;
     43   IKE_PACKET                  *IkePacket;
     44   IKE_PAYLOAD                 *IkePayload;
     45   IKEV2_INFO_EXCHANGE_CONTEXT *InfoContext;
     46 
     47   InfoContext  = NULL;
     48   IkeSaSession = (IKEV2_SA_SESSION *) SaSession;
     49   IkePacket    = IkePacketAlloc ();
     50   ASSERT (IkePacket != NULL);
     51 
     52   //
     53   // Fill IkePacket Header.
     54   //
     55   IkePacket->Header->ExchangeType    = IKEV2_EXCHANGE_TYPE_INFO;
     56   IkePacket->Header->Version         = (UINT8) (2 << 4);
     57 
     58   if (Context != NULL) {
     59     InfoContext = (IKEV2_INFO_EXCHANGE_CONTEXT *) Context;
     60   }
     61 
     62   //
     63   // For Liveness Check
     64   //
     65   if (InfoContext != NULL &&
     66       (InfoContext->InfoType == Ikev2InfoLiveCheck || InfoContext->InfoType == Ikev2InfoNotify)
     67     ) {
     68     IkePacket->Header->MessageId       = InfoContext->MessageId;
     69     IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
     70     IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
     71     IkePacket->Header->NextPayload     = IKEV2_PAYLOAD_TYPE_NONE;
     72     IkePacket->Header->Flags           = IKE_HEADER_FLAGS_RESPOND;
     73     //
     74     // TODO: add Notify Payload for Notification Information.
     75     //
     76     return IkePacket;
     77   }
     78 
     79   //
     80   // For delete SAs
     81   //
     82   if (IkeSaSession->SessionCommon.IkeSessionType == IkeSessionTypeIkeSa) {
     83 
     84     IkePacket->Header->InitiatorCookie = IkeSaSession->InitiatorCookie;
     85     IkePacket->Header->ResponderCookie = IkeSaSession->ResponderCookie;
     86 
     87     //
     88     // If the information message is response message,the MessageId should
     89     // be same as the request MessageId which passed through the Context.
     90     //
     91     if (InfoContext != NULL) {
     92       IkePacket->Header->MessageId     = InfoContext->MessageId;
     93     } else {
     94       IkePacket->Header->MessageId     = IkeSaSession->MessageId;
     95       Ikev2SaSessionIncreaseMessageId (IkeSaSession);
     96     }
     97     //
     98     // If the state is on deleting generate a Delete Payload for it.
     99     //
    100     if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting ) {
    101       IkePayload = Ikev2GenerateDeletePayload (
    102                      IkeSaSession,
    103                      IKEV2_PAYLOAD_TYPE_NONE,
    104                      0,
    105                      0,
    106                      NULL
    107                      );
    108       if (IkePayload == NULL) {
    109         goto ERROR_EXIT;
    110       }
    111       //
    112       // Fill the next payload in IkePacket's Header.
    113       //
    114       IkePacket->Header->NextPayload     = IKEV2_PAYLOAD_TYPE_DELETE;
    115       IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);
    116       IkePacket->Private           = IkeSaSession->SessionCommon.Private;
    117       IkePacket->Spi               = 0;
    118       IkePacket->IsDeleteInfo      = TRUE;
    119 
    120     } else if (Context != NULL) {
    121       //
    122       // TODO: If contest is not NULL Generate a Notify Payload.
    123       //
    124     } else {
    125       //
    126       // The input parameter is not correct.
    127       //
    128       goto ERROR_EXIT;
    129     }
    130   } else {
    131     //
    132     // Delete the Child SA Information Exchagne
    133     //
    134     ChildSaSession                     = (IKEV2_CHILD_SA_SESSION *) SaSession;
    135     IkeSaSession                       = ChildSaSession->IkeSaSession;
    136     IkePacket->Header->InitiatorCookie = ChildSaSession->IkeSaSession->InitiatorCookie;
    137     IkePacket->Header->ResponderCookie = ChildSaSession->IkeSaSession->ResponderCookie;
    138 
    139     //
    140     // If the information message is response message,the MessageId should
    141     // be same as the request MessageId which passed through the Context.
    142     //
    143     if (InfoContext != NULL && InfoContext->MessageId != 0) {
    144       IkePacket->Header->MessageId     = InfoContext->MessageId;
    145     } else {
    146       IkePacket->Header->MessageId     = ChildSaSession->IkeSaSession->MessageId;
    147       Ikev2SaSessionIncreaseMessageId (IkeSaSession);
    148     }
    149 
    150     IkePayload     = Ikev2GenerateDeletePayload (
    151                        ChildSaSession->IkeSaSession,
    152                        IKEV2_PAYLOAD_TYPE_DELETE,
    153                        4,
    154                        1,
    155                        (UINT8 *)&ChildSaSession->LocalPeerSpi
    156                        );
    157     if (IkePayload == NULL) {
    158       goto ERROR_EXIT;
    159     }
    160     //
    161     // Fill the Next Payload in IkePacket's Header.
    162     //
    163     IkePacket->Header->NextPayload     = IKEV2_PAYLOAD_TYPE_DELETE;
    164     IKE_PACKET_APPEND_PAYLOAD (IkePacket, IkePayload);
    165 
    166     IkePacket->Private      = IkeSaSession->SessionCommon.Private;
    167     IkePacket->Spi          = ChildSaSession->LocalPeerSpi;
    168     IkePacket->IsDeleteInfo = TRUE;
    169 
    170     if (!ChildSaSession->SessionCommon.IsInitiator) {
    171       //
    172       // If responder, use the MessageId fromt the initiator.
    173       //
    174       IkePacket->Header->MessageId = ChildSaSession->MessageId;
    175     }
    176 
    177     //
    178     // Change the IsOnDeleting Flag
    179     //
    180     ChildSaSession->SessionCommon.IsOnDeleting = TRUE;
    181   }
    182 
    183   if (InfoContext == NULL) {
    184     IkePacket->Header->Flags = IKE_HEADER_FLAGS_INIT;
    185   } else {
    186     IkePacket->Header->Flags = IKE_HEADER_FLAGS_RESPOND;
    187   }
    188   return IkePacket;
    189 
    190 ERROR_EXIT:
    191    if (IkePacket != NULL) {
    192      FreePool (IkePacket);
    193    }
    194    return NULL;
    195 
    196 }
    197 
    198 /**
    199   Parse the Info Exchange.
    200 
    201   @param[in]  SaSession   Pointer to IKEV2_SA_SESSION.
    202   @param[in]  IkePacket   Pointer to IkePacket related to the Information Exchange.
    203 
    204   @retval  EFI_SUCCESS    The operation finised successed.
    205 
    206 **/
    207 EFI_STATUS
    208 Ikev2InfoParser (
    209   IN UINT8                         *SaSession,
    210   IN IKE_PACKET                    *IkePacket
    211   )
    212 {
    213   IKEV2_CHILD_SA_SESSION *ChildSaSession;
    214   IKEV2_SA_SESSION       *IkeSaSession;
    215   IKE_PAYLOAD            *DeletePayload;
    216   IKE_PAYLOAD            *IkePayload;
    217   IKEV2_DELETE           *Delete;
    218   LIST_ENTRY             *Entry;
    219   LIST_ENTRY             *ListEntry;
    220   UINT8                  Index;
    221   UINT32                 Spi;
    222   UINT8                  *SpiBuffer;
    223   IPSEC_PRIVATE_DATA     *Private;
    224   UINT8                  Value;
    225   EFI_STATUS             Status;
    226   IKE_PACKET             *RespondPacket;
    227 
    228   IKEV2_INFO_EXCHANGE_CONTEXT Context;
    229 
    230   IkeSaSession   = (IKEV2_SA_SESSION *) SaSession;
    231 
    232   DeletePayload  = NULL;
    233   Private        = NULL;
    234   RespondPacket  = NULL;
    235   Status         = EFI_SUCCESS;
    236 
    237   //
    238   // For Liveness Check
    239   //
    240   if (IkePacket->Header->NextPayload == IKEV2_PAYLOAD_TYPE_NONE &&
    241       (IkePacket->PayloadTotalSize == 0)
    242       ) {
    243     if (IkePacket->Header->Flags == IKE_HEADER_FLAGS_INIT) {
    244       //
    245       // If it is Liveness check request, reply it.
    246       //
    247       Context.InfoType  = Ikev2InfoLiveCheck;
    248       Context.MessageId = IkePacket->Header->MessageId;
    249       RespondPacket     = Ikev2InfoGenerator ((UINT8 *)IkeSaSession, &Context);
    250 
    251       if (RespondPacket == NULL) {
    252         Status = EFI_INVALID_PARAMETER;
    253         return Status;
    254       }
    255       Status = Ikev2SendIkePacket (
    256                  IkeSaSession->SessionCommon.UdpService,
    257                  (UINT8 *)(&IkeSaSession->SessionCommon),
    258                  RespondPacket,
    259                  0
    260                  );
    261 
    262     } else {
    263       //
    264       // Todo: verify the liveness check response packet.
    265       //
    266     }
    267     return Status;
    268   }
    269 
    270   //
    271   // For SA Delete
    272   //
    273   NET_LIST_FOR_EACH (Entry, &(IkePacket)->PayloadList) {
    274 
    275   //
    276   // Iterate payloads to find the Delete/Notify Payload.
    277   //
    278     IkePayload  = IKE_PAYLOAD_BY_PACKET (Entry);
    279 
    280     if (IkePayload->PayloadType == IKEV2_PAYLOAD_TYPE_DELETE) {
    281       DeletePayload = IkePayload;
    282       Delete = (IKEV2_DELETE *)DeletePayload->PayloadBuf;
    283 
    284       if (Delete->SpiSize == 0) {
    285         //
    286         // Delete IKE SA.
    287         //
    288         if (IkeSaSession->SessionCommon.State == IkeStateSaDeleting) {
    289           RemoveEntryList (&IkeSaSession->BySessionTable);
    290           Ikev2SaSessionFree (IkeSaSession);
    291           //
    292           // Checking the Private status.
    293           //
    294           //
    295           // when all IKE SAs were disabled by calling "IPsecConfig -disable", the IPsec
    296           // status should be changed.
    297           //
    298           Private = IkeSaSession->SessionCommon.Private;
    299           if (Private != NULL && Private->IsIPsecDisabling) {
    300             //
    301             // After all IKE SAs were deleted, set the IPSEC_STATUS_DISABLED value in
    302             // IPsec status variable.
    303             //
    304             if (IsListEmpty (&Private->Ikev1EstablishedList) &&
    305                 (IsListEmpty (&Private->Ikev2EstablishedList))
    306                ) {
    307               Value  = IPSEC_STATUS_DISABLED;
    308               Status = gRT->SetVariable (
    309                          IPSECCONFIG_STATUS_NAME,
    310                          &gEfiIpSecConfigProtocolGuid,
    311                          EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
    312                          sizeof (Value),
    313                          &Value
    314                          );
    315               if (!EFI_ERROR (Status)) {
    316                 //
    317                 // Set the DisabledFlag in Private data.
    318                 //
    319                 Private->IpSec.DisabledFlag = TRUE;
    320                 Private->IsIPsecDisabling   = FALSE;
    321               }
    322             }
    323           }
    324         } else {
    325           IkeSaSession->SessionCommon.State = IkeStateSaDeleting;
    326           Context.InfoType                  = Ikev2InfoDelete;
    327           Context.MessageId                 = IkePacket->Header->MessageId;
    328 
    329           RespondPacket = Ikev2InfoGenerator ((UINT8 *)IkeSaSession, &Context);
    330           if (RespondPacket == NULL) {
    331             Status = EFI_INVALID_PARAMETER;
    332             return Status;
    333           }
    334           Status = Ikev2SendIkePacket (
    335                      IkeSaSession->SessionCommon.UdpService,
    336                      (UINT8 *)(&IkeSaSession->SessionCommon),
    337                      RespondPacket,
    338                      0
    339                      );
    340         }
    341       } else if (Delete->SpiSize == 4) {
    342         //
    343         // Move the Child SAs to DeleteList
    344         //
    345         SpiBuffer = (UINT8 *)(Delete + 1);
    346         for (Index = 0; Index < Delete->NumSpis; Index++) {
    347           Spi = ReadUnaligned32 ((UINT32 *)SpiBuffer);
    348           for (ListEntry = IkeSaSession->ChildSaEstablishSessionList.ForwardLink;
    349                ListEntry != &IkeSaSession->ChildSaEstablishSessionList;
    350           ) {
    351             ChildSaSession = IKEV2_CHILD_SA_SESSION_BY_IKE_SA (ListEntry);
    352             ListEntry = ListEntry->ForwardLink;
    353 
    354             if (ChildSaSession->RemotePeerSpi == HTONL(Spi)) {
    355               if (ChildSaSession->SessionCommon.State != IkeStateSaDeleting) {
    356 
    357                 //
    358                 // Insert the ChildSa Session into Delete List.
    359                 //
    360                 InsertTailList (&IkeSaSession->DeleteSaList, &ChildSaSession->ByDelete);
    361                 ChildSaSession->SessionCommon.State       = IkeStateSaDeleting;
    362                 ChildSaSession->SessionCommon.IsInitiator = FALSE;
    363                 ChildSaSession->MessageId                 = IkePacket->Header->MessageId;
    364 
    365                 Context.InfoType = Ikev2InfoDelete;
    366                 Context.MessageId = IkePacket->Header->MessageId;
    367 
    368                 RespondPacket = Ikev2InfoGenerator ((UINT8 *)ChildSaSession, &Context);
    369                 if (RespondPacket == NULL) {
    370                   Status = EFI_INVALID_PARAMETER;
    371                   return Status;
    372                 }
    373                 Status = Ikev2SendIkePacket (
    374                            ChildSaSession->SessionCommon.UdpService,
    375                            (UINT8 *)(&ChildSaSession->SessionCommon),
    376                            RespondPacket,
    377                            0
    378                            );
    379               } else {
    380                 //
    381                 // Delete the Child SA.
    382                 //
    383                 Ikev2ChildSaSilentDelete (IkeSaSession, Spi);
    384                 RemoveEntryList (&ChildSaSession->ByDelete);
    385               }
    386             }
    387           }
    388           SpiBuffer = SpiBuffer + sizeof (Spi);
    389         }
    390       }
    391     }
    392   }
    393 
    394   return Status;
    395 }
    396 
    397 GLOBAL_REMOVE_IF_UNREFERENCED IKEV2_PACKET_HANDLER  mIkev2Info = {
    398   Ikev2InfoParser,
    399   Ikev2InfoGenerator
    400 };
    401